From 14cdce44e25935ce1a4d310e4ad47420a3f44bc3 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Mon, 6 Mar 2023 16:46:38 -0800 Subject: [PATCH 1/2] Add Descriptor::dpl const method THis requires making `PrivilegeLevel::from_u16` const Signed-off-by: Joe Richey --- src/lib.rs | 4 ++-- src/structures/gdt.rs | 44 ++++++++++++++++++++++++++++--------------- 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 372e7a9ac..820452803 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,13 +52,13 @@ impl PrivilegeLevel { /// /// This function panics if the passed value is >3. #[inline] - pub fn from_u16(value: u16) -> PrivilegeLevel { + pub const fn from_u16(value: u16) -> PrivilegeLevel { match value { 0 => PrivilegeLevel::Ring0, 1 => PrivilegeLevel::Ring1, 2 => PrivilegeLevel::Ring2, 3 => PrivilegeLevel::Ring3, - i => panic!("{} is not a valid privilege level", i), + _ => panic!("invalid privilege level"), } } } diff --git a/src/structures/gdt.rs b/src/structures/gdt.rs index 5942030d0..84f290337 100644 --- a/src/structures/gdt.rs +++ b/src/structures/gdt.rs @@ -115,20 +115,7 @@ impl GlobalDescriptorTable { index } }; - - 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, - }; - - SegmentSelector::new(index as u16, rpl) + SegmentSelector::new(index as u16, entry.dpl()) } /// Loads the GDT in the CPU using the `lgdt` instruction. This does **not** alter any of the @@ -187,7 +174,7 @@ impl GlobalDescriptorTable { /// /// Segmentation is no longer supported in 64-bit mode, so most of the descriptor /// contents are ignored. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub enum Descriptor { /// Descriptor for a code or data segment. /// @@ -283,6 +270,19 @@ impl DescriptorFlags { } impl Descriptor { + /// Returns the Descriptor Privilage Level (DPL). When using this descriptor + /// via a [`SegmentSelector`], the `rpl` and Current Privilage Level (CPL) + /// must less than or equal to the DPL. + #[inline] + pub const fn dpl(self) -> PrivilegeLevel { + let value_low = match self { + Descriptor::UserSegment(v) => v, + Descriptor::SystemSegment(v, _) => v, + }; + let dpl = (value_low & DescriptorFlags::DPL_RING_3.bits()) >> 45; + PrivilegeLevel::from_u16(dpl as u16) + } + /// Creates a segment descriptor for a 64-bit kernel code segment. Suitable /// for use with `syscall` or 64-bit `sysenter`. #[inline] @@ -408,4 +408,18 @@ mod tests { // We have one free slot, but the GDT requires two gdt.add_entry(Descriptor::tss_segment(&TSS)); } + + #[test] + pub fn descriptor_dpl() { + assert_eq!( + Descriptor::kernel_code_segment().dpl(), + PrivilegeLevel::Ring0 + ); + assert_eq!( + Descriptor::kernel_data_segment().dpl(), + PrivilegeLevel::Ring0 + ); + assert_eq!(Descriptor::user_code_segment().dpl(), PrivilegeLevel::Ring3); + assert_eq!(Descriptor::user_code_segment().dpl(), PrivilegeLevel::Ring3); + } } From 767355118f220d90316dce52e3d1b7ec01036346 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Wed, 8 Mar 2023 14:13:09 -0800 Subject: [PATCH 2/2] Descriptor: update comments Clarify the DPL_RING_3 flag, remove the the comment saying that the DPL is ignored in 64-bit mode data segments, explain the exception for stack segments. Signed-off-by: Joe Richey --- src/structures/gdt.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/structures/gdt.rs b/src/structures/gdt.rs index 84f290337..7e6c66a58 100644 --- a/src/structures/gdt.rs +++ b/src/structures/gdt.rs @@ -202,7 +202,8 @@ bitflags! { const EXECUTABLE = 1 << 43; /// This flag must be set for user segments (in contrast to system segments). const USER_SEGMENT = 1 << 44; - /// The DPL for this descriptor is Ring 3. In 64-bit mode, ignored for data segments. + /// These two bits encode the Descriptor Privilege Level (DPL) for this descriptor. + /// If both bits are set, the DPL is Ring 3, if both are unset, the DPL is Ring 0. const DPL_RING_3 = 3 << 45; /// Must be set for any segment, causes a segment not present exception if not set. const PRESENT = 1 << 47; @@ -270,9 +271,10 @@ impl DescriptorFlags { } impl Descriptor { - /// Returns the Descriptor Privilage Level (DPL). When using this descriptor - /// via a [`SegmentSelector`], the `rpl` and Current Privilage Level (CPL) - /// must less than or equal to the DPL. + /// Returns the Descriptor Privilege Level (DPL). When using this descriptor + /// via a [`SegmentSelector`], the RPL and Current Privilege Level (CPL) + /// must less than or equal to the DPL, except for stack segments where the + /// RPL, CPL, and DPL must all be equal. #[inline] pub const fn dpl(self) -> PrivilegeLevel { let value_low = match self {