Skip to content

Commit 2516997

Browse files
committed
gdt: Set unused bits for syscall/sysret compatiblity
Also update the documentation to note that fs/gs don't ignored the BASE value. Signed-off-by: Joe Richey <[email protected]>
1 parent 9a0524c commit 2516997

File tree

1 file changed

+27
-22
lines changed

1 file changed

+27
-22
lines changed

src/structures/gdt.rs

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -216,42 +216,39 @@ bitflags! {
216216
const LIMIT_0_15 = 0xFFFF;
217217
/// Bits `16..=19` of the limit field (ignored in 64-bit mode)
218218
const LIMIT_16_19 = 0xF << 48;
219-
/// 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, except for fs and gs)
220220
const BASE_0_23 = 0xFF_FFFF << 16;
221-
/// 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, except for fs and gs)
222222
const BASE_24_31 = 0xFF << 56;
223223
}
224224
}
225225

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].
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.
230231
///
231232
/// In short, these values disable segmentation, permission checks, and access
232233
/// tracking at the GDT level. Kernels using these values should use paging to
233234
/// implement this functionality.
234235
impl DescriptorFlags {
235-
// Flags that we set for all user segments
236+
// Flags that we set for all our default segments
236237
const COMMON: Self = Self::from_bits_truncate(
237238
Self::USER_SEGMENT.bits()
238239
| Self::PRESENT.bits()
239240
| 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()
241+
| Self::ACCESSED.bits()
245242
| Self::LIMIT_0_15.bits()
246243
| Self::LIMIT_16_19.bits()
247244
| Self::GRANULARITY.bits(),
248245
);
249246
/// A kernel data segment (64-bit or flat 32-bit)
250247
pub const KERNEL_DATA: Self =
251-
Self::from_bits_truncate(Self::COMMON_FLAT.bits() | Self::DEFAULT_SIZE.bits());
248+
Self::from_bits_truncate(Self::COMMON.bits() | Self::DEFAULT_SIZE.bits());
252249
/// A flat 32-bit kernel code segment
253250
pub const KERNEL_CODE32: Self = Self::from_bits_truncate(
254-
Self::COMMON_FLAT.bits() | Self::EXECUTABLE.bits() | Self::DEFAULT_SIZE.bits(),
251+
Self::COMMON.bits() | Self::EXECUTABLE.bits() | Self::DEFAULT_SIZE.bits(),
255252
);
256253
/// A 64-bit kernel code segment
257254
pub const KERNEL_CODE64: Self = Self::from_bits_truncate(
@@ -269,19 +266,29 @@ impl DescriptorFlags {
269266
}
270267

271268
impl Descriptor {
272-
/// Creates a segment descriptor for a 64-bit 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`.
273271
#[inline]
274272
pub const fn kernel_code_segment() -> Descriptor {
275273
Descriptor::UserSegment(DescriptorFlags::KERNEL_CODE64.bits())
276274
}
277275

278-
/// Creates a segment descriptor for a ring 3 data segment (64-bit or 32-bit).
276+
/// Creates a segment descriptor for a kernel data segment (32-bit or
277+
/// 64-bit). Suitable for use with `syscall` or `sysenter`.
278+
#[inline]
279+
pub const fn kernel_data_segment() -> Descriptor {
280+
Descriptor::UserSegment(DescriptorFlags::KERNEL_DATA.bits())
281+
}
282+
283+
/// Creates a segment descriptor for a ring 3 data segment (32-bit or
284+
/// 64-bit). Suitable for use with `sysret` or `sysexit`.
279285
#[inline]
280286
pub const fn user_data_segment() -> Descriptor {
281287
Descriptor::UserSegment(DescriptorFlags::USER_DATA.bits())
282288
}
283289

284-
/// Creates a segment descriptor for a 64-bit ring 3 code segment.
290+
/// Creates a segment descriptor for a 64-bit ring 3 code segment. Suitable
291+
/// for use with `sysret` or `sysexit`.
285292
#[inline]
286293
pub const fn user_code_segment() -> Descriptor {
287294
Descriptor::UserSegment(DescriptorFlags::USER_CODE64.bits())
@@ -318,15 +325,13 @@ mod tests {
318325
#[test]
319326
#[rustfmt::skip]
320327
pub fn linux_kernel_defaults() {
321-
// Make sure our 32-bit defaults match the ones used by the Linux kernel.
328+
// Make sure our defaults match the ones used by the Linux kernel.
322329
// Constants pulled from an old version of arch/x86/kernel/cpu/common.c
330+
assert_eq!(Flags::KERNEL_CODE64.bits(), 0x00af9b000000ffff);
323331
assert_eq!(Flags::KERNEL_CODE32.bits(), 0x00cf9b000000ffff);
324332
assert_eq!(Flags::KERNEL_DATA.bits(), 0x00cf93000000ffff);
333+
assert_eq!(Flags::USER_CODE64.bits(), 0x00affb000000ffff);
325334
assert_eq!(Flags::USER_CODE32.bits(), 0x00cffb000000ffff);
326335
assert_eq!(Flags::USER_DATA.bits(), 0x00cff3000000ffff);
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));
331336
}
332337
}

0 commit comments

Comments
 (0)