xref: /qemu/hw/arm/xen-pvh.c (revision a9fbd5275a66535ac7a450666a51653e46daed83)
1 /*
2  * QEMU ARM Xen PVH Machine
3  *
4  * SPDX-License-Identifier: MIT
5  */
6 
7 #include "qemu/osdep.h"
8 #include "qemu/error-report.h"
9 #include "qapi/qapi-commands-migration.h"
10 #include "qapi/visitor.h"
11 #include "hw/boards.h"
12 #include "hw/irq.h"
13 #include "hw/sysbus.h"
14 #include "sysemu/block-backend.h"
15 #include "sysemu/tpm_backend.h"
16 #include "sysemu/sysemu.h"
17 #include "hw/xen/xen-hvm-common.h"
18 #include "sysemu/tpm.h"
19 #include "hw/xen/arch_hvm.h"
20 #include "trace.h"
21 
22 #define TYPE_XEN_ARM  MACHINE_TYPE_NAME("xenpvh")
23 OBJECT_DECLARE_SIMPLE_TYPE(XenArmState, XEN_ARM)
24 
25 static const MemoryListener xen_memory_listener = {
26     .region_add = xen_region_add,
27     .region_del = xen_region_del,
28     .log_start = NULL,
29     .log_stop = NULL,
30     .log_sync = NULL,
31     .log_global_start = NULL,
32     .log_global_stop = NULL,
33     .priority = MEMORY_LISTENER_PRIORITY_ACCEL,
34 };
35 
36 struct XenArmState {
37     /*< private >*/
38     MachineState parent;
39 
40     XenIOState *state;
41 
42     struct {
43         uint64_t tpm_base_addr;
44     } cfg;
45 };
46 
47 static MemoryRegion ram_lo, ram_hi;
48 
49 /*
50  * VIRTIO_MMIO_DEV_SIZE is imported from tools/libs/light/libxl_arm.c under Xen
51  * repository.
52  *
53  * Origin: git://xenbits.xen.org/xen.git 2128143c114c
54  */
55 #define VIRTIO_MMIO_DEV_SIZE   0x200
56 
57 #define NR_VIRTIO_MMIO_DEVICES   \
58    (GUEST_VIRTIO_MMIO_SPI_LAST - GUEST_VIRTIO_MMIO_SPI_FIRST)
59 
60 static void xen_set_irq(void *opaque, int irq, int level)
61 {
62     if (xendevicemodel_set_irq_level(xen_dmod, xen_domid, irq, level)) {
63         error_report("xendevicemodel_set_irq_level failed");
64     }
65 }
66 
67 static void xen_create_virtio_mmio_devices(XenArmState *xam)
68 {
69     int i;
70 
71     for (i = 0; i < NR_VIRTIO_MMIO_DEVICES; i++) {
72         hwaddr base = GUEST_VIRTIO_MMIO_BASE + i * VIRTIO_MMIO_DEV_SIZE;
73         qemu_irq irq = qemu_allocate_irq(xen_set_irq, NULL,
74                                          GUEST_VIRTIO_MMIO_SPI_FIRST + i);
75 
76         sysbus_create_simple("virtio-mmio", base, irq);
77 
78         trace_xen_create_virtio_mmio_devices(i,
79                                              GUEST_VIRTIO_MMIO_SPI_FIRST + i,
80                                              base);
81     }
82 }
83 
84 static void xen_init_ram(MachineState *machine)
85 {
86     MemoryRegion *sysmem = get_system_memory();
87     ram_addr_t block_len, ram_size[GUEST_RAM_BANKS];
88 
89     trace_xen_init_ram(machine->ram_size);
90     if (machine->ram_size <= GUEST_RAM0_SIZE) {
91         ram_size[0] = machine->ram_size;
92         ram_size[1] = 0;
93         block_len = GUEST_RAM0_BASE + ram_size[0];
94     } else {
95         ram_size[0] = GUEST_RAM0_SIZE;
96         ram_size[1] = machine->ram_size - GUEST_RAM0_SIZE;
97         block_len = GUEST_RAM1_BASE + ram_size[1];
98     }
99 
100     memory_region_init_ram(&xen_memory, NULL, "xen.ram", block_len,
101                            &error_fatal);
102 
103     memory_region_init_alias(&ram_lo, NULL, "xen.ram.lo", &xen_memory,
104                              GUEST_RAM0_BASE, ram_size[0]);
105     memory_region_add_subregion(sysmem, GUEST_RAM0_BASE, &ram_lo);
106     if (ram_size[1] > 0) {
107         memory_region_init_alias(&ram_hi, NULL, "xen.ram.hi", &xen_memory,
108                                  GUEST_RAM1_BASE, ram_size[1]);
109         memory_region_add_subregion(sysmem, GUEST_RAM1_BASE, &ram_hi);
110     }
111 
112     /* Setup support for grants.  */
113     memory_region_init_ram(&xen_grants, NULL, "xen.grants", block_len,
114                            &error_fatal);
115     memory_region_add_subregion(sysmem, XEN_GRANT_ADDR_OFF, &xen_grants);
116 }
117 
118 #ifdef CONFIG_TPM
119 static void xen_enable_tpm(XenArmState *xam)
120 {
121     Error *errp = NULL;
122     DeviceState *dev;
123     SysBusDevice *busdev;
124 
125     TPMBackend *be = qemu_find_tpm_be("tpm0");
126     if (be == NULL) {
127         error_report("Couldn't find tmp0 backend");
128         return;
129     }
130     dev = qdev_new(TYPE_TPM_TIS_SYSBUS);
131     object_property_set_link(OBJECT(dev), "tpmdev", OBJECT(be), &errp);
132     object_property_set_str(OBJECT(dev), "tpmdev", be->id, &errp);
133     busdev = SYS_BUS_DEVICE(dev);
134     sysbus_realize_and_unref(busdev, &error_fatal);
135     sysbus_mmio_map(busdev, 0, xam->cfg.tpm_base_addr);
136 
137     trace_xen_enable_tpm(xam->cfg.tpm_base_addr);
138 }
139 #endif
140 
141 static void xen_arm_init(MachineState *machine)
142 {
143     XenArmState *xam = XEN_ARM(machine);
144 
145     xam->state =  g_new0(XenIOState, 1);
146 
147     if (machine->ram_size == 0) {
148         warn_report("%s: ram size not specified. QEMU machine started"
149                     " without IOREQ (no emulated devices including virtio)",
150                     MACHINE_CLASS(object_get_class(OBJECT(machine)))->desc);
151         return;
152     }
153 
154     xen_init_ram(machine);
155 
156     xen_register_ioreq(xam->state, machine->smp.max_cpus, &xen_memory_listener);
157 
158     xen_create_virtio_mmio_devices(xam);
159 
160 #ifdef CONFIG_TPM
161     if (xam->cfg.tpm_base_addr) {
162         xen_enable_tpm(xam);
163     } else {
164         warn_report("tpm-base-addr is not provided. TPM will not be enabled");
165     }
166 #endif
167 }
168 
169 #ifdef CONFIG_TPM
170 static void xen_arm_get_tpm_base_addr(Object *obj, Visitor *v,
171                                       const char *name, void *opaque,
172                                       Error **errp)
173 {
174     XenArmState *xam = XEN_ARM(obj);
175     uint64_t value = xam->cfg.tpm_base_addr;
176 
177     visit_type_uint64(v, name, &value, errp);
178 }
179 
180 static void xen_arm_set_tpm_base_addr(Object *obj, Visitor *v,
181                                       const char *name, void *opaque,
182                                       Error **errp)
183 {
184     XenArmState *xam = XEN_ARM(obj);
185     uint64_t value;
186 
187     if (!visit_type_uint64(v, name, &value, errp)) {
188         return;
189     }
190 
191     xam->cfg.tpm_base_addr = value;
192 }
193 #endif
194 
195 static void xen_arm_machine_class_init(ObjectClass *oc, void *data)
196 {
197 
198     MachineClass *mc = MACHINE_CLASS(oc);
199     mc->desc = "Xen PVH ARM machine";
200     mc->init = xen_arm_init;
201 
202     /*
203      * mc->max_cpus holds the MAX value allowed in the -smp command-line opts.
204      *
205      * 1. If users don't pass any -smp option:
206      *   ms->smp.cpus will default to 1.
207      *   ms->smp.max_cpus will default to 1.
208      *
209      * 2. If users pass -smp X:
210      *   ms->smp.cpus will be set to X.
211      *   ms->smp.max_cpus will also be set to X.
212      *
213      * 3. If users pass -smp X,maxcpus=Y:
214      *   ms->smp.cpus will be set to X.
215      *   ms->smp.max_cpus will be set to Y.
216      *
217      * In scenarios 2 and 3, if X or Y are set to something larger than
218      * mc->max_cpus, QEMU will bail out with an error message.
219      */
220     mc->max_cpus = GUEST_MAX_VCPUS;
221     mc->default_machine_opts = "accel=xen";
222     /* Set explicitly here to make sure that real ram_size is passed */
223     mc->default_ram_size = 0;
224 
225 #ifdef CONFIG_TPM
226     object_class_property_add(oc, "tpm-base-addr", "uint64_t",
227                               xen_arm_get_tpm_base_addr,
228                               xen_arm_set_tpm_base_addr,
229                               NULL, NULL);
230     object_class_property_set_description(oc, "tpm-base-addr",
231                                           "Set Base address for TPM device.");
232 
233     machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS);
234 #endif
235 }
236 
237 static const TypeInfo xen_arm_machine_type = {
238     .name = TYPE_XEN_ARM,
239     .parent = TYPE_MACHINE,
240     .class_init = xen_arm_machine_class_init,
241     .instance_size = sizeof(XenArmState),
242 };
243 
244 static void xen_arm_machine_register_types(void)
245 {
246     type_register_static(&xen_arm_machine_type);
247 }
248 
249 type_init(xen_arm_machine_register_types)
250