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