From: Chao Peng <chao.p.peng@linux.intel.com>
To: qemu-devel@nongnu.org
Cc: "Michael S. Tsirkin" <mst@redhat.com>,
gor Mammedov <imammedo@redhat.com>,
Xiao Guangrong <guangrong.xiao@linux.intel.com>,
Paolo Bonzini <pbonzini@redhat.com>,
Richard Henderson <rth@twiddle.net>,
Eduardo Habkost <ehabkost@redhat.com>,
Haozhong Zhang <haozhong.zhang@intel.com>
Subject: [Qemu-devel] [RFC PATCH v2 08/12] acpi: patch guest ACPI when there is no firmware
Date: Thu, 25 Aug 2016 06:15:01 -0400 [thread overview]
Message-ID: <1472120105-29235-9-git-send-email-chao.p.peng@linux.intel.com> (raw)
In-Reply-To: <1472120105-29235-1-git-send-email-chao.p.peng@linux.intel.com>
From: Haozhong Zhang <haozhong.zhang@intel.com>
Traditionally, guest firmware is responsible to patch ACPI tables
generated by QEMU. However, no firmware is used with pc-lite and
patching ACPI should be done in QEMU for pc-lite.
Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
---
hw/acpi/nvdimm.c | 6 +-
hw/i386/Makefile.objs | 2 +-
hw/i386/acpi-build-nofw.c | 295 ++++++++++++++++++++++++++++++++++++++++++++++
hw/i386/acpi-build.c | 71 +++++------
hw/i386/acpi-build.h | 5 +
5 files changed, 341 insertions(+), 38 deletions(-)
create mode 100644 hw/i386/acpi-build-nofw.c
diff --git a/hw/acpi/nvdimm.c b/hw/acpi/nvdimm.c
index e486128..a05463e 100644
--- a/hw/acpi/nvdimm.c
+++ b/hw/acpi/nvdimm.c
@@ -770,8 +770,10 @@ void nvdimm_init_acpi_state(AcpiNVDIMMState *state, MemoryRegion *io,
state->dsm_mem = g_array_new(false, true /* clear */, 1);
acpi_data_push(state->dsm_mem, sizeof(NvdimmDsmIn));
- fw_cfg_add_file(fw_cfg, NVDIMM_DSM_MEM_FILE, state->dsm_mem->data,
- state->dsm_mem->len);
+ if (fw_cfg) {
+ fw_cfg_add_file(fw_cfg, NVDIMM_DSM_MEM_FILE, state->dsm_mem->data,
+ state->dsm_mem->len);
+ }
}
#define NVDIMM_COMMON_DSM "NCAL"
diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs
index 90e94ff..9d81af7 100644
--- a/hw/i386/Makefile.objs
+++ b/hw/i386/Makefile.objs
@@ -6,5 +6,5 @@ obj-y += x86-iommu.o intel_iommu.o
obj-$(CONFIG_XEN) += ../xenpv/ xen/
obj-y += kvmvapic.o
-obj-y += acpi-build.o
+obj-y += acpi-build.o acpi-build-nofw.o
obj-y += pci-assign-load-rom.o
diff --git a/hw/i386/acpi-build-nofw.c b/hw/i386/acpi-build-nofw.c
new file mode 100644
index 0000000..8f4fbe3
--- /dev/null
+++ b/hw/i386/acpi-build-nofw.c
@@ -0,0 +1,295 @@
+#include "qemu/osdep.h"
+#include <glib.h>
+#include "qemu-common.h"
+#include "qemu/mmap-alloc.h"
+#include "acpi-build.h"
+#include "hw/i386/pc.h"
+#include "hw/acpi/acpi.h"
+#include "hw/acpi/aml-build.h"
+#include "hw/acpi/bios-linker-loader.h"
+#include "exec/memory.h"
+#include "qapi/error.h"
+
+/* #define DEBUG_ACPI */
+#ifdef DEBUG_ACPI
+#define acpi_dprintf(fmt, ...) \
+ do { \
+ printf("ACPI: "fmt, ##__VA_ARGS__); \
+ } while (0)
+#else
+#define acpi_dprintf(fmt, ...)
+#endif
+
+
+typedef
+struct AcpiZone {
+ MemoryRegion *mr;
+ hwaddr start;
+ hwaddr offset;
+} AcpiZone;
+static AcpiZone acpi_himem_zone;
+static AcpiZone acpi_fseg_zone;
+
+#define ACPI_HIMEM_SIZE (256 * 1024)
+#define ACPI_FSEG_SIZE (0x100000 - 0xe0000)
+
+static AcpiZone *acpi_get_zone(uint8_t zone)
+{
+ if (zone == BIOS_LINKER_LOADER_ALLOC_ZONE_HIGH) {
+ return &acpi_himem_zone;
+ } else if (zone == BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG) {
+ return &acpi_fseg_zone;
+ } else {
+ return NULL;
+ }
+}
+
+static int acpi_zone_init(AcpiZone *zone, const char *name,
+ hwaddr start, uint64_t size)
+{
+ void *buf;
+ MemoryRegion *mr;
+
+ buf = qemu_ram_mmap(-1, size, 0x1000, true);
+ if (buf == MAP_FAILED) {
+ return -1;
+ }
+
+ mr = g_malloc(sizeof(*mr));
+ memory_region_init_ram_ptr(mr, NULL, name, size, buf);
+ memory_region_add_subregion_overlap(get_system_memory(), start, mr, 0);
+ e820_add_entry(start, size, E820_RESERVED);
+
+ zone->mr = mr;
+ zone->start = start;
+ zone->offset = 0;
+
+ return 0;
+}
+
+static void acpi_zones_init(PCMachineState *pcms)
+{
+ uint64_t start;
+
+ assert(pcms->below_4g_mem_size >= ACPI_HIMEM_SIZE);
+ start = pcms->below_4g_mem_size - ACPI_HIMEM_SIZE;
+ acpi_zone_init(&acpi_himem_zone, "acpi_himem",
+ start, ACPI_HIMEM_SIZE);
+ acpi_zone_init(&acpi_fseg_zone, "acpi_fseg",
+ 0xe0000, ACPI_FSEG_SIZE);
+}
+
+/* return the offset within the corresponding zone, or ~0 for failure */
+static hwaddr acpi_zone_alloc(AcpiZone *zone,
+ uint64_t size, uint64_t align,
+ Error **errp)
+{
+ hwaddr start = zone->start;
+ hwaddr offset = zone->offset;
+ uint64_t max_size = memory_region_size(zone->mr);
+ uint64_t addr;
+ Error *local_err = NULL;
+
+ addr = ROUND_UP(start + offset, align);
+ offset = addr - start;
+ if (size > max_size || max_size - size < offset) {
+ error_setg(&local_err, "Not enough space");
+ goto out;
+ }
+ zone->offset = offset + size;
+
+ out:
+ error_propagate(errp, local_err);
+ return offset;
+}
+
+
+typedef
+struct PCLiteAcpiFileEntry {
+ char *name;
+ MemoryRegion *mr;
+ hwaddr offset;
+} PCLiteAcpiFileEntry;
+
+typedef
+struct PCLiteAcpiFiles {
+ GArray *file_list;
+} PCLiteAcpiFiles;
+
+static PCLiteAcpiFiles *acpi_files;
+
+static void acpi_files_init(void)
+{
+ acpi_files = g_new(PCLiteAcpiFiles, 1);
+ acpi_files->file_list = g_array_new(false, true /* clear */,
+ sizeof(PCLiteAcpiFileEntry));
+}
+
+static PCLiteAcpiFileEntry *acpi_file_search(const char *name)
+{
+ int i;
+ GArray *file_list = acpi_files->file_list;
+ PCLiteAcpiFileEntry *file;
+
+ for (i = 0; i < file_list->len; i++) {
+ file = &g_array_index(file_list, PCLiteAcpiFileEntry, i);
+ if (!strcmp(file->name, name)) {
+ return file;
+ }
+ }
+ return NULL;
+}
+
+static void acpi_file_add(const char *name,
+ MemoryRegion *mr, hwaddr offset)
+{
+ PCLiteAcpiFileEntry file = { g_strdup(name), mr, offset };
+ assert(!acpi_file_search(name));
+ g_array_append_val(acpi_files->file_list, file);
+}
+
+static void *acpi_file_get_ptr(PCLiteAcpiFileEntry *file)
+{
+ void *ptr = memory_region_get_ram_ptr(file->mr);
+ return ptr + file->offset;
+}
+
+static hwaddr acpi_file_get_addr(PCLiteAcpiFileEntry *file)
+{
+ return file->mr->addr + file->offset;
+}
+
+static void acpi_patch_allocate(const BiosLinkerLoaderEntry *cmd,
+ const BiosLinkerFileEntry *file,
+ Error **errp)
+{
+ AcpiZone *zone = acpi_get_zone(cmd->alloc.zone);
+ MemoryRegion *zone_mr = zone->mr;
+ GArray *data = file->blob;
+ unsigned size = acpi_data_len(data);
+ hwaddr offset;
+ void *dest;
+ Error *local_err = NULL;
+
+ assert(!strncmp(cmd->alloc.file, file->name, BIOS_LINKER_LOADER_FILESZ));
+
+ if (!zone) {
+ error_setg(&local_err, "Unknown zone type %d of file %s",
+ cmd->alloc.zone, cmd->alloc.file);
+ goto out;
+ }
+
+ offset = acpi_zone_alloc(zone, size, cmd->alloc.align, &local_err);
+ if (local_err) {
+ goto out;
+ }
+
+ dest = memory_region_get_ram_ptr(zone_mr);
+ memcpy(dest + offset, data->data, size);
+ memory_region_set_dirty(zone_mr, offset, size);
+
+ acpi_file_add(cmd->alloc.file, zone_mr, offset);
+
+ out:
+ error_propagate(errp, local_err);
+}
+
+static void acpi_patch_add_pointer(const BiosLinkerLoaderEntry *cmd,
+ Error **errp)
+{
+ PCLiteAcpiFileEntry *dest_file, *src_file;
+ void *dest;
+ uint64_t pointer = 0;
+ uint32_t offset = cmd->pointer.offset;
+ uint32_t size = cmd->pointer.size;
+ Error *local_err = NULL;
+
+ dest_file = acpi_file_search(cmd->pointer.dest_file);
+ if (!dest_file) {
+ error_setg(&local_err, "Not found dest_file %s",
+ cmd->pointer.dest_file);
+ goto out;
+ }
+ src_file = acpi_file_search(cmd->pointer.src_file);
+ if (!src_file) {
+ error_setg(&local_err, "Not found src_file %s",
+ cmd->pointer.src_file);
+ goto out;
+ }
+
+ dest = acpi_file_get_ptr(dest_file);
+ memcpy(&pointer, dest + offset, size);
+ pointer += acpi_file_get_addr(src_file);
+ memcpy(dest + offset, &pointer, size);
+ memory_region_set_dirty(dest_file->mr, dest_file->offset + offset, size);
+
+ out:
+ error_propagate(errp, local_err);
+}
+
+static void acpi_patch_add_checksum(const BiosLinkerLoaderEntry *cmd,
+ Error **errp)
+{
+ PCLiteAcpiFileEntry *file = acpi_file_search(cmd->cksum.file);
+ uint32_t offset = cmd->cksum.offset;
+ uint8_t *dest, *cksum;
+ Error *local_err = NULL;
+
+ if (!file) {
+ error_setg(&local_err, "Not found file %s", cmd->cksum.file);
+ goto out;
+ }
+
+ dest = acpi_file_get_ptr(file);
+ cksum = dest + offset;
+ *cksum = acpi_checksum(dest + cmd->cksum.start, cmd->cksum.length);
+ memory_region_set_dirty(file->mr, file->offset + offset, sizeof(*cksum));
+
+ out:
+ error_propagate(errp, local_err);
+}
+
+static void acpi_patch(BIOSLinker *linker, Error **errp)
+{
+ void *cmd_blob_data = linker->cmd_blob->data;
+ unsigned cmd_blob_len = linker->cmd_blob->len;
+ uint64_t offset;
+ const BiosLinkerLoaderEntry *cmd;
+ const BiosLinkerFileEntry *file;
+ Error *local_err = NULL;
+
+ for (offset = 0; offset < cmd_blob_len; offset += sizeof(*cmd)) {
+ cmd = cmd_blob_data + offset;
+
+ switch (cmd->command) {
+ case BIOS_LINKER_LOADER_COMMAND_ALLOCATE:
+ file = bios_linker_find_file(linker, cmd->alloc.file);
+ acpi_patch_allocate(cmd, file, &local_err);
+ break;
+ case BIOS_LINKER_LOADER_COMMAND_ADD_POINTER:
+ acpi_patch_add_pointer(cmd, &local_err);
+ break;
+ case BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM:
+ acpi_patch_add_checksum(cmd, &local_err);
+ break;
+ default:
+ acpi_dprintf("Ignore unknown command 0x%x\n", cmd->command);
+ continue;
+ }
+
+ if (local_err) {
+ goto out;
+ }
+ }
+
+ out:
+ error_propagate(errp, local_err);
+}
+
+
+void acpi_build_nofw(PCMachineState *pcms, BIOSLinker *linker, Error **errp)
+{
+ acpi_zones_init(pcms);
+ acpi_files_init();
+ acpi_patch(linker, errp);
+}
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 60c0896..4daa6ae 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -2228,8 +2228,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
aml_append(scope, aml_name_decl("_S5", pkg));
aml_append(dsdt, scope);
- /* create fw_cfg node, unconditionally */
- {
+ if (pcms->fw_cfg) {
/* when using port i/o, the 8-bit data register *always* overlaps
* with half of the 16-bit control register. Hence, the total size
* of the i/o region used is FW_CFG_CTL_SIZE; when using DMA, the
@@ -2879,11 +2878,6 @@ void acpi_setup(void)
AcpiBuildTables tables;
AcpiBuildState *build_state;
- if (!pcms->fw_cfg) {
- ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n");
- return;
- }
-
if (!pcmc->has_acpi_build) {
ACPI_BUILD_DPRINTF("ACPI build disabled. Bailing out.\n");
return;
@@ -2902,41 +2896,48 @@ void acpi_setup(void)
acpi_build(&tables, MACHINE(pcms));
/* Now expose it all to Guest */
- build_state->table_mr = acpi_add_rom_blob(build_state, tables.table_data,
- ACPI_BUILD_TABLE_FILE,
- ACPI_BUILD_TABLE_MAX_SIZE);
- assert(build_state->table_mr != NULL);
-
- build_state->linker_mr =
- acpi_add_rom_blob(build_state, tables.linker->cmd_blob,
- "etc/table-loader", 0);
-
- fw_cfg_add_file(pcms->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
- tables.tcpalog->data, acpi_data_len(tables.tcpalog));
-
- if (!pcmc->rsdp_in_ram) {
- /*
- * Keep for compatibility with old machine types.
- * Though RSDP is small, its contents isn't immutable, so
- * we'll update it along with the rest of tables on guest access.
- */
- uint32_t rsdp_size = acpi_data_len(tables.rsdp);
+ if (pcms->fw_cfg) {
+ build_state->table_mr = acpi_add_rom_blob(build_state, tables.table_data,
+ ACPI_BUILD_TABLE_FILE,
+ ACPI_BUILD_TABLE_MAX_SIZE);
+ assert(build_state->table_mr != NULL);
- build_state->rsdp = g_memdup(tables.rsdp->data, rsdp_size);
- fw_cfg_add_file_callback(pcms->fw_cfg, ACPI_BUILD_RSDP_FILE,
- acpi_build_update, build_state,
- build_state->rsdp, rsdp_size);
- build_state->rsdp_mr = NULL;
- } else {
- build_state->rsdp = NULL;
- build_state->rsdp_mr = acpi_add_rom_blob(build_state, tables.rsdp,
- ACPI_BUILD_RSDP_FILE, 0);
+ build_state->linker_mr =
+ acpi_add_rom_blob(build_state, tables.linker->cmd_blob,
+ "etc/table-loader", 0);
+
+ fw_cfg_add_file(pcms->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
+ tables.tcpalog->data, acpi_data_len(tables.tcpalog));
+
+ if (!pcmc->rsdp_in_ram) {
+ /*
+ * Keep for compatibility with old machine types.
+ * Though RSDP is small, its contents isn't immutable, so
+ * we'll update it along with the rest of tables on guest access.
+ */
+ uint32_t rsdp_size = acpi_data_len(tables.rsdp);
+
+ build_state->rsdp = g_memdup(tables.rsdp->data, rsdp_size);
+ fw_cfg_add_file_callback(pcms->fw_cfg, ACPI_BUILD_RSDP_FILE,
+ acpi_build_update, build_state,
+ build_state->rsdp, rsdp_size);
+ build_state->rsdp_mr = NULL;
+ } else {
+ build_state->rsdp = NULL;
+ build_state->rsdp_mr = acpi_add_rom_blob(build_state, tables.rsdp,
+ ACPI_BUILD_RSDP_FILE, 0);
+ }
}
qemu_register_reset(acpi_build_reset, build_state);
acpi_build_reset(build_state);
vmstate_register(NULL, 0, &vmstate_acpi_build, build_state);
+ if (!pcms->fw_cfg) {
+ acpi_build_nofw(pcms, tables.linker, &error_abort);
+ build_state->patched = 1;
+ }
+
/* Cleanup tables but don't free the memory: we track it
* in build_state.
*/
diff --git a/hw/i386/acpi-build.h b/hw/i386/acpi-build.h
index 007332e..4e5f2e5 100644
--- a/hw/i386/acpi-build.h
+++ b/hw/i386/acpi-build.h
@@ -2,6 +2,11 @@
#ifndef HW_I386_ACPI_BUILD_H
#define HW_I386_ACPI_BUILD_H
+#include "hw/i386/pc.h"
+#include "hw/acpi/bios-linker-loader.h"
+#include "qapi/error.h"
+
void acpi_setup(void);
+void acpi_build_nofw(PCMachineState *pcms, BIOSLinker *linker, Error **errp);
#endif
--
1.8.3.1
next prev parent reply other threads:[~2016-08-25 10:23 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-08-25 10:14 [Qemu-devel] [RFC PATCH v2 00/12] Guest startup time optimization Chao Peng
2016-08-25 10:14 ` [Qemu-devel] [RFC PATCH v2 01/12] pc: make smbus configurable Chao Peng
2016-09-06 20:18 ` Eduardo Habkost
2016-08-25 10:14 ` [Qemu-devel] [RFC PATCH v2 02/12] pc: make sata configurable Chao Peng
2016-08-25 10:14 ` [Qemu-devel] [RFC PATCH v2 03/12] pc: make pic configurable Chao Peng
2016-08-25 10:14 ` [Qemu-devel] [RFC PATCH v2 04/12] pc: make pit configurable Chao Peng
2016-08-25 10:14 ` [Qemu-devel] [RFC PATCH v2 05/12] acpi: build static _PRT Chao Peng
2016-08-29 17:06 ` Paolo Bonzini
2016-08-25 10:14 ` [Qemu-devel] [RFC PATCH v2 06/12] acpi: expose data structurs and functions of BIOS linker loader Chao Peng
2016-08-25 10:15 ` [Qemu-devel] [RFC PATCH v2 07/12] acpi: expose acpi_checksum() Chao Peng
2016-08-25 10:15 ` Chao Peng [this message]
2016-08-25 10:15 ` [Qemu-devel] [RFC PATCH v2 09/12] ich9: enable pm registers when there is no firmware Chao Peng
2016-08-25 10:15 ` [Qemu-devel] [RFC PATCH v2 10/12] q35: initialize MMCFG base " Chao Peng
2016-08-25 10:15 ` [Qemu-devel] [RFC PATCH v2 11/12] pc: support direct loading protected/long mode kernel Chao Peng
2016-08-25 10:15 ` [Qemu-devel] [RFC PATCH v2 12/12] pc: skip firmware Chao Peng
2016-08-29 17:08 ` Paolo Bonzini
2016-09-02 11:08 ` [Qemu-devel] [RFC PATCH v2 00/12] Guest startup time optimization Paolo Bonzini
2016-09-05 2:37 ` Michael S. Tsirkin
2016-09-06 10:48 ` Chao Peng
2016-09-06 11:53 ` Michael S. Tsirkin
2016-09-06 14:28 ` Chao Peng
2016-09-12 15:15 ` Gerd Hoffmann
2016-09-12 17:57 ` [Qemu-devel] [SeaBIOS] " Peter Stuge
2016-09-06 14:21 ` [Qemu-devel] " Paolo Bonzini
2016-09-06 14:31 ` Chao Peng
2016-09-06 14:45 ` Michael S. Tsirkin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1472120105-29235-9-git-send-email-chao.p.peng@linux.intel.com \
--to=chao.p.peng@linux.intel.com \
--cc=ehabkost@redhat.com \
--cc=guangrong.xiao@linux.intel.com \
--cc=haozhong.zhang@intel.com \
--cc=imammedo@redhat.com \
--cc=mst@redhat.com \
--cc=pbonzini@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=rth@twiddle.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).