mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/riscv/tags/riscv-for-master-3.1-sf0' into staging
First RISC-V Patch Set for the 3.1 Soft Freeze This pull request contains a handful of patches that have been floating around various trees for a while but haven't made it upstream. These patches all appear quite safe. They're all somewhat independent from each other: * One refactors our IRQ management function to allow multiple interrupts to be raised an once. This patch has no functional difference. * Cleaning up the op_helper/cpu_helper split. This patch has no functional difference. * Updates to various constants to keep them in sync with the latest ISA specification and to remove some non-standard bits that snuck in. * A fix for a memory leak in the PLIC driver. * A fix to our device tree handling to avoid provinging a NULL string. I've given this my standard test: building the port, booting a Fedora root filesytem on the latest Linux tag, and then shutting down that image. Essentially I'm just following the QEMU RISC-V wiki page's instructions. Everything looks fine here. We have a lot more outstanding patches so I'll definately be submitting another PR for the soft freeze. # gpg: Signature made Wed 17 Oct 2018 21:17:52 BST # gpg: using RSA key EF4CA1502CCBAB41 # gpg: Good signature from "Palmer Dabbelt <palmer@dabbelt.com>" # gpg: aka "Palmer Dabbelt <palmer@sifive.com>" # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 00CE 76D1 8349 60DF CE88 6DF8 EF4C A150 2CCB AB41 * remotes/riscv/tags/riscv-for-master-3.1-sf0: RISC-V: Don't add NULL bootargs to device-tree RISC-V: Add missing free for plic_hart_config RISC-V: Update CSR and interrupt definitions RISC-V: Move non-ops from op_helper to cpu_helper RISC-V: Allow setting and clearing multiple irqs Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -47,12 +47,12 @@ static void sifive_clint_write_timecmp(RISCVCPU *cpu, uint64_t value)
|
||||
if (cpu->env.timecmp <= rtc_r) {
|
||||
/* if we're setting an MTIMECMP value in the "past",
|
||||
immediately raise the timer interrupt */
|
||||
riscv_set_local_interrupt(cpu, MIP_MTIP, 1);
|
||||
riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
|
||||
return;
|
||||
}
|
||||
|
||||
/* otherwise, set up the future timer interrupt */
|
||||
riscv_set_local_interrupt(cpu, MIP_MTIP, 0);
|
||||
riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(0));
|
||||
diff = cpu->env.timecmp - rtc_r;
|
||||
/* back to ns (note args switched in muldiv64) */
|
||||
next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
|
||||
@@ -67,7 +67,7 @@ static void sifive_clint_write_timecmp(RISCVCPU *cpu, uint64_t value)
|
||||
static void sifive_clint_timer_cb(void *opaque)
|
||||
{
|
||||
RISCVCPU *cpu = opaque;
|
||||
riscv_set_local_interrupt(cpu, MIP_MTIP, 1);
|
||||
riscv_cpu_update_mip(cpu, MIP_MTIP, BOOL_TO_MASK(1));
|
||||
}
|
||||
|
||||
/* CPU wants to read rtc or timecmp register */
|
||||
@@ -132,7 +132,7 @@ static void sifive_clint_write(void *opaque, hwaddr addr, uint64_t value,
|
||||
if (!env) {
|
||||
error_report("clint: invalid timecmp hartid: %zu", hartid);
|
||||
} else if ((addr & 0x3) == 0) {
|
||||
riscv_set_local_interrupt(RISCV_CPU(cpu), MIP_MSIP, value != 0);
|
||||
riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MSIP, BOOL_TO_MASK(value));
|
||||
} else {
|
||||
error_report("clint: invalid sip write: %08x", (uint32_t)addr);
|
||||
}
|
||||
|
||||
@@ -142,10 +142,10 @@ static void sifive_plic_update(SiFivePLICState *plic)
|
||||
int level = sifive_plic_irqs_pending(plic, addrid);
|
||||
switch (mode) {
|
||||
case PLICMode_M:
|
||||
riscv_set_local_interrupt(RISCV_CPU(cpu), MIP_MEIP, level);
|
||||
riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MEIP, BOOL_TO_MASK(level));
|
||||
break;
|
||||
case PLICMode_S:
|
||||
riscv_set_local_interrupt(RISCV_CPU(cpu), MIP_SEIP, level);
|
||||
riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_SEIP, BOOL_TO_MASK(level));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
+3
-1
@@ -230,7 +230,9 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
|
||||
|
||||
qemu_fdt_add_subnode(fdt, "/chosen");
|
||||
qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", nodename);
|
||||
qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
|
||||
if (cmdline) {
|
||||
qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
|
||||
}
|
||||
g_free(nodename);
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -156,8 +156,10 @@ static void create_fdt(SpikeState *s, const struct MemmapEntry *memmap,
|
||||
g_free(cells);
|
||||
g_free(nodename);
|
||||
|
||||
qemu_fdt_add_subnode(fdt, "/chosen");
|
||||
qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
|
||||
if (cmdline) {
|
||||
qemu_fdt_add_subnode(fdt, "/chosen");
|
||||
qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
|
||||
}
|
||||
}
|
||||
|
||||
static void spike_v1_10_0_board_init(MachineState *machine)
|
||||
|
||||
+5
-1
@@ -254,7 +254,9 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
|
||||
|
||||
qemu_fdt_add_subnode(fdt, "/chosen");
|
||||
qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", nodename);
|
||||
qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
|
||||
if (cmdline) {
|
||||
qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
|
||||
}
|
||||
g_free(nodename);
|
||||
|
||||
return fdt;
|
||||
@@ -385,6 +387,8 @@ static void riscv_virt_board_init(MachineState *machine)
|
||||
serial_mm_init(system_memory, memmap[VIRT_UART0].base,
|
||||
0, qdev_get_gpio_in(DEVICE(s->plic), UART0_IRQ), 399193,
|
||||
serial_hd(0), DEVICE_LITTLE_ENDIAN);
|
||||
|
||||
g_free(plic_hart_config);
|
||||
}
|
||||
|
||||
static void riscv_virt_board_machine_init(MachineClass *mc)
|
||||
|
||||
@@ -1 +1 @@
|
||||
obj-y += translate.o op_helper.o helper.o cpu.o fpu_helper.o gdbstub.o pmp.o
|
||||
obj-y += translate.o op_helper.o cpu_helper.o cpu.o fpu_helper.o gdbstub.o pmp.o
|
||||
|
||||
+4
-2
@@ -74,8 +74,10 @@ const char * const riscv_intr_names[] = {
|
||||
"s_external",
|
||||
"h_external",
|
||||
"m_external",
|
||||
"coprocessor",
|
||||
"host"
|
||||
"reserved",
|
||||
"reserved",
|
||||
"reserved",
|
||||
"reserved"
|
||||
};
|
||||
|
||||
typedef struct RISCVCPUInfo {
|
||||
|
||||
+13
-9
@@ -126,13 +126,18 @@ struct CPURISCVState {
|
||||
|
||||
target_ulong mhartid;
|
||||
target_ulong mstatus;
|
||||
|
||||
/*
|
||||
* CAUTION! Unlike the rest of this struct, mip is accessed asynchonously
|
||||
* by I/O threads and other vCPUs, so hold the iothread mutex before
|
||||
* operating on it. CPU_INTERRUPT_HARD should be in effect iff this is
|
||||
* non-zero. Use riscv_cpu_set_local_interrupt.
|
||||
* by I/O threads. It should be read with atomic_read. It should be updated
|
||||
* using riscv_cpu_update_mip with the iothread mutex held. The iothread
|
||||
* mutex must be held because mip must be consistent with the CPU inturrept
|
||||
* state. riscv_cpu_update_mip calls cpu_interrupt or cpu_reset_interrupt
|
||||
* wuth the invariant that CPU_INTERRUPT_HARD is set iff mip is non-zero.
|
||||
* mip is 32-bits to allow atomic_read on 32-bit hosts.
|
||||
*/
|
||||
uint32_t mip; /* allow atomic_read for >= 32-bit hosts */
|
||||
uint32_t mip;
|
||||
|
||||
target_ulong mie;
|
||||
target_ulong mideleg;
|
||||
|
||||
@@ -247,7 +252,6 @@ void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
|
||||
uintptr_t retaddr);
|
||||
int riscv_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int size,
|
||||
int rw, int mmu_idx);
|
||||
|
||||
char *riscv_isa_string(RISCVCPU *cpu);
|
||||
void riscv_cpu_list(FILE *f, fprintf_function cpu_fprintf);
|
||||
|
||||
@@ -255,6 +259,10 @@ void riscv_cpu_list(FILE *f, fprintf_function cpu_fprintf);
|
||||
#define cpu_list riscv_cpu_list
|
||||
#define cpu_mmu_index riscv_cpu_mmu_index
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value);
|
||||
#define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */
|
||||
#endif
|
||||
void riscv_set_mode(CPURISCVState *env, target_ulong newpriv);
|
||||
|
||||
void riscv_translate_init(void);
|
||||
@@ -285,10 +293,6 @@ void csr_write_helper(CPURISCVState *env, target_ulong val_to_write,
|
||||
target_ulong csrno);
|
||||
target_ulong csr_read_helper(CPURISCVState *env, target_ulong csrno);
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
void riscv_set_local_interrupt(RISCVCPU *cpu, target_ulong mask, int value);
|
||||
#endif
|
||||
|
||||
#include "exec/cpu-all.h"
|
||||
|
||||
#endif /* RISCV_CPU_H */
|
||||
|
||||
+358
-311
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* RISC-V emulation helpers for qemu.
|
||||
* RISC-V CPU helpers for qemu.
|
||||
*
|
||||
* Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
|
||||
* Copyright (c) 2017-2018 SiFive, Inc.
|
||||
@@ -72,6 +72,39 @@ bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
||||
/* iothread_mutex must be held */
|
||||
uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value)
|
||||
{
|
||||
CPURISCVState *env = &cpu->env;
|
||||
uint32_t old, new, cmp = atomic_read(&env->mip);
|
||||
|
||||
do {
|
||||
old = cmp;
|
||||
new = (old & ~mask) | (value & mask);
|
||||
cmp = atomic_cmpxchg(&env->mip, old, new);
|
||||
} while (old != cmp);
|
||||
|
||||
if (new && !old) {
|
||||
cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
|
||||
} else if (!new && old) {
|
||||
cpu_reset_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
|
||||
}
|
||||
|
||||
return old;
|
||||
}
|
||||
|
||||
void riscv_set_mode(CPURISCVState *env, target_ulong newpriv)
|
||||
{
|
||||
if (newpriv > PRV_M) {
|
||||
g_assert_not_reached();
|
||||
}
|
||||
if (newpriv == PRV_H) {
|
||||
newpriv = PRV_U;
|
||||
}
|
||||
/* tlb_flush is unnecessary as mode is contained in mmu_idx */
|
||||
env->priv = newpriv;
|
||||
}
|
||||
|
||||
/* get_physical_address - get the physical address for this virtual address
|
||||
*
|
||||
* Do a page table walk to obtain the physical address corresponding to a
|
||||
@@ -90,7 +90,7 @@ void csr_write_helper(CPURISCVState *env, target_ulong val_to_write,
|
||||
target_ulong csrno)
|
||||
{
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
uint64_t delegable_ints = MIP_SSIP | MIP_STIP | MIP_SEIP | (1 << IRQ_X_COP);
|
||||
uint64_t delegable_ints = MIP_SSIP | MIP_STIP | MIP_SEIP;
|
||||
uint64_t all_ints = delegable_ints | MIP_MSIP | MIP_MTIP;
|
||||
#endif
|
||||
|
||||
@@ -171,10 +171,8 @@ void csr_write_helper(CPURISCVState *env, target_ulong val_to_write,
|
||||
*/
|
||||
qemu_mutex_lock_iothread();
|
||||
RISCVCPU *cpu = riscv_env_get_cpu(env);
|
||||
riscv_set_local_interrupt(cpu, MIP_SSIP,
|
||||
(val_to_write & MIP_SSIP) != 0);
|
||||
riscv_set_local_interrupt(cpu, MIP_STIP,
|
||||
(val_to_write & MIP_STIP) != 0);
|
||||
riscv_cpu_update_mip(cpu, MIP_SSIP | MIP_STIP,
|
||||
(val_to_write & (MIP_SSIP | MIP_STIP)));
|
||||
/*
|
||||
* csrs, csrc on mip.SEIP is not decomposable into separate read and
|
||||
* write steps, so a different implementation is needed
|
||||
@@ -656,31 +654,6 @@ target_ulong helper_csrrc(CPURISCVState *env, target_ulong src,
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
||||
/* iothread_mutex must be held */
|
||||
void riscv_set_local_interrupt(RISCVCPU *cpu, target_ulong mask, int value)
|
||||
{
|
||||
target_ulong old_mip = cpu->env.mip;
|
||||
cpu->env.mip = (old_mip & ~mask) | (value ? mask : 0);
|
||||
|
||||
if (cpu->env.mip && !old_mip) {
|
||||
cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
|
||||
} else if (!cpu->env.mip && old_mip) {
|
||||
cpu_reset_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
|
||||
}
|
||||
}
|
||||
|
||||
void riscv_set_mode(CPURISCVState *env, target_ulong newpriv)
|
||||
{
|
||||
if (newpriv > PRV_M) {
|
||||
g_assert_not_reached();
|
||||
}
|
||||
if (newpriv == PRV_H) {
|
||||
newpriv = PRV_U;
|
||||
}
|
||||
/* tlb_flush is unnecessary as mode is contained in mmu_idx */
|
||||
env->priv = newpriv;
|
||||
}
|
||||
|
||||
target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
|
||||
{
|
||||
if (!(env->priv >= PRV_S)) {
|
||||
@@ -731,7 +704,6 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
|
||||
return retpc;
|
||||
}
|
||||
|
||||
|
||||
void helper_wfi(CPURISCVState *env)
|
||||
{
|
||||
CPUState *cs = CPU(riscv_env_get_cpu(env));
|
||||
|
||||
Reference in New Issue
Block a user