Hotplugged memory is not persistent in the e820 memory maps. After hotplugging a memslot and rebooting the VM, the hotplugged device is not present.
A possible solution is to add an e820 for the new memslot in the acpi_piix4 hot-add handler. On a reset, Seabios (see next patch in series) will enable all memory devices for which it finds an e820 entry that covers the devices's address range.
On hot-remove, the acpi_piix4 handler will try to remove the e820 entry corresponding to the device. This will work when no VM reboots happen between hot-add and hot-remove, but it is not a sufficient solution in general: Seabios and GuestOS merge adjacent e820 entries on machine reboot, so the sequence hot-add/ rebootVM / hot-remove will fail to remove a corresponding e820 entry at the hot-remove phase.
Signed-off-by: Vasilis Liaskovitis vasilis.liaskovitis@profitbricks.com --- hw/acpi_piix4.c | 6 ++++++ hw/pc.c | 28 ++++++++++++++++++++++++++++ hw/pc.h | 1 + 3 files changed, 35 insertions(+), 0 deletions(-)
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index 2921d18..2b5fd04 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -619,6 +619,9 @@ static void piix4_memslot_eject(uint32_t addr, uint32_t val) s = memslot_find_from_idx(start + idx); assert(s != NULL); memslot_depopulate(s); + if (e820_del_entry(s->start, s->size, E820_RAM) == -EBUSY) + PIIX4_DPRINTF("failed to remove e820 entry for memslot %u\n", + s->idx); } val = val >> 1; idx++; @@ -634,6 +637,9 @@ static int piix4_memslot_hotplug(DeviceState *qdev, SysBusDevice *dev, int
if (add) { enable_mem_device(s, slot->idx); + if (e820_add_entry(slot->start, slot->size, E820_RAM) == -EBUSY) + PIIX4_DPRINTF("failed to add e820 entry for memslot %u\n", + slot->idx); } else { disable_mem_device(s, slot->idx); diff --git a/hw/pc.c b/hw/pc.c index f1f550a..04d243f 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -593,6 +593,34 @@ int e820_add_entry(uint64_t address, uint64_t length, uint32_t type) return index; }
+int e820_del_entry(uint64_t address, uint64_t length, uint32_t type) +{ + int index = le32_to_cpu(e820_table.count); + int search; + struct e820_entry *entry; + + if (index == 0) + return -EBUSY; + search = index - 1; + entry = &e820_table.entry[search]; + while (search >= 0) { + if ((entry->address == cpu_to_le64(address)) && + (entry->length == cpu_to_le64(length)) && + (entry->type == cpu_to_le32(type))){ + if (search != index - 1) { + memcpy(&e820_table.entry[search], &e820_table.entry[search + 1], + sizeof(struct e820_entry) * (index - search)); + } + index--; + e820_table.count = cpu_to_le32(index); + return 1; + } + search--; + entry = &e820_table.entry[search]; + } + return -EBUSY; +} + static void bochs_bios_setup_hp_memslots(uint64_t *fw_cfg_slots);
static void *bochs_bios_init(void) diff --git a/hw/pc.h b/hw/pc.h index 74d3369..4925e8c 100644 --- a/hw/pc.h +++ b/hw/pc.h @@ -226,5 +226,6 @@ void pc_system_firmware_init(MemoryRegion *rom_memory); #define E820_UNUSABLE 5
int e820_add_entry(uint64_t, uint64_t, uint32_t); +int e820_del_entry(uint64_t, uint64_t, uint32_t);
#endif