All of lore.kernel.org
 help / color / mirror / Atom feed
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

  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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.