]> git.proxmox.com Git - mirror_qemu.git/blame - hw/riscv/virt.c
linux-user/riscv: Add the CPU type as a comment
[mirror_qemu.git] / hw / riscv / virt.c
CommitLineData
04331d0b
MC
1/*
2 * QEMU RISC-V VirtIO Board
3 *
4 * Copyright (c) 2017 SiFive, Inc.
5 *
6 * RISC-V machine with 16550a UART and VirtIO MMIO
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2 or later, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include "qemu/osdep.h"
4bf46af7 22#include "qemu/units.h"
04331d0b
MC
23#include "qemu/log.h"
24#include "qemu/error-report.h"
25#include "qapi/error.h"
26#include "hw/hw.h"
27#include "hw/boards.h"
28#include "hw/loader.h"
29#include "hw/sysbus.h"
30#include "hw/char/serial.h"
31#include "target/riscv/cpu.h"
04331d0b
MC
32#include "hw/riscv/riscv_hart.h"
33#include "hw/riscv/sifive_plic.h"
34#include "hw/riscv/sifive_clint.h"
35#include "hw/riscv/sifive_test.h"
36#include "hw/riscv/virt.h"
37#include "chardev/char.h"
38#include "sysemu/arch_init.h"
39#include "sysemu/device_tree.h"
40#include "exec/address-spaces.h"
6d56e396
AF
41#include "hw/pci/pci.h"
42#include "hw/pci-host/gpex.h"
04331d0b
MC
43#include "elf.h"
44
5aec3247
MC
45#include <libfdt.h>
46
04331d0b
MC
47static const struct MemmapEntry {
48 hwaddr base;
49 hwaddr size;
50} virt_memmap[] = {
bb1973aa
AF
51 [VIRT_DEBUG] = { 0x0, 0x100 },
52 [VIRT_MROM] = { 0x1000, 0x11000 },
53 [VIRT_TEST] = { 0x100000, 0x1000 },
54 [VIRT_CLINT] = { 0x2000000, 0x10000 },
55 [VIRT_PLIC] = { 0xc000000, 0x4000000 },
56 [VIRT_UART0] = { 0x10000000, 0x100 },
57 [VIRT_VIRTIO] = { 0x10001000, 0x1000 },
58 [VIRT_DRAM] = { 0x80000000, 0x0 },
6d56e396
AF
59 [VIRT_PCIE_MMIO] = { 0x40000000, 0x40000000 },
60 [VIRT_PCIE_PIO] = { 0x03000000, 0x00010000 },
61 [VIRT_PCIE_ECAM] = { 0x30000000, 0x10000000 },
04331d0b
MC
62};
63
40e46e51 64static target_ulong load_kernel(const char *kernel_filename)
04331d0b
MC
65{
66 uint64_t kernel_entry, kernel_high;
67
4366e1db 68 if (load_elf(kernel_filename, NULL, NULL, NULL,
04331d0b 69 &kernel_entry, NULL, &kernel_high,
89854803 70 0, EM_RISCV, 1, 0) < 0) {
371b74e2 71 error_report("could not load kernel '%s'", kernel_filename);
04331d0b
MC
72 exit(1);
73 }
74 return kernel_entry;
75}
76
77static hwaddr load_initrd(const char *filename, uint64_t mem_size,
78 uint64_t kernel_entry, hwaddr *start)
79{
80 int size;
81
82 /* We want to put the initrd far enough into RAM that when the
83 * kernel is uncompressed it will not clobber the initrd. However
84 * on boards without much RAM we must ensure that we still leave
85 * enough room for a decent sized initrd, and on boards with large
86 * amounts of RAM we must avoid the initrd being so far up in RAM
87 * that it is outside lowmem and inaccessible to the kernel.
88 * So for boards with less than 256MB of RAM we put the initrd
89 * halfway into RAM, and for boards with 256MB of RAM or more we put
90 * the initrd at 128MB.
91 */
4bf46af7 92 *start = kernel_entry + MIN(mem_size / 2, 128 * MiB);
04331d0b
MC
93
94 size = load_ramdisk(filename, *start, mem_size - *start);
95 if (size == -1) {
96 size = load_image_targphys(filename, *start, mem_size - *start);
97 if (size == -1) {
371b74e2 98 error_report("could not load ramdisk '%s'", filename);
04331d0b
MC
99 exit(1);
100 }
101 }
102 return *start + size;
103}
104
6d56e396
AF
105static void create_pcie_irq_map(void *fdt, char *nodename,
106 uint32_t plic_phandle)
107{
108 int pin, dev;
109 uint32_t
110 full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS * FDT_INT_MAP_WIDTH] = {};
111 uint32_t *irq_map = full_irq_map;
112
113 /* This code creates a standard swizzle of interrupts such that
114 * each device's first interrupt is based on it's PCI_SLOT number.
115 * (See pci_swizzle_map_irq_fn())
116 *
117 * We only need one entry per interrupt in the table (not one per
118 * possible slot) seeing the interrupt-map-mask will allow the table
119 * to wrap to any number of devices.
120 */
121 for (dev = 0; dev < GPEX_NUM_IRQS; dev++) {
122 int devfn = dev * 0x8;
123
124 for (pin = 0; pin < GPEX_NUM_IRQS; pin++) {
125 int irq_nr = PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS);
126 int i = 0;
127
128 irq_map[i] = cpu_to_be32(devfn << 8);
129
130 i += FDT_PCI_ADDR_CELLS;
131 irq_map[i] = cpu_to_be32(pin + 1);
132
133 i += FDT_PCI_INT_CELLS;
134 irq_map[i++] = cpu_to_be32(plic_phandle);
135
136 i += FDT_PLIC_ADDR_CELLS;
137 irq_map[i] = cpu_to_be32(irq_nr);
138
139 irq_map += FDT_INT_MAP_WIDTH;
140 }
141 }
142
143 qemu_fdt_setprop(fdt, nodename, "interrupt-map",
144 full_irq_map, sizeof(full_irq_map));
145
146 qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask",
147 0x1800, 0, 0, 0x7);
148}
149
04331d0b
MC
150static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
151 uint64_t mem_size, const char *cmdline)
152{
153 void *fdt;
154 int cpu;
155 uint32_t *cells;
156 char *nodename;
157 uint32_t plic_phandle, phandle = 1;
158 int i;
159
160 fdt = s->fdt = create_device_tree(&s->fdt_size);
161 if (!fdt) {
162 error_report("create_device_tree() failed");
163 exit(1);
164 }
165
166 qemu_fdt_setprop_string(fdt, "/", "model", "riscv-virtio,qemu");
167 qemu_fdt_setprop_string(fdt, "/", "compatible", "riscv-virtio");
168 qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x2);
169 qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2);
170
171 qemu_fdt_add_subnode(fdt, "/soc");
172 qemu_fdt_setprop(fdt, "/soc", "ranges", NULL, 0);
53f54508 173 qemu_fdt_setprop_string(fdt, "/soc", "compatible", "simple-bus");
04331d0b
MC
174 qemu_fdt_setprop_cell(fdt, "/soc", "#size-cells", 0x2);
175 qemu_fdt_setprop_cell(fdt, "/soc", "#address-cells", 0x2);
176
177 nodename = g_strdup_printf("/memory@%lx",
178 (long)memmap[VIRT_DRAM].base);
179 qemu_fdt_add_subnode(fdt, nodename);
180 qemu_fdt_setprop_cells(fdt, nodename, "reg",
181 memmap[VIRT_DRAM].base >> 32, memmap[VIRT_DRAM].base,
182 mem_size >> 32, mem_size);
183 qemu_fdt_setprop_string(fdt, nodename, "device_type", "memory");
184 g_free(nodename);
185
186 qemu_fdt_add_subnode(fdt, "/cpus");
2a8756ed
MC
187 qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
188 SIFIVE_CLINT_TIMEBASE_FREQ);
04331d0b
MC
189 qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
190 qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
191
192 for (cpu = s->soc.num_harts - 1; cpu >= 0; cpu--) {
193 int cpu_phandle = phandle++;
194 nodename = g_strdup_printf("/cpus/cpu@%d", cpu);
195 char *intc = g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu);
196 char *isa = riscv_isa_string(&s->soc.harts[cpu]);
197 qemu_fdt_add_subnode(fdt, nodename);
2a8756ed
MC
198 qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency",
199 VIRT_CLOCK_FREQ);
04331d0b
MC
200 qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv48");
201 qemu_fdt_setprop_string(fdt, nodename, "riscv,isa", isa);
202 qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv");
203 qemu_fdt_setprop_string(fdt, nodename, "status", "okay");
204 qemu_fdt_setprop_cell(fdt, nodename, "reg", cpu);
205 qemu_fdt_setprop_string(fdt, nodename, "device_type", "cpu");
206 qemu_fdt_add_subnode(fdt, intc);
207 qemu_fdt_setprop_cell(fdt, intc, "phandle", cpu_phandle);
208 qemu_fdt_setprop_cell(fdt, intc, "linux,phandle", cpu_phandle);
209 qemu_fdt_setprop_string(fdt, intc, "compatible", "riscv,cpu-intc");
210 qemu_fdt_setprop(fdt, intc, "interrupt-controller", NULL, 0);
211 qemu_fdt_setprop_cell(fdt, intc, "#interrupt-cells", 1);
212 g_free(isa);
213 g_free(intc);
214 g_free(nodename);
215 }
216
217 cells = g_new0(uint32_t, s->soc.num_harts * 4);
218 for (cpu = 0; cpu < s->soc.num_harts; cpu++) {
219 nodename =
220 g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu);
221 uint32_t intc_phandle = qemu_fdt_get_phandle(fdt, nodename);
222 cells[cpu * 4 + 0] = cpu_to_be32(intc_phandle);
223 cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_SOFT);
224 cells[cpu * 4 + 2] = cpu_to_be32(intc_phandle);
225 cells[cpu * 4 + 3] = cpu_to_be32(IRQ_M_TIMER);
226 g_free(nodename);
227 }
228 nodename = g_strdup_printf("/soc/clint@%lx",
229 (long)memmap[VIRT_CLINT].base);
230 qemu_fdt_add_subnode(fdt, nodename);
231 qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv,clint0");
232 qemu_fdt_setprop_cells(fdt, nodename, "reg",
233 0x0, memmap[VIRT_CLINT].base,
234 0x0, memmap[VIRT_CLINT].size);
235 qemu_fdt_setprop(fdt, nodename, "interrupts-extended",
236 cells, s->soc.num_harts * sizeof(uint32_t) * 4);
237 g_free(cells);
238 g_free(nodename);
239
240 plic_phandle = phandle++;
241 cells = g_new0(uint32_t, s->soc.num_harts * 4);
242 for (cpu = 0; cpu < s->soc.num_harts; cpu++) {
243 nodename =
244 g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu);
245 uint32_t intc_phandle = qemu_fdt_get_phandle(fdt, nodename);
246 cells[cpu * 4 + 0] = cpu_to_be32(intc_phandle);
247 cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_EXT);
248 cells[cpu * 4 + 2] = cpu_to_be32(intc_phandle);
249 cells[cpu * 4 + 3] = cpu_to_be32(IRQ_S_EXT);
250 g_free(nodename);
251 }
252 nodename = g_strdup_printf("/soc/interrupt-controller@%lx",
253 (long)memmap[VIRT_PLIC].base);
254 qemu_fdt_add_subnode(fdt, nodename);
6d56e396
AF
255 qemu_fdt_setprop_cells(fdt, nodename, "#address-cells",
256 FDT_PLIC_ADDR_CELLS);
257 qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells",
258 FDT_PLIC_INT_CELLS);
04331d0b
MC
259 qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv,plic0");
260 qemu_fdt_setprop(fdt, nodename, "interrupt-controller", NULL, 0);
261 qemu_fdt_setprop(fdt, nodename, "interrupts-extended",
262 cells, s->soc.num_harts * sizeof(uint32_t) * 4);
263 qemu_fdt_setprop_cells(fdt, nodename, "reg",
264 0x0, memmap[VIRT_PLIC].base,
265 0x0, memmap[VIRT_PLIC].size);
266 qemu_fdt_setprop_string(fdt, nodename, "reg-names", "control");
267 qemu_fdt_setprop_cell(fdt, nodename, "riscv,max-priority", 7);
268 qemu_fdt_setprop_cell(fdt, nodename, "riscv,ndev", VIRTIO_NDEV);
269 qemu_fdt_setprop_cells(fdt, nodename, "phandle", plic_phandle);
270 qemu_fdt_setprop_cells(fdt, nodename, "linux,phandle", plic_phandle);
271 plic_phandle = qemu_fdt_get_phandle(fdt, nodename);
272 g_free(cells);
273 g_free(nodename);
274
275 for (i = 0; i < VIRTIO_COUNT; i++) {
276 nodename = g_strdup_printf("/virtio_mmio@%lx",
277 (long)(memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size));
278 qemu_fdt_add_subnode(fdt, nodename);
279 qemu_fdt_setprop_string(fdt, nodename, "compatible", "virtio,mmio");
280 qemu_fdt_setprop_cells(fdt, nodename, "reg",
281 0x0, memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size,
282 0x0, memmap[VIRT_VIRTIO].size);
283 qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", plic_phandle);
284 qemu_fdt_setprop_cells(fdt, nodename, "interrupts", VIRTIO_IRQ + i);
285 g_free(nodename);
286 }
287
6d56e396
AF
288 nodename = g_strdup_printf("/soc/pci@%lx",
289 (long) memmap[VIRT_PCIE_ECAM].base);
290 qemu_fdt_add_subnode(fdt, nodename);
291 qemu_fdt_setprop_cells(fdt, nodename, "#address-cells",
292 FDT_PCI_ADDR_CELLS);
293 qemu_fdt_setprop_cells(fdt, nodename, "#interrupt-cells",
294 FDT_PCI_INT_CELLS);
295 qemu_fdt_setprop_cells(fdt, nodename, "#size-cells", 0x2);
296 qemu_fdt_setprop_string(fdt, nodename, "compatible",
297 "pci-host-ecam-generic");
298 qemu_fdt_setprop_string(fdt, nodename, "device_type", "pci");
299 qemu_fdt_setprop_cell(fdt, nodename, "linux,pci-domain", 0);
300 qemu_fdt_setprop_cells(fdt, nodename, "bus-range", 0,
301 memmap[VIRT_PCIE_ECAM].base /
302 PCIE_MMCFG_SIZE_MIN - 1);
303 qemu_fdt_setprop(fdt, nodename, "dma-coherent", NULL, 0);
304 qemu_fdt_setprop_cells(fdt, nodename, "reg", 0, memmap[VIRT_PCIE_ECAM].base,
305 0, memmap[VIRT_PCIE_ECAM].size);
306 qemu_fdt_setprop_sized_cells(fdt, nodename, "ranges",
307 1, FDT_PCI_RANGE_IOPORT, 2, 0,
308 2, memmap[VIRT_PCIE_PIO].base, 2, memmap[VIRT_PCIE_PIO].size,
309 1, FDT_PCI_RANGE_MMIO,
310 2, memmap[VIRT_PCIE_MMIO].base,
311 2, memmap[VIRT_PCIE_MMIO].base, 2, memmap[VIRT_PCIE_MMIO].size);
312 create_pcie_irq_map(fdt, nodename, plic_phandle);
313 g_free(nodename);
314
04331d0b
MC
315 nodename = g_strdup_printf("/test@%lx",
316 (long)memmap[VIRT_TEST].base);
317 qemu_fdt_add_subnode(fdt, nodename);
318 qemu_fdt_setprop_string(fdt, nodename, "compatible", "sifive,test0");
319 qemu_fdt_setprop_cells(fdt, nodename, "reg",
320 0x0, memmap[VIRT_TEST].base,
321 0x0, memmap[VIRT_TEST].size);
632fb279 322 g_free(nodename);
04331d0b
MC
323
324 nodename = g_strdup_printf("/uart@%lx",
325 (long)memmap[VIRT_UART0].base);
326 qemu_fdt_add_subnode(fdt, nodename);
327 qemu_fdt_setprop_string(fdt, nodename, "compatible", "ns16550a");
328 qemu_fdt_setprop_cells(fdt, nodename, "reg",
329 0x0, memmap[VIRT_UART0].base,
330 0x0, memmap[VIRT_UART0].size);
331 qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency", 3686400);
332 qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", plic_phandle);
333 qemu_fdt_setprop_cells(fdt, nodename, "interrupts", UART0_IRQ);
334
335 qemu_fdt_add_subnode(fdt, "/chosen");
336 qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", nodename);
7c28f4da
MC
337 if (cmdline) {
338 qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
339 }
04331d0b
MC
340 g_free(nodename);
341
342 return fdt;
343}
344
6d56e396
AF
345
346static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem,
347 hwaddr ecam_base, hwaddr ecam_size,
348 hwaddr mmio_base, hwaddr mmio_size,
349 hwaddr pio_base,
350 DeviceState *plic, bool link_up)
351{
352 DeviceState *dev;
353 MemoryRegion *ecam_alias, *ecam_reg;
354 MemoryRegion *mmio_alias, *mmio_reg;
355 qemu_irq irq;
356 int i;
357
358 dev = qdev_create(NULL, TYPE_GPEX_HOST);
359
360 qdev_init_nofail(dev);
361
362 ecam_alias = g_new0(MemoryRegion, 1);
363 ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
364 memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam",
365 ecam_reg, 0, ecam_size);
366 memory_region_add_subregion(get_system_memory(), ecam_base, ecam_alias);
367
368 mmio_alias = g_new0(MemoryRegion, 1);
369 mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
370 memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio",
371 mmio_reg, mmio_base, mmio_size);
372 memory_region_add_subregion(get_system_memory(), mmio_base, mmio_alias);
373
374 sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, pio_base);
375
376 for (i = 0; i < GPEX_NUM_IRQS; i++) {
377 irq = qdev_get_gpio_in(plic, PCIE_IRQ + i);
378
379 sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
380 gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ + i);
381 }
382
383 return dev;
384}
385
04331d0b
MC
386static void riscv_virt_board_init(MachineState *machine)
387{
388 const struct MemmapEntry *memmap = virt_memmap;
389
390 RISCVVirtState *s = g_new0(RISCVVirtState, 1);
391 MemoryRegion *system_memory = get_system_memory();
392 MemoryRegion *main_mem = g_new(MemoryRegion, 1);
5aec3247 393 MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
04331d0b
MC
394 char *plic_hart_config;
395 size_t plic_hart_config_len;
396 int i;
397 void *fdt;
398
399 /* Initialize SOC */
a993cb15
AF
400 object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc),
401 TYPE_RISCV_HART_ARRAY, &error_abort, NULL);
04331d0b
MC
402 object_property_set_str(OBJECT(&s->soc), VIRT_CPU, "cpu-type",
403 &error_abort);
404 object_property_set_int(OBJECT(&s->soc), smp_cpus, "num-harts",
405 &error_abort);
406 object_property_set_bool(OBJECT(&s->soc), true, "realized",
407 &error_abort);
408
409 /* register system main memory (actual RAM) */
410 memory_region_init_ram(main_mem, NULL, "riscv_virt_board.ram",
411 machine->ram_size, &error_fatal);
412 memory_region_add_subregion(system_memory, memmap[VIRT_DRAM].base,
413 main_mem);
414
415 /* create device tree */
416 fdt = create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline);
417
418 /* boot rom */
5aec3247
MC
419 memory_region_init_rom(mask_rom, NULL, "riscv_virt_board.mrom",
420 memmap[VIRT_MROM].size, &error_fatal);
421 memory_region_add_subregion(system_memory, memmap[VIRT_MROM].base,
422 mask_rom);
04331d0b
MC
423
424 if (machine->kernel_filename) {
425 uint64_t kernel_entry = load_kernel(machine->kernel_filename);
426
427 if (machine->initrd_filename) {
428 hwaddr start;
429 hwaddr end = load_initrd(machine->initrd_filename,
430 machine->ram_size, kernel_entry,
431 &start);
432 qemu_fdt_setprop_cell(fdt, "/chosen",
433 "linux,initrd-start", start);
434 qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
435 end);
436 }
437 }
438
439 /* reset vector */
440 uint32_t reset_vec[8] = {
441 0x00000297, /* 1: auipc t0, %pcrel_hi(dtb) */
442 0x02028593, /* addi a1, t0, %pcrel_lo(1b) */
443 0xf1402573, /* csrr a0, mhartid */
444#if defined(TARGET_RISCV32)
445 0x0182a283, /* lw t0, 24(t0) */
446#elif defined(TARGET_RISCV64)
447 0x0182b283, /* ld t0, 24(t0) */
448#endif
449 0x00028067, /* jr t0 */
450 0x00000000,
451 memmap[VIRT_DRAM].base, /* start: .dword memmap[VIRT_DRAM].base */
452 0x00000000,
453 /* dtb: */
454 };
455
5aec3247
MC
456 /* copy in the reset vector in little_endian byte order */
457 for (i = 0; i < sizeof(reset_vec) >> 2; i++) {
458 reset_vec[i] = cpu_to_le32(reset_vec[i]);
459 }
460 rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),
461 memmap[VIRT_MROM].base, &address_space_memory);
04331d0b
MC
462
463 /* copy in the device tree */
5aec3247
MC
464 if (fdt_pack(s->fdt) || fdt_totalsize(s->fdt) >
465 memmap[VIRT_MROM].size - sizeof(reset_vec)) {
466 error_report("not enough space to store device-tree");
467 exit(1);
468 }
469 qemu_fdt_dumpdtb(s->fdt, fdt_totalsize(s->fdt));
470 rom_add_blob_fixed_as("mrom.fdt", s->fdt, fdt_totalsize(s->fdt),
471 memmap[VIRT_MROM].base + sizeof(reset_vec),
472 &address_space_memory);
04331d0b
MC
473
474 /* create PLIC hart topology configuration string */
475 plic_hart_config_len = (strlen(VIRT_PLIC_HART_CONFIG) + 1) * smp_cpus;
476 plic_hart_config = g_malloc0(plic_hart_config_len);
477 for (i = 0; i < smp_cpus; i++) {
478 if (i != 0) {
479 strncat(plic_hart_config, ",", plic_hart_config_len);
480 }
481 strncat(plic_hart_config, VIRT_PLIC_HART_CONFIG, plic_hart_config_len);
482 plic_hart_config_len -= (strlen(VIRT_PLIC_HART_CONFIG) + 1);
483 }
484
485 /* MMIO */
486 s->plic = sifive_plic_create(memmap[VIRT_PLIC].base,
487 plic_hart_config,
488 VIRT_PLIC_NUM_SOURCES,
489 VIRT_PLIC_NUM_PRIORITIES,
490 VIRT_PLIC_PRIORITY_BASE,
491 VIRT_PLIC_PENDING_BASE,
492 VIRT_PLIC_ENABLE_BASE,
493 VIRT_PLIC_ENABLE_STRIDE,
494 VIRT_PLIC_CONTEXT_BASE,
495 VIRT_PLIC_CONTEXT_STRIDE,
496 memmap[VIRT_PLIC].size);
497 sifive_clint_create(memmap[VIRT_CLINT].base,
498 memmap[VIRT_CLINT].size, smp_cpus,
499 SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE);
500 sifive_test_create(memmap[VIRT_TEST].base);
501
502 for (i = 0; i < VIRTIO_COUNT; i++) {
503 sysbus_create_simple("virtio-mmio",
504 memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size,
647a70a1 505 qdev_get_gpio_in(DEVICE(s->plic), VIRTIO_IRQ + i));
04331d0b
MC
506 }
507
6d56e396
AF
508 gpex_pcie_init(system_memory,
509 memmap[VIRT_PCIE_ECAM].base,
510 memmap[VIRT_PCIE_ECAM].size,
511 memmap[VIRT_PCIE_MMIO].base,
512 memmap[VIRT_PCIE_MMIO].size,
513 memmap[VIRT_PCIE_PIO].base,
514 DEVICE(s->plic), true);
515
04331d0b 516 serial_mm_init(system_memory, memmap[VIRT_UART0].base,
647a70a1 517 0, qdev_get_gpio_in(DEVICE(s->plic), UART0_IRQ), 399193,
9bca0edb 518 serial_hd(0), DEVICE_LITTLE_ENDIAN);
b6aa6ced
MC
519
520 g_free(plic_hart_config);
04331d0b
MC
521}
522
04331d0b
MC
523static void riscv_virt_board_machine_init(MachineClass *mc)
524{
77ff5bba 525 mc->desc = "RISC-V VirtIO Board (Privileged ISA v1.10)";
04331d0b
MC
526 mc->init = riscv_virt_board_init;
527 mc->max_cpus = 8; /* hardcoded limit in BBL */
528}
529
530DEFINE_MACHINE("virt", riscv_virt_board_machine_init)