@@ -184,55 +184,114 @@ pub enum Descriptor {
184
184
bitflags ! {
185
185
/// Flags for a GDT descriptor. Not all flags are valid for all descriptor types.
186
186
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.
188
192
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.
191
196
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 .
193
198
const EXECUTABLE = 1 << 43 ;
194
199
/// This flag must be set for user segments (in contrast to system segments).
195
200
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 ;
196
203
/// Must be set for any segment, causes a segment not present exception if not set.
197
204
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.
199
208
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 ;
200
214
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 ;
203
223
}
204
224
}
205
225
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
+
206
268
impl 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`.
208
271
#[ 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 ( ) )
214
274
}
215
275
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`.
217
278
#[ 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 ( ) )
223
281
}
224
282
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`.
226
285
#[ 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
+ }
229
289
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 ( ) )
236
295
}
237
296
238
297
/// Creates a TSS system descriptor for the given TSS.
@@ -258,3 +317,21 @@ impl Descriptor {
258
317
Descriptor :: SystemSegment ( low, high)
259
318
}
260
319
}
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