xref: /qemu/hw/arm/xen-pvh.c (revision 1af029d799d0ab9a14e11c6e35620c26a3b87945)
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 void arch_handle_ioreq(XenIOState *state, ioreq_t *req)
119 {
120     hw_error("Invalid ioreq type 0x%x\n", req->type);
121 
122     return;
123 }
124 
125 void arch_xen_set_memory(XenIOState *state, MemoryRegionSection *section,
126                          bool add)
127 {
128 }
129 
130 void xen_hvm_modified_memory(ram_addr_t start, ram_addr_t length)
131 {
132 }
133 
134 void qmp_xen_set_global_dirty_log(bool enable, Error **errp)
135 {
136 }
137 
138 #ifdef CONFIG_TPM
139 static void xen_enable_tpm(XenArmState *xam)
140 {
141     Error *errp = NULL;
142     DeviceState *dev;
143     SysBusDevice *busdev;
144 
145     TPMBackend *be = qemu_find_tpm_be("tpm0");
146     if (be == NULL) {
147         error_report("Couldn't find tmp0 backend");
148         return;
149     }
150     dev = qdev_new(TYPE_TPM_TIS_SYSBUS);
151     object_property_set_link(OBJECT(dev), "tpmdev", OBJECT(be), &errp);
152     object_property_set_str(OBJECT(dev), "tpmdev", be->id, &errp);
153     busdev = SYS_BUS_DEVICE(dev);
154     sysbus_realize_and_unref(busdev, &error_fatal);
155     sysbus_mmio_map(busdev, 0, xam->cfg.tpm_base_addr);
156 
157     trace_xen_enable_tpm(xam->cfg.tpm_base_addr);
158 }
159 #endif
160 
161 static void xen_arm_init(MachineState *machine)
162 {
163     XenArmState *xam = XEN_ARM(machine);
164 
165     xam->state =  g_new0(XenIOState, 1);
166 
167     if (machine->ram_size == 0) {
168         warn_report("%s: ram size not specified. QEMU machine started"
169                     " without IOREQ (no emulated devices including virtio)",
170                     MACHINE_CLASS(object_get_class(OBJECT(machine)))->desc);
171         return;
172     }
173 
174     xen_init_ram(machine);
175 
176     xen_register_ioreq(xam->state, machine->smp.max_cpus, &xen_memory_listener);
177 
178     xen_create_virtio_mmio_devices(xam);
179 
180 #ifdef CONFIG_TPM
181     if (xam->cfg.tpm_base_addr) {
182         xen_enable_tpm(xam);
183     } else {
184         warn_report("tpm-base-addr is not provided. TPM will not be enabled");
185     }
186 #endif
187 }
188 
189 #ifdef CONFIG_TPM
190 static void xen_arm_get_tpm_base_addr(Object *obj, Visitor *v,
191                                       const char *name, void *opaque,
192                                       Error **errp)
193 {
194     XenArmState *xam = XEN_ARM(obj);
195     uint64_t value = xam->cfg.tpm_base_addr;
196 
197     visit_type_uint64(v, name, &value, errp);
198 }
199 
200 static void xen_arm_set_tpm_base_addr(Object *obj, Visitor *v,
201                                       const char *name, void *opaque,
202                                       Error **errp)
203 {
204     XenArmState *xam = XEN_ARM(obj);
205     uint64_t value;
206 
207     if (!visit_type_uint64(v, name, &value, errp)) {
208         return;
209     }
210 
211     xam->cfg.tpm_base_addr = value;
212 }
213 #endif
214 
215 static void xen_arm_machine_class_init(ObjectClass *oc, void *data)
216 {
217 
218     MachineClass *mc = MACHINE_CLASS(oc);
219     mc->desc = "Xen PVH ARM machine";
220     mc->init = xen_arm_init;
221 
222     /*
223      * mc->max_cpus holds the MAX value allowed in the -smp command-line opts.
224      *
225      * 1. If users don't pass any -smp option:
226      *   ms->smp.cpus will default to 1.
227      *   ms->smp.max_cpus will default to 1.
228      *
229      * 2. If users pass -smp X:
230      *   ms->smp.cpus will be set to X.
231      *   ms->smp.max_cpus will also be set to X.
232      *
233      * 3. If users pass -smp X,maxcpus=Y:
234      *   ms->smp.cpus will be set to X.
235      *   ms->smp.max_cpus will be set to Y.
236      *
237      * In scenarios 2 and 3, if X or Y are set to something larger than
238      * mc->max_cpus, QEMU will bail out with an error message.
239      */
240     mc->max_cpus = GUEST_MAX_VCPUS;
241     mc->default_machine_opts = "accel=xen";
242     /* Set explicitly here to make sure that real ram_size is passed */
243     mc->default_ram_size = 0;
244 
245 #ifdef CONFIG_TPM
246     object_class_property_add(oc, "tpm-base-addr", "uint64_t",
247                               xen_arm_get_tpm_base_addr,
248                               xen_arm_set_tpm_base_addr,
249                               NULL, NULL);
250     object_class_property_set_description(oc, "tpm-base-addr",
251                                           "Set Base address for TPM device.");
252 
253     machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS);
254 #endif
255 }
256 
257 static const TypeInfo xen_arm_machine_type = {
258     .name = TYPE_XEN_ARM,
259     .parent = TYPE_MACHINE,
260     .class_init = xen_arm_machine_class_init,
261     .instance_size = sizeof(XenArmState),
262 };
263 
264 static void xen_arm_machine_register_types(void)
265 {
266     type_register_static(&xen_arm_machine_type);
267 }
268 
269 type_init(xen_arm_machine_register_types)
270