On Wed, Sep 02, 2026 at 02:10:56PM +0800, Ray Lee wrote: > With -kernel/-initrd, x86_load_linux() places the initrd at the top > of low RAM but does not reserve that range in e820. SeaBIOS > allocates virtio vrings top-down from the same area, so with enough > devices the vrings overlap the initrd and firmware DMA corrupts it. > > Reserve the initrd range in the e820 table; SeaBIOS and OVMF both > honor "etc/e820" reservations when setting up their memory > allocators. > > Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4396 > Signed-off-by: Ray Lee <[email protected]>
Hmm. Yes this would fix it, but it would steal this memory from the guest permanently, won't it? Could you check free -m, or cat /proc/meminfo, with and without the patch? > --- > hw/i386/x86-common.c | 15 +++++++++++++++ > 1 file changed, 15 insertions(+) > > diff --git a/hw/i386/x86-common.c b/hw/i386/x86-common.c > index 8f9419e7d3..4e85fde987 100644 > --- a/hw/i386/x86-common.c > +++ b/hw/i386/x86-common.c > @@ -38,6 +38,7 @@ > > #include "hw/core/irq.h" > #include "hw/core/loader.h" > +#include "e820_memory_layout.h" > #include "multiboot.h" > #include "elf.h" > #include "standard-headers/asm-x86/bootparam.h" > @@ -744,6 +745,13 @@ void x86_load_linux(X86MachineState *x86ms, > > initrd_addr = (initrd_max - initrd_size) & ~4095; > > + /* > + * Keep firmware (e.g. SeaBIOS) from allocating over the > + * initrd at the top of RAM. > + */ > + e820_add_entry(initrd_addr, QEMU_ALIGN_UP(initrd_size, 4096), > + E820_RESERVED); > + > fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr); > fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size); > fw_cfg_add_bytes(fw_cfg, FW_CFG_INITRD_DATA, initrd_data, > @@ -889,6 +897,13 @@ void x86_load_linux(X86MachineState *x86ms, > > initrd_addr = (initrd_max - initrd_size) & ~4095; > > + /* > + * Keep firmware (e.g. SeaBIOS) from allocating over the initrd > + * at the top of RAM. > + */ > + e820_add_entry(initrd_addr, QEMU_ALIGN_UP(initrd_size, 4096), > + E820_RESERVED); > + > fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr); > fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size); > fw_cfg_add_bytes(fw_cfg, FW_CFG_INITRD_DATA, initrd_data, > initrd_size); > -- > 2.53.0
