@@ -184,55 +184,80 @@ 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
+ 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.
188
191
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.
191
195
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 .
193
197
const EXECUTABLE = 1 << 43 ;
194
198
/// This flag must be set for user segments (in contrast to system segments).
195
199
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 ;
196
202
/// Must be set for any segment, causes a segment not present exception if not set.
197
203
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.
199
207
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 ;
200
213
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;
203
241
}
204
242
}
205
243
206
244
impl 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.
208
246
#[ 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 ( ) )
214
249
}
215
250
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) .
217
252
#[ 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 ( ) )
223
255
}
224
256
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.
226
258
#[ 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 ( ) )
236
261
}
237
262
238
263
/// Creates a TSS system descriptor for the given TSS.
@@ -258,3 +283,21 @@ impl Descriptor {
258
283
Descriptor :: SystemSegment ( low, high)
259
284
}
260
285
}
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