Skip to content

Use rustversion and remove const_fn! #353

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 24, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -64,7 +64,7 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: doc
args: --no-default-features --features external_asm,instructions
args: --no-default-features --features instructions
if: runner.os != 'Windows'

- name: "Run cargo doc without default features"
@@ -83,14 +83,14 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: build
args: --no-default-features --features external_asm,instructions
args: --no-default-features --features instructions
if: runner.os != 'Windows'

- name: "Run cargo build for stable on musl"
uses: actions-rs/cargo@v1
with:
command: build
args: --target x86_64-unknown-linux-musl --no-default-features --features external_asm,instructions
args: --target x86_64-unknown-linux-musl --no-default-features --features instructions
if: runner.os == 'Linux'

- name: "Run cargo test"
@@ -102,14 +102,14 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: test
args: --no-default-features --features external_asm,instructions
args: --no-default-features --features instructions
if: runner.os != 'Windows'

- name: "Run cargo test for stable on musl"
uses: actions-rs/cargo@v1
with:
command: test
args: --target x86_64-unknown-linux-musl --no-default-features --features external_asm,instructions
args: --target x86_64-unknown-linux-musl --no-default-features --features instructions
if: runner.os == 'Linux'

- name: "Install Rustup Targets"
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -29,6 +29,7 @@ edition = "2018"
bit_field = "0.10.1"
bitflags = "1.0.4"
volatile = "0.4.4"
rustversion = "1.0.5"

[features]
default = [ "nightly", "instructions" ]
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -9,7 +9,6 @@ Support for x86_64 specific instructions (e.g. TLB flush), registers (e.g. contr

* `nightly`: Enables features only available on nightly Rust; enabled by default.
* `instructions`: Enabled by default, turns on x86\_64 specific instructions, and dependent features. Only available for x86\_64 targets.
* `external_asm`: Use this to build with non-nightly rust. Needs `default-features = false, features = ["instructions"]`. Is unsupported on Windows.

## Building with stable rust

6 changes: 2 additions & 4 deletions src/addr.rs
Original file line number Diff line number Diff line change
@@ -625,8 +625,7 @@ impl Sub<PhysAddr> for PhysAddr {
///
/// Returns the greatest `x` with alignment `align` so that `x <= addr`.
///
/// Panics if the alignment is not a power of two. Without the `const_fn`
/// feature, the panic message will be "index out of bounds".
/// Panics if the alignment is not a power of two.
#[inline]
pub const fn align_down(addr: u64, align: u64) -> u64 {
assert!(align.is_power_of_two(), "`align` must be a power of two");
@@ -637,8 +636,7 @@ pub const fn align_down(addr: u64, align: u64) -> u64 {
///
/// Returns the smallest `x` with alignment `align` so that `x >= addr`.
///
/// Panics if the alignment is not a power of two. Without the `const_fn`
/// feature, the panic message will be "index out of bounds".
/// Panics if the alignment is not a power of two.
#[inline]
pub const fn align_up(addr: u64, align: u64) -> u64 {
assert!(align.is_power_of_two(), "`align` must be a power of two");
31 changes: 0 additions & 31 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -12,37 +12,6 @@

pub use crate::addr::{align_down, align_up, PhysAddr, VirtAddr};

/// Makes a function const only when `feature = "const_fn"` is enabled.
///
/// This is needed for const functions with bounds on their generic parameters,
/// such as those in `Page` and `PhysFrame` and many more.
macro_rules! const_fn {
(
$(#[$attr:meta])*
$sv:vis fn $($fn:tt)*
) => {
$(#[$attr])*
#[cfg(feature = "const_fn")]
$sv const fn $($fn)*

$(#[$attr])*
#[cfg(not(feature = "const_fn"))]
$sv fn $($fn)*
};
(
$(#[$attr:meta])*
$sv:vis unsafe fn $($fn:tt)*
) => {
$(#[$attr])*
#[cfg(feature = "const_fn")]
$sv const unsafe fn $($fn)*

$(#[$attr])*
#[cfg(not(feature = "const_fn"))]
$sv unsafe fn $($fn)*
};
}

pub mod addr;
pub mod instructions;
pub mod registers;
73 changes: 35 additions & 38 deletions src/structures/gdt.rs
Original file line number Diff line number Diff line change
@@ -93,36 +93,34 @@ impl GlobalDescriptorTable {
&self.table[..self.next_free]
}

const_fn! {
/// Adds the given segment descriptor to the GDT, returning the segment selector.
///
/// Panics if the GDT has no free entries left. Without the `const_fn`
/// feature, the panic message will be "index out of bounds".
#[inline]
pub fn add_entry(&mut self, entry: Descriptor) -> SegmentSelector {
let index = match entry {
Descriptor::UserSegment(value) => self.push(value),
Descriptor::SystemSegment(value_low, value_high) => {
let index = self.push(value_low);
self.push(value_high);
index
}
};
/// Adds the given segment descriptor to the GDT, returning the segment selector.
///
/// Panics if the GDT has no free entries left.
#[inline]
#[cfg_attr(feature = "const_fn", rustversion::attr(all(), const))]
pub fn add_entry(&mut self, entry: Descriptor) -> SegmentSelector {
let index = match entry {
Descriptor::UserSegment(value) => self.push(value),
Descriptor::SystemSegment(value_low, value_high) => {
let index = self.push(value_low);
self.push(value_high);
index
}
};

let rpl = match entry {
Descriptor::UserSegment(value) => {
if DescriptorFlags::from_bits_truncate(value).contains(DescriptorFlags::DPL_RING_3)
{
PrivilegeLevel::Ring3
} else {
PrivilegeLevel::Ring0
}
let rpl = match entry {
Descriptor::UserSegment(value) => {
if DescriptorFlags::from_bits_truncate(value).contains(DescriptorFlags::DPL_RING_3)
{
PrivilegeLevel::Ring3
} else {
PrivilegeLevel::Ring0
}
Descriptor::SystemSegment(_, _) => PrivilegeLevel::Ring0,
};
}
Descriptor::SystemSegment(_, _) => PrivilegeLevel::Ring0,
};

SegmentSelector::new(index as u16, rpl)
}
SegmentSelector::new(index as u16, rpl)
}

/// Loads the GDT in the CPU using the `lgdt` instruction. This does **not** alter any of the
@@ -156,17 +154,16 @@ impl GlobalDescriptorTable {
}
}

const_fn! {
#[inline]
fn push(&mut self, value: u64) -> usize {
if self.next_free < self.table.len() {
let index = self.next_free;
self.table[index] = value;
self.next_free += 1;
index
} else {
panic!("GDT full");
}
#[inline]
#[cfg_attr(feature = "const_fn", rustversion::attr(all(), const))]
fn push(&mut self, value: u64) -> usize {
if self.next_free < self.table.len() {
let index = self.next_free;
self.table[index] = value;
self.next_free += 1;
index
} else {
panic!("GDT full");
}
}

64 changes: 31 additions & 33 deletions src/structures/idt.rs
Original file line number Diff line number Diff line change
@@ -410,39 +410,37 @@ pub struct InterruptDescriptorTable {
}

impl InterruptDescriptorTable {
// TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61
const_fn! {
/// Creates a new IDT filled with non-present entries.
#[inline]
pub fn new() -> InterruptDescriptorTable {
InterruptDescriptorTable {
divide_error: Entry::missing(),
debug: Entry::missing(),
non_maskable_interrupt: Entry::missing(),
breakpoint: Entry::missing(),
overflow: Entry::missing(),
bound_range_exceeded: Entry::missing(),
invalid_opcode: Entry::missing(),
device_not_available: Entry::missing(),
double_fault: Entry::missing(),
coprocessor_segment_overrun: Entry::missing(),
invalid_tss: Entry::missing(),
segment_not_present: Entry::missing(),
stack_segment_fault: Entry::missing(),
general_protection_fault: Entry::missing(),
page_fault: Entry::missing(),
reserved_1: Entry::missing(),
x87_floating_point: Entry::missing(),
alignment_check: Entry::missing(),
machine_check: Entry::missing(),
simd_floating_point: Entry::missing(),
virtualization: Entry::missing(),
reserved_2: [Entry::missing(); 8],
vmm_communication_exception: Entry::missing(),
security_exception: Entry::missing(),
reserved_3: Entry::missing(),
interrupts: [Entry::missing(); 256 - 32],
}
/// Creates a new IDT filled with non-present entries.
#[inline]
#[rustversion::attr(since(1.61), const)]
pub fn new() -> InterruptDescriptorTable {
InterruptDescriptorTable {
divide_error: Entry::missing(),
debug: Entry::missing(),
non_maskable_interrupt: Entry::missing(),
breakpoint: Entry::missing(),
overflow: Entry::missing(),
bound_range_exceeded: Entry::missing(),
invalid_opcode: Entry::missing(),
device_not_available: Entry::missing(),
double_fault: Entry::missing(),
coprocessor_segment_overrun: Entry::missing(),
invalid_tss: Entry::missing(),
segment_not_present: Entry::missing(),
stack_segment_fault: Entry::missing(),
general_protection_fault: Entry::missing(),
page_fault: Entry::missing(),
reserved_1: Entry::missing(),
x87_floating_point: Entry::missing(),
alignment_check: Entry::missing(),
machine_check: Entry::missing(),
simd_floating_point: Entry::missing(),
virtualization: Entry::missing(),
reserved_2: [Entry::missing(); 8],
vmm_communication_exception: Entry::missing(),
security_exception: Entry::missing(),
reserved_3: Entry::missing(),
interrupts: [Entry::missing(); 256 - 32],
}
}

72 changes: 31 additions & 41 deletions src/structures/paging/frame.rs
Original file line number Diff line number Diff line change
@@ -30,19 +30,17 @@ impl<S: PageSize> PhysFrame<S> {
Ok(unsafe { PhysFrame::from_start_address_unchecked(address) })
}

// TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61
const_fn! {
/// Returns the frame that starts at the given virtual address.
///
/// ## Safety
///
/// The address must be correctly aligned.
#[inline]
pub unsafe fn from_start_address_unchecked(start_address: PhysAddr) -> Self {
PhysFrame {
start_address,
size: PhantomData,
}
/// Returns the frame that starts at the given virtual address.
///
/// ## Safety
///
/// The address must be correctly aligned.
#[inline]
#[rustversion::attr(since(1.61), const)]
pub unsafe fn from_start_address_unchecked(start_address: PhysAddr) -> Self {
PhysFrame {
start_address,
size: PhantomData,
}
}

@@ -55,40 +53,32 @@ impl<S: PageSize> PhysFrame<S> {
}
}

// TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61
const_fn! {
/// Returns the start address of the frame.
#[inline]
pub fn start_address(self) -> PhysAddr {
self.start_address
}
/// Returns the start address of the frame.
#[inline]
#[rustversion::attr(since(1.61), const)]
pub fn start_address(self) -> PhysAddr {
self.start_address
}

// TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61
const_fn! {
/// Returns the size the frame (4KB, 2MB or 1GB).
#[inline]
pub fn size(self) -> u64 {
S::SIZE
}
/// Returns the size the frame (4KB, 2MB or 1GB).
#[inline]
#[rustversion::attr(since(1.61), const)]
pub fn size(self) -> u64 {
S::SIZE
}

// TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61
const_fn! {
/// Returns a range of frames, exclusive `end`.
#[inline]
pub fn range(start: PhysFrame<S>, end: PhysFrame<S>) -> PhysFrameRange<S> {
PhysFrameRange { start, end }
}
/// Returns a range of frames, exclusive `end`.
#[inline]
#[rustversion::attr(since(1.61), const)]
pub fn range(start: PhysFrame<S>, end: PhysFrame<S>) -> PhysFrameRange<S> {
PhysFrameRange { start, end }
}

// TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61
const_fn! {
/// Returns a range of frames, inclusive `end`.
#[inline]
pub fn range_inclusive(start: PhysFrame<S>, end: PhysFrame<S>) -> PhysFrameRangeInclusive<S> {
PhysFrameRangeInclusive { start, end }
}
/// Returns a range of frames, inclusive `end`.
#[inline]
#[rustversion::attr(since(1.61), const)]
pub fn range_inclusive(start: PhysFrame<S>, end: PhysFrame<S>) -> PhysFrameRangeInclusive<S> {
PhysFrameRangeInclusive { start, end }
}
}

120 changes: 51 additions & 69 deletions src/structures/paging/page.rs
Original file line number Diff line number Diff line change
@@ -77,19 +77,17 @@ impl<S: PageSize> Page<S> {
Ok(Page::containing_address(address))
}

// TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61
const_fn! {
/// Returns the page that starts at the given virtual address.
///
/// ## Safety
///
/// The address must be correctly aligned.
#[inline]
pub unsafe fn from_start_address_unchecked(start_address: VirtAddr) -> Self {
Page {
start_address,
size: PhantomData,
}
/// Returns the page that starts at the given virtual address.
///
/// ## Safety
///
/// The address must be correctly aligned.
#[inline]
#[rustversion::attr(since(1.61), const)]
pub unsafe fn from_start_address_unchecked(start_address: VirtAddr) -> Self {
Page {
start_address,
size: PhantomData,
}
}

@@ -102,78 +100,62 @@ impl<S: PageSize> Page<S> {
}
}

// TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61
const_fn! {
/// Returns the start address of the page.
#[inline]
pub fn start_address(self) -> VirtAddr {
self.start_address
}
/// Returns the start address of the page.
#[inline]
#[rustversion::attr(since(1.61), const)]
pub fn start_address(self) -> VirtAddr {
self.start_address
}

// TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61
const_fn! {
/// Returns the size the page (4KB, 2MB or 1GB).
#[inline]
pub fn size(self) -> u64 {
S::SIZE
}
/// Returns the size the page (4KB, 2MB or 1GB).
#[inline]
#[rustversion::attr(since(1.61), const)]
pub fn size(self) -> u64 {
S::SIZE
}

// TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61
const_fn! {
/// Returns the level 4 page table index of this page.
#[inline]
pub fn p4_index(self) -> PageTableIndex {
self.start_address().p4_index()
}
/// Returns the level 4 page table index of this page.
#[inline]
#[rustversion::attr(since(1.61), const)]
pub fn p4_index(self) -> PageTableIndex {
self.start_address().p4_index()
}

// TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61
const_fn! {
/// Returns the level 3 page table index of this page.
#[inline]
pub fn p3_index(self) -> PageTableIndex {
self.start_address().p3_index()
}
/// Returns the level 3 page table index of this page.
#[inline]
#[rustversion::attr(since(1.61), const)]
pub fn p3_index(self) -> PageTableIndex {
self.start_address().p3_index()
}

// TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61
const_fn! {
/// Returns the table index of this page at the specified level.
#[inline]
pub fn page_table_index(self, level: PageTableLevel) -> PageTableIndex {
self.start_address().page_table_index(level)
}
/// Returns the table index of this page at the specified level.
#[inline]
#[rustversion::attr(since(1.61), const)]
pub fn page_table_index(self, level: PageTableLevel) -> PageTableIndex {
self.start_address().page_table_index(level)
}

// TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61
const_fn! {
/// Returns a range of pages, exclusive `end`.
#[inline]
pub fn range(start: Self, end: Self) -> PageRange<S> {
PageRange { start, end }
}
/// Returns a range of pages, exclusive `end`.
#[inline]
#[rustversion::attr(since(1.61), const)]
pub fn range(start: Self, end: Self) -> PageRange<S> {
PageRange { start, end }
}

// TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61
const_fn! {
/// Returns a range of pages, inclusive `end`.
#[inline]
pub fn range_inclusive(start: Self, end: Self) -> PageRangeInclusive<S> {
PageRangeInclusive { start, end }
}
/// Returns a range of pages, inclusive `end`.
#[inline]
#[rustversion::attr(since(1.61), const)]
pub fn range_inclusive(start: Self, end: Self) -> PageRangeInclusive<S> {
PageRangeInclusive { start, end }
}
}

impl<S: NotGiantPageSize> Page<S> {
// TODO: Remove const_fn! when our minimum supported stable Rust version is 1.61
const_fn! {
/// Returns the level 2 page table index of this page.
#[inline]
pub fn p2_index(self) -> PageTableIndex {
self.start_address().p2_index()
}
/// Returns the level 2 page table index of this page.
#[inline]
#[rustversion::attr(since(1.61), const)]
pub fn p2_index(self) -> PageTableIndex {
self.start_address().p2_index()
}
}