aboutsummaryrefslogtreecommitdiff
path: root/hw/riscv/virt.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/riscv/virt.c')
-rw-r--r--hw/riscv/virt.c79
1 files changed, 30 insertions, 49 deletions
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 84d94d0c42..d8181a4ff1 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -34,13 +34,13 @@
#include "hw/riscv/sifive_clint.h"
#include "hw/riscv/sifive_test.h"
#include "hw/riscv/virt.h"
+#include "hw/riscv/boot.h"
#include "chardev/char.h"
#include "sysemu/arch_init.h"
#include "sysemu/device_tree.h"
#include "exec/address-spaces.h"
#include "hw/pci/pci.h"
#include "hw/pci-host/gpex.h"
-#include "elf.h"
#include <libfdt.h>
@@ -61,47 +61,6 @@ static const struct MemmapEntry {
[VIRT_PCIE_ECAM] = { 0x30000000, 0x10000000 },
};
-static target_ulong load_kernel(const char *kernel_filename)
-{
- uint64_t kernel_entry, kernel_high;
-
- if (load_elf(kernel_filename, NULL, NULL, NULL,
- &kernel_entry, NULL, &kernel_high,
- 0, EM_RISCV, 1, 0) < 0) {
- error_report("could not load kernel '%s'", kernel_filename);
- exit(1);
- }
- return kernel_entry;
-}
-
-static hwaddr load_initrd(const char *filename, uint64_t mem_size,
- uint64_t kernel_entry, hwaddr *start)
-{
- int size;
-
- /* We want to put the initrd far enough into RAM that when the
- * kernel is uncompressed it will not clobber the initrd. However
- * on boards without much RAM we must ensure that we still leave
- * enough room for a decent sized initrd, and on boards with large
- * amounts of RAM we must avoid the initrd being so far up in RAM
- * that it is outside lowmem and inaccessible to the kernel.
- * So for boards with less than 256MB of RAM we put the initrd
- * halfway into RAM, and for boards with 256MB of RAM or more we put
- * the initrd at 128MB.
- */
- *start = kernel_entry + MIN(mem_size / 2, 128 * MiB);
-
- size = load_ramdisk(filename, *start, mem_size - *start);
- if (size == -1) {
- size = load_image_targphys(filename, *start, mem_size - *start);
- if (size == -1) {
- error_report("could not load ramdisk '%s'", filename);
- exit(1);
- }
- }
- return *start + size;
-}
-
static void create_pcie_irq_map(void *fdt, char *nodename,
uint32_t plic_phandle)
{
@@ -191,6 +150,7 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
for (cpu = s->soc.num_harts - 1; cpu >= 0; cpu--) {
int cpu_phandle = phandle++;
+ int intc_phandle;
nodename = g_strdup_printf("/cpus/cpu@%d", cpu);
char *intc = g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu);
char *isa = riscv_isa_string(&s->soc.harts[cpu]);
@@ -203,9 +163,12 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
qemu_fdt_setprop_string(fdt, nodename, "status", "okay");
qemu_fdt_setprop_cell(fdt, nodename, "reg", cpu);
qemu_fdt_setprop_string(fdt, nodename, "device_type", "cpu");
+ qemu_fdt_setprop_cell(fdt, nodename, "phandle", cpu_phandle);
+ qemu_fdt_setprop_cell(fdt, nodename, "linux,phandle", cpu_phandle);
+ intc_phandle = phandle++;
qemu_fdt_add_subnode(fdt, intc);
- qemu_fdt_setprop_cell(fdt, intc, "phandle", cpu_phandle);
- qemu_fdt_setprop_cell(fdt, intc, "linux,phandle", cpu_phandle);
+ qemu_fdt_setprop_cell(fdt, intc, "phandle", intc_phandle);
+ qemu_fdt_setprop_cell(fdt, intc, "linux,phandle", intc_phandle);
qemu_fdt_setprop_string(fdt, intc, "compatible", "riscv,cpu-intc");
qemu_fdt_setprop(fdt, intc, "interrupt-controller", NULL, 0);
qemu_fdt_setprop_cell(fdt, intc, "#interrupt-cells", 1);
@@ -214,6 +177,20 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
g_free(nodename);
}
+ /* Add cpu-topology node */
+ qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
+ qemu_fdt_add_subnode(fdt, "/cpus/cpu-map/cluster0");
+ for (cpu = s->soc.num_harts - 1; cpu >= 0; cpu--) {
+ char *core_nodename = g_strdup_printf("/cpus/cpu-map/cluster0/core%d",
+ cpu);
+ char *cpu_nodename = g_strdup_printf("/cpus/cpu@%d", cpu);
+ uint32_t intc_phandle = qemu_fdt_get_phandle(fdt, cpu_nodename);
+ qemu_fdt_add_subnode(fdt, core_nodename);
+ qemu_fdt_setprop_cell(fdt, core_nodename, "cpu", intc_phandle);
+ g_free(core_nodename);
+ g_free(cpu_nodename);
+ }
+
cells = g_new0(uint32_t, s->soc.num_harts * 4);
for (cpu = 0; cpu < s->soc.num_harts; cpu++) {
nodename =
@@ -298,7 +275,7 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
qemu_fdt_setprop_string(fdt, nodename, "device_type", "pci");
qemu_fdt_setprop_cell(fdt, nodename, "linux,pci-domain", 0);
qemu_fdt_setprop_cells(fdt, nodename, "bus-range", 0,
- memmap[VIRT_PCIE_ECAM].base /
+ memmap[VIRT_PCIE_ECAM].size /
PCIE_MMCFG_SIZE_MIN - 1);
qemu_fdt_setprop(fdt, nodename, "dma-coherent", NULL, 0);
qemu_fdt_setprop_cells(fdt, nodename, "reg", 0, memmap[VIRT_PCIE_ECAM].base,
@@ -421,14 +398,18 @@ static void riscv_virt_board_init(MachineState *machine)
memory_region_add_subregion(system_memory, memmap[VIRT_MROM].base,
mask_rom);
+ if (machine->firmware) {
+ riscv_load_firmware(machine->firmware, memmap[VIRT_DRAM].base);
+ }
+
if (machine->kernel_filename) {
- uint64_t kernel_entry = load_kernel(machine->kernel_filename);
+ uint64_t kernel_entry = riscv_load_kernel(machine->kernel_filename);
if (machine->initrd_filename) {
hwaddr start;
- hwaddr end = load_initrd(machine->initrd_filename,
- machine->ram_size, kernel_entry,
- &start);
+ hwaddr end = riscv_load_initrd(machine->initrd_filename,
+ machine->ram_size, kernel_entry,
+ &start);
qemu_fdt_setprop_cell(fdt, "/chosen",
"linux,initrd-start", start);
qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",