@@ -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 ) ]
191178pub enum Descriptor {
192179 /// Descriptor for a code or data segment.
193180 ///
@@ -215,7 +202,8 @@ bitflags! {
215202 const EXECUTABLE = 1 << 43 ;
216203 /// This flag must be set for user segments (in contrast to system segments).
217204 const USER_SEGMENT = 1 << 44 ;
218- /// The DPL for this descriptor is Ring 3. In 64-bit mode, ignored for data segments.
205+ /// These two bits encode the Descriptor Privilege Level (DPL) for this descriptor.
206+ /// If both bits are set, the DPL is Ring 3, if both are unset, the DPL is Ring 0.
219207 const DPL_RING_3 = 3 << 45 ;
220208 /// Must be set for any segment, causes a segment not present exception if not set.
221209 const PRESENT = 1 << 47 ;
@@ -283,6 +271,20 @@ impl DescriptorFlags {
283271}
284272
285273impl Descriptor {
274+ /// Returns the Descriptor Privilege Level (DPL). When using this descriptor
275+ /// via a [`SegmentSelector`], the RPL and Current Privilege Level (CPL)
276+ /// must less than or equal to the DPL, except for stack segments where the
277+ /// RPL, CPL, and DPL must all be equal.
278+ #[ inline]
279+ pub const fn dpl ( self ) -> PrivilegeLevel {
280+ let value_low = match self {
281+ Descriptor :: UserSegment ( v) => v,
282+ Descriptor :: SystemSegment ( v, _) => v,
283+ } ;
284+ let dpl = ( value_low & DescriptorFlags :: DPL_RING_3 . bits ( ) ) >> 45 ;
285+ PrivilegeLevel :: from_u16 ( dpl as u16 )
286+ }
287+
286288 /// Creates a segment descriptor for a 64-bit kernel code segment. Suitable
287289 /// for use with `syscall` or 64-bit `sysenter`.
288290 #[ inline]
@@ -408,4 +410,18 @@ mod tests {
408410 // We have one free slot, but the GDT requires two
409411 gdt. add_entry ( Descriptor :: tss_segment ( & TSS ) ) ;
410412 }
413+
414+ #[ test]
415+ pub fn descriptor_dpl ( ) {
416+ assert_eq ! (
417+ Descriptor :: kernel_code_segment( ) . dpl( ) ,
418+ PrivilegeLevel :: Ring0
419+ ) ;
420+ assert_eq ! (
421+ Descriptor :: kernel_data_segment( ) . dpl( ) ,
422+ PrivilegeLevel :: Ring0
423+ ) ;
424+ assert_eq ! ( Descriptor :: user_code_segment( ) . dpl( ) , PrivilegeLevel :: Ring3 ) ;
425+ assert_eq ! ( Descriptor :: user_code_segment( ) . dpl( ) , PrivilegeLevel :: Ring3 ) ;
426+ }
411427}
0 commit comments