diff options
Diffstat (limited to 'src/fw/paravirt.c')
-rw-r--r-- | src/fw/paravirt.c | 133 |
1 files changed, 82 insertions, 51 deletions
diff --git a/src/fw/paravirt.c b/src/fw/paravirt.c index b21f1aef..3465f97e 100644 --- a/src/fw/paravirt.c +++ b/src/fw/paravirt.c @@ -151,6 +151,8 @@ static void qemu_detect(void) } } +static int qemu_early_e820(void); + void qemu_preinit(void) { @@ -165,22 +167,24 @@ qemu_preinit(void) return; } - // On emulators, get memory size from nvram. - u32 rs = ((rtc_read(CMOS_MEM_EXTMEM2_LOW) << 16) - | (rtc_read(CMOS_MEM_EXTMEM2_HIGH) << 24)); - if (rs) - rs += 16 * 1024 * 1024; - else - rs = (((rtc_read(CMOS_MEM_EXTMEM_LOW) << 10) - | (rtc_read(CMOS_MEM_EXTMEM_HIGH) << 18)) - + 1 * 1024 * 1024); - RamSize = rs; - e820_add(0, rs, E820_RAM); + // try read e820 table first + if (!qemu_early_e820()) { + // when it fails get memory size from nvram. + u32 rs = ((rtc_read(CMOS_MEM_EXTMEM2_LOW) << 16) + | (rtc_read(CMOS_MEM_EXTMEM2_HIGH) << 24)); + if (rs) + rs += 16 * 1024 * 1024; + else + rs = (((rtc_read(CMOS_MEM_EXTMEM_LOW) << 10) + | (rtc_read(CMOS_MEM_EXTMEM_HIGH) << 18)) + + 1 * 1024 * 1024); + RamSize = rs; + e820_add(0, rs, E820_RAM); + dprintf(1, "RamSize: 0x%08x [cmos]\n", RamSize); + } /* reserve 256KB BIOS area at the end of 4 GB */ e820_add(0xfffc0000, 256*1024, E820_RESERVED); - - dprintf(1, "RamSize: 0x%08x [cmos]\n", RamSize); } #define MSR_IA32_FEATURE_CONTROL 0x0000003a @@ -476,47 +480,11 @@ struct qemu_smbios_header { static void qemu_cfg_e820(void) { - struct e820_reservation *table; - int i, size; - if (!CONFIG_QEMU) return; - // "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: - e820_add(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; - } - } + if (romfile_find("etc/e820")) { + // qemu_early_e820() has handled everything return; } @@ -678,3 +646,66 @@ void qemu_cfg_init(void) && !romfile_find("vgaroms/sgabios.bin")) const_romfile_add_int("etc/sercon-port", PORT_SERIAL1); } + +/* + * This runs before malloc and romfile are ready, so we have to work + * with stack allocations and read from fw_cfg in chunks. + */ +static int qemu_early_e820(void) +{ + struct e820_reservation table; + struct QemuCfgFile qfile; + u32 select = 0, size = 0; + u32 count, i; + + if (!qemu_cfg_detect()) + return 0; + + // find e820 table + qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count)); + count = be32_to_cpu(count); + for (i = 0; i < count; i++) { + qemu_cfg_read(&qfile, sizeof(qfile)); + if (memcmp(qfile.name, "etc/e820", 9) != 0) + continue; + select = be16_to_cpu(qfile.select); + size = be32_to_cpu(qfile.size); + break; + } + if (select == 0) { + // may happen on old qemu + dprintf(1, "qemu/e820: fw_cfg file etc/e820 not found\n"); + return 0; + } + + // walk e820 table + qemu_cfg_select(select); + count = size/sizeof(table); + for (i = 0, select = 0; i < count; i++) { + qemu_cfg_read(&table, sizeof(table)); + switch (table.type) { + case E820_RESERVED: + e820_add(table.address, table.length, table.type); + dprintf(3, "qemu/e820: addr 0x%016llx len 0x%016llx [reserved]\n", + table.address, table.length); + break; + case E820_RAM: + e820_add(table.address, table.length, table.type); + dprintf(1, "qemu/e820: addr 0x%016llx len 0x%016llx [RAM]\n", + table.address, table.length); + if (table.address < 0x100000000LL) { + // below 4g + if (RamSize < table.address + table.length) + RamSize = table.address + table.length; + } else { + // above 4g + if (RamSizeOver4G < table.address + table.length - 0x100000000LL) + RamSizeOver4G = table.address + table.length - 0x100000000LL; + } + } + } + + dprintf(3, "qemu/e820: RamSize: 0x%08x\n", RamSize); + dprintf(3, "qemu/e820: RamSizeOver4G: 0x%016llx\n", RamSizeOver4G); + return 1; +} |