aboutsummaryrefslogtreecommitdiff
path: root/src/fw
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2020-05-08 12:22:53 +0200
committerGerd Hoffmann <kraxel@redhat.com>2020-05-15 13:29:28 +0200
commitfffac0fa089cf51437a692b546d0bdc0a92da7f9 (patch)
tree8ba8aa4147a06179b48f1119ab3e5de0d7cfb3c5 /src/fw
parent1206efcd89e3945cfe29a4b922cb91d3096d984c (diff)
downloadseabios-hppa-fffac0fa089cf51437a692b546d0bdc0a92da7f9.zip
seabios-hppa-fffac0fa089cf51437a692b546d0bdc0a92da7f9.tar.gz
seabios-hppa-fffac0fa089cf51437a692b546d0bdc0a92da7f9.tar.bz2
qemu: rework e820 detection
Read e820 table from fw_cfg early. This avoids reading the cmos for ram detection on modern qemu. It also simplifies the ram detection logic. We stop doing ram detecion in two steps, so we don't have to worry about the second step overwriting the setup done by the first step. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Diffstat (limited to 'src/fw')
-rw-r--r--src/fw/paravirt.c133
1 files changed, 82 insertions, 51 deletions
diff --git a/src/fw/paravirt.c b/src/fw/paravirt.c
index b21f1ae..3465f97 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;
+}