Hi,
qemu got a new fw_cfg file named "etc/e820" carrying e820 ram regions and reservations. This little patch series makes seabios use it if present. It also moves qemu e820 initialization into its own function.
cheers, Gerd
Gerd Hoffmann (2): Add qemu_cfg_e820 function. Add support for etc/e820 fw_cfg file
src/fw/paravirt.c | 98 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 73 insertions(+), 25 deletions(-)
Move all ram detection and e820 setup to the new function, except for lowmem detection which must remain in preinit so we can initialize our memory allocator properly.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/fw/paravirt.c | 57 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 25 deletions(-)
diff --git a/src/fw/paravirt.c b/src/fw/paravirt.c index c118480..58973a2 100644 --- a/src/fw/paravirt.c +++ b/src/fw/paravirt.c @@ -115,17 +115,10 @@ qemu_preinit(void) RamSize = rs; add_e820(0, rs, E820_RAM);
- // Check for memory over 4Gig - u64 high = ((rtc_read(CMOS_MEM_HIGHMEM_LOW) << 16) - | ((u32)rtc_read(CMOS_MEM_HIGHMEM_MID) << 24) - | ((u64)rtc_read(CMOS_MEM_HIGHMEM_HIGH) << 32)); - RamSizeOver4G = high; - add_e820(0x100000000ull, high, E820_RAM); - /* reserve 256KB BIOS area at the end of 4 GB */ add_e820(0xfffc0000, 256*1024, E820_RESERVED);
- dprintf(1, "Ram Size=0x%08x (0x%016llx high)\n", RamSize, RamSizeOver4G); + dprintf(1, "RamSize: 0x%08x [cmos]\n", RamSize); }
void @@ -254,6 +247,35 @@ struct qemu_smbios_header { u16 fieldoffset; } PACKED;
+static void +qemu_cfg_e820(void) +{ + // QEMU_CFG_E820_TABLE has reservations only + u32 count32; + qemu_cfg_read_entry(&count32, QEMU_CFG_E820_TABLE, sizeof(count32)); + if (count32) { + struct e820_reservation entry; + int i; + for (i = 0; i < count32; i++) { + qemu_cfg_read(&entry, sizeof(entry)); + add_e820(entry.address, entry.length, entry.type); + } + } else if (runningOnKVM()) { + // Backwards compatibility - provide hard coded range. + // 4 pages before the bios, 3 pages for vmx tss pages, the + // other page for EPT real mode pagetable + add_e820(0xfffbc000, 4*4096, E820_RESERVED); + } + + // Check for memory over 4Gig in cmos + u64 high = ((rtc_read(CMOS_MEM_HIGHMEM_LOW) << 16) + | ((u32)rtc_read(CMOS_MEM_HIGHMEM_MID) << 24) + | ((u64)rtc_read(CMOS_MEM_HIGHMEM_HIGH) << 32)); + RamSizeOver4G = high; + add_e820(0x100000000ull, high, E820_RAM); + dprintf(1, "RamSizeOver4G: 0x%016llx [cmos]\n", RamSizeOver4G); +} + // Populate romfile entries for legacy fw_cfg ports (that predate the // "file" interface). static void @@ -277,23 +299,6 @@ qemu_cfg_legacy(void) , sizeof(numacount) + max_cpu*sizeof(u64) , numacount*sizeof(u64));
- // e820 data - u32 count32; - qemu_cfg_read_entry(&count32, QEMU_CFG_E820_TABLE, sizeof(count32)); - if (count32) { - struct e820_reservation entry; - int i; - for (i = 0; i < count32; i++) { - qemu_cfg_read(&entry, sizeof(entry)); - add_e820(entry.address, entry.length, entry.type); - } - } else if (runningOnKVM()) { - // Backwards compatibility - provide hard coded range. - // 4 pages before the bios, 3 pages for vmx tss pages, the - // other page for EPT real mode pagetable - add_e820(0xfffbc000, 4*4096, E820_RESERVED); - } - // ACPI tables char name[128]; u16 cnt; @@ -367,4 +372,6 @@ void qemu_cfg_init(void) qemu_romfile_add(qfile.name, be16_to_cpu(qfile.select) , 0, be32_to_cpu(qfile.size)); } + + qemu_cfg_e820(); }
The new fw_cfg is simliar to the QEMU_CFG_E820_TABLE entry, but carries both reservations and RAM regions, so we can use it instead of the cmos for RAM detection.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/fw/paravirt.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+)
diff --git a/src/fw/paravirt.c b/src/fw/paravirt.c index 58973a2..b84196a 100644 --- a/src/fw/paravirt.c +++ b/src/fw/paravirt.c @@ -250,6 +250,47 @@ struct qemu_smbios_header { static void qemu_cfg_e820(void) { + struct e820_reservation *table; + int i, size; + + // "etc/e820" has both ram and reservations + table = romfile_loadfile("etc/e820", &size); + if (table) { + for (i = 0; i < size / sizeof(struct e820_reservation); i++) { + switch (table[i].type) { + case E820_RAM: + dprintf(1, "RamBlock: addr 0x%016llx len 0x%016llx [e820]\n", + table[i].address, table[i].length); + if (table[i].address < RamSize) + // ignore, preinit got it from cmos already and + // adding this again would ruin any reservations + // done so far + continue; + if (table[i].address < 0x100000000LL) { + // below 4g -- adjust RamSize to mark highest lowram addr + if (RamSize < table[i].address + table[i].length) + RamSize = table[i].address + table[i].length; + } else { + // above 4g -- adjust RamSizeOver4G to mark highest ram addr + if (0x100000000LL + RamSizeOver4G < table[i].address + table[i].length) + RamSizeOver4G = table[i].address + table[i].length - 0x100000000LL; + } + /* fall through */ + case E820_RESERVED: + add_e820(table[i].address, table[i].length, table[i].type); + break; + default: + /* + * Qemu 1.7 uses RAM + RESERVED only. Ignore + * everything else, so we have the option to + * extend this in the future without breakage. + */ + break; + } + } + return; + } + // QEMU_CFG_E820_TABLE has reservations only u32 count32; qemu_cfg_read_entry(&count32, QEMU_CFG_E820_TABLE, sizeof(count32));
On Wed, Nov 06, 2013 at 09:39:03AM +0100, Gerd Hoffmann wrote:
Hi,
qemu got a new fw_cfg file named "etc/e820" carrying e820 ram regions and reservations. This little patch series makes seabios use it if present. It also moves qemu e820 initialization into its own function.
How does this series work when setting ram under 4gig? Seabios configures it's malloc zones before it reads the e820 table, so doesn't that make this difficult?
-Kevin
On Sa, 2013-11-16 at 00:35 -0500, Kevin O'Connor wrote:
On Wed, Nov 06, 2013 at 09:39:03AM +0100, Gerd Hoffmann wrote:
Hi,
qemu got a new fw_cfg file named "etc/e820" carrying e820 ram regions and reservations. This little patch series makes seabios use it if present. It also moves qemu e820 initialization into its own function.
How does this series work when setting ram under 4gig? Seabios configures it's malloc zones before it reads the e820 table, so doesn't that make this difficult?
cmos is still used/needed for the first memory block. etc/e820 entries overlapping with the lowmem detected via cmos are ignored. Patch #2 actually adds a comment to the code which handles this to make clear how this works.
cheers, Gerd