Skip to content

Commit

Permalink
Merge pull request #410 from rust-osdev/dpl
Browse files Browse the repository at this point in the history
Add Descriptor::dpl const method and use it in GDT construction
  • Loading branch information
josephlr committed Mar 8, 2023
2 parents a967e24 + 7673551 commit 2d41827
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 18 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"),
}
}
}
48 changes: 32 additions & 16 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 @@ -215,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;
Expand Down Expand Up @@ -283,6 +271,20 @@ impl DescriptorFlags {
}

impl Descriptor {
/// 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 {
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 +410,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 2d41827

Please sign in to comment.