@@ -185,6 +185,7 @@ bitflags! {
185185 /// Flags for a GDT descriptor. Not all flags are valid for all descriptor types.
186186 pub struct DescriptorFlags : u64 {
187187 /// Set by the processor if this segment has been accessed. Only cleared by software.
188+ /// _Setting_ this bit in software prevents GDT writes on first use.
188189 const ACCESSED = 1 << 40 ;
189190 /// For 32-bit data segments, sets the segment as writable. For 32-bit code segments,
190191 /// sets the segment as _readable_. In 64-bit mode, ignored for all segments.
@@ -205,42 +206,68 @@ bitflags! {
205206 const AVAILABLE = 1 << 52 ;
206207 /// Must be set for 64-bit code segments, unset otherwise.
207208 const LONG_MODE = 1 << 53 ;
208- /// Use 32-bit (as opposed to 16-bit) operands. If [`LONG_MODE`] is set,
209+ /// Use 32-bit (as opposed to 16-bit) operands. If [`LONG_MODE`][Self::LONG_MODE] is set,
209210 /// this must be unset. In 64-bit mode, ignored for data segments.
210211 const DEFAULT_SIZE = 1 << 54 ;
211212 /// Limit field is scaled by 4096 bytes. In 64-bit mode, ignored for all segments.
212213 const GRANULARITY = 1 << 55 ;
213214
214- /// Bits 0..=15 of the limit field (ignored in 64-bit mode)
215+ /// Bits ` 0..=15` of the limit field (ignored in 64-bit mode)
215216 const LIMIT_0_15 = 0xFFFF ;
216- /// Bits 16..=19 of the limit field (ignored in 64-bit mode)
217+ /// Bits ` 16..=19` of the limit field (ignored in 64-bit mode)
217218 const LIMIT_16_19 = 0xF << 48 ;
218- /// Bits 0..=23 of the base field (ignored in 64-bit mode)
219+ /// Bits ` 0..=23` of the base field (ignored in 64-bit mode)
219220 const BASE_0_23 = 0xFF_FFFF << 16 ;
220- /// Bits 24..=31 of the base field (ignored in 64-bit mode)
221+ /// Bits ` 24..=31` of the base field (ignored in 64-bit mode)
221222 const BASE_24_31 = 0xFF << 56 ;
222-
223- /// Flags that should be set for all flat user segments
224- const FLAT_COMMON = Self :: LIMIT_0_15 . bits | Self :: LIMIT_16_19 . bits
225- | Self :: GRANULARITY . bits | Self :: ACCESSED . bits | Self :: WRITABLE . bits
226- | Self :: USER_SEGMENT . bits | Self :: PRESENT . bits;
227-
228- /// Flags for a flat 32-bit kernel code segment
229- const KERNEL_CODE32 = Self :: FLAT_COMMON . bits | Self :: EXECUTABLE . bits | Self :: DEFAULT_SIZE . bits;
230- /// Flags for a 64-bit kernel code segment
231- const KERNEL_CODE64 = Self :: FLAT_COMMON . bits | Self :: EXECUTABLE . bits | Self :: LONG_MODE . bits;
232- /// Flags for a kernel data segment (64-bit or flat 32-bit)
233- const KERNEL_DATA = Self :: FLAT_COMMON . bits | Self :: DEFAULT_SIZE . bits;
234-
235- /// Flags for a flat 32-bit user code segment
236- const USER_CODE32 = Self :: KERNEL_CODE32 . bits | Self :: DPL_RING_3 . bits;
237- /// Flags for a 64-bit user code segment
238- const USER_CODE64 = Self :: KERNEL_CODE64 . bits | Self :: DPL_RING_3 . bits;
239- /// Flags for a user data segment (64-bit or flat 32-bit)
240- const USER_DATA = Self :: KERNEL_DATA . bits | Self :: DPL_RING_3 . bits;
241223 }
242224}
243225
226+ /// The following constants define default values for common GDT use-cases. They
227+ /// are all "flat" segments meaning that they can access the entire address
228+ /// space. These values all set [`WRITABLE`][DescriptorFlags::WRITABLE] and
229+ /// [`ACCESSED`][DescriptorFlags::ACCESSED].
230+ ///
231+ /// In short, these values disable segmentation, permission checks, and access
232+ /// tracking at the GDT level. Kernels using these values should use paging to
233+ /// implement this functionality.
234+ impl DescriptorFlags {
235+ // Flags that we set for all user segments
236+ const COMMON : Self = Self :: from_bits_truncate (
237+ Self :: USER_SEGMENT . bits ( )
238+ | Self :: PRESENT . bits ( )
239+ | Self :: WRITABLE . bits ( )
240+ | Self :: ACCESSED . bits ( ) ,
241+ ) ;
242+ // Flags that need to be set for all flat 32-bit segments
243+ const COMMON_FLAT : Self = Self :: from_bits_truncate (
244+ Self :: COMMON . bits ( )
245+ | Self :: LIMIT_0_15 . bits ( )
246+ | Self :: LIMIT_16_19 . bits ( )
247+ | Self :: GRANULARITY . bits ( ) ,
248+ ) ;
249+ /// A kernel data segment (64-bit or flat 32-bit)
250+ pub const KERNEL_DATA : Self =
251+ Self :: from_bits_truncate ( Self :: COMMON_FLAT . bits ( ) | Self :: DEFAULT_SIZE . bits ( ) ) ;
252+ /// A flat 32-bit kernel code segment
253+ pub const KERNEL_CODE32 : Self = Self :: from_bits_truncate (
254+ Self :: COMMON_FLAT . bits ( ) | Self :: EXECUTABLE . bits ( ) | Self :: DEFAULT_SIZE . bits ( ) ,
255+ ) ;
256+ /// A 64-bit kernel code segment
257+ pub const KERNEL_CODE64 : Self = Self :: from_bits_truncate (
258+ Self :: COMMON . bits ( ) | Self :: EXECUTABLE . bits ( ) | Self :: LONG_MODE . bits ( ) ,
259+ ) ;
260+ /// A user data segment (64-bit or flat 32-bit)
261+ pub const USER_DATA : Self =
262+ Self :: from_bits_truncate ( Self :: KERNEL_DATA . bits ( ) | Self :: DPL_RING_3 . bits ( ) ) ;
263+ /// A flat 32-bit user code segment
264+ pub const USER_CODE32 : Self =
265+ Self :: from_bits_truncate ( Self :: KERNEL_CODE32 . bits ( ) | Self :: DPL_RING_3 . bits ( ) ) ;
266+ /// A 64-bit user code segment
267+ pub const USER_CODE64 : Self =
268+ Self :: from_bits_truncate ( Self :: KERNEL_CODE64 . bits ( ) | Self :: DPL_RING_3 . bits ( ) ) ;
269+ }
270+
244271impl Descriptor {
245272 /// Creates a segment descriptor for a 64-bit kernel code segment.
246273 #[ inline]
@@ -291,13 +318,15 @@ mod tests {
291318 #[ test]
292319 #[ rustfmt:: skip]
293320 pub fn linux_kernel_defaults ( ) {
294- // Make sure our defaults match the ones used by the Linux kernel.
321+ // Make sure our 32-bit defaults match the ones used by the Linux kernel.
295322 // Constants pulled from an old version of arch/x86/kernel/cpu/common.c
296323 assert_eq ! ( Flags :: KERNEL_CODE32 . bits( ) , 0x00cf9b000000ffff ) ;
297- assert_eq ! ( Flags :: KERNEL_CODE64 . bits( ) , 0x00af9b000000ffff ) ;
298324 assert_eq ! ( Flags :: KERNEL_DATA . bits( ) , 0x00cf93000000ffff ) ;
299325 assert_eq ! ( Flags :: USER_CODE32 . bits( ) , 0x00cffb000000ffff ) ;
300326 assert_eq ! ( Flags :: USER_DATA . bits( ) , 0x00cff3000000ffff ) ;
301- assert_eq ! ( Flags :: USER_CODE64 . bits( ) , 0x00affb000000ffff ) ;
327+
328+ // Our 64-bit code segments only use a subset of the kernel's flags
329+ assert ! ( Flags :: from_bits( 0x00af9b000000ffff ) . unwrap( ) . contains( Flags :: KERNEL_CODE64 ) ) ;
330+ assert ! ( Flags :: from_bits( 0x00affb000000ffff ) . unwrap( ) . contains( Flags :: KERNEL_CODE64 ) ) ;
302331 }
303332}
0 commit comments