@@ -115,20 +115,7 @@ impl GlobalDescriptorTable {
115
115
index
116
116
}
117
117
} ;
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 ( ) )
132
119
}
133
120
134
121
/// Loads the GDT in the CPU using the `lgdt` instruction. This does **not** alter any of the
@@ -187,7 +174,7 @@ impl GlobalDescriptorTable {
187
174
///
188
175
/// Segmentation is no longer supported in 64-bit mode, so most of the descriptor
189
176
/// contents are ignored.
190
- #[ derive( Debug , Clone ) ]
177
+ #[ derive( Debug , Clone , Copy ) ]
191
178
pub enum Descriptor {
192
179
/// Descriptor for a code or data segment.
193
180
///
@@ -215,7 +202,8 @@ bitflags! {
215
202
const EXECUTABLE = 1 << 43 ;
216
203
/// This flag must be set for user segments (in contrast to system segments).
217
204
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.
219
207
const DPL_RING_3 = 3 << 45 ;
220
208
/// Must be set for any segment, causes a segment not present exception if not set.
221
209
const PRESENT = 1 << 47 ;
@@ -283,6 +271,20 @@ impl DescriptorFlags {
283
271
}
284
272
285
273
impl 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
+
286
288
/// Creates a segment descriptor for a 64-bit kernel code segment. Suitable
287
289
/// for use with `syscall` or 64-bit `sysenter`.
288
290
#[ inline]
@@ -408,4 +410,18 @@ mod tests {
408
410
// We have one free slot, but the GDT requires two
409
411
gdt. add_entry ( Descriptor :: tss_segment ( & TSS ) ) ;
410
412
}
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
+ }
411
427
}
0 commit comments