@@ -184,55 +184,114 @@ 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+ /// _Setting_ this bit in software prevents GDT writes on first use.
189+ const ACCESSED = 1 << 40 ;
190+ /// For 32-bit data segments, sets the segment as writable. For 32-bit code segments,
191+ /// sets the segment as _readable_. In 64-bit mode, ignored for all segments.
188192 const WRITABLE = 1 << 41 ;
189- /// Marks a code segment as “conforming”. This influences the privilege checks that
190- /// occur on control transfers.
193+ /// For code segments, sets the segment as “conforming”, influencing the
194+ /// privilege checks that occur on control transfers. For 32-bit data segments,
195+ /// sets the segment as "expand down". In 64-bit mode, ignored for data segments.
191196 const CONFORMING = 1 << 42 ;
192- /// This flag must be set for code segments.
197+ /// This flag must be set for code segments and unset for data segments .
193198 const EXECUTABLE = 1 << 43 ;
194199 /// This flag must be set for user segments (in contrast to system segments).
195200 const USER_SEGMENT = 1 << 44 ;
201+ /// The DPL for this descriptor is Ring 3. In 64-bit mode, ignored for data segments.
202+ const DPL_RING_3 = 3 << 45 ;
196203 /// Must be set for any segment, causes a segment not present exception if not set.
197204 const PRESENT = 1 << 47 ;
198- /// Must be set for long mode code segments.
205+ /// Available for use by the Operating System
206+ const AVAILABLE = 1 << 52 ;
207+ /// Must be set for 64-bit code segments, unset otherwise.
199208 const LONG_MODE = 1 << 53 ;
209+ /// Use 32-bit (as opposed to 16-bit) operands. If [`LONG_MODE`][Self::LONG_MODE] is set,
210+ /// this must be unset. In 64-bit mode, ignored for data segments.
211+ const DEFAULT_SIZE = 1 << 54 ;
212+ /// Limit field is scaled by 4096 bytes. In 64-bit mode, ignored for all segments.
213+ const GRANULARITY = 1 << 55 ;
200214
201- /// The DPL for this descriptor is Ring 3
202- const DPL_RING_3 = 3 << 45 ;
215+ /// Bits `0..=15` of the limit field (ignored in 64-bit mode)
216+ const LIMIT_0_15 = 0xFFFF ;
217+ /// Bits `16..=19` of the limit field (ignored in 64-bit mode)
218+ const LIMIT_16_19 = 0xF << 48 ;
219+ /// Bits `0..=23` of the base field (ignored in 64-bit mode, except for fs and gs)
220+ const BASE_0_23 = 0xFF_FFFF << 16 ;
221+ /// Bits `24..=31` of the base field (ignored in 64-bit mode, except for fs and gs)
222+ const BASE_24_31 = 0xFF << 56 ;
203223 }
204224}
205225
226+ /// The following constants define default values for common GDT entries. They
227+ /// are all "flat" segments, meaning they can access the entire address space.
228+ /// These values all set [`WRITABLE`][DescriptorFlags::WRITABLE] and
229+ /// [`ACCESSED`][DescriptorFlags::ACCESSED]. They also match the values loaded
230+ /// by the `syscall`/`sysret` and `sysenter`/`sysexit` instructions.
231+ ///
232+ /// In short, these values disable segmentation, permission checks, and access
233+ /// tracking at the GDT level. Kernels using these values should use paging to
234+ /// implement this functionality.
235+ impl DescriptorFlags {
236+ // Flags that we set for all our default segments
237+ const COMMON : Self = Self :: from_bits_truncate (
238+ Self :: USER_SEGMENT . bits ( )
239+ | Self :: PRESENT . bits ( )
240+ | Self :: WRITABLE . bits ( )
241+ | Self :: ACCESSED . bits ( )
242+ | Self :: LIMIT_0_15 . bits ( )
243+ | Self :: LIMIT_16_19 . bits ( )
244+ | Self :: GRANULARITY . bits ( ) ,
245+ ) ;
246+ /// A kernel data segment (64-bit or flat 32-bit)
247+ pub const KERNEL_DATA : Self =
248+ Self :: from_bits_truncate ( Self :: COMMON . bits ( ) | Self :: DEFAULT_SIZE . bits ( ) ) ;
249+ /// A flat 32-bit kernel code segment
250+ pub const KERNEL_CODE32 : Self = Self :: from_bits_truncate (
251+ Self :: COMMON . bits ( ) | Self :: EXECUTABLE . bits ( ) | Self :: DEFAULT_SIZE . bits ( ) ,
252+ ) ;
253+ /// A 64-bit kernel code segment
254+ pub const KERNEL_CODE64 : Self = Self :: from_bits_truncate (
255+ Self :: COMMON . bits ( ) | Self :: EXECUTABLE . bits ( ) | Self :: LONG_MODE . bits ( ) ,
256+ ) ;
257+ /// A user data segment (64-bit or flat 32-bit)
258+ pub const USER_DATA : Self =
259+ Self :: from_bits_truncate ( Self :: KERNEL_DATA . bits ( ) | Self :: DPL_RING_3 . bits ( ) ) ;
260+ /// A flat 32-bit user code segment
261+ pub const USER_CODE32 : Self =
262+ Self :: from_bits_truncate ( Self :: KERNEL_CODE32 . bits ( ) | Self :: DPL_RING_3 . bits ( ) ) ;
263+ /// A 64-bit user code segment
264+ pub const USER_CODE64 : Self =
265+ Self :: from_bits_truncate ( Self :: KERNEL_CODE64 . bits ( ) | Self :: DPL_RING_3 . bits ( ) ) ;
266+ }
267+
206268impl Descriptor {
207- /// Creates a segment descriptor for a long mode kernel code segment.
269+ /// Creates a segment descriptor for a 64-bit kernel code segment. Suitable
270+ /// for use with `syscall` or 64-bit `sysenter`.
208271 #[ 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 ( ) )
272+ pub const fn kernel_code_segment ( ) -> Descriptor {
273+ Descriptor :: UserSegment ( DescriptorFlags :: KERNEL_CODE64 . bits ( ) )
214274 }
215275
216- /// Creates a segment descriptor for a long mode ring 3 data segment.
276+ /// Creates a segment descriptor for a kernel data segment (32-bit or
277+ /// 64-bit). Suitable for use with `syscall` or `sysenter`.
217278 #[ 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 ( ) )
279+ pub const fn kernel_data_segment ( ) -> Descriptor {
280+ Descriptor :: UserSegment ( DescriptorFlags :: KERNEL_DATA . bits ( ) )
223281 }
224282
225- /// Creates a segment descriptor for a long mode ring 3 code segment.
283+ /// Creates a segment descriptor for a ring 3 data segment (32-bit or
284+ /// 64-bit). Suitable for use with `sysret` or `sysexit`.
226285 #[ inline]
227- pub fn user_code_segment ( ) -> Descriptor {
228- use self :: DescriptorFlags as Flags ;
286+ pub const fn user_data_segment ( ) -> Descriptor {
287+ Descriptor :: UserSegment ( DescriptorFlags :: USER_DATA . bits ( ) )
288+ }
229289
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 ( ) )
290+ /// Creates a segment descriptor for a 64-bit ring 3 code segment. Suitable
291+ /// for use with `sysret` or `sysexit`.
292+ #[ inline]
293+ pub const fn user_code_segment ( ) -> Descriptor {
294+ Descriptor :: UserSegment ( DescriptorFlags :: USER_CODE64 . bits ( ) )
236295 }
237296
238297 /// Creates a TSS system descriptor for the given TSS.
@@ -258,3 +317,21 @@ impl Descriptor {
258317 Descriptor :: SystemSegment ( low, high)
259318 }
260319}
320+
321+ #[ cfg( test) ]
322+ mod tests {
323+ use super :: DescriptorFlags as Flags ;
324+
325+ #[ test]
326+ #[ rustfmt:: skip]
327+ pub fn linux_kernel_defaults ( ) {
328+ // Make sure our defaults match the ones used by the Linux kernel.
329+ // Constants pulled from an old version of arch/x86/kernel/cpu/common.c
330+ assert_eq ! ( Flags :: KERNEL_CODE64 . bits( ) , 0x00af9b000000ffff ) ;
331+ assert_eq ! ( Flags :: KERNEL_CODE32 . bits( ) , 0x00cf9b000000ffff ) ;
332+ assert_eq ! ( Flags :: KERNEL_DATA . bits( ) , 0x00cf93000000ffff ) ;
333+ assert_eq ! ( Flags :: USER_CODE64 . bits( ) , 0x00affb000000ffff ) ;
334+ assert_eq ! ( Flags :: USER_CODE32 . bits( ) , 0x00cffb000000ffff ) ;
335+ assert_eq ! ( Flags :: USER_DATA . bits( ) , 0x00cff3000000ffff ) ;
336+ }
337+ }
0 commit comments