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
xen_pvh_cpu_new(MachineState * ms,int64_t apic_id)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
xen_pvh_init(MachineState * ms)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
xen_pvh_instance_init(Object * obj)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 */
xen_pvh_set_pci_intx_irq(void * opaque,int irq,int level)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
xen_pvh_machine_class_init(ObjectClass * oc,const void * data)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
xen_pvh_machine_register_types(void)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