@@ -184,55 +184,80 @@ pub enum Descriptor {
184184bitflags ! {
185185 /// Flags for a GDT descriptor. Not all flags are valid for all descriptor types.
186186 pub struct DescriptorFlags : u64 {
187- /// For data segments, this flag sets the segment as writable. Ignored for code segments.
187+ /// Set by the processor if this segment has been accessed. Only cleared by software.
188+ const ACCESSED = 1 << 40 ;
189+ /// For 32-bit data segments, sets the segment as writable. For 32-bit code segments,
190+ /// sets the segment as _readable_. In 64-bit mode, ignored for all segments.
188191 const WRITABLE = 1 << 41 ;
189- /// Marks a code segment as “conforming”. This influences the privilege checks that
190- /// occur on control transfers.
192+ /// For code segments, sets the segment as “conforming”, influencing the
193+ /// privilege checks that occur on control transfers. For 32-bit data segments,
194+ /// sets the segment as "expand down". In 64-bit mode, ignored for data segments.
191195 const CONFORMING = 1 << 42 ;
192- /// This flag must be set for code segments.
196+ /// This flag must be set for code segments and unset for data segments .
193197 const EXECUTABLE = 1 << 43 ;
194198 /// This flag must be set for user segments (in contrast to system segments).
195199 const USER_SEGMENT = 1 << 44 ;
200+ /// The DPL for this descriptor is Ring 3. In 64-bit mode, ignored for data segments.
201+ const DPL_RING_3 = 3 << 45 ;
196202 /// Must be set for any segment, causes a segment not present exception if not set.
197203 const PRESENT = 1 << 47 ;
198- /// Must be set for long mode code segments.
204+ /// Available for use by the Operating System
205+ const AVAILABLE = 1 << 52 ;
206+ /// Must be set for 64-bit code segments, unset otherwise.
199207 const LONG_MODE = 1 << 53 ;
208+ /// Use 32-bit (as opposed to 16-bit) operands. If [`LONG_MODE`] is set,
209+ /// this must be unset. In 64-bit mode, ignored for data segments.
210+ const DEFAULT_SIZE = 1 << 54 ;
211+ /// Limit field is scaled by 4096 bytes. In 64-bit mode, ignored for all segments.
212+ const GRANULARITY = 1 << 55 ;
200213
201- /// The DPL for this descriptor is Ring 3
202- const DPL_RING_3 = 3 << 45 ;
214+ /// Bits 0..=15 of the limit field (ignored in 64-bit mode)
215+ const LIMIT_0_15 = 0xFFFF ;
216+ /// Bits 16..=19 of the limit field (ignored in 64-bit mode)
217+ const LIMIT_16_19 = 0xF << 48 ;
218+ /// Bits 0..=23 of the base field (ignored in 64-bit mode)
219+ const BASE_0_23 = 0xFF_FFFF << 16 ;
220+ /// Bits 24..=31 of the base field (ignored in 64-bit mode)
221+ 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;
203241 }
204242}
205243
206244impl Descriptor {
207- /// Creates a segment descriptor for a long mode kernel code segment.
245+ /// Creates a segment descriptor for a 64-bit kernel code segment.
208246 #[ inline]
209- pub fn kernel_code_segment ( ) -> Descriptor {
210- use self :: DescriptorFlags as Flags ;
211-
212- let flags = Flags :: USER_SEGMENT | Flags :: PRESENT | Flags :: EXECUTABLE | Flags :: LONG_MODE ;
213- Descriptor :: UserSegment ( flags. bits ( ) )
247+ pub const fn kernel_code_segment ( ) -> Descriptor {
248+ Descriptor :: UserSegment ( DescriptorFlags :: KERNEL_CODE64 . bits ( ) )
214249 }
215250
216- /// Creates a segment descriptor for a long mode ring 3 data segment.
251+ /// Creates a segment descriptor for a ring 3 data segment (64-bit or 32-bit) .
217252 #[ inline]
218- pub fn user_data_segment ( ) -> Descriptor {
219- use self :: DescriptorFlags as Flags ;
220-
221- let flags = Flags :: USER_SEGMENT | Flags :: PRESENT | Flags :: WRITABLE | Flags :: DPL_RING_3 ;
222- Descriptor :: UserSegment ( flags. bits ( ) )
253+ pub const fn user_data_segment ( ) -> Descriptor {
254+ Descriptor :: UserSegment ( DescriptorFlags :: USER_DATA . bits ( ) )
223255 }
224256
225- /// Creates a segment descriptor for a long mode ring 3 code segment.
257+ /// Creates a segment descriptor for a 64-bit ring 3 code segment.
226258 #[ inline]
227- pub fn user_code_segment ( ) -> Descriptor {
228- use self :: DescriptorFlags as Flags ;
229-
230- let flags = Flags :: USER_SEGMENT
231- | Flags :: PRESENT
232- | Flags :: EXECUTABLE
233- | Flags :: LONG_MODE
234- | Flags :: DPL_RING_3 ;
235- Descriptor :: UserSegment ( flags. bits ( ) )
259+ pub const fn user_code_segment ( ) -> Descriptor {
260+ Descriptor :: UserSegment ( DescriptorFlags :: USER_CODE64 . bits ( ) )
236261 }
237262
238263 /// Creates a TSS system descriptor for the given TSS.
@@ -258,3 +283,21 @@ impl Descriptor {
258283 Descriptor :: SystemSegment ( low, high)
259284 }
260285}
286+
287+ #[ cfg( test) ]
288+ mod tests {
289+ use super :: DescriptorFlags as Flags ;
290+
291+ #[ test]
292+ #[ rustfmt:: skip]
293+ pub fn linux_kernel_defaults ( ) {
294+ // Make sure our defaults match the ones used by the Linux kernel.
295+ // Constants pulled from an old version of arch/x86/kernel/cpu/common.c
296+ assert_eq ! ( Flags :: KERNEL_CODE32 . bits( ) , 0x00cf9b000000ffff ) ;
297+ assert_eq ! ( Flags :: KERNEL_CODE64 . bits( ) , 0x00af9b000000ffff ) ;
298+ assert_eq ! ( Flags :: KERNEL_DATA . bits( ) , 0x00cf93000000ffff ) ;
299+ assert_eq ! ( Flags :: USER_CODE32 . bits( ) , 0x00cffb000000ffff ) ;
300+ assert_eq ! ( Flags :: USER_DATA . bits( ) , 0x00cff3000000ffff ) ;
301+ assert_eq ! ( Flags :: USER_CODE64 . bits( ) , 0x00affb000000ffff ) ;
302+ }
303+ }
0 commit comments