@@ -130,6 +130,7 @@ struct VirtMachineClass {
/* Machines < 6.2 have no support for describing cpu topology to guest */
bool no_cpu_topology;
bool no_tcg_lpa2;
+ bool no_ns_el2_virt_timer_irq;
};
struct VirtMachineState {
@@ -173,6 +174,7 @@ struct VirtMachineState {
PCIBus *bus;
char *oem_id;
char *oem_table_id;
+ bool ns_el2_virt_timer_irq;
};
#define VIRT_ECAM_ID(high) (high ? VIRT_HIGH_PCIE_ECAM : VIRT_PCIE_ECAM)
@@ -533,8 +533,8 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
}
/*
- * ACPI spec, Revision 5.1
- * 5.2.24 Generic Timer Description Table (GTDT)
+ * ACPI spec, Revision 6.5
+ * 5.2.25 Generic Timer Description Table (GTDT)
*/
static void
build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
@@ -548,7 +548,7 @@ build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
uint32_t irqflags = vmc->claim_edge_triggered_timers ?
1 : /* Interrupt is Edge triggered */
0; /* Interrupt is Level triggered */
- AcpiTable table = { .sig = "GTDT", .rev = 2, .oem_id = vms->oem_id,
+ AcpiTable table = { .sig = "GTDT", .rev = 3, .oem_id = vms->oem_id,
.oem_table_id = vms->oem_table_id };
acpi_table_begin(&table, table_data);
@@ -584,7 +584,15 @@ build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
build_append_int_noprefix(table_data, 0, 4);
/* Platform Timer Offset */
build_append_int_noprefix(table_data, 0, 4);
-
+ if (vms->ns_el2_virt_timer_irq) {
+ /* Virtual EL2 Timer GSIV */
+ build_append_int_noprefix(table_data, ARCH_TIMER_NS_EL2_VIRT_IRQ, 4);
+ /* Virtual EL2 Timer Flags */
+ build_append_int_noprefix(table_data, irqflags, 4);
+ } else {
+ build_append_int_noprefix(table_data, 0, 4);
+ build_append_int_noprefix(table_data, 0, 4);
+ }
acpi_table_end(linker, &table);
}
@@ -771,10 +779,10 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
static void build_fadt_rev6(GArray *table_data, BIOSLinker *linker,
VirtMachineState *vms, unsigned dsdt_tbl_offset)
{
- /* ACPI v6.0 */
+ /* ACPI v6.3 */
AcpiFadtData fadt = {
.rev = 6,
- .minor_ver = 0,
+ .minor_ver = 3,
.flags = 1 << ACPI_FADT_F_HW_REDUCED_ACPI,
.xdsdt_tbl_offset = &dsdt_tbl_offset,
};
@@ -221,6 +221,20 @@ static void create_randomness(MachineState *ms, const char *node)
qemu_fdt_setprop(ms->fdt, node, "rng-seed", seed.rng, sizeof(seed.rng));
}
+/*
+ * The CPU object always exposes the NS EL2 virt timer IRQ line,
+ * but we don't want to advertise it to the guest in the dtb or ACPI
+ * table unless it's really going to do something.
+ */
+static bool ns_el2_virt_timer_present(void)
+{
+ ARMCPU *cpu = ARM_CPU(qemu_get_cpu(0));
+ CPUARMState *env = &cpu->env;
+
+ return arm_feature(env, ARM_FEATURE_AARCH64) &&
+ arm_feature(env, ARM_FEATURE_EL2) && cpu_isar_feature(aa64_vh, cpu);
+}
+
static void create_fdt(VirtMachineState *vms)
{
MachineState *ms = MACHINE(vms);
@@ -338,15 +352,29 @@ static void fdt_add_timer_nodes(const VirtMachineState *vms)
"arm,armv7-timer");
}
qemu_fdt_setprop(ms->fdt, "/timer", "always-on", NULL, 0);
- qemu_fdt_setprop_cells(ms->fdt, "/timer", "interrupts",
- GIC_FDT_IRQ_TYPE_PPI,
- INTID_TO_PPI(ARCH_TIMER_S_EL1_IRQ), irqflags,
- GIC_FDT_IRQ_TYPE_PPI,
- INTID_TO_PPI(ARCH_TIMER_NS_EL1_IRQ), irqflags,
- GIC_FDT_IRQ_TYPE_PPI,
- INTID_TO_PPI(ARCH_TIMER_VIRT_IRQ), irqflags,
- GIC_FDT_IRQ_TYPE_PPI,
- INTID_TO_PPI(ARCH_TIMER_NS_EL2_IRQ), irqflags);
+ if (vms->ns_el2_virt_timer_irq) {
+ qemu_fdt_setprop_cells(ms->fdt, "/timer", "interrupts",
+ GIC_FDT_IRQ_TYPE_PPI,
+ INTID_TO_PPI(ARCH_TIMER_S_EL1_IRQ), irqflags,
+ GIC_FDT_IRQ_TYPE_PPI,
+ INTID_TO_PPI(ARCH_TIMER_NS_EL1_IRQ), irqflags,
+ GIC_FDT_IRQ_TYPE_PPI,
+ INTID_TO_PPI(ARCH_TIMER_VIRT_IRQ), irqflags,
+ GIC_FDT_IRQ_TYPE_PPI,
+ INTID_TO_PPI(ARCH_TIMER_NS_EL2_IRQ), irqflags,
+ GIC_FDT_IRQ_TYPE_PPI,
+ INTID_TO_PPI(ARCH_TIMER_NS_EL2_VIRT_IRQ), irqflags);
+ } else {
+ qemu_fdt_setprop_cells(ms->fdt, "/timer", "interrupts",
+ GIC_FDT_IRQ_TYPE_PPI,
+ INTID_TO_PPI(ARCH_TIMER_S_EL1_IRQ), irqflags,
+ GIC_FDT_IRQ_TYPE_PPI,
+ INTID_TO_PPI(ARCH_TIMER_NS_EL1_IRQ), irqflags,
+ GIC_FDT_IRQ_TYPE_PPI,
+ INTID_TO_PPI(ARCH_TIMER_VIRT_IRQ), irqflags,
+ GIC_FDT_IRQ_TYPE_PPI,
+ INTID_TO_PPI(ARCH_TIMER_NS_EL2_IRQ), irqflags);
+ }
}
static void fdt_add_cpu_nodes(const VirtMachineState *vms)
@@ -789,6 +817,7 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
[GTIMER_VIRT] = ARCH_TIMER_VIRT_IRQ,
[GTIMER_HYP] = ARCH_TIMER_NS_EL2_IRQ,
[GTIMER_SEC] = ARCH_TIMER_S_EL1_IRQ,
+ [GTIMER_HYPVIRT] = ARCH_TIMER_NS_EL2_VIRT_IRQ,
};
for (unsigned irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
@@ -2222,6 +2251,11 @@ static void machvirt_init(MachineState *machine)
qdev_realize(DEVICE(cpuobj), NULL, &error_fatal);
object_unref(cpuobj);
}
+
+ /* Now we've created the CPUs we can see if they have the hypvirt timer */
+ vms->ns_el2_virt_timer_irq = ns_el2_virt_timer_present() &&
+ !vmc->no_ns_el2_virt_timer_irq;
+
fdt_add_timer_nodes(vms);
fdt_add_cpu_nodes(vms);
@@ -3179,8 +3213,16 @@ DEFINE_VIRT_MACHINE_AS_LATEST(9, 0)
static void virt_machine_8_2_options(MachineClass *mc)
{
+ VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
+
virt_machine_9_0_options(mc);
compat_props_add(mc->compat_props, hw_compat_8_2, hw_compat_8_2_len);
+ /*
+ * Don't expose NS_EL2_VIRT timer IRQ in DTB on ACPI on 8.2 and
+ * earlier machines. (Exposing it tickles a bug in older EDK2
+ * guest BIOS binaries.)
+ */
+ vmc->no_ns_el2_virt_timer_irq = true;
}
DEFINE_VIRT_MACHINE(8, 2)