Skip to content

Commit 9a0524c

Browse files
committed
gdt: Clarify documentation and move flags
Signed-off-by: Joe Richey <[email protected]>
1 parent dd049bb commit 9a0524c

File tree

1 file changed

+56
-27
lines changed

1 file changed

+56
-27
lines changed

src/structures/gdt.rs

+56-27
Original file line numberDiff line numberDiff line change
@@ -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+
244271
impl 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

Comments
 (0)