*
* 0) HTIF Console and Poweroff
* 1) CLINT (Timer and IPI)
- * 2) PLIC (Platform Level Interrupt Controller)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
*/
#include "qemu/osdep.h"
-#include "qemu/log.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "hw/boards.h"
#include "hw/riscv/boot.h"
#include "hw/riscv/numa.h"
#include "hw/char/riscv_htif.h"
-#include "hw/intc/sifive_clint.h"
+#include "hw/intc/riscv_aclint.h"
#include "chardev/char.h"
-#include "sysemu/arch_init.h"
#include "sysemu/device_tree.h"
-#include "sysemu/qtest.h"
#include "sysemu/sysemu.h"
-static const struct MemmapEntry {
- hwaddr base;
- hwaddr size;
-} spike_memmap[] = {
+#include <libfdt.h>
+
+static const MemMapEntry spike_memmap[] = {
[SPIKE_MROM] = { 0x1000, 0xf000 },
+ [SPIKE_HTIF] = { 0x1000000, 0x1000 },
[SPIKE_CLINT] = { 0x2000000, 0x10000 },
[SPIKE_DRAM] = { 0x80000000, 0x0 },
};
-static void create_fdt(SpikeState *s, const struct MemmapEntry *memmap,
- uint64_t mem_size, const char *cmdline, bool is_32_bit)
+static void create_fdt(SpikeState *s, const MemMapEntry *memmap,
+ uint64_t mem_size, const char *cmdline,
+ bool is_32_bit, bool htif_custom_base)
{
void *fdt;
uint64_t addr, size;
uint32_t cpu_phandle, intc_phandle, phandle = 1;
char *name, *mem_name, *clint_name, *clust_name;
char *core_name, *cpu_name, *intc_name;
+ static const char * const clint_compat[2] = {
+ "sifive,clint0", "riscv,clint0"
+ };
fdt = s->fdt = create_device_tree(&s->fdt_size);
if (!fdt) {
qemu_fdt_add_subnode(fdt, "/htif");
qemu_fdt_setprop_string(fdt, "/htif", "compatible", "ucb,htif0");
+ if (htif_custom_base) {
+ qemu_fdt_setprop_cells(fdt, "/htif", "reg",
+ 0x0, memmap[SPIKE_HTIF].base, 0x0, memmap[SPIKE_HTIF].size);
+ }
qemu_fdt_add_subnode(fdt, "/soc");
qemu_fdt_setprop(fdt, "/soc", "ranges", NULL, 0);
qemu_fdt_add_subnode(fdt, "/cpus");
qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
- SIFIVE_CLINT_TIMEBASE_FREQ);
+ RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ);
qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
qemu_fdt_add_subnode(fdt, "/cpus/cpu-map");
(memmap[SPIKE_CLINT].size * socket);
clint_name = g_strdup_printf("/soc/clint@%lx", clint_addr);
qemu_fdt_add_subnode(fdt, clint_name);
- qemu_fdt_setprop_string(fdt, clint_name, "compatible", "riscv,clint0");
+ qemu_fdt_setprop_string_array(fdt, clint_name, "compatible",
+ (char **)&clint_compat, ARRAY_SIZE(clint_compat));
qemu_fdt_setprop_cells(fdt, clint_name, "reg",
0x0, clint_addr, 0x0, memmap[SPIKE_CLINT].size);
qemu_fdt_setprop(fdt, clint_name, "interrupts-extended",
riscv_socket_fdt_write_distance_matrix(mc, fdt);
- if (cmdline) {
- qemu_fdt_add_subnode(fdt, "/chosen");
+ qemu_fdt_add_subnode(fdt, "/chosen");
+ qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", "/htif");
+
+ if (cmdline && *cmdline) {
qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
}
}
+static bool spike_test_elf_image(char *filename)
+{
+ Error *err = NULL;
+
+ load_elf_hdr(filename, NULL, NULL, &err);
+ if (err) {
+ error_free(err);
+ return false;
+ } else {
+ return true;
+ }
+}
+
static void spike_board_init(MachineState *machine)
{
- const struct MemmapEntry *memmap = spike_memmap;
+ const MemMapEntry *memmap = spike_memmap;
SpikeState *s = SPIKE_MACHINE(machine);
MemoryRegion *system_memory = get_system_memory();
- MemoryRegion *main_mem = g_new(MemoryRegion, 1);
MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
- target_ulong firmware_end_addr, kernel_start_addr;
+ target_ulong firmware_end_addr = memmap[SPIKE_DRAM].base;
+ target_ulong kernel_start_addr;
+ char *firmware_name;
uint32_t fdt_load_addr;
uint64_t kernel_entry;
char *soc_name;
int i, base_hartid, hart_count;
+ bool htif_custom_base = false;
/* Check socket count limit */
if (SPIKE_SOCKETS_MAX < riscv_socket_count(machine)) {
base_hartid, &error_abort);
object_property_set_int(OBJECT(&s->soc[i]), "num-harts",
hart_count, &error_abort);
- sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_abort);
+ sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_fatal);
/* Core Local Interruptor (timer and IPI) for each socket */
- sifive_clint_create(
+ riscv_aclint_swi_create(
memmap[SPIKE_CLINT].base + i * memmap[SPIKE_CLINT].size,
- memmap[SPIKE_CLINT].size, base_hartid, hart_count,
- SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
- SIFIVE_CLINT_TIMEBASE_FREQ, false);
+ base_hartid, hart_count, false);
+ riscv_aclint_mtimer_create(
+ memmap[SPIKE_CLINT].base + i * memmap[SPIKE_CLINT].size +
+ RISCV_ACLINT_SWI_SIZE,
+ RISCV_ACLINT_DEFAULT_MTIMER_SIZE, base_hartid, hart_count,
+ RISCV_ACLINT_DEFAULT_MTIMECMP, RISCV_ACLINT_DEFAULT_MTIME,
+ RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, false);
}
/* register system main memory (actual RAM) */
- memory_region_init_ram(main_mem, NULL, "riscv.spike.ram",
- machine->ram_size, &error_fatal);
memory_region_add_subregion(system_memory, memmap[SPIKE_DRAM].base,
- main_mem);
-
- /* create device tree */
- create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline,
- riscv_is_32bit(s->soc[0]));
+ machine->ram);
/* boot rom */
memory_region_init_rom(mask_rom, NULL, "riscv.spike.mrom",
memory_region_add_subregion(system_memory, memmap[SPIKE_MROM].base,
mask_rom);
+ /* Find firmware */
+ firmware_name = riscv_find_firmware(machine->firmware,
+ riscv_default_firmware_name(&s->soc[0]));
+
/*
- * Not like other RISC-V machines that use plain binary bios images,
- * keeping ELF files here was intentional because BIN files don't work
- * for the Spike machine as HTIF emulation depends on ELF parsing.
+ * Test the given firmware or kernel file to see if it is an ELF image.
+ * If it is an ELF, we assume it contains the symbols required for
+ * the HTIF console, otherwise we fall back to use the custom base
+ * passed from device tree for the HTIF console.
*/
- if (riscv_is_32bit(s->soc[0])) {
- firmware_end_addr = riscv_find_and_load_firmware(machine,
- "opensbi-riscv32-generic-fw_dynamic.elf",
- memmap[SPIKE_DRAM].base,
- htif_symbol_callback);
+ if (!firmware_name && !machine->kernel_filename) {
+ htif_custom_base = true;
} else {
- firmware_end_addr = riscv_find_and_load_firmware(machine,
- "opensbi-riscv64-generic-fw_dynamic.elf",
- memmap[SPIKE_DRAM].base,
- htif_symbol_callback);
+ if (firmware_name) {
+ htif_custom_base = !spike_test_elf_image(firmware_name);
+ }
+ if (!htif_custom_base && machine->kernel_filename) {
+ htif_custom_base = !spike_test_elf_image(machine->kernel_filename);
+ }
+ }
+
+ /* Load firmware */
+ if (firmware_name) {
+ firmware_end_addr = riscv_load_firmware(firmware_name,
+ memmap[SPIKE_DRAM].base,
+ htif_symbol_callback);
+ g_free(firmware_name);
}
+ /* Load kernel */
if (machine->kernel_filename) {
- kernel_start_addr = riscv_calc_kernel_start_addr(s->soc[0],
+ kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc[0],
firmware_end_addr);
kernel_entry = riscv_load_kernel(machine->kernel_filename,
kernel_start_addr,
htif_symbol_callback);
-
- if (machine->initrd_filename) {
- hwaddr start;
- hwaddr end = riscv_load_initrd(machine->initrd_filename,
- machine->ram_size, kernel_entry,
- &start);
- qemu_fdt_setprop_cell(s->fdt, "/chosen",
- "linux,initrd-start", start);
- qemu_fdt_setprop_cell(s->fdt, "/chosen", "linux,initrd-end",
- end);
- }
} else {
/*
* If dynamic firmware is used, it doesn't know where is the next mode
kernel_entry = 0;
}
+ /* Create device tree */
+ create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline,
+ riscv_is_32bit(&s->soc[0]), htif_custom_base);
+
+ /* Load initrd */
+ if (machine->kernel_filename && machine->initrd_filename) {
+ hwaddr start;
+ hwaddr end = riscv_load_initrd(machine->initrd_filename,
+ machine->ram_size, kernel_entry,
+ &start);
+ qemu_fdt_setprop_cell(s->fdt, "/chosen",
+ "linux,initrd-start", start);
+ qemu_fdt_setprop_cell(s->fdt, "/chosen", "linux,initrd-end",
+ end);
+ }
+
/* Compute the fdt load address in dram */
fdt_load_addr = riscv_load_fdt(memmap[SPIKE_DRAM].base,
machine->ram_size, s->fdt);
+
+ /* Set machine->fdt for 'dumpdtb' QMP/HMP command */
+ machine->fdt = s->fdt;
+
/* load the reset vector */
- riscv_setup_rom_reset_vec(machine, s->soc[0], memmap[SPIKE_DRAM].base,
+ riscv_setup_rom_reset_vec(machine, &s->soc[0], memmap[SPIKE_DRAM].base,
memmap[SPIKE_MROM].base,
memmap[SPIKE_MROM].size, kernel_entry,
- fdt_load_addr, s->fdt);
+ fdt_load_addr);
/* initialize HTIF using symbols found in load_kernel */
- htif_mm_init(system_memory, mask_rom,
- &s->soc[0].harts[0].env, serial_hd(0));
+ htif_mm_init(system_memory, serial_hd(0), memmap[SPIKE_HTIF].base,
+ htif_custom_base);
}
static void spike_machine_instance_init(Object *obj)
mc->cpu_index_to_instance_props = riscv_numa_cpu_index_to_props;
mc->get_default_cpu_node_id = riscv_numa_get_default_cpu_node_id;
mc->numa_mem_supported = true;
+ mc->default_ram_id = "riscv.spike.ram";
}
static const TypeInfo spike_machine_typeinfo = {