x86_64: add a null GDT entry for 64-bit protocol

Based on https://docs.kernel.org/arch/x86/boot.html#id1, this patch
adds a null GDT entry to match the Linux 64-bit Boot Protocol. With
this patch, CS is 0x10, DS, ES, and SS are 0x18.

Booted a bzImage and an ELF kernel, no issues observed.

TEST=cargo test -p x86_64
BUG=None

Change-Id: I234e9c43598fd5edb9d4e1b0fed1ba67f06a1845
Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/4680287
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Commit-Queue: Changyuan Lyu <changyuanl@google.com>
This commit is contained in:
Changyuan Lyu 2023-07-12 13:13:18 -07:00 committed by crosvm LUCI
parent c244741015
commit 9c8f539695

View file

@ -228,9 +228,9 @@ const EFER_LME: u64 = 0x100;
const EFER_LMA: u64 = 0x400;
const BOOT_GDT_OFFSET: u64 = 0x1500;
const BOOT_IDT_OFFSET: u64 = 0x1520;
const BOOT_IDT_OFFSET: u64 = 0x1528;
const BOOT_GDT_MAX: usize = 4;
const BOOT_GDT_MAX: usize = 5;
fn write_gdt_table(table: &[u64], guest_mem: &GuestMemory) -> Result<()> {
let boot_gdt_addr = GuestAddress(BOOT_GDT_OFFSET);
@ -258,16 +258,18 @@ fn write_idt_value(val: u64, guest_mem: &GuestMemory) -> Result<()> {
/// Configures the GDT, IDT, and segment registers for long mode.
pub fn configure_segments_and_sregs(mem: &GuestMemory, sregs: &mut Sregs) -> Result<()> {
// reference: https://docs.kernel.org/arch/x86/boot.html?highlight=__BOOT_CS#id1
let gdt_table: [u64; BOOT_GDT_MAX] = [
gdt::gdt_entry(0, 0, 0), // NULL
gdt::gdt_entry(0, 0, 0), // NULL
gdt::gdt_entry(0xa09b, 0, 0xfffff), // CODE
gdt::gdt_entry(0xc093, 0, 0xfffff), // DATA
gdt::gdt_entry(0x808b, 0, 0xfffff), // TSS
];
let code_seg = gdt::segment_from_gdt(gdt_table[1], 1);
let data_seg = gdt::segment_from_gdt(gdt_table[2], 2);
let tss_seg = gdt::segment_from_gdt(gdt_table[3], 3);
let code_seg = gdt::segment_from_gdt(gdt_table[2], 2);
let data_seg = gdt::segment_from_gdt(gdt_table[3], 3);
let tss_seg = gdt::segment_from_gdt(gdt_table[4], 4);
// Write segments
write_gdt_table(&gdt_table[..], mem)?;
@ -344,14 +346,17 @@ mod tests {
configure_segments_and_sregs(&gm, &mut sregs).unwrap();
assert_eq!(0x0, read_u64(&gm, BOOT_GDT_OFFSET));
assert_eq!(0xaf9b000000ffff, read_u64(&gm, BOOT_GDT_OFFSET + 8));
assert_eq!(0xcf93000000ffff, read_u64(&gm, BOOT_GDT_OFFSET + 16));
assert_eq!(0x8f8b000000ffff, read_u64(&gm, BOOT_GDT_OFFSET + 24));
assert_eq!(0xaf9b000000ffff, read_u64(&gm, BOOT_GDT_OFFSET + 0x10));
assert_eq!(0xcf93000000ffff, read_u64(&gm, BOOT_GDT_OFFSET + 0x18));
assert_eq!(0x8f8b000000ffff, read_u64(&gm, BOOT_GDT_OFFSET + 0x20));
assert_eq!(0x0, read_u64(&gm, BOOT_IDT_OFFSET));
assert_eq!(0, sregs.cs.base);
assert_eq!(0xfffff, sregs.ds.limit);
assert_eq!(0x10, sregs.es.selector);
assert_eq!(0x10, sregs.cs.selector);
assert_eq!(0x18, sregs.ds.selector);
assert_eq!(0x18, sregs.es.selector);
assert_eq!(0x18, sregs.ss.selector);
assert_eq!(1, sregs.fs.present);
assert_eq!(1, sregs.gs.g);
assert_eq!(0, sregs.ss.avl);