[PATCH] load hpet info for HPET ACPI table from qemu
Load hpet info for HPET ACPI table from qemu instead of using hardcoded values. Use hardcoded values anyway if old qemu is detected. Signed-off-by: Gleb Natapov <gleb@redhat.com> diff --git a/src/acpi.c b/src/acpi.c index 0559443..eeecca1 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -469,7 +469,7 @@ build_ssdt(void) #define HPET_SIGNATURE 0x54455048 //HPET static void* -build_hpet(void) +build_hpet(struct hpet_fw_entry *e, u8 id) { struct acpi_20_hpet *hpet = malloc_high(sizeof(*hpet)); if (!hpet) { @@ -478,11 +478,11 @@ build_hpet(void) } memset(hpet, 0, sizeof(*hpet)); - /* Note timer_block_id value must be kept in sync with value advertised by - * emulated hpet - */ - hpet->timer_block_id = cpu_to_le32(0x8086a201); - hpet->addr.address = cpu_to_le32(ACPI_HPET_ADDRESS); + hpet->timer_block_id = cpu_to_le32(e->event_timer_block_id); + hpet->addr.address = cpu_to_le32(e->address); + hpet->min_tick = cpu_to_le32(e->min_tick); + hpet->hpet_number = id; + hpet->page_protect = e->page_prot; build_header((void*)hpet, HPET_SIGNATURE, sizeof(*hpet), 1); return hpet; @@ -637,9 +637,28 @@ acpi_bios_init(void) ACPI_INIT_TABLE(build_fadt(bdf)); ACPI_INIT_TABLE(build_ssdt()); ACPI_INIT_TABLE(build_madt()); - ACPI_INIT_TABLE(build_hpet()); ACPI_INIT_TABLE(build_srat()); + u8 hpet_id = 0; + u32 c = qemu_cfg_hpet_entries(); + struct hpet_fw_entry e; + + if (c == ~0) { + /* qemu do not provide hpet description */ + e.event_timer_block_id = 0x8086a201; + e.address = ACPI_HPET_ADDRESS; + e.min_tick = 0; + c = 1; + } else if (c != 0) + qemu_cfg_hpet_load_next(&e); + + while (c--) { + ACPI_INIT_TABLE(build_hpet(&e, hpet_id++)); + if (c) + qemu_cfg_hpet_load_next(&e); + } + + u16 i, external_tables = qemu_cfg_acpi_additional_tables(); for(i = 0; i < external_tables; i++) { diff --git a/src/paravirt.c b/src/paravirt.c index 5c77b5c..13a4916 100644 --- a/src/paravirt.c +++ b/src/paravirt.c @@ -149,6 +149,26 @@ void* qemu_cfg_e820_load_next(void *addr) return addr; } +u32 qemu_cfg_hpet_entries(void) +{ + u8 cnt; + + if (!qemu_cfg_present) + return 0; + + /* read valid flags */ + qemu_cfg_read_entry(&cnt, QEMU_CFG_HPET, sizeof(cnt)); + if (!cnt) + return ~0; + qemu_cfg_read(&cnt, sizeof(cnt)); + return cnt; +} + +void qemu_cfg_hpet_load_next(struct hpet_fw_entry *e) +{ + qemu_cfg_read((u8*)e, sizeof(*e)); +} + struct smbios_header { u16 length; u8 type; diff --git a/src/paravirt.h b/src/paravirt.h index c46418f..2fd98cc 100644 --- a/src/paravirt.h +++ b/src/paravirt.h @@ -37,6 +37,7 @@ static inline int kvm_para_available(void) #define QEMU_CFG_SMBIOS_ENTRIES (QEMU_CFG_ARCH_LOCAL + 1) #define QEMU_CFG_IRQ0_OVERRIDE (QEMU_CFG_ARCH_LOCAL + 2) #define QEMU_CFG_E820_TABLE (QEMU_CFG_ARCH_LOCAL + 3) +#define QEMU_CFG_HPET (QEMU_CFG_ARCH_LOCAL + 4) extern int qemu_cfg_present; @@ -68,10 +69,20 @@ struct e820_reservation { u32 type; }; +struct hpet_fw_entry +{ + u32 event_timer_block_id; + u64 address; + u16 min_tick; + u8 page_prot; +} __attribute__ ((packed)); + u16 qemu_cfg_first_file(QemuCfgFile *entry); u16 qemu_cfg_next_file(QemuCfgFile *entry); u32 qemu_cfg_read_file(QemuCfgFile *entry, void *dst, u32 maxlen); u32 qemu_cfg_e820_entries(void); void* qemu_cfg_e820_load_next(void *addr); +u32 qemu_cfg_hpet_entries(void); +void qemu_cfg_hpet_load_next(struct hpet_fw_entry *e); #endif -- Gleb.
participants (1)
-
Gleb Natapov