From a9c3dc8135dd176b6547d2dd136555adfbfd0b2a Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Fri, 24 May 2024 12:16:29 +0200 Subject: [PATCH 01/30] fix indentation in doc comments --- src/registers/model_specific.rs | 16 ++++++++-------- src/structures/idt.rs | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/registers/model_specific.rs b/src/registers/model_specific.rs index 07504878..0471bfae 100644 --- a/src/registers/model_specific.rs +++ b/src/registers/model_specific.rs @@ -357,11 +357,11 @@ mod x86_64 { /// /// # Returns /// - Field 1 (SYSRET): The CS selector is set to this field + 16. SS.Sel is set to - /// this field + 8. Because SYSRET always returns to CPL 3, the - /// RPL bits 1:0 should be initialized to 11b. + /// this field + 8. Because SYSRET always returns to CPL 3, the + /// RPL bits 1:0 should be initialized to 11b. /// - Field 2 (SYSCALL): This field is copied directly into CS.Sel. SS.Sel is set to - /// this field + 8. Because SYSCALL always switches to CPL 0, the RPL bits - /// 33:32 should be initialized to 00b. + /// this field + 8. Because SYSCALL always switches to CPL 0, the RPL bits + /// 33:32 should be initialized to 00b. #[inline] pub fn read_raw() -> (u16, u16) { let msr_value = unsafe { Self::MSR.read() }; @@ -398,11 +398,11 @@ mod x86_64 { /// /// # Parameters /// - sysret: The CS selector is set to this field + 16. SS.Sel is set to - /// this field + 8. Because SYSRET always returns to CPL 3, the - /// RPL bits 1:0 should be initialized to 11b. + /// this field + 8. Because SYSRET always returns to CPL 3, the + /// RPL bits 1:0 should be initialized to 11b. /// - syscall: This field is copied directly into CS.Sel. SS.Sel is set to - /// this field + 8. Because SYSCALL always switches to CPL 0, the RPL bits - /// 33:32 should be initialized to 00b. + /// this field + 8. Because SYSCALL always switches to CPL 0, the RPL bits + /// 33:32 should be initialized to 00b. /// /// # Safety /// diff --git a/src/structures/idt.rs b/src/structures/idt.rs index 2d9beb5a..2883bb68 100644 --- a/src/structures/idt.rs +++ b/src/structures/idt.rs @@ -153,9 +153,9 @@ pub struct InterruptDescriptorTable { /// is enabled. /// - Execution of any legacy SSE instruction when `CR4.OSFXSR` is cleared to 0. /// - Execution of any SSE instruction (uses `YMM`/`XMM` registers), or 64-bit media - /// instruction (uses `MMXTM` registers) when `CR0.EM` = 1. + /// instruction (uses `MMXTM` registers) when `CR0.EM` = 1. /// - Execution of any SSE floating-point instruction (uses `YMM`/`XMM` registers) that - /// causes a numeric exception when `CR4.OSXMMEXCPT` = 0. + /// causes a numeric exception when `CR4.OSXMMEXCPT` = 0. /// - Use of the `DR4` or `DR5` debug registers when `CR4.DE` = 1. /// - Execution of `RSM` when not in `SMM` mode. /// @@ -503,7 +503,7 @@ impl InterruptDescriptorTable { /// /// - `self` is never destroyed. /// - `self` always stays at the same memory location. It is recommended to wrap it in - /// a `Box`. + /// a `Box`. /// #[cfg(all(feature = "instructions", target_arch = "x86_64"))] #[inline] From a98580e4ccc03f6fb4132b529cd2176c0da06a3d Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Fri, 24 May 2024 12:17:36 +0200 Subject: [PATCH 02/30] fix warnings in tests --- src/structures/idt.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/structures/idt.rs b/src/structures/idt.rs index 2883bb68..4a92bacf 100644 --- a/src/structures/idt.rs +++ b/src/structures/idt.rs @@ -1642,7 +1642,7 @@ mod test { #[test] fn entry_derive_test() { - fn foo(_: impl Clone + Copy + PartialEq + fmt::Debug) {} + fn foo(_: impl Copy + PartialEq + fmt::Debug) {} foo(Entry:: { pointer_low: 0, @@ -1667,9 +1667,7 @@ mod test { }); unsafe { - frame - .as_mut() - .update(|f| f.instruction_pointer = f.instruction_pointer + 2u64); + frame.as_mut().update(|f| f.instruction_pointer += 2u64); } } } From 3eaf06f0763f8d964377186b53ccadfabe470862 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Sun, 9 Jun 2024 14:15:32 +0000 Subject: [PATCH 03/30] add private const variants for PhysAddr functions Much like 4aaa21c7267119dfa13602e19ec2eafa41d6f112, but for PhysAddr. --- src/addr.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/addr.rs b/src/addr.rs index 19031986..8afe53f3 100644 --- a/src/addr.rs +++ b/src/addr.rs @@ -495,7 +495,15 @@ impl PhysAddr { where U: Into, { - PhysAddr(align_down(self.0, align.into())) + self.align_down_u64(align.into()) + } + + /// Aligns the physical address downwards to the given alignment. + /// + /// See the `align_down` function for more information. + #[inline] + pub(crate) const fn align_down_u64(self, align: u64) -> Self { + PhysAddr(align_down(self.0, align)) } /// Checks whether the physical address has the demanded alignment. @@ -504,7 +512,13 @@ impl PhysAddr { where U: Into, { - self.align_down(align) == self + self.is_aligned_u64(align.into()) + } + + /// Checks whether the physical address has the demanded alignment. + #[inline] + pub(crate) const fn is_aligned_u64(self, align: u64) -> bool { + self.align_down_u64(align).as_u64() == self.as_u64() } } From c5bc9fcefdeb99286fd00793a0c840b142114349 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Sun, 9 Jun 2024 14:16:32 +0000 Subject: [PATCH 04/30] constify PhysFrame functions --- src/structures/paging/frame.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/structures/paging/frame.rs b/src/structures/paging/frame.rs index 6cae8fab..1e5862b6 100644 --- a/src/structures/paging/frame.rs +++ b/src/structures/paging/frame.rs @@ -21,8 +21,9 @@ impl PhysFrame { /// /// Returns an error if the address is not correctly aligned (i.e. is not a valid frame start). #[inline] + #[rustversion::attr(since(1.61), const)] pub fn from_start_address(address: PhysAddr) -> Result { - if !address.is_aligned(S::SIZE) { + if !address.is_aligned_u64(S::SIZE) { return Err(AddressNotAligned); } @@ -46,9 +47,10 @@ impl PhysFrame { /// Returns the frame that contains the given physical address. #[inline] + #[rustversion::attr(since(1.61), const)] pub fn containing_address(address: PhysAddr) -> Self { PhysFrame { - start_address: address.align_down(S::SIZE), + start_address: address.align_down_u64(S::SIZE), size: PhantomData, } } From b0843da89f65d4acb18d46a9776252af38bf6852 Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Thu, 4 Jul 2024 16:26:59 +0200 Subject: [PATCH 05/30] Ensure that Page actually implements Hash --- src/structures/paging/page.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/structures/paging/page.rs b/src/structures/paging/page.rs index e05b576d..445abd26 100644 --- a/src/structures/paging/page.rs +++ b/src/structures/paging/page.rs @@ -23,17 +23,17 @@ pub trait PageSize: Copy + Eq + PartialOrd + Ord + Sealed { pub trait NotGiantPageSize: PageSize {} /// A standard 4KiB page. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Size4KiB {} /// A “huge” 2MiB page. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Size2MiB {} /// A “giant” 1GiB page. /// /// (Only available on newer x86_64 CPUs.) -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Size1GiB {} impl PageSize for Size4KiB { @@ -429,6 +429,15 @@ impl fmt::Display for AddressNotAligned { mod tests { use super::*; + fn test_is_hash() {} + + #[test] + pub fn test_page_is_hash() { + test_is_hash::>(); + test_is_hash::>(); + test_is_hash::>(); + } + #[test] pub fn test_page_ranges() { let page_size = Size4KiB::SIZE; From 3fec974dadc45b7cf2507af1937fe95eb42ecb1e Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Sun, 14 Jul 2024 16:22:20 +0200 Subject: [PATCH 06/30] don't use label starting with `1` Starting with the latest nightly, this results in an error: error: avoid using labels containing only the digits `0` and `1` in inline assembly --> src/instructions/segmentation.rs:81:18 | 81 | "1:", | ^ use a different label that doesn't start with `0` or `1` | = note: an LLVM bug makes these labels ambiguous with a binary literal number = note: `#[deny(binary_asm_labels)]` on by default --- src/instructions/segmentation.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/instructions/segmentation.rs b/src/instructions/segmentation.rs index f170b083..c8fbfbab 100644 --- a/src/instructions/segmentation.rs +++ b/src/instructions/segmentation.rs @@ -75,10 +75,10 @@ impl Segment for CS { unsafe { asm!( "push {sel}", - "lea {tmp}, [1f + rip]", + "lea {tmp}, [55f + rip]", "push {tmp}", "retfq", - "1:", + "55:", sel = in(reg) u64::from(sel.0), tmp = lateout(reg) _, options(preserves_flags), From ae65fb6808a2de39646d9cf0fa878ae7ed1b6b4a Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Sun, 14 Jul 2024 15:47:37 +0200 Subject: [PATCH 07/30] Add size and len for PageRange, PhysFrameRange etc --- Changelog.md | 4 +++ src/structures/paging/frame.rs | 49 ++++++++++++++++++++++++++++++++++ src/structures/paging/page.rs | 45 +++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+) diff --git a/Changelog.md b/Changelog.md index 10772bf7..f517e673 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,9 @@ # Unreleased +## New Features + +- [add `size` and `len` for `PageRange`, `PhysFrameRange`, `PageRangeInclusive` and `PhysFrameRangeInclusive`](https://github.com/rust-osdev/x86_64/pull/491) + # 0.15.1 – 2024-03-19 ## New Features diff --git a/src/structures/paging/frame.rs b/src/structures/paging/frame.rs index 1e5862b6..c4a8c97a 100644 --- a/src/structures/paging/frame.rs +++ b/src/structures/paging/frame.rs @@ -148,6 +148,22 @@ impl PhysFrameRange { pub fn is_empty(&self) -> bool { self.start >= self.end } + + /// Returns the number of frames in the range. + #[inline] + pub fn len(&self) -> u64 { + if !self.is_empty() { + self.end - self.start + } else { + 0 + } + } + + /// Returns the size in bytes of all frames within the range. + #[inline] + pub fn size(&self) -> u64 { + S::SIZE * self.len() + } } impl Iterator for PhysFrameRange { @@ -190,6 +206,22 @@ impl PhysFrameRangeInclusive { pub fn is_empty(&self) -> bool { self.start > self.end } + + /// Returns the number of frames in the range. + #[inline] + pub fn len(&self) -> u64 { + if !self.is_empty() { + self.end - self.start + 1 + } else { + 0 + } + } + + /// Returns the size in bytes of all frames within the range. + #[inline] + pub fn size(&self) -> u64 { + S::SIZE * self.len() + } } impl Iterator for PhysFrameRangeInclusive { @@ -215,3 +247,20 @@ impl fmt::Debug for PhysFrameRangeInclusive { .finish() } } + +#[cfg(test)] +mod tests { + use super::*; + #[test] + pub fn test_frame_range_len() { + let start_addr = PhysAddr::new(0xdead_beaf); + let start = PhysFrame::::containing_address(start_addr); + let end = start + 50; + + let range = PhysFrameRange { start, end }; + assert_eq!(range.len(), 50); + + let range_inclusive = PhysFrameRangeInclusive { start, end }; + assert_eq!(range_inclusive.len(), 51); + } +} diff --git a/src/structures/paging/page.rs b/src/structures/paging/page.rs index 445abd26..55720cf4 100644 --- a/src/structures/paging/page.rs +++ b/src/structures/paging/page.rs @@ -327,6 +327,22 @@ impl PageRange { pub fn is_empty(&self) -> bool { self.start >= self.end } + + /// Returns the number of pages in the range. + #[inline] + pub fn len(&self) -> u64 { + if !self.is_empty() { + self.end - self.start + } else { + 0 + } + } + + /// Returns the size in bytes of all pages within the range. + #[inline] + pub fn size(&self) -> u64 { + S::SIZE * self.len() + } } impl Iterator for PageRange { @@ -380,6 +396,22 @@ impl PageRangeInclusive { pub fn is_empty(&self) -> bool { self.start > self.end } + + /// Returns the number of frames in the range. + #[inline] + pub fn len(&self) -> u64 { + if !self.is_empty() { + self.end - self.start + 1 + } else { + 0 + } + } + + /// Returns the size in bytes of all frames within the range. + #[inline] + pub fn size(&self) -> u64 { + S::SIZE * self.len() + } } impl Iterator for PageRangeInclusive { @@ -484,4 +516,17 @@ mod tests { } assert_eq!(range_inclusive.next(), None); } + + #[test] + pub fn test_page_range_len() { + let start_addr = VirtAddr::new(0xdead_beaf); + let start = Page::::containing_address(start_addr); + let end = start + 50; + + let range = PageRange { start, end }; + assert_eq!(range.len(), 50); + + let range_inclusive = PageRangeInclusive { start, end }; + assert_eq!(range_inclusive.len(), 51); + } } From b34996173fe1f9ff94160d1a7319f5af95583525 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Wed, 31 Jul 2024 12:36:15 +0200 Subject: [PATCH 08/30] fix warning in integration test --- testing/src/gdt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/src/gdt.rs b/testing/src/gdt.rs index 2fa192dd..28620921 100644 --- a/testing/src/gdt.rs +++ b/testing/src/gdt.rs @@ -13,7 +13,7 @@ lazy_static! { const STACK_SIZE: usize = 4096; static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; - let stack_start = VirtAddr::from_ptr(unsafe { ptr::addr_of!(STACK) }); + let stack_start = VirtAddr::from_ptr(ptr::addr_of!(STACK)); let stack_end = stack_start + STACK_SIZE as u64; stack_end }; From 9dca072c91e104c57007ad5b5e7661f0c61fa41a Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Thu, 15 Aug 2024 08:16:24 +0200 Subject: [PATCH 09/30] remove #![feature(asm_const)] This feature will be stable as of Rust 1.80 and so enabling it explicitly throws a warning. --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 0f0ee2b1..8decec3e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,6 @@ #![cfg_attr(not(test), no_std)] #![cfg_attr(feature = "const_fn", feature(const_mut_refs))] // GDT::append() -#![cfg_attr(feature = "asm_const", feature(asm_const))] #![cfg_attr(feature = "abi_x86_interrupt", feature(abi_x86_interrupt))] #![cfg_attr(feature = "step_trait", feature(step_trait))] #![cfg_attr(feature = "doc_auto_cfg", feature(doc_auto_cfg))] From d3e28e9065e2f526ff339956f5a1f4b3eb33769c Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Mon, 7 Oct 2024 20:43:47 +0200 Subject: [PATCH 10/30] Remove stabilized `const_mut_refs` feature Make `GDT::append` and `GDT::push` `const` by default. The `const_fn` feature is now a no-op. --- Cargo.toml | 3 ++- src/lib.rs | 1 - src/structures/gdt.rs | 6 ++---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5d53caae..b48dae0b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,8 +28,9 @@ rustversion = "1.0.5" [features] default = ["nightly", "instructions"] instructions = [] -nightly = [ "const_fn", "step_trait", "abi_x86_interrupt", "asm_const" ] +nightly = ["const_fn", "step_trait", "abi_x86_interrupt", "asm_const"] abi_x86_interrupt = [] +# deprecated, no longer needed const_fn = [] asm_const = [] step_trait = [] diff --git a/src/lib.rs b/src/lib.rs index 8decec3e..08b30ee9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,6 @@ //! and access to various system registers. #![cfg_attr(not(test), no_std)] -#![cfg_attr(feature = "const_fn", feature(const_mut_refs))] // GDT::append() #![cfg_attr(feature = "abi_x86_interrupt", feature(abi_x86_interrupt))] #![cfg_attr(feature = "step_trait", feature(step_trait))] #![cfg_attr(feature = "doc_auto_cfg", feature(doc_auto_cfg))] diff --git a/src/structures/gdt.rs b/src/structures/gdt.rs index c04b4e42..b2725a46 100644 --- a/src/structures/gdt.rs +++ b/src/structures/gdt.rs @@ -193,8 +193,7 @@ impl GlobalDescriptorTable { /// /// Panics if the GDT doesn't have enough free entries. #[inline] - #[cfg_attr(feature = "const_fn", rustversion::attr(all(), const))] - pub fn append(&mut self, entry: Descriptor) -> SegmentSelector { + pub const fn append(&mut self, entry: Descriptor) -> SegmentSelector { let index = match entry { Descriptor::UserSegment(value) => { if self.len > self.table.len().saturating_sub(1) { @@ -246,8 +245,7 @@ impl GlobalDescriptorTable { } #[inline] - #[cfg_attr(feature = "const_fn", rustversion::attr(all(), const))] - fn push(&mut self, value: u64) -> usize { + const fn push(&mut self, value: u64) -> usize { let index = self.len; self.table[index] = Entry::new(value); self.len += 1; From eec5d2554a40f6f981beba7282b094460df361b9 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Mon, 7 Oct 2024 20:47:26 +0200 Subject: [PATCH 11/30] Break long doc paragraph --- src/instructions/mod.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/instructions/mod.rs b/src/instructions/mod.rs index 4b676c55..8018698c 100644 --- a/src/instructions/mod.rs +++ b/src/instructions/mod.rs @@ -32,8 +32,11 @@ pub fn nop() { } } -/// Emits a '[magic breakpoint](https://wiki.osdev.org/Bochs#Magic_Breakpoint)' instruction for the [Bochs](http://bochs.sourceforge.net/) CPU -/// emulator. Make sure to set `magic_break: enabled=1` in your `.bochsrc` file. +/// Emits a '[magic breakpoint](https://wiki.osdev.org/Bochs#Magic_Breakpoint)' +/// instruction for the [Bochs](http://bochs.sourceforge.net/) CPU +/// emulator. +/// +/// Make sure to set `magic_break: enabled=1` in your `.bochsrc` file. #[inline] pub fn bochs_breakpoint() { unsafe { From 1829dc13b1777c3d6c0f3d6195bd026366fb7188 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Mon, 7 Oct 2024 20:49:11 +0200 Subject: [PATCH 12/30] Elide explicit lifetimes when possible --- src/structures/paging/mapper/mapped_page_table.rs | 10 +++++----- src/structures/paging/mapper/offset_page_table.rs | 10 +++++----- src/structures/paging/mapper/recursive_page_table.rs | 10 +++++----- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/structures/paging/mapper/mapped_page_table.rs b/src/structures/paging/mapper/mapped_page_table.rs index 830b4759..b50f072e 100644 --- a/src/structures/paging/mapper/mapped_page_table.rs +++ b/src/structures/paging/mapper/mapped_page_table.rs @@ -150,7 +150,7 @@ impl<'a, P: PageTableFrameMapping> MappedPageTable<'a, P> { } } -impl<'a, P: PageTableFrameMapping> Mapper for MappedPageTable<'a, P> { +impl Mapper for MappedPageTable<'_, P> { #[inline] unsafe fn map_to_with_table_flags( &mut self, @@ -258,7 +258,7 @@ impl<'a, P: PageTableFrameMapping> Mapper for MappedPageTable<'a, P> { } } -impl<'a, P: PageTableFrameMapping> Mapper for MappedPageTable<'a, P> { +impl Mapper for MappedPageTable<'_, P> { #[inline] unsafe fn map_to_with_table_flags( &mut self, @@ -386,7 +386,7 @@ impl<'a, P: PageTableFrameMapping> Mapper for MappedPageTable<'a, P> { } } -impl<'a, P: PageTableFrameMapping> Mapper for MappedPageTable<'a, P> { +impl Mapper for MappedPageTable<'_, P> { #[inline] unsafe fn map_to_with_table_flags( &mut self, @@ -530,7 +530,7 @@ impl<'a, P: PageTableFrameMapping> Mapper for MappedPageTable<'a, P> { } } -impl<'a, P: PageTableFrameMapping> Translate for MappedPageTable<'a, P> { +impl Translate for MappedPageTable<'_, P> { #[allow(clippy::inconsistent_digit_grouping)] fn translate(&self, addr: VirtAddr) -> TranslateResult { let p4 = &self.level_4_table; @@ -594,7 +594,7 @@ impl<'a, P: PageTableFrameMapping> Translate for MappedPageTable<'a, P> { } } -impl<'a, P: PageTableFrameMapping> CleanUp for MappedPageTable<'a, P> { +impl CleanUp for MappedPageTable<'_, P> { #[inline] unsafe fn clean_up(&mut self, frame_deallocator: &mut D) where diff --git a/src/structures/paging/mapper/offset_page_table.rs b/src/structures/paging/mapper/offset_page_table.rs index 37c9cca2..6fb86e79 100644 --- a/src/structures/paging/mapper/offset_page_table.rs +++ b/src/structures/paging/mapper/offset_page_table.rs @@ -65,7 +65,7 @@ unsafe impl PageTableFrameMapping for PhysOffset { // delegate all trait implementations to inner -impl<'a> Mapper for OffsetPageTable<'a> { +impl Mapper for OffsetPageTable<'_> { #[inline] unsafe fn map_to_with_table_flags( &mut self, @@ -134,7 +134,7 @@ impl<'a> Mapper for OffsetPageTable<'a> { } } -impl<'a> Mapper for OffsetPageTable<'a> { +impl Mapper for OffsetPageTable<'_> { #[inline] unsafe fn map_to_with_table_flags( &mut self, @@ -203,7 +203,7 @@ impl<'a> Mapper for OffsetPageTable<'a> { } } -impl<'a> Mapper for OffsetPageTable<'a> { +impl Mapper for OffsetPageTable<'_> { #[inline] unsafe fn map_to_with_table_flags( &mut self, @@ -272,14 +272,14 @@ impl<'a> Mapper for OffsetPageTable<'a> { } } -impl<'a> Translate for OffsetPageTable<'a> { +impl Translate for OffsetPageTable<'_> { #[inline] fn translate(&self, addr: VirtAddr) -> TranslateResult { self.inner.translate(addr) } } -impl<'a> CleanUp for OffsetPageTable<'a> { +impl CleanUp for OffsetPageTable<'_> { #[inline] unsafe fn clean_up(&mut self, frame_deallocator: &mut D) where diff --git a/src/structures/paging/mapper/recursive_page_table.rs b/src/structures/paging/mapper/recursive_page_table.rs index 1e8a3b18..ff427ffa 100644 --- a/src/structures/paging/mapper/recursive_page_table.rs +++ b/src/structures/paging/mapper/recursive_page_table.rs @@ -299,7 +299,7 @@ impl<'a> RecursivePageTable<'a> { } } -impl<'a> Mapper for RecursivePageTable<'a> { +impl Mapper for RecursivePageTable<'_> { #[inline] unsafe fn map_to_with_table_flags( &mut self, @@ -419,7 +419,7 @@ impl<'a> Mapper for RecursivePageTable<'a> { } } -impl<'a> Mapper for RecursivePageTable<'a> { +impl Mapper for RecursivePageTable<'_> { #[inline] unsafe fn map_to_with_table_flags( &mut self, @@ -574,7 +574,7 @@ impl<'a> Mapper for RecursivePageTable<'a> { } } -impl<'a> Mapper for RecursivePageTable<'a> { +impl Mapper for RecursivePageTable<'_> { #[inline] unsafe fn map_to_with_table_flags( &mut self, @@ -763,7 +763,7 @@ impl<'a> Mapper for RecursivePageTable<'a> { } } -impl<'a> Translate for RecursivePageTable<'a> { +impl Translate for RecursivePageTable<'_> { #[allow(clippy::inconsistent_digit_grouping)] fn translate(&self, addr: VirtAddr) -> TranslateResult { let page = Page::containing_address(addr); @@ -836,7 +836,7 @@ impl<'a> Translate for RecursivePageTable<'a> { } } -impl<'a> CleanUp for RecursivePageTable<'a> { +impl CleanUp for RecursivePageTable<'_> { #[inline] unsafe fn clean_up(&mut self, frame_deallocator: &mut D) where From 0b5476eddefd21da725313fa22f24fc1a002a47a Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Mon, 21 Oct 2024 19:28:23 +0200 Subject: [PATCH 13/30] gate HandlerFunc behind target_arch = "x86{_64}" rustc is phasing out allowing the "x86-interrupt" ABI on non-x86 targets. Using "x86-interrupt" on a non-x86 target currently causes a warning, but this will become a hard error in a future version. Previously, if `abi_x86_interrupt` was enabled (it's enabled by default ), we used it in a pointer type for the declaration of the `HandlerFunc`- family of types and used a private empty tuple if `abi_x86_interrupt` wasn't enabled. This patch changes the cfg gate to only use the "x86-interrupt" abi on x86 targets. This is technically a breaking change, but I'd like to argue that we shouldn't treat it as such: The danger with treating this as a breaking change is that we can't release this fix as a patch update and so once rustc eventually treats this as an error, we might not yet have released the next breaking version leaving our users with not published fix. My hope is that there is no one using `HandlerFunc` on a non-x86 target. Even today, declaring a function (not just a function pointer) with the "x86-interrupt" abi on a non-x86 target causes an error, so it's unlikely that this will affect real code. It's technically possible to create a `HandlerFunc` on a non-x86 target by using transmute, but, again my hope is that no one is actually doing that. I'd also like to point out that the only use of a `HandlerFunc` on a non-x86 target would be to call set_handler_fn and any such calls could simply be replaced by calls to set_handler_addr. --- src/structures/idt.rs | 55 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/src/structures/idt.rs b/src/structures/idt.rs index 4a92bacf..1da184e7 100644 --- a/src/structures/idt.rs +++ b/src/structures/idt.rs @@ -712,52 +712,82 @@ impl PartialEq for Entry { /// A handler function for an interrupt or an exception without error code. /// /// This type alias is only usable with the `abi_x86_interrupt` feature enabled. -#[cfg(feature = "abi_x86_interrupt")] +#[cfg(all( + any(target_arch = "x86", target_arch = "x86_64"), + feature = "abi_x86_interrupt" +))] pub type HandlerFunc = extern "x86-interrupt" fn(InterruptStackFrame); /// This type is not usable without the `abi_x86_interrupt` feature. -#[cfg(not(feature = "abi_x86_interrupt"))] +#[cfg(not(all( + any(target_arch = "x86", target_arch = "x86_64"), + feature = "abi_x86_interrupt" +)))] #[derive(Copy, Clone, Debug)] pub struct HandlerFunc(()); /// A handler function for an exception that pushes an error code. /// /// This type alias is only usable with the `abi_x86_interrupt` feature enabled. -#[cfg(feature = "abi_x86_interrupt")] +#[cfg(all( + any(target_arch = "x86", target_arch = "x86_64"), + feature = "abi_x86_interrupt" +))] pub type HandlerFuncWithErrCode = extern "x86-interrupt" fn(InterruptStackFrame, error_code: u64); /// This type is not usable without the `abi_x86_interrupt` feature. -#[cfg(not(feature = "abi_x86_interrupt"))] +#[cfg(not(all( + any(target_arch = "x86", target_arch = "x86_64"), + feature = "abi_x86_interrupt" +)))] #[derive(Copy, Clone, Debug)] pub struct HandlerFuncWithErrCode(()); /// A page fault handler function that pushes a page fault error code. /// /// This type alias is only usable with the `abi_x86_interrupt` feature enabled. -#[cfg(feature = "abi_x86_interrupt")] +#[cfg(all( + any(target_arch = "x86", target_arch = "x86_64"), + feature = "abi_x86_interrupt" +))] pub type PageFaultHandlerFunc = extern "x86-interrupt" fn(InterruptStackFrame, error_code: PageFaultErrorCode); /// This type is not usable without the `abi_x86_interrupt` feature. -#[cfg(not(feature = "abi_x86_interrupt"))] +#[cfg(not(all( + any(target_arch = "x86", target_arch = "x86_64"), + feature = "abi_x86_interrupt" +)))] #[derive(Copy, Clone, Debug)] pub struct PageFaultHandlerFunc(()); /// A handler function that must not return, e.g. for a machine check exception. /// /// This type alias is only usable with the `abi_x86_interrupt` feature enabled. -#[cfg(feature = "abi_x86_interrupt")] +#[cfg(all( + any(target_arch = "x86", target_arch = "x86_64"), + feature = "abi_x86_interrupt" +))] pub type DivergingHandlerFunc = extern "x86-interrupt" fn(InterruptStackFrame) -> !; /// This type is not usable without the `abi_x86_interrupt` feature. -#[cfg(not(feature = "abi_x86_interrupt"))] +#[cfg(not(all( + any(target_arch = "x86", target_arch = "x86_64"), + feature = "abi_x86_interrupt" +)))] #[derive(Copy, Clone, Debug)] pub struct DivergingHandlerFunc(()); /// A handler function with an error code that must not return, e.g. for a double fault exception. /// /// This type alias is only usable with the `abi_x86_interrupt` feature enabled. -#[cfg(feature = "abi_x86_interrupt")] +#[cfg(all( + any(target_arch = "x86", target_arch = "x86_64"), + feature = "abi_x86_interrupt" +))] pub type DivergingHandlerFuncWithErrCode = extern "x86-interrupt" fn(InterruptStackFrame, error_code: u64) -> !; /// This type is not usable without the `abi_x86_interrupt` feature. -#[cfg(not(feature = "abi_x86_interrupt"))] +#[cfg(not(all( + any(target_arch = "x86", target_arch = "x86_64"), + feature = "abi_x86_interrupt" +)))] #[derive(Copy, Clone, Debug)] pub struct DivergingHandlerFuncWithErrCode(()); @@ -853,7 +883,10 @@ pub unsafe trait HandlerFuncType { macro_rules! impl_handler_func_type { ($f:ty) => { - #[cfg(feature = "abi_x86_interrupt")] + #[cfg(all( + any(target_arch = "x86", target_arch = "x86_64"), + feature = "abi_x86_interrupt" + ))] unsafe impl HandlerFuncType for $f { #[inline] fn to_virt_addr(self) -> VirtAddr { From 4bd1973be4255b62b1a1ffdf36d873b8fd3d293f Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Sun, 3 Nov 2024 13:33:59 +0100 Subject: [PATCH 14/30] fix field order for INVPCID descriptor Both Intel's and AMD's manuals describe the INVPCID descriptor as a 128-bit value with the linear address stored in the upper half and the PCID stored in the lower half. x86 uses little-endian byte ordering and so the lower half (pcid) should be stored before the upper half (address). Previously, our `InvpcidDescriptor` type stored the halves in the opposite order with the address before the pcid. This patch fixes the order, so that the pcid is stored before the address. This new order is also the order used by Linux and OpenBSD: https://github.com/torvalds/linux/blob/3e5e6c9900c3d71895e8bdeacfb579462e98eba1/arch/x86/include/asm/invpcid.h#L8 https://github.com/openbsd/src/blob/4e368faebf86e9a349446b5839c333bc17bd3f9a/sys/arch/amd64/include/cpufunc.h#L173 It's beyond me how this wasn't noticed earlier. The previous incorrect layout could lead to TLB entries not being flushed and #GP faults. --- src/instructions/tlb.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/instructions/tlb.rs b/src/instructions/tlb.rs index ea60fce7..8558f5f5 100644 --- a/src/instructions/tlb.rs +++ b/src/instructions/tlb.rs @@ -49,8 +49,8 @@ pub enum InvPicdCommand { #[repr(C)] #[derive(Debug)] struct InvpcidDescriptor { - address: u64, pcid: u64, + address: u64, } /// Structure of a PCID. A PCID has to be <= 4096 for x86_64. @@ -95,8 +95,8 @@ impl fmt::Display for PcidTooBig { #[inline] pub unsafe fn flush_pcid(command: InvPicdCommand) { let mut desc = InvpcidDescriptor { - address: 0, pcid: 0, + address: 0, }; let kind: u64; From e04530074e10bc54da4d860e02362672164f1042 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Tue, 12 Nov 2024 18:37:01 +0100 Subject: [PATCH 15/30] fix CI job for building on MSRV It turns out that dtolnay/rust-toolchain sets the installed toolchain as the global default, but rustup prioritizes our rust-toolchain.toml. Instead, set an environment variable. RUSTUP_TOOLCHAIN has a higher priority than rust-toolchain.toml [^1]. [^1]: https://rust-lang.github.io/rustup/overrides.html#overrides --- .github/workflows/build.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e64a6df0..a406cbba 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -26,6 +26,9 @@ jobs: - nightly - 1.59 runs-on: ubuntu-latest + env: + # rustup prioritizes environment variables over rust-toolchain.toml files. + RUSTUP_TOOLCHAIN: ${{ matrix.rust }} steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master From def4212444904a2d10fc78384661e5d8fcc36492 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Tue, 12 Nov 2024 18:42:21 +0100 Subject: [PATCH 16/30] only make append & push const on Rust 1.83+ --- src/structures/gdt.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/structures/gdt.rs b/src/structures/gdt.rs index b2725a46..e839fa6e 100644 --- a/src/structures/gdt.rs +++ b/src/structures/gdt.rs @@ -193,7 +193,8 @@ impl GlobalDescriptorTable { /// /// Panics if the GDT doesn't have enough free entries. #[inline] - pub const fn append(&mut self, entry: Descriptor) -> SegmentSelector { + #[rustversion::attr(since(1.83), const)] + pub fn append(&mut self, entry: Descriptor) -> SegmentSelector { let index = match entry { Descriptor::UserSegment(value) => { if self.len > self.table.len().saturating_sub(1) { @@ -245,7 +246,8 @@ impl GlobalDescriptorTable { } #[inline] - const fn push(&mut self, value: u64) -> usize { + #[rustversion::attr(since(1.83), const)] + fn push(&mut self, value: u64) -> usize { let index = self.len; self.table[index] = Entry::new(value); self.len += 1; From 199d614637ef7ee9c825bc667d9bbd2b0889e6c4 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Sun, 10 Nov 2024 09:51:51 +0100 Subject: [PATCH 17/30] fix typo in "InvPicdCommand" Rename the enum and add a deprecated type alias for the old name. --- src/instructions/tlb.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/instructions/tlb.rs b/src/instructions/tlb.rs index 8558f5f5..3f5c4467 100644 --- a/src/instructions/tlb.rs +++ b/src/instructions/tlb.rs @@ -30,7 +30,7 @@ pub fn flush_all() { /// The Invalidate PCID Command to execute. #[derive(Debug)] -pub enum InvPicdCommand { +pub enum InvPcidCommand { /// The logical processor invalidates mappings—except global translations—for the linear address and PCID specified. Address(VirtAddr, Pcid), @@ -44,6 +44,11 @@ pub enum InvPicdCommand { AllExceptGlobal, } +// TODO: Remove this in the next breaking release. +#[deprecated = "please use `InvPcidCommand` instead"] +#[doc(hidden)] +pub type InvPicdCommand = InvPcidCommand; + /// The INVPCID descriptor comprises 128 bits and consists of a PCID and a linear address. /// For INVPCID type 0, the processor uses the full 64 bits of the linear address even outside 64-bit mode; the linear address is not used for other INVPCID types. #[repr(C)] @@ -93,7 +98,7 @@ impl fmt::Display for PcidTooBig { /// /// This function is unsafe as it requires CPUID.(EAX=07H, ECX=0H):EBX.INVPCID to be 1. #[inline] -pub unsafe fn flush_pcid(command: InvPicdCommand) { +pub unsafe fn flush_pcid(command: InvPcidCommand) { let mut desc = InvpcidDescriptor { pcid: 0, address: 0, @@ -101,17 +106,17 @@ pub unsafe fn flush_pcid(command: InvPicdCommand) { let kind: u64; match command { - InvPicdCommand::Address(addr, pcid) => { + InvPcidCommand::Address(addr, pcid) => { kind = 0; desc.pcid = pcid.value().into(); desc.address = addr.as_u64() } - InvPicdCommand::Single(pcid) => { + InvPcidCommand::Single(pcid) => { kind = 1; desc.pcid = pcid.0.into() } - InvPicdCommand::All => kind = 2, - InvPicdCommand::AllExceptGlobal => kind = 3, + InvPcidCommand::All => kind = 2, + InvPcidCommand::AllExceptGlobal => kind = 3, } unsafe { From 6e0652f68a8b8c86238094944fc62c8fab2668f5 Mon Sep 17 00:00:00 2001 From: German Date: Mon, 21 Oct 2024 01:26:48 +0300 Subject: [PATCH 18/30] TryFrom implementation for ExceptionVector --- src/structures/idt.rs | 47 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/structures/idt.rs b/src/structures/idt.rs index 1da184e7..d4a8deb8 100644 --- a/src/structures/idt.rs +++ b/src/structures/idt.rs @@ -24,6 +24,7 @@ use crate::registers::rflags::RFlags; use crate::{PrivilegeLevel, VirtAddr}; use bit_field::BitField; use bitflags::bitflags; +use core::convert::TryFrom; use core::fmt; use core::marker::PhantomData; use core::ops::Bound::{Excluded, Included, Unbounded}; @@ -1361,6 +1362,52 @@ pub enum ExceptionVector { Security = 0x1E, } +/// Exception vector number is invalid +#[derive(Debug)] +pub struct InvalidExceptionVectorNumber(u8); + +impl fmt::Display for InvalidExceptionVectorNumber { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{} is not a valid exception vector", self.0) + } +} + +impl TryFrom for ExceptionVector { + type Error = InvalidExceptionVectorNumber; + + /// Tries to convert the exception vector number to [`ExceptionVector`] + /// + /// Fails if exception vector number is Coprocessor Segment Overrun, reserved or not exception vector number + fn try_from(exception_vector_number: u8) -> Result { + match exception_vector_number { + 0x00 => Ok(Self::Division), + 0x01 => Ok(Self::Debug), + 0x02 => Ok(Self::NonMaskableInterrupt), + 0x03 => Ok(Self::Breakpoint), + 0x04 => Ok(Self::Overflow), + 0x05 => Ok(Self::BoundRange), + 0x06 => Ok(Self::InvalidOpcode), + 0x07 => Ok(Self::DeviceNotAvailable), + 0x08 => Ok(Self::Double), + 0x0A => Ok(Self::InvalidTss), + 0x0B => Ok(Self::SegmentNotPresent), + 0x0C => Ok(Self::Stack), + 0x0D => Ok(Self::GeneralProtection), + 0x0E => Ok(Self::Page), + 0x10 => Ok(Self::X87FloatingPoint), + 0x11 => Ok(Self::AlignmentCheck), + 0x12 => Ok(Self::MachineCheck), + 0x13 => Ok(Self::SimdFloatingPoint), + 0x14 => Ok(Self::Virtualization), + 0x15 => Ok(Self::ControlProtection), + 0x1C => Ok(Self::HypervisorInjection), + 0x1D => Ok(Self::VmmCommunication), + 0x1E => Ok(Self::Security), + _ => Err(InvalidExceptionVectorNumber(exception_vector_number)), + } + } +} + #[cfg(all( feature = "instructions", feature = "abi_x86_interrupt", From 87d1eb13aebd3a21f5ca181081d5163989a05e0d Mon Sep 17 00:00:00 2001 From: mrjbom <37502620+mrjbom@users.noreply.github.com> Date: Sat, 19 Oct 2024 23:57:07 +0300 Subject: [PATCH 19/30] More precise comments in TaskStateSegment --- src/structures/tss.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/structures/tss.rs b/src/structures/tss.rs index dcedc383..6640a736 100644 --- a/src/structures/tss.rs +++ b/src/structures/tss.rs @@ -5,16 +5,17 @@ use core::mem::size_of; /// In 64-bit mode the TSS holds information that is not /// directly related to the task-switch mechanism, -/// but is used for finding kernel level stack -/// if interrupts arrive while in kernel mode. +/// but is used for stack switching when interrupt occurs. #[derive(Debug, Clone, Copy)] #[repr(C, packed(4))] pub struct TaskStateSegment { reserved_1: u32, /// The full 64-bit canonical forms of the stack pointers (RSP) for privilege levels 0-2. + /// The stack pointers used to load the stack when a privilege level change occurs from a lower privilege level to a higher one. pub privilege_stack_table: [VirtAddr; 3], reserved_2: u64, /// The full 64-bit canonical forms of the interrupt stack table (IST) pointers. + /// The stack pointers used to load the stack when an entry in the Interrupt Descriptor Table has an IST value other than 0. pub interrupt_stack_table: [VirtAddr; 7], reserved_3: u64, reserved_4: u16, From 701154798bf5005bf686b0849676abf795487b18 Mon Sep 17 00:00:00 2001 From: mrjbom <37502620+mrjbom@users.noreply.github.com> Date: Mon, 21 Oct 2024 22:37:16 +0300 Subject: [PATCH 20/30] More precise comments in TaskStateSegment Co-authored-by: Tom Dohrmann --- src/structures/tss.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structures/tss.rs b/src/structures/tss.rs index 6640a736..11ea3334 100644 --- a/src/structures/tss.rs +++ b/src/structures/tss.rs @@ -5,7 +5,7 @@ use core::mem::size_of; /// In 64-bit mode the TSS holds information that is not /// directly related to the task-switch mechanism, -/// but is used for stack switching when interrupt occurs. +/// but is used for stack switching when an interrupt or exception occurs. #[derive(Debug, Clone, Copy)] #[repr(C, packed(4))] pub struct TaskStateSegment { From a9187deca843f71ac7ced62c0e7458a2f9394887 Mon Sep 17 00:00:00 2001 From: mrjbom <37502620+mrjbom@users.noreply.github.com> Date: Mon, 21 Oct 2024 22:37:22 +0300 Subject: [PATCH 21/30] More precise comments in TaskStateSegment Co-authored-by: Tom Dohrmann --- src/structures/tss.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structures/tss.rs b/src/structures/tss.rs index 11ea3334..d0689d45 100644 --- a/src/structures/tss.rs +++ b/src/structures/tss.rs @@ -11,7 +11,7 @@ use core::mem::size_of; pub struct TaskStateSegment { reserved_1: u32, /// The full 64-bit canonical forms of the stack pointers (RSP) for privilege levels 0-2. - /// The stack pointers used to load the stack when a privilege level change occurs from a lower privilege level to a higher one. + /// The stack pointers used when a privilege level change occurs from a lower privilege level to a higher one. pub privilege_stack_table: [VirtAddr; 3], reserved_2: u64, /// The full 64-bit canonical forms of the interrupt stack table (IST) pointers. From 6d94a4696e710d8ca72e79b78c5d4afad58682c9 Mon Sep 17 00:00:00 2001 From: mrjbom <37502620+mrjbom@users.noreply.github.com> Date: Mon, 21 Oct 2024 22:37:28 +0300 Subject: [PATCH 22/30] More precise comments in TaskStateSegment Co-authored-by: Tom Dohrmann --- src/structures/tss.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structures/tss.rs b/src/structures/tss.rs index d0689d45..cbfeff47 100644 --- a/src/structures/tss.rs +++ b/src/structures/tss.rs @@ -15,7 +15,7 @@ pub struct TaskStateSegment { pub privilege_stack_table: [VirtAddr; 3], reserved_2: u64, /// The full 64-bit canonical forms of the interrupt stack table (IST) pointers. - /// The stack pointers used to load the stack when an entry in the Interrupt Descriptor Table has an IST value other than 0. + /// The stack pointers used when an entry in the Interrupt Descriptor Table has an IST value other than 0. pub interrupt_stack_table: [VirtAddr; 7], reserved_3: u64, reserved_4: u16, From f9c352b8246de3ea14823a06d1010bec8cfeb3e8 Mon Sep 17 00:00:00 2001 From: mrjbom <37502620+mrjbom@users.noreply.github.com> Date: Sat, 19 Oct 2024 23:47:44 +0300 Subject: [PATCH 23/30] Minor clarification --- src/structures/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structures/mod.rs b/src/structures/mod.rs index 3bfcf78e..1bf7d19f 100644 --- a/src/structures/mod.rs +++ b/src/structures/mod.rs @@ -15,7 +15,7 @@ pub mod tss; #[derive(Debug, Clone, Copy)] #[repr(C, packed(2))] pub struct DescriptorTablePointer { - /// Size of the DT. + /// Size of the DT in bytes - 1. pub limit: u16, /// Pointer to the memory region containing the DT. pub base: VirtAddr, From b9e3d259ef84868c757c809c7d04c6d4bccfa402 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Sun, 24 Nov 2024 07:40:11 +0100 Subject: [PATCH 24/30] fix signature of Step::steps_between implementations A recent nightly changed the signature of Step::steps_between to match the signature of Iterator::size_hint. This patch changes our implementations to match the new signature. --- src/addr.rs | 39 ++++++++++++++++++----------- src/instructions/tlb.rs | 4 +-- src/structures/paging/page.rs | 10 +++++--- src/structures/paging/page_table.rs | 4 +-- 4 files changed, 35 insertions(+), 22 deletions(-) diff --git a/src/addr.rs b/src/addr.rs index 8afe53f3..fd29a896 100644 --- a/src/addr.rs +++ b/src/addr.rs @@ -241,13 +241,18 @@ impl VirtAddr { // FIXME: Move this into the `Step` impl, once `Step` is stabilized. #[cfg(any(feature = "instructions", feature = "step_trait"))] - pub(crate) fn steps_between_impl(start: &Self, end: &Self) -> Option { - let mut steps = end.0.checked_sub(start.0)?; + pub(crate) fn steps_between_impl(start: &Self, end: &Self) -> (usize, Option) { + let mut steps = if let Some(steps) = end.0.checked_sub(start.0) { + steps + } else { + return (0, None); + }; // Mask away extra bits that appear while jumping the gap. steps &= 0xffff_ffff_ffff; - usize::try_from(steps).ok() + let steps = usize::try_from(steps).ok(); + (steps.unwrap_or(usize::MAX), steps) } // FIXME: Move this into the `Step` impl, once `Step` is stabilized. @@ -360,7 +365,7 @@ impl Sub for VirtAddr { #[cfg(feature = "step_trait")] impl Step for VirtAddr { #[inline] - fn steps_between(start: &Self, end: &Self) -> Option { + fn steps_between(start: &Self, end: &Self) -> (usize, Option) { Self::steps_between_impl(start, end) } @@ -721,43 +726,49 @@ mod tests { #[test] #[cfg(feature = "step_trait")] fn virtaddr_steps_between() { - assert_eq!(Step::steps_between(&VirtAddr(0), &VirtAddr(0)), Some(0)); - assert_eq!(Step::steps_between(&VirtAddr(0), &VirtAddr(1)), Some(1)); - assert_eq!(Step::steps_between(&VirtAddr(1), &VirtAddr(0)), None); + assert_eq!( + Step::steps_between(&VirtAddr(0), &VirtAddr(0)), + (0, Some(0)) + ); + assert_eq!( + Step::steps_between(&VirtAddr(0), &VirtAddr(1)), + (1, Some(1)) + ); + assert_eq!(Step::steps_between(&VirtAddr(1), &VirtAddr(0)), (0, None)); assert_eq!( Step::steps_between( &VirtAddr(0x7fff_ffff_ffff), &VirtAddr(0xffff_8000_0000_0000) ), - Some(1) + (1, Some(1)) ); assert_eq!( Step::steps_between( &VirtAddr(0xffff_8000_0000_0000), &VirtAddr(0x7fff_ffff_ffff) ), - None + (0, None) ); assert_eq!( Step::steps_between( &VirtAddr(0xffff_8000_0000_0000), &VirtAddr(0xffff_8000_0000_0000) ), - Some(0) + (0, Some(0)) ); assert_eq!( Step::steps_between( &VirtAddr(0xffff_8000_0000_0000), &VirtAddr(0xffff_8000_0000_0001) ), - Some(1) + (1, Some(1)) ); assert_eq!( Step::steps_between( &VirtAddr(0xffff_8000_0000_0001), &VirtAddr(0xffff_8000_0000_0000) ), - None + (0, None) ); } @@ -951,7 +962,7 @@ mod proofs { }; // ...then `steps_between` succeeds as well. - assert!(Step::steps_between(&start, &end) == Some(count)); + assert!(Step::steps_between(&start, &end) == (count, Some(count))); } // This harness proves that for all inputs for which `steps_between` @@ -968,7 +979,7 @@ mod proofs { }; // If `steps_between` succeeds... - let Some(count) = Step::steps_between(&start, &end) else { + let Some(count) = Step::steps_between(&start, &end).1 else { return; }; diff --git a/src/instructions/tlb.rs b/src/instructions/tlb.rs index 3f5c4467..4a523483 100644 --- a/src/instructions/tlb.rs +++ b/src/instructions/tlb.rs @@ -315,14 +315,14 @@ where if let Some(mut pages) = self.page_range { while !pages.is_empty() { // Calculate out how many pages we still need to flush. - let count = Page::::steps_between_impl(&pages.start, &pages.end).unwrap(); + let count = Page::::steps_between_impl(&pages.start, &pages.end).0; // Make sure that we never jump the gap in the address space when flushing. let second_half_start = Page::::containing_address(VirtAddr::new(0xffff_8000_0000_0000)); let count = if pages.start < second_half_start { let count_to_second_half = - Page::steps_between_impl(&pages.start, &second_half_start).unwrap(); + Page::steps_between_impl(&pages.start, &second_half_start).0; cmp::min(count, count_to_second_half) } else { count diff --git a/src/structures/paging/page.rs b/src/structures/paging/page.rs index 55720cf4..e71067f5 100644 --- a/src/structures/paging/page.rs +++ b/src/structures/paging/page.rs @@ -160,9 +160,11 @@ impl Page { // FIXME: Move this into the `Step` impl, once `Step` is stabilized. #[cfg(any(feature = "instructions", feature = "step_trait"))] - pub(crate) fn steps_between_impl(start: &Self, end: &Self) -> Option { - VirtAddr::steps_between_impl(&start.start_address, &end.start_address) - .map(|steps| steps / S::SIZE as usize) + pub(crate) fn steps_between_impl(start: &Self, end: &Self) -> (usize, Option) { + let (lower, upper) = VirtAddr::steps_between_impl(&start.start_address, &end.start_address); + let lower = lower / S::SIZE as usize; + let upper = upper.map(|steps| steps / S::SIZE as usize); + (lower, upper) } // FIXME: Move this into the `Step` impl, once `Step` is stabilized. @@ -293,7 +295,7 @@ impl Sub for Page { #[cfg(feature = "step_trait")] impl Step for Page { - fn steps_between(start: &Self, end: &Self) -> Option { + fn steps_between(start: &Self, end: &Self) -> (usize, Option) { Self::steps_between_impl(start, end) } diff --git a/src/structures/paging/page_table.rs b/src/structures/paging/page_table.rs index fe9ebde0..e9069bcc 100644 --- a/src/structures/paging/page_table.rs +++ b/src/structures/paging/page_table.rs @@ -353,8 +353,8 @@ impl From for usize { #[cfg(feature = "step_trait")] impl Step for PageTableIndex { #[inline] - fn steps_between(start: &Self, end: &Self) -> Option { - end.0.checked_sub(start.0).map(usize::from) + fn steps_between(start: &Self, end: &Self) -> (usize, Option) { + Step::steps_between(&start.0, &end.0) } #[inline] From 3d6571458fc48f3b4a81d137536c3b5d6f98a9ad Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Sun, 24 Nov 2024 09:21:58 +0100 Subject: [PATCH 25/30] actually test with slice instead of array Without the as_slice call, the value passed to from_ptr was &[i32; 5] which is *not* a slice. --- src/addr.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/addr.rs b/src/addr.rs index fd29a896..2f894bb5 100644 --- a/src/addr.rs +++ b/src/addr.rs @@ -823,7 +823,10 @@ mod tests { fn test_from_ptr_array() { let slice = &[1, 2, 3, 4, 5]; // Make sure that from_ptr(slice) is the address of the first element - assert_eq!(VirtAddr::from_ptr(slice), VirtAddr::from_ptr(&slice[0])); + assert_eq!( + VirtAddr::from_ptr(slice.as_slice()), + VirtAddr::from_ptr(&slice[0]) + ); } } From 1e5b5a1e45383fd41df90650c9bed2f4c0caa1db Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Sun, 24 Nov 2024 09:23:52 +0100 Subject: [PATCH 26/30] fix tests on 32-bit platforms --- src/addr.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/addr.rs b/src/addr.rs index 2f894bb5..cdc97ffe 100644 --- a/src/addr.rs +++ b/src/addr.rs @@ -669,22 +669,27 @@ mod tests { Step::forward_checked(VirtAddr(0xffff_ffff_ffff_ffff), 1), None ); + #[cfg(target_pointer_width = "64")] assert_eq!( Step::forward(VirtAddr(0x7fff_ffff_ffff), 0x1234_5678_9abd), VirtAddr(0xffff_9234_5678_9abc) ); + #[cfg(target_pointer_width = "64")] assert_eq!( Step::forward(VirtAddr(0x7fff_ffff_ffff), 0x8000_0000_0000), VirtAddr(0xffff_ffff_ffff_ffff) ); + #[cfg(target_pointer_width = "64")] assert_eq!( Step::forward(VirtAddr(0x7fff_ffff_ff00), 0x8000_0000_00ff), VirtAddr(0xffff_ffff_ffff_ffff) ); + #[cfg(target_pointer_width = "64")] assert_eq!( Step::forward_checked(VirtAddr(0x7fff_ffff_ff00), 0x8000_0000_0100), None ); + #[cfg(target_pointer_width = "64")] assert_eq!( Step::forward_checked(VirtAddr(0x7fff_ffff_ffff), 0x8000_0000_0001), None @@ -705,18 +710,22 @@ mod tests { Step::backward(VirtAddr(0xffff_8000_0000_0001), 1), VirtAddr(0xffff_8000_0000_0000) ); + #[cfg(target_pointer_width = "64")] assert_eq!( Step::backward(VirtAddr(0xffff_9234_5678_9abc), 0x1234_5678_9abd), VirtAddr(0x7fff_ffff_ffff) ); + #[cfg(target_pointer_width = "64")] assert_eq!( Step::backward(VirtAddr(0xffff_8000_0000_0000), 0x8000_0000_0000), VirtAddr(0) ); + #[cfg(target_pointer_width = "64")] assert_eq!( Step::backward(VirtAddr(0xffff_8000_0000_0000), 0x7fff_ffff_ff01), VirtAddr(0xff) ); + #[cfg(target_pointer_width = "64")] assert_eq!( Step::backward_checked(VirtAddr(0xffff_8000_0000_0000), 0x8000_0000_0001), None @@ -820,6 +829,7 @@ mod tests { } #[test] + #[cfg(target_pointer_width = "64")] fn test_from_ptr_array() { let slice = &[1, 2, 3, 4, 5]; // Make sure that from_ptr(slice) is the address of the first element From 8fb0668eccf8c917d657f740ac7a416933392b25 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Sun, 24 Nov 2024 09:24:05 +0100 Subject: [PATCH 27/30] run tests on a 32-bit platform --- .github/workflows/build.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a406cbba..1216bcab 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -56,7 +56,7 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@nightly with: - targets: x86_64-unknown-linux-musl, i686-unknown-linux-gnu, thumbv7em-none-eabihf + targets: x86_64-unknown-linux-musl, i686-unknown-linux-musl, thumbv7em-none-eabihf - run: cargo build @@ -72,9 +72,12 @@ jobs: - name: "Build on non x86_64 platforms" run: | - cargo build --target i686-unknown-linux-gnu --no-default-features --features nightly + cargo build --target i686-unknown-linux-musl --no-default-features --features nightly cargo build --target thumbv7em-none-eabihf --no-default-features --features nightly + - run: cargo test --target i686-unknown-linux-musl --no-default-features --features nightly + if: runner.os == 'Linux' + bootloader-test: name: "Bootloader Integration Test" From b4b66637b7306254447bde805789f1a2cf92b6e5 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Sun, 24 Nov 2024 09:25:42 +0100 Subject: [PATCH 28/30] fix Page Step impl on 32-bit platforms Previously, we scaled count as a usize, not a u64. This is bad because stepping forward by 0x10_0000 is perfectly fine, yet we were always rejecting this because 0x10_0000 * 0x1000 doesn't fit in usize on 32-bit platforms. Similarly, we would fail to return a step count above or equal to 0x10_0000 because the call to ::steps_between would fail. Never scale usize values, instead, always scale u64 values. To make this easier to work with, this patch adds variants of the Step functions to VirtAddr that take and return u64 instead of usize. This patch also adds some regression tests. --- src/addr.rs | 94 ++++++++++++++++-------- src/structures/paging/page.rs | 133 ++++++++++++++++++++++++++++++++-- 2 files changed, 189 insertions(+), 38 deletions(-) diff --git a/src/addr.rs b/src/addr.rs index cdc97ffe..7ce471ee 100644 --- a/src/addr.rs +++ b/src/addr.rs @@ -240,30 +240,43 @@ impl VirtAddr { } // FIXME: Move this into the `Step` impl, once `Step` is stabilized. - #[cfg(any(feature = "instructions", feature = "step_trait"))] + #[cfg(feature = "step_trait")] pub(crate) fn steps_between_impl(start: &Self, end: &Self) -> (usize, Option) { - let mut steps = if let Some(steps) = end.0.checked_sub(start.0) { - steps + if let Some(steps) = Self::steps_between_u64(start, end) { + let steps = usize::try_from(steps).ok(); + (steps.unwrap_or(usize::MAX), steps) } else { - return (0, None); - }; + (0, None) + } + } + + /// An implementation of steps_between that returns u64. Note that this + /// function always returns the exact bound, so it doesn't need to return a + /// lower and upper bound like steps_between does. + #[cfg(any(feature = "instructions", feature = "step_trait"))] + pub(crate) fn steps_between_u64(start: &Self, end: &Self) -> Option { + let mut steps = end.0.checked_sub(start.0)?; // Mask away extra bits that appear while jumping the gap. steps &= 0xffff_ffff_ffff; - let steps = usize::try_from(steps).ok(); - (steps.unwrap_or(usize::MAX), steps) + Some(steps) } // FIXME: Move this into the `Step` impl, once `Step` is stabilized. #[inline] pub(crate) fn forward_checked_impl(start: Self, count: usize) -> Option { - let offset = u64::try_from(count).ok()?; - if offset > ADDRESS_SPACE_SIZE { + Self::forward_checked_u64(start, u64::try_from(count).ok()?) + } + + /// An implementation of forward_checked that takes u64 instead of usize. + #[inline] + pub(crate) fn forward_checked_u64(start: Self, count: u64) -> Option { + if count > ADDRESS_SPACE_SIZE { return None; } - let mut addr = start.0.checked_add(offset)?; + let mut addr = start.0.checked_add(count)?; match addr.get_bits(47..) { 0x1 => { @@ -279,6 +292,31 @@ impl VirtAddr { Some(unsafe { Self::new_unsafe(addr) }) } + + /// An implementation of backward_checked that takes u64 instead of usize. + #[cfg(feature = "step_trait")] + #[inline] + pub(crate) fn backward_checked_u64(start: Self, count: u64) -> Option { + if count > ADDRESS_SPACE_SIZE { + return None; + } + + let mut addr = start.0.checked_sub(count)?; + + match addr.get_bits(47..) { + 0x1fffe => { + // Jump the gap by sign extending the 47th bit. + addr.set_bits(47.., 0); + } + 0x1fffd => { + // Address underflow + return None; + } + _ => {} + } + + Some(unsafe { Self::new_unsafe(addr) }) + } } impl fmt::Debug for VirtAddr { @@ -376,26 +414,7 @@ impl Step for VirtAddr { #[inline] fn backward_checked(start: Self, count: usize) -> Option { - let offset = u64::try_from(count).ok()?; - if offset > ADDRESS_SPACE_SIZE { - return None; - } - - let mut addr = start.0.checked_sub(offset)?; - - match addr.get_bits(47..) { - 0x1fffe => { - // Jump the gap by sign extending the 47th bit. - addr.set_bits(47.., 0); - } - 0x1fffd => { - // Address underflow - return None; - } - _ => {} - } - - Some(unsafe { Self::new_unsafe(addr) }) + Self::backward_checked_u64(start, u64::try_from(count).ok()?) } } @@ -779,6 +798,21 @@ mod tests { ), (0, None) ); + // Make sure that we handle `steps > u32::MAX` correctly on 32-bit + // targets. On 64-bit targets, `0x1_0000_0000` fits into `usize`, so we + // can return exact lower and upper bounds. On 32-bit targets, + // `0x1_0000_0000` doesn't fit into `usize`, so we only return an lower + // bound of `usize::MAX` and don't return an upper bound. + #[cfg(target_pointer_width = "64")] + assert_eq!( + Step::steps_between(&VirtAddr(0), &VirtAddr(0x1_0000_0000)), + (0x1_0000_0000, Some(0x1_0000_0000)) + ); + #[cfg(not(target_pointer_width = "64"))] + assert_eq!( + Step::steps_between(&VirtAddr(0), &VirtAddr(0x1_0000_0000)), + (usize::MAX, None) + ); } #[test] diff --git a/src/structures/paging/page.rs b/src/structures/paging/page.rs index e71067f5..a51b4df4 100644 --- a/src/structures/paging/page.rs +++ b/src/structures/paging/page.rs @@ -161,17 +161,26 @@ impl Page { // FIXME: Move this into the `Step` impl, once `Step` is stabilized. #[cfg(any(feature = "instructions", feature = "step_trait"))] pub(crate) fn steps_between_impl(start: &Self, end: &Self) -> (usize, Option) { - let (lower, upper) = VirtAddr::steps_between_impl(&start.start_address, &end.start_address); - let lower = lower / S::SIZE as usize; - let upper = upper.map(|steps| steps / S::SIZE as usize); - (lower, upper) + use core::convert::TryFrom; + + if let Some(steps) = + VirtAddr::steps_between_u64(&start.start_address(), &end.start_address()) + { + let steps = steps / S::SIZE; + let steps = usize::try_from(steps).ok(); + (steps.unwrap_or(usize::MAX), steps) + } else { + (0, None) + } } // FIXME: Move this into the `Step` impl, once `Step` is stabilized. #[cfg(any(feature = "instructions", feature = "step_trait"))] pub(crate) fn forward_checked_impl(start: Self, count: usize) -> Option { - let count = count.checked_mul(S::SIZE as usize)?; - let start_address = VirtAddr::forward_checked_impl(start.start_address, count)?; + use core::convert::TryFrom; + + let count = u64::try_from(count).ok()?.checked_mul(S::SIZE)?; + let start_address = VirtAddr::forward_checked_u64(start.start_address, count)?; Some(Self { start_address, size: PhantomData, @@ -304,8 +313,10 @@ impl Step for Page { } fn backward_checked(start: Self, count: usize) -> Option { - let count = count.checked_mul(S::SIZE as usize)?; - let start_address = Step::backward_checked(start.start_address, count)?; + use core::convert::TryFrom; + + let count = u64::try_from(count).ok()?.checked_mul(S::SIZE)?; + let start_address = VirtAddr::backward_checked_u64(start.start_address, count)?; Some(Self { start_address, size: PhantomData, @@ -531,4 +542,110 @@ mod tests { let range_inclusive = PageRangeInclusive { start, end }; assert_eq!(range_inclusive.len(), 51); } + + #[test] + #[cfg(feature = "step_trait")] + fn page_step_forward() { + let test_cases = [ + (0, 0, Some(0)), + (0, 1, Some(0x1000)), + (0x1000, 1, Some(0x2000)), + (0x7fff_ffff_f000, 1, Some(0xffff_8000_0000_0000)), + (0xffff_8000_0000_0000, 1, Some(0xffff_8000_0000_1000)), + (0xffff_ffff_ffff_f000, 1, None), + #[cfg(target_pointer_width = "64")] + (0x7fff_ffff_f000, 0x1_2345_6789, Some(0xffff_9234_5678_8000)), + #[cfg(target_pointer_width = "64")] + (0x7fff_ffff_f000, 0x8_0000_0000, Some(0xffff_ffff_ffff_f000)), + #[cfg(target_pointer_width = "64")] + (0x7fff_fff0_0000, 0x8_0000_00ff, Some(0xffff_ffff_ffff_f000)), + #[cfg(target_pointer_width = "64")] + (0x7fff_fff0_0000, 0x8_0000_0100, None), + #[cfg(target_pointer_width = "64")] + (0x7fff_ffff_f000, 0x8_0000_0001, None), + // Make sure that we handle `steps * PAGE_SIZE > u32::MAX` + // correctly on 32-bit targets. + (0, 0x10_0000, Some(0x1_0000_0000)), + ]; + for (start, count, result) in test_cases { + let start = Page::::from_start_address(VirtAddr::new(start)).unwrap(); + let result = result + .map(|result| Page::::from_start_address(VirtAddr::new(result)).unwrap()); + assert_eq!(Step::forward_checked(start, count), result); + } + } + + #[test] + #[cfg(feature = "step_trait")] + fn page_step_backwards() { + let test_cases = [ + (0, 0, Some(0)), + (0, 1, None), + (0x1000, 1, Some(0)), + (0xffff_8000_0000_0000, 1, Some(0x7fff_ffff_f000)), + (0xffff_8000_0000_1000, 1, Some(0xffff_8000_0000_0000)), + #[cfg(target_pointer_width = "64")] + (0xffff_9234_5678_8000, 0x1_2345_6789, Some(0x7fff_ffff_f000)), + #[cfg(target_pointer_width = "64")] + (0xffff_8000_0000_0000, 0x8_0000_0000, Some(0)), + #[cfg(target_pointer_width = "64")] + (0xffff_8000_0000_0000, 0x7_ffff_ff01, Some(0xff000)), + #[cfg(target_pointer_width = "64")] + (0xffff_8000_0000_0000, 0x8_0000_0001, None), + // Make sure that we handle `steps * PAGE_SIZE > u32::MAX` + // correctly on 32-bit targets. + (0x1_0000_0000, 0x10_0000, Some(0)), + ]; + for (start, count, result) in test_cases { + let start = Page::::from_start_address(VirtAddr::new(start)).unwrap(); + let result = result + .map(|result| Page::::from_start_address(VirtAddr::new(result)).unwrap()); + assert_eq!(Step::backward_checked(start, count), result); + } + } + + #[test] + #[cfg(feature = "step_trait")] + fn page_steps_between() { + let test_cases = [ + (0, 0, 0, Some(0)), + (0, 0x1000, 1, Some(1)), + (0x1000, 0, 0, None), + (0x1000, 0x1000, 0, Some(0)), + (0x7fff_ffff_f000, 0xffff_8000_0000_0000, 1, Some(1)), + (0xffff_8000_0000_0000, 0x7fff_ffff_f000, 0, None), + (0xffff_8000_0000_0000, 0xffff_8000_0000_0000, 0, Some(0)), + (0xffff_8000_0000_0000, 0xffff_8000_0000_1000, 1, Some(1)), + (0xffff_8000_0000_1000, 0xffff_8000_0000_0000, 0, None), + (0xffff_8000_0000_1000, 0xffff_8000_0000_1000, 0, Some(0)), + // Make sure that we handle `steps * PAGE_SIZE > u32::MAX` correctly on 32-bit + // targets. + ( + 0x0000_0000_0000, + 0x0001_0000_0000, + 0x10_0000, + Some(0x10_0000), + ), + // The returned bounds are different when `steps` doesn't fit in + // into `usize`. On 64-bit targets, `0x1_0000_0000` fits into + // `usize`, so we can return exact lower and upper bounds. On + // 32-bit targets, `0x1_0000_0000` doesn't fit into `usize`, so we + // only return an lower bound of `usize::MAX` and don't return an + // upper bound. + #[cfg(target_pointer_width = "64")] + ( + 0x0000_0000_0000, + 0x1000_0000_0000, + 0x1_0000_0000, + Some(0x1_0000_0000), + ), + #[cfg(not(target_pointer_width = "64"))] + (0x0000_0000_0000, 0x1000_0000_0000, usize::MAX, None), + ]; + for (start, end, lower, upper) in test_cases { + let start = Page::::from_start_address(VirtAddr::new(start)).unwrap(); + let end = Page::from_start_address(VirtAddr::new(end)).unwrap(); + assert_eq!(Step::steps_between(&start, &end), (lower, upper)); + } + } } From 2a794a4ac2784a3b6dbf7bc8b13fa2253496332e Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Fri, 29 Nov 2024 18:03:34 +0100 Subject: [PATCH 29/30] update changelog --- Changelog.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/Changelog.md b/Changelog.md index f517e673..907c2c23 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,8 +1,44 @@ # Unreleased +# 0.15.2 – 2024-11-30 + +This release is compatible with Rust nightlies starting with `nightly-2024-11-23` (this only applies when the `nightly` feature is used). + ## New Features +- [add `GlobalDescriptorTable::limit`](https://github.com/rust-osdev/x86_64/pull/413) +- [constify PhysFrame functions](https://github.com/rust-osdev/x86_64/pull/489) - [add `size` and `len` for `PageRange`, `PhysFrameRange`, `PageRangeInclusive` and `PhysFrameRangeInclusive`](https://github.com/rust-osdev/x86_64/pull/491) +- [TryFrom implementation for ExceptionVector](https://github.com/rust-osdev/x86_64/pull/506) + +## Fixes + +- [Only enable instructions on `x86_64`](https://github.com/rust-osdev/x86_64/pull/483) +- [Ensure that Page actually implements Hash](https://github.com/rust-osdev/x86_64/pull/490) +- [fix field order for INVPCID descriptor](https://github.com/rust-osdev/x86_64/pull/508) +- [fix typo in "InvPicdCommand"](https://github.com/rust-osdev/x86_64/pull/509) +- [fix signature of Step::steps_between implementations](https://github.com/rust-osdev/x86_64/pull/513) + +## Other Improvements + +- [docs: add aliases for `in{,b,w,l}` and `out{,b,w,l}`](https://github.com/rust-osdev/x86_64/pull/474) +- [ci: migrate away from unmaintained actions](https://github.com/rust-osdev/x86_64/pull/478) +- [chore: migrate from legacy `rust-toolchain` to `rust-toolchain.toml`](https://github.com/rust-osdev/x86_64/pull/479) +- [test: replace `x86_64-bare-metal.json` with `x86_64-unknown-none`](https://github.com/rust-osdev/x86_64/pull/477) +- [docs: fix and detect warnings](https://github.com/rust-osdev/x86_64/pull/475) +- [CI: Set `-Crelocation-model=static` in `RUSTFLAGS` for bootloader test job](https://github.com/rust-osdev/x86_64/pull/480) +- [silence warning about cast](https://github.com/rust-osdev/x86_64/pull/482) +- [fix cfg related warnings](https://github.com/rust-osdev/x86_64/pull/485) +- [fix warnings](https://github.com/rust-osdev/x86_64/pull/488) +- [don't use label starting with 1](https://github.com/rust-osdev/x86_64/pull/492) +- [fix testing](https://github.com/rust-osdev/x86_64/pull/495) +- [remove `#![feature(asm_const)]`](https://github.com/rust-osdev/x86_64/pull/496) +- [Remove stabilized const_mut_refs feature](https://github.com/rust-osdev/x86_64/pull/501) +- [Fix clippy warnings](https://github.com/rust-osdev/x86_64/pull/502) +- [fix CI job for building on MSRV](https://github.com/rust-osdev/x86_64/pull/510) +- [gate HandlerFunc behind target_arch = "x86{\_64}"](https://github.com/rust-osdev/x86_64/pull/507) +- [Typo fix in TaskStateSegment comment](https://github.com/rust-osdev/x86_64/pull/504) +- [Minor clarification DescriptorTablePointer::limit comment](https://github.com/rust-osdev/x86_64/pull/503) # 0.15.1 – 2024-03-19 From 1ca3e52b94e7df6c6d3247b365c95613b9866d7f Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Fri, 29 Nov 2024 18:04:47 +0100 Subject: [PATCH 30/30] release 0.15.2 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index b48dae0b..9b51f248 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ license = "MIT/Apache-2.0" name = "x86_64" readme = "README.md" repository = "https://github.com/rust-osdev/x86_64" -version = "0.15.1" +version = "0.15.2" edition = "2018" rust-version = "1.59" # Needed to support inline asm and default const generics