1
From b206938d22ff59109087a33851e658af7442dba2 Mon Sep 17 00:00:00 2001
2
From: Peter Maydell <peter.maydell@linaro.org>
3
Date: Fri, 22 Nov 2013 17:17:14 +0000
4
Subject: [PATCH 08/49] hw/arm: Add 'virt' platform
6
Add 'virt' platform support corresponding to arch/arm/mach-virt
7
in the Linux kernel tree. This has no platform-specific code but
8
can use any device whose kernel driver is is able to work purely
9
from a device tree node. We use this to instantiate a minimal
10
set of devices: a GIC and some virtio-mmio transports.
12
Signed-off-by: John Rigby <john.rigby@linaro.org>
13
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
14
Message-id: 1385140638-10444-8-git-send-email-peter.maydell@linaro.org
16
Significantly overhauled:
17
* renamed user-facing machine to just "virt"
18
* removed the A9 support (it can't work since the A9 has no
20
* added virtio-mmio transports instead of random set of 'soc' devices
21
(though we retain a pl011 UART)
22
* instead of updating io_base as we step through adding devices,
23
define a memory map with an array (similar to vexpress)
24
* similarly, define irqmap with an array
25
* folded in some minor fixes from John's aarch64-support patch
26
* rather than explicitly doing endian-swapping on FDT cells,
27
use fdt APIs that let us just pass in host-endian values
28
and let the fdt layer take care of the swapping
29
* miscellaneous minor code cleanups and style fixes
31
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
33
hw/arm/Makefile.objs | 2 +-
34
hw/arm/virt.c | 444 +++++++++++++++++++++++++++++++++++++++++++++++++++
35
2 files changed, 445 insertions(+), 1 deletion(-)
36
create mode 100644 hw/arm/virt.c
38
Index: qemu/hw/arm/Makefile.objs
39
===================================================================
40
--- qemu.orig/hw/arm/Makefile.objs 2014-01-10 12:03:45.756161023 -0600
41
+++ qemu/hw/arm/Makefile.objs 2014-01-10 12:06:39.008164917 -0600
43
obj-y += boot.o collie.o exynos4_boards.o gumstix.o highbank.o
44
obj-y += integratorcp.o kzm.o mainstone.o musicpal.o nseries.o
45
obj-y += omap_sx1.o overo.o palm.o realview.o spitz.o stellaris.o
46
-obj-y += tosa.o versatilepb.o vexpress.o xilinx_zynq.o z2.o
47
+obj-y += tosa.o versatilepb.o vexpress.o virt.o xilinx_zynq.o z2.o
49
obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
50
obj-y += omap1.o omap2.o omap3.o strongarm.o beagle.o
51
Index: qemu/hw/arm/virt.c
52
===================================================================
53
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
54
+++ qemu/hw/arm/virt.c 2014-01-10 12:03:50.656161133 -0600
57
+ * ARM mach-virt emulation
59
+ * Copyright (c) 2013 Linaro Limited
61
+ * This program is free software; you can redistribute it and/or modify it
62
+ * under the terms and conditions of the GNU General Public License,
63
+ * version 2 or later, as published by the Free Software Foundation.
65
+ * This program is distributed in the hope it will be useful, but WITHOUT
66
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
67
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
70
+ * You should have received a copy of the GNU General Public License along with
71
+ * this program. If not, see <http://www.gnu.org/licenses/>.
73
+ * Emulate a virtual board which works by passing Linux all the information
74
+ * it needs about what devices are present via the device tree.
75
+ * There are some restrictions about what we can do here:
76
+ * + we can only present devices whose Linux drivers will work based
77
+ * purely on the device tree with no platform data at all
78
+ * + we want to present a very stripped-down minimalist platform,
79
+ * both because this reduces the security attack surface from the guest
80
+ * and also because it reduces our exposure to being broken when
81
+ * the kernel updates its device tree bindings and requires further
82
+ * information in a device binding that we aren't providing.
83
+ * This is essentially the same approach kvmtool uses.
86
+#include "hw/sysbus.h"
87
+#include "hw/arm/arm.h"
88
+#include "hw/arm/primecell.h"
89
+#include "hw/devices.h"
91
+#include "sysemu/device_tree.h"
92
+#include "sysemu/sysemu.h"
93
+#include "sysemu/kvm.h"
94
+#include "hw/boards.h"
95
+#include "exec/address-spaces.h"
96
+#include "qemu/bitops.h"
97
+#include "qemu/error-report.h"
99
+#define NUM_VIRTIO_TRANSPORTS 32
101
+/* Number of external interrupt lines to configure the GIC with */
102
+#define NUM_IRQS 128
104
+#define GIC_FDT_IRQ_TYPE_SPI 0
105
+#define GIC_FDT_IRQ_TYPE_PPI 1
107
+#define GIC_FDT_IRQ_FLAGS_EDGE_LO_HI 1
108
+#define GIC_FDT_IRQ_FLAGS_EDGE_HI_LO 2
109
+#define GIC_FDT_IRQ_FLAGS_LEVEL_HI 4
110
+#define GIC_FDT_IRQ_FLAGS_LEVEL_LO 8
112
+#define GIC_FDT_IRQ_PPI_CPU_START 8
113
+#define GIC_FDT_IRQ_PPI_CPU_WIDTH 8
125
+typedef struct MemMapEntry {
130
+typedef struct VirtBoardInfo {
131
+ struct arm_boot_info bootinfo;
132
+ const char *cpu_model;
133
+ const char *qdevname;
134
+ const char *gic_compatible;
135
+ const MemMapEntry *memmap;
140
+ uint32_t clock_phandle;
143
+/* Addresses and sizes of our components.
144
+ * 0..128MB is space for a flash device so we can run bootrom code such as UEFI.
145
+ * 128MB..256MB is used for miscellaneous device I/O.
146
+ * 256MB..1GB is reserved for possible future PCI support (ie where the
147
+ * PCI memory window will go if we add a PCI host controller).
148
+ * 1GB and up is RAM (which may happily spill over into the
149
+ * high memory region beyond 4GB).
150
+ * This represents a compromise between how much RAM can be given to
151
+ * a 32 bit VM and leaving space for expansion and in particular for PCI.
153
+static const MemMapEntry a15memmap[] = {
154
+ /* Space up to 0x8000000 is reserved for a boot ROM */
155
+ [VIRT_FLASH] = { 0, 0x8000000 },
156
+ [VIRT_CPUPERIPHS] = { 0x8000000, 0x8000 },
157
+ /* GIC distributor and CPU interfaces sit inside the CPU peripheral space */
158
+ [VIRT_GIC_DIST] = { 0x8001000, 0x1000 },
159
+ [VIRT_GIC_CPU] = { 0x8002000, 0x1000 },
160
+ [VIRT_UART] = { 0x9000000, 0x1000 },
161
+ [VIRT_MMIO] = { 0xa000000, 0x200 },
162
+ /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
163
+ /* 0x10000000 .. 0x40000000 reserved for PCI */
164
+ [VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 },
167
+static const int a15irqmap[] = {
169
+ [VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */
172
+static VirtBoardInfo machines[] = {
174
+ .cpu_model = "cortex-a15",
175
+ .qdevname = "a15mpcore_priv",
176
+ .gic_compatible = "arm,cortex-a15-gic",
177
+ .memmap = a15memmap,
178
+ .irqmap = a15irqmap,
182
+static VirtBoardInfo *find_machine_info(const char *cpu)
186
+ for (i = 0; i < ARRAY_SIZE(machines); i++) {
187
+ if (strcmp(cpu, machines[i].cpu_model) == 0) {
188
+ return &machines[i];
194
+static void create_fdt(VirtBoardInfo *vbi)
196
+ void *fdt = create_device_tree(&vbi->fdt_size);
199
+ error_report("create_device_tree() failed");
206
+ qemu_devtree_setprop_string(fdt, "/", "compatible", "linux,dummy-virt");
207
+ qemu_devtree_setprop_cell(fdt, "/", "#address-cells", 0x2);
208
+ qemu_devtree_setprop_cell(fdt, "/", "#size-cells", 0x2);
211
+ * /chosen and /memory nodes must exist for load_dtb
212
+ * to fill in necessary properties later
214
+ qemu_devtree_add_subnode(fdt, "/chosen");
215
+ qemu_devtree_add_subnode(fdt, "/memory");
216
+ qemu_devtree_setprop_string(fdt, "/memory", "device_type", "memory");
218
+ /* Clock node, for the benefit of the UART. The kernel device tree
219
+ * binding documentation claims the PL011 node clock properties are
220
+ * optional but in practice if you omit them the kernel refuses to
221
+ * probe for the device.
223
+ vbi->clock_phandle = qemu_devtree_alloc_phandle(fdt);
224
+ qemu_devtree_add_subnode(fdt, "/apb-pclk");
225
+ qemu_devtree_setprop_string(fdt, "/apb-pclk", "compatible", "fixed-clock");
226
+ qemu_devtree_setprop_cell(fdt, "/apb-pclk", "#clock-cells", 0x0);
227
+ qemu_devtree_setprop_cell(fdt, "/apb-pclk", "clock-frequency", 24000000);
228
+ qemu_devtree_setprop_string(fdt, "/apb-pclk", "clock-output-names",
230
+ qemu_devtree_setprop_cell(fdt, "/apb-pclk", "phandle", vbi->clock_phandle);
232
+ /* No PSCI for TCG yet */
233
+ if (kvm_enabled()) {
234
+ qemu_devtree_add_subnode(fdt, "/psci");
235
+ qemu_devtree_setprop_string(fdt, "/psci", "compatible", "arm,psci");
236
+ qemu_devtree_setprop_string(fdt, "/psci", "method", "hvc");
237
+ qemu_devtree_setprop_cell(fdt, "/psci", "cpu_suspend",
238
+ PSCI_FN_CPU_SUSPEND);
239
+ qemu_devtree_setprop_cell(fdt, "/psci", "cpu_off", PSCI_FN_CPU_OFF);
240
+ qemu_devtree_setprop_cell(fdt, "/psci", "cpu_on", PSCI_FN_CPU_ON);
241
+ qemu_devtree_setprop_cell(fdt, "/psci", "migrate", PSCI_FN_MIGRATE);
245
+static void fdt_add_timer_nodes(const VirtBoardInfo *vbi)
247
+ /* Note that on A15 h/w these interrupts are level-triggered,
248
+ * but for the GIC implementation provided by both QEMU and KVM
249
+ * they are edge-triggered.
251
+ uint32_t irqflags = GIC_FDT_IRQ_FLAGS_EDGE_LO_HI;
253
+ irqflags = deposit32(irqflags, GIC_FDT_IRQ_PPI_CPU_START,
254
+ GIC_FDT_IRQ_PPI_CPU_WIDTH, (1 << vbi->smp_cpus) - 1);
256
+ qemu_devtree_add_subnode(vbi->fdt, "/timer");
257
+ qemu_devtree_setprop_string(vbi->fdt, "/timer",
258
+ "compatible", "arm,armv7-timer");
259
+ qemu_devtree_setprop_cells(vbi->fdt, "/timer", "interrupts",
260
+ GIC_FDT_IRQ_TYPE_PPI, 13, irqflags,
261
+ GIC_FDT_IRQ_TYPE_PPI, 14, irqflags,
262
+ GIC_FDT_IRQ_TYPE_PPI, 11, irqflags,
263
+ GIC_FDT_IRQ_TYPE_PPI, 10, irqflags);
266
+static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi)
270
+ qemu_devtree_add_subnode(vbi->fdt, "/cpus");
271
+ qemu_devtree_setprop_cell(vbi->fdt, "/cpus", "#address-cells", 0x1);
272
+ qemu_devtree_setprop_cell(vbi->fdt, "/cpus", "#size-cells", 0x0);
274
+ for (cpu = vbi->smp_cpus - 1; cpu >= 0; cpu--) {
275
+ char *nodename = g_strdup_printf("/cpus/cpu@%d", cpu);
276
+ ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu));
278
+ qemu_devtree_add_subnode(vbi->fdt, nodename);
279
+ qemu_devtree_setprop_string(vbi->fdt, nodename, "device_type", "cpu");
280
+ qemu_devtree_setprop_string(vbi->fdt, nodename, "compatible",
281
+ armcpu->dtb_compatible);
283
+ if (vbi->smp_cpus > 1) {
284
+ qemu_devtree_setprop_string(vbi->fdt, nodename,
285
+ "enable-method", "psci");
288
+ qemu_devtree_setprop_cell(vbi->fdt, nodename, "reg", cpu);
293
+static void fdt_add_gic_node(const VirtBoardInfo *vbi)
295
+ uint32_t gic_phandle;
297
+ gic_phandle = qemu_devtree_alloc_phandle(vbi->fdt);
298
+ qemu_devtree_setprop_cell(vbi->fdt, "/", "interrupt-parent", gic_phandle);
300
+ qemu_devtree_add_subnode(vbi->fdt, "/intc");
301
+ qemu_devtree_setprop_string(vbi->fdt, "/intc", "compatible",
302
+ vbi->gic_compatible);
303
+ qemu_devtree_setprop_cell(vbi->fdt, "/intc", "#interrupt-cells", 3);
304
+ qemu_devtree_setprop(vbi->fdt, "/intc", "interrupt-controller", NULL, 0);
305
+ qemu_devtree_setprop_sized_cells(vbi->fdt, "/intc", "reg",
306
+ 2, vbi->memmap[VIRT_GIC_DIST].base,
307
+ 2, vbi->memmap[VIRT_GIC_DIST].size,
308
+ 2, vbi->memmap[VIRT_GIC_CPU].base,
309
+ 2, vbi->memmap[VIRT_GIC_CPU].size);
310
+ qemu_devtree_setprop_cell(vbi->fdt, "/intc", "phandle", gic_phandle);
313
+static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic)
316
+ hwaddr base = vbi->memmap[VIRT_UART].base;
317
+ hwaddr size = vbi->memmap[VIRT_UART].size;
318
+ int irq = vbi->irqmap[VIRT_UART];
319
+ const char compat[] = "arm,pl011\0arm,primecell";
320
+ const char clocknames[] = "uartclk\0apb_pclk";
322
+ sysbus_create_simple("pl011", base, pic[irq]);
324
+ nodename = g_strdup_printf("/pl011@%" PRIx64, base);
325
+ qemu_devtree_add_subnode(vbi->fdt, nodename);
326
+ /* Note that we can't use setprop_string because of the embedded NUL */
327
+ qemu_devtree_setprop(vbi->fdt, nodename, "compatible",
328
+ compat, sizeof(compat));
329
+ qemu_devtree_setprop_sized_cells(vbi->fdt, nodename, "reg",
331
+ qemu_devtree_setprop_cells(vbi->fdt, nodename, "interrupts",
332
+ GIC_FDT_IRQ_TYPE_SPI, irq,
333
+ GIC_FDT_IRQ_FLAGS_EDGE_LO_HI);
334
+ qemu_devtree_setprop_cells(vbi->fdt, nodename, "clocks",
335
+ vbi->clock_phandle, vbi->clock_phandle);
336
+ qemu_devtree_setprop(vbi->fdt, nodename, "clock-names",
337
+ clocknames, sizeof(clocknames));
341
+static void create_virtio_devices(const VirtBoardInfo *vbi, qemu_irq *pic)
344
+ hwaddr size = vbi->memmap[VIRT_MMIO].size;
346
+ /* Note that we have to create the transports in forwards order
347
+ * so that command line devices are inserted lowest address first,
348
+ * and then add dtb nodes in reverse order so that they appear in
349
+ * the finished device tree lowest address first.
351
+ for (i = 0; i < NUM_VIRTIO_TRANSPORTS; i++) {
352
+ int irq = vbi->irqmap[VIRT_MMIO] + i;
353
+ hwaddr base = vbi->memmap[VIRT_MMIO].base + i * size;
355
+ sysbus_create_simple("virtio-mmio", base, pic[irq]);
358
+ for (i = NUM_VIRTIO_TRANSPORTS - 1; i >= 0; i--) {
360
+ int irq = vbi->irqmap[VIRT_MMIO] + i;
361
+ hwaddr base = vbi->memmap[VIRT_MMIO].base + i * size;
363
+ nodename = g_strdup_printf("/virtio_mmio@%" PRIx64, base);
364
+ qemu_devtree_add_subnode(vbi->fdt, nodename);
365
+ qemu_devtree_setprop_string(vbi->fdt, nodename,
366
+ "compatible", "virtio,mmio");
367
+ qemu_devtree_setprop_sized_cells(vbi->fdt, nodename, "reg",
369
+ qemu_devtree_setprop_cells(vbi->fdt, nodename, "interrupts",
370
+ GIC_FDT_IRQ_TYPE_SPI, irq,
371
+ GIC_FDT_IRQ_FLAGS_EDGE_LO_HI);
376
+static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
378
+ const VirtBoardInfo *board = (const VirtBoardInfo *)binfo;
380
+ *fdt_size = board->fdt_size;
384
+static void machvirt_init(QEMUMachineInitArgs *args)
386
+ qemu_irq pic[NUM_IRQS];
387
+ MemoryRegion *sysmem = get_system_memory();
389
+ MemoryRegion *ram = g_new(MemoryRegion, 1);
391
+ SysBusDevice *busdev;
392
+ const char *cpu_model = args->cpu_model;
393
+ VirtBoardInfo *vbi;
396
+ cpu_model = "cortex-a15";
399
+ vbi = find_machine_info(cpu_model);
402
+ error_report("mach-virt: CPU %s not supported", cpu_model);
406
+ vbi->smp_cpus = smp_cpus;
409
+ * Only supported method of starting secondary CPUs is PSCI and
410
+ * PSCI is not yet supported with TCG, so limit smp_cpus to 1
411
+ * if we're not using KVM.
413
+ if (!kvm_enabled() && smp_cpus > 1) {
414
+ error_report("mach-virt: must enable KVM to use multiple CPUs");
418
+ if (args->ram_size > vbi->memmap[VIRT_MEM].size) {
419
+ error_report("mach-virt: cannot model more than 30GB RAM");
424
+ fdt_add_timer_nodes(vbi);
426
+ for (n = 0; n < smp_cpus; n++) {
427
+ ObjectClass *oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
431
+ fprintf(stderr, "Unable to find CPU definition\n");
434
+ cpuobj = object_new(object_class_get_name(oc));
436
+ /* Secondary CPUs start in PSCI powered-down state */
438
+ object_property_set_bool(cpuobj, true, "start-powered-off", NULL);
440
+ object_property_set_bool(cpuobj, true, "realized", NULL);
442
+ fdt_add_cpu_nodes(vbi);
444
+ memory_region_init_ram(ram, NULL, "mach-virt.ram", args->ram_size);
445
+ vmstate_register_ram_global(ram);
446
+ memory_region_add_subregion(sysmem, vbi->memmap[VIRT_MEM].base, ram);
448
+ dev = qdev_create(NULL, vbi->qdevname);
449
+ qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
450
+ /* Note that the num-irq property counts both internal and external
451
+ * interrupts; there are always 32 of the former (mandated by GIC spec).
453
+ qdev_prop_set_uint32(dev, "num-irq", NUM_IRQS + 32);
454
+ qdev_init_nofail(dev);
455
+ busdev = SYS_BUS_DEVICE(dev);
456
+ sysbus_mmio_map(busdev, 0, vbi->memmap[VIRT_CPUPERIPHS].base);
457
+ fdt_add_gic_node(vbi);
458
+ for (n = 0; n < smp_cpus; n++) {
459
+ DeviceState *cpudev = DEVICE(qemu_get_cpu(n));
461
+ sysbus_connect_irq(busdev, n, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
464
+ for (n = 0; n < NUM_IRQS; n++) {
465
+ pic[n] = qdev_get_gpio_in(dev, n);
468
+ create_uart(vbi, pic);
470
+ /* Create mmio transports, so the user can create virtio backends
471
+ * (which will be automatically plugged in to the transports). If
472
+ * no backend is created the transport will just sit harmlessly idle.
474
+ create_virtio_devices(vbi, pic);
476
+ vbi->bootinfo.ram_size = args->ram_size;
477
+ vbi->bootinfo.kernel_filename = args->kernel_filename;
478
+ vbi->bootinfo.kernel_cmdline = args->kernel_cmdline;
479
+ vbi->bootinfo.initrd_filename = args->initrd_filename;
480
+ vbi->bootinfo.nb_cpus = smp_cpus;
481
+ vbi->bootinfo.board_id = -1;
482
+ vbi->bootinfo.loader_start = vbi->memmap[VIRT_MEM].base;
483
+ vbi->bootinfo.get_dtb = machvirt_dtb;
484
+ arm_load_kernel(ARM_CPU(first_cpu), &vbi->bootinfo);
487
+static QEMUMachine machvirt_a15_machine = {
489
+ .desc = "ARM Virtual Machine",
490
+ .init = machvirt_init,
494
+static void machvirt_machine_init(void)
496
+ qemu_register_machine(&machvirt_a15_machine);
499
+machine_init(machvirt_machine_init);