]>
Commit | Line | Data |
---|---|---|
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 | 23 | #include "qemu/error-report.h" |
e4b4f0b7 | 24 | #include "qemu/guest-random.h" |
04331d0b | 25 | #include "qapi/error.h" |
04331d0b MC |
26 | #include "hw/boards.h" |
27 | #include "hw/loader.h" | |
28 | #include "hw/sysbus.h" | |
71eb522c | 29 | #include "hw/qdev-properties.h" |
04331d0b MC |
30 | #include "hw/char/serial.h" |
31 | #include "target/riscv/cpu.h" | |
3029fab6 | 32 | #include "hw/core/sysbus-fdt.h" |
abd9a206 | 33 | #include "target/riscv/pmu.h" |
04331d0b | 34 | #include "hw/riscv/riscv_hart.h" |
04331d0b | 35 | #include "hw/riscv/virt.h" |
0ac24d56 | 36 | #include "hw/riscv/boot.h" |
18df0b46 | 37 | #include "hw/riscv/numa.h" |
cc63a182 | 38 | #include "hw/intc/riscv_aclint.h" |
e6faee65 | 39 | #include "hw/intc/riscv_aplic.h" |
28d8c281 | 40 | #include "hw/intc/riscv_imsic.h" |
84fcf3c1 | 41 | #include "hw/intc/sifive_plic.h" |
a4b84608 | 42 | #include "hw/misc/sifive_test.h" |
1832b7cb | 43 | #include "hw/platform-bus.h" |
04331d0b | 44 | #include "chardev/char.h" |
04331d0b | 45 | #include "sysemu/device_tree.h" |
46517dd4 | 46 | #include "sysemu/sysemu.h" |
ad40be27 | 47 | #include "sysemu/kvm.h" |
325b7c4e | 48 | #include "sysemu/tpm.h" |
6d56e396 AF |
49 | #include "hw/pci/pci.h" |
50 | #include "hw/pci-host/gpex.h" | |
c346749e | 51 | #include "hw/display/ramfb.h" |
90477a65 | 52 | #include "hw/acpi/aml-build.h" |
168b8c29 | 53 | #include "qapi/qapi-visit-common.h" |
04331d0b | 54 | |
0631aaae AP |
55 | /* |
56 | * The virt machine physical address space used by some of the devices | |
57 | * namely ACLINT, PLIC, APLIC, and IMSIC depend on number of Sockets, | |
58 | * number of CPUs, and number of IMSIC guest files. | |
59 | * | |
60 | * Various limits defined by VIRT_SOCKETS_MAX_BITS, VIRT_CPUS_MAX_BITS, | |
61 | * and VIRT_IRQCHIP_MAX_GUESTS_BITS are tuned for maximum utilization | |
62 | * of virt machine physical address space. | |
63 | */ | |
64 | ||
28d8c281 AP |
65 | #define VIRT_IMSIC_GROUP_MAX_SIZE (1U << IMSIC_MMIO_GROUP_MIN_SHIFT) |
66 | #if VIRT_IMSIC_GROUP_MAX_SIZE < \ | |
67 | IMSIC_GROUP_SIZE(VIRT_CPUS_MAX_BITS, VIRT_IRQCHIP_MAX_GUESTS_BITS) | |
68 | #error "Can't accomodate single IMSIC group in address space" | |
69 | #endif | |
70 | ||
71 | #define VIRT_IMSIC_MAX_SIZE (VIRT_SOCKETS_MAX * \ | |
72 | VIRT_IMSIC_GROUP_MAX_SIZE) | |
73 | #if 0x4000000 < VIRT_IMSIC_MAX_SIZE | |
74 | #error "Can't accomodate all IMSIC groups in address space" | |
75 | #endif | |
76 | ||
73261285 | 77 | static const MemMapEntry virt_memmap[] = { |
1832b7cb AF |
78 | [VIRT_DEBUG] = { 0x0, 0x100 }, |
79 | [VIRT_MROM] = { 0x1000, 0xf000 }, | |
80 | [VIRT_TEST] = { 0x100000, 0x1000 }, | |
81 | [VIRT_RTC] = { 0x101000, 0x1000 }, | |
82 | [VIRT_CLINT] = { 0x2000000, 0x10000 }, | |
83 | [VIRT_ACLINT_SSWI] = { 0x2F00000, 0x4000 }, | |
84 | [VIRT_PCIE_PIO] = { 0x3000000, 0x10000 }, | |
85 | [VIRT_PLATFORM_BUS] = { 0x4000000, 0x2000000 }, | |
86 | [VIRT_PLIC] = { 0xc000000, VIRT_PLIC_SIZE(VIRT_CPUS_MAX * 2) }, | |
87 | [VIRT_APLIC_M] = { 0xc000000, APLIC_SIZE(VIRT_CPUS_MAX) }, | |
88 | [VIRT_APLIC_S] = { 0xd000000, APLIC_SIZE(VIRT_CPUS_MAX) }, | |
89 | [VIRT_UART0] = { 0x10000000, 0x100 }, | |
90 | [VIRT_VIRTIO] = { 0x10001000, 0x1000 }, | |
91 | [VIRT_FW_CFG] = { 0x10100000, 0x18 }, | |
92 | [VIRT_FLASH] = { 0x20000000, 0x4000000 }, | |
93 | [VIRT_IMSIC_M] = { 0x24000000, VIRT_IMSIC_MAX_SIZE }, | |
94 | [VIRT_IMSIC_S] = { 0x28000000, VIRT_IMSIC_MAX_SIZE }, | |
95 | [VIRT_PCIE_ECAM] = { 0x30000000, 0x10000000 }, | |
96 | [VIRT_PCIE_MMIO] = { 0x40000000, 0x40000000 }, | |
97 | [VIRT_DRAM] = { 0x80000000, 0x0 }, | |
04331d0b MC |
98 | }; |
99 | ||
19800265 BM |
100 | /* PCIe high mmio is fixed for RV32 */ |
101 | #define VIRT32_HIGH_PCIE_MMIO_BASE 0x300000000ULL | |
102 | #define VIRT32_HIGH_PCIE_MMIO_SIZE (4 * GiB) | |
103 | ||
104 | /* PCIe high mmio for RV64, size is fixed but base depends on top of RAM */ | |
105 | #define VIRT64_HIGH_PCIE_MMIO_SIZE (16 * GiB) | |
106 | ||
107 | static MemMapEntry virt_high_pcie_memmap; | |
108 | ||
71eb522c AF |
109 | #define VIRT_FLASH_SECTOR_SIZE (256 * KiB) |
110 | ||
111 | static PFlashCFI01 *virt_flash_create1(RISCVVirtState *s, | |
112 | const char *name, | |
113 | const char *alias_prop_name) | |
114 | { | |
115 | /* | |
116 | * Create a single flash device. We use the same parameters as | |
117 | * the flash devices on the ARM virt board. | |
118 | */ | |
df707969 | 119 | DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01); |
71eb522c AF |
120 | |
121 | qdev_prop_set_uint64(dev, "sector-length", VIRT_FLASH_SECTOR_SIZE); | |
122 | qdev_prop_set_uint8(dev, "width", 4); | |
123 | qdev_prop_set_uint8(dev, "device-width", 2); | |
124 | qdev_prop_set_bit(dev, "big-endian", false); | |
125 | qdev_prop_set_uint16(dev, "id0", 0x89); | |
126 | qdev_prop_set_uint16(dev, "id1", 0x18); | |
127 | qdev_prop_set_uint16(dev, "id2", 0x00); | |
128 | qdev_prop_set_uint16(dev, "id3", 0x00); | |
129 | qdev_prop_set_string(dev, "name", name); | |
130 | ||
d2623129 | 131 | object_property_add_child(OBJECT(s), name, OBJECT(dev)); |
71eb522c | 132 | object_property_add_alias(OBJECT(s), alias_prop_name, |
d2623129 | 133 | OBJECT(dev), "drive"); |
71eb522c AF |
134 | |
135 | return PFLASH_CFI01(dev); | |
136 | } | |
137 | ||
138 | static void virt_flash_create(RISCVVirtState *s) | |
139 | { | |
140 | s->flash[0] = virt_flash_create1(s, "virt.flash0", "pflash0"); | |
141 | s->flash[1] = virt_flash_create1(s, "virt.flash1", "pflash1"); | |
142 | } | |
143 | ||
144 | static void virt_flash_map1(PFlashCFI01 *flash, | |
145 | hwaddr base, hwaddr size, | |
146 | MemoryRegion *sysmem) | |
147 | { | |
148 | DeviceState *dev = DEVICE(flash); | |
149 | ||
4cdd0a77 | 150 | assert(QEMU_IS_ALIGNED(size, VIRT_FLASH_SECTOR_SIZE)); |
71eb522c AF |
151 | assert(size / VIRT_FLASH_SECTOR_SIZE <= UINT32_MAX); |
152 | qdev_prop_set_uint32(dev, "num-blocks", size / VIRT_FLASH_SECTOR_SIZE); | |
3c6ef471 | 153 | sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); |
71eb522c AF |
154 | |
155 | memory_region_add_subregion(sysmem, base, | |
156 | sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), | |
157 | 0)); | |
158 | } | |
159 | ||
160 | static void virt_flash_map(RISCVVirtState *s, | |
161 | MemoryRegion *sysmem) | |
162 | { | |
163 | hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2; | |
164 | hwaddr flashbase = virt_memmap[VIRT_FLASH].base; | |
165 | ||
166 | virt_flash_map1(s->flash[0], flashbase, flashsize, | |
167 | sysmem); | |
168 | virt_flash_map1(s->flash[1], flashbase + flashsize, flashsize, | |
169 | sysmem); | |
170 | } | |
171 | ||
e6faee65 AP |
172 | static void create_pcie_irq_map(RISCVVirtState *s, void *fdt, char *nodename, |
173 | uint32_t irqchip_phandle) | |
6d56e396 AF |
174 | { |
175 | int pin, dev; | |
e6faee65 AP |
176 | uint32_t irq_map_stride = 0; |
177 | uint32_t full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS * | |
178 | FDT_MAX_INT_MAP_WIDTH] = {}; | |
6d56e396 AF |
179 | uint32_t *irq_map = full_irq_map; |
180 | ||
181 | /* This code creates a standard swizzle of interrupts such that | |
182 | * each device's first interrupt is based on it's PCI_SLOT number. | |
183 | * (See pci_swizzle_map_irq_fn()) | |
184 | * | |
185 | * We only need one entry per interrupt in the table (not one per | |
186 | * possible slot) seeing the interrupt-map-mask will allow the table | |
187 | * to wrap to any number of devices. | |
188 | */ | |
189 | for (dev = 0; dev < GPEX_NUM_IRQS; dev++) { | |
190 | int devfn = dev * 0x8; | |
191 | ||
192 | for (pin = 0; pin < GPEX_NUM_IRQS; pin++) { | |
193 | int irq_nr = PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS); | |
194 | int i = 0; | |
195 | ||
e6faee65 | 196 | /* Fill PCI address cells */ |
6d56e396 | 197 | irq_map[i] = cpu_to_be32(devfn << 8); |
6d56e396 | 198 | i += FDT_PCI_ADDR_CELLS; |
6d56e396 | 199 | |
e6faee65 AP |
200 | /* Fill PCI Interrupt cells */ |
201 | irq_map[i] = cpu_to_be32(pin + 1); | |
6d56e396 | 202 | i += FDT_PCI_INT_CELLS; |
6d56e396 | 203 | |
e6faee65 AP |
204 | /* Fill interrupt controller phandle and cells */ |
205 | irq_map[i++] = cpu_to_be32(irqchip_phandle); | |
206 | irq_map[i++] = cpu_to_be32(irq_nr); | |
207 | if (s->aia_type != VIRT_AIA_TYPE_NONE) { | |
208 | irq_map[i++] = cpu_to_be32(0x4); | |
209 | } | |
6d56e396 | 210 | |
e6faee65 AP |
211 | if (!irq_map_stride) { |
212 | irq_map_stride = i; | |
213 | } | |
214 | irq_map += irq_map_stride; | |
6d56e396 AF |
215 | } |
216 | } | |
217 | ||
e6faee65 AP |
218 | qemu_fdt_setprop(fdt, nodename, "interrupt-map", full_irq_map, |
219 | GPEX_NUM_IRQS * GPEX_NUM_IRQS * | |
220 | irq_map_stride * sizeof(uint32_t)); | |
6d56e396 AF |
221 | |
222 | qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask", | |
223 | 0x1800, 0, 0, 0x7); | |
224 | } | |
225 | ||
0ffc1a95 AP |
226 | static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, |
227 | char *clust_name, uint32_t *phandle, | |
914c97f9 | 228 | uint32_t *intc_phandles) |
04331d0b | 229 | { |
0ffc1a95 AP |
230 | int cpu; |
231 | uint32_t cpu_phandle; | |
568e0614 | 232 | MachineState *ms = MACHINE(s); |
ed9eb206 | 233 | char *name, *cpu_name, *core_name, *intc_name, *sv_name; |
914c97f9 | 234 | bool is_32_bit = riscv_is_32bit(&s->soc[0]); |
ed9eb206 | 235 | uint8_t satp_mode_max; |
0ffc1a95 AP |
236 | |
237 | for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) { | |
c95c9d20 DHB |
238 | RISCVCPU *cpu_ptr = &s->soc[socket].harts[cpu]; |
239 | ||
0ffc1a95 AP |
240 | cpu_phandle = (*phandle)++; |
241 | ||
242 | cpu_name = g_strdup_printf("/cpus/cpu@%d", | |
243 | s->soc[socket].hartid_base + cpu); | |
568e0614 | 244 | qemu_fdt_add_subnode(ms->fdt, cpu_name); |
ed9eb206 AG |
245 | |
246 | satp_mode_max = satp_mode_max_from_map( | |
247 | s->soc[socket].harts[cpu].cfg.satp_mode.map); | |
248 | sv_name = g_strdup_printf("riscv,%s", | |
249 | satp_mode_str(satp_mode_max, is_32_bit)); | |
250 | qemu_fdt_setprop_string(ms->fdt, cpu_name, "mmu-type", sv_name); | |
251 | g_free(sv_name); | |
252 | ||
253 | ||
c95c9d20 | 254 | name = riscv_isa_string(cpu_ptr); |
568e0614 | 255 | qemu_fdt_setprop_string(ms->fdt, cpu_name, "riscv,isa", name); |
0ffc1a95 | 256 | g_free(name); |
00769863 AP |
257 | |
258 | if (cpu_ptr->cfg.ext_icbom) { | |
259 | qemu_fdt_setprop_cell(ms->fdt, cpu_name, "riscv,cbom-block-size", | |
260 | cpu_ptr->cfg.cbom_blocksize); | |
261 | } | |
262 | ||
263 | if (cpu_ptr->cfg.ext_icboz) { | |
264 | qemu_fdt_setprop_cell(ms->fdt, cpu_name, "riscv,cboz-block-size", | |
265 | cpu_ptr->cfg.cboz_blocksize); | |
266 | } | |
267 | ||
568e0614 DHB |
268 | qemu_fdt_setprop_string(ms->fdt, cpu_name, "compatible", "riscv"); |
269 | qemu_fdt_setprop_string(ms->fdt, cpu_name, "status", "okay"); | |
270 | qemu_fdt_setprop_cell(ms->fdt, cpu_name, "reg", | |
0ffc1a95 | 271 | s->soc[socket].hartid_base + cpu); |
568e0614 DHB |
272 | qemu_fdt_setprop_string(ms->fdt, cpu_name, "device_type", "cpu"); |
273 | riscv_socket_fdt_write_id(ms, cpu_name, socket); | |
274 | qemu_fdt_setprop_cell(ms->fdt, cpu_name, "phandle", cpu_phandle); | |
0ffc1a95 AP |
275 | |
276 | intc_phandles[cpu] = (*phandle)++; | |
277 | ||
278 | intc_name = g_strdup_printf("%s/interrupt-controller", cpu_name); | |
568e0614 DHB |
279 | qemu_fdt_add_subnode(ms->fdt, intc_name); |
280 | qemu_fdt_setprop_cell(ms->fdt, intc_name, "phandle", | |
0ffc1a95 | 281 | intc_phandles[cpu]); |
568e0614 | 282 | qemu_fdt_setprop_string(ms->fdt, intc_name, "compatible", |
dc9acc9c | 283 | "riscv,cpu-intc"); |
568e0614 DHB |
284 | qemu_fdt_setprop(ms->fdt, intc_name, "interrupt-controller", NULL, 0); |
285 | qemu_fdt_setprop_cell(ms->fdt, intc_name, "#interrupt-cells", 1); | |
0ffc1a95 AP |
286 | |
287 | core_name = g_strdup_printf("%s/core%d", clust_name, cpu); | |
568e0614 DHB |
288 | qemu_fdt_add_subnode(ms->fdt, core_name); |
289 | qemu_fdt_setprop_cell(ms->fdt, core_name, "cpu", cpu_phandle); | |
0ffc1a95 AP |
290 | |
291 | g_free(core_name); | |
292 | g_free(intc_name); | |
293 | g_free(cpu_name); | |
294 | } | |
295 | } | |
296 | ||
297 | static void create_fdt_socket_memory(RISCVVirtState *s, | |
298 | const MemMapEntry *memmap, int socket) | |
299 | { | |
300 | char *mem_name; | |
18df0b46 | 301 | uint64_t addr, size; |
568e0614 | 302 | MachineState *ms = MACHINE(s); |
0ffc1a95 | 303 | |
568e0614 DHB |
304 | addr = memmap[VIRT_DRAM].base + riscv_socket_mem_offset(ms, socket); |
305 | size = riscv_socket_mem_size(ms, socket); | |
0ffc1a95 | 306 | mem_name = g_strdup_printf("/memory@%lx", (long)addr); |
568e0614 DHB |
307 | qemu_fdt_add_subnode(ms->fdt, mem_name); |
308 | qemu_fdt_setprop_cells(ms->fdt, mem_name, "reg", | |
0ffc1a95 | 309 | addr >> 32, addr, size >> 32, size); |
568e0614 DHB |
310 | qemu_fdt_setprop_string(ms->fdt, mem_name, "device_type", "memory"); |
311 | riscv_socket_fdt_write_id(ms, mem_name, socket); | |
0ffc1a95 AP |
312 | g_free(mem_name); |
313 | } | |
314 | ||
315 | static void create_fdt_socket_clint(RISCVVirtState *s, | |
316 | const MemMapEntry *memmap, int socket, | |
317 | uint32_t *intc_phandles) | |
318 | { | |
319 | int cpu; | |
320 | char *clint_name; | |
321 | uint32_t *clint_cells; | |
322 | unsigned long clint_addr; | |
568e0614 | 323 | MachineState *ms = MACHINE(s); |
7cfbb17f BM |
324 | static const char * const clint_compat[2] = { |
325 | "sifive,clint0", "riscv,clint0" | |
326 | }; | |
0ffc1a95 AP |
327 | |
328 | clint_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4); | |
329 | ||
330 | for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) { | |
331 | clint_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]); | |
332 | clint_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_SOFT); | |
333 | clint_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]); | |
334 | clint_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_M_TIMER); | |
335 | } | |
336 | ||
337 | clint_addr = memmap[VIRT_CLINT].base + (memmap[VIRT_CLINT].size * socket); | |
338 | clint_name = g_strdup_printf("/soc/clint@%lx", clint_addr); | |
568e0614 DHB |
339 | qemu_fdt_add_subnode(ms->fdt, clint_name); |
340 | qemu_fdt_setprop_string_array(ms->fdt, clint_name, "compatible", | |
0ffc1a95 AP |
341 | (char **)&clint_compat, |
342 | ARRAY_SIZE(clint_compat)); | |
568e0614 | 343 | qemu_fdt_setprop_cells(ms->fdt, clint_name, "reg", |
0ffc1a95 | 344 | 0x0, clint_addr, 0x0, memmap[VIRT_CLINT].size); |
568e0614 | 345 | qemu_fdt_setprop(ms->fdt, clint_name, "interrupts-extended", |
0ffc1a95 | 346 | clint_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4); |
568e0614 | 347 | riscv_socket_fdt_write_id(ms, clint_name, socket); |
0ffc1a95 AP |
348 | g_free(clint_name); |
349 | ||
350 | g_free(clint_cells); | |
351 | } | |
352 | ||
954886ea AP |
353 | static void create_fdt_socket_aclint(RISCVVirtState *s, |
354 | const MemMapEntry *memmap, int socket, | |
355 | uint32_t *intc_phandles) | |
356 | { | |
357 | int cpu; | |
358 | char *name; | |
28d8c281 | 359 | unsigned long addr, size; |
954886ea AP |
360 | uint32_t aclint_cells_size; |
361 | uint32_t *aclint_mswi_cells; | |
362 | uint32_t *aclint_sswi_cells; | |
363 | uint32_t *aclint_mtimer_cells; | |
568e0614 | 364 | MachineState *ms = MACHINE(s); |
954886ea AP |
365 | |
366 | aclint_mswi_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2); | |
367 | aclint_mtimer_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2); | |
368 | aclint_sswi_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2); | |
369 | ||
370 | for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) { | |
371 | aclint_mswi_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]); | |
372 | aclint_mswi_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_M_SOFT); | |
373 | aclint_mtimer_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]); | |
374 | aclint_mtimer_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_M_TIMER); | |
375 | aclint_sswi_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]); | |
376 | aclint_sswi_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_S_SOFT); | |
377 | } | |
378 | aclint_cells_size = s->soc[socket].num_harts * sizeof(uint32_t) * 2; | |
379 | ||
28d8c281 AP |
380 | if (s->aia_type != VIRT_AIA_TYPE_APLIC_IMSIC) { |
381 | addr = memmap[VIRT_CLINT].base + (memmap[VIRT_CLINT].size * socket); | |
382 | name = g_strdup_printf("/soc/mswi@%lx", addr); | |
568e0614 DHB |
383 | qemu_fdt_add_subnode(ms->fdt, name); |
384 | qemu_fdt_setprop_string(ms->fdt, name, "compatible", | |
28d8c281 | 385 | "riscv,aclint-mswi"); |
568e0614 | 386 | qemu_fdt_setprop_cells(ms->fdt, name, "reg", |
28d8c281 | 387 | 0x0, addr, 0x0, RISCV_ACLINT_SWI_SIZE); |
568e0614 | 388 | qemu_fdt_setprop(ms->fdt, name, "interrupts-extended", |
28d8c281 | 389 | aclint_mswi_cells, aclint_cells_size); |
568e0614 DHB |
390 | qemu_fdt_setprop(ms->fdt, name, "interrupt-controller", NULL, 0); |
391 | qemu_fdt_setprop_cell(ms->fdt, name, "#interrupt-cells", 0); | |
392 | riscv_socket_fdt_write_id(ms, name, socket); | |
28d8c281 AP |
393 | g_free(name); |
394 | } | |
954886ea | 395 | |
28d8c281 AP |
396 | if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) { |
397 | addr = memmap[VIRT_CLINT].base + | |
398 | (RISCV_ACLINT_DEFAULT_MTIMER_SIZE * socket); | |
399 | size = RISCV_ACLINT_DEFAULT_MTIMER_SIZE; | |
400 | } else { | |
401 | addr = memmap[VIRT_CLINT].base + RISCV_ACLINT_SWI_SIZE + | |
402 | (memmap[VIRT_CLINT].size * socket); | |
403 | size = memmap[VIRT_CLINT].size - RISCV_ACLINT_SWI_SIZE; | |
404 | } | |
954886ea | 405 | name = g_strdup_printf("/soc/mtimer@%lx", addr); |
568e0614 DHB |
406 | qemu_fdt_add_subnode(ms->fdt, name); |
407 | qemu_fdt_setprop_string(ms->fdt, name, "compatible", | |
954886ea | 408 | "riscv,aclint-mtimer"); |
568e0614 | 409 | qemu_fdt_setprop_cells(ms->fdt, name, "reg", |
954886ea | 410 | 0x0, addr + RISCV_ACLINT_DEFAULT_MTIME, |
28d8c281 | 411 | 0x0, size - RISCV_ACLINT_DEFAULT_MTIME, |
954886ea AP |
412 | 0x0, addr + RISCV_ACLINT_DEFAULT_MTIMECMP, |
413 | 0x0, RISCV_ACLINT_DEFAULT_MTIME); | |
568e0614 | 414 | qemu_fdt_setprop(ms->fdt, name, "interrupts-extended", |
954886ea | 415 | aclint_mtimer_cells, aclint_cells_size); |
568e0614 | 416 | riscv_socket_fdt_write_id(ms, name, socket); |
954886ea AP |
417 | g_free(name); |
418 | ||
28d8c281 AP |
419 | if (s->aia_type != VIRT_AIA_TYPE_APLIC_IMSIC) { |
420 | addr = memmap[VIRT_ACLINT_SSWI].base + | |
421 | (memmap[VIRT_ACLINT_SSWI].size * socket); | |
422 | name = g_strdup_printf("/soc/sswi@%lx", addr); | |
568e0614 DHB |
423 | qemu_fdt_add_subnode(ms->fdt, name); |
424 | qemu_fdt_setprop_string(ms->fdt, name, "compatible", | |
28d8c281 | 425 | "riscv,aclint-sswi"); |
568e0614 | 426 | qemu_fdt_setprop_cells(ms->fdt, name, "reg", |
28d8c281 | 427 | 0x0, addr, 0x0, memmap[VIRT_ACLINT_SSWI].size); |
568e0614 | 428 | qemu_fdt_setprop(ms->fdt, name, "interrupts-extended", |
28d8c281 | 429 | aclint_sswi_cells, aclint_cells_size); |
568e0614 DHB |
430 | qemu_fdt_setprop(ms->fdt, name, "interrupt-controller", NULL, 0); |
431 | qemu_fdt_setprop_cell(ms->fdt, name, "#interrupt-cells", 0); | |
432 | riscv_socket_fdt_write_id(ms, name, socket); | |
28d8c281 AP |
433 | g_free(name); |
434 | } | |
954886ea AP |
435 | |
436 | g_free(aclint_mswi_cells); | |
437 | g_free(aclint_mtimer_cells); | |
438 | g_free(aclint_sswi_cells); | |
439 | } | |
440 | ||
0ffc1a95 AP |
441 | static void create_fdt_socket_plic(RISCVVirtState *s, |
442 | const MemMapEntry *memmap, int socket, | |
443 | uint32_t *phandle, uint32_t *intc_phandles, | |
444 | uint32_t *plic_phandles) | |
445 | { | |
446 | int cpu; | |
447 | char *plic_name; | |
448 | uint32_t *plic_cells; | |
449 | unsigned long plic_addr; | |
568e0614 | 450 | MachineState *ms = MACHINE(s); |
60bb5407 BM |
451 | static const char * const plic_compat[2] = { |
452 | "sifive,plic-1.0.0", "riscv,plic0" | |
453 | }; | |
04331d0b | 454 | |
ad40be27 YJ |
455 | if (kvm_enabled()) { |
456 | plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2); | |
457 | } else { | |
458 | plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4); | |
459 | } | |
0ffc1a95 AP |
460 | |
461 | for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) { | |
ad40be27 YJ |
462 | if (kvm_enabled()) { |
463 | plic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]); | |
464 | plic_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_S_EXT); | |
465 | } else { | |
466 | plic_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]); | |
467 | plic_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_EXT); | |
468 | plic_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]); | |
469 | plic_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_S_EXT); | |
470 | } | |
04331d0b MC |
471 | } |
472 | ||
0ffc1a95 AP |
473 | plic_phandles[socket] = (*phandle)++; |
474 | plic_addr = memmap[VIRT_PLIC].base + (memmap[VIRT_PLIC].size * socket); | |
475 | plic_name = g_strdup_printf("/soc/plic@%lx", plic_addr); | |
568e0614 DHB |
476 | qemu_fdt_add_subnode(ms->fdt, plic_name); |
477 | qemu_fdt_setprop_cell(ms->fdt, plic_name, | |
0ffc1a95 | 478 | "#interrupt-cells", FDT_PLIC_INT_CELLS); |
568e0614 | 479 | qemu_fdt_setprop_cell(ms->fdt, plic_name, |
95e401d3 | 480 | "#address-cells", FDT_PLIC_ADDR_CELLS); |
568e0614 | 481 | qemu_fdt_setprop_string_array(ms->fdt, plic_name, "compatible", |
0ffc1a95 AP |
482 | (char **)&plic_compat, |
483 | ARRAY_SIZE(plic_compat)); | |
568e0614 DHB |
484 | qemu_fdt_setprop(ms->fdt, plic_name, "interrupt-controller", NULL, 0); |
485 | qemu_fdt_setprop(ms->fdt, plic_name, "interrupts-extended", | |
0ffc1a95 | 486 | plic_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4); |
568e0614 | 487 | qemu_fdt_setprop_cells(ms->fdt, plic_name, "reg", |
0ffc1a95 | 488 | 0x0, plic_addr, 0x0, memmap[VIRT_PLIC].size); |
568e0614 | 489 | qemu_fdt_setprop_cell(ms->fdt, plic_name, "riscv,ndev", |
59f74489 | 490 | VIRT_IRQCHIP_NUM_SOURCES - 1); |
568e0614 DHB |
491 | riscv_socket_fdt_write_id(ms, plic_name, socket); |
492 | qemu_fdt_setprop_cell(ms->fdt, plic_name, "phandle", | |
0ffc1a95 | 493 | plic_phandles[socket]); |
3029fab6 | 494 | |
d644e5e4 | 495 | if (!socket) { |
568e0614 | 496 | platform_bus_add_all_fdt_nodes(ms->fdt, plic_name, |
d644e5e4 AP |
497 | memmap[VIRT_PLATFORM_BUS].base, |
498 | memmap[VIRT_PLATFORM_BUS].size, | |
499 | VIRT_PLATFORM_BUS_IRQ); | |
500 | } | |
3029fab6 | 501 | |
0ffc1a95 AP |
502 | g_free(plic_name); |
503 | ||
504 | g_free(plic_cells); | |
505 | } | |
04331d0b | 506 | |
28d8c281 AP |
507 | static uint32_t imsic_num_bits(uint32_t count) |
508 | { | |
509 | uint32_t ret = 0; | |
510 | ||
511 | while (BIT(ret) < count) { | |
512 | ret++; | |
513 | } | |
514 | ||
515 | return ret; | |
516 | } | |
517 | ||
518 | static void create_fdt_imsic(RISCVVirtState *s, const MemMapEntry *memmap, | |
519 | uint32_t *phandle, uint32_t *intc_phandles, | |
520 | uint32_t *msi_m_phandle, uint32_t *msi_s_phandle) | |
521 | { | |
522 | int cpu, socket; | |
523 | char *imsic_name; | |
568e0614 DHB |
524 | MachineState *ms = MACHINE(s); |
525 | int socket_count = riscv_socket_count(ms); | |
28d8c281 AP |
526 | uint32_t imsic_max_hart_per_socket, imsic_guest_bits; |
527 | uint32_t *imsic_cells, *imsic_regs, imsic_addr, imsic_size; | |
528 | ||
529 | *msi_m_phandle = (*phandle)++; | |
530 | *msi_s_phandle = (*phandle)++; | |
568e0614 | 531 | imsic_cells = g_new0(uint32_t, ms->smp.cpus * 2); |
2967f37d | 532 | imsic_regs = g_new0(uint32_t, socket_count * 4); |
28d8c281 AP |
533 | |
534 | /* M-level IMSIC node */ | |
568e0614 | 535 | for (cpu = 0; cpu < ms->smp.cpus; cpu++) { |
28d8c281 AP |
536 | imsic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]); |
537 | imsic_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_M_EXT); | |
538 | } | |
539 | imsic_max_hart_per_socket = 0; | |
2967f37d | 540 | for (socket = 0; socket < socket_count; socket++) { |
28d8c281 AP |
541 | imsic_addr = memmap[VIRT_IMSIC_M].base + |
542 | socket * VIRT_IMSIC_GROUP_MAX_SIZE; | |
543 | imsic_size = IMSIC_HART_SIZE(0) * s->soc[socket].num_harts; | |
544 | imsic_regs[socket * 4 + 0] = 0; | |
545 | imsic_regs[socket * 4 + 1] = cpu_to_be32(imsic_addr); | |
546 | imsic_regs[socket * 4 + 2] = 0; | |
547 | imsic_regs[socket * 4 + 3] = cpu_to_be32(imsic_size); | |
548 | if (imsic_max_hart_per_socket < s->soc[socket].num_harts) { | |
549 | imsic_max_hart_per_socket = s->soc[socket].num_harts; | |
550 | } | |
551 | } | |
552 | imsic_name = g_strdup_printf("/soc/imsics@%lx", | |
553 | (unsigned long)memmap[VIRT_IMSIC_M].base); | |
568e0614 DHB |
554 | qemu_fdt_add_subnode(ms->fdt, imsic_name); |
555 | qemu_fdt_setprop_string(ms->fdt, imsic_name, "compatible", | |
28d8c281 | 556 | "riscv,imsics"); |
568e0614 | 557 | qemu_fdt_setprop_cell(ms->fdt, imsic_name, "#interrupt-cells", |
28d8c281 | 558 | FDT_IMSIC_INT_CELLS); |
568e0614 | 559 | qemu_fdt_setprop(ms->fdt, imsic_name, "interrupt-controller", |
28d8c281 | 560 | NULL, 0); |
568e0614 | 561 | qemu_fdt_setprop(ms->fdt, imsic_name, "msi-controller", |
28d8c281 | 562 | NULL, 0); |
568e0614 DHB |
563 | qemu_fdt_setprop(ms->fdt, imsic_name, "interrupts-extended", |
564 | imsic_cells, ms->smp.cpus * sizeof(uint32_t) * 2); | |
565 | qemu_fdt_setprop(ms->fdt, imsic_name, "reg", imsic_regs, | |
2967f37d | 566 | socket_count * sizeof(uint32_t) * 4); |
568e0614 | 567 | qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,num-ids", |
28d8c281 | 568 | VIRT_IRQCHIP_NUM_MSIS); |
2967f37d | 569 | if (socket_count > 1) { |
568e0614 | 570 | qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,hart-index-bits", |
28d8c281 | 571 | imsic_num_bits(imsic_max_hart_per_socket)); |
568e0614 | 572 | qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,group-index-bits", |
2967f37d | 573 | imsic_num_bits(socket_count)); |
568e0614 | 574 | qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,group-index-shift", |
28d8c281 AP |
575 | IMSIC_MMIO_GROUP_MIN_SHIFT); |
576 | } | |
568e0614 | 577 | qemu_fdt_setprop_cell(ms->fdt, imsic_name, "phandle", *msi_m_phandle); |
3029fab6 | 578 | |
28d8c281 AP |
579 | g_free(imsic_name); |
580 | ||
581 | /* S-level IMSIC node */ | |
568e0614 | 582 | for (cpu = 0; cpu < ms->smp.cpus; cpu++) { |
28d8c281 AP |
583 | imsic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]); |
584 | imsic_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_S_EXT); | |
585 | } | |
586 | imsic_guest_bits = imsic_num_bits(s->aia_guests + 1); | |
587 | imsic_max_hart_per_socket = 0; | |
2967f37d | 588 | for (socket = 0; socket < socket_count; socket++) { |
28d8c281 AP |
589 | imsic_addr = memmap[VIRT_IMSIC_S].base + |
590 | socket * VIRT_IMSIC_GROUP_MAX_SIZE; | |
591 | imsic_size = IMSIC_HART_SIZE(imsic_guest_bits) * | |
592 | s->soc[socket].num_harts; | |
593 | imsic_regs[socket * 4 + 0] = 0; | |
594 | imsic_regs[socket * 4 + 1] = cpu_to_be32(imsic_addr); | |
595 | imsic_regs[socket * 4 + 2] = 0; | |
596 | imsic_regs[socket * 4 + 3] = cpu_to_be32(imsic_size); | |
597 | if (imsic_max_hart_per_socket < s->soc[socket].num_harts) { | |
598 | imsic_max_hart_per_socket = s->soc[socket].num_harts; | |
599 | } | |
600 | } | |
601 | imsic_name = g_strdup_printf("/soc/imsics@%lx", | |
602 | (unsigned long)memmap[VIRT_IMSIC_S].base); | |
568e0614 DHB |
603 | qemu_fdt_add_subnode(ms->fdt, imsic_name); |
604 | qemu_fdt_setprop_string(ms->fdt, imsic_name, "compatible", | |
28d8c281 | 605 | "riscv,imsics"); |
568e0614 | 606 | qemu_fdt_setprop_cell(ms->fdt, imsic_name, "#interrupt-cells", |
28d8c281 | 607 | FDT_IMSIC_INT_CELLS); |
568e0614 | 608 | qemu_fdt_setprop(ms->fdt, imsic_name, "interrupt-controller", |
28d8c281 | 609 | NULL, 0); |
568e0614 | 610 | qemu_fdt_setprop(ms->fdt, imsic_name, "msi-controller", |
28d8c281 | 611 | NULL, 0); |
568e0614 DHB |
612 | qemu_fdt_setprop(ms->fdt, imsic_name, "interrupts-extended", |
613 | imsic_cells, ms->smp.cpus * sizeof(uint32_t) * 2); | |
614 | qemu_fdt_setprop(ms->fdt, imsic_name, "reg", imsic_regs, | |
2967f37d | 615 | socket_count * sizeof(uint32_t) * 4); |
568e0614 | 616 | qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,num-ids", |
28d8c281 | 617 | VIRT_IRQCHIP_NUM_MSIS); |
28d8c281 | 618 | if (imsic_guest_bits) { |
568e0614 | 619 | qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,guest-index-bits", |
28d8c281 AP |
620 | imsic_guest_bits); |
621 | } | |
2967f37d | 622 | if (socket_count > 1) { |
568e0614 | 623 | qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,hart-index-bits", |
28d8c281 | 624 | imsic_num_bits(imsic_max_hart_per_socket)); |
568e0614 | 625 | qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,group-index-bits", |
2967f37d | 626 | imsic_num_bits(socket_count)); |
568e0614 | 627 | qemu_fdt_setprop_cell(ms->fdt, imsic_name, "riscv,group-index-shift", |
28d8c281 AP |
628 | IMSIC_MMIO_GROUP_MIN_SHIFT); |
629 | } | |
568e0614 | 630 | qemu_fdt_setprop_cell(ms->fdt, imsic_name, "phandle", *msi_s_phandle); |
28d8c281 AP |
631 | g_free(imsic_name); |
632 | ||
633 | g_free(imsic_regs); | |
634 | g_free(imsic_cells); | |
635 | } | |
636 | ||
637 | static void create_fdt_socket_aplic(RISCVVirtState *s, | |
638 | const MemMapEntry *memmap, int socket, | |
639 | uint32_t msi_m_phandle, | |
640 | uint32_t msi_s_phandle, | |
641 | uint32_t *phandle, | |
642 | uint32_t *intc_phandles, | |
643 | uint32_t *aplic_phandles) | |
e6faee65 AP |
644 | { |
645 | int cpu; | |
646 | char *aplic_name; | |
647 | uint32_t *aplic_cells; | |
648 | unsigned long aplic_addr; | |
568e0614 | 649 | MachineState *ms = MACHINE(s); |
e6faee65 AP |
650 | uint32_t aplic_m_phandle, aplic_s_phandle; |
651 | ||
652 | aplic_m_phandle = (*phandle)++; | |
653 | aplic_s_phandle = (*phandle)++; | |
654 | aplic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2); | |
655 | ||
656 | /* M-level APLIC node */ | |
657 | for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) { | |
658 | aplic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]); | |
659 | aplic_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_M_EXT); | |
660 | } | |
661 | aplic_addr = memmap[VIRT_APLIC_M].base + | |
662 | (memmap[VIRT_APLIC_M].size * socket); | |
663 | aplic_name = g_strdup_printf("/soc/aplic@%lx", aplic_addr); | |
568e0614 DHB |
664 | qemu_fdt_add_subnode(ms->fdt, aplic_name); |
665 | qemu_fdt_setprop_string(ms->fdt, aplic_name, "compatible", "riscv,aplic"); | |
666 | qemu_fdt_setprop_cell(ms->fdt, aplic_name, | |
e6faee65 | 667 | "#interrupt-cells", FDT_APLIC_INT_CELLS); |
568e0614 | 668 | qemu_fdt_setprop(ms->fdt, aplic_name, "interrupt-controller", NULL, 0); |
28d8c281 | 669 | if (s->aia_type == VIRT_AIA_TYPE_APLIC) { |
568e0614 | 670 | qemu_fdt_setprop(ms->fdt, aplic_name, "interrupts-extended", |
28d8c281 AP |
671 | aplic_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 2); |
672 | } else { | |
568e0614 | 673 | qemu_fdt_setprop_cell(ms->fdt, aplic_name, "msi-parent", |
28d8c281 AP |
674 | msi_m_phandle); |
675 | } | |
568e0614 | 676 | qemu_fdt_setprop_cells(ms->fdt, aplic_name, "reg", |
e6faee65 | 677 | 0x0, aplic_addr, 0x0, memmap[VIRT_APLIC_M].size); |
568e0614 | 678 | qemu_fdt_setprop_cell(ms->fdt, aplic_name, "riscv,num-sources", |
e6faee65 | 679 | VIRT_IRQCHIP_NUM_SOURCES); |
568e0614 | 680 | qemu_fdt_setprop_cell(ms->fdt, aplic_name, "riscv,children", |
e6faee65 | 681 | aplic_s_phandle); |
568e0614 | 682 | qemu_fdt_setprop_cells(ms->fdt, aplic_name, "riscv,delegate", |
e6faee65 | 683 | aplic_s_phandle, 0x1, VIRT_IRQCHIP_NUM_SOURCES); |
568e0614 DHB |
684 | riscv_socket_fdt_write_id(ms, aplic_name, socket); |
685 | qemu_fdt_setprop_cell(ms->fdt, aplic_name, "phandle", aplic_m_phandle); | |
e6faee65 AP |
686 | g_free(aplic_name); |
687 | ||
688 | /* S-level APLIC node */ | |
689 | for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) { | |
690 | aplic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]); | |
691 | aplic_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_S_EXT); | |
692 | } | |
693 | aplic_addr = memmap[VIRT_APLIC_S].base + | |
694 | (memmap[VIRT_APLIC_S].size * socket); | |
695 | aplic_name = g_strdup_printf("/soc/aplic@%lx", aplic_addr); | |
568e0614 DHB |
696 | qemu_fdt_add_subnode(ms->fdt, aplic_name); |
697 | qemu_fdt_setprop_string(ms->fdt, aplic_name, "compatible", "riscv,aplic"); | |
698 | qemu_fdt_setprop_cell(ms->fdt, aplic_name, | |
e6faee65 | 699 | "#interrupt-cells", FDT_APLIC_INT_CELLS); |
568e0614 | 700 | qemu_fdt_setprop(ms->fdt, aplic_name, "interrupt-controller", NULL, 0); |
28d8c281 | 701 | if (s->aia_type == VIRT_AIA_TYPE_APLIC) { |
568e0614 | 702 | qemu_fdt_setprop(ms->fdt, aplic_name, "interrupts-extended", |
28d8c281 AP |
703 | aplic_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 2); |
704 | } else { | |
568e0614 | 705 | qemu_fdt_setprop_cell(ms->fdt, aplic_name, "msi-parent", |
28d8c281 AP |
706 | msi_s_phandle); |
707 | } | |
568e0614 | 708 | qemu_fdt_setprop_cells(ms->fdt, aplic_name, "reg", |
e6faee65 | 709 | 0x0, aplic_addr, 0x0, memmap[VIRT_APLIC_S].size); |
568e0614 | 710 | qemu_fdt_setprop_cell(ms->fdt, aplic_name, "riscv,num-sources", |
e6faee65 | 711 | VIRT_IRQCHIP_NUM_SOURCES); |
568e0614 DHB |
712 | riscv_socket_fdt_write_id(ms, aplic_name, socket); |
713 | qemu_fdt_setprop_cell(ms->fdt, aplic_name, "phandle", aplic_s_phandle); | |
3029fab6 | 714 | |
d644e5e4 | 715 | if (!socket) { |
568e0614 | 716 | platform_bus_add_all_fdt_nodes(ms->fdt, aplic_name, |
d644e5e4 AP |
717 | memmap[VIRT_PLATFORM_BUS].base, |
718 | memmap[VIRT_PLATFORM_BUS].size, | |
719 | VIRT_PLATFORM_BUS_IRQ); | |
720 | } | |
3029fab6 | 721 | |
e6faee65 AP |
722 | g_free(aplic_name); |
723 | ||
724 | g_free(aplic_cells); | |
725 | aplic_phandles[socket] = aplic_s_phandle; | |
726 | } | |
727 | ||
abd9a206 AP |
728 | static void create_fdt_pmu(RISCVVirtState *s) |
729 | { | |
730 | char *pmu_name; | |
568e0614 | 731 | MachineState *ms = MACHINE(s); |
abd9a206 AP |
732 | RISCVCPU hart = s->soc[0].harts[0]; |
733 | ||
734 | pmu_name = g_strdup_printf("/soc/pmu"); | |
568e0614 DHB |
735 | qemu_fdt_add_subnode(ms->fdt, pmu_name); |
736 | qemu_fdt_setprop_string(ms->fdt, pmu_name, "compatible", "riscv,pmu"); | |
737 | riscv_pmu_generate_fdt_node(ms->fdt, hart.cfg.pmu_num, pmu_name); | |
abd9a206 AP |
738 | |
739 | g_free(pmu_name); | |
740 | } | |
741 | ||
0ffc1a95 | 742 | static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, |
914c97f9 | 743 | uint32_t *phandle, |
0ffc1a95 AP |
744 | uint32_t *irq_mmio_phandle, |
745 | uint32_t *irq_pcie_phandle, | |
28d8c281 AP |
746 | uint32_t *irq_virtio_phandle, |
747 | uint32_t *msi_pcie_phandle) | |
0ffc1a95 | 748 | { |
0ffc1a95 | 749 | char *clust_name; |
28d8c281 | 750 | int socket, phandle_pos; |
568e0614 | 751 | MachineState *ms = MACHINE(s); |
28d8c281 AP |
752 | uint32_t msi_m_phandle = 0, msi_s_phandle = 0; |
753 | uint32_t *intc_phandles, xplic_phandles[MAX_NODES]; | |
568e0614 | 754 | int socket_count = riscv_socket_count(ms); |
04331d0b | 755 | |
568e0614 DHB |
756 | qemu_fdt_add_subnode(ms->fdt, "/cpus"); |
757 | qemu_fdt_setprop_cell(ms->fdt, "/cpus", "timebase-frequency", | |
b8fb878a | 758 | RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ); |
568e0614 DHB |
759 | qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#size-cells", 0x0); |
760 | qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#address-cells", 0x1); | |
761 | qemu_fdt_add_subnode(ms->fdt, "/cpus/cpu-map"); | |
18df0b46 | 762 | |
568e0614 | 763 | intc_phandles = g_new0(uint32_t, ms->smp.cpus); |
28d8c281 | 764 | |
568e0614 | 765 | phandle_pos = ms->smp.cpus; |
2967f37d | 766 | for (socket = (socket_count - 1); socket >= 0; socket--) { |
28d8c281 AP |
767 | phandle_pos -= s->soc[socket].num_harts; |
768 | ||
18df0b46 | 769 | clust_name = g_strdup_printf("/cpus/cpu-map/cluster%d", socket); |
568e0614 | 770 | qemu_fdt_add_subnode(ms->fdt, clust_name); |
0ffc1a95 | 771 | |
0ffc1a95 | 772 | create_fdt_socket_cpus(s, socket, clust_name, phandle, |
914c97f9 | 773 | &intc_phandles[phandle_pos]); |
04331d0b | 774 | |
0ffc1a95 AP |
775 | create_fdt_socket_memory(s, memmap, socket); |
776 | ||
28d8c281 AP |
777 | g_free(clust_name); |
778 | ||
ad40be27 YJ |
779 | if (!kvm_enabled()) { |
780 | if (s->have_aclint) { | |
28d8c281 AP |
781 | create_fdt_socket_aclint(s, memmap, socket, |
782 | &intc_phandles[phandle_pos]); | |
ad40be27 | 783 | } else { |
28d8c281 AP |
784 | create_fdt_socket_clint(s, memmap, socket, |
785 | &intc_phandles[phandle_pos]); | |
ad40be27 | 786 | } |
954886ea | 787 | } |
28d8c281 AP |
788 | } |
789 | ||
790 | if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) { | |
791 | create_fdt_imsic(s, memmap, phandle, intc_phandles, | |
792 | &msi_m_phandle, &msi_s_phandle); | |
793 | *msi_pcie_phandle = msi_s_phandle; | |
794 | } | |
795 | ||
568e0614 | 796 | phandle_pos = ms->smp.cpus; |
2967f37d | 797 | for (socket = (socket_count - 1); socket >= 0; socket--) { |
28d8c281 | 798 | phandle_pos -= s->soc[socket].num_harts; |
0ffc1a95 | 799 | |
e6faee65 AP |
800 | if (s->aia_type == VIRT_AIA_TYPE_NONE) { |
801 | create_fdt_socket_plic(s, memmap, socket, phandle, | |
28d8c281 | 802 | &intc_phandles[phandle_pos], xplic_phandles); |
e6faee65 | 803 | } else { |
28d8c281 AP |
804 | create_fdt_socket_aplic(s, memmap, socket, |
805 | msi_m_phandle, msi_s_phandle, phandle, | |
806 | &intc_phandles[phandle_pos], xplic_phandles); | |
e6faee65 | 807 | } |
28a4df97 AP |
808 | } |
809 | ||
28d8c281 AP |
810 | g_free(intc_phandles); |
811 | ||
2967f37d | 812 | for (socket = 0; socket < socket_count; socket++) { |
18df0b46 | 813 | if (socket == 0) { |
0ffc1a95 AP |
814 | *irq_mmio_phandle = xplic_phandles[socket]; |
815 | *irq_virtio_phandle = xplic_phandles[socket]; | |
816 | *irq_pcie_phandle = xplic_phandles[socket]; | |
18df0b46 AP |
817 | } |
818 | if (socket == 1) { | |
0ffc1a95 AP |
819 | *irq_virtio_phandle = xplic_phandles[socket]; |
820 | *irq_pcie_phandle = xplic_phandles[socket]; | |
18df0b46 AP |
821 | } |
822 | if (socket == 2) { | |
0ffc1a95 | 823 | *irq_pcie_phandle = xplic_phandles[socket]; |
18df0b46 | 824 | } |
04331d0b | 825 | } |
18df0b46 | 826 | |
568e0614 | 827 | riscv_socket_fdt_write_distance_matrix(ms); |
0ffc1a95 AP |
828 | } |
829 | ||
830 | static void create_fdt_virtio(RISCVVirtState *s, const MemMapEntry *memmap, | |
831 | uint32_t irq_virtio_phandle) | |
832 | { | |
833 | int i; | |
834 | char *name; | |
568e0614 | 835 | MachineState *ms = MACHINE(s); |
04331d0b MC |
836 | |
837 | for (i = 0; i < VIRTIO_COUNT; i++) { | |
18df0b46 | 838 | name = g_strdup_printf("/soc/virtio_mmio@%lx", |
04331d0b | 839 | (long)(memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size)); |
568e0614 DHB |
840 | qemu_fdt_add_subnode(ms->fdt, name); |
841 | qemu_fdt_setprop_string(ms->fdt, name, "compatible", "virtio,mmio"); | |
842 | qemu_fdt_setprop_cells(ms->fdt, name, "reg", | |
04331d0b MC |
843 | 0x0, memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size, |
844 | 0x0, memmap[VIRT_VIRTIO].size); | |
568e0614 | 845 | qemu_fdt_setprop_cell(ms->fdt, name, "interrupt-parent", |
0ffc1a95 | 846 | irq_virtio_phandle); |
e6faee65 | 847 | if (s->aia_type == VIRT_AIA_TYPE_NONE) { |
568e0614 | 848 | qemu_fdt_setprop_cell(ms->fdt, name, "interrupts", |
e6faee65 AP |
849 | VIRTIO_IRQ + i); |
850 | } else { | |
568e0614 | 851 | qemu_fdt_setprop_cells(ms->fdt, name, "interrupts", |
e6faee65 AP |
852 | VIRTIO_IRQ + i, 0x4); |
853 | } | |
18df0b46 | 854 | g_free(name); |
04331d0b | 855 | } |
0ffc1a95 AP |
856 | } |
857 | ||
858 | static void create_fdt_pcie(RISCVVirtState *s, const MemMapEntry *memmap, | |
28d8c281 AP |
859 | uint32_t irq_pcie_phandle, |
860 | uint32_t msi_pcie_phandle) | |
0ffc1a95 AP |
861 | { |
862 | char *name; | |
568e0614 | 863 | MachineState *ms = MACHINE(s); |
04331d0b | 864 | |
18df0b46 | 865 | name = g_strdup_printf("/soc/pci@%lx", |
6d56e396 | 866 | (long) memmap[VIRT_PCIE_ECAM].base); |
568e0614 DHB |
867 | qemu_fdt_add_subnode(ms->fdt, name); |
868 | qemu_fdt_setprop_cell(ms->fdt, name, "#address-cells", | |
0ffc1a95 | 869 | FDT_PCI_ADDR_CELLS); |
568e0614 | 870 | qemu_fdt_setprop_cell(ms->fdt, name, "#interrupt-cells", |
0ffc1a95 | 871 | FDT_PCI_INT_CELLS); |
568e0614 DHB |
872 | qemu_fdt_setprop_cell(ms->fdt, name, "#size-cells", 0x2); |
873 | qemu_fdt_setprop_string(ms->fdt, name, "compatible", | |
0ffc1a95 | 874 | "pci-host-ecam-generic"); |
568e0614 DHB |
875 | qemu_fdt_setprop_string(ms->fdt, name, "device_type", "pci"); |
876 | qemu_fdt_setprop_cell(ms->fdt, name, "linux,pci-domain", 0); | |
877 | qemu_fdt_setprop_cells(ms->fdt, name, "bus-range", 0, | |
18df0b46 | 878 | memmap[VIRT_PCIE_ECAM].size / PCIE_MMCFG_SIZE_MIN - 1); |
568e0614 | 879 | qemu_fdt_setprop(ms->fdt, name, "dma-coherent", NULL, 0); |
28d8c281 | 880 | if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) { |
568e0614 | 881 | qemu_fdt_setprop_cell(ms->fdt, name, "msi-parent", msi_pcie_phandle); |
28d8c281 | 882 | } |
568e0614 | 883 | qemu_fdt_setprop_cells(ms->fdt, name, "reg", 0, |
18df0b46 | 884 | memmap[VIRT_PCIE_ECAM].base, 0, memmap[VIRT_PCIE_ECAM].size); |
568e0614 | 885 | qemu_fdt_setprop_sized_cells(ms->fdt, name, "ranges", |
6d56e396 AF |
886 | 1, FDT_PCI_RANGE_IOPORT, 2, 0, |
887 | 2, memmap[VIRT_PCIE_PIO].base, 2, memmap[VIRT_PCIE_PIO].size, | |
888 | 1, FDT_PCI_RANGE_MMIO, | |
889 | 2, memmap[VIRT_PCIE_MMIO].base, | |
19800265 BM |
890 | 2, memmap[VIRT_PCIE_MMIO].base, 2, memmap[VIRT_PCIE_MMIO].size, |
891 | 1, FDT_PCI_RANGE_MMIO_64BIT, | |
892 | 2, virt_high_pcie_memmap.base, | |
893 | 2, virt_high_pcie_memmap.base, 2, virt_high_pcie_memmap.size); | |
894 | ||
568e0614 | 895 | create_pcie_irq_map(s, ms->fdt, name, irq_pcie_phandle); |
18df0b46 | 896 | g_free(name); |
0ffc1a95 | 897 | } |
6d56e396 | 898 | |
0ffc1a95 AP |
899 | static void create_fdt_reset(RISCVVirtState *s, const MemMapEntry *memmap, |
900 | uint32_t *phandle) | |
901 | { | |
902 | char *name; | |
903 | uint32_t test_phandle; | |
568e0614 | 904 | MachineState *ms = MACHINE(s); |
0ffc1a95 AP |
905 | |
906 | test_phandle = (*phandle)++; | |
18df0b46 | 907 | name = g_strdup_printf("/soc/test@%lx", |
04331d0b | 908 | (long)memmap[VIRT_TEST].base); |
568e0614 | 909 | qemu_fdt_add_subnode(ms->fdt, name); |
9c0fb20c | 910 | { |
2cc04550 BM |
911 | static const char * const compat[3] = { |
912 | "sifive,test1", "sifive,test0", "syscon" | |
913 | }; | |
568e0614 | 914 | qemu_fdt_setprop_string_array(ms->fdt, name, "compatible", |
0ffc1a95 | 915 | (char **)&compat, ARRAY_SIZE(compat)); |
9c0fb20c | 916 | } |
568e0614 | 917 | qemu_fdt_setprop_cells(ms->fdt, name, "reg", |
0ffc1a95 | 918 | 0x0, memmap[VIRT_TEST].base, 0x0, memmap[VIRT_TEST].size); |
568e0614 DHB |
919 | qemu_fdt_setprop_cell(ms->fdt, name, "phandle", test_phandle); |
920 | test_phandle = qemu_fdt_get_phandle(ms->fdt, name); | |
18df0b46 AP |
921 | g_free(name); |
922 | ||
ae293799 | 923 | name = g_strdup_printf("/reboot"); |
568e0614 DHB |
924 | qemu_fdt_add_subnode(ms->fdt, name); |
925 | qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon-reboot"); | |
926 | qemu_fdt_setprop_cell(ms->fdt, name, "regmap", test_phandle); | |
927 | qemu_fdt_setprop_cell(ms->fdt, name, "offset", 0x0); | |
928 | qemu_fdt_setprop_cell(ms->fdt, name, "value", FINISHER_RESET); | |
18df0b46 AP |
929 | g_free(name); |
930 | ||
ae293799 | 931 | name = g_strdup_printf("/poweroff"); |
568e0614 DHB |
932 | qemu_fdt_add_subnode(ms->fdt, name); |
933 | qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon-poweroff"); | |
934 | qemu_fdt_setprop_cell(ms->fdt, name, "regmap", test_phandle); | |
935 | qemu_fdt_setprop_cell(ms->fdt, name, "offset", 0x0); | |
936 | qemu_fdt_setprop_cell(ms->fdt, name, "value", FINISHER_PASS); | |
18df0b46 | 937 | g_free(name); |
0ffc1a95 AP |
938 | } |
939 | ||
940 | static void create_fdt_uart(RISCVVirtState *s, const MemMapEntry *memmap, | |
941 | uint32_t irq_mmio_phandle) | |
942 | { | |
943 | char *name; | |
568e0614 | 944 | MachineState *ms = MACHINE(s); |
18df0b46 | 945 | |
53c38f7a | 946 | name = g_strdup_printf("/soc/serial@%lx", (long)memmap[VIRT_UART0].base); |
568e0614 DHB |
947 | qemu_fdt_add_subnode(ms->fdt, name); |
948 | qemu_fdt_setprop_string(ms->fdt, name, "compatible", "ns16550a"); | |
949 | qemu_fdt_setprop_cells(ms->fdt, name, "reg", | |
04331d0b MC |
950 | 0x0, memmap[VIRT_UART0].base, |
951 | 0x0, memmap[VIRT_UART0].size); | |
568e0614 DHB |
952 | qemu_fdt_setprop_cell(ms->fdt, name, "clock-frequency", 3686400); |
953 | qemu_fdt_setprop_cell(ms->fdt, name, "interrupt-parent", irq_mmio_phandle); | |
e6faee65 | 954 | if (s->aia_type == VIRT_AIA_TYPE_NONE) { |
568e0614 | 955 | qemu_fdt_setprop_cell(ms->fdt, name, "interrupts", UART0_IRQ); |
e6faee65 | 956 | } else { |
568e0614 | 957 | qemu_fdt_setprop_cells(ms->fdt, name, "interrupts", UART0_IRQ, 0x4); |
e6faee65 | 958 | } |
04331d0b | 959 | |
568e0614 DHB |
960 | qemu_fdt_add_subnode(ms->fdt, "/chosen"); |
961 | qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", name); | |
18df0b46 | 962 | g_free(name); |
0ffc1a95 AP |
963 | } |
964 | ||
965 | static void create_fdt_rtc(RISCVVirtState *s, const MemMapEntry *memmap, | |
966 | uint32_t irq_mmio_phandle) | |
967 | { | |
968 | char *name; | |
568e0614 | 969 | MachineState *ms = MACHINE(s); |
18df0b46 AP |
970 | |
971 | name = g_strdup_printf("/soc/rtc@%lx", (long)memmap[VIRT_RTC].base); | |
568e0614 DHB |
972 | qemu_fdt_add_subnode(ms->fdt, name); |
973 | qemu_fdt_setprop_string(ms->fdt, name, "compatible", | |
0ffc1a95 | 974 | "google,goldfish-rtc"); |
568e0614 | 975 | qemu_fdt_setprop_cells(ms->fdt, name, "reg", |
0ffc1a95 | 976 | 0x0, memmap[VIRT_RTC].base, 0x0, memmap[VIRT_RTC].size); |
568e0614 | 977 | qemu_fdt_setprop_cell(ms->fdt, name, "interrupt-parent", |
0ffc1a95 | 978 | irq_mmio_phandle); |
e6faee65 | 979 | if (s->aia_type == VIRT_AIA_TYPE_NONE) { |
568e0614 | 980 | qemu_fdt_setprop_cell(ms->fdt, name, "interrupts", RTC_IRQ); |
e6faee65 | 981 | } else { |
568e0614 | 982 | qemu_fdt_setprop_cells(ms->fdt, name, "interrupts", RTC_IRQ, 0x4); |
e6faee65 | 983 | } |
18df0b46 | 984 | g_free(name); |
0ffc1a95 AP |
985 | } |
986 | ||
987 | static void create_fdt_flash(RISCVVirtState *s, const MemMapEntry *memmap) | |
988 | { | |
989 | char *name; | |
568e0614 | 990 | MachineState *ms = MACHINE(s); |
0ffc1a95 AP |
991 | hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2; |
992 | hwaddr flashbase = virt_memmap[VIRT_FLASH].base; | |
18df0b46 | 993 | |
58bde469 | 994 | name = g_strdup_printf("/flash@%" PRIx64, flashbase); |
568e0614 DHB |
995 | qemu_fdt_add_subnode(ms->fdt, name); |
996 | qemu_fdt_setprop_string(ms->fdt, name, "compatible", "cfi-flash"); | |
997 | qemu_fdt_setprop_sized_cells(ms->fdt, name, "reg", | |
71eb522c AF |
998 | 2, flashbase, 2, flashsize, |
999 | 2, flashbase + flashsize, 2, flashsize); | |
568e0614 | 1000 | qemu_fdt_setprop_cell(ms->fdt, name, "bank-width", 4); |
18df0b46 | 1001 | g_free(name); |
0ffc1a95 AP |
1002 | } |
1003 | ||
f9a461b2 AP |
1004 | static void create_fdt_fw_cfg(RISCVVirtState *s, const MemMapEntry *memmap) |
1005 | { | |
1006 | char *nodename; | |
568e0614 | 1007 | MachineState *ms = MACHINE(s); |
f9a461b2 AP |
1008 | hwaddr base = memmap[VIRT_FW_CFG].base; |
1009 | hwaddr size = memmap[VIRT_FW_CFG].size; | |
1010 | ||
1011 | nodename = g_strdup_printf("/fw-cfg@%" PRIx64, base); | |
568e0614 DHB |
1012 | qemu_fdt_add_subnode(ms->fdt, nodename); |
1013 | qemu_fdt_setprop_string(ms->fdt, nodename, | |
f9a461b2 | 1014 | "compatible", "qemu,fw-cfg-mmio"); |
568e0614 | 1015 | qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", |
f9a461b2 | 1016 | 2, base, 2, size); |
568e0614 | 1017 | qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0); |
f9a461b2 AP |
1018 | g_free(nodename); |
1019 | } | |
1020 | ||
914c97f9 | 1021 | static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap) |
0ffc1a95 | 1022 | { |
568e0614 | 1023 | MachineState *ms = MACHINE(s); |
28d8c281 | 1024 | uint32_t phandle = 1, irq_mmio_phandle = 1, msi_pcie_phandle = 1; |
0ffc1a95 | 1025 | uint32_t irq_pcie_phandle = 1, irq_virtio_phandle = 1; |
e4b4f0b7 | 1026 | uint8_t rng_seed[32]; |
0ffc1a95 | 1027 | |
fc9ec362 BM |
1028 | ms->fdt = create_device_tree(&s->fdt_size); |
1029 | if (!ms->fdt) { | |
1030 | error_report("create_device_tree() failed"); | |
1031 | exit(1); | |
0ffc1a95 AP |
1032 | } |
1033 | ||
568e0614 DHB |
1034 | qemu_fdt_setprop_string(ms->fdt, "/", "model", "riscv-virtio,qemu"); |
1035 | qemu_fdt_setprop_string(ms->fdt, "/", "compatible", "riscv-virtio"); | |
1036 | qemu_fdt_setprop_cell(ms->fdt, "/", "#size-cells", 0x2); | |
1037 | qemu_fdt_setprop_cell(ms->fdt, "/", "#address-cells", 0x2); | |
0ffc1a95 | 1038 | |
568e0614 DHB |
1039 | qemu_fdt_add_subnode(ms->fdt, "/soc"); |
1040 | qemu_fdt_setprop(ms->fdt, "/soc", "ranges", NULL, 0); | |
1041 | qemu_fdt_setprop_string(ms->fdt, "/soc", "compatible", "simple-bus"); | |
1042 | qemu_fdt_setprop_cell(ms->fdt, "/soc", "#size-cells", 0x2); | |
1043 | qemu_fdt_setprop_cell(ms->fdt, "/soc", "#address-cells", 0x2); | |
0ffc1a95 | 1044 | |
914c97f9 DHB |
1045 | create_fdt_sockets(s, memmap, &phandle, &irq_mmio_phandle, |
1046 | &irq_pcie_phandle, &irq_virtio_phandle, | |
1047 | &msi_pcie_phandle); | |
0ffc1a95 AP |
1048 | |
1049 | create_fdt_virtio(s, memmap, irq_virtio_phandle); | |
1050 | ||
28d8c281 | 1051 | create_fdt_pcie(s, memmap, irq_pcie_phandle, msi_pcie_phandle); |
0ffc1a95 AP |
1052 | |
1053 | create_fdt_reset(s, memmap, &phandle); | |
1054 | ||
1055 | create_fdt_uart(s, memmap, irq_mmio_phandle); | |
1056 | ||
1057 | create_fdt_rtc(s, memmap, irq_mmio_phandle); | |
1058 | ||
1059 | create_fdt_flash(s, memmap); | |
f9a461b2 | 1060 | create_fdt_fw_cfg(s, memmap); |
abd9a206 | 1061 | create_fdt_pmu(s); |
4e1e3003 | 1062 | |
e4b4f0b7 JD |
1063 | /* Pass seed to RNG */ |
1064 | qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); | |
568e0614 | 1065 | qemu_fdt_setprop(ms->fdt, "/chosen", "rng-seed", |
2967f37d | 1066 | rng_seed, sizeof(rng_seed)); |
04331d0b MC |
1067 | } |
1068 | ||
6d56e396 AF |
1069 | static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, |
1070 | hwaddr ecam_base, hwaddr ecam_size, | |
1071 | hwaddr mmio_base, hwaddr mmio_size, | |
19800265 BM |
1072 | hwaddr high_mmio_base, |
1073 | hwaddr high_mmio_size, | |
6d56e396 | 1074 | hwaddr pio_base, |
e6faee65 | 1075 | DeviceState *irqchip) |
6d56e396 AF |
1076 | { |
1077 | DeviceState *dev; | |
1078 | MemoryRegion *ecam_alias, *ecam_reg; | |
19800265 | 1079 | MemoryRegion *mmio_alias, *high_mmio_alias, *mmio_reg; |
6d56e396 AF |
1080 | qemu_irq irq; |
1081 | int i; | |
1082 | ||
3e80f690 | 1083 | dev = qdev_new(TYPE_GPEX_HOST); |
6d56e396 | 1084 | |
3c6ef471 | 1085 | sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); |
6d56e396 AF |
1086 | |
1087 | ecam_alias = g_new0(MemoryRegion, 1); | |
1088 | ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); | |
1089 | memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam", | |
1090 | ecam_reg, 0, ecam_size); | |
1091 | memory_region_add_subregion(get_system_memory(), ecam_base, ecam_alias); | |
1092 | ||
1093 | mmio_alias = g_new0(MemoryRegion, 1); | |
1094 | mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1); | |
1095 | memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio", | |
1096 | mmio_reg, mmio_base, mmio_size); | |
1097 | memory_region_add_subregion(get_system_memory(), mmio_base, mmio_alias); | |
1098 | ||
19800265 BM |
1099 | /* Map high MMIO space */ |
1100 | high_mmio_alias = g_new0(MemoryRegion, 1); | |
1101 | memory_region_init_alias(high_mmio_alias, OBJECT(dev), "pcie-mmio-high", | |
1102 | mmio_reg, high_mmio_base, high_mmio_size); | |
1103 | memory_region_add_subregion(get_system_memory(), high_mmio_base, | |
1104 | high_mmio_alias); | |
1105 | ||
6d56e396 AF |
1106 | sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, pio_base); |
1107 | ||
1108 | for (i = 0; i < GPEX_NUM_IRQS; i++) { | |
e6faee65 | 1109 | irq = qdev_get_gpio_in(irqchip, PCIE_IRQ + i); |
6d56e396 AF |
1110 | |
1111 | sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq); | |
1112 | gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ + i); | |
1113 | } | |
1114 | ||
1115 | return dev; | |
1116 | } | |
1117 | ||
568e0614 | 1118 | static FWCfgState *create_fw_cfg(const MachineState *ms) |
0489348d AC |
1119 | { |
1120 | hwaddr base = virt_memmap[VIRT_FW_CFG].base; | |
0489348d | 1121 | FWCfgState *fw_cfg; |
0489348d AC |
1122 | |
1123 | fw_cfg = fw_cfg_init_mem_wide(base + 8, base, 8, base + 16, | |
1124 | &address_space_memory); | |
568e0614 | 1125 | fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)ms->smp.cpus); |
0489348d | 1126 | |
0489348d AC |
1127 | return fw_cfg; |
1128 | } | |
1129 | ||
e6faee65 AP |
1130 | static DeviceState *virt_create_plic(const MemMapEntry *memmap, int socket, |
1131 | int base_hartid, int hart_count) | |
1132 | { | |
1133 | DeviceState *ret; | |
1134 | char *plic_hart_config; | |
1135 | ||
1136 | /* Per-socket PLIC hart topology configuration string */ | |
1137 | plic_hart_config = riscv_plic_hart_config_string(hart_count); | |
1138 | ||
1139 | /* Per-socket PLIC */ | |
1140 | ret = sifive_plic_create( | |
1141 | memmap[VIRT_PLIC].base + socket * memmap[VIRT_PLIC].size, | |
1142 | plic_hart_config, hart_count, base_hartid, | |
1143 | VIRT_IRQCHIP_NUM_SOURCES, | |
1144 | ((1U << VIRT_IRQCHIP_NUM_PRIO_BITS) - 1), | |
1145 | VIRT_PLIC_PRIORITY_BASE, | |
1146 | VIRT_PLIC_PENDING_BASE, | |
1147 | VIRT_PLIC_ENABLE_BASE, | |
1148 | VIRT_PLIC_ENABLE_STRIDE, | |
1149 | VIRT_PLIC_CONTEXT_BASE, | |
1150 | VIRT_PLIC_CONTEXT_STRIDE, | |
1151 | memmap[VIRT_PLIC].size); | |
1152 | ||
1153 | g_free(plic_hart_config); | |
1154 | ||
1155 | return ret; | |
1156 | } | |
1157 | ||
28d8c281 | 1158 | static DeviceState *virt_create_aia(RISCVVirtAIAType aia_type, int aia_guests, |
e6faee65 AP |
1159 | const MemMapEntry *memmap, int socket, |
1160 | int base_hartid, int hart_count) | |
1161 | { | |
28d8c281 AP |
1162 | int i; |
1163 | hwaddr addr; | |
1164 | uint32_t guest_bits; | |
e6faee65 | 1165 | DeviceState *aplic_m; |
28d8c281 AP |
1166 | bool msimode = (aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) ? true : false; |
1167 | ||
1168 | if (msimode) { | |
1169 | /* Per-socket M-level IMSICs */ | |
1170 | addr = memmap[VIRT_IMSIC_M].base + socket * VIRT_IMSIC_GROUP_MAX_SIZE; | |
1171 | for (i = 0; i < hart_count; i++) { | |
1172 | riscv_imsic_create(addr + i * IMSIC_HART_SIZE(0), | |
1173 | base_hartid + i, true, 1, | |
1174 | VIRT_IRQCHIP_NUM_MSIS); | |
1175 | } | |
1176 | ||
1177 | /* Per-socket S-level IMSICs */ | |
1178 | guest_bits = imsic_num_bits(aia_guests + 1); | |
1179 | addr = memmap[VIRT_IMSIC_S].base + socket * VIRT_IMSIC_GROUP_MAX_SIZE; | |
1180 | for (i = 0; i < hart_count; i++) { | |
1181 | riscv_imsic_create(addr + i * IMSIC_HART_SIZE(guest_bits), | |
1182 | base_hartid + i, false, 1 + aia_guests, | |
1183 | VIRT_IRQCHIP_NUM_MSIS); | |
1184 | } | |
1185 | } | |
e6faee65 AP |
1186 | |
1187 | /* Per-socket M-level APLIC */ | |
1188 | aplic_m = riscv_aplic_create( | |
1189 | memmap[VIRT_APLIC_M].base + socket * memmap[VIRT_APLIC_M].size, | |
1190 | memmap[VIRT_APLIC_M].size, | |
28d8c281 AP |
1191 | (msimode) ? 0 : base_hartid, |
1192 | (msimode) ? 0 : hart_count, | |
e6faee65 AP |
1193 | VIRT_IRQCHIP_NUM_SOURCES, |
1194 | VIRT_IRQCHIP_NUM_PRIO_BITS, | |
28d8c281 | 1195 | msimode, true, NULL); |
e6faee65 AP |
1196 | |
1197 | if (aplic_m) { | |
1198 | /* Per-socket S-level APLIC */ | |
1199 | riscv_aplic_create( | |
1200 | memmap[VIRT_APLIC_S].base + socket * memmap[VIRT_APLIC_S].size, | |
1201 | memmap[VIRT_APLIC_S].size, | |
28d8c281 AP |
1202 | (msimode) ? 0 : base_hartid, |
1203 | (msimode) ? 0 : hart_count, | |
e6faee65 AP |
1204 | VIRT_IRQCHIP_NUM_SOURCES, |
1205 | VIRT_IRQCHIP_NUM_PRIO_BITS, | |
28d8c281 | 1206 | msimode, false, aplic_m); |
e6faee65 AP |
1207 | } |
1208 | ||
1209 | return aplic_m; | |
1210 | } | |
1211 | ||
1832b7cb AF |
1212 | static void create_platform_bus(RISCVVirtState *s, DeviceState *irqchip) |
1213 | { | |
1214 | DeviceState *dev; | |
1215 | SysBusDevice *sysbus; | |
1216 | const MemMapEntry *memmap = virt_memmap; | |
1217 | int i; | |
1218 | MemoryRegion *sysmem = get_system_memory(); | |
1219 | ||
1220 | dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE); | |
1221 | dev->id = g_strdup(TYPE_PLATFORM_BUS_DEVICE); | |
1222 | qdev_prop_set_uint32(dev, "num_irqs", VIRT_PLATFORM_BUS_NUM_IRQS); | |
1223 | qdev_prop_set_uint32(dev, "mmio_size", memmap[VIRT_PLATFORM_BUS].size); | |
1224 | sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); | |
1225 | s->platform_bus_dev = dev; | |
1226 | ||
1227 | sysbus = SYS_BUS_DEVICE(dev); | |
1228 | for (i = 0; i < VIRT_PLATFORM_BUS_NUM_IRQS; i++) { | |
1229 | int irq = VIRT_PLATFORM_BUS_IRQ + i; | |
1230 | sysbus_connect_irq(sysbus, i, qdev_get_gpio_in(irqchip, irq)); | |
1231 | } | |
1232 | ||
1233 | memory_region_add_subregion(sysmem, | |
1234 | memmap[VIRT_PLATFORM_BUS].base, | |
1235 | sysbus_mmio_get_region(sysbus, 0)); | |
1236 | } | |
1237 | ||
1c20d3ff AF |
1238 | static void virt_machine_done(Notifier *notifier, void *data) |
1239 | { | |
1240 | RISCVVirtState *s = container_of(notifier, RISCVVirtState, | |
1241 | machine_done); | |
1242 | const MemMapEntry *memmap = virt_memmap; | |
1243 | MachineState *machine = MACHINE(s); | |
1244 | target_ulong start_addr = memmap[VIRT_DRAM].base; | |
1245 | target_ulong firmware_end_addr, kernel_start_addr; | |
9d3f7108 | 1246 | const char *firmware_name = riscv_default_firmware_name(&s->soc[0]); |
1c20d3ff AF |
1247 | uint32_t fdt_load_addr; |
1248 | uint64_t kernel_entry; | |
1249 | ||
1250 | /* | |
1251 | * Only direct boot kernel is currently supported for KVM VM, | |
1252 | * so the "-bios" parameter is not supported when KVM is enabled. | |
1253 | */ | |
1254 | if (kvm_enabled()) { | |
1255 | if (machine->firmware) { | |
1256 | if (strcmp(machine->firmware, "none")) { | |
1257 | error_report("Machine mode firmware is not supported in " | |
1258 | "combination with KVM."); | |
1259 | exit(1); | |
1260 | } | |
1261 | } else { | |
1262 | machine->firmware = g_strdup("none"); | |
1263 | } | |
1264 | } | |
1265 | ||
9d3f7108 DHB |
1266 | firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name, |
1267 | start_addr, NULL); | |
1c20d3ff | 1268 | |
a5b0249d S |
1269 | if (drive_get(IF_PFLASH, 0, 1)) { |
1270 | /* | |
1271 | * S-mode FW like EDK2 will be kept in second plash (unit 1). | |
1272 | * When both kernel, initrd and pflash options are provided in the | |
1273 | * command line, the kernel and initrd will be copied to the fw_cfg | |
1274 | * table and opensbi will jump to the flash address which is the | |
1275 | * entry point of S-mode FW. It is the job of the S-mode FW to load | |
1276 | * the kernel and initrd using fw_cfg table. | |
1277 | * | |
1278 | * If only pflash is given but not -kernel, then it is the job of | |
1279 | * of the S-mode firmware to locate and load the kernel. | |
1280 | * In either case, the next_addr for opensbi will be the flash address. | |
1281 | */ | |
1282 | riscv_setup_firmware_boot(machine); | |
1283 | kernel_entry = virt_memmap[VIRT_FLASH].base + | |
1284 | virt_memmap[VIRT_FLASH].size / 2; | |
1285 | } else if (machine->kernel_filename) { | |
1c20d3ff AF |
1286 | kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc[0], |
1287 | firmware_end_addr); | |
1288 | ||
62c5bc34 | 1289 | kernel_entry = riscv_load_kernel(machine, &s->soc[0], |
487d73fc | 1290 | kernel_start_addr, true, NULL); |
1c20d3ff AF |
1291 | } else { |
1292 | /* | |
1293 | * If dynamic firmware is used, it doesn't know where is the next mode | |
1294 | * if kernel argument is not set. | |
1295 | */ | |
1296 | kernel_entry = 0; | |
1297 | } | |
1298 | ||
1299 | if (drive_get(IF_PFLASH, 0, 0)) { | |
1300 | /* | |
1301 | * Pflash was supplied, let's overwrite the address we jump to after | |
1302 | * reset to the base of the flash. | |
1303 | */ | |
1304 | start_addr = virt_memmap[VIRT_FLASH].base; | |
1305 | } | |
1306 | ||
bc2c0153 | 1307 | fdt_load_addr = riscv_compute_fdt_addr(memmap[VIRT_DRAM].base, |
4b402886 DHB |
1308 | memmap[VIRT_DRAM].size, |
1309 | machine); | |
bc2c0153 DHB |
1310 | riscv_load_fdt(fdt_load_addr, machine->fdt); |
1311 | ||
1c20d3ff AF |
1312 | /* load the reset vector */ |
1313 | riscv_setup_rom_reset_vec(machine, &s->soc[0], start_addr, | |
1314 | virt_memmap[VIRT_MROM].base, | |
1315 | virt_memmap[VIRT_MROM].size, kernel_entry, | |
6934f15b | 1316 | fdt_load_addr); |
1c20d3ff AF |
1317 | |
1318 | /* | |
1319 | * Only direct boot kernel is currently supported for KVM VM, | |
1320 | * So here setup kernel start address and fdt address. | |
1321 | * TODO:Support firmware loading and integrate to TCG start | |
1322 | */ | |
1323 | if (kvm_enabled()) { | |
1324 | riscv_setup_direct_kernel(kernel_entry, fdt_load_addr); | |
1325 | } | |
f709360f S |
1326 | |
1327 | if (virt_is_acpi_enabled(s)) { | |
1328 | virt_acpi_setup(s); | |
1329 | } | |
1c20d3ff AF |
1330 | } |
1331 | ||
b2a3a071 | 1332 | static void virt_machine_init(MachineState *machine) |
04331d0b | 1333 | { |
73261285 | 1334 | const MemMapEntry *memmap = virt_memmap; |
cdfc19e4 | 1335 | RISCVVirtState *s = RISCV_VIRT_MACHINE(machine); |
04331d0b | 1336 | MemoryRegion *system_memory = get_system_memory(); |
5aec3247 | 1337 | MemoryRegion *mask_rom = g_new(MemoryRegion, 1); |
e6faee65 | 1338 | char *soc_name; |
e6faee65 | 1339 | DeviceState *mmio_irqchip, *virtio_irqchip, *pcie_irqchip; |
33fcedfa | 1340 | int i, base_hartid, hart_count; |
2967f37d | 1341 | int socket_count = riscv_socket_count(machine); |
04331d0b | 1342 | |
18df0b46 | 1343 | /* Check socket count limit */ |
2967f37d | 1344 | if (VIRT_SOCKETS_MAX < socket_count) { |
18df0b46 AP |
1345 | error_report("number of sockets/nodes should be less than %d", |
1346 | VIRT_SOCKETS_MAX); | |
1347 | exit(1); | |
1348 | } | |
1349 | ||
1350 | /* Initialize sockets */ | |
e6faee65 | 1351 | mmio_irqchip = virtio_irqchip = pcie_irqchip = NULL; |
2967f37d | 1352 | for (i = 0; i < socket_count; i++) { |
18df0b46 AP |
1353 | if (!riscv_socket_check_hartids(machine, i)) { |
1354 | error_report("discontinuous hartids in socket%d", i); | |
1355 | exit(1); | |
1356 | } | |
1357 | ||
1358 | base_hartid = riscv_socket_first_hartid(machine, i); | |
1359 | if (base_hartid < 0) { | |
1360 | error_report("can't find hartid base for socket%d", i); | |
1361 | exit(1); | |
1362 | } | |
1363 | ||
1364 | hart_count = riscv_socket_hart_count(machine, i); | |
1365 | if (hart_count < 0) { | |
1366 | error_report("can't find hart count for socket%d", i); | |
1367 | exit(1); | |
1368 | } | |
1369 | ||
1370 | soc_name = g_strdup_printf("soc%d", i); | |
1371 | object_initialize_child(OBJECT(machine), soc_name, &s->soc[i], | |
1372 | TYPE_RISCV_HART_ARRAY); | |
1373 | g_free(soc_name); | |
1374 | object_property_set_str(OBJECT(&s->soc[i]), "cpu-type", | |
1375 | machine->cpu_type, &error_abort); | |
1376 | object_property_set_int(OBJECT(&s->soc[i]), "hartid-base", | |
1377 | base_hartid, &error_abort); | |
1378 | object_property_set_int(OBJECT(&s->soc[i]), "num-harts", | |
1379 | hart_count, &error_abort); | |
4bcfc391 | 1380 | sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_fatal); |
18df0b46 | 1381 | |
ad40be27 | 1382 | if (!kvm_enabled()) { |
ad40be27 | 1383 | if (s->have_aclint) { |
28d8c281 AP |
1384 | if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) { |
1385 | /* Per-socket ACLINT MTIMER */ | |
1386 | riscv_aclint_mtimer_create(memmap[VIRT_CLINT].base + | |
1387 | i * RISCV_ACLINT_DEFAULT_MTIMER_SIZE, | |
1388 | RISCV_ACLINT_DEFAULT_MTIMER_SIZE, | |
1389 | base_hartid, hart_count, | |
1390 | RISCV_ACLINT_DEFAULT_MTIMECMP, | |
1391 | RISCV_ACLINT_DEFAULT_MTIME, | |
1392 | RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, true); | |
1393 | } else { | |
1394 | /* Per-socket ACLINT MSWI, MTIMER, and SSWI */ | |
1395 | riscv_aclint_swi_create(memmap[VIRT_CLINT].base + | |
1396 | i * memmap[VIRT_CLINT].size, | |
1397 | base_hartid, hart_count, false); | |
1398 | riscv_aclint_mtimer_create(memmap[VIRT_CLINT].base + | |
1399 | i * memmap[VIRT_CLINT].size + | |
1400 | RISCV_ACLINT_SWI_SIZE, | |
1401 | RISCV_ACLINT_DEFAULT_MTIMER_SIZE, | |
1402 | base_hartid, hart_count, | |
1403 | RISCV_ACLINT_DEFAULT_MTIMECMP, | |
1404 | RISCV_ACLINT_DEFAULT_MTIME, | |
1405 | RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, true); | |
1406 | riscv_aclint_swi_create(memmap[VIRT_ACLINT_SSWI].base + | |
1407 | i * memmap[VIRT_ACLINT_SSWI].size, | |
1408 | base_hartid, hart_count, true); | |
1409 | } | |
1410 | } else { | |
1411 | /* Per-socket SiFive CLINT */ | |
ad40be27 | 1412 | riscv_aclint_swi_create( |
28d8c281 AP |
1413 | memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size, |
1414 | base_hartid, hart_count, false); | |
1415 | riscv_aclint_mtimer_create(memmap[VIRT_CLINT].base + | |
1416 | i * memmap[VIRT_CLINT].size + RISCV_ACLINT_SWI_SIZE, | |
1417 | RISCV_ACLINT_DEFAULT_MTIMER_SIZE, base_hartid, hart_count, | |
1418 | RISCV_ACLINT_DEFAULT_MTIMECMP, RISCV_ACLINT_DEFAULT_MTIME, | |
1419 | RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, true); | |
ad40be27 | 1420 | } |
954886ea AP |
1421 | } |
1422 | ||
e6faee65 AP |
1423 | /* Per-socket interrupt controller */ |
1424 | if (s->aia_type == VIRT_AIA_TYPE_NONE) { | |
1425 | s->irqchip[i] = virt_create_plic(memmap, i, | |
1426 | base_hartid, hart_count); | |
1427 | } else { | |
28d8c281 AP |
1428 | s->irqchip[i] = virt_create_aia(s->aia_type, s->aia_guests, |
1429 | memmap, i, base_hartid, | |
1430 | hart_count); | |
e6faee65 | 1431 | } |
18df0b46 | 1432 | |
e6faee65 | 1433 | /* Try to use different IRQCHIP instance based device type */ |
18df0b46 | 1434 | if (i == 0) { |
e6faee65 AP |
1435 | mmio_irqchip = s->irqchip[i]; |
1436 | virtio_irqchip = s->irqchip[i]; | |
1437 | pcie_irqchip = s->irqchip[i]; | |
18df0b46 AP |
1438 | } |
1439 | if (i == 1) { | |
e6faee65 AP |
1440 | virtio_irqchip = s->irqchip[i]; |
1441 | pcie_irqchip = s->irqchip[i]; | |
18df0b46 AP |
1442 | } |
1443 | if (i == 2) { | |
e6faee65 | 1444 | pcie_irqchip = s->irqchip[i]; |
18df0b46 AP |
1445 | } |
1446 | } | |
04331d0b | 1447 | |
cfeb8a17 BM |
1448 | if (riscv_is_32bit(&s->soc[0])) { |
1449 | #if HOST_LONG_BITS == 64 | |
1450 | /* limit RAM size in a 32-bit system */ | |
1451 | if (machine->ram_size > 10 * GiB) { | |
1452 | machine->ram_size = 10 * GiB; | |
1453 | error_report("Limiting RAM size to 10 GiB"); | |
1454 | } | |
1455 | #endif | |
19800265 BM |
1456 | virt_high_pcie_memmap.base = VIRT32_HIGH_PCIE_MMIO_BASE; |
1457 | virt_high_pcie_memmap.size = VIRT32_HIGH_PCIE_MMIO_SIZE; | |
1458 | } else { | |
1459 | virt_high_pcie_memmap.size = VIRT64_HIGH_PCIE_MMIO_SIZE; | |
1460 | virt_high_pcie_memmap.base = memmap[VIRT_DRAM].base + machine->ram_size; | |
1461 | virt_high_pcie_memmap.base = | |
1462 | ROUND_UP(virt_high_pcie_memmap.base, virt_high_pcie_memmap.size); | |
cfeb8a17 BM |
1463 | } |
1464 | ||
71302ff3 S |
1465 | s->memmap = virt_memmap; |
1466 | ||
04331d0b | 1467 | /* register system main memory (actual RAM) */ |
04331d0b | 1468 | memory_region_add_subregion(system_memory, memmap[VIRT_DRAM].base, |
03fd0c5f | 1469 | machine->ram); |
04331d0b | 1470 | |
04331d0b | 1471 | /* boot rom */ |
5aec3247 MC |
1472 | memory_region_init_rom(mask_rom, NULL, "riscv_virt_board.mrom", |
1473 | memmap[VIRT_MROM].size, &error_fatal); | |
1474 | memory_region_add_subregion(system_memory, memmap[VIRT_MROM].base, | |
1475 | mask_rom); | |
04331d0b | 1476 | |
b748352c DHB |
1477 | /* |
1478 | * Init fw_cfg. Must be done before riscv_load_fdt, otherwise the | |
1479 | * device tree cannot be altered and we get FDT_ERR_NOSPACE. | |
1480 | */ | |
1481 | s->fw_cfg = create_fw_cfg(machine); | |
1482 | rom_set_fw(s->fw_cfg); | |
1483 | ||
18df0b46 | 1484 | /* SiFive Test MMIO device */ |
04331d0b MC |
1485 | sifive_test_create(memmap[VIRT_TEST].base); |
1486 | ||
18df0b46 | 1487 | /* VirtIO MMIO devices */ |
04331d0b MC |
1488 | for (i = 0; i < VIRTIO_COUNT; i++) { |
1489 | sysbus_create_simple("virtio-mmio", | |
1490 | memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size, | |
7d5b0d68 | 1491 | qdev_get_gpio_in(virtio_irqchip, VIRTIO_IRQ + i)); |
04331d0b MC |
1492 | } |
1493 | ||
6d56e396 | 1494 | gpex_pcie_init(system_memory, |
2fa3c7b6 BM |
1495 | memmap[VIRT_PCIE_ECAM].base, |
1496 | memmap[VIRT_PCIE_ECAM].size, | |
1497 | memmap[VIRT_PCIE_MMIO].base, | |
1498 | memmap[VIRT_PCIE_MMIO].size, | |
19800265 BM |
1499 | virt_high_pcie_memmap.base, |
1500 | virt_high_pcie_memmap.size, | |
2fa3c7b6 | 1501 | memmap[VIRT_PCIE_PIO].base, |
7d5b0d68 | 1502 | pcie_irqchip); |
6d56e396 | 1503 | |
7d5b0d68 | 1504 | create_platform_bus(s, mmio_irqchip); |
1832b7cb | 1505 | |
04331d0b | 1506 | serial_mm_init(system_memory, memmap[VIRT_UART0].base, |
7d5b0d68 | 1507 | 0, qdev_get_gpio_in(mmio_irqchip, UART0_IRQ), 399193, |
9bca0edb | 1508 | serial_hd(0), DEVICE_LITTLE_ENDIAN); |
b6aa6ced | 1509 | |
67b5ef30 | 1510 | sysbus_create_simple("goldfish_rtc", memmap[VIRT_RTC].base, |
7d5b0d68 | 1511 | qdev_get_gpio_in(mmio_irqchip, RTC_IRQ)); |
67b5ef30 | 1512 | |
71eb522c AF |
1513 | virt_flash_create(s); |
1514 | ||
1515 | for (i = 0; i < ARRAY_SIZE(s->flash); i++) { | |
1516 | /* Map legacy -drive if=pflash to machine properties */ | |
1517 | pflash_cfi01_legacy_drive(s->flash[i], | |
1518 | drive_get(IF_PFLASH, 0, i)); | |
1519 | } | |
1520 | virt_flash_map(s, system_memory); | |
1c20d3ff | 1521 | |
fc9ec362 BM |
1522 | /* load/create device tree */ |
1523 | if (machine->dtb) { | |
1524 | machine->fdt = load_device_tree(machine->dtb, &s->fdt_size); | |
1525 | if (!machine->fdt) { | |
1526 | error_report("load_device_tree() failed"); | |
1527 | exit(1); | |
1528 | } | |
1529 | } else { | |
1530 | create_fdt(s, memmap); | |
1531 | } | |
1c20d3ff AF |
1532 | |
1533 | s->machine_done.notify = virt_machine_done; | |
1534 | qemu_add_machine_init_done_notifier(&s->machine_done); | |
04331d0b MC |
1535 | } |
1536 | ||
b2a3a071 | 1537 | static void virt_machine_instance_init(Object *obj) |
04331d0b | 1538 | { |
90477a65 S |
1539 | RISCVVirtState *s = RISCV_VIRT_MACHINE(obj); |
1540 | ||
1541 | s->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6); | |
1542 | s->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8); | |
168b8c29 | 1543 | s->acpi = ON_OFF_AUTO_AUTO; |
cdfc19e4 AF |
1544 | } |
1545 | ||
28d8c281 AP |
1546 | static char *virt_get_aia_guests(Object *obj, Error **errp) |
1547 | { | |
1548 | RISCVVirtState *s = RISCV_VIRT_MACHINE(obj); | |
1549 | char val[32]; | |
1550 | ||
1551 | sprintf(val, "%d", s->aia_guests); | |
1552 | return g_strdup(val); | |
1553 | } | |
1554 | ||
1555 | static void virt_set_aia_guests(Object *obj, const char *val, Error **errp) | |
1556 | { | |
1557 | RISCVVirtState *s = RISCV_VIRT_MACHINE(obj); | |
1558 | ||
1559 | s->aia_guests = atoi(val); | |
1560 | if (s->aia_guests < 0 || s->aia_guests > VIRT_IRQCHIP_MAX_GUESTS) { | |
1561 | error_setg(errp, "Invalid number of AIA IMSIC guests"); | |
1562 | error_append_hint(errp, "Valid values be between 0 and %d.\n", | |
1563 | VIRT_IRQCHIP_MAX_GUESTS); | |
1564 | } | |
1565 | } | |
1566 | ||
e6faee65 AP |
1567 | static char *virt_get_aia(Object *obj, Error **errp) |
1568 | { | |
1569 | RISCVVirtState *s = RISCV_VIRT_MACHINE(obj); | |
1570 | const char *val; | |
1571 | ||
1572 | switch (s->aia_type) { | |
1573 | case VIRT_AIA_TYPE_APLIC: | |
1574 | val = "aplic"; | |
1575 | break; | |
28d8c281 AP |
1576 | case VIRT_AIA_TYPE_APLIC_IMSIC: |
1577 | val = "aplic-imsic"; | |
1578 | break; | |
e6faee65 AP |
1579 | default: |
1580 | val = "none"; | |
1581 | break; | |
1582 | }; | |
1583 | ||
1584 | return g_strdup(val); | |
1585 | } | |
1586 | ||
1587 | static void virt_set_aia(Object *obj, const char *val, Error **errp) | |
1588 | { | |
1589 | RISCVVirtState *s = RISCV_VIRT_MACHINE(obj); | |
1590 | ||
1591 | if (!strcmp(val, "none")) { | |
1592 | s->aia_type = VIRT_AIA_TYPE_NONE; | |
1593 | } else if (!strcmp(val, "aplic")) { | |
1594 | s->aia_type = VIRT_AIA_TYPE_APLIC; | |
28d8c281 AP |
1595 | } else if (!strcmp(val, "aplic-imsic")) { |
1596 | s->aia_type = VIRT_AIA_TYPE_APLIC_IMSIC; | |
e6faee65 AP |
1597 | } else { |
1598 | error_setg(errp, "Invalid AIA interrupt controller type"); | |
28d8c281 AP |
1599 | error_append_hint(errp, "Valid values are none, aplic, and " |
1600 | "aplic-imsic.\n"); | |
e6faee65 AP |
1601 | } |
1602 | } | |
1603 | ||
954886ea AP |
1604 | static bool virt_get_aclint(Object *obj, Error **errp) |
1605 | { | |
5474aa4f | 1606 | RISCVVirtState *s = RISCV_VIRT_MACHINE(obj); |
954886ea AP |
1607 | |
1608 | return s->have_aclint; | |
1609 | } | |
1610 | ||
1611 | static void virt_set_aclint(Object *obj, bool value, Error **errp) | |
1612 | { | |
5474aa4f | 1613 | RISCVVirtState *s = RISCV_VIRT_MACHINE(obj); |
954886ea AP |
1614 | |
1615 | s->have_aclint = value; | |
1616 | } | |
1617 | ||
168b8c29 S |
1618 | bool virt_is_acpi_enabled(RISCVVirtState *s) |
1619 | { | |
1620 | return s->acpi != ON_OFF_AUTO_OFF; | |
1621 | } | |
1622 | ||
1623 | static void virt_get_acpi(Object *obj, Visitor *v, const char *name, | |
1624 | void *opaque, Error **errp) | |
1625 | { | |
1626 | RISCVVirtState *s = RISCV_VIRT_MACHINE(obj); | |
1627 | OnOffAuto acpi = s->acpi; | |
1628 | ||
1629 | visit_type_OnOffAuto(v, name, &acpi, errp); | |
1630 | } | |
1631 | ||
1632 | static void virt_set_acpi(Object *obj, Visitor *v, const char *name, | |
1633 | void *opaque, Error **errp) | |
1634 | { | |
1635 | RISCVVirtState *s = RISCV_VIRT_MACHINE(obj); | |
1636 | ||
1637 | visit_type_OnOffAuto(v, name, &s->acpi, errp); | |
1638 | } | |
1639 | ||
58d5a5a7 AF |
1640 | static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine, |
1641 | DeviceState *dev) | |
1642 | { | |
1643 | MachineClass *mc = MACHINE_GET_CLASS(machine); | |
1644 | ||
1645 | if (device_is_dynamic_sysbus(mc, dev)) { | |
1646 | return HOTPLUG_HANDLER(machine); | |
1647 | } | |
1648 | return NULL; | |
1649 | } | |
1650 | ||
1651 | static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev, | |
1652 | DeviceState *dev, Error **errp) | |
1653 | { | |
1654 | RISCVVirtState *s = RISCV_VIRT_MACHINE(hotplug_dev); | |
1655 | ||
1656 | if (s->platform_bus_dev) { | |
1657 | MachineClass *mc = MACHINE_GET_CLASS(s); | |
1658 | ||
1659 | if (device_is_dynamic_sysbus(mc, dev)) { | |
1660 | platform_bus_link_device(PLATFORM_BUS_DEVICE(s->platform_bus_dev), | |
1661 | SYS_BUS_DEVICE(dev)); | |
1662 | } | |
1663 | } | |
1664 | } | |
1665 | ||
b2a3a071 | 1666 | static void virt_machine_class_init(ObjectClass *oc, void *data) |
cdfc19e4 | 1667 | { |
28d8c281 | 1668 | char str[128]; |
cdfc19e4 | 1669 | MachineClass *mc = MACHINE_CLASS(oc); |
58d5a5a7 | 1670 | HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); |
cdfc19e4 AF |
1671 | |
1672 | mc->desc = "RISC-V VirtIO board"; | |
b2a3a071 | 1673 | mc->init = virt_machine_init; |
18df0b46 | 1674 | mc->max_cpus = VIRT_CPUS_MAX; |
09fe1712 | 1675 | mc->default_cpu_type = TYPE_RISCV_CPU_BASE; |
acead54c | 1676 | mc->pci_allow_0_address = true; |
18df0b46 AP |
1677 | mc->possible_cpu_arch_ids = riscv_numa_possible_cpu_arch_ids; |
1678 | mc->cpu_index_to_instance_props = riscv_numa_cpu_index_to_props; | |
1679 | mc->get_default_cpu_node_id = riscv_numa_get_default_cpu_node_id; | |
1680 | mc->numa_mem_supported = true; | |
03fd0c5f | 1681 | mc->default_ram_id = "riscv_virt_board.ram"; |
58d5a5a7 AF |
1682 | assert(!mc->get_hotplug_handler); |
1683 | mc->get_hotplug_handler = virt_machine_get_hotplug_handler; | |
1684 | ||
1685 | hc->plug = virt_machine_device_plug_cb; | |
c346749e AC |
1686 | |
1687 | machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE); | |
325b7c4e AF |
1688 | #ifdef CONFIG_TPM |
1689 | machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS); | |
1690 | #endif | |
954886ea AP |
1691 | |
1692 | object_class_property_add_bool(oc, "aclint", virt_get_aclint, | |
1693 | virt_set_aclint); | |
1694 | object_class_property_set_description(oc, "aclint", | |
1695 | "Set on/off to enable/disable " | |
1696 | "emulating ACLINT devices"); | |
e6faee65 AP |
1697 | |
1698 | object_class_property_add_str(oc, "aia", virt_get_aia, | |
1699 | virt_set_aia); | |
1700 | object_class_property_set_description(oc, "aia", | |
1701 | "Set type of AIA interrupt " | |
1702 | "conttoller. Valid values are " | |
28d8c281 AP |
1703 | "none, aplic, and aplic-imsic."); |
1704 | ||
1705 | object_class_property_add_str(oc, "aia-guests", | |
1706 | virt_get_aia_guests, | |
1707 | virt_set_aia_guests); | |
1708 | sprintf(str, "Set number of guest MMIO pages for AIA IMSIC. Valid value " | |
1709 | "should be between 0 and %d.", VIRT_IRQCHIP_MAX_GUESTS); | |
1710 | object_class_property_set_description(oc, "aia-guests", str); | |
168b8c29 S |
1711 | object_class_property_add(oc, "acpi", "OnOffAuto", |
1712 | virt_get_acpi, virt_set_acpi, | |
1713 | NULL, NULL); | |
1714 | object_class_property_set_description(oc, "acpi", | |
1715 | "Enable ACPI"); | |
04331d0b MC |
1716 | } |
1717 | ||
b2a3a071 | 1718 | static const TypeInfo virt_machine_typeinfo = { |
cdfc19e4 AF |
1719 | .name = MACHINE_TYPE_NAME("virt"), |
1720 | .parent = TYPE_MACHINE, | |
b2a3a071 BM |
1721 | .class_init = virt_machine_class_init, |
1722 | .instance_init = virt_machine_instance_init, | |
cdfc19e4 | 1723 | .instance_size = sizeof(RISCVVirtState), |
58d5a5a7 AF |
1724 | .interfaces = (InterfaceInfo[]) { |
1725 | { TYPE_HOTPLUG_HANDLER }, | |
1726 | { } | |
1727 | }, | |
cdfc19e4 AF |
1728 | }; |
1729 | ||
b2a3a071 | 1730 | static void virt_machine_init_register_types(void) |
cdfc19e4 | 1731 | { |
b2a3a071 | 1732 | type_register_static(&virt_machine_typeinfo); |
cdfc19e4 AF |
1733 | } |
1734 | ||
b2a3a071 | 1735 | type_init(virt_machine_init_register_types) |