1*258b2a40SEdgar E. Iglesias /* 2*258b2a40SEdgar E. Iglesias * QEMU Xen PVH machine - common code. 3*258b2a40SEdgar E. Iglesias * 4*258b2a40SEdgar E. Iglesias * Copyright (c) 2024 Advanced Micro Devices, Inc. 5*258b2a40SEdgar E. Iglesias * 6*258b2a40SEdgar E. Iglesias * SPDX-License-Identifier: GPL-2.0-or-later 7*258b2a40SEdgar E. Iglesias */ 8*258b2a40SEdgar E. Iglesias 9*258b2a40SEdgar E. Iglesias #include "qemu/osdep.h" 10*258b2a40SEdgar E. Iglesias #include "qemu/error-report.h" 11*258b2a40SEdgar E. Iglesias #include "qapi/error.h" 12*258b2a40SEdgar E. Iglesias #include "qapi/visitor.h" 13*258b2a40SEdgar E. Iglesias #include "hw/boards.h" 14*258b2a40SEdgar E. Iglesias #include "hw/irq.h" 15*258b2a40SEdgar E. Iglesias #include "hw/sysbus.h" 16*258b2a40SEdgar E. Iglesias #include "sysemu/sysemu.h" 17*258b2a40SEdgar E. Iglesias #include "sysemu/tpm.h" 18*258b2a40SEdgar E. Iglesias #include "sysemu/tpm_backend.h" 19*258b2a40SEdgar E. Iglesias #include "hw/xen/xen-pvh-common.h" 20*258b2a40SEdgar E. Iglesias #include "trace.h" 21*258b2a40SEdgar E. Iglesias 22*258b2a40SEdgar E. Iglesias static const MemoryListener xen_memory_listener = { 23*258b2a40SEdgar E. Iglesias .region_add = xen_region_add, 24*258b2a40SEdgar E. Iglesias .region_del = xen_region_del, 25*258b2a40SEdgar E. Iglesias .log_start = NULL, 26*258b2a40SEdgar E. Iglesias .log_stop = NULL, 27*258b2a40SEdgar E. Iglesias .log_sync = NULL, 28*258b2a40SEdgar E. Iglesias .log_global_start = NULL, 29*258b2a40SEdgar E. Iglesias .log_global_stop = NULL, 30*258b2a40SEdgar E. Iglesias .priority = MEMORY_LISTENER_PRIORITY_ACCEL, 31*258b2a40SEdgar E. Iglesias }; 32*258b2a40SEdgar E. Iglesias 33*258b2a40SEdgar E. Iglesias static void xen_pvh_init_ram(XenPVHMachineState *s, 34*258b2a40SEdgar E. Iglesias MemoryRegion *sysmem) 35*258b2a40SEdgar E. Iglesias { 36*258b2a40SEdgar E. Iglesias MachineState *ms = MACHINE(s); 37*258b2a40SEdgar E. Iglesias ram_addr_t block_len, ram_size[2]; 38*258b2a40SEdgar E. Iglesias 39*258b2a40SEdgar E. Iglesias if (ms->ram_size <= s->cfg.ram_low.size) { 40*258b2a40SEdgar E. Iglesias ram_size[0] = ms->ram_size; 41*258b2a40SEdgar E. Iglesias ram_size[1] = 0; 42*258b2a40SEdgar E. Iglesias block_len = s->cfg.ram_low.base + ram_size[0]; 43*258b2a40SEdgar E. Iglesias } else { 44*258b2a40SEdgar E. Iglesias ram_size[0] = s->cfg.ram_low.size; 45*258b2a40SEdgar E. Iglesias ram_size[1] = ms->ram_size - s->cfg.ram_low.size; 46*258b2a40SEdgar E. Iglesias block_len = s->cfg.ram_high.base + ram_size[1]; 47*258b2a40SEdgar E. Iglesias } 48*258b2a40SEdgar E. Iglesias 49*258b2a40SEdgar E. Iglesias memory_region_init_ram(&xen_memory, NULL, "xen.ram", block_len, 50*258b2a40SEdgar E. Iglesias &error_fatal); 51*258b2a40SEdgar E. Iglesias 52*258b2a40SEdgar E. Iglesias memory_region_init_alias(&s->ram.low, NULL, "xen.ram.lo", &xen_memory, 53*258b2a40SEdgar E. Iglesias s->cfg.ram_low.base, ram_size[0]); 54*258b2a40SEdgar E. Iglesias memory_region_add_subregion(sysmem, s->cfg.ram_low.base, &s->ram.low); 55*258b2a40SEdgar E. Iglesias if (ram_size[1] > 0) { 56*258b2a40SEdgar E. Iglesias memory_region_init_alias(&s->ram.high, NULL, "xen.ram.hi", &xen_memory, 57*258b2a40SEdgar E. Iglesias s->cfg.ram_high.base, ram_size[1]); 58*258b2a40SEdgar E. Iglesias memory_region_add_subregion(sysmem, s->cfg.ram_high.base, &s->ram.high); 59*258b2a40SEdgar E. Iglesias } 60*258b2a40SEdgar E. Iglesias 61*258b2a40SEdgar E. Iglesias /* Setup support for grants. */ 62*258b2a40SEdgar E. Iglesias memory_region_init_ram(&xen_grants, NULL, "xen.grants", block_len, 63*258b2a40SEdgar E. Iglesias &error_fatal); 64*258b2a40SEdgar E. Iglesias memory_region_add_subregion(sysmem, XEN_GRANT_ADDR_OFF, &xen_grants); 65*258b2a40SEdgar E. Iglesias } 66*258b2a40SEdgar E. Iglesias 67*258b2a40SEdgar E. Iglesias static void xen_set_irq(void *opaque, int irq, int level) 68*258b2a40SEdgar E. Iglesias { 69*258b2a40SEdgar E. Iglesias if (xendevicemodel_set_irq_level(xen_dmod, xen_domid, irq, level)) { 70*258b2a40SEdgar E. Iglesias error_report("xendevicemodel_set_irq_level failed"); 71*258b2a40SEdgar E. Iglesias } 72*258b2a40SEdgar E. Iglesias } 73*258b2a40SEdgar E. Iglesias 74*258b2a40SEdgar E. Iglesias static void xen_create_virtio_mmio_devices(XenPVHMachineState *s) 75*258b2a40SEdgar E. Iglesias { 76*258b2a40SEdgar E. Iglesias int i; 77*258b2a40SEdgar E. Iglesias 78*258b2a40SEdgar E. Iglesias for (i = 0; i < s->cfg.virtio_mmio_num; i++) { 79*258b2a40SEdgar E. Iglesias hwaddr base = s->cfg.virtio_mmio.base + i * s->cfg.virtio_mmio.size; 80*258b2a40SEdgar E. Iglesias qemu_irq irq = qemu_allocate_irq(xen_set_irq, NULL, 81*258b2a40SEdgar E. Iglesias s->cfg.virtio_mmio_irq_base + i); 82*258b2a40SEdgar E. Iglesias 83*258b2a40SEdgar E. Iglesias sysbus_create_simple("virtio-mmio", base, irq); 84*258b2a40SEdgar E. Iglesias 85*258b2a40SEdgar E. Iglesias trace_xen_create_virtio_mmio_devices(i, 86*258b2a40SEdgar E. Iglesias s->cfg.virtio_mmio_irq_base + i, 87*258b2a40SEdgar E. Iglesias base); 88*258b2a40SEdgar E. Iglesias } 89*258b2a40SEdgar E. Iglesias } 90*258b2a40SEdgar E. Iglesias 91*258b2a40SEdgar E. Iglesias #ifdef CONFIG_TPM 92*258b2a40SEdgar E. Iglesias static void xen_enable_tpm(XenPVHMachineState *s) 93*258b2a40SEdgar E. Iglesias { 94*258b2a40SEdgar E. Iglesias Error *errp = NULL; 95*258b2a40SEdgar E. Iglesias DeviceState *dev; 96*258b2a40SEdgar E. Iglesias SysBusDevice *busdev; 97*258b2a40SEdgar E. Iglesias 98*258b2a40SEdgar E. Iglesias TPMBackend *be = qemu_find_tpm_be("tpm0"); 99*258b2a40SEdgar E. Iglesias if (be == NULL) { 100*258b2a40SEdgar E. Iglesias error_report("Couldn't find tmp0 backend"); 101*258b2a40SEdgar E. Iglesias return; 102*258b2a40SEdgar E. Iglesias } 103*258b2a40SEdgar E. Iglesias dev = qdev_new(TYPE_TPM_TIS_SYSBUS); 104*258b2a40SEdgar E. Iglesias object_property_set_link(OBJECT(dev), "tpmdev", OBJECT(be), &errp); 105*258b2a40SEdgar E. Iglesias object_property_set_str(OBJECT(dev), "tpmdev", be->id, &errp); 106*258b2a40SEdgar E. Iglesias busdev = SYS_BUS_DEVICE(dev); 107*258b2a40SEdgar E. Iglesias sysbus_realize_and_unref(busdev, &error_fatal); 108*258b2a40SEdgar E. Iglesias sysbus_mmio_map(busdev, 0, s->cfg.tpm.base); 109*258b2a40SEdgar E. Iglesias 110*258b2a40SEdgar E. Iglesias trace_xen_enable_tpm(s->cfg.tpm.base); 111*258b2a40SEdgar E. Iglesias } 112*258b2a40SEdgar E. Iglesias #endif 113*258b2a40SEdgar E. Iglesias 114*258b2a40SEdgar E. Iglesias static void xen_pvh_init(MachineState *ms) 115*258b2a40SEdgar E. Iglesias { 116*258b2a40SEdgar E. Iglesias XenPVHMachineState *s = XEN_PVH_MACHINE(ms); 117*258b2a40SEdgar E. Iglesias XenPVHMachineClass *xpc = XEN_PVH_MACHINE_GET_CLASS(s); 118*258b2a40SEdgar E. Iglesias MemoryRegion *sysmem = get_system_memory(); 119*258b2a40SEdgar E. Iglesias 120*258b2a40SEdgar E. Iglesias if (ms->ram_size == 0) { 121*258b2a40SEdgar E. Iglesias warn_report("%s: ram size not specified. QEMU machine started" 122*258b2a40SEdgar E. Iglesias " without IOREQ (no emulated devices including virtio)", 123*258b2a40SEdgar E. Iglesias MACHINE_CLASS(object_get_class(OBJECT(ms)))->desc); 124*258b2a40SEdgar E. Iglesias return; 125*258b2a40SEdgar E. Iglesias } 126*258b2a40SEdgar E. Iglesias 127*258b2a40SEdgar E. Iglesias xen_pvh_init_ram(s, sysmem); 128*258b2a40SEdgar E. Iglesias xen_register_ioreq(&s->ioreq, ms->smp.max_cpus, &xen_memory_listener); 129*258b2a40SEdgar E. Iglesias 130*258b2a40SEdgar E. Iglesias if (s->cfg.virtio_mmio_num) { 131*258b2a40SEdgar E. Iglesias xen_create_virtio_mmio_devices(s); 132*258b2a40SEdgar E. Iglesias } 133*258b2a40SEdgar E. Iglesias 134*258b2a40SEdgar E. Iglesias #ifdef CONFIG_TPM 135*258b2a40SEdgar E. Iglesias if (xpc->has_tpm) { 136*258b2a40SEdgar E. Iglesias if (s->cfg.tpm.base) { 137*258b2a40SEdgar E. Iglesias xen_enable_tpm(s); 138*258b2a40SEdgar E. Iglesias } else { 139*258b2a40SEdgar E. Iglesias warn_report("tpm-base-addr is not set. TPM will not be enabled"); 140*258b2a40SEdgar E. Iglesias } 141*258b2a40SEdgar E. Iglesias } 142*258b2a40SEdgar E. Iglesias #endif 143*258b2a40SEdgar E. Iglesias 144*258b2a40SEdgar E. Iglesias /* Call the implementation specific init. */ 145*258b2a40SEdgar E. Iglesias if (xpc->init) { 146*258b2a40SEdgar E. Iglesias xpc->init(ms); 147*258b2a40SEdgar E. Iglesias } 148*258b2a40SEdgar E. Iglesias } 149*258b2a40SEdgar E. Iglesias 150*258b2a40SEdgar E. Iglesias #define XEN_PVH_PROP_MEMMAP_SETTER(n, f) \ 151*258b2a40SEdgar E. Iglesias static void xen_pvh_set_ ## n ## _ ## f(Object *obj, Visitor *v, \ 152*258b2a40SEdgar E. Iglesias const char *name, void *opaque, \ 153*258b2a40SEdgar E. Iglesias Error **errp) \ 154*258b2a40SEdgar E. Iglesias { \ 155*258b2a40SEdgar E. Iglesias XenPVHMachineState *xp = XEN_PVH_MACHINE(obj); \ 156*258b2a40SEdgar E. Iglesias uint64_t value; \ 157*258b2a40SEdgar E. Iglesias \ 158*258b2a40SEdgar E. Iglesias if (!visit_type_size(v, name, &value, errp)) { \ 159*258b2a40SEdgar E. Iglesias return; \ 160*258b2a40SEdgar E. Iglesias } \ 161*258b2a40SEdgar E. Iglesias xp->cfg.n.f = value; \ 162*258b2a40SEdgar E. Iglesias } 163*258b2a40SEdgar E. Iglesias 164*258b2a40SEdgar E. Iglesias #define XEN_PVH_PROP_MEMMAP_GETTER(n, f) \ 165*258b2a40SEdgar E. Iglesias static void xen_pvh_get_ ## n ## _ ## f(Object *obj, Visitor *v, \ 166*258b2a40SEdgar E. Iglesias const char *name, void *opaque, \ 167*258b2a40SEdgar E. Iglesias Error **errp) \ 168*258b2a40SEdgar E. Iglesias { \ 169*258b2a40SEdgar E. Iglesias XenPVHMachineState *xp = XEN_PVH_MACHINE(obj); \ 170*258b2a40SEdgar E. Iglesias uint64_t value = xp->cfg.n.f; \ 171*258b2a40SEdgar E. Iglesias \ 172*258b2a40SEdgar E. Iglesias visit_type_uint64(v, name, &value, errp); \ 173*258b2a40SEdgar E. Iglesias } 174*258b2a40SEdgar E. Iglesias 175*258b2a40SEdgar E. Iglesias #define XEN_PVH_PROP_MEMMAP_BASE(n) \ 176*258b2a40SEdgar E. Iglesias XEN_PVH_PROP_MEMMAP_SETTER(n, base) \ 177*258b2a40SEdgar E. Iglesias XEN_PVH_PROP_MEMMAP_GETTER(n, base) \ 178*258b2a40SEdgar E. Iglesias 179*258b2a40SEdgar E. Iglesias #define XEN_PVH_PROP_MEMMAP_SIZE(n) \ 180*258b2a40SEdgar E. Iglesias XEN_PVH_PROP_MEMMAP_SETTER(n, size) \ 181*258b2a40SEdgar E. Iglesias XEN_PVH_PROP_MEMMAP_GETTER(n, size) 182*258b2a40SEdgar E. Iglesias 183*258b2a40SEdgar E. Iglesias #define XEN_PVH_PROP_MEMMAP(n) \ 184*258b2a40SEdgar E. Iglesias XEN_PVH_PROP_MEMMAP_BASE(n) \ 185*258b2a40SEdgar E. Iglesias XEN_PVH_PROP_MEMMAP_SIZE(n) 186*258b2a40SEdgar E. Iglesias 187*258b2a40SEdgar E. Iglesias XEN_PVH_PROP_MEMMAP(ram_low) 188*258b2a40SEdgar E. Iglesias XEN_PVH_PROP_MEMMAP(ram_high) 189*258b2a40SEdgar E. Iglesias /* TPM only has a base-addr option. */ 190*258b2a40SEdgar E. Iglesias XEN_PVH_PROP_MEMMAP_BASE(tpm) 191*258b2a40SEdgar E. Iglesias XEN_PVH_PROP_MEMMAP(virtio_mmio) 192*258b2a40SEdgar E. Iglesias 193*258b2a40SEdgar E. Iglesias void xen_pvh_class_setup_common_props(XenPVHMachineClass *xpc) 194*258b2a40SEdgar E. Iglesias { 195*258b2a40SEdgar E. Iglesias ObjectClass *oc = OBJECT_CLASS(xpc); 196*258b2a40SEdgar E. Iglesias MachineClass *mc = MACHINE_CLASS(xpc); 197*258b2a40SEdgar E. Iglesias 198*258b2a40SEdgar E. Iglesias #define OC_MEMMAP_PROP_BASE(c, prop_name, name) \ 199*258b2a40SEdgar E. Iglesias do { \ 200*258b2a40SEdgar E. Iglesias object_class_property_add(c, prop_name "-base", "uint64_t", \ 201*258b2a40SEdgar E. Iglesias xen_pvh_get_ ## name ## _base, \ 202*258b2a40SEdgar E. Iglesias xen_pvh_set_ ## name ## _base, NULL, NULL); \ 203*258b2a40SEdgar E. Iglesias object_class_property_set_description(oc, prop_name "-base", \ 204*258b2a40SEdgar E. Iglesias "Set base address for " prop_name); \ 205*258b2a40SEdgar E. Iglesias } while (0) 206*258b2a40SEdgar E. Iglesias 207*258b2a40SEdgar E. Iglesias #define OC_MEMMAP_PROP_SIZE(c, prop_name, name) \ 208*258b2a40SEdgar E. Iglesias do { \ 209*258b2a40SEdgar E. Iglesias object_class_property_add(c, prop_name "-size", "uint64_t", \ 210*258b2a40SEdgar E. Iglesias xen_pvh_get_ ## name ## _size, \ 211*258b2a40SEdgar E. Iglesias xen_pvh_set_ ## name ## _size, NULL, NULL); \ 212*258b2a40SEdgar E. Iglesias object_class_property_set_description(oc, prop_name "-size", \ 213*258b2a40SEdgar E. Iglesias "Set memory range size for " prop_name); \ 214*258b2a40SEdgar E. Iglesias } while (0) 215*258b2a40SEdgar E. Iglesias 216*258b2a40SEdgar E. Iglesias #define OC_MEMMAP_PROP(c, prop_name, name) \ 217*258b2a40SEdgar E. Iglesias do { \ 218*258b2a40SEdgar E. Iglesias OC_MEMMAP_PROP_BASE(c, prop_name, name); \ 219*258b2a40SEdgar E. Iglesias OC_MEMMAP_PROP_SIZE(c, prop_name, name); \ 220*258b2a40SEdgar E. Iglesias } while (0) 221*258b2a40SEdgar E. Iglesias 222*258b2a40SEdgar E. Iglesias /* 223*258b2a40SEdgar E. Iglesias * We provide memmap properties to allow Xen to move things to other 224*258b2a40SEdgar E. Iglesias * addresses for example when users need to accomodate the memory-map 225*258b2a40SEdgar E. Iglesias * for 1:1 mapped devices/memory. 226*258b2a40SEdgar E. Iglesias */ 227*258b2a40SEdgar E. Iglesias OC_MEMMAP_PROP(oc, "ram-low", ram_low); 228*258b2a40SEdgar E. Iglesias OC_MEMMAP_PROP(oc, "ram-high", ram_high); 229*258b2a40SEdgar E. Iglesias 230*258b2a40SEdgar E. Iglesias if (xpc->has_virtio_mmio) { 231*258b2a40SEdgar E. Iglesias OC_MEMMAP_PROP(oc, "virtio-mmio", virtio_mmio); 232*258b2a40SEdgar E. Iglesias } 233*258b2a40SEdgar E. Iglesias 234*258b2a40SEdgar E. Iglesias #ifdef CONFIG_TPM 235*258b2a40SEdgar E. Iglesias if (xpc->has_tpm) { 236*258b2a40SEdgar E. Iglesias object_class_property_add(oc, "tpm-base-addr", "uint64_t", 237*258b2a40SEdgar E. Iglesias xen_pvh_get_tpm_base, 238*258b2a40SEdgar E. Iglesias xen_pvh_set_tpm_base, 239*258b2a40SEdgar E. Iglesias NULL, NULL); 240*258b2a40SEdgar E. Iglesias object_class_property_set_description(oc, "tpm-base-addr", 241*258b2a40SEdgar E. Iglesias "Set Base address for TPM device."); 242*258b2a40SEdgar E. Iglesias 243*258b2a40SEdgar E. Iglesias machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS); 244*258b2a40SEdgar E. Iglesias } 245*258b2a40SEdgar E. Iglesias #endif 246*258b2a40SEdgar E. Iglesias } 247*258b2a40SEdgar E. Iglesias 248*258b2a40SEdgar E. Iglesias static void xen_pvh_class_init(ObjectClass *oc, void *data) 249*258b2a40SEdgar E. Iglesias { 250*258b2a40SEdgar E. Iglesias MachineClass *mc = MACHINE_CLASS(oc); 251*258b2a40SEdgar E. Iglesias 252*258b2a40SEdgar E. Iglesias mc->init = xen_pvh_init; 253*258b2a40SEdgar E. Iglesias 254*258b2a40SEdgar E. Iglesias mc->desc = "Xen PVH machine"; 255*258b2a40SEdgar E. Iglesias mc->max_cpus = 1; 256*258b2a40SEdgar E. Iglesias mc->default_machine_opts = "accel=xen"; 257*258b2a40SEdgar E. Iglesias /* Set to zero to make sure that the real ram size is passed. */ 258*258b2a40SEdgar E. Iglesias mc->default_ram_size = 0; 259*258b2a40SEdgar E. Iglesias } 260*258b2a40SEdgar E. Iglesias 261*258b2a40SEdgar E. Iglesias static const TypeInfo xen_pvh_info = { 262*258b2a40SEdgar E. Iglesias .name = TYPE_XEN_PVH_MACHINE, 263*258b2a40SEdgar E. Iglesias .parent = TYPE_MACHINE, 264*258b2a40SEdgar E. Iglesias .abstract = true, 265*258b2a40SEdgar E. Iglesias .instance_size = sizeof(XenPVHMachineState), 266*258b2a40SEdgar E. Iglesias .class_size = sizeof(XenPVHMachineClass), 267*258b2a40SEdgar E. Iglesias .class_init = xen_pvh_class_init, 268*258b2a40SEdgar E. Iglesias }; 269*258b2a40SEdgar E. Iglesias 270*258b2a40SEdgar E. Iglesias static void xen_pvh_register_types(void) 271*258b2a40SEdgar E. Iglesias { 272*258b2a40SEdgar E. Iglesias type_register_static(&xen_pvh_info); 273*258b2a40SEdgar E. Iglesias } 274*258b2a40SEdgar E. Iglesias 275*258b2a40SEdgar E. Iglesias type_init(xen_pvh_register_types); 276