~ubuntu-branches/ubuntu/trusty/qemu/trusty

« back to all changes in this revision

Viewing changes to .pc/arm64/0011-hw-arm-virt-Support-cpu-host.patch/hw/arm/virt.c

  • Committer: Package Import Robot
  • Author(s): Serge Hallyn
  • Date: 2014-02-04 12:13:08 UTC
  • mfrom: (10.1.45 sid)
  • Revision ID: package-import@ubuntu.com-20140204121308-1xq92lrfs75agw2g
Tags: 1.7.0+dfsg-3ubuntu1~ppa1
* Merge 1.7.0+dfsg-3 from debian.  Remaining changes:
  - debian/patches/ubuntu:
    * expose-vmx_qemu64cpu.patch
    * linaro (omap3) and arm64 patches
    * ubuntu/target-ppc-add-stubs-for-kvm-breakpoints: fix FTBFS
      on ppc
    * ubuntu/CVE-2013-4377.patch: fix denial of service via virtio
  - debian/qemu-system-x86.modprobe: set kvm_intel nested=1 options
  - debian/control:
    * add arm64 to Architectures
    * add qemu-common and qemu-system-aarch64 packages
  - debian/qemu-system-common.install: add debian/tmp/usr/lib
  - debian/qemu-system-common.preinst: add kvm group
  - debian/qemu-system-common.postinst: remove acl placed by udev,
    and add udevadm trigger.
  - qemu-system-x86.links: add eepro100.rom, remove pxe-virtio,
    pxe-e1000 and pxe-rtl8139.
  - add qemu-system-x86.qemu-kvm.upstart and .default
  - qemu-user-static.postinst-in: remove arm64 binfmt
  - debian/rules:
    * allow parallel build
    * add aarch64 to system_targets and sys_systems
    * add qemu-kvm-spice links
    * install qemu-system-x86.modprobe
  - add debian/qemu-system-common.links for OVMF.fd link
* Remove kvm-img, kvm-nbd, kvm-ifup and kvm-ifdown symlinks.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * ARM mach-virt emulation
3
 
 *
4
 
 * Copyright (c) 2013 Linaro Limited
5
 
 *
6
 
 * This program is free software; you can redistribute it and/or modify it
7
 
 * under the terms and conditions of the GNU General Public License,
8
 
 * version 2 or later, as published by the Free Software Foundation.
9
 
 *
10
 
 * This program is distributed in the hope it will be useful, but WITHOUT
11
 
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
 
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13
 
 * more details.
14
 
 *
15
 
 * You should have received a copy of the GNU General Public License along with
16
 
 * this program.  If not, see <http://www.gnu.org/licenses/>.
17
 
 *
18
 
 * Emulate a virtual board which works by passing Linux all the information
19
 
 * it needs about what devices are present via the device tree.
20
 
 * There are some restrictions about what we can do here:
21
 
 *  + we can only present devices whose Linux drivers will work based
22
 
 *    purely on the device tree with no platform data at all
23
 
 *  + we want to present a very stripped-down minimalist platform,
24
 
 *    both because this reduces the security attack surface from the guest
25
 
 *    and also because it reduces our exposure to being broken when
26
 
 *    the kernel updates its device tree bindings and requires further
27
 
 *    information in a device binding that we aren't providing.
28
 
 * This is essentially the same approach kvmtool uses.
29
 
 */
30
 
 
31
 
#include "hw/sysbus.h"
32
 
#include "hw/arm/arm.h"
33
 
#include "hw/arm/primecell.h"
34
 
#include "hw/devices.h"
35
 
#include "net/net.h"
36
 
#include "sysemu/device_tree.h"
37
 
#include "sysemu/sysemu.h"
38
 
#include "sysemu/kvm.h"
39
 
#include "hw/boards.h"
40
 
#include "exec/address-spaces.h"
41
 
#include "qemu/bitops.h"
42
 
#include "qemu/error-report.h"
43
 
 
44
 
#define NUM_VIRTIO_TRANSPORTS 32
45
 
 
46
 
/* Number of external interrupt lines to configure the GIC with */
47
 
#define NUM_IRQS 128
48
 
 
49
 
#define GIC_FDT_IRQ_TYPE_SPI 0
50
 
#define GIC_FDT_IRQ_TYPE_PPI 1
51
 
 
52
 
#define GIC_FDT_IRQ_FLAGS_EDGE_LO_HI 1
53
 
#define GIC_FDT_IRQ_FLAGS_EDGE_HI_LO 2
54
 
#define GIC_FDT_IRQ_FLAGS_LEVEL_HI 4
55
 
#define GIC_FDT_IRQ_FLAGS_LEVEL_LO 8
56
 
 
57
 
#define GIC_FDT_IRQ_PPI_CPU_START 8
58
 
#define GIC_FDT_IRQ_PPI_CPU_WIDTH 8
59
 
 
60
 
enum {
61
 
    VIRT_FLASH,
62
 
    VIRT_MEM,
63
 
    VIRT_CPUPERIPHS,
64
 
    VIRT_GIC_DIST,
65
 
    VIRT_GIC_CPU,
66
 
    VIRT_UART,
67
 
    VIRT_MMIO,
68
 
};
69
 
 
70
 
typedef struct MemMapEntry {
71
 
    hwaddr base;
72
 
    hwaddr size;
73
 
} MemMapEntry;
74
 
 
75
 
typedef struct VirtBoardInfo {
76
 
    struct arm_boot_info bootinfo;
77
 
    const char *cpu_model;
78
 
    const char *qdevname;
79
 
    const char *gic_compatible;
80
 
    const MemMapEntry *memmap;
81
 
    const int *irqmap;
82
 
    int smp_cpus;
83
 
    void *fdt;
84
 
    int fdt_size;
85
 
    uint32_t clock_phandle;
86
 
} VirtBoardInfo;
87
 
 
88
 
/* Addresses and sizes of our components.
89
 
 * 0..128MB is space for a flash device so we can run bootrom code such as UEFI.
90
 
 * 128MB..256MB is used for miscellaneous device I/O.
91
 
 * 256MB..1GB is reserved for possible future PCI support (ie where the
92
 
 * PCI memory window will go if we add a PCI host controller).
93
 
 * 1GB and up is RAM (which may happily spill over into the
94
 
 * high memory region beyond 4GB).
95
 
 * This represents a compromise between how much RAM can be given to
96
 
 * a 32 bit VM and leaving space for expansion and in particular for PCI.
97
 
 */
98
 
static const MemMapEntry a15memmap[] = {
99
 
    /* Space up to 0x8000000 is reserved for a boot ROM */
100
 
    [VIRT_FLASH] = { 0, 0x8000000 },
101
 
    [VIRT_CPUPERIPHS] = { 0x8000000, 0x8000 },
102
 
    /* GIC distributor and CPU interfaces sit inside the CPU peripheral space */
103
 
    [VIRT_GIC_DIST] = { 0x8001000, 0x1000 },
104
 
    [VIRT_GIC_CPU] = { 0x8002000, 0x1000 },
105
 
    [VIRT_UART] = { 0x9000000, 0x1000 },
106
 
    [VIRT_MMIO] = { 0xa000000, 0x200 },
107
 
    /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
108
 
    /* 0x10000000 .. 0x40000000 reserved for PCI */
109
 
    [VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 },
110
 
};
111
 
 
112
 
static const int a15irqmap[] = {
113
 
    [VIRT_UART] = 1,
114
 
    [VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */
115
 
};
116
 
 
117
 
static VirtBoardInfo machines[] = {
118
 
    {
119
 
        .cpu_model = "cortex-a15",
120
 
        .qdevname = "a15mpcore_priv",
121
 
        .gic_compatible = "arm,cortex-a15-gic",
122
 
        .memmap = a15memmap,
123
 
        .irqmap = a15irqmap,
124
 
    },
125
 
};
126
 
 
127
 
static VirtBoardInfo *find_machine_info(const char *cpu)
128
 
{
129
 
    int i;
130
 
 
131
 
    for (i = 0; i < ARRAY_SIZE(machines); i++) {
132
 
        if (strcmp(cpu, machines[i].cpu_model) == 0) {
133
 
            return &machines[i];
134
 
        }
135
 
    }
136
 
    return NULL;
137
 
}
138
 
 
139
 
static void create_fdt(VirtBoardInfo *vbi)
140
 
{
141
 
    void *fdt = create_device_tree(&vbi->fdt_size);
142
 
 
143
 
    if (!fdt) {
144
 
        error_report("create_device_tree() failed");
145
 
        exit(1);
146
 
    }
147
 
 
148
 
    vbi->fdt = fdt;
149
 
 
150
 
    /* Header */
151
 
    qemu_devtree_setprop_string(fdt, "/", "compatible", "linux,dummy-virt");
152
 
    qemu_devtree_setprop_cell(fdt, "/", "#address-cells", 0x2);
153
 
    qemu_devtree_setprop_cell(fdt, "/", "#size-cells", 0x2);
154
 
 
155
 
    /*
156
 
     * /chosen and /memory nodes must exist for load_dtb
157
 
     * to fill in necessary properties later
158
 
     */
159
 
    qemu_devtree_add_subnode(fdt, "/chosen");
160
 
    qemu_devtree_add_subnode(fdt, "/memory");
161
 
    qemu_devtree_setprop_string(fdt, "/memory", "device_type", "memory");
162
 
 
163
 
    /* Clock node, for the benefit of the UART. The kernel device tree
164
 
     * binding documentation claims the PL011 node clock properties are
165
 
     * optional but in practice if you omit them the kernel refuses to
166
 
     * probe for the device.
167
 
     */
168
 
    vbi->clock_phandle = qemu_devtree_alloc_phandle(fdt);
169
 
    qemu_devtree_add_subnode(fdt, "/apb-pclk");
170
 
    qemu_devtree_setprop_string(fdt, "/apb-pclk", "compatible", "fixed-clock");
171
 
    qemu_devtree_setprop_cell(fdt, "/apb-pclk", "#clock-cells", 0x0);
172
 
    qemu_devtree_setprop_cell(fdt, "/apb-pclk", "clock-frequency", 24000000);
173
 
    qemu_devtree_setprop_string(fdt, "/apb-pclk", "clock-output-names",
174
 
                                "clk24mhz");
175
 
    qemu_devtree_setprop_cell(fdt, "/apb-pclk", "phandle", vbi->clock_phandle);
176
 
 
177
 
    /* No PSCI for TCG yet */
178
 
    if (kvm_enabled()) {
179
 
        qemu_devtree_add_subnode(fdt, "/psci");
180
 
        qemu_devtree_setprop_string(fdt, "/psci", "compatible", "arm,psci");
181
 
        qemu_devtree_setprop_string(fdt, "/psci", "method", "hvc");
182
 
        qemu_devtree_setprop_cell(fdt, "/psci", "cpu_suspend",
183
 
                                  PSCI_FN_CPU_SUSPEND);
184
 
        qemu_devtree_setprop_cell(fdt, "/psci", "cpu_off", PSCI_FN_CPU_OFF);
185
 
        qemu_devtree_setprop_cell(fdt, "/psci", "cpu_on", PSCI_FN_CPU_ON);
186
 
        qemu_devtree_setprop_cell(fdt, "/psci", "migrate", PSCI_FN_MIGRATE);
187
 
    }
188
 
}
189
 
 
190
 
static void fdt_add_timer_nodes(const VirtBoardInfo *vbi)
191
 
{
192
 
    /* Note that on A15 h/w these interrupts are level-triggered,
193
 
     * but for the GIC implementation provided by both QEMU and KVM
194
 
     * they are edge-triggered.
195
 
     */
196
 
    uint32_t irqflags = GIC_FDT_IRQ_FLAGS_EDGE_LO_HI;
197
 
 
198
 
    irqflags = deposit32(irqflags, GIC_FDT_IRQ_PPI_CPU_START,
199
 
                         GIC_FDT_IRQ_PPI_CPU_WIDTH, (1 << vbi->smp_cpus) - 1);
200
 
 
201
 
    qemu_devtree_add_subnode(vbi->fdt, "/timer");
202
 
    qemu_devtree_setprop_string(vbi->fdt, "/timer",
203
 
                                "compatible", "arm,armv7-timer");
204
 
    qemu_devtree_setprop_cells(vbi->fdt, "/timer", "interrupts",
205
 
                               GIC_FDT_IRQ_TYPE_PPI, 13, irqflags,
206
 
                               GIC_FDT_IRQ_TYPE_PPI, 14, irqflags,
207
 
                               GIC_FDT_IRQ_TYPE_PPI, 11, irqflags,
208
 
                               GIC_FDT_IRQ_TYPE_PPI, 10, irqflags);
209
 
}
210
 
 
211
 
static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi)
212
 
{
213
 
    int cpu;
214
 
 
215
 
    qemu_devtree_add_subnode(vbi->fdt, "/cpus");
216
 
    qemu_devtree_setprop_cell(vbi->fdt, "/cpus", "#address-cells", 0x1);
217
 
    qemu_devtree_setprop_cell(vbi->fdt, "/cpus", "#size-cells", 0x0);
218
 
 
219
 
    for (cpu = vbi->smp_cpus - 1; cpu >= 0; cpu--) {
220
 
        char *nodename = g_strdup_printf("/cpus/cpu@%d", cpu);
221
 
        ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu));
222
 
 
223
 
        qemu_devtree_add_subnode(vbi->fdt, nodename);
224
 
        qemu_devtree_setprop_string(vbi->fdt, nodename, "device_type", "cpu");
225
 
        qemu_devtree_setprop_string(vbi->fdt, nodename, "compatible",
226
 
                                    armcpu->dtb_compatible);
227
 
 
228
 
        if (vbi->smp_cpus > 1) {
229
 
            qemu_devtree_setprop_string(vbi->fdt, nodename,
230
 
                                        "enable-method", "psci");
231
 
        }
232
 
 
233
 
        qemu_devtree_setprop_cell(vbi->fdt, nodename, "reg", cpu);
234
 
        g_free(nodename);
235
 
    }
236
 
}
237
 
 
238
 
static void fdt_add_gic_node(const VirtBoardInfo *vbi)
239
 
{
240
 
    uint32_t gic_phandle;
241
 
 
242
 
    gic_phandle = qemu_devtree_alloc_phandle(vbi->fdt);
243
 
    qemu_devtree_setprop_cell(vbi->fdt, "/", "interrupt-parent", gic_phandle);
244
 
 
245
 
    qemu_devtree_add_subnode(vbi->fdt, "/intc");
246
 
    qemu_devtree_setprop_string(vbi->fdt, "/intc", "compatible",
247
 
                                vbi->gic_compatible);
248
 
    qemu_devtree_setprop_cell(vbi->fdt, "/intc", "#interrupt-cells", 3);
249
 
    qemu_devtree_setprop(vbi->fdt, "/intc", "interrupt-controller", NULL, 0);
250
 
    qemu_devtree_setprop_sized_cells(vbi->fdt, "/intc", "reg",
251
 
                                     2, vbi->memmap[VIRT_GIC_DIST].base,
252
 
                                     2, vbi->memmap[VIRT_GIC_DIST].size,
253
 
                                     2, vbi->memmap[VIRT_GIC_CPU].base,
254
 
                                     2, vbi->memmap[VIRT_GIC_CPU].size);
255
 
    qemu_devtree_setprop_cell(vbi->fdt, "/intc", "phandle", gic_phandle);
256
 
}
257
 
 
258
 
static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic)
259
 
{
260
 
    char *nodename;
261
 
    hwaddr base = vbi->memmap[VIRT_UART].base;
262
 
    hwaddr size = vbi->memmap[VIRT_UART].size;
263
 
    int irq = vbi->irqmap[VIRT_UART];
264
 
    const char compat[] = "arm,pl011\0arm,primecell";
265
 
    const char clocknames[] = "uartclk\0apb_pclk";
266
 
 
267
 
    sysbus_create_simple("pl011", base, pic[irq]);
268
 
 
269
 
    nodename = g_strdup_printf("/pl011@%" PRIx64, base);
270
 
    qemu_devtree_add_subnode(vbi->fdt, nodename);
271
 
    /* Note that we can't use setprop_string because of the embedded NUL */
272
 
    qemu_devtree_setprop(vbi->fdt, nodename, "compatible",
273
 
                         compat, sizeof(compat));
274
 
    qemu_devtree_setprop_sized_cells(vbi->fdt, nodename, "reg",
275
 
                                     2, base, 2, size);
276
 
    qemu_devtree_setprop_cells(vbi->fdt, nodename, "interrupts",
277
 
                               GIC_FDT_IRQ_TYPE_SPI, irq,
278
 
                               GIC_FDT_IRQ_FLAGS_EDGE_LO_HI);
279
 
    qemu_devtree_setprop_cells(vbi->fdt, nodename, "clocks",
280
 
                               vbi->clock_phandle, vbi->clock_phandle);
281
 
    qemu_devtree_setprop(vbi->fdt, nodename, "clock-names",
282
 
                         clocknames, sizeof(clocknames));
283
 
    g_free(nodename);
284
 
}
285
 
 
286
 
static void create_virtio_devices(const VirtBoardInfo *vbi, qemu_irq *pic)
287
 
{
288
 
    int i;
289
 
    hwaddr size = vbi->memmap[VIRT_MMIO].size;
290
 
 
291
 
    /* Note that we have to create the transports in forwards order
292
 
     * so that command line devices are inserted lowest address first,
293
 
     * and then add dtb nodes in reverse order so that they appear in
294
 
     * the finished device tree lowest address first.
295
 
     */
296
 
    for (i = 0; i < NUM_VIRTIO_TRANSPORTS; i++) {
297
 
        int irq = vbi->irqmap[VIRT_MMIO] + i;
298
 
        hwaddr base = vbi->memmap[VIRT_MMIO].base + i * size;
299
 
 
300
 
        sysbus_create_simple("virtio-mmio", base, pic[irq]);
301
 
    }
302
 
 
303
 
    for (i = NUM_VIRTIO_TRANSPORTS - 1; i >= 0; i--) {
304
 
        char *nodename;
305
 
        int irq = vbi->irqmap[VIRT_MMIO] + i;
306
 
        hwaddr base = vbi->memmap[VIRT_MMIO].base + i * size;
307
 
 
308
 
        nodename = g_strdup_printf("/virtio_mmio@%" PRIx64, base);
309
 
        qemu_devtree_add_subnode(vbi->fdt, nodename);
310
 
        qemu_devtree_setprop_string(vbi->fdt, nodename,
311
 
                                    "compatible", "virtio,mmio");
312
 
        qemu_devtree_setprop_sized_cells(vbi->fdt, nodename, "reg",
313
 
                                         2, base, 2, size);
314
 
        qemu_devtree_setprop_cells(vbi->fdt, nodename, "interrupts",
315
 
                                   GIC_FDT_IRQ_TYPE_SPI, irq,
316
 
                                   GIC_FDT_IRQ_FLAGS_EDGE_LO_HI);
317
 
        g_free(nodename);
318
 
    }
319
 
}
320
 
 
321
 
static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
322
 
{
323
 
    const VirtBoardInfo *board = (const VirtBoardInfo *)binfo;
324
 
 
325
 
    *fdt_size = board->fdt_size;
326
 
    return board->fdt;
327
 
}
328
 
 
329
 
static void machvirt_init(QEMUMachineInitArgs *args)
330
 
{
331
 
    qemu_irq pic[NUM_IRQS];
332
 
    MemoryRegion *sysmem = get_system_memory();
333
 
    int n;
334
 
    MemoryRegion *ram = g_new(MemoryRegion, 1);
335
 
    DeviceState *dev;
336
 
    SysBusDevice *busdev;
337
 
    const char *cpu_model = args->cpu_model;
338
 
    VirtBoardInfo *vbi;
339
 
 
340
 
    if (!cpu_model) {
341
 
        cpu_model = "cortex-a15";
342
 
    }
343
 
 
344
 
    vbi = find_machine_info(cpu_model);
345
 
 
346
 
    if (!vbi) {
347
 
        error_report("mach-virt: CPU %s not supported", cpu_model);
348
 
        exit(1);
349
 
    }
350
 
 
351
 
    vbi->smp_cpus = smp_cpus;
352
 
 
353
 
    /*
354
 
     * Only supported method of starting secondary CPUs is PSCI and
355
 
     * PSCI is not yet supported with TCG, so limit smp_cpus to 1
356
 
     * if we're not using KVM.
357
 
     */
358
 
    if (!kvm_enabled() && smp_cpus > 1) {
359
 
        error_report("mach-virt: must enable KVM to use multiple CPUs");
360
 
        exit(1);
361
 
    }
362
 
 
363
 
    if (args->ram_size > vbi->memmap[VIRT_MEM].size) {
364
 
        error_report("mach-virt: cannot model more than 30GB RAM");
365
 
        exit(1);
366
 
    }
367
 
 
368
 
    create_fdt(vbi);
369
 
    fdt_add_timer_nodes(vbi);
370
 
 
371
 
    for (n = 0; n < smp_cpus; n++) {
372
 
        ObjectClass *oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
373
 
        Object *cpuobj;
374
 
 
375
 
        if (!oc) {
376
 
            fprintf(stderr, "Unable to find CPU definition\n");
377
 
            exit(1);
378
 
        }
379
 
        cpuobj = object_new(object_class_get_name(oc));
380
 
 
381
 
        /* Secondary CPUs start in PSCI powered-down state */
382
 
        if (n > 0) {
383
 
            object_property_set_bool(cpuobj, true, "start-powered-off", NULL);
384
 
        }
385
 
        object_property_set_bool(cpuobj, true, "realized", NULL);
386
 
    }
387
 
    fdt_add_cpu_nodes(vbi);
388
 
 
389
 
    memory_region_init_ram(ram, NULL, "mach-virt.ram", args->ram_size);
390
 
    vmstate_register_ram_global(ram);
391
 
    memory_region_add_subregion(sysmem, vbi->memmap[VIRT_MEM].base, ram);
392
 
 
393
 
    dev = qdev_create(NULL, vbi->qdevname);
394
 
    qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
395
 
    /* Note that the num-irq property counts both internal and external
396
 
     * interrupts; there are always 32 of the former (mandated by GIC spec).
397
 
     */
398
 
    qdev_prop_set_uint32(dev, "num-irq", NUM_IRQS + 32);
399
 
    qdev_init_nofail(dev);
400
 
    busdev = SYS_BUS_DEVICE(dev);
401
 
    sysbus_mmio_map(busdev, 0, vbi->memmap[VIRT_CPUPERIPHS].base);
402
 
    fdt_add_gic_node(vbi);
403
 
    for (n = 0; n < smp_cpus; n++) {
404
 
        DeviceState *cpudev = DEVICE(qemu_get_cpu(n));
405
 
 
406
 
        sysbus_connect_irq(busdev, n, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
407
 
    }
408
 
 
409
 
    for (n = 0; n < NUM_IRQS; n++) {
410
 
        pic[n] = qdev_get_gpio_in(dev, n);
411
 
    }
412
 
 
413
 
    create_uart(vbi, pic);
414
 
 
415
 
    /* Create mmio transports, so the user can create virtio backends
416
 
     * (which will be automatically plugged in to the transports). If
417
 
     * no backend is created the transport will just sit harmlessly idle.
418
 
     */
419
 
    create_virtio_devices(vbi, pic);
420
 
 
421
 
    vbi->bootinfo.ram_size = args->ram_size;
422
 
    vbi->bootinfo.kernel_filename = args->kernel_filename;
423
 
    vbi->bootinfo.kernel_cmdline = args->kernel_cmdline;
424
 
    vbi->bootinfo.initrd_filename = args->initrd_filename;
425
 
    vbi->bootinfo.nb_cpus = smp_cpus;
426
 
    vbi->bootinfo.board_id = -1;
427
 
    vbi->bootinfo.loader_start = vbi->memmap[VIRT_MEM].base;
428
 
    vbi->bootinfo.get_dtb = machvirt_dtb;
429
 
    arm_load_kernel(ARM_CPU(first_cpu), &vbi->bootinfo);
430
 
}
431
 
 
432
 
static QEMUMachine machvirt_a15_machine = {
433
 
    .name = "virt",
434
 
    .desc = "ARM Virtual Machine",
435
 
    .init = machvirt_init,
436
 
    .max_cpus = 4,
437
 
};
438
 
 
439
 
static void machvirt_machine_init(void)
440
 
{
441
 
    qemu_register_machine(&machvirt_a15_machine);
442
 
}
443
 
 
444
 
machine_init(machvirt_machine_init);