1 /* 2 * QEMU Xen PVH x86 Machine 3 * 4 * Copyright (c) 2024 Advanced Micro Devices, Inc. 5 * Written by Edgar E. Iglesias <edgar.iglesias@amd.com> 6 * 7 * SPDX-License-Identifier: GPL-2.0-or-later 8 */ 9 10 #include "qemu/osdep.h" 11 #include "qemu/error-report.h" 12 #include "hw/boards.h" 13 #include "system/system.h" 14 #include "hw/xen/arch_hvm.h" 15 #include <xen/hvm/hvm_info_table.h> 16 #include "hw/xen/xen-pvh-common.h" 17 #include "target/i386/cpu.h" 18 19 #define TYPE_XEN_PVH_X86 MACHINE_TYPE_NAME("xenpvh") 20 OBJECT_DECLARE_SIMPLE_TYPE(XenPVHx86State, XEN_PVH_X86) 21 22 struct XenPVHx86State { 23 /*< private >*/ 24 XenPVHMachineState parent; 25 26 DeviceState **cpu; 27 }; 28 29 static DeviceState *xen_pvh_cpu_new(MachineState *ms, 30 int64_t apic_id) 31 { 32 Object *cpu = object_new(ms->cpu_type); 33 34 object_property_add_child(OBJECT(ms), "cpu[*]", cpu); 35 object_property_set_uint(cpu, "apic-id", apic_id, &error_fatal); 36 qdev_realize(DEVICE(cpu), NULL, &error_fatal); 37 object_unref(cpu); 38 39 return DEVICE(cpu); 40 } 41 42 static void xen_pvh_init(MachineState *ms) 43 { 44 XenPVHx86State *xp = XEN_PVH_X86(ms); 45 int i; 46 47 /* Create dummy cores. This will indirectly create the APIC MSI window. */ 48 xp->cpu = g_malloc(sizeof xp->cpu[0] * ms->smp.max_cpus); 49 for (i = 0; i < ms->smp.max_cpus; i++) { 50 xp->cpu[i] = xen_pvh_cpu_new(ms, i); 51 } 52 } 53 54 static void xen_pvh_instance_init(Object *obj) 55 { 56 XenPVHMachineState *s = XEN_PVH_MACHINE(obj); 57 58 /* Default values. */ 59 s->cfg.ram_low = (MemMapEntry) { 0x0, 0x80000000U }; 60 s->cfg.ram_high = (MemMapEntry) { 0xC000000000ULL, 0x4000000000ULL }; 61 s->cfg.pci_intx_irq_base = 16; 62 } 63 64 /* 65 * Deliver INTX interrupts to Xen guest. 66 */ 67 static void xen_pvh_set_pci_intx_irq(void *opaque, int irq, int level) 68 { 69 /* 70 * Since QEMU emulates all of the swizziling 71 * We don't want Xen to do any additional swizzling in 72 * xen_set_pci_intx_level() so we always set device to 0. 73 */ 74 if (xen_set_pci_intx_level(xen_domid, 0, 0, 0, irq, level)) { 75 error_report("xendevicemodel_set_pci_intx_level failed"); 76 } 77 } 78 79 static void xen_pvh_machine_class_init(ObjectClass *oc, const void *data) 80 { 81 XenPVHMachineClass *xpc = XEN_PVH_MACHINE_CLASS(oc); 82 MachineClass *mc = MACHINE_CLASS(oc); 83 84 mc->desc = "Xen PVH x86 machine"; 85 mc->default_cpu_type = TARGET_DEFAULT_CPU_TYPE; 86 87 /* mc->max_cpus holds the MAX value allowed in the -smp cmd-line opts. */ 88 mc->max_cpus = HVM_MAX_VCPUS; 89 90 /* We have an implementation specific init to create CPU objects. */ 91 xpc->init = xen_pvh_init; 92 93 /* Enable buffered IOREQs. */ 94 xpc->handle_bufioreq = HVM_IOREQSRV_BUFIOREQ_ATOMIC; 95 96 /* 97 * PCI INTX routing. 98 * 99 * We describe the mapping between the 4 INTX interrupt and GSIs 100 * using xen_set_pci_link_route(). xen_pvh_set_pci_intx_irq is 101 * used to deliver the interrupt. 102 */ 103 xpc->set_pci_intx_irq = xen_pvh_set_pci_intx_irq; 104 xpc->set_pci_link_route = xen_set_pci_link_route; 105 106 /* List of supported features known to work on PVH x86. */ 107 xpc->has_pci = true; 108 109 xen_pvh_class_setup_common_props(xpc); 110 } 111 112 static const TypeInfo xen_pvh_x86_machine_type = { 113 .name = TYPE_XEN_PVH_X86, 114 .parent = TYPE_XEN_PVH_MACHINE, 115 .class_init = xen_pvh_machine_class_init, 116 .instance_init = xen_pvh_instance_init, 117 .instance_size = sizeof(XenPVHx86State), 118 }; 119 120 static void xen_pvh_machine_register_types(void) 121 { 122 type_register_static(&xen_pvh_x86_machine_type); 123 } 124 125 type_init(xen_pvh_machine_register_types) 126