Skip to content

Commit

Permalink
acpi: Set proper maximum size for "etc/table-loader" blob
Browse files Browse the repository at this point in the history
The resizeable memory region / RAMBlock that is created for the cmd blob
has a maximum size of whole host pages (e.g., 4k), because RAMBlocks
work on full host pages. In addition, in i386 ACPI code:
  acpi_align_size(tables->linker->cmd_blob, ACPI_BUILD_ALIGN_SIZE);
makes sure to align to multiples of 4k, padding with 0.

For example, if our cmd_blob is created with a size of 2k, the maximum
size is 4k - we cannot grow beyond that. Growing might be required
due to guest action when rebuilding the tables, but also on incoming
migration.

This automatic generation of the maximum size used to be sufficient,
however, there are cases where we cross host pages now when growing at
runtime: we exceed the maximum size of the RAMBlock and can crash QEMU when
trying to resize the resizeable memory region / RAMBlock:
  $ build/qemu-system-x86_64 --enable-kvm \
      -machine q35,nvdimm=on \
      -smp 1 \
      -cpu host \
      -m size=2G,slots=8,maxmem=4G \
      -object memory-backend-file,id=mem0,mem-path=/tmp/nvdimm,size=256M \
      -device nvdimm,label-size=131072,memdev=mem0,id=nvdimm0,slot=1 \
      -nodefaults \
      -device vmgenid \
      -device intel-iommu

Results in:
  Unexpected error in qemu_ram_resize() at ../softmmu/physmem.c:1850:
  qemu-system-x86_64: Size too large: /rom@etc/table-loader:
    0x2000 > 0x1000: Invalid argument

In this configuration, we consume exactly 4k (32 entries, 128 bytes each)
when creating the VM. However, once the guest boots up and maps the MCFG,
we also create the MCFG table and end up consuming 2 additional entries
(pointer + checksum) -- which is where we try resizing the memory region
/ RAMBlock, however, the maximum size does not allow for it.

Currently, we get the following maximum sizes for our different
mutable tables based on behavior of resizeable RAMBlock:

  hw       table                max_size
  -------  ---------------------------------------------------------

  virt     "etc/acpi/tables"    ACPI_BUILD_TABLE_MAX_SIZE (0x200000)
  virt     "etc/table-loader"   HOST_PAGE_ALIGN(initial_size)
  virt     "etc/acpi/rsdp"      HOST_PAGE_ALIGN(initial_size)

  i386     "etc/acpi/tables"    ACPI_BUILD_TABLE_MAX_SIZE (0x200000)
  i386     "etc/table-loader"   HOST_PAGE_ALIGN(initial_size)
  i386     "etc/acpi/rsdp"      HOST_PAGE_ALIGN(initial_size)

  microvm  "etc/acpi/tables"    ACPI_BUILD_TABLE_MAX_SIZE (0x200000)
  microvm  "etc/table-loader"   HOST_PAGE_ALIGN(initial_size)
  microvm  "etc/acpi/rsdp"      HOST_PAGE_ALIGN(initial_size)

Let's set the maximum table size for "etc/table-loader" to 64k, so we
can properly grow at runtime, which should be good enough for the future.

Migration is not concerned with the maximum size of a RAMBlock, only
with the used size - so existing setups are not affected. Of course, we
cannot migrate a VM that would have crash when started on older QEMU from
new QEMU to older QEMU without failing early on the destination when
synchronizing the RAM state:
    qemu-system-x86_64: Size too large: /rom@etc/table-loader: 0x2000 > 0x1000: Invalid argument
    qemu-system-x86_64: error while loading state for instance 0x0 of device 'ram'
    qemu-system-x86_64: load of migration failed: Invalid argument

We'll refactor the code next, to make sure we get rid of this implicit
behavior for "etc/acpi/rsdp" as well and to make the code easier to
grasp.

Reviewed-by: Igor Mammedov <[email protected]>
Cc: Alistair Francis <[email protected]>
Cc: Paolo Bonzini <[email protected]>
Cc: "Michael S. Tsirkin" <[email protected]>
Cc: Igor Mammedov <[email protected]>
Cc: Peter Maydell <[email protected]>
Cc: Shannon Zhao <[email protected]>
Cc: Marcel Apfelbaum <[email protected]>
Cc: Paolo Bonzini <[email protected]>
Cc: Richard Henderson <[email protected]>
Cc: Laszlo Ersek <[email protected]>
Signed-off-by: David Hildenbrand <[email protected]>
Message-Id: <[email protected]>
Reviewed-by: Laszlo Ersek <[email protected]>
Reviewed-by: Igor Mammedov <[email protected]>
Reviewed-by: Michael S. Tsirkin <[email protected]>
Signed-off-by: Michael S. Tsirkin <[email protected]>
  • Loading branch information
davidhildenbrand authored and mstsirkin committed Mar 22, 2021
1 parent 835fde4 commit 6c2b24d
Show file tree
Hide file tree
Showing 4 changed files with 6 additions and 3 deletions.
3 changes: 2 additions & 1 deletion hw/arm/virt-acpi-build.c
Original file line number Diff line number Diff line change
Expand Up @@ -865,7 +865,8 @@ void virt_acpi_setup(VirtMachineState *vms)

build_state->linker_mr =
acpi_add_rom_blob(virt_acpi_build_update, build_state,
tables.linker->cmd_blob, ACPI_BUILD_LOADER_FILE, 0);
tables.linker->cmd_blob, ACPI_BUILD_LOADER_FILE,
ACPI_BUILD_LOADER_MAX_SIZE);

fw_cfg_add_file(vms->fw_cfg, ACPI_BUILD_TPMLOG_FILE, tables.tcpalog->data,
acpi_data_len(tables.tcpalog));
Expand Down
3 changes: 2 additions & 1 deletion hw/i386/acpi-build.c
Original file line number Diff line number Diff line change
Expand Up @@ -2634,7 +2634,8 @@ void acpi_setup(void)

build_state->linker_mr =
acpi_add_rom_blob(acpi_build_update, build_state,
tables.linker->cmd_blob, ACPI_BUILD_LOADER_FILE, 0);
tables.linker->cmd_blob, ACPI_BUILD_LOADER_FILE,
ACPI_BUILD_LOADER_MAX_SIZE);

fw_cfg_add_file(x86ms->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
tables.tcpalog->data, acpi_data_len(tables.tcpalog));
Expand Down
2 changes: 1 addition & 1 deletion hw/i386/acpi-microvm.c
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ void acpi_setup_microvm(MicrovmMachineState *mms)
ACPI_BUILD_TABLE_MAX_SIZE);
acpi_add_rom_blob(acpi_build_no_update, NULL,
tables.linker->cmd_blob,
"etc/table-loader", 0);
"etc/table-loader", ACPI_BUILD_LOADER_MAX_SIZE);
acpi_add_rom_blob(acpi_build_no_update, NULL,
tables.rsdp,
ACPI_BUILD_RSDP_FILE, 0);
Expand Down
1 change: 1 addition & 0 deletions include/hw/acpi/aml-build.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

/* Reserve RAM space for tables: add another order of magnitude. */
#define ACPI_BUILD_TABLE_MAX_SIZE 0x200000
#define ACPI_BUILD_LOADER_MAX_SIZE 0x10000

#define ACPI_BUILD_APPNAME6 "BOCHS "
#define ACPI_BUILD_APPNAME8 "BXPC "
Expand Down

0 comments on commit 6c2b24d

Please sign in to comment.