*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "qemu/datadir.h"
#include "qemu/units.h"
#include "qemu/error-report.h"
#include "elf.h"
#include "sysemu/device_tree.h"
#include "sysemu/qtest.h"
+#include "sysemu/kvm.h"
#include <libfdt.h>
-bool riscv_is_32bit(RISCVHartArrayState harts)
+bool riscv_is_32bit(RISCVHartArrayState *harts)
{
- RISCVCPU hart = harts.harts[0];
+ return harts->harts[0].env.misa_mxl_max == MXL_RV32;
+}
+
+/*
+ * Return the per-socket PLIC hart topology configuration string
+ * (caller must free with g_free())
+ */
+char *riscv_plic_hart_config_string(int hart_count)
+{
+ g_autofree const char **vals = g_new(const char *, hart_count + 1);
+ int i;
+
+ for (i = 0; i < hart_count; i++) {
+ CPUState *cs = qemu_get_cpu(i);
+ CPURISCVState *env = &RISCV_CPU(cs)->env;
+
+ if (kvm_enabled()) {
+ vals[i] = "S";
+ } else if (riscv_has_ext(env, RVS)) {
+ vals[i] = "MS";
+ } else {
+ vals[i] = "M";
+ }
+ }
+ vals[i] = NULL;
- return riscv_cpu_is_32bit(&hart.env);
+ /* g_strjoinv() obliges us to cast away const here */
+ return g_strjoinv(",", (char **)vals);
}
-target_ulong riscv_calc_kernel_start_addr(RISCVHartArrayState harts,
+target_ulong riscv_calc_kernel_start_addr(RISCVHartArrayState *harts,
target_ulong firmware_end_addr) {
if (riscv_is_32bit(harts)) {
return QEMU_ALIGN_UP(firmware_end_addr, 4 * MiB);
target_ulong kernel_start_addr,
symbol_fn_t sym_cb)
{
- uint64_t kernel_entry;
+ uint64_t kernel_load_base, kernel_entry;
+ /*
+ * NB: Use low address not ELF entry point to ensure that the fw_dynamic
+ * behaviour when loading an ELF matches the fw_payload, fw_jump and BBL
+ * behaviour, as well as fw_dynamic with a raw binary, all of which jump to
+ * the (expected) load address load address. This allows kernels to have
+ * separate SBI and ELF entry points (used by FreeBSD, for example).
+ */
if (load_elf_ram_sym(kernel_filename, NULL, NULL, NULL,
- &kernel_entry, NULL, NULL, NULL, 0,
+ NULL, &kernel_load_base, NULL, NULL, 0,
EM_RISCV, 1, 0, NULL, true, sym_cb) > 0) {
- return kernel_entry;
+ return kernel_load_base;
}
if (load_uimage_as(kernel_filename, &kernel_entry, NULL, NULL,
{
uint32_t temp, fdt_addr;
hwaddr dram_end = dram_base + mem_size;
- int fdtsize = fdt_totalsize(fdt);
+ int ret, fdtsize = fdt_totalsize(fdt);
if (fdtsize <= 0) {
error_report("invalid device-tree");
temp = MIN(dram_end, 3072 * MiB);
fdt_addr = QEMU_ALIGN_DOWN(temp - fdtsize, 16 * MiB);
- fdt_pack(fdt);
+ ret = fdt_pack(fdt);
+ /* Should only fail if we've built a corrupted tree */
+ g_assert(ret == 0);
/* copy in the device tree */
qemu_fdt_dumpdtb(fdt, fdtsize);
&address_space_memory);
}
-void riscv_setup_rom_reset_vec(MachineState *machine, RISCVHartArrayState harts,
+void riscv_setup_rom_reset_vec(MachineState *machine, RISCVHartArrayState *harts,
hwaddr start_addr,
hwaddr rom_base, hwaddr rom_size,
uint64_t kernel_entry,
return;
}
+
+void riscv_setup_direct_kernel(hwaddr kernel_addr, hwaddr fdt_addr)
+{
+ CPUState *cs;
+
+ for (cs = first_cpu; cs; cs = CPU_NEXT(cs)) {
+ RISCVCPU *riscv_cpu = RISCV_CPU(cs);
+ riscv_cpu->env.kernel_addr = kernel_addr;
+ riscv_cpu->env.fdt_addr = fdt_addr;
+ }
+}