From 67be0e65a636d86c06e9f4d84926bf64b4b38caf Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Tue, 22 Jun 2021 04:42:14 -0700 Subject: [PATCH 1/4] Make align_up and align_down const We can't make VirtAddr and PhysAddr methods const as they wrap an into impl. --- src/addr.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/addr.rs b/src/addr.rs index 5cac6c2db..2b064f718 100644 --- a/src/addr.rs +++ b/src/addr.rs @@ -534,8 +534,12 @@ impl Sub for PhysAddr { /// Returns the greatest x with alignment `align` so that x <= addr. The alignment must be /// a power of 2. #[inline] -pub fn align_down(addr: u64, align: u64) -> u64 { +pub const fn align_down(addr: u64, align: u64) -> u64 { + #[cfg(feature = "const_fn")] assert!(align.is_power_of_two(), "`align` must be a power of two"); + #[cfg(not(feature = "const_fn"))] + [(); 1][!align.is_power_of_two() as usize]; + addr & !(align - 1) } @@ -544,8 +548,12 @@ pub fn align_down(addr: u64, align: u64) -> u64 { /// Returns the smallest x with alignment `align` so that x >= addr. The alignment must be /// a power of 2. #[inline] -pub fn align_up(addr: u64, align: u64) -> u64 { +pub const fn align_up(addr: u64, align: u64) -> u64 { + #[cfg(feature = "const_fn")] assert!(align.is_power_of_two(), "`align` must be a power of two"); + #[cfg(not(feature = "const_fn"))] + [(); 1][!align.is_power_of_two() as usize]; + let align_mask = align - 1; if addr & align_mask == 0 { addr // already aligned From e501deaecb4f4c255a6a3746e039450e10d9b14e Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Fri, 16 Jul 2021 01:56:28 -0700 Subject: [PATCH 2/4] const_fn: Add const_assert helper macro Signed-off-by: Joe Richey --- src/lib.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 42be18368..cf146e31a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,6 +45,19 @@ macro_rules! const_fn { }; } +// Helper method for assert! in const fn. Uses out of bounds indexing if an +// assertion fails and the "const_fn" feature is not enabled. +#[cfg(feature = "const_fn")] +macro_rules! const_assert { + ($cond:expr, $($arg:tt)+) => { assert!($cond, $($arg)*) }; +} +#[cfg(not(feature = "const_fn"))] +macro_rules! const_assert { + ($cond:expr, $($arg:tt)+) => { + [(); 1][!($cond as bool) as usize] + }; +} + #[cfg(all(feature = "instructions", feature = "external_asm"))] pub(crate) mod asm; From 2bbaebbfcf6295ecb051fbd611a870cf66737f51 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Fri, 16 Jul 2021 01:57:03 -0700 Subject: [PATCH 3/4] const_fn: Use const_assert helper macro Signed-off-by: Joe Richey --- src/addr.rs | 12 ++---------- src/structures/gdt.rs | 5 +---- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/src/addr.rs b/src/addr.rs index 2b064f718..942376095 100644 --- a/src/addr.rs +++ b/src/addr.rs @@ -535,11 +535,7 @@ impl Sub for PhysAddr { /// a power of 2. #[inline] pub const fn align_down(addr: u64, align: u64) -> u64 { - #[cfg(feature = "const_fn")] - assert!(align.is_power_of_two(), "`align` must be a power of two"); - #[cfg(not(feature = "const_fn"))] - [(); 1][!align.is_power_of_two() as usize]; - + const_assert!(align.is_power_of_two(), "`align` must be a power of two"); addr & !(align - 1) } @@ -549,11 +545,7 @@ pub const fn align_down(addr: u64, align: u64) -> u64 { /// a power of 2. #[inline] pub const fn align_up(addr: u64, align: u64) -> u64 { - #[cfg(feature = "const_fn")] - assert!(align.is_power_of_two(), "`align` must be a power of two"); - #[cfg(not(feature = "const_fn"))] - [(); 1][!align.is_power_of_two() as usize]; - + const_assert!(align.is_power_of_two(), "`align` must be a power of two"); let align_mask = align - 1; if addr & align_mask == 0 { addr // already aligned diff --git a/src/structures/gdt.rs b/src/structures/gdt.rs index f71a8c11c..aa95ccf61 100644 --- a/src/structures/gdt.rs +++ b/src/structures/gdt.rs @@ -117,13 +117,10 @@ impl GlobalDescriptorTable { let mut table = [0; 8]; let mut idx = 0; - #[cfg(feature = "const_fn")] - assert!( + const_assert!( next_free <= 8, "initializing a GDT from a slice requires it to be **at most** 8 elements." ); - #[cfg(not(feature = "const_fn"))] - [(); 1][!(next_free <= 8) as usize]; while idx != next_free { table[idx] = slice[idx]; From 45d7c847bbf7cc1000078d7e6b3104498e0afc00 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Fri, 16 Jul 2021 01:57:22 -0700 Subject: [PATCH 4/4] Update documentation to note the weird panic message. Signed-off-by: Joe Richey --- src/addr.rs | 12 ++++++++---- src/structures/gdt.rs | 3 ++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/addr.rs b/src/addr.rs index 942376095..1c93f0219 100644 --- a/src/addr.rs +++ b/src/addr.rs @@ -531,8 +531,10 @@ impl Sub for PhysAddr { /// Align address downwards. /// -/// Returns the greatest x with alignment `align` so that x <= addr. The alignment must be -/// a power of 2. +/// 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". #[inline] pub const fn align_down(addr: u64, align: u64) -> u64 { const_assert!(align.is_power_of_two(), "`align` must be a power of two"); @@ -541,8 +543,10 @@ pub const fn align_down(addr: u64, align: u64) -> u64 { /// Align address upwards. /// -/// Returns the smallest x with alignment `align` so that x >= addr. The alignment must be -/// a power of 2. +/// 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". #[inline] pub const fn align_up(addr: u64, align: u64) -> u64 { const_assert!(align.is_power_of_two(), "`align` must be a power of two"); diff --git a/src/structures/gdt.rs b/src/structures/gdt.rs index aa95ccf61..c96d81161 100644 --- a/src/structures/gdt.rs +++ b/src/structures/gdt.rs @@ -141,7 +141,8 @@ impl GlobalDescriptorTable { const_fn! { /// Adds the given segment descriptor to the GDT, returning the segment selector. /// - /// Panics if the GDT has no free entries left. + /// 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 {