Skip to content

Commit

Permalink
Add Descriptor::dpl const method
Browse files Browse the repository at this point in the history
THis requires making `PrivilegeLevel::from_u16` const

Signed-off-by: Joe Richey <[email protected]>
  • Loading branch information
josephlr committed Mar 7, 2023
1 parent a967e24 commit 14cdce4
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 17 deletions.
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
}
}
}
44 changes: 29 additions & 15 deletions src/structures/gdt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
///
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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);
}
}

0 comments on commit 14cdce4

Please sign in to comment.