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