From 8764deb8dd0d3e60ac191c48f10c542c6dc9445b Mon Sep 17 00:00:00 2001 From: Junichi Uekawa Date: Fri, 21 Jan 2022 17:17:58 +0900 Subject: [PATCH] crosvm: Minimal change for manatee memory mapping. Do not map RAM to where the coreboot regions are. Shift boot time GDT and IDT a bit to make way for coreboot region at 0..fff. BUG=b:188011323 TEST=boot volteer-manatee TEST=tast run rammus-arc-r arc.Boot.vm # ARCVM still boots. TEST=tast run rammus-arc-r crostini.Basic.bullseye_stable volteer-manatee memory map: after: localhost ~ # dmesg | grep e820 [ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable [ 0.000000] BIOS-e820: [mem 0x0000000000200000-0x00000000cfffffff] usable [ 0.000000] BIOS-e820: [mem 0x00000000f4000000-0x00000000f7ffffff] reserved [ 0.000000] BIOS-e820: [mem 0x0000000100000000-0x00000003f05fffff] usable before: localhost ~ # dmesg | grep e820 [ 0.000000] BIOS-e820: [mem 0x0000000000001000-0x000000000009fbff] usable [ 0.000000] BIOS-e820: [mem 0x0000000000200000-0x000000005fffffff] usable [ 0.000000] BIOS-e820: [mem 0x00000000f4000000-0x00000000f7ffffff] reserved [ 0.000000] BIOS-e820: [mem 0x0000000100000000-0x0000000460600fff] usable Change-Id: Ifa19988c444d79dc81eb77c59e5b5434abf883fb Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3405402 Reviewed-by: Daniel Verkamp Tested-by: kokoro Commit-Queue: Junichi Uekawa --- Cargo.toml | 2 +- x86_64/Cargo.toml | 1 + x86_64/src/lib.rs | 104 ++++++++++++++++++++++++++++++++++----------- x86_64/src/regs.rs | 4 +- 4 files changed, 83 insertions(+), 28 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ec9ef88d7b..9bb5bcb3bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -104,7 +104,7 @@ chromeos = ["base/chromeos", "audio_cras", "devices/chromeos"] composite-disk = ["protos/composite-disk", "protobuf", "disk/composite-disk"] default = ["audio", "gpu", "usb"] default-no-sandbox = [] -direct = ["devices/direct"] +direct = ["devices/direct", "x86_64/direct"] gdb = ["gdbstub", "gdbstub_arch", "arch/gdb", "vm_control/gdb", "x86_64/gdb"] gfxstream = ["devices/gfxstream"] gpu = ["devices/gpu"] diff --git a/x86_64/Cargo.toml b/x86_64/Cargo.toml index 22c42e08f0..2e8ecd2d2e 100644 --- a/x86_64/Cargo.toml +++ b/x86_64/Cargo.toml @@ -6,6 +6,7 @@ edition = "2018" [features] gdb = ["gdbstub_arch", "arch/gdb"] +direct = [] [dependencies] arch = { path = "../arch" } diff --git a/x86_64/src/lib.rs b/x86_64/src/lib.rs index 94fd5e5b52..e8e7053921 100644 --- a/x86_64/src/lib.rs +++ b/x86_64/src/lib.rs @@ -195,7 +195,18 @@ const GB: u64 = 1 << 30; const BOOT_STACK_POINTER: u64 = 0x8000; // Make sure it align to 256MB for MTRR convenient -const MEM_32BIT_GAP_SIZE: u64 = 768 * MB; +const MEM_32BIT_GAP_SIZE: u64 = if cfg!(feature = "direct") { + // Allow space for identity mapping coreboot memory regions on the host + // which is found at around 7a00_0000 (little bit before 2GB) + // + // TODO(b/188011323): stop hardcoding sizes and addresses here and instead + // determine the memory map from how the VM has been configured via the + // command line. + 2560 * MB +} else { + 768 * MB +}; +const START_OF_RAM_32BITS: u64 = if cfg!(feature = "direct") { 0x1000 } else { 0 }; const FIRST_ADDR_PAST_32BITS: u64 = 1 << 32; // Reserved memory for nand_bios/LAPIC/IOAPIC/HPET/..... const RESERVED_MEM_SIZE: u64 = 0x800_0000; @@ -264,7 +275,12 @@ fn configure_system( params.hdr.ramdisk_size = initrd_size as u32; } - add_e820_entry(&mut params, 0, EBDA_START, E820Type::Ram)?; + add_e820_entry( + &mut params, + START_OF_RAM_32BITS, + EBDA_START - START_OF_RAM_32BITS, + E820Type::Ram, + )?; let mem_end = guest_mem.end_addr(); if mem_end < end_32bit_gap_start { @@ -334,18 +350,21 @@ fn add_e820_entry( /// For x86_64 all addresses are valid from the start of the kernel except a /// carve out at the end of 32bit address space. fn arch_memory_regions(size: u64, bios_size: Option) -> Vec<(GuestAddress, u64)> { - let mem_end = GuestAddress(size); + let mem_start = START_OF_RAM_32BITS; + let mem_end = GuestAddress(size + mem_start); let first_addr_past_32bits = GuestAddress(FIRST_ADDR_PAST_32BITS); let end_32bit_gap_start = GuestAddress(END_ADDR_BEFORE_32BITS); - let mut regions = Vec::new(); if mem_end <= end_32bit_gap_start { - regions.push((GuestAddress(0), size)); + regions.push((GuestAddress(mem_start), size)); if let Some(bios_size) = bios_size { regions.push((bios_start(bios_size), bios_size)); } } else { - regions.push((GuestAddress(0), end_32bit_gap_start.offset())); + regions.push(( + GuestAddress(mem_start), + end_32bit_gap_start.offset() - mem_start, + )); if let Some(bios_size) = bios_size { regions.push((bios_start(bios_size), bios_size)); } @@ -1364,27 +1383,29 @@ mod tests { #[test] fn regions_lt_4gb_nobios() { - let regions = arch_memory_regions(1u64 << 29, /* bios_size */ None); + let regions = arch_memory_regions(512 * MB, /* bios_size */ None); assert_eq!(1, regions.len()); - assert_eq!(GuestAddress(0), regions[0].0); + assert_eq!(GuestAddress(START_OF_RAM_32BITS), regions[0].0); assert_eq!(1u64 << 29, regions[0].1); } #[test] fn regions_gt_4gb_nobios() { - let regions = arch_memory_regions((1u64 << 32) + 0x8000, /* bios_size */ None); + let size = 4 * GB + 0x8000; + let regions = arch_memory_regions(size, /* bios_size */ None); assert_eq!(2, regions.len()); - assert_eq!(GuestAddress(0), regions[0].0); - assert_eq!(GuestAddress(1u64 << 32), regions[1].0); + assert_eq!(GuestAddress(START_OF_RAM_32BITS), regions[0].0); + assert_eq!(GuestAddress(4 * GB), regions[1].0); + assert_eq!(4 * GB + 0x8000, regions[0].1 + regions[1].1); } #[test] fn regions_lt_4gb_bios() { let bios_len = 1 * MB; - let regions = arch_memory_regions(1u64 << 29, Some(bios_len)); + let regions = arch_memory_regions(512 * MB, Some(bios_len)); assert_eq!(2, regions.len()); - assert_eq!(GuestAddress(0), regions[0].0); - assert_eq!(1u64 << 29, regions[0].1); + assert_eq!(GuestAddress(START_OF_RAM_32BITS), regions[0].0); + assert_eq!(512 * MB, regions[0].1); assert_eq!( GuestAddress(FIRST_ADDR_PAST_32BITS - bios_len), regions[1].0 @@ -1395,38 +1416,71 @@ mod tests { #[test] fn regions_gt_4gb_bios() { let bios_len = 1 * MB; - let regions = arch_memory_regions((1u64 << 32) + 0x8000, Some(bios_len)); + let regions = arch_memory_regions(4 * GB + 0x8000, Some(bios_len)); assert_eq!(3, regions.len()); - assert_eq!(GuestAddress(0), regions[0].0); + assert_eq!(GuestAddress(START_OF_RAM_32BITS), regions[0].0); assert_eq!( GuestAddress(FIRST_ADDR_PAST_32BITS - bios_len), regions[1].0 ); assert_eq!(bios_len, regions[1].1); - assert_eq!(GuestAddress(1u64 << 32), regions[2].0); + assert_eq!(GuestAddress(4 * GB), regions[2].0); } #[test] fn regions_eq_4gb_nobios() { - // Test with size = 3328, which is exactly 4 GiB minus the size of the gap (768 MB). - let regions = arch_memory_regions(3328 * MB, /* bios_size */ None); + // Test with exact size of 4GB - the overhead. + let regions = arch_memory_regions( + 4 * GB - MEM_32BIT_GAP_SIZE - START_OF_RAM_32BITS, + /* bios_size */ None, + ); + dbg!(®ions); assert_eq!(1, regions.len()); - assert_eq!(GuestAddress(0), regions[0].0); - assert_eq!(3328 * MB, regions[0].1); + assert_eq!(GuestAddress(START_OF_RAM_32BITS), regions[0].0); + assert_eq!( + 4 * GB - MEM_32BIT_GAP_SIZE - START_OF_RAM_32BITS, + regions[0].1 + ); } #[test] fn regions_eq_4gb_bios() { - // Test with size = 3328, which is exactly 4 GiB minus the size of the gap (768 MB). + // Test with exact size of 4GB - the overhead. let bios_len = 1 * MB; - let regions = arch_memory_regions(3328 * MB, Some(bios_len)); + let regions = arch_memory_regions( + 4 * GB - MEM_32BIT_GAP_SIZE - START_OF_RAM_32BITS, + Some(bios_len), + ); assert_eq!(2, regions.len()); - assert_eq!(GuestAddress(0), regions[0].0); - assert_eq!(3328 * MB, regions[0].1); + assert_eq!(GuestAddress(START_OF_RAM_32BITS), regions[0].0); + assert_eq!( + 4 * GB - MEM_32BIT_GAP_SIZE - START_OF_RAM_32BITS, + regions[0].1 + ); assert_eq!( GuestAddress(FIRST_ADDR_PAST_32BITS - bios_len), regions[1].0 ); assert_eq!(bios_len, regions[1].1); } + + #[test] + #[cfg(feature = "direct")] + fn end_addr_before_32bits() { + // On volteer, type16 (coreboot) region is at 0x00000000769f3000-0x0000000076ffffff. + // On brya, type16 region is at 0x0000000076876000-0x00000000803fffff + let brya_type16_address = 0x7687_6000; + assert!( + END_ADDR_BEFORE_32BITS < brya_type16_address, + "{} < {}", + END_ADDR_BEFORE_32BITS, + brya_type16_address + ); + } + + #[test] + fn check_32bit_gap_size_alignment() { + // 32bit gap memory is 256 MB aligned to be friendly for MTRR mappings. + assert_eq!(MEM_32BIT_GAP_SIZE % (256 * MB), 0); + } } diff --git a/x86_64/src/regs.rs b/x86_64/src/regs.rs index 3ede53c78c..82df5d99ca 100644 --- a/x86_64/src/regs.rs +++ b/x86_64/src/regs.rs @@ -244,8 +244,8 @@ const X86_CR4_PAE: u64 = 0x20; const EFER_LME: u64 = 0x100; const EFER_LMA: u64 = 0x400; -const BOOT_GDT_OFFSET: u64 = 0x500; -const BOOT_IDT_OFFSET: u64 = 0x520; +const BOOT_GDT_OFFSET: u64 = 0x1500; +const BOOT_IDT_OFFSET: u64 = 0x1520; const BOOT_GDT_MAX: usize = 4;