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..864f1a8 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,27 @@ 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, 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..458ab08 100644 --- a/src/paravirt.c +++ b/src/paravirt.c @@ -149,6 +149,23 @@ void* qemu_cfg_e820_load_next(void *addr) return addr; }
+u8 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)); + 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..272af81 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); +u8 qemu_cfg_hpet_entries(void); +void qemu_cfg_hpet_load_next(struct hpet_fw_entry *e);
#endif -- Gleb.