| 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/core/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) |