Skip to content

Commit 14cdce4

Browse files
committed
Add Descriptor::dpl const method
THis requires making `PrivilegeLevel::from_u16` const Signed-off-by: Joe Richey <[email protected]>
1 parent a967e24 commit 14cdce4

File tree

2 files changed

+31
-17
lines changed

2 files changed

+31
-17
lines changed

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,13 @@ impl PrivilegeLevel {
5252
///
5353
/// This function panics if the passed value is >3.
5454
#[inline]
55-
pub fn from_u16(value: u16) -> PrivilegeLevel {
55+
pub const fn from_u16(value: u16) -> PrivilegeLevel {
5656
match value {
5757
0 => PrivilegeLevel::Ring0,
5858
1 => PrivilegeLevel::Ring1,
5959
2 => PrivilegeLevel::Ring2,
6060
3 => PrivilegeLevel::Ring3,
61-
i => panic!("{} is not a valid privilege level", i),
61+
_ => panic!("invalid privilege level"),
6262
}
6363
}
6464
}

src/structures/gdt.rs

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -115,20 +115,7 @@ impl GlobalDescriptorTable {
115115
index
116116
}
117117
};
118-
119-
let rpl = match entry {
120-
Descriptor::UserSegment(value) => {
121-
if DescriptorFlags::from_bits_truncate(value).contains(DescriptorFlags::DPL_RING_3)
122-
{
123-
PrivilegeLevel::Ring3
124-
} else {
125-
PrivilegeLevel::Ring0
126-
}
127-
}
128-
Descriptor::SystemSegment(_, _) => PrivilegeLevel::Ring0,
129-
};
130-
131-
SegmentSelector::new(index as u16, rpl)
118+
SegmentSelector::new(index as u16, entry.dpl())
132119
}
133120

134121
/// Loads the GDT in the CPU using the `lgdt` instruction. This does **not** alter any of the
@@ -187,7 +174,7 @@ impl GlobalDescriptorTable {
187174
///
188175
/// Segmentation is no longer supported in 64-bit mode, so most of the descriptor
189176
/// contents are ignored.
190-
#[derive(Debug, Clone)]
177+
#[derive(Debug, Clone, Copy)]
191178
pub enum Descriptor {
192179
/// Descriptor for a code or data segment.
193180
///
@@ -283,6 +270,19 @@ impl DescriptorFlags {
283270
}
284271

285272
impl Descriptor {
273+
/// Returns the Descriptor Privilage Level (DPL). When using this descriptor
274+
/// via a [`SegmentSelector`], the `rpl` and Current Privilage Level (CPL)
275+
/// must less than or equal to the DPL.
276+
#[inline]
277+
pub const fn dpl(self) -> PrivilegeLevel {
278+
let value_low = match self {
279+
Descriptor::UserSegment(v) => v,
280+
Descriptor::SystemSegment(v, _) => v,
281+
};
282+
let dpl = (value_low & DescriptorFlags::DPL_RING_3.bits()) >> 45;
283+
PrivilegeLevel::from_u16(dpl as u16)
284+
}
285+
286286
/// Creates a segment descriptor for a 64-bit kernel code segment. Suitable
287287
/// for use with `syscall` or 64-bit `sysenter`.
288288
#[inline]
@@ -408,4 +408,18 @@ mod tests {
408408
// We have one free slot, but the GDT requires two
409409
gdt.add_entry(Descriptor::tss_segment(&TSS));
410410
}
411+
412+
#[test]
413+
pub fn descriptor_dpl() {
414+
assert_eq!(
415+
Descriptor::kernel_code_segment().dpl(),
416+
PrivilegeLevel::Ring0
417+
);
418+
assert_eq!(
419+
Descriptor::kernel_data_segment().dpl(),
420+
PrivilegeLevel::Ring0
421+
);
422+
assert_eq!(Descriptor::user_code_segment().dpl(), PrivilegeLevel::Ring3);
423+
assert_eq!(Descriptor::user_code_segment().dpl(), PrivilegeLevel::Ring3);
424+
}
411425
}

0 commit comments

Comments
 (0)