From: Gleb Natapov <gleb@redhat.com>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH] Allow additions of ACPI tables from command line
Date: Mon, 9 Feb 2009 13:39:47 +0200 [thread overview]
Message-ID: <20090209113947.GA28969@redhat.com> (raw)
This is needed to dynamically add SLIC tables with Windows
activation keys.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
diff --git a/hw/acpi.c b/hw/acpi.c
index 4338d02..2c1d680 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -16,6 +16,7 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
*/
+#include <sys/mman.h>
#include "hw.h"
#include "pc.h"
#include "pci.h"
@@ -561,3 +562,166 @@ void qemu_system_powerdown(void)
}
}
#endif
+
+struct acpi_table_header
+{
+ char signature [4]; /* ACPI signature (4 ASCII characters) */
+ uint32_t length; /* Length of table, in bytes, including header */
+ uint8_t revision; /* ACPI Specification minor version # */
+ uint8_t checksum; /* To make sum of entire table == 0 */
+ char oem_id [6]; /* OEM identification */
+ char oem_table_id [8]; /* OEM table identification */
+ uint32_t oem_revision; /* OEM revision number */
+ char asl_compiler_id [4]; /* ASL compiler vendor ID */
+ uint32_t asl_compiler_revision; /* ASL compiler revision number */
+};
+
+char *acpi_tables;
+size_t acpi_tables_len;
+
+static int acpi_checksum(const uint8_t *data, int len)
+{
+ int sum, i;
+ sum = 0;
+ for(i = 0; i < len; i++)
+ sum += data[i];
+ return (-sum) & 0xff;
+}
+
+int acpi_table_add(const char *t)
+{
+ static const char *dfl_id = "QEMUQEMU";
+ char buf[1024], *p, *f;
+ struct acpi_table_header acpi_hdr;
+ unsigned long val;
+ size_t off;
+
+ memset(&acpi_hdr, 0, sizeof(acpi_hdr));
+
+ if (get_param_value(buf, sizeof(buf), "sig", t)) {
+ strncpy(acpi_hdr.signature, buf, 4);
+ } else {
+ strncpy(acpi_hdr.signature, dfl_id, 4);
+ }
+ if (get_param_value(buf, sizeof(buf), "rev", t)) {
+ val = strtoul(buf, &p, 10);
+ if (val > 255 || *p != '\0')
+ goto out;
+ } else {
+ val = 1;
+ }
+ acpi_hdr.revision = (int8_t)val;
+
+ if (get_param_value(buf, sizeof(buf), "oem_id", t)) {
+ strncpy(acpi_hdr.oem_id, buf, 6);
+ } else {
+ strncpy(acpi_hdr.oem_id, dfl_id, 6);
+ }
+
+ if (get_param_value(buf, sizeof(buf), "oem_table_id", t)) {
+ strncpy(acpi_hdr.oem_table_id, buf, 8);
+ } else {
+ strncpy(acpi_hdr.oem_table_id, dfl_id, 8);
+ }
+
+ if (get_param_value(buf, sizeof(buf), "oem_rev", t)) {
+ val = strtol(buf, &p, 10);
+ if(*p != '\0')
+ goto out;
+ } else {
+ val = 1;
+ }
+ acpi_hdr.oem_revision = val;
+
+ if (get_param_value(buf, sizeof(buf), "asl_compiler_id", t)) {
+ strncpy(acpi_hdr.asl_compiler_id, buf, 4);
+ } else {
+ strncpy(acpi_hdr.asl_compiler_id, dfl_id, 4);
+ }
+
+ if (get_param_value(buf, sizeof(buf), "asl_compiler_rev", t)) {
+ val = strtol(buf, &p, 10);
+ if(*p != '\0')
+ goto out;
+ } else {
+ val = 1;
+ }
+ acpi_hdr.asl_compiler_revision = val;
+
+ if (!get_param_value(buf, sizeof(buf), "data", t)) {
+ buf[0] = '\0';
+ }
+
+ acpi_hdr.length = sizeof(acpi_hdr);
+
+ f = buf;
+ while (buf[0]) {
+ struct stat s;
+ char *n = index(f, ':');
+ if (n)
+ *n = '\0';
+ if(stat(f, &s) < 0) {
+ fprintf(stderr, "Can't stat file '%s': %s\n", f, strerror(errno));
+ goto out;
+ }
+ acpi_hdr.length += s.st_size;
+ if (!n)
+ break;
+ *n = ':';
+ f = n + 1;
+ }
+
+ if (!acpi_tables) {
+ acpi_tables_len = sizeof(uint16_t);
+ acpi_tables = qemu_mallocz(acpi_tables_len);
+ }
+ p = acpi_tables + acpi_tables_len;
+ acpi_tables_len += sizeof(uint16_t) + acpi_hdr.length;
+ acpi_tables = qemu_realloc(acpi_tables, acpi_tables_len);
+
+ *(uint16_t*)p = acpi_hdr.length;
+ p += sizeof(uint16_t);
+ memcpy(p, &acpi_hdr, sizeof(acpi_hdr));
+ off = sizeof(acpi_hdr);
+
+ f = buf;
+ while (buf[0]) {
+ void *addr;
+ struct stat s;
+ int fd;
+ char *n = index(f, ':');
+ if (n)
+ *n = '\0';
+ fd = open(f, O_RDONLY);
+
+ if(fd < 0)
+ goto out;
+ if(fstat(fd, &s) < 0) {
+ close(fd);
+ goto out;
+ }
+ addr = mmap(NULL, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if(addr == MAP_FAILED) {
+ close(fd);
+ goto out;
+ }
+ memcpy(p + off, addr, s.st_size);
+ off += s.st_size;
+ munmap(addr, s.st_size);
+ close(fd);
+ if (!n)
+ break;
+ f = n + 1;
+ }
+
+ ((struct acpi_table_header*)p)->checksum = acpi_checksum((uint8_t*)p, off);
+ /* increase number of tables */
+ (*(uint16_t*)acpi_tables)++;
+ return 0;
+out:
+ if (acpi_tables) {
+ free(acpi_tables);
+ acpi_tables = NULL;
+ }
+ return -1;
+}
diff --git a/hw/pc.c b/hw/pc.c
index 176730e..c403305 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -50,9 +50,13 @@
/* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables. */
#define ACPI_DATA_SIZE 0x10000
#define BIOS_CFG_IOPORT 0x510
+#define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0)
#define MAX_IDE_BUS 2
+extern uint8_t *acpi_tables;
+extern size_t acpi_tables_len;
+
static fdctrl_t *floppy_controller;
static RTCState *rtc_state;
static PITState *pit;
@@ -438,6 +442,7 @@ static void bochs_bios_init(void)
fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0);
fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
+ fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES, acpi_tables, acpi_tables_len);
}
/* Generate an initial boot sector which sets state and jump to
diff --git a/hw/pc.h b/hw/pc.h
index c67294d..7d2ed44 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -102,6 +102,7 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
qemu_irq sci_irq);
void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr);
void acpi_bios_init(void);
+int acpi_table_add(const char *table_desc);
/* hpet.c */
extern int no_hpet;
diff --git a/pc-bios/bios-pq/0011_kvm-bios-acpi-table-read.patch b/pc-bios/bios-pq/0011_kvm-bios-acpi-table-read.patch
new file mode 100644
index 0000000..72c5fac
--- /dev/null
+++ b/pc-bios/bios-pq/0011_kvm-bios-acpi-table-read.patch
@@ -0,0 +1,144 @@
+Read additional ACPI tables from Qemu.
+
+Signed-off-by: Glen Matapov <gleb@redhat.com>
+
+diff --git a/bios/rombios32.c b/bios/rombios32.c
+index f6ce225..29fd40a 100644
+--- a/bios/rombios32.c
++++ b/bios/rombios32.c
+@@ -455,6 +455,8 @@ unsigned long bios_table_end_addr;
+ #define QEMU_CFG_SIGNATURE 0x00
+ #define QEMU_CFG_ID 0x01
+ #define QEMU_CFG_UUID 0x02
++#define FW_CFG_ARCH_LOCAL 0x8000
++#define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0)
+
+ int qemu_cfg_port;
+
+@@ -482,6 +484,27 @@ void qemu_cfg_read(uint8_t *buf, int len)
+ while (len--)
+ *(buf++) = inb(QEMU_CFG_DATA_PORT);
+ }
++
++static int acpi_additional_tables(void)
++{
++ uint16_t cnt;
++
++ qemu_cfg_select(FW_CFG_ACPI_TABLES);
++ qemu_cfg_read((uint8_t*)&cnt, sizeof(cnt));
++
++ return cnt;
++}
++
++static int acpi_load_table(int i, uint32_t addr, uint16_t *len)
++{
++ qemu_cfg_read((uint8_t*)len, sizeof(*len));
++
++ if (!*len)
++ return -1;
++
++ qemu_cfg_read((uint8_t*)addr, *len);
++ return 0;
++}
+ #endif
+
+ void init_smp_msrs(void)
+@@ -1545,8 +1568,8 @@ void acpi_bios_init(void)
+ uint32_t hpet_addr;
+ #endif
+ uint32_t base_addr, rsdt_addr, fadt_addr, addr, facs_addr, dsdt_addr, ssdt_addr;
+- uint32_t acpi_tables_size, madt_addr, madt_size;
+- int i;
++ uint32_t acpi_tables_size, madt_addr, madt_size, rsdt_size;
++ int i, ext_tbl;
+
+ /* reserve memory space for tables */
+ #ifdef BX_USE_EBDA_TABLES
+@@ -1559,10 +1582,17 @@ void acpi_bios_init(void)
+ bios_table_cur_addr += sizeof(*rsdp);
+ #endif
+
++#ifdef BX_QEMU
++ ext_tbl = acpi_additional_tables();
++#else
++ ext_tbl = 0;
++#endif
++
+ addr = base_addr = ram_size - ACPI_DATA_SIZE;
+ rsdt_addr = addr;
+ rsdt = (void *)(addr);
+- addr += sizeof(*rsdt);
++ rsdt_size = sizeof(*rsdt) + ext_tbl * sizeof(rsdt->table_offset_entry[0]);
++ addr += rsdt_size;
+
+ fadt_addr = addr;
+ fadt = (void *)(addr);
+@@ -1601,12 +1631,6 @@ void acpi_bios_init(void)
+ addr += sizeof(*hpet);
+ #endif
+
+- acpi_tables_size = addr - base_addr;
+-
+- BX_INFO("ACPI tables: RSDP addr=0x%08lx ACPI DATA addr=0x%08lx size=0x%x\n",
+- (unsigned long)rsdp,
+- (unsigned long)rsdt, acpi_tables_size);
+-
+ /* RSDP */
+ memset(rsdp, 0, sizeof(*rsdp));
+ memcpy(rsdp->signature, "RSD PTR ", 8);
+@@ -1618,17 +1642,6 @@ void acpi_bios_init(void)
+ rsdp->rsdt_physical_address = cpu_to_le32(rsdt_addr);
+ rsdp->checksum = acpi_checksum((void *)rsdp, 20);
+
+- /* RSDT */
+- memset(rsdt, 0, sizeof(*rsdt));
+- rsdt->table_offset_entry[0] = cpu_to_le32(fadt_addr);
+- rsdt->table_offset_entry[1] = cpu_to_le32(madt_addr);
+- rsdt->table_offset_entry[2] = cpu_to_le32(ssdt_addr);
+-#ifdef BX_QEMU
+- rsdt->table_offset_entry[3] = cpu_to_le32(hpet_addr);
+-#endif
+- acpi_build_table_header((struct acpi_table_header *)rsdt,
+- "RSDT", sizeof(*rsdt), 1);
+-
+ /* FADT */
+ memset(fadt, 0, sizeof(*fadt));
+ fadt->firmware_ctrl = cpu_to_le32(facs_addr);
+@@ -1715,6 +1728,37 @@ void acpi_bios_init(void)
+ "HPET", sizeof(*hpet), 1);
+ #endif
+
++
++#ifdef BX_QEMU
++ acpi_additional_tables(); /* resets cfg to required entry */
++ for(i = 0; i < ext_tbl; i++) {
++ uint16_t len;
++ if(addr >= ram_size)
++ BX_PANIC("ACPI table overflow\n");
++ if(acpi_load_table(i, addr, &len) < 0)
++ BX_PANIC("Fail to load ACPI table from QEMU\n");
++ rsdt->table_offset_entry[i+4] = cpu_to_le32(addr);
++ addr += len;
++ }
++#endif
++
++ /* RSDT */
++ memset(rsdt, 0, sizeof(*rsdt));
++ rsdt->table_offset_entry[0] = cpu_to_le32(fadt_addr);
++ rsdt->table_offset_entry[1] = cpu_to_le32(madt_addr);
++ rsdt->table_offset_entry[2] = cpu_to_le32(ssdt_addr);
++#ifdef BX_QEMU
++ rsdt->table_offset_entry[3] = cpu_to_le32(hpet_addr);
++#endif
++ acpi_build_table_header((struct acpi_table_header *)rsdt,
++ "RSDT", rsdt_size, 1);
++
++ acpi_tables_size = addr - base_addr;
++
++ BX_INFO("ACPI tables: RSDP addr=0x%08lx ACPI DATA addr=0x%08lx size=0x%x\n",
++ (unsigned long)rsdp,
++ (unsigned long)rsdt, acpi_tables_size);
++
+ }
+
+ /* SMBIOS entry point -- must be written to a 16-bit aligned address
diff --git a/pc-bios/bios-pq/series b/pc-bios/bios-pq/series
index 728d041..23d5681 100644
--- a/pc-bios/bios-pq/series
+++ b/pc-bios/bios-pq/series
@@ -8,3 +8,4 @@
0008_kvm-bios-switch-mtrrs-to-cover-only-the-pci-range-and--default-to-wb.patch
0009_kvm-bios-resolve-memory-device-roll-over-reporting--issues-with-32g-guests.patch
0010_kvm-bios-fix-smbios-memory-device-length-boundary--condition.patch
+0011_kvm-bios-acpi-table-read.patch
diff --git a/qemu-doc.texi b/qemu-doc.texi
index efb88d2..44e9a82 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -893,6 +893,9 @@ only).
@item -no-hpet
Disable HPET support.
+@item -acpitable [sig=@var{str}][,rev=@var{n}][,oem_id=@var{str}][,oem_table_id=@var{str}][,oem_rev=@var{n}] [,asl_compiler_id=@var{str}][,asl_compiler_rev=@var{n}][,data=@var{file1}[:@var{file2}]...]
+Add ACPI table with specified header fields and context from specified files.
+
@end table
Linux boot specific: When using these options, you can use a given
diff --git a/vl.c b/vl.c
index aff2b2c..8cc4d50 100644
--- a/vl.c
+++ b/vl.c
@@ -3957,6 +3957,8 @@ static void help(int exitcode)
"-no-fd-bootchk disable boot signature checking for floppy disks\n"
"-no-acpi disable ACPI\n"
"-no-hpet disable HPET\n"
+ "-acpitable [sig=str][,rev=n][,oem_id=str][,oem_table_id=str][,oem_rev=n][,asl_compiler_id=str][,asl_compiler_rev=n][,data=file1[:file2]...]\n"
+ " ACPI table description\n"
#endif
"Linux boot specific:\n"
"-kernel bzImage use 'bzImage' as kernel image\n"
@@ -4092,6 +4094,7 @@ enum {
QEMU_OPTION_no_fd_bootchk,
QEMU_OPTION_no_acpi,
QEMU_OPTION_no_hpet,
+ QEMU_OPTION_acpitable,
/* Linux boot specific: */
QEMU_OPTION_kernel,
@@ -4210,6 +4213,7 @@ static const QEMUOption qemu_options[] = {
{ "no-fd-bootchk", 0, QEMU_OPTION_no_fd_bootchk },
{ "no-acpi", 0, QEMU_OPTION_no_acpi },
{ "no-hpet", 0, QEMU_OPTION_no_hpet },
+ { "acpitable", HAS_ARG, QEMU_OPTION_acpitable },
#endif
/* Linux boot specific: */
@@ -5069,6 +5073,12 @@ int main(int argc, char **argv, char **envp)
case QEMU_OPTION_rtc_td_hack:
rtc_td_hack = 1;
break;
+ case QEMU_OPTION_acpitable:
+ if(acpi_table_add(optarg) < 0) {
+ fprintf(stderr, "Wrong acpi table provided\n");
+ exit(1);
+ }
+ break;
#endif
#ifdef USE_KQEMU
case QEMU_OPTION_no_kqemu:
--
Gleb.
next reply other threads:[~2009-02-09 11:42 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-02-09 11:39 Gleb Natapov [this message]
2009-02-09 13:19 ` [Qemu-devel] [PATCH] Allow additions of ACPI tables from command line Anthony Liguori
2009-02-09 13:48 ` Gleb Natapov
-- strict thread matches above, loose matches on Subject: below --
2009-02-12 8:10 Gleb Natapov
2009-02-12 15:53 ` Blue Swirl
2009-02-12 16:37 ` Gleb Natapov
2009-02-12 16:59 ` Blue Swirl
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=20090209113947.GA28969@redhat.com \
--to=gleb@redhat.com \
--cc=qemu-devel@nongnu.org \
/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.