Re: [PULL 1/1] target/openrisc: Set EPCR to next PC on FPE exceptions
On Thu, Aug 10, 2023 at 09:35:18AM +0300, Michael Tokarev wrote: > 09.08.2023 23:34, Stafford Horne пишет: > > The architecture specification calls for the EPCR to be set to "Address > > of next not executed instruction" when there is a floating point > > exception (FPE). This was not being done, so fix it by using the same > > pattern as syscall. Also, we move this logic down to be done for > > instructions not in the delay slot as called for by the architecture > > manual. > > > > Without this patch FPU exceptions will loop, as the exception handling > > will always return back to the failed floating point instruction. > > > > This was not noticed in earlier testing because: > > > > 1. The compiler usually generates code which clobbers the input operand > > such as: > > > >lf.div.s r19,r17,r19 > > > > 2. The target will store the operation output before to the register > > before handling the exception. So an operation such as: > > > >float a = 100.0f; > >float b = 0.0f; > >float c = a / b;/* lf.div.s r19,r17,r19 */ > > > > Will first execute: > > > >100 / 0-> Store inf to c (r19) > > -> triggering divide by zero exception > > -> handle and return > > > > Then it will execute: > > > >100 / inf -> Store 0 to c (no exception) > > > > To confirm the looping behavior and the fix I used the following: > > > > float fpu_div(float a, float b) { > > float c; > > asm volatile("lf.div.s %0, %1, %2" > > : "+r" (c) > > : "r" (a), "r" (b)); > > return c; > > } > > Is it a -stable material? It applies cleanly to 8.0 and 7.2. > Or maybe it is not needed on older versions, not being noticed before? I would say no, it will work on 8.0 an 7.2 but this code path is not very useful withouth the other 8.1 Floating Point Exception handling updates. -Stafford
[PULL 0/1] OpenRISC FPU Fix for 8.1
The following changes since commit ccdd31267678db9d80578b5f80bbe94141609ef4: Merge tag 'pull-qapi-2023-07-26-v2' of https://repo.or.cz/qemu/armbru into staging (2023-07-26 07:16:19 -0700) are available in the Git repository at: https://github.com/stffrdhrn/qemu.git tags/or1k-pull-request-20230809 for you to fetch changes up to 765fdc1e8355d4bae563b3b185c5f9d079384164: target/openrisc: Set EPCR to next PC on FPE exceptions (2023-07-31 22:01:03 +0100) OpenRISC FPU Fix for 8.1 A patch to pass the correct exception address when handling floating point exceptions. Stafford Horne (1): target/openrisc: Set EPCR to next PC on FPE exceptions target/openrisc/interrupt.c | 7 --- 1 file changed, 4 insertions(+), 3 deletions(-)
[PULL 1/1] target/openrisc: Set EPCR to next PC on FPE exceptions
The architecture specification calls for the EPCR to be set to "Address of next not executed instruction" when there is a floating point exception (FPE). This was not being done, so fix it by using the same pattern as syscall. Also, we move this logic down to be done for instructions not in the delay slot as called for by the architecture manual. Without this patch FPU exceptions will loop, as the exception handling will always return back to the failed floating point instruction. This was not noticed in earlier testing because: 1. The compiler usually generates code which clobbers the input operand such as: lf.div.s r19,r17,r19 2. The target will store the operation output before to the register before handling the exception. So an operation such as: float a = 100.0f; float b = 0.0f; float c = a / b;/* lf.div.s r19,r17,r19 */ Will first execute: 100 / 0-> Store inf to c (r19) -> triggering divide by zero exception -> handle and return Then it will execute: 100 / inf -> Store 0 to c (no exception) To confirm the looping behavior and the fix I used the following: float fpu_div(float a, float b) { float c; asm volatile("lf.div.s %0, %1, %2" : "+r" (c) : "r" (a), "r" (b)); return c; } Reviewed-by: Richard Henderson Signed-off-by: Stafford Horne --- target/openrisc/interrupt.c | 7 --- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/target/openrisc/interrupt.c b/target/openrisc/interrupt.c index 3887812810..d4fdb8ce8e 100644 --- a/target/openrisc/interrupt.c +++ b/target/openrisc/interrupt.c @@ -34,9 +34,7 @@ void openrisc_cpu_do_interrupt(CPUState *cs) int exception = cs->exception_index; env->epcr = env->pc; -if (exception == EXCP_SYSCALL) { -env->epcr += 4; -} + /* When we have an illegal instruction the error effective address shall be set to the illegal instruction address. */ if (exception == EXCP_ILLEGAL) { @@ -63,6 +61,9 @@ void openrisc_cpu_do_interrupt(CPUState *cs) env->epcr -= 4; } else { env->sr &= ~SR_DSX; +if (exception == EXCP_SYSCALL || exception == EXCP_FPE) { +env->epcr += 4; +} } if (exception > 0 && exception < EXCP_NR) { -- 2.39.1
[PATCH v2] target/openrisc: Set EPCR to next PC on FPE exceptions
The architecture specification calls for the EPCR to be set to "Address of next not executed instruction" when there is a floating point exception (FPE). This was not being done, so fix it by using the same pattern as syscall. Also, we move this logic down to be done for instructions not in the delay slot as called for by the architecture manual. Without this patch FPU exceptions will loop, as the exception handling will always return back to the failed floating point instruction. This was not noticed in earlier testing because: 1. The compiler usually generates code which clobbers the input operand such as: lf.div.s r19,r17,r19 2. The target will store the operation output before to the register before handling the exception. So an operation such as: float a = 100.0f; float b = 0.0f; float c = a / b;/* lf.div.s r19,r17,r19 */ Will first execute: 100 / 0-> Store inf to c (r19) -> triggering divide by zero exception -> handle and return Then it will execute: 100 / inf -> Store 0 to c (no exception) To confirm the looping behavior and the fix I used the following: float fpu_div(float a, float b) { float c; asm volatile("lf.div.s %0, %1, %2" : "+r" (c) : "r" (a), "r" (b)); return c; } Reviewed-by: Richard Henderson Signed-off-by: Stafford Horne --- target/openrisc/interrupt.c | 7 --- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/target/openrisc/interrupt.c b/target/openrisc/interrupt.c index 3887812810..d4fdb8ce8e 100644 --- a/target/openrisc/interrupt.c +++ b/target/openrisc/interrupt.c @@ -34,9 +34,7 @@ void openrisc_cpu_do_interrupt(CPUState *cs) int exception = cs->exception_index; env->epcr = env->pc; -if (exception == EXCP_SYSCALL) { -env->epcr += 4; -} + /* When we have an illegal instruction the error effective address shall be set to the illegal instruction address. */ if (exception == EXCP_ILLEGAL) { @@ -63,6 +61,9 @@ void openrisc_cpu_do_interrupt(CPUState *cs) env->epcr -= 4; } else { env->sr &= ~SR_DSX; +if (exception == EXCP_SYSCALL || exception == EXCP_FPE) { +env->epcr += 4; +} } if (exception > 0 && exception < EXCP_NR) { -- 2.39.1
Re: [PATCH] target/openrisc: Set EPCR to next PC on FPE exceptions
On Sun, Jul 30, 2023 at 10:43:45AM -0700, Richard Henderson wrote: > On 7/29/23 14:08, Stafford Horne wrote: > > The architecture specification calls for the EPCR to be set to "Address > > of next not executed instruction" when there is a floating point > > exception (FPE). This was not being done, so fix it by using the same > > method as syscall. Note, this may need a lot more work if we start > > seeing floating point operations in delay slots which exceptions > > enabled. > > > > Without this patch FPU exceptions will loop, as the exception hanlding > > will always return back to the failed floating point instruction. > > > > This was not noticed in earlier testing because: > > > > 1. The compiler usually generates code which clobbers the input operand > > such as: > > > >lf.div.s r19,r17,r19 > > > > 2. The target will store the operation output before to the register > > before handling the exception. So an operation such as: > > > >float a = 100.0f; > >float b = 0.0f; > >float c = a / b;/* lf.div.s r19,r17,r19 */ > > > > Will first execute: > > > >100 / 0-> Store inf to c (r19) > > -> triggering divide by zero exception > > -> handle and return > > > > Then it will exectute: > > > >100 / inf -> Store 0 to c (no exception) > > > > To confirm the looping behavoid and the fix I used the following: > > > > float fpu_div(float a, float b) { > > float c; > > asm volatile("lf.div.s %0, %1, %2" > > : "+r" (c) > > : "r" (a), "r" (b)); > > return c; > > } > > > > Signed-off-by: Stafford Horne > > --- > > target/openrisc/interrupt.c | 2 +- > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > > diff --git a/target/openrisc/interrupt.c b/target/openrisc/interrupt.c > > index 3887812810..9b14b8a2c6 100644 > > --- a/target/openrisc/interrupt.c > > +++ b/target/openrisc/interrupt.c > > @@ -34,7 +34,7 @@ void openrisc_cpu_do_interrupt(CPUState *cs) > > int exception = cs->exception_index; > > env->epcr = env->pc; > > -if (exception == EXCP_SYSCALL) { > > +if (exception == EXCP_SYSCALL || exception == EXCP_FPE) { > > env->epcr += 4; > > } > > /* When we have an illegal instruction the error effective address > > According to Table 6-3, when in a delay slot the EPCR should be the address > of the jump, for both syscall and fpe. This whole block should be moved > down... > > > /* Set/clear dsx to indicate if we are in a delay slot exception. */ > > if (env->dflag) { > > env->dflag = 0; > > env->sr |= SR_DSX; > > env->epcr -= 4; > > } else { > > env->sr &= ~SR_DSX; > > } > > ... into the else. Thanks for looking at this. This is correct. I will fix it this way, though this points to an issue in the architecture (in the manual as "Particular delay slot issues"). If we have instructions causing exceptions in delay slots like l.sys it will cause looping. > With that, > Reviewed-by: Richard Henderson Thank you. -Stafford
Re: [PATCH] target/openrisc: Set EPCR to next PC on FPE exceptions
On Sat, Jul 29, 2023 at 10:08:51PM +0100, Stafford Horne wrote: > The architecture specification calls for the EPCR to be set to "Address > of next not executed instruction" when there is a floating point > exception (FPE). This was not being done, so fix it by using the same > method as syscall. Note, this may need a lot more work if we start > seeing floating point operations in delay slots which exceptions > enabled. It should be "with exceptions enabled." > > Without this patch FPU exceptions will loop, as the exception hanlding "handling" > will always return back to the failed floating point instruction. > > This was not noticed in earlier testing because: > > 1. The compiler usually generates code which clobbers the input operand > such as: > > lf.div.s r19,r17,r19 > > 2. The target will store the operation output before to the register > before handling the exception. So an operation such as: > > float a = 100.0f; > float b = 0.0f; > float c = a / b;/* lf.div.s r19,r17,r19 */ > > Will first execute: > > 100 / 0-> Store inf to c (r19) > -> triggering divide by zero exception > -> handle and return > > Then it will exectute: > > 100 / inf -> Store 0 to c (no exception) > > To confirm the looping behavoid and the fix I used the following: "behavior" > float fpu_div(float a, float b) { > float c; > asm volatile("lf.div.s %0, %1, %2" > : "+r" (c) > : "r" (a), "r" (b)); > return c; > } > > Signed-off-by: Stafford Horne -Stafford > --- > target/openrisc/interrupt.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/target/openrisc/interrupt.c b/target/openrisc/interrupt.c > index 3887812810..9b14b8a2c6 100644 > --- a/target/openrisc/interrupt.c > +++ b/target/openrisc/interrupt.c > @@ -34,7 +34,7 @@ void openrisc_cpu_do_interrupt(CPUState *cs) > int exception = cs->exception_index; > > env->epcr = env->pc; > -if (exception == EXCP_SYSCALL) { > +if (exception == EXCP_SYSCALL || exception == EXCP_FPE) { > env->epcr += 4; > } > /* When we have an illegal instruction the error effective address > -- > 2.39.1 >
[PATCH] target/openrisc: Set EPCR to next PC on FPE exceptions
The architecture specification calls for the EPCR to be set to "Address of next not executed instruction" when there is a floating point exception (FPE). This was not being done, so fix it by using the same method as syscall. Note, this may need a lot more work if we start seeing floating point operations in delay slots which exceptions enabled. Without this patch FPU exceptions will loop, as the exception hanlding will always return back to the failed floating point instruction. This was not noticed in earlier testing because: 1. The compiler usually generates code which clobbers the input operand such as: lf.div.s r19,r17,r19 2. The target will store the operation output before to the register before handling the exception. So an operation such as: float a = 100.0f; float b = 0.0f; float c = a / b;/* lf.div.s r19,r17,r19 */ Will first execute: 100 / 0-> Store inf to c (r19) -> triggering divide by zero exception -> handle and return Then it will exectute: 100 / inf -> Store 0 to c (no exception) To confirm the looping behavoid and the fix I used the following: float fpu_div(float a, float b) { float c; asm volatile("lf.div.s %0, %1, %2" : "+r" (c) : "r" (a), "r" (b)); return c; } Signed-off-by: Stafford Horne --- target/openrisc/interrupt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/openrisc/interrupt.c b/target/openrisc/interrupt.c index 3887812810..9b14b8a2c6 100644 --- a/target/openrisc/interrupt.c +++ b/target/openrisc/interrupt.c @@ -34,7 +34,7 @@ void openrisc_cpu_do_interrupt(CPUState *cs) int exception = cs->exception_index; env->epcr = env->pc; -if (exception == EXCP_SYSCALL) { +if (exception == EXCP_SYSCALL || exception == EXCP_FPE) { env->epcr += 4; } /* When we have an illegal instruction the error effective address -- 2.39.1
[PULL 0/3] OpenRISC FPU Updates for 8.1
The following changes since commit c1eb2ddf0f8075faddc5f7c3d39feae3e8e9d6b4: Update version for v8.0.0 release (2023-04-19 17:27:13 +0100) are available in the Git repository at: https://github.com/stffrdhrn/qemu.git tags/or1k-pull-request-20230513 for you to fetch changes up to 874c52991e1fbe020812b4b15440b6875369aacf: target/openrisc: Setup FPU for detecting tininess before rounding (2023-05-11 15:40:28 +0100) OpenRISC FPU Updates for 8.1 A few fixes and updates to bring OpenRISC inline with the latest architecture spec updates: - Allow FPCSR to be accessed in user mode - Select tininess detection before rounding - Fix FPE Exception PC value Stafford Horne (3): target/openrisc: Allow fpcsr access in user mode target/openrisc: Set PC to cpu state on FPU exception target/openrisc: Setup FPU for detecting tininess before rounding target/openrisc/cpu.c| 4 +++ target/openrisc/fpu_helper.c | 13 ++-- target/openrisc/sys_helper.c | 45 --- target/openrisc/translate.c | 72 4 files changed, 81 insertions(+), 53 deletions(-)
[PULL 3/3] target/openrisc: Setup FPU for detecting tininess before rounding
OpenRISC defines tininess to be detected before rounding. Setup qemu to obey this. Signed-off-by: Stafford Horne Reviewed-by: Richard Henderson --- target/openrisc/cpu.c | 4 1 file changed, 4 insertions(+) diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index 0ce4f796fa..61d748cfdc 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -22,6 +22,7 @@ #include "qemu/qemu-print.h" #include "cpu.h" #include "exec/exec-all.h" +#include "fpu/softfloat-helpers.h" #include "tcg/tcg.h" static void openrisc_cpu_set_pc(CPUState *cs, vaddr value) @@ -90,6 +91,9 @@ static void openrisc_cpu_reset_hold(Object *obj) s->exception_index = -1; cpu_set_fpcsr(>env, 0); +set_float_detect_tininess(float_tininess_before_rounding, + >env.fp_status); + #ifndef CONFIG_USER_ONLY cpu->env.picmr = 0x; cpu->env.picsr = 0x; -- 2.39.1
[PULL 1/3] target/openrisc: Allow fpcsr access in user mode
As per OpenRISC spec 1.4 FPCSR can be read and written in user mode. Update mtspr and mfspr helpers to support this by moving the is_user check into the helper. Link: https://raw.githubusercontent.com/openrisc/doc/master/openrisc-arch-1.4-rev0.pdf Signed-off-by: Stafford Horne Reviewed-by: Richard Henderson --- target/openrisc/sys_helper.c | 45 -- target/openrisc/translate.c | 72 2 files changed, 66 insertions(+), 51 deletions(-) diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index ec145960e3..ccdee3b8be 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -29,17 +29,37 @@ #define TO_SPR(group, number) (((group) << 11) + (number)) +static inline bool is_user(CPUOpenRISCState *env) +{ +#ifdef CONFIG_USER_ONLY +return true; +#else +return (env->sr & SR_SM) == 0; +#endif +} + void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) { -#ifndef CONFIG_USER_ONLY OpenRISCCPU *cpu = env_archcpu(env); +#ifndef CONFIG_USER_ONLY CPUState *cs = env_cpu(env); target_ulong mr; int idx; #endif +/* Handle user accessible SPRs first. */ switch (spr) { +case TO_SPR(0, 20): /* FPCSR */ +cpu_set_fpcsr(env, rb); +return; +} + +if (is_user(env)) { +raise_exception(cpu, EXCP_ILLEGAL); +} + #ifndef CONFIG_USER_ONLY +switch (spr) { case TO_SPR(0, 11): /* EVBAR */ env->evbar = rb; break; @@ -187,27 +207,33 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) cpu_openrisc_timer_update(cpu); qemu_mutex_unlock_iothread(); break; -#endif - -case TO_SPR(0, 20): /* FPCSR */ -cpu_set_fpcsr(env, rb); -break; } +#endif } target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, target_ulong spr) { +OpenRISCCPU *cpu = env_archcpu(env); #ifndef CONFIG_USER_ONLY uint64_t data[TARGET_INSN_START_WORDS]; MachineState *ms = MACHINE(qdev_get_machine()); -OpenRISCCPU *cpu = env_archcpu(env); CPUState *cs = env_cpu(env); int idx; #endif +/* Handle user accessible SPRs first. */ switch (spr) { +case TO_SPR(0, 20): /* FPCSR */ +return env->fpcsr; +} + +if (is_user(env)) { +raise_exception(cpu, EXCP_ILLEGAL); +} + #ifndef CONFIG_USER_ONLY +switch (spr) { case TO_SPR(0, 0): /* VR */ return env->vr; @@ -324,11 +350,8 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, cpu_openrisc_count_update(cpu); qemu_mutex_unlock_iothread(); return cpu_openrisc_count_get(cpu); -#endif - -case TO_SPR(0, 20): /* FPCSR */ -return env->fpcsr; } +#endif /* for rd is passed in, if rd unchanged, just keep it back. */ return rd; diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 76e53c78d4..43ba0cc1ad 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -819,45 +819,12 @@ static bool trans_l_xori(DisasContext *dc, arg_rri *a) static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a) { -check_r0_write(dc, a->d); - -if (is_user(dc)) { -gen_illegal_exception(dc); -} else { -TCGv spr = tcg_temp_new(); - -if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { -gen_io_start(); -if (dc->delayed_branch) { -tcg_gen_mov_tl(cpu_pc, jmp_pc); -tcg_gen_discard_tl(jmp_pc); -} else { -tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4); -} -dc->base.is_jmp = DISAS_EXIT; -} +TCGv spr = tcg_temp_new(); -tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k); -gen_helper_mfspr(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), spr); -} -return true; -} - -static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a) -{ -if (is_user(dc)) { -gen_illegal_exception(dc); -} else { -TCGv spr; +check_r0_write(dc, a->d); -if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { -gen_io_start(); -} -/* For SR, we will need to exit the TB to recognize the new - * exception state. For NPC, in theory this counts as a branch - * (although the SPR only exists for use by an ICE). Save all - * of the cpu state first, allowing it to be overwritten. - */ +if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { +gen_io_start(); if (dc->delayed_branch) { tcg_gen_mov_tl(cpu_pc, jmp_pc); tcg_gen_discard_tl(jmp_pc); @@ -865,11 +832,36 @@ static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a) tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4); }
[PULL 2/3] target/openrisc: Set PC to cpu state on FPU exception
Store the PC to ensure the correct value can be read in the exception handler. Signed-off-by: Stafford Horne Reviewed-by: Richard Henderson --- target/openrisc/fpu_helper.c | 13 +++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/target/openrisc/fpu_helper.c b/target/openrisc/fpu_helper.c index f9e34fa2cc..8b81d2f62f 100644 --- a/target/openrisc/fpu_helper.c +++ b/target/openrisc/fpu_helper.c @@ -20,8 +20,8 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "exec/exec-all.h" #include "exec/helper-proto.h" -#include "exception.h" #include "fpu/softfloat.h" static int ieee_ex_to_openrisc(int fexcp) @@ -45,6 +45,15 @@ static int ieee_ex_to_openrisc(int fexcp) return ret; } +static G_NORETURN +void do_fpe(CPUOpenRISCState *env, uintptr_t pc) +{ +CPUState *cs = env_cpu(env); + +cs->exception_index = EXCP_FPE; +cpu_loop_exit_restore(cs, pc); +} + void HELPER(update_fpcsr)(CPUOpenRISCState *env) { int tmp = get_float_exception_flags(>fp_status); @@ -55,7 +64,7 @@ void HELPER(update_fpcsr)(CPUOpenRISCState *env) if (tmp) { env->fpcsr |= tmp; if (env->fpcsr & FPCSR_FPEE) { -helper_exception(env, EXCP_FPE); +do_fpe(env, GETPC()); } } } -- 2.39.1
[PATCH v3 3/3] target/openrisc: Setup FPU for detecting tininess before rounding
OpenRISC defines tininess to be detected before rounding. Setup qemu to obey this. Signed-off-by: Stafford Horne Reviewed-by: Richard Henderson --- Since v2: - Add reviewed-by Since v1: - Remove setting default NaN behavior. target/openrisc/cpu.c | 4 1 file changed, 4 insertions(+) diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index 0ce4f796fa..61d748cfdc 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -22,6 +22,7 @@ #include "qemu/qemu-print.h" #include "cpu.h" #include "exec/exec-all.h" +#include "fpu/softfloat-helpers.h" #include "tcg/tcg.h" static void openrisc_cpu_set_pc(CPUState *cs, vaddr value) @@ -90,6 +91,9 @@ static void openrisc_cpu_reset_hold(Object *obj) s->exception_index = -1; cpu_set_fpcsr(>env, 0); +set_float_detect_tininess(float_tininess_before_rounding, + >env.fp_status); + #ifndef CONFIG_USER_ONLY cpu->env.picmr = 0x; cpu->env.picsr = 0x; -- 2.39.1
[PATCH v3 0/3] OpenRISC updates for user space FPU
Hello, Since v2: - Add reviewed-by's from Richard - Pull cpu definition out of ifdef in helper_mfspr Since v1: - Fixups suggested by Richard Henderson This series adds support for the FPU related architecture changes defined in architecture spec revision v1.4. - https://openrisc.io/revisions/r1.4 In summary the architecture changes are: - Change FPCSR SPR permissions to allow for reading and writing from user space. - Clarify that FPU underflow detection is done by detecting tininess before rounding. Previous to this series FPCSR reads and writes from user-mode in QEMU would throw an illegal argument exception. The proper behavior should have been to treat these operations as no-ops as the cpu implementations do. As mentioned series changes FPCSR read/write to follow the spec. The series has been tested with the FPU support added in glibc test suite and all math tests are passing. Stafford Horne (3): target/openrisc: Allow fpcsr access in user mode target/openrisc: Set PC to cpu state on FPU exception target/openrisc: Setup FPU for detecting tininess before rounding target/openrisc/cpu.c| 4 ++ target/openrisc/fpu_helper.c | 13 ++- target/openrisc/sys_helper.c | 45 -- target/openrisc/translate.c | 72 4 files changed, 81 insertions(+), 53 deletions(-) -- 2.39.1
[PATCH v3 1/3] target/openrisc: Allow fpcsr access in user mode
As per OpenRISC spec 1.4 FPCSR can be read and written in user mode. Update mtspr and mfspr helpers to support this by moving the is_user check into the helper. Link: https://raw.githubusercontent.com/openrisc/doc/master/openrisc-arch-1.4-rev0.pdf Signed-off-by: Stafford Horne Reviewed-by: Richard Henderson --- Since v2: - Add reviewed-by - In helper_mfspr bring cpu out of ifdef to avoid replicatig the definition. Originally I left it in the ifdef to avoid having to mix having pointers and the data array defined on the stack. But that's overthinking. Since v1: - Update commit message to remove text about no-existant logic change. target/openrisc/sys_helper.c | 45 -- target/openrisc/translate.c | 72 2 files changed, 66 insertions(+), 51 deletions(-) diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index ec145960e3..ccdee3b8be 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -29,17 +29,37 @@ #define TO_SPR(group, number) (((group) << 11) + (number)) +static inline bool is_user(CPUOpenRISCState *env) +{ +#ifdef CONFIG_USER_ONLY +return true; +#else +return (env->sr & SR_SM) == 0; +#endif +} + void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) { -#ifndef CONFIG_USER_ONLY OpenRISCCPU *cpu = env_archcpu(env); +#ifndef CONFIG_USER_ONLY CPUState *cs = env_cpu(env); target_ulong mr; int idx; #endif +/* Handle user accessible SPRs first. */ switch (spr) { +case TO_SPR(0, 20): /* FPCSR */ +cpu_set_fpcsr(env, rb); +return; +} + +if (is_user(env)) { +raise_exception(cpu, EXCP_ILLEGAL); +} + #ifndef CONFIG_USER_ONLY +switch (spr) { case TO_SPR(0, 11): /* EVBAR */ env->evbar = rb; break; @@ -187,27 +207,33 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) cpu_openrisc_timer_update(cpu); qemu_mutex_unlock_iothread(); break; -#endif - -case TO_SPR(0, 20): /* FPCSR */ -cpu_set_fpcsr(env, rb); -break; } +#endif } target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, target_ulong spr) { +OpenRISCCPU *cpu = env_archcpu(env); #ifndef CONFIG_USER_ONLY uint64_t data[TARGET_INSN_START_WORDS]; MachineState *ms = MACHINE(qdev_get_machine()); -OpenRISCCPU *cpu = env_archcpu(env); CPUState *cs = env_cpu(env); int idx; #endif +/* Handle user accessible SPRs first. */ switch (spr) { +case TO_SPR(0, 20): /* FPCSR */ +return env->fpcsr; +} + +if (is_user(env)) { +raise_exception(cpu, EXCP_ILLEGAL); +} + #ifndef CONFIG_USER_ONLY +switch (spr) { case TO_SPR(0, 0): /* VR */ return env->vr; @@ -324,11 +350,8 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, cpu_openrisc_count_update(cpu); qemu_mutex_unlock_iothread(); return cpu_openrisc_count_get(cpu); -#endif - -case TO_SPR(0, 20): /* FPCSR */ -return env->fpcsr; } +#endif /* for rd is passed in, if rd unchanged, just keep it back. */ return rd; diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 76e53c78d4..43ba0cc1ad 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -819,45 +819,12 @@ static bool trans_l_xori(DisasContext *dc, arg_rri *a) static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a) { -check_r0_write(dc, a->d); - -if (is_user(dc)) { -gen_illegal_exception(dc); -} else { -TCGv spr = tcg_temp_new(); - -if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { -gen_io_start(); -if (dc->delayed_branch) { -tcg_gen_mov_tl(cpu_pc, jmp_pc); -tcg_gen_discard_tl(jmp_pc); -} else { -tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4); -} -dc->base.is_jmp = DISAS_EXIT; -} +TCGv spr = tcg_temp_new(); -tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k); -gen_helper_mfspr(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), spr); -} -return true; -} - -static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a) -{ -if (is_user(dc)) { -gen_illegal_exception(dc); -} else { -TCGv spr; +check_r0_write(dc, a->d); -if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { -gen_io_start(); -} -/* For SR, we will need to exit the TB to recognize the new - * exception state. For NPC, in theory this counts as a branch - * (although the SPR only exists for use by an ICE). Save all - * of the cpu state first, allowing it to be overwritten. - */ +if (tb_cflags(dc->
[PATCH v3 2/3] target/openrisc: Set PC to cpu state on FPU exception
Store the PC to ensure the correct value can be read in the exception handler. Signed-off-by: Stafford Horne Reviewed-by: Richard Henderson --- Since v2: - Add reviewed-by Since v1: - Use function do_fpe (similar to do_range) to raise exception. target/openrisc/fpu_helper.c | 13 +++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/target/openrisc/fpu_helper.c b/target/openrisc/fpu_helper.c index f9e34fa2cc..8b81d2f62f 100644 --- a/target/openrisc/fpu_helper.c +++ b/target/openrisc/fpu_helper.c @@ -20,8 +20,8 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "exec/exec-all.h" #include "exec/helper-proto.h" -#include "exception.h" #include "fpu/softfloat.h" static int ieee_ex_to_openrisc(int fexcp) @@ -45,6 +45,15 @@ static int ieee_ex_to_openrisc(int fexcp) return ret; } +static G_NORETURN +void do_fpe(CPUOpenRISCState *env, uintptr_t pc) +{ +CPUState *cs = env_cpu(env); + +cs->exception_index = EXCP_FPE; +cpu_loop_exit_restore(cs, pc); +} + void HELPER(update_fpcsr)(CPUOpenRISCState *env) { int tmp = get_float_exception_flags(>fp_status); @@ -55,7 +64,7 @@ void HELPER(update_fpcsr)(CPUOpenRISCState *env) if (tmp) { env->fpcsr |= tmp; if (env->fpcsr & FPCSR_FPEE) { -helper_exception(env, EXCP_FPE); +do_fpe(env, GETPC()); } } } -- 2.39.1
Re: [PATCH v2 3/3] target/openrisc: Setup FPU for detecting tininess before rounding
On Wed, May 10, 2023 at 05:16:20PM +0100, Richard Henderson wrote: > On 5/10/23 16:32, Stafford Horne wrote: > > OpenRISC defines tininess to be detected before rounding. Setup qemu to > > obey this. > > > > Signed-off-by: Stafford Horne > > --- > > Since v1: > > - Remove setting default NaN behavior. I discussed with the FPU > > developers and > > they mentioned the OpenRISC hardware should be IEEE compliant when > > handling > > and forwarding NaN payloads, and they don't want try change this. > > There is no such thing as IEEE compliant for NaN payloads. > All of that is implementation defined. I see, I haven't yet seen to IEEE 754 spec so I don't know how much is covered. It was incorrect to assume forwarding semantics was covered. > All OpenRISC needs to do is document its intentions (and then double-check > that fpu/softfloat-specialize.c.inc does what is documented). Understood, that makes sense, also reading that code I see how all other architectures are able to ifdef their way to a specific behavior. I will see what our current implementions do and update the spec and qemu as a separate task. > > Anyway, back to this patch, > Reviewed-by: Richard Henderson > > :-) Thank you ^_^ -Stafford
Re: [PATCH v2 1/3] target/openrisc: Allow fpcsr access in user mode
On Wed, May 10, 2023 at 05:13:03PM +0100, Richard Henderson wrote: > On 5/10/23 16:32, Stafford Horne wrote: > > void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong > > rb) > > { > > -#ifndef CONFIG_USER_ONLY > > OpenRISCCPU *cpu = env_archcpu(env); > > +#ifndef CONFIG_USER_ONLY > > CPUState *cs = env_cpu(env); > > Pulled cpu out if ifdef here... > > > @@ -204,10 +220,22 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, > > target_ulong rd, > > OpenRISCCPU *cpu = env_archcpu(env); > > CPUState *cs = env_cpu(env); > > int idx; > > +#else > > +OpenRISCCPU *cpu = env_archcpu(env); > > #endif > > But replicated it here. Right, let me make it consistent in this patch. > Otherwise, > Reviewed-by: Richard Henderson Thank you, -Stafford
[PATCH v2 3/3] target/openrisc: Setup FPU for detecting tininess before rounding
OpenRISC defines tininess to be detected before rounding. Setup qemu to obey this. Signed-off-by: Stafford Horne --- Since v1: - Remove setting default NaN behavior. I discussed with the FPU developers and they mentioned the OpenRISC hardware should be IEEE compliant when handling and forwarding NaN payloads, and they don't want try change this. target/openrisc/cpu.c | 4 1 file changed, 4 insertions(+) diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index 0ce4f796fa..61d748cfdc 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -22,6 +22,7 @@ #include "qemu/qemu-print.h" #include "cpu.h" #include "exec/exec-all.h" +#include "fpu/softfloat-helpers.h" #include "tcg/tcg.h" static void openrisc_cpu_set_pc(CPUState *cs, vaddr value) @@ -90,6 +91,9 @@ static void openrisc_cpu_reset_hold(Object *obj) s->exception_index = -1; cpu_set_fpcsr(>env, 0); +set_float_detect_tininess(float_tininess_before_rounding, + >env.fp_status); + #ifndef CONFIG_USER_ONLY cpu->env.picmr = 0x; cpu->env.picsr = 0x; -- 2.39.1
[PATCH v2 2/3] target/openrisc: Set PC to cpu state on FPU exception
Store the PC to ensure the correct value can be read in the exception handler. Signed-off-by: Stafford Horne --- Since v1: - Use function do_fpe (similar to do_range) to raise exception. target/openrisc/fpu_helper.c | 13 +++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/target/openrisc/fpu_helper.c b/target/openrisc/fpu_helper.c index f9e34fa2cc..8b81d2f62f 100644 --- a/target/openrisc/fpu_helper.c +++ b/target/openrisc/fpu_helper.c @@ -20,8 +20,8 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "exec/exec-all.h" #include "exec/helper-proto.h" -#include "exception.h" #include "fpu/softfloat.h" static int ieee_ex_to_openrisc(int fexcp) @@ -45,6 +45,15 @@ static int ieee_ex_to_openrisc(int fexcp) return ret; } +static G_NORETURN +void do_fpe(CPUOpenRISCState *env, uintptr_t pc) +{ +CPUState *cs = env_cpu(env); + +cs->exception_index = EXCP_FPE; +cpu_loop_exit_restore(cs, pc); +} + void HELPER(update_fpcsr)(CPUOpenRISCState *env) { int tmp = get_float_exception_flags(>fp_status); @@ -55,7 +64,7 @@ void HELPER(update_fpcsr)(CPUOpenRISCState *env) if (tmp) { env->fpcsr |= tmp; if (env->fpcsr & FPCSR_FPEE) { -helper_exception(env, EXCP_FPE); +do_fpe(env, GETPC()); } } } -- 2.39.1
[PATCH v2 0/3] OpenRISC updates for user space FPU
Since v1: - Fixups suggested by Richard Henderson This series adds support for the FPU related architecture changes defined in architecture spec revision v1.4. - https://openrisc.io/revisions/r1.4 In summary the architecture changes are: - Change FPCSR SPR permissions to allow for reading and writing from user space. - Clarify that FPU underflow detection is done by detecting tininess before rounding. Previous to this series FPCSR reads and writes from user-mode in QEMU would throw an illegal argument exception. The proper behavior should have been to treat these operations as no-ops as the cpu implementations do. As mentioned series changes FPCSR read/write to follow the spec. The series has been tested with the FPU support added in glibc test suite and all math tests are passing. Stafford Horne (3): target/openrisc: Allow fpcsr access in user mode target/openrisc: Set PC to cpu state on FPU exception target/openrisc: Setup FPU for detecting tininess before rounding target/openrisc/cpu.c| 4 ++ target/openrisc/fpu_helper.c | 13 ++- target/openrisc/sys_helper.c | 45 +- target/openrisc/translate.c | 72 4 files changed, 82 insertions(+), 52 deletions(-) -- 2.39.1
[PATCH v2 1/3] target/openrisc: Allow fpcsr access in user mode
As per OpenRISC spec 1.4 FPCSR can be read and written in user mode. Update mtspr and mfspr helpers to support this by moving the is_user check into the helper. Link: https://raw.githubusercontent.com/openrisc/doc/master/openrisc-arch-1.4-rev0.pdf Signed-off-by: Stafford Horne --- Since v1: - Update commit message to remove text about no-existant logic change. target/openrisc/sys_helper.c | 45 +- target/openrisc/translate.c | 72 2 files changed, 67 insertions(+), 50 deletions(-) diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index ec145960e3..8a0259c710 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -29,17 +29,37 @@ #define TO_SPR(group, number) (((group) << 11) + (number)) +static inline bool is_user(CPUOpenRISCState *env) +{ +#ifdef CONFIG_USER_ONLY +return true; +#else +return (env->sr & SR_SM) == 0; +#endif +} + void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) { -#ifndef CONFIG_USER_ONLY OpenRISCCPU *cpu = env_archcpu(env); +#ifndef CONFIG_USER_ONLY CPUState *cs = env_cpu(env); target_ulong mr; int idx; #endif +/* Handle user accessible SPRs first. */ switch (spr) { +case TO_SPR(0, 20): /* FPCSR */ +cpu_set_fpcsr(env, rb); +return; +} + +if (is_user(env)) { +raise_exception(cpu, EXCP_ILLEGAL); +} + #ifndef CONFIG_USER_ONLY +switch (spr) { case TO_SPR(0, 11): /* EVBAR */ env->evbar = rb; break; @@ -187,12 +207,8 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) cpu_openrisc_timer_update(cpu); qemu_mutex_unlock_iothread(); break; -#endif - -case TO_SPR(0, 20): /* FPCSR */ -cpu_set_fpcsr(env, rb); -break; } +#endif } target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, @@ -204,10 +220,22 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, OpenRISCCPU *cpu = env_archcpu(env); CPUState *cs = env_cpu(env); int idx; +#else +OpenRISCCPU *cpu = env_archcpu(env); #endif +/* Handle user accessible SPRs first. */ switch (spr) { +case TO_SPR(0, 20): /* FPCSR */ +return env->fpcsr; +} + +if (is_user(env)) { +raise_exception(cpu, EXCP_ILLEGAL); +} + #ifndef CONFIG_USER_ONLY +switch (spr) { case TO_SPR(0, 0): /* VR */ return env->vr; @@ -324,11 +352,8 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, cpu_openrisc_count_update(cpu); qemu_mutex_unlock_iothread(); return cpu_openrisc_count_get(cpu); -#endif - -case TO_SPR(0, 20): /* FPCSR */ -return env->fpcsr; } +#endif /* for rd is passed in, if rd unchanged, just keep it back. */ return rd; diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 76e53c78d4..43ba0cc1ad 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -819,45 +819,12 @@ static bool trans_l_xori(DisasContext *dc, arg_rri *a) static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a) { -check_r0_write(dc, a->d); - -if (is_user(dc)) { -gen_illegal_exception(dc); -} else { -TCGv spr = tcg_temp_new(); - -if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { -gen_io_start(); -if (dc->delayed_branch) { -tcg_gen_mov_tl(cpu_pc, jmp_pc); -tcg_gen_discard_tl(jmp_pc); -} else { -tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4); -} -dc->base.is_jmp = DISAS_EXIT; -} +TCGv spr = tcg_temp_new(); -tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k); -gen_helper_mfspr(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), spr); -} -return true; -} - -static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a) -{ -if (is_user(dc)) { -gen_illegal_exception(dc); -} else { -TCGv spr; +check_r0_write(dc, a->d); -if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { -gen_io_start(); -} -/* For SR, we will need to exit the TB to recognize the new - * exception state. For NPC, in theory this counts as a branch - * (although the SPR only exists for use by an ICE). Save all - * of the cpu state first, allowing it to be overwritten. - */ +if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { +gen_io_start(); if (dc->delayed_branch) { tcg_gen_mov_tl(cpu_pc, jmp_pc); tcg_gen_discard_tl(jmp_pc); @@ -865,11 +832,36 @@ static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a) tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4); } dc->
Re: [PATCH] scripts/coverity-scan: Add xtensa and openrisc components
On Thu, May 04, 2023 at 02:45:26PM +0100, Peter Maydell wrote: > We have two target architectures which don't have Coverity components > defined for them: xtensa and openrisc. Add them. > > Signed-off-by: Peter Maydell > --- > As usual with coverity components, these will need to be added > manually via the scanner UI, since it has no import-from-file... > > scripts/coverity-scan/COMPONENTS.md | 6 ++ > 1 file changed, 6 insertions(+) > > diff --git a/scripts/coverity-scan/COMPONENTS.md > b/scripts/coverity-scan/COMPONENTS.md > index 7c48e0f1d21..add7c5a279c 100644 > --- a/scripts/coverity-scan/COMPONENTS.md > +++ b/scripts/coverity-scan/COMPONENTS.md > @@ -143,3 +143,9 @@ loongarch > > riscv >~ > (/qemu)?((/include)?/hw/riscv/.*|/target/riscv/.*|/hw/.*/(riscv_|ibex_|sifive_).*) > + > +openrisc > + ~ (/qemu)?((/include)?/hw/openrisc/.*|/target/openrisc/.*) This looks good to me for OpenRISC. Where can we view the coverity reports? Is it this?: https://scan.coverity.com/projects/378 Acked-by: Stafford Horne > +xtensa > + ~ (/qemu)?((/include)?/hw/xtensa/.*|/target/xtensa/.*)
Re: [PATCH 3/3] target/openrisc: Setup FPU for detecting tininess before rounding
On Wed, May 03, 2023 at 10:41:42AM +0100, Richard Henderson wrote: > On 5/3/23 10:14, Stafford Horne wrote: > > > > +set_default_nan_mode(1, >env.fp_status); > > > > +set_float_detect_tininess(float_tininess_before_rounding, > > > > + >env.fp_status); > > > > > > You don't mention the nan change in the commit message. > > > > Right, and I am not sure I need it. Let me remove it and run tests again. > > I > > was just adding it as a few other architectures did who set > > float_tininess_before_rounding. > > What that does is *not* propagate NaN payloads from (some) input to the > output. This is certainly true of RISC-V, which specifies this in their > architecture manual. OpenRISC does not specify any NaN behaviour at all. Thanks, that is what I also gathered from reading up on it. > It's not a bad choice, really, and it almost certainly simplifies the design > of the FPU, as you can do NaN propagation and silencing in one step. Right, it makes sense to optimize. It doesn't look like any of our FPU implementation do that at the moment. I will check with bandvig who implemented the FPU to understand his thought on this. It at least deserves to be discussed how nan payload is to be handled in the architecture spec. -Stafford
Re: [PATCH 3/3] target/openrisc: Setup FPU for detecting tininess before rounding
On Wed, May 03, 2023 at 08:37:31AM +0100, Richard Henderson wrote: > On 5/2/23 19:57, Stafford Horne wrote: > > OpenRISC defines tininess to be detected before rounding. Setup qemu to > > obey this. > > > > Signed-off-by: Stafford Horne > > --- > > target/openrisc/cpu.c | 5 + > > 1 file changed, 5 insertions(+) > > > > diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c > > index 0ce4f796fa..cdbff26fb5 100644 > > --- a/target/openrisc/cpu.c > > +++ b/target/openrisc/cpu.c > > @@ -22,6 +22,7 @@ > > #include "qemu/qemu-print.h" > > #include "cpu.h" > > #include "exec/exec-all.h" > > +#include "fpu/softfloat-helpers.h" > > #include "tcg/tcg.h" > > static void openrisc_cpu_set_pc(CPUState *cs, vaddr value) > > @@ -90,6 +91,10 @@ static void openrisc_cpu_reset_hold(Object *obj) > > s->exception_index = -1; > > cpu_set_fpcsr(>env, 0); > > +set_default_nan_mode(1, >env.fp_status); > > +set_float_detect_tininess(float_tininess_before_rounding, > > + >env.fp_status); > > You don't mention the nan change in the commit message. Right, and I am not sure I need it. Let me remove it and run tests again. I was just adding it as a few other architectures did who set float_tininess_before_rounding. Will clean this up.
Re: [PATCH 2/3] target/openrisc: Set PC to cpu state on FPU exception
On Wed, May 03, 2023 at 08:36:13AM +0100, Richard Henderson wrote: > On 5/2/23 19:57, Stafford Horne wrote: > > @@ -55,6 +56,9 @@ void HELPER(update_fpcsr)(CPUOpenRISCState *env) > > if (tmp) { > > env->fpcsr |= tmp; > > if (env->fpcsr & FPCSR_FPEE) { > > +CPUState *cs = env_cpu(env); > > + > > +cpu_restore_state(cs, GETPC()); > > helper_exception(env, EXCP_FPE); > > Better to mirror do_range(). OK.
Re: [PATCH 1/3] target/openrisc: Allow fpcsr access in user mode
On Tue, May 02, 2023 at 07:57:29PM +0100, Stafford Horne wrote: > As per OpenRISC spec 1.4 FPCSR can be read and written in user mode. > > Update mtspr and mfspr helpers to support this by moving the is_user > check into the helper. > > There is a logic change here to no longer throw an illegal instruction > exception when executing mtspr/mfspr in user mode. The illegal > instruction exception is not part of the spec, so this should be OK. This is wrong, I considered doing it but left the exception in (moved to the helper). I will remove this bit of the commit messages in the next version. But it is something we could consider doing. Conversely, the architecture pec should be more clear as to what happens when mfspr/mtspr privileges are violated. -Stafford > Link: > https://raw.githubusercontent.com/openrisc/doc/master/openrisc-arch-1.4-rev0.pdf > Signed-off-by: Stafford Horne > --- > target/openrisc/sys_helper.c | 45 +- > target/openrisc/translate.c | 72 > 2 files changed, 67 insertions(+), 50 deletions(-) > > diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c > index ec145960e3..8a0259c710 100644 > --- a/target/openrisc/sys_helper.c > +++ b/target/openrisc/sys_helper.c > @@ -29,17 +29,37 @@ > > #define TO_SPR(group, number) (((group) << 11) + (number)) > > +static inline bool is_user(CPUOpenRISCState *env) > +{ > +#ifdef CONFIG_USER_ONLY > +return true; > +#else > +return (env->sr & SR_SM) == 0; > +#endif > +} > + > void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) > { > -#ifndef CONFIG_USER_ONLY > OpenRISCCPU *cpu = env_archcpu(env); > +#ifndef CONFIG_USER_ONLY > CPUState *cs = env_cpu(env); > target_ulong mr; > int idx; > #endif > > +/* Handle user accessible SPRs first. */ > switch (spr) { > +case TO_SPR(0, 20): /* FPCSR */ > +cpu_set_fpcsr(env, rb); > +return; > +} > + > +if (is_user(env)) { > +raise_exception(cpu, EXCP_ILLEGAL); > +} > + > #ifndef CONFIG_USER_ONLY > +switch (spr) { > case TO_SPR(0, 11): /* EVBAR */ > env->evbar = rb; > break; > @@ -187,12 +207,8 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong > spr, target_ulong rb) > cpu_openrisc_timer_update(cpu); > qemu_mutex_unlock_iothread(); > break; > -#endif > - > -case TO_SPR(0, 20): /* FPCSR */ > -cpu_set_fpcsr(env, rb); > -break; > } > +#endif > } > > target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, > @@ -204,10 +220,22 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, > target_ulong rd, > OpenRISCCPU *cpu = env_archcpu(env); > CPUState *cs = env_cpu(env); > int idx; > +#else > +OpenRISCCPU *cpu = env_archcpu(env); > #endif > > +/* Handle user accessible SPRs first. */ > switch (spr) { > +case TO_SPR(0, 20): /* FPCSR */ > +return env->fpcsr; > +} > + > +if (is_user(env)) { > +raise_exception(cpu, EXCP_ILLEGAL); > +} > + > #ifndef CONFIG_USER_ONLY > +switch (spr) { > case TO_SPR(0, 0): /* VR */ > return env->vr; > > @@ -324,11 +352,8 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, > target_ulong rd, > cpu_openrisc_count_update(cpu); > qemu_mutex_unlock_iothread(); > return cpu_openrisc_count_get(cpu); > -#endif > - > -case TO_SPR(0, 20): /* FPCSR */ > -return env->fpcsr; > } > +#endif > > /* for rd is passed in, if rd unchanged, just keep it back. */ > return rd; > diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c > index 76e53c78d4..43ba0cc1ad 100644 > --- a/target/openrisc/translate.c > +++ b/target/openrisc/translate.c > @@ -819,45 +819,12 @@ static bool trans_l_xori(DisasContext *dc, arg_rri *a) > > static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a) > { > -check_r0_write(dc, a->d); > - > -if (is_user(dc)) { > -gen_illegal_exception(dc); > -} else { > -TCGv spr = tcg_temp_new(); > - > -if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { > -gen_io_start(); > -if (dc->delayed_branch) { > -tcg_gen_mov_tl(cpu_pc, jmp_pc); > -tcg_gen_discard_tl(jmp_pc); > -} else { > -tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4); > -} > -dc->base.is_jmp = DISAS_EXIT; > -
[PATCH 2/3] target/openrisc: Set PC to cpu state on FPU exception
Store the PC to ensure the correct value can be read in the exception handler. Signed-off-by: Stafford Horne --- target/openrisc/fpu_helper.c | 4 1 file changed, 4 insertions(+) diff --git a/target/openrisc/fpu_helper.c b/target/openrisc/fpu_helper.c index f9e34fa2cc..1feebb9ac7 100644 --- a/target/openrisc/fpu_helper.c +++ b/target/openrisc/fpu_helper.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "exception.h" #include "fpu/softfloat.h" @@ -55,6 +56,9 @@ void HELPER(update_fpcsr)(CPUOpenRISCState *env) if (tmp) { env->fpcsr |= tmp; if (env->fpcsr & FPCSR_FPEE) { +CPUState *cs = env_cpu(env); + +cpu_restore_state(cs, GETPC()); helper_exception(env, EXCP_FPE); } } -- 2.39.1
[PATCH 1/3] target/openrisc: Allow fpcsr access in user mode
As per OpenRISC spec 1.4 FPCSR can be read and written in user mode. Update mtspr and mfspr helpers to support this by moving the is_user check into the helper. There is a logic change here to no longer throw an illegal instruction exception when executing mtspr/mfspr in user mode. The illegal instruction exception is not part of the spec, so this should be OK. Link: https://raw.githubusercontent.com/openrisc/doc/master/openrisc-arch-1.4-rev0.pdf Signed-off-by: Stafford Horne --- target/openrisc/sys_helper.c | 45 +- target/openrisc/translate.c | 72 2 files changed, 67 insertions(+), 50 deletions(-) diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index ec145960e3..8a0259c710 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -29,17 +29,37 @@ #define TO_SPR(group, number) (((group) << 11) + (number)) +static inline bool is_user(CPUOpenRISCState *env) +{ +#ifdef CONFIG_USER_ONLY +return true; +#else +return (env->sr & SR_SM) == 0; +#endif +} + void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) { -#ifndef CONFIG_USER_ONLY OpenRISCCPU *cpu = env_archcpu(env); +#ifndef CONFIG_USER_ONLY CPUState *cs = env_cpu(env); target_ulong mr; int idx; #endif +/* Handle user accessible SPRs first. */ switch (spr) { +case TO_SPR(0, 20): /* FPCSR */ +cpu_set_fpcsr(env, rb); +return; +} + +if (is_user(env)) { +raise_exception(cpu, EXCP_ILLEGAL); +} + #ifndef CONFIG_USER_ONLY +switch (spr) { case TO_SPR(0, 11): /* EVBAR */ env->evbar = rb; break; @@ -187,12 +207,8 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) cpu_openrisc_timer_update(cpu); qemu_mutex_unlock_iothread(); break; -#endif - -case TO_SPR(0, 20): /* FPCSR */ -cpu_set_fpcsr(env, rb); -break; } +#endif } target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, @@ -204,10 +220,22 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, OpenRISCCPU *cpu = env_archcpu(env); CPUState *cs = env_cpu(env); int idx; +#else +OpenRISCCPU *cpu = env_archcpu(env); #endif +/* Handle user accessible SPRs first. */ switch (spr) { +case TO_SPR(0, 20): /* FPCSR */ +return env->fpcsr; +} + +if (is_user(env)) { +raise_exception(cpu, EXCP_ILLEGAL); +} + #ifndef CONFIG_USER_ONLY +switch (spr) { case TO_SPR(0, 0): /* VR */ return env->vr; @@ -324,11 +352,8 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, cpu_openrisc_count_update(cpu); qemu_mutex_unlock_iothread(); return cpu_openrisc_count_get(cpu); -#endif - -case TO_SPR(0, 20): /* FPCSR */ -return env->fpcsr; } +#endif /* for rd is passed in, if rd unchanged, just keep it back. */ return rd; diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 76e53c78d4..43ba0cc1ad 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -819,45 +819,12 @@ static bool trans_l_xori(DisasContext *dc, arg_rri *a) static bool trans_l_mfspr(DisasContext *dc, arg_l_mfspr *a) { -check_r0_write(dc, a->d); - -if (is_user(dc)) { -gen_illegal_exception(dc); -} else { -TCGv spr = tcg_temp_new(); - -if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { -gen_io_start(); -if (dc->delayed_branch) { -tcg_gen_mov_tl(cpu_pc, jmp_pc); -tcg_gen_discard_tl(jmp_pc); -} else { -tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4); -} -dc->base.is_jmp = DISAS_EXIT; -} +TCGv spr = tcg_temp_new(); -tcg_gen_ori_tl(spr, cpu_R(dc, a->a), a->k); -gen_helper_mfspr(cpu_R(dc, a->d), cpu_env, cpu_R(dc, a->d), spr); -} -return true; -} - -static bool trans_l_mtspr(DisasContext *dc, arg_l_mtspr *a) -{ -if (is_user(dc)) { -gen_illegal_exception(dc); -} else { -TCGv spr; +check_r0_write(dc, a->d); -if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { -gen_io_start(); -} -/* For SR, we will need to exit the TB to recognize the new - * exception state. For NPC, in theory this counts as a branch - * (although the SPR only exists for use by an ICE). Save all - * of the cpu state first, allowing it to be overwritten. - */ +if (tb_cflags(dc->base.tb) & CF_USE_ICOUNT) { +gen_io_start(); if (dc->delayed_branch) { tcg_gen_mov_tl(cpu_pc, jmp_pc); tcg_gen_discard_tl(jmp_pc); @@ -865,11 +832,36 @@ static bool trans_l_mtspr(DisasContext *dc
[PATCH 3/3] target/openrisc: Setup FPU for detecting tininess before rounding
OpenRISC defines tininess to be detected before rounding. Setup qemu to obey this. Signed-off-by: Stafford Horne --- target/openrisc/cpu.c | 5 + 1 file changed, 5 insertions(+) diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index 0ce4f796fa..cdbff26fb5 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -22,6 +22,7 @@ #include "qemu/qemu-print.h" #include "cpu.h" #include "exec/exec-all.h" +#include "fpu/softfloat-helpers.h" #include "tcg/tcg.h" static void openrisc_cpu_set_pc(CPUState *cs, vaddr value) @@ -90,6 +91,10 @@ static void openrisc_cpu_reset_hold(Object *obj) s->exception_index = -1; cpu_set_fpcsr(>env, 0); +set_default_nan_mode(1, >env.fp_status); +set_float_detect_tininess(float_tininess_before_rounding, + >env.fp_status); + #ifndef CONFIG_USER_ONLY cpu->env.picmr = 0x; cpu->env.picsr = 0x; -- 2.39.1
[PATCH 0/3] OpenRISC updates for user space FPU
This series adds support for the FPU related architecture changes defined in architecture spec revision v1.4. - https://openrisc.io/revisions/r1.4 In summary the architecture changes are: - Change FPCSR SPR permissions to allow for reading and writing from user space. - Clarify that FPU underflow detection is done by detecting tininess before rounding. Previous to this series FPCSR reads and writes from user-mode in QEMU would throw an illegal argument exception. The proper behavior should have been to treat these operations as no-ops as the cpu implementations do. As mentioned series changes FPCSR read/write to follow the spec. The series has been tested with the FPU support added in glibc test suite and all math tests are passing. Stafford Horne (3): target/openrisc: Allow fpcsr access in user mode target/openrisc: Set PC to cpu state on FPU exception target/openrisc: Setup FPU for detecting tininess before rounding target/openrisc/cpu.c| 5 +++ target/openrisc/fpu_helper.c | 4 ++ target/openrisc/sys_helper.c | 45 +- target/openrisc/translate.c | 72 4 files changed, 76 insertions(+), 50 deletions(-) -- 2.39.1
Re: [PATCH v3 6/8] openrisc: re-randomize rng-seed on reboot
Hi Jason, On Thu, Oct 13, 2022 at 08:16:51PM -0600, Jason A. Donenfeld wrote: > When the system reboots, the rng-seed that the FDT has should be > re-randomized, so that the new boot gets a new seed. Since the FDT is in > the ROM region at this point, we add a hook right after the ROM has been > added, so that we have a pointer to that copy of the FDT. This looks good to me. Acked-by: Stafford Horne > Cc: Stafford Horne > Signed-off-by: Jason A. Donenfeld > --- > hw/openrisc/boot.c | 3 +++ > 1 file changed, 3 insertions(+) > > diff --git a/hw/openrisc/boot.c b/hw/openrisc/boot.c > index 128ccbcba2..007e80cd5a 100644 > --- a/hw/openrisc/boot.c > +++ b/hw/openrisc/boot.c > @@ -14,6 +14,7 @@ > #include "hw/openrisc/boot.h" > #include "sysemu/device_tree.h" > #include "sysemu/qtest.h" > +#include "sysemu/reset.h" > > #include > > @@ -111,6 +112,8 @@ uint32_t openrisc_load_fdt(void *fdt, hwaddr load_start, > > rom_add_blob_fixed_as("fdt", fdt, fdtsize, fdt_addr, >_space_memory); > +qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds, > +rom_ptr_for_as(_space_memory, fdt_addr, > fdtsize)); > > return fdt_addr; > } > -- > 2.37.3 >
[PULL 09/11] target/openrisc: Interrupt handling fixes
When running SMP systems we sometimes were seeing lockups where IPI interrupts were being raised by never handled. This looks to be caused by 2 issues in the openrisc interrupt handling logic. 1. After clearing an interrupt the openrisc_cpu_set_irq handler will always clear PICSR. This is not correct as masked interrupts should still be visible in PICSR. 2. After setting PICMR (mask register) and exposed interrupts should cause an interrupt to be raised. This was not being done so add it. This patch fixes both issues. Reviewed-by: Richard Henderson Signed-off-by: Stafford Horne --- target/openrisc/cpu.c| 1 - target/openrisc/sys_helper.c | 7 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index 41d1b2a24a..cb9f35f408 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -98,7 +98,6 @@ static void openrisc_cpu_set_irq(void *opaque, int irq, int level) cpu_interrupt(cs, CPU_INTERRUPT_HARD); } else { cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); -cpu->env.picsr = 0; } } #endif diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index da88ad9e77..09b3c97d7c 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -139,6 +139,13 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) break; case TO_SPR(9, 0): /* PICMR */ env->picmr = rb; +qemu_mutex_lock_iothread(); +if (env->picsr & env->picmr) { +cpu_interrupt(cs, CPU_INTERRUPT_HARD); +} else { +cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); +} +qemu_mutex_unlock_iothread(); break; case TO_SPR(9, 2): /* PICSR */ env->picsr &= ~rb; -- 2.37.2
[PULL 11/11] docs/system: openrisc: Add OpenRISC documentation
Reviewed-by: Richard Henderson Signed-off-by: Stafford Horne --- docs/system/openrisc/cpu-features.rst | 15 ++ docs/system/openrisc/emulation.rst| 17 +++ docs/system/openrisc/or1k-sim.rst | 43 docs/system/openrisc/virt.rst | 50 +++ docs/system/target-openrisc.rst | 71 +++ docs/system/targets.rst | 1 + 6 files changed, 197 insertions(+) create mode 100644 docs/system/openrisc/cpu-features.rst create mode 100644 docs/system/openrisc/emulation.rst create mode 100644 docs/system/openrisc/or1k-sim.rst create mode 100644 docs/system/openrisc/virt.rst create mode 100644 docs/system/target-openrisc.rst diff --git a/docs/system/openrisc/cpu-features.rst b/docs/system/openrisc/cpu-features.rst new file mode 100644 index 00..aeb65e22ff --- /dev/null +++ b/docs/system/openrisc/cpu-features.rst @@ -0,0 +1,15 @@ +CPU Features + + +The QEMU emulation of the OpenRISC architecture provides following built in +features. + +- Shadow GPRs +- MMU TLB with 128 entries, 1 way +- Power Management (PM) +- Programmable Interrupt Controller (PIC) +- Tick Timer + +These features are on by default and the presence can be confirmed by checking +the contents of the Unit Presence Register (``UPR``) and CPU Configuration +Register (``CPUCFGR``). diff --git a/docs/system/openrisc/emulation.rst b/docs/system/openrisc/emulation.rst new file mode 100644 index 00..0af898ab20 --- /dev/null +++ b/docs/system/openrisc/emulation.rst @@ -0,0 +1,17 @@ +OpenRISC 1000 CPU architecture support +== + +QEMU's TCG emulation includes support for the OpenRISC or1200 implementation of +the OpenRISC 1000 cpu architecture. + +The or1200 cpu also has support for the following instruction subsets: + +- ORBIS32 (OpenRISC Basic Instruction Set) +- ORFPX32 (OpenRISC Floating-Point eXtension) + +In addition to the instruction subsets the QEMU TCG emulation also has support +for most Class II (optional) instructions. + +For information on all OpenRISC instructions please refer to the latest +architecture manual available on the OpenRISC website in the +`OpenRISC Architecture <https://openrisc.io/architecture>`_ section. diff --git a/docs/system/openrisc/or1k-sim.rst b/docs/system/openrisc/or1k-sim.rst new file mode 100644 index 00..ef10439737 --- /dev/null +++ b/docs/system/openrisc/or1k-sim.rst @@ -0,0 +1,43 @@ +Or1ksim board += + +The QEMU Or1ksim machine emulates the standard OpenRISC board simulator which is +also the standard SoC configuration. + +Supported devices +- + + * 16550A UART + * ETHOC Ethernet controller + * SMP (OpenRISC multicore using ompic) + +Boot options + + +The Or1ksim machine can be started using the ``-kernel`` and ``-initrd`` options +to load a Linux kernel and optional disk image. + +.. code-block:: bash + + $ qemu-system-or1k -cpu or1220 -M or1k-sim -nographic \ +-kernel vmlinux \ +-initrd initramfs.cpio.gz \ +-m 128 + +Linux guest kernel configuration +"""""""""""""""""""""""""""""""" + +The 'or1ksim_defconfig' for Linux openrisc kernels includes the right +drivers for the or1ksim machine. If you would like to run an SMP system +choose the 'simple_smp_defconfig' config. + +Hardware configuration information +"""""""""""""""""""""""""""""""""" + +The ``or1k-sim`` board automatically generates a device tree blob ("dtb") +which it passes to the guest. This provides information about the +addresses, interrupt lines and other configuration of the various devices +in the system. + +The location of the DTB will be passed in register ``r3`` to the guest operating +system. diff --git a/docs/system/openrisc/virt.rst b/docs/system/openrisc/virt.rst new file mode 100644 index 00..2fe61ac942 --- /dev/null +++ b/docs/system/openrisc/virt.rst @@ -0,0 +1,50 @@ +'virt' generic virtual platform +=== + +The ``virt`` board is a platform which does not correspond to any +real hardware; it is designed for use in virtual machines. +It is the recommended board type if you simply want to run +a guest such as Linux and do not care about reproducing the +idiosyncrasies and limitations of a particular bit of real-world +hardware. + +Supported devices +- + + * PCI/PCIe devices + * 8 virtio-mmio transport devices + * 16550A UART + * Goldfish RTC + * SiFive Test device for poweroff and reboot + * SMP (OpenRISC multicore using ompic) + +Boot options + + +The virt machine can be started using the ``-kernel`` a
[PULL 07/11] target/openrisc: Add interrupted CPU to log
When we are tracing it's helpful to know which CPU's are getting interrupted, add that detail to the log line. Reviewed-by: Richard Henderson Signed-off-by: Stafford Horne --- target/openrisc/interrupt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target/openrisc/interrupt.c b/target/openrisc/interrupt.c index e5724f5371..c31c6f12c4 100644 --- a/target/openrisc/interrupt.c +++ b/target/openrisc/interrupt.c @@ -83,7 +83,9 @@ void openrisc_cpu_do_interrupt(CPUState *cs) [EXCP_TRAP] = "TRAP", }; -qemu_log_mask(CPU_LOG_INT, "INT: %s\n", int_name[exception]); +qemu_log_mask(CPU_LOG_INT, "CPU: %d INT: %s\n", + cs->cpu_index, + int_name[exception]); hwaddr vect_pc = exception << 8; if (env->cpucfgr & CPUCFGR_EVBARP) { -- 2.37.2
[PULL 05/11] hw/openrisc: Add PCI bus support to virt
This is mostly borrowed from xtensa and riscv as examples. The create_pcie_irq_map swizzle function is almost and exact copy but here we use a single cell interrupt, possibly we can make this generic. Signed-off-by: Stafford Horne --- hw/openrisc/Kconfig | 3 + hw/openrisc/virt.c | 160 ++-- 2 files changed, 157 insertions(+), 6 deletions(-) diff --git a/hw/openrisc/Kconfig b/hw/openrisc/Kconfig index 202134668e..97af258b55 100644 --- a/hw/openrisc/Kconfig +++ b/hw/openrisc/Kconfig @@ -7,8 +7,11 @@ config OR1K_SIM config OR1K_VIRT bool +imply PCI_DEVICES imply VIRTIO_VGA imply TEST_DEVICES +select PCI +select PCI_EXPRESS_GENERIC_BRIDGE select GOLDFISH_RTC select SERIAL select SIFIVE_TEST diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c index 54f2732a6b..9a78234a28 100644 --- a/hw/openrisc/virt.c +++ b/hw/openrisc/virt.c @@ -17,6 +17,8 @@ #include "hw/core/split-irq.h" #include "hw/openrisc/boot.h" #include "hw/misc/sifive_test.h" +#include "hw/pci/pci.h" +#include "hw/pci-host/gpex.h" #include "hw/qdev-properties.h" #include "hw/rtc/goldfish_rtc.h" #include "hw/sysbus.h" @@ -47,6 +49,9 @@ typedef struct OR1KVirtState { enum { VIRT_DRAM, +VIRT_ECAM, +VIRT_MMIO, +VIRT_PIO, VIRT_TEST, VIRT_RTC, VIRT_VIRTIO, @@ -60,6 +65,7 @@ enum { VIRT_RTC_IRQ = 3, VIRT_VIRTIO_IRQ = 4, /* to 12 */ VIRTIO_COUNT = 8, +VIRT_PCI_IRQ_BASE = 13, /* to 17 */ }; static const struct MemmapEntry { @@ -72,6 +78,9 @@ static const struct MemmapEntry { [VIRT_RTC] = { 0x96005000, 0x1000 }, [VIRT_VIRTIO] ={ 0x9700, 0x1000 }, [VIRT_OMPIC] = { 0x9800, VIRT_CPUS_MAX * 8 }, +[VIRT_ECAM] = { 0x9e00, 0x100 }, +[VIRT_PIO] = { 0x9f00, 0x100 }, +[VIRT_MMIO] = { 0xa000, 0x1000 }, }; static struct openrisc_boot_info { @@ -115,12 +124,12 @@ static qemu_irq get_per_cpu_irq(OpenRISCCPU *cpus[], int num_cpus, int irq_pin) static void openrisc_create_fdt(OR1KVirtState *state, const struct MemmapEntry *memmap, int num_cpus, uint64_t mem_size, -const char *cmdline) +const char *cmdline, +int32_t *pic_phandle) { void *fdt; int cpu; char *nodename; -int pic_ph; fdt = state->fdt = create_device_tree(>fdt_size); if (!fdt) { @@ -163,14 +172,14 @@ static void openrisc_create_fdt(OR1KVirtState *state, nodename = (char *)"/pic"; qemu_fdt_add_subnode(fdt, nodename); -pic_ph = qemu_fdt_alloc_phandle(fdt); +*pic_phandle = qemu_fdt_alloc_phandle(fdt); qemu_fdt_setprop_string(fdt, nodename, "compatible", "opencores,or1k-pic-level"); qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells", 1); qemu_fdt_setprop(fdt, nodename, "interrupt-controller", NULL, 0); -qemu_fdt_setprop_cell(fdt, nodename, "phandle", pic_ph); +qemu_fdt_setprop_cell(fdt, nodename, "phandle", *pic_phandle); -qemu_fdt_setprop_cell(fdt, "/", "interrupt-parent", pic_ph); +qemu_fdt_setprop_cell(fdt, "/", "interrupt-parent", *pic_phandle); qemu_fdt_add_subnode(fdt, "/chosen"); if (cmdline) { @@ -275,6 +284,7 @@ static void openrisc_virt_test_init(OR1KVirtState *state, hwaddr base, g_free(nodename); } + static void openrisc_virt_rtc_init(OR1KVirtState *state, hwaddr base, hwaddr size, int num_cpus, OpenRISCCPU *cpus[], int irq_pin) @@ -296,6 +306,134 @@ static void openrisc_virt_rtc_init(OR1KVirtState *state, hwaddr base, g_free(nodename); } + +static void create_pcie_irq_map(void *fdt, char *nodename, int irq_base, +uint32_t irqchip_phandle) +{ +int pin, dev; +uint32_t irq_map_stride = 0; +uint32_t full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS * 6] = {}; +uint32_t *irq_map = full_irq_map; + +/* + * This code creates a standard swizzle of interrupts such that + * each device's first interrupt is based on it's PCI_SLOT number. + * (See pci_swizzle_map_irq_fn()) + * + * We only need one entry per interrupt in the table (not one per + * possible slot) seeing the interrupt-map-mask will allow the table + * to wrap to any number of devices. + */ +for (dev = 0; dev < GPEX_NUM_IRQS; dev++) { +int devfn = dev << 3; + +for (pin = 0; pin < GPEX_NUM_IRQS; pin++) { +int irq_nr = irq_base + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS); +
[PULL 08/11] target/openrisc: Enable MTTCG
This patch enables multithread TCG for OpenRISC. Since the or1k shared syncrhonized timer can be updated from each vCPU via helpers we use a mutex to synchronize updates. Reviewed-by: Richard Henderson Signed-off-by: Stafford Horne --- configs/targets/or1k-softmmu.mak | 1 + target/openrisc/cpu.h| 2 ++ target/openrisc/sys_helper.c | 7 ++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/configs/targets/or1k-softmmu.mak b/configs/targets/or1k-softmmu.mak index 263e970870..432f855a30 100644 --- a/configs/targets/or1k-softmmu.mak +++ b/configs/targets/or1k-softmmu.mak @@ -1,3 +1,4 @@ TARGET_ARCH=openrisc +TARGET_SUPPORTS_MTTCG=y TARGET_BIG_ENDIAN=y TARGET_NEED_FDT=y diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index b9584f10d4..1d5efa5ca2 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -25,6 +25,8 @@ #include "hw/core/cpu.h" #include "qom/object.h" +#define TCG_GUEST_DEFAULT_MO (0) + #define TYPE_OPENRISC_CPU "or1k-cpu" OBJECT_DECLARE_CPU_TYPE(OpenRISCCPU, OpenRISCCPUClass, OPENRISC_CPU) diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index 48674231e7..da88ad9e77 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -145,6 +145,7 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) break; case TO_SPR(10, 0): /* TTMR */ { +qemu_mutex_lock_iothread(); if ((env->ttmr & TTMR_M) ^ (rb & TTMR_M)) { switch (rb & TTMR_M) { case TIMER_NONE: @@ -168,14 +169,16 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) env->ttmr = rb & ~TTMR_IP; cs->interrupt_request &= ~CPU_INTERRUPT_TIMER; } - cpu_openrisc_timer_update(cpu); +qemu_mutex_unlock_iothread(); } break; case TO_SPR(10, 1): /* TTCR */ +qemu_mutex_lock_iothread(); cpu_openrisc_count_set(cpu, rb); cpu_openrisc_timer_update(cpu); +qemu_mutex_unlock_iothread(); break; #endif @@ -303,7 +306,9 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, return env->ttmr; case TO_SPR(10, 1): /* TTCR */ +qemu_mutex_lock_iothread(); cpu_openrisc_count_update(cpu); +qemu_mutex_unlock_iothread(); return cpu_openrisc_count_get(cpu); #endif -- 2.37.2
[PULL 04/11] hw/openrisc: Add the OpenRISC virtual machine
This patch adds the OpenRISC virtual machine 'virt' for OpenRISC. This platform allows for a convenient CI platform for toolchain, software ports and the OpenRISC linux kernel port. Much of this has been sourced from the m68k and riscv virt platforms. The platform provides: - OpenRISC SMP with up to 4 cpus - A virtio bus with up to 8 devices - Standard ns16550a serial - Goldfish RTC - SiFive TEST device for poweroff and reboot - Generated Device Tree to automatically configure the guest kernel Signed-off-by: Stafford Horne --- configs/devices/or1k-softmmu/default.mak | 1 + hw/openrisc/Kconfig | 9 + hw/openrisc/meson.build | 1 + hw/openrisc/virt.c | 417 +++ 4 files changed, 428 insertions(+) create mode 100644 hw/openrisc/virt.c diff --git a/configs/devices/or1k-softmmu/default.mak b/configs/devices/or1k-softmmu/default.mak index 168101c39a..89c39e3123 100644 --- a/configs/devices/or1k-softmmu/default.mak +++ b/configs/devices/or1k-softmmu/default.mak @@ -3,3 +3,4 @@ # Boards: # CONFIG_OR1K_SIM=y +CONFIG_OR1K_VIRT=y diff --git a/hw/openrisc/Kconfig b/hw/openrisc/Kconfig index 8f284f3ba0..202134668e 100644 --- a/hw/openrisc/Kconfig +++ b/hw/openrisc/Kconfig @@ -4,3 +4,12 @@ config OR1K_SIM select OPENCORES_ETH select OMPIC select SPLIT_IRQ + +config OR1K_VIRT +bool +imply VIRTIO_VGA +imply TEST_DEVICES +select GOLDFISH_RTC +select SERIAL +select SIFIVE_TEST +select VIRTIO_MMIO diff --git a/hw/openrisc/meson.build b/hw/openrisc/meson.build index ab563820c5..2dbc6365bb 100644 --- a/hw/openrisc/meson.build +++ b/hw/openrisc/meson.build @@ -2,5 +2,6 @@ openrisc_ss = ss.source_set() openrisc_ss.add(files('cputimer.c')) openrisc_ss.add(files('boot.c')) openrisc_ss.add(when: 'CONFIG_OR1K_SIM', if_true: [files('openrisc_sim.c'), fdt]) +openrisc_ss.add(when: 'CONFIG_OR1K_VIRT', if_true: [files('virt.c'), fdt]) hw_arch += {'openrisc': openrisc_ss} diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c new file mode 100644 index 00..54f2732a6b --- /dev/null +++ b/hw/openrisc/virt.c @@ -0,0 +1,417 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * OpenRISC QEMU virtual machine. + * + * (c) 2022 Stafford Horne + */ + +#include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "cpu.h" +#include "exec/address-spaces.h" +#include "hw/irq.h" +#include "hw/boards.h" +#include "hw/char/serial.h" +#include "hw/core/split-irq.h" +#include "hw/openrisc/boot.h" +#include "hw/misc/sifive_test.h" +#include "hw/qdev-properties.h" +#include "hw/rtc/goldfish_rtc.h" +#include "hw/sysbus.h" +#include "hw/virtio/virtio-mmio.h" +#include "sysemu/device_tree.h" +#include "sysemu/sysemu.h" +#include "sysemu/qtest.h" +#include "sysemu/reset.h" + +#include + +#define VIRT_CPUS_MAX 4 +#define VIRT_CLK_MHZ 2000 + +#define TYPE_VIRT_MACHINE MACHINE_TYPE_NAME("virt") +#define VIRT_MACHINE(obj) \ +OBJECT_CHECK(OR1KVirtState, (obj), TYPE_VIRT_MACHINE) + +typedef struct OR1KVirtState { +/*< private >*/ +MachineState parent_obj; + +/*< public >*/ +void *fdt; +int fdt_size; + +} OR1KVirtState; + +enum { +VIRT_DRAM, +VIRT_TEST, +VIRT_RTC, +VIRT_VIRTIO, +VIRT_UART, +VIRT_OMPIC, +}; + +enum { +VIRT_OMPIC_IRQ = 1, +VIRT_UART_IRQ = 2, +VIRT_RTC_IRQ = 3, +VIRT_VIRTIO_IRQ = 4, /* to 12 */ +VIRTIO_COUNT = 8, +}; + +static const struct MemmapEntry { +hwaddr base; +hwaddr size; +} virt_memmap[] = { +[VIRT_DRAM] = { 0x, 0 }, +[VIRT_UART] = { 0x9000, 0x100 }, +[VIRT_TEST] = { 0x9600,0x8 }, +[VIRT_RTC] = { 0x96005000, 0x1000 }, +[VIRT_VIRTIO] ={ 0x9700, 0x1000 }, +[VIRT_OMPIC] = { 0x9800, VIRT_CPUS_MAX * 8 }, +}; + +static struct openrisc_boot_info { +uint32_t bootstrap_pc; +uint32_t fdt_addr; +} boot_info; + +static void main_cpu_reset(void *opaque) +{ +OpenRISCCPU *cpu = opaque; +CPUState *cs = CPU(cpu); + +cpu_reset(CPU(cpu)); + +cpu_set_pc(cs, boot_info.bootstrap_pc); +cpu_set_gpr(>env, 3, boot_info.fdt_addr); +} + +static qemu_irq get_cpu_irq(OpenRISCCPU *cpus[], int cpunum, int irq_pin) +{ +return qdev_get_gpio_in_named(DEVICE(cpus[cpunum]), "IRQ", irq_pin); +} + +static qemu_irq get_per_cpu_irq(OpenRISCCPU *cpus[], int num_cpus, int irq_pin) +{ +int i; + +if (num_cpus > 1) { +DeviceState *splitter = qdev_new(TYPE_SPLIT_IRQ); +qdev_prop_set_uint32(splitter, "num-lines", num_cpus); +qdev_realize_and_unref(splitter, NULL, _fatal); +for (i = 0; i <
[PULL 06/11] hw/openrisc: Initialize timer time at startup
The last_clk time was initialized at zero, this means when we calculate the first delta we will calculate 0 vs current time which could cause unnecessary hops. This patch moves timer initialization to the cpu reset. There are two resets registered here: 1. Per cpu timer mask (ttmr) reset. 2. Global cpu timer (last_clk and ttcr) reset, attached to the first cpu only. Reviewed-by: Richard Henderson Signed-off-by: Stafford Horne --- hw/openrisc/cputimer.c | 22 +- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/hw/openrisc/cputimer.c b/hw/openrisc/cputimer.c index 93268815d8..10163b391b 100644 --- a/hw/openrisc/cputimer.c +++ b/hw/openrisc/cputimer.c @@ -22,6 +22,7 @@ #include "cpu.h" #include "migration/vmstate.h" #include "qemu/timer.h" +#include "sysemu/reset.h" #define TIMER_PERIOD 50 /* 50 ns period for 20 MHz timer */ @@ -122,6 +123,24 @@ static void openrisc_timer_cb(void *opaque) qemu_cpu_kick(CPU(cpu)); } +/* Reset the per CPU counter state. */ +static void openrisc_count_reset(void *opaque) +{ +OpenRISCCPU *cpu = opaque; + +if (cpu->env.is_counting) { +cpu_openrisc_count_stop(cpu); +} +cpu->env.ttmr = 0x; +} + +/* Reset the global timer state. */ +static void openrisc_timer_reset(void *opaque) +{ +or1k_timer->ttcr = 0x; +or1k_timer->last_clk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); +} + static const VMStateDescription vmstate_or1k_timer = { .name = "or1k_timer", .version_id = 1, @@ -136,10 +155,11 @@ static const VMStateDescription vmstate_or1k_timer = { void cpu_openrisc_clock_init(OpenRISCCPU *cpu) { cpu->env.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, _timer_cb, cpu); -cpu->env.ttmr = 0x; +qemu_register_reset(openrisc_count_reset, cpu); if (or1k_timer == NULL) { or1k_timer = g_new0(OR1KTimerState, 1); +qemu_register_reset(openrisc_timer_reset, cpu); vmstate_register(NULL, 0, _or1k_timer, or1k_timer); } } -- 2.37.2
[PULL 01/11] hw/openrisc: Split re-usable boot time apis out to boot.c
These will be shared with the virt platform. Reviewed-by: Richard Henderson Signed-off-by: Stafford Horne --- hw/openrisc/boot.c | 116 + hw/openrisc/meson.build| 1 + hw/openrisc/openrisc_sim.c | 106 ++--- include/hw/openrisc/boot.h | 34 +++ 4 files changed, 157 insertions(+), 100 deletions(-) create mode 100644 hw/openrisc/boot.c create mode 100644 include/hw/openrisc/boot.h diff --git a/hw/openrisc/boot.c b/hw/openrisc/boot.c new file mode 100644 index 00..128ccbcba2 --- /dev/null +++ b/hw/openrisc/boot.c @@ -0,0 +1,116 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * QEMU OpenRISC boot helpers. + * + * (c) 2022 Stafford Horne + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/cpu-defs.h" +#include "elf.h" +#include "hw/loader.h" +#include "hw/openrisc/boot.h" +#include "sysemu/device_tree.h" +#include "sysemu/qtest.h" + +#include + +#define KERNEL_LOAD_ADDR 0x100 + +hwaddr openrisc_load_kernel(ram_addr_t ram_size, +const char *kernel_filename, +uint32_t *bootstrap_pc) +{ +long kernel_size; +uint64_t elf_entry; +uint64_t high_addr; +hwaddr entry; + +if (kernel_filename && !qtest_enabled()) { +kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, + _entry, NULL, _addr, NULL, 1, + EM_OPENRISC, 1, 0); +entry = elf_entry; +if (kernel_size < 0) { +kernel_size = load_uimage(kernel_filename, + , NULL, NULL, NULL, NULL); +high_addr = entry + kernel_size; +} +if (kernel_size < 0) { +kernel_size = load_image_targphys(kernel_filename, + KERNEL_LOAD_ADDR, + ram_size - KERNEL_LOAD_ADDR); +high_addr = KERNEL_LOAD_ADDR + kernel_size; +} + +if (entry <= 0) { +entry = KERNEL_LOAD_ADDR; +} + +if (kernel_size < 0) { +error_report("couldn't load the kernel '%s'", kernel_filename); +exit(1); +} +*bootstrap_pc = entry; + +return high_addr; +} +return 0; +} + +hwaddr openrisc_load_initrd(void *fdt, const char *filename, +hwaddr load_start, uint64_t mem_size) +{ +int size; +hwaddr start; + +/* We put the initrd right after the kernel; page aligned. */ +start = TARGET_PAGE_ALIGN(load_start); + +size = load_ramdisk(filename, start, mem_size - start); +if (size < 0) { +size = load_image_targphys(filename, start, mem_size - start); +if (size < 0) { +error_report("could not load ramdisk '%s'", filename); +exit(1); +} +} + +if (fdt) { +qemu_fdt_setprop_cell(fdt, "/chosen", + "linux,initrd-start", start); +qemu_fdt_setprop_cell(fdt, "/chosen", + "linux,initrd-end", start + size); +} + +return start + size; +} + +uint32_t openrisc_load_fdt(void *fdt, hwaddr load_start, + uint64_t mem_size) +{ +uint32_t fdt_addr; +int ret; +int fdtsize = fdt_totalsize(fdt); + +if (fdtsize <= 0) { +error_report("invalid device-tree"); +exit(1); +} + +/* We put fdt right after the kernel and/or initrd. */ +fdt_addr = TARGET_PAGE_ALIGN(load_start); + +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); + +rom_add_blob_fixed_as("fdt", fdt, fdtsize, fdt_addr, + _space_memory); + +return fdt_addr; +} diff --git a/hw/openrisc/meson.build b/hw/openrisc/meson.build index ec48172c9d..ab563820c5 100644 --- a/hw/openrisc/meson.build +++ b/hw/openrisc/meson.build @@ -1,5 +1,6 @@ openrisc_ss = ss.source_set() openrisc_ss.add(files('cputimer.c')) +openrisc_ss.add(files('boot.c')) openrisc_ss.add(when: 'CONFIG_OR1K_SIM', if_true: [files('openrisc_sim.c'), fdt]) hw_arch += {'openrisc': openrisc_ss} diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 35adce17ac..35da123aef 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -24,10 +24,9 @@ #include "cpu.h" #include "hw/irq.h" #include "hw/boards.h" -#include "elf.h" #include "hw/char/serial.h" #include "net/net.h" -#include "hw/loader.h" +#include "hw/openrisc/boot.h" #includ
[PULL 10/11] hw/openrisc: virt: pass random seed to fdt
From: "Jason A. Donenfeld" If the FDT contains /chosen/rng-seed, then the Linux RNG will use it to initialize early. Set this using the usual guest random number generation function. This is confirmed to successfully initialize the RNG on Linux 5.19-rc2. Signed-off-by: Jason A. Donenfeld Reviewed-by: Richard Henderson Signed-off-by: Stafford Horne --- hw/openrisc/virt.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c index 9a78234a28..f8a68a6a6b 100644 --- a/hw/openrisc/virt.c +++ b/hw/openrisc/virt.c @@ -8,6 +8,7 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" +#include "qemu/guest-random.h" #include "qapi/error.h" #include "cpu.h" #include "exec/address-spaces.h" @@ -130,6 +131,7 @@ static void openrisc_create_fdt(OR1KVirtState *state, void *fdt; int cpu; char *nodename; +uint8_t rng_seed[32]; fdt = state->fdt = create_device_tree(>fdt_size); if (!fdt) { @@ -186,6 +188,10 @@ static void openrisc_create_fdt(OR1KVirtState *state, qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline); } +/* Pass seed to RNG. */ +qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); +qemu_fdt_setprop(fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed)); + /* Create aliases node for use by devices. */ qemu_fdt_add_subnode(fdt, "/aliases"); } -- 2.37.2
[PULL 03/11] goldfish_rtc: Add big-endian property
Add a new property "big-endian" to allow configuring the RTC as either little or big endian, the default is little endian. Currently overriding the default to big endian is only used by the m68k virt platform. New platforms should prefer to use little endian and not set this. Cc: Laurent Vivier Reviewed-by: Anup Patel Reviewed-by: Richard Henderson Signed-off-by: Stafford Horne --- hw/m68k/virt.c| 1 + hw/rtc/goldfish_rtc.c | 37 ++- include/hw/rtc/goldfish_rtc.h | 2 ++ 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/hw/m68k/virt.c b/hw/m68k/virt.c index 3122c8ef2c..2f3ffc0de6 100644 --- a/hw/m68k/virt.c +++ b/hw/m68k/virt.c @@ -173,6 +173,7 @@ static void virt_init(MachineState *machine) io_base = VIRT_GF_RTC_MMIO_BASE; for (i = 0; i < VIRT_GF_RTC_NB; i++) { dev = qdev_new(TYPE_GOLDFISH_RTC); +qdev_prop_set_bit(dev, "big-endian", true); sysbus = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(sysbus, _fatal); sysbus_mmio_map(sysbus, 0, io_base); diff --git a/hw/rtc/goldfish_rtc.c b/hw/rtc/goldfish_rtc.c index 35e493be31..19a56402a0 100644 --- a/hw/rtc/goldfish_rtc.c +++ b/hw/rtc/goldfish_rtc.c @@ -216,14 +216,25 @@ static int goldfish_rtc_post_load(void *opaque, int version_id) return 0; } -static const MemoryRegionOps goldfish_rtc_ops = { -.read = goldfish_rtc_read, -.write = goldfish_rtc_write, -.endianness = DEVICE_NATIVE_ENDIAN, -.valid = { -.min_access_size = 4, -.max_access_size = 4 -} +static const MemoryRegionOps goldfish_rtc_ops[2] = { +[false] = { +.read = goldfish_rtc_read, +.write = goldfish_rtc_write, +.endianness = DEVICE_LITTLE_ENDIAN, +.valid = { +.min_access_size = 4, +.max_access_size = 4 +} +}, +[true] = { +.read = goldfish_rtc_read, +.write = goldfish_rtc_write, +.endianness = DEVICE_BIG_ENDIAN, +.valid = { +.min_access_size = 4, +.max_access_size = 4 +} +}, }; static const VMStateDescription goldfish_rtc_vmstate = { @@ -265,7 +276,8 @@ static void goldfish_rtc_realize(DeviceState *d, Error **errp) SysBusDevice *dev = SYS_BUS_DEVICE(d); GoldfishRTCState *s = GOLDFISH_RTC(d); -memory_region_init_io(>iomem, OBJECT(s), _rtc_ops, s, +memory_region_init_io(>iomem, OBJECT(s), + _rtc_ops[s->big_endian], s, "goldfish_rtc", 0x24); sysbus_init_mmio(dev, >iomem); @@ -274,10 +286,17 @@ static void goldfish_rtc_realize(DeviceState *d, Error **errp) s->timer = timer_new_ns(rtc_clock, goldfish_rtc_interrupt, s); } +static Property goldfish_rtc_properties[] = { +DEFINE_PROP_BOOL("big-endian", GoldfishRTCState, big_endian, + false), +DEFINE_PROP_END_OF_LIST(), +}; + static void goldfish_rtc_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); +device_class_set_props(dc, goldfish_rtc_properties); dc->realize = goldfish_rtc_realize; dc->reset = goldfish_rtc_reset; dc->vmsd = _rtc_vmstate; diff --git a/include/hw/rtc/goldfish_rtc.h b/include/hw/rtc/goldfish_rtc.h index 79ca7daf5d..162be33863 100644 --- a/include/hw/rtc/goldfish_rtc.h +++ b/include/hw/rtc/goldfish_rtc.h @@ -42,6 +42,8 @@ struct GoldfishRTCState { uint32_t irq_pending; uint32_t irq_enabled; uint32_t time_high; + +bool big_endian; }; #endif -- 2.37.2
[PULL 02/11] target/openrisc: Fix memory reading in debugger
In commit f0655423ca ("target/openrisc: Reorg tlb lookup") data and instruction TLB reads were combined. This, broke debugger reads where we first tried to map using the data tlb then fall back to the instruction tlb. This patch replicates this logic by first requesting a PAGE_READ protection mapping then falling back to PAGE_EXEC. Reviewed-by: Richard Henderson Signed-off-by: Stafford Horne --- target/openrisc/mmu.c | 8 +++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/target/openrisc/mmu.c b/target/openrisc/mmu.c index d7e1320998..0b8afdbacf 100644 --- a/target/openrisc/mmu.c +++ b/target/openrisc/mmu.c @@ -148,7 +148,13 @@ hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) case SR_DME | SR_IME: /* The mmu is definitely enabled. */ excp = get_phys_mmu(cpu, _addr, , addr, -PAGE_EXEC | PAGE_READ | PAGE_WRITE, +PAGE_READ, +(sr & SR_SM) != 0); +if (!excp) { +return phys_addr; +} +excp = get_phys_mmu(cpu, _addr, , addr, +PAGE_EXEC, (sr & SR_SM) != 0); return excp ? -1 : phys_addr; -- 2.37.2
[PULL 00/11] OpenRISC updates for 7.2.0
The following changes since commit 61fd710b8da8aedcea9b4f197283dc38638e4b60: Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging (2022-09-02 13:24:28 -0400) are available in the Git repository at: g...@github.com:stffrdhrn/qemu.git tags/pull-or1k-20220904 for you to fetch changes up to b14df228d7c4fe6e86e7f8a4998e9ccf4967b678: docs/system: openrisc: Add OpenRISC documentation (2022-09-04 07:02:57 +0100) OpenRISC updates for 7.2.0 Updates to add the OpenRISC virt plaform to QEMU. Highlights include: - New virt plaform with, virtio and pci bus support - OpenRISC support for MTTCG - Goldfish RTC device endianness is configurable now Jason A. Donenfeld (1): hw/openrisc: virt: pass random seed to fdt Stafford Horne (10): hw/openrisc: Split re-usable boot time apis out to boot.c target/openrisc: Fix memory reading in debugger goldfish_rtc: Add big-endian property hw/openrisc: Add the OpenRISC virtual machine hw/openrisc: Add PCI bus support to virt hw/openrisc: Initialize timer time at startup target/openrisc: Add interrupted CPU to log target/openrisc: Enable MTTCG target/openrisc: Interrupt handling fixes docs/system: openrisc: Add OpenRISC documentation configs/devices/or1k-softmmu/default.mak | 1 + configs/targets/or1k-softmmu.mak | 1 + docs/system/openrisc/cpu-features.rst| 15 + docs/system/openrisc/emulation.rst | 17 + docs/system/openrisc/or1k-sim.rst| 43 +++ docs/system/openrisc/virt.rst| 50 +++ docs/system/target-openrisc.rst | 71 docs/system/targets.rst | 1 + hw/m68k/virt.c | 1 + hw/openrisc/Kconfig | 12 + hw/openrisc/boot.c | 116 +++ hw/openrisc/cputimer.c | 22 +- hw/openrisc/meson.build | 2 + hw/openrisc/openrisc_sim.c | 106 +- hw/openrisc/virt.c | 571 +++ hw/rtc/goldfish_rtc.c| 37 +- include/hw/openrisc/boot.h | 34 ++ include/hw/rtc/goldfish_rtc.h| 2 + target/openrisc/cpu.c| 1 - target/openrisc/cpu.h| 2 + target/openrisc/interrupt.c | 4 +- target/openrisc/mmu.c| 8 +- target/openrisc/sys_helper.c | 14 +- 23 files changed, 1017 insertions(+), 114 deletions(-) create mode 100644 docs/system/openrisc/cpu-features.rst create mode 100644 docs/system/openrisc/emulation.rst create mode 100644 docs/system/openrisc/or1k-sim.rst create mode 100644 docs/system/openrisc/virt.rst create mode 100644 docs/system/target-openrisc.rst create mode 100644 hw/openrisc/boot.c create mode 100644 hw/openrisc/virt.c create mode 100644 include/hw/openrisc/boot.h Jason A. Donenfeld (1): hw/openrisc: virt: pass random seed to fdt Stafford Horne (10): hw/openrisc: Split re-usable boot time apis out to boot.c target/openrisc: Fix memory reading in debugger goldfish_rtc: Add big-endian property hw/openrisc: Add the OpenRISC virtual machine hw/openrisc: Add PCI bus support to virt hw/openrisc: Initialize timer time at startup target/openrisc: Add interrupted CPU to log target/openrisc: Enable MTTCG target/openrisc: Interrupt handling fixes docs/system: openrisc: Add OpenRISC documentation configs/devices/or1k-softmmu/default.mak | 1 + configs/targets/or1k-softmmu.mak | 1 + docs/system/openrisc/cpu-features.rst| 15 + docs/system/openrisc/emulation.rst | 17 + docs/system/openrisc/or1k-sim.rst| 43 ++ docs/system/openrisc/virt.rst| 50 ++ docs/system/target-openrisc.rst | 71 +++ docs/system/targets.rst | 1 + hw/m68k/virt.c | 1 + hw/openrisc/Kconfig | 12 + hw/openrisc/boot.c | 116 + hw/openrisc/cputimer.c | 22 +- hw/openrisc/meson.build | 2 + hw/openrisc/openrisc_sim.c | 106 + hw/openrisc/virt.c | 571 +++ hw/rtc/goldfish_rtc.c| 37 +- include/hw/openrisc/boot.h | 34 ++ include/hw/rtc/goldfish_rtc.h| 2 + target/openrisc/cpu.c| 1 - target/openrisc/cpu.h| 2 + target/openrisc/interrupt.c | 4 +- target/openrisc/mmu.c| 8 +- target/openrisc/sys_helper.c | 14 +- 23 files changed, 1017 insertions(+), 114 deletions(-) create mode 100644 docs/system/openrisc/cpu-features.rst create mode 100644 docs/system/openrisc/emulation.rst create mode 100644 docs
Re: [PATCH v3 08/11] target/openrisc: Enable MTTCG
On Fri, Jul 29, 2022 at 04:42:54PM -0700, Richard Henderson wrote: > On 7/29/22 16:01, Stafford Horne wrote: > > This patch enables multithread TCG for OpenRISC. Since the or1k shared > > syncrhonized timer can be updated from each vCPU via helpers we use a > > mutex to synchronize updates. > > > > Signed-off-by: Stafford Horne > > --- > > Since v2: > > - Removed cpu_openrisc_timer_has_advanced lock optimization, measuring > > revealed > > it did not help much. > > > > configs/targets/or1k-softmmu.mak | 1 + > > target/openrisc/cpu.h| 2 ++ > > target/openrisc/sys_helper.c | 7 ++- > > 3 files changed, 9 insertions(+), 1 deletion(-) > > Reviewed-by: Richard Henderson Thank you, I guess this whole series is a bit late for 7.1.0 now. I will post the PR after 7.1.0 is released and target it for 7.2.0. -Stafford
[PATCH v3 11/11] docs/system: openrisc: Add OpenRISC documentation
Reviewed-by: Richard Henderson Signed-off-by: Stafford Horne --- Since v2; - Added Reviewed-by docs/system/openrisc/cpu-features.rst | 15 ++ docs/system/openrisc/emulation.rst| 17 +++ docs/system/openrisc/or1k-sim.rst | 43 docs/system/openrisc/virt.rst | 50 +++ docs/system/target-openrisc.rst | 72 +++ docs/system/targets.rst | 1 + 6 files changed, 198 insertions(+) create mode 100644 docs/system/openrisc/cpu-features.rst create mode 100644 docs/system/openrisc/emulation.rst create mode 100644 docs/system/openrisc/or1k-sim.rst create mode 100644 docs/system/openrisc/virt.rst create mode 100644 docs/system/target-openrisc.rst diff --git a/docs/system/openrisc/cpu-features.rst b/docs/system/openrisc/cpu-features.rst new file mode 100644 index 00..aeb65e22ff --- /dev/null +++ b/docs/system/openrisc/cpu-features.rst @@ -0,0 +1,15 @@ +CPU Features + + +The QEMU emulation of the OpenRISC architecture provides following built in +features. + +- Shadow GPRs +- MMU TLB with 128 entries, 1 way +- Power Management (PM) +- Programmable Interrupt Controller (PIC) +- Tick Timer + +These features are on by default and the presence can be confirmed by checking +the contents of the Unit Presence Register (``UPR``) and CPU Configuration +Register (``CPUCFGR``). diff --git a/docs/system/openrisc/emulation.rst b/docs/system/openrisc/emulation.rst new file mode 100644 index 00..0af898ab20 --- /dev/null +++ b/docs/system/openrisc/emulation.rst @@ -0,0 +1,17 @@ +OpenRISC 1000 CPU architecture support +== + +QEMU's TCG emulation includes support for the OpenRISC or1200 implementation of +the OpenRISC 1000 cpu architecture. + +The or1200 cpu also has support for the following instruction subsets: + +- ORBIS32 (OpenRISC Basic Instruction Set) +- ORFPX32 (OpenRISC Floating-Point eXtension) + +In addition to the instruction subsets the QEMU TCG emulation also has support +for most Class II (optional) instructions. + +For information on all OpenRISC instructions please refer to the latest +architecture manual available on the OpenRISC website in the +`OpenRISC Architecture <https://openrisc.io/architecture>`_ section. diff --git a/docs/system/openrisc/or1k-sim.rst b/docs/system/openrisc/or1k-sim.rst new file mode 100644 index 00..ef10439737 --- /dev/null +++ b/docs/system/openrisc/or1k-sim.rst @@ -0,0 +1,43 @@ +Or1ksim board += + +The QEMU Or1ksim machine emulates the standard OpenRISC board simulator which is +also the standard SoC configuration. + +Supported devices +- + + * 16550A UART + * ETHOC Ethernet controller + * SMP (OpenRISC multicore using ompic) + +Boot options + + +The Or1ksim machine can be started using the ``-kernel`` and ``-initrd`` options +to load a Linux kernel and optional disk image. + +.. code-block:: bash + + $ qemu-system-or1k -cpu or1220 -M or1k-sim -nographic \ +-kernel vmlinux \ +-initrd initramfs.cpio.gz \ +-m 128 + +Linux guest kernel configuration +"""""""""""""""""""""""""""""""" + +The 'or1ksim_defconfig' for Linux openrisc kernels includes the right +drivers for the or1ksim machine. If you would like to run an SMP system +choose the 'simple_smp_defconfig' config. + +Hardware configuration information +"""""""""""""""""""""""""""""""""" + +The ``or1k-sim`` board automatically generates a device tree blob ("dtb") +which it passes to the guest. This provides information about the +addresses, interrupt lines and other configuration of the various devices +in the system. + +The location of the DTB will be passed in register ``r3`` to the guest operating +system. diff --git a/docs/system/openrisc/virt.rst b/docs/system/openrisc/virt.rst new file mode 100644 index 00..2fe61ac942 --- /dev/null +++ b/docs/system/openrisc/virt.rst @@ -0,0 +1,50 @@ +'virt' generic virtual platform +=== + +The ``virt`` board is a platform which does not correspond to any +real hardware; it is designed for use in virtual machines. +It is the recommended board type if you simply want to run +a guest such as Linux and do not care about reproducing the +idiosyncrasies and limitations of a particular bit of real-world +hardware. + +Supported devices +- + + * PCI/PCIe devices + * 8 virtio-mmio transport devices + * 16550A UART + * Goldfish RTC + * SiFive Test device for poweroff and reboot + * SMP (OpenRISC multicore using ompic) + +Boot options + + +The virt machine can b
[PATCH v3 08/11] target/openrisc: Enable MTTCG
This patch enables multithread TCG for OpenRISC. Since the or1k shared syncrhonized timer can be updated from each vCPU via helpers we use a mutex to synchronize updates. Signed-off-by: Stafford Horne --- Since v2: - Removed cpu_openrisc_timer_has_advanced lock optimization, measuring revealed it did not help much. configs/targets/or1k-softmmu.mak | 1 + target/openrisc/cpu.h| 2 ++ target/openrisc/sys_helper.c | 7 ++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/configs/targets/or1k-softmmu.mak b/configs/targets/or1k-softmmu.mak index 263e970870..432f855a30 100644 --- a/configs/targets/or1k-softmmu.mak +++ b/configs/targets/or1k-softmmu.mak @@ -1,3 +1,4 @@ TARGET_ARCH=openrisc +TARGET_SUPPORTS_MTTCG=y TARGET_BIG_ENDIAN=y TARGET_NEED_FDT=y diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index b9584f10d4..1d5efa5ca2 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -25,6 +25,8 @@ #include "hw/core/cpu.h" #include "qom/object.h" +#define TCG_GUEST_DEFAULT_MO (0) + #define TYPE_OPENRISC_CPU "or1k-cpu" OBJECT_DECLARE_CPU_TYPE(OpenRISCCPU, OpenRISCCPUClass, OPENRISC_CPU) diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index 48674231e7..da88ad9e77 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -145,6 +145,7 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) break; case TO_SPR(10, 0): /* TTMR */ { +qemu_mutex_lock_iothread(); if ((env->ttmr & TTMR_M) ^ (rb & TTMR_M)) { switch (rb & TTMR_M) { case TIMER_NONE: @@ -168,14 +169,16 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) env->ttmr = rb & ~TTMR_IP; cs->interrupt_request &= ~CPU_INTERRUPT_TIMER; } - cpu_openrisc_timer_update(cpu); +qemu_mutex_unlock_iothread(); } break; case TO_SPR(10, 1): /* TTCR */ +qemu_mutex_lock_iothread(); cpu_openrisc_count_set(cpu, rb); cpu_openrisc_timer_update(cpu); +qemu_mutex_unlock_iothread(); break; #endif @@ -303,7 +306,9 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, return env->ttmr; case TO_SPR(10, 1): /* TTCR */ +qemu_mutex_lock_iothread(); cpu_openrisc_count_update(cpu); +qemu_mutex_unlock_iothread(); return cpu_openrisc_count_get(cpu); #endif -- 2.37.1
[PATCH v3 03/11] goldfish_rtc: Add big-endian property
Add a new property "big-endian" to allow configuring the RTC as either little or big endian, the default is little endian. Currently overriding the default to big endian is only used by the m68k virt platform. New platforms should prefer to use little endian and not set this. Cc: Laurent Vivier Reviewed-by: Anup Patel Signed-off-by: Stafford Horne --- Since v2: - Added Reviewed-by - Changed from enum property to boolean as suggested by Richard hw/m68k/virt.c| 1 + hw/rtc/goldfish_rtc.c | 37 ++- include/hw/rtc/goldfish_rtc.h | 2 ++ 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/hw/m68k/virt.c b/hw/m68k/virt.c index 0aa383fa6b..c7a6c766e3 100644 --- a/hw/m68k/virt.c +++ b/hw/m68k/virt.c @@ -173,6 +173,7 @@ static void virt_init(MachineState *machine) io_base = VIRT_GF_RTC_MMIO_BASE; for (i = 0; i < VIRT_GF_RTC_NB; i++) { dev = qdev_new(TYPE_GOLDFISH_RTC); +qdev_prop_set_bit(dev, "big-endian", true); sysbus = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(sysbus, _fatal); sysbus_mmio_map(sysbus, 0, io_base); diff --git a/hw/rtc/goldfish_rtc.c b/hw/rtc/goldfish_rtc.c index 35e493be31..19a56402a0 100644 --- a/hw/rtc/goldfish_rtc.c +++ b/hw/rtc/goldfish_rtc.c @@ -216,14 +216,25 @@ static int goldfish_rtc_post_load(void *opaque, int version_id) return 0; } -static const MemoryRegionOps goldfish_rtc_ops = { -.read = goldfish_rtc_read, -.write = goldfish_rtc_write, -.endianness = DEVICE_NATIVE_ENDIAN, -.valid = { -.min_access_size = 4, -.max_access_size = 4 -} +static const MemoryRegionOps goldfish_rtc_ops[2] = { +[false] = { +.read = goldfish_rtc_read, +.write = goldfish_rtc_write, +.endianness = DEVICE_LITTLE_ENDIAN, +.valid = { +.min_access_size = 4, +.max_access_size = 4 +} +}, +[true] = { +.read = goldfish_rtc_read, +.write = goldfish_rtc_write, +.endianness = DEVICE_BIG_ENDIAN, +.valid = { +.min_access_size = 4, +.max_access_size = 4 +} +}, }; static const VMStateDescription goldfish_rtc_vmstate = { @@ -265,7 +276,8 @@ static void goldfish_rtc_realize(DeviceState *d, Error **errp) SysBusDevice *dev = SYS_BUS_DEVICE(d); GoldfishRTCState *s = GOLDFISH_RTC(d); -memory_region_init_io(>iomem, OBJECT(s), _rtc_ops, s, +memory_region_init_io(>iomem, OBJECT(s), + _rtc_ops[s->big_endian], s, "goldfish_rtc", 0x24); sysbus_init_mmio(dev, >iomem); @@ -274,10 +286,17 @@ static void goldfish_rtc_realize(DeviceState *d, Error **errp) s->timer = timer_new_ns(rtc_clock, goldfish_rtc_interrupt, s); } +static Property goldfish_rtc_properties[] = { +DEFINE_PROP_BOOL("big-endian", GoldfishRTCState, big_endian, + false), +DEFINE_PROP_END_OF_LIST(), +}; + static void goldfish_rtc_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); +device_class_set_props(dc, goldfish_rtc_properties); dc->realize = goldfish_rtc_realize; dc->reset = goldfish_rtc_reset; dc->vmsd = _rtc_vmstate; diff --git a/include/hw/rtc/goldfish_rtc.h b/include/hw/rtc/goldfish_rtc.h index 79ca7daf5d..162be33863 100644 --- a/include/hw/rtc/goldfish_rtc.h +++ b/include/hw/rtc/goldfish_rtc.h @@ -42,6 +42,8 @@ struct GoldfishRTCState { uint32_t irq_pending; uint32_t irq_enabled; uint32_t time_high; + +bool big_endian; }; #endif -- 2.37.1
[PATCH v3 10/11] hw/openrisc: virt: pass random seed to fdt
From: "Jason A. Donenfeld" If the FDT contains /chosen/rng-seed, then the Linux RNG will use it to initialize early. Set this using the usual guest random number generation function. This is confirmed to successfully initialize the RNG on Linux 5.19-rc2. Signed-off-by: Jason A. Donenfeld Reviewed-by: Richard Henderson Signed-off-by: Stafford Horne --- Since v2: - No changes hw/openrisc/virt.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c index 9a78234a28..f8a68a6a6b 100644 --- a/hw/openrisc/virt.c +++ b/hw/openrisc/virt.c @@ -8,6 +8,7 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" +#include "qemu/guest-random.h" #include "qapi/error.h" #include "cpu.h" #include "exec/address-spaces.h" @@ -130,6 +131,7 @@ static void openrisc_create_fdt(OR1KVirtState *state, void *fdt; int cpu; char *nodename; +uint8_t rng_seed[32]; fdt = state->fdt = create_device_tree(>fdt_size); if (!fdt) { @@ -186,6 +188,10 @@ static void openrisc_create_fdt(OR1KVirtState *state, qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline); } +/* Pass seed to RNG. */ +qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); +qemu_fdt_setprop(fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed)); + /* Create aliases node for use by devices. */ qemu_fdt_add_subnode(fdt, "/aliases"); } -- 2.37.1
[PATCH v3 07/11] target/openrisc: Add interrupted CPU to log
When we are tracing it's helpful to know which CPU's are getting interrupted, add that detail to the log line. Reviewed-by: Richard Henderson Signed-off-by: Stafford Horne --- Since v2: - Added Reviewed-by target/openrisc/interrupt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target/openrisc/interrupt.c b/target/openrisc/interrupt.c index e5724f5371..c31c6f12c4 100644 --- a/target/openrisc/interrupt.c +++ b/target/openrisc/interrupt.c @@ -83,7 +83,9 @@ void openrisc_cpu_do_interrupt(CPUState *cs) [EXCP_TRAP] = "TRAP", }; -qemu_log_mask(CPU_LOG_INT, "INT: %s\n", int_name[exception]); +qemu_log_mask(CPU_LOG_INT, "CPU: %d INT: %s\n", + cs->cpu_index, + int_name[exception]); hwaddr vect_pc = exception << 8; if (env->cpucfgr & CPUCFGR_EVBARP) { -- 2.37.1
[PATCH v3 05/11] hw/openrisc: Add PCI bus support to virt
This is mostly borrowed from xtensa and riscv as examples. The create_pcie_irq_map swizzle function is almost and exact copy but here we use a single cell interrupt, possibly we can make this generic. Signed-off-by: Stafford Horne --- Since v2: - No changes hw/openrisc/Kconfig | 3 + hw/openrisc/virt.c | 160 ++-- 2 files changed, 157 insertions(+), 6 deletions(-) diff --git a/hw/openrisc/Kconfig b/hw/openrisc/Kconfig index 202134668e..97af258b55 100644 --- a/hw/openrisc/Kconfig +++ b/hw/openrisc/Kconfig @@ -7,8 +7,11 @@ config OR1K_SIM config OR1K_VIRT bool +imply PCI_DEVICES imply VIRTIO_VGA imply TEST_DEVICES +select PCI +select PCI_EXPRESS_GENERIC_BRIDGE select GOLDFISH_RTC select SERIAL select SIFIVE_TEST diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c index 54f2732a6b..9a78234a28 100644 --- a/hw/openrisc/virt.c +++ b/hw/openrisc/virt.c @@ -17,6 +17,8 @@ #include "hw/core/split-irq.h" #include "hw/openrisc/boot.h" #include "hw/misc/sifive_test.h" +#include "hw/pci/pci.h" +#include "hw/pci-host/gpex.h" #include "hw/qdev-properties.h" #include "hw/rtc/goldfish_rtc.h" #include "hw/sysbus.h" @@ -47,6 +49,9 @@ typedef struct OR1KVirtState { enum { VIRT_DRAM, +VIRT_ECAM, +VIRT_MMIO, +VIRT_PIO, VIRT_TEST, VIRT_RTC, VIRT_VIRTIO, @@ -60,6 +65,7 @@ enum { VIRT_RTC_IRQ = 3, VIRT_VIRTIO_IRQ = 4, /* to 12 */ VIRTIO_COUNT = 8, +VIRT_PCI_IRQ_BASE = 13, /* to 17 */ }; static const struct MemmapEntry { @@ -72,6 +78,9 @@ static const struct MemmapEntry { [VIRT_RTC] = { 0x96005000, 0x1000 }, [VIRT_VIRTIO] ={ 0x9700, 0x1000 }, [VIRT_OMPIC] = { 0x9800, VIRT_CPUS_MAX * 8 }, +[VIRT_ECAM] = { 0x9e00, 0x100 }, +[VIRT_PIO] = { 0x9f00, 0x100 }, +[VIRT_MMIO] = { 0xa000, 0x1000 }, }; static struct openrisc_boot_info { @@ -115,12 +124,12 @@ static qemu_irq get_per_cpu_irq(OpenRISCCPU *cpus[], int num_cpus, int irq_pin) static void openrisc_create_fdt(OR1KVirtState *state, const struct MemmapEntry *memmap, int num_cpus, uint64_t mem_size, -const char *cmdline) +const char *cmdline, +int32_t *pic_phandle) { void *fdt; int cpu; char *nodename; -int pic_ph; fdt = state->fdt = create_device_tree(>fdt_size); if (!fdt) { @@ -163,14 +172,14 @@ static void openrisc_create_fdt(OR1KVirtState *state, nodename = (char *)"/pic"; qemu_fdt_add_subnode(fdt, nodename); -pic_ph = qemu_fdt_alloc_phandle(fdt); +*pic_phandle = qemu_fdt_alloc_phandle(fdt); qemu_fdt_setprop_string(fdt, nodename, "compatible", "opencores,or1k-pic-level"); qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells", 1); qemu_fdt_setprop(fdt, nodename, "interrupt-controller", NULL, 0); -qemu_fdt_setprop_cell(fdt, nodename, "phandle", pic_ph); +qemu_fdt_setprop_cell(fdt, nodename, "phandle", *pic_phandle); -qemu_fdt_setprop_cell(fdt, "/", "interrupt-parent", pic_ph); +qemu_fdt_setprop_cell(fdt, "/", "interrupt-parent", *pic_phandle); qemu_fdt_add_subnode(fdt, "/chosen"); if (cmdline) { @@ -275,6 +284,7 @@ static void openrisc_virt_test_init(OR1KVirtState *state, hwaddr base, g_free(nodename); } + static void openrisc_virt_rtc_init(OR1KVirtState *state, hwaddr base, hwaddr size, int num_cpus, OpenRISCCPU *cpus[], int irq_pin) @@ -296,6 +306,134 @@ static void openrisc_virt_rtc_init(OR1KVirtState *state, hwaddr base, g_free(nodename); } + +static void create_pcie_irq_map(void *fdt, char *nodename, int irq_base, +uint32_t irqchip_phandle) +{ +int pin, dev; +uint32_t irq_map_stride = 0; +uint32_t full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS * 6] = {}; +uint32_t *irq_map = full_irq_map; + +/* + * This code creates a standard swizzle of interrupts such that + * each device's first interrupt is based on it's PCI_SLOT number. + * (See pci_swizzle_map_irq_fn()) + * + * We only need one entry per interrupt in the table (not one per + * possible slot) seeing the interrupt-map-mask will allow the table + * to wrap to any number of devices. + */ +for (dev = 0; dev < GPEX_NUM_IRQS; dev++) { +int devfn = dev << 3; + +for (pin = 0; pin < GPEX_NUM_IRQS; pin++) { +int irq_nr = irq_base + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS); +
[PATCH v3 02/11] target/openrisc: Fix memory reading in debugger
In commit f0655423ca ("target/openrisc: Reorg tlb lookup") data and instruction TLB reads were combined. This, broke debugger reads where we first tried to map using the data tlb then fall back to the instruction tlb. This patch replicates this logic by first requesting a PAGE_READ protection mapping then falling back to PAGE_EXEC. Reviewed-by: Richard Henderson Signed-off-by: Stafford Horne --- Since v2: - No changes, added Reviewed-by target/openrisc/mmu.c | 8 +++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/target/openrisc/mmu.c b/target/openrisc/mmu.c index d7e1320998..0b8afdbacf 100644 --- a/target/openrisc/mmu.c +++ b/target/openrisc/mmu.c @@ -148,7 +148,13 @@ hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) case SR_DME | SR_IME: /* The mmu is definitely enabled. */ excp = get_phys_mmu(cpu, _addr, , addr, -PAGE_EXEC | PAGE_READ | PAGE_WRITE, +PAGE_READ, +(sr & SR_SM) != 0); +if (!excp) { +return phys_addr; +} +excp = get_phys_mmu(cpu, _addr, , addr, +PAGE_EXEC, (sr & SR_SM) != 0); return excp ? -1 : phys_addr; -- 2.37.1
[PATCH v3 01/11] hw/openrisc: Split re-usable boot time apis out to boot.c
These will be shared with the virt platform. Reviewed-by: Richard Henderson Signed-off-by: Stafford Horne --- Since v2: - No changes hw/openrisc/boot.c | 117 + hw/openrisc/meson.build| 1 + hw/openrisc/openrisc_sim.c | 106 ++--- include/hw/openrisc/boot.h | 34 +++ 4 files changed, 158 insertions(+), 100 deletions(-) create mode 100644 hw/openrisc/boot.c create mode 100644 include/hw/openrisc/boot.h diff --git a/hw/openrisc/boot.c b/hw/openrisc/boot.c new file mode 100644 index 00..ca773b385e --- /dev/null +++ b/hw/openrisc/boot.c @@ -0,0 +1,117 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * QEMU OpenRISC boot helpers. + * + * (c) 2022 Stafford Horne + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/cpu-defs.h" +#include "elf.h" +#include "hw/loader.h" +#include "hw/openrisc/boot.h" +#include "sysemu/device_tree.h" +#include "sysemu/qtest.h" + +#include + +#define KERNEL_LOAD_ADDR 0x100 + +hwaddr openrisc_load_kernel(ram_addr_t ram_size, +const char *kernel_filename, +uint32_t *bootstrap_pc) +{ +long kernel_size; +uint64_t elf_entry; +uint64_t high_addr; +hwaddr entry; + +if (kernel_filename && !qtest_enabled()) { +kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, + _entry, NULL, _addr, NULL, 1, + EM_OPENRISC, 1, 0); +entry = elf_entry; +if (kernel_size < 0) { +kernel_size = load_uimage(kernel_filename, + , NULL, NULL, NULL, NULL); +high_addr = entry + kernel_size; +} +if (kernel_size < 0) { +kernel_size = load_image_targphys(kernel_filename, + KERNEL_LOAD_ADDR, + ram_size - KERNEL_LOAD_ADDR); +high_addr = KERNEL_LOAD_ADDR + kernel_size; +} + +if (entry <= 0) { +entry = KERNEL_LOAD_ADDR; +} + +if (kernel_size < 0) { +error_report("couldn't load the kernel '%s'", kernel_filename); +exit(1); +} +*bootstrap_pc = entry; + +return high_addr; +} +return 0; +} + +hwaddr openrisc_load_initrd(void *fdt, const char *filename, +hwaddr load_start, uint64_t mem_size) +{ +int size; +hwaddr start; + +/* We put the initrd right after the kernel; page aligned. */ +start = TARGET_PAGE_ALIGN(load_start); + +size = load_ramdisk(filename, start, mem_size - start); +if (size < 0) { +size = load_image_targphys(filename, start, mem_size - start); +if (size < 0) { +error_report("could not load ramdisk '%s'", filename); +exit(1); +} +} + +if (fdt) { +qemu_fdt_setprop_cell(fdt, "/chosen", + "linux,initrd-start", start); +qemu_fdt_setprop_cell(fdt, "/chosen", + "linux,initrd-end", start + size); +} + +return start + size; +} + +uint32_t openrisc_load_fdt(void *fdt, hwaddr load_start, + uint64_t mem_size) +{ +uint32_t fdt_addr; +int ret; +int fdtsize = fdt_totalsize(fdt); + +if (fdtsize <= 0) { +error_report("invalid device-tree"); +exit(1); +} + +/* We put fdt right after the kernel and/or initrd. */ +fdt_addr = TARGET_PAGE_ALIGN(load_start); + +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); + +rom_add_blob_fixed_as("fdt", fdt, fdtsize, fdt_addr, + _space_memory); + +return fdt_addr; +} + diff --git a/hw/openrisc/meson.build b/hw/openrisc/meson.build index ec48172c9d..ab563820c5 100644 --- a/hw/openrisc/meson.build +++ b/hw/openrisc/meson.build @@ -1,5 +1,6 @@ openrisc_ss = ss.source_set() openrisc_ss.add(files('cputimer.c')) +openrisc_ss.add(files('boot.c')) openrisc_ss.add(when: 'CONFIG_OR1K_SIM', if_true: [files('openrisc_sim.c'), fdt]) hw_arch += {'openrisc': openrisc_ss} diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 35adce17ac..35da123aef 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -24,10 +24,9 @@ #include "cpu.h" #include "hw/irq.h" #include "hw/boards.h" -#include "elf.h" #include "hw/char/serial.h" #include "net/net.h" -#include "hw/loader.h" +#include "hw/openrisc/boot.h" #includ
[PATCH v3 09/11] target/openrisc: Interrupt handling fixes
When running SMP systems we sometimes were seeing lockups where IPI interrupts were being raised by never handled. This looks to be caused by 2 issues in the openrisc interrupt handling logic. 1. After clearing an interrupt the openrisc_cpu_set_irq handler will always clear PICSR. This is not correct as masked interrupts should still be visible in PICSR. 2. After setting PICMR (mask register) and exposed interrupts should cause an interrupt to be raised. This was not being done so add it. This patch fixes both issues. Reviewed-by: Richard Henderson Signed-off-by: Stafford Horne --- Since v2: - Added Reviewed-by target/openrisc/cpu.c| 1 - target/openrisc/sys_helper.c | 7 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index 41d1b2a24a..cb9f35f408 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -98,7 +98,6 @@ static void openrisc_cpu_set_irq(void *opaque, int irq, int level) cpu_interrupt(cs, CPU_INTERRUPT_HARD); } else { cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); -cpu->env.picsr = 0; } } #endif diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index da88ad9e77..09b3c97d7c 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -139,6 +139,13 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) break; case TO_SPR(9, 0): /* PICMR */ env->picmr = rb; +qemu_mutex_lock_iothread(); +if (env->picsr & env->picmr) { +cpu_interrupt(cs, CPU_INTERRUPT_HARD); +} else { +cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); +} +qemu_mutex_unlock_iothread(); break; case TO_SPR(9, 2): /* PICSR */ env->picsr &= ~rb; -- 2.37.1
[PATCH v3 06/11] hw/openrisc: Initialize timer time at startup
The last_clk time was initialized at zero, this means when we calculate the first delta we will calculate 0 vs current time which could cause unnecessary hops. This patch moves timer initialization to the cpu reset. There are two resets registered here: 1. Per cpu timer mask (ttmr) reset. 2. Global cpu timer (last_clk and ttcr) reset, attached to the first cpu only. Signed-off-by: Stafford Horne --- Since v2: - Moved timer init from init to reset suggested by Richard hw/openrisc/cputimer.c | 22 +- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/hw/openrisc/cputimer.c b/hw/openrisc/cputimer.c index 93268815d8..10163b391b 100644 --- a/hw/openrisc/cputimer.c +++ b/hw/openrisc/cputimer.c @@ -22,6 +22,7 @@ #include "cpu.h" #include "migration/vmstate.h" #include "qemu/timer.h" +#include "sysemu/reset.h" #define TIMER_PERIOD 50 /* 50 ns period for 20 MHz timer */ @@ -122,6 +123,24 @@ static void openrisc_timer_cb(void *opaque) qemu_cpu_kick(CPU(cpu)); } +/* Reset the per CPU counter state. */ +static void openrisc_count_reset(void *opaque) +{ +OpenRISCCPU *cpu = opaque; + +if (cpu->env.is_counting) { +cpu_openrisc_count_stop(cpu); +} +cpu->env.ttmr = 0x; +} + +/* Reset the global timer state. */ +static void openrisc_timer_reset(void *opaque) +{ +or1k_timer->ttcr = 0x; +or1k_timer->last_clk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); +} + static const VMStateDescription vmstate_or1k_timer = { .name = "or1k_timer", .version_id = 1, @@ -136,10 +155,11 @@ static const VMStateDescription vmstate_or1k_timer = { void cpu_openrisc_clock_init(OpenRISCCPU *cpu) { cpu->env.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, _timer_cb, cpu); -cpu->env.ttmr = 0x; +qemu_register_reset(openrisc_count_reset, cpu); if (or1k_timer == NULL) { or1k_timer = g_new0(OR1KTimerState, 1); +qemu_register_reset(openrisc_timer_reset, cpu); vmstate_register(NULL, 0, _or1k_timer, or1k_timer); } } -- 2.37.1
[PATCH v3 04/11] hw/openrisc: Add the OpenRISC virtual machine
This patch adds the OpenRISC virtual machine 'virt' for OpenRISC. This platform allows for a convenient CI platform for toolchain, software ports and the OpenRISC linux kernel port. Much of this has been sourced from the m68k and riscv virt platforms. The platform provides: - OpenRISC SMP with up to 4 cpus - A virtio bus with up to 8 devices - Standard ns16550a serial - Goldfish RTC - SiFive TEST device for poweroff and reboot - Generated Device Tree to automatically configure the guest kernel Signed-off-by: Stafford Horne --- Since v2: - No changes configs/devices/or1k-softmmu/default.mak | 1 + hw/openrisc/Kconfig | 9 + hw/openrisc/meson.build | 1 + hw/openrisc/virt.c | 417 +++ 4 files changed, 428 insertions(+) create mode 100644 hw/openrisc/virt.c diff --git a/configs/devices/or1k-softmmu/default.mak b/configs/devices/or1k-softmmu/default.mak index 168101c39a..89c39e3123 100644 --- a/configs/devices/or1k-softmmu/default.mak +++ b/configs/devices/or1k-softmmu/default.mak @@ -3,3 +3,4 @@ # Boards: # CONFIG_OR1K_SIM=y +CONFIG_OR1K_VIRT=y diff --git a/hw/openrisc/Kconfig b/hw/openrisc/Kconfig index 8f284f3ba0..202134668e 100644 --- a/hw/openrisc/Kconfig +++ b/hw/openrisc/Kconfig @@ -4,3 +4,12 @@ config OR1K_SIM select OPENCORES_ETH select OMPIC select SPLIT_IRQ + +config OR1K_VIRT +bool +imply VIRTIO_VGA +imply TEST_DEVICES +select GOLDFISH_RTC +select SERIAL +select SIFIVE_TEST +select VIRTIO_MMIO diff --git a/hw/openrisc/meson.build b/hw/openrisc/meson.build index ab563820c5..2dbc6365bb 100644 --- a/hw/openrisc/meson.build +++ b/hw/openrisc/meson.build @@ -2,5 +2,6 @@ openrisc_ss = ss.source_set() openrisc_ss.add(files('cputimer.c')) openrisc_ss.add(files('boot.c')) openrisc_ss.add(when: 'CONFIG_OR1K_SIM', if_true: [files('openrisc_sim.c'), fdt]) +openrisc_ss.add(when: 'CONFIG_OR1K_VIRT', if_true: [files('virt.c'), fdt]) hw_arch += {'openrisc': openrisc_ss} diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c new file mode 100644 index 00..54f2732a6b --- /dev/null +++ b/hw/openrisc/virt.c @@ -0,0 +1,417 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * OpenRISC QEMU virtual machine. + * + * (c) 2022 Stafford Horne + */ + +#include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "cpu.h" +#include "exec/address-spaces.h" +#include "hw/irq.h" +#include "hw/boards.h" +#include "hw/char/serial.h" +#include "hw/core/split-irq.h" +#include "hw/openrisc/boot.h" +#include "hw/misc/sifive_test.h" +#include "hw/qdev-properties.h" +#include "hw/rtc/goldfish_rtc.h" +#include "hw/sysbus.h" +#include "hw/virtio/virtio-mmio.h" +#include "sysemu/device_tree.h" +#include "sysemu/sysemu.h" +#include "sysemu/qtest.h" +#include "sysemu/reset.h" + +#include + +#define VIRT_CPUS_MAX 4 +#define VIRT_CLK_MHZ 2000 + +#define TYPE_VIRT_MACHINE MACHINE_TYPE_NAME("virt") +#define VIRT_MACHINE(obj) \ +OBJECT_CHECK(OR1KVirtState, (obj), TYPE_VIRT_MACHINE) + +typedef struct OR1KVirtState { +/*< private >*/ +MachineState parent_obj; + +/*< public >*/ +void *fdt; +int fdt_size; + +} OR1KVirtState; + +enum { +VIRT_DRAM, +VIRT_TEST, +VIRT_RTC, +VIRT_VIRTIO, +VIRT_UART, +VIRT_OMPIC, +}; + +enum { +VIRT_OMPIC_IRQ = 1, +VIRT_UART_IRQ = 2, +VIRT_RTC_IRQ = 3, +VIRT_VIRTIO_IRQ = 4, /* to 12 */ +VIRTIO_COUNT = 8, +}; + +static const struct MemmapEntry { +hwaddr base; +hwaddr size; +} virt_memmap[] = { +[VIRT_DRAM] = { 0x, 0 }, +[VIRT_UART] = { 0x9000, 0x100 }, +[VIRT_TEST] = { 0x9600,0x8 }, +[VIRT_RTC] = { 0x96005000, 0x1000 }, +[VIRT_VIRTIO] ={ 0x9700, 0x1000 }, +[VIRT_OMPIC] = { 0x9800, VIRT_CPUS_MAX * 8 }, +}; + +static struct openrisc_boot_info { +uint32_t bootstrap_pc; +uint32_t fdt_addr; +} boot_info; + +static void main_cpu_reset(void *opaque) +{ +OpenRISCCPU *cpu = opaque; +CPUState *cs = CPU(cpu); + +cpu_reset(CPU(cpu)); + +cpu_set_pc(cs, boot_info.bootstrap_pc); +cpu_set_gpr(>env, 3, boot_info.fdt_addr); +} + +static qemu_irq get_cpu_irq(OpenRISCCPU *cpus[], int cpunum, int irq_pin) +{ +return qdev_get_gpio_in_named(DEVICE(cpus[cpunum]), "IRQ", irq_pin); +} + +static qemu_irq get_per_cpu_irq(OpenRISCCPU *cpus[], int num_cpus, int irq_pin) +{ +int i; + +if (num_cpus > 1) { +DeviceState *splitter = qdev_new(TYPE_SPLIT_IRQ); +qdev_prop_set_uint32(splitter, "num-lines", num_cpus); +qdev_realize_and_unref(splitter, NULL, _fatal);
[PATCH v3 00/11] OpenRISC Virtual Machine
Hello, This is the OpenRISC Virtual Machine plaform which we are now using for OpenRISC CI such as the wireguard testing that Jason has been working on. I also have recently used it to test glibc 2.36 and it worked well. Previous glibc testsuite runs on my FPGA board took about 3 days, running on qemu virt now takes 6 hours. The first few patches help get OpenRISC QEMU ready for the virtual machine. There is one bug fix for GDB debugging there too. Next we have the Virt patch followed by a separate patch to add PCI support which is split out because it's a bit easier to review that way I thought. The next few patches are fixes to get the Multicore platform stable, such as adding MTTCG support and fixing some interrupt and timer related bugs. The platform is relatively stable now, but every few boots we get about 10 second hangs. However, overall this is much more stable than the SMP support we had before. So I want to submit this for review and maybe upstream it before tracking down these last issues which might take significant more time. This is being tested with the or1k-5.20-updates kernel branch here: https://github.com/stffrdhrn/linux/commits/or1k-5.20-updates This tree has support for: OpenRISC PCI and virt_defconfig and an irqchip bug fix. Changes since v2: - Changed goldfish_rtc endian property to boolean - Moved or1k timer init from init to reset - Removed cpu_openrisc_timer_has_advanced lock optimization in MTTCG patch, measuring revealed it did not help much. Changes since v1: - Dropped semihosting support - Added PCI support - Added OpenRISC documentation - Added OpenRISC support for MTTCG - Support Configurating Goldfish RTC endianness - Added a few bug fix patches Jason A. Donenfeld (1): hw/openrisc: virt: pass random seed to fdt Stafford Horne (10): hw/openrisc: Split re-usable boot time apis out to boot.c target/openrisc: Fix memory reading in debugger goldfish_rtc: Add big-endian property hw/openrisc: Add the OpenRISC virtual machine hw/openrisc: Add PCI bus support to virt hw/openrisc: Initialize timer time at startup target/openrisc: Add interrupted CPU to log target/openrisc: Enable MTTCG target/openrisc: Interrupt handling fixes docs/system: openrisc: Add OpenRISC documentation configs/devices/or1k-softmmu/default.mak | 1 + configs/targets/or1k-softmmu.mak | 1 + docs/system/openrisc/cpu-features.rst| 15 + docs/system/openrisc/emulation.rst | 17 + docs/system/openrisc/or1k-sim.rst| 43 ++ docs/system/openrisc/virt.rst| 50 ++ docs/system/target-openrisc.rst | 72 +++ docs/system/targets.rst | 1 + hw/m68k/virt.c | 1 + hw/openrisc/Kconfig | 12 + hw/openrisc/boot.c | 117 + hw/openrisc/cputimer.c | 22 +- hw/openrisc/meson.build | 2 + hw/openrisc/openrisc_sim.c | 106 + hw/openrisc/virt.c | 571 +++ hw/rtc/goldfish_rtc.c| 37 +- include/hw/openrisc/boot.h | 34 ++ include/hw/rtc/goldfish_rtc.h| 2 + target/openrisc/cpu.c| 1 - target/openrisc/cpu.h| 2 + target/openrisc/interrupt.c | 4 +- target/openrisc/mmu.c| 8 +- target/openrisc/sys_helper.c | 14 +- 23 files changed, 1019 insertions(+), 114 deletions(-) create mode 100644 docs/system/openrisc/cpu-features.rst create mode 100644 docs/system/openrisc/emulation.rst create mode 100644 docs/system/openrisc/or1k-sim.rst create mode 100644 docs/system/openrisc/virt.rst create mode 100644 docs/system/target-openrisc.rst create mode 100644 hw/openrisc/boot.c create mode 100644 hw/openrisc/virt.c create mode 100644 include/hw/openrisc/boot.h -- 2.37.1
Re: [PATCH v2 03/11] goldfish_rtc: Add endianness property
On Mon, Jul 04, 2022 at 12:23:23PM +0200, Laurent Vivier wrote: > On 04/07/2022 12:21, Richard Henderson wrote: > > On 7/4/22 15:46, Laurent Vivier wrote: > > > On 04/07/2022 11:59, Richard Henderson wrote: > > > > On 7/4/22 02:58, Stafford Horne wrote: > > > > > -static const MemoryRegionOps goldfish_rtc_ops = { > > > > > - .read = goldfish_rtc_read, > > > > > - .write = goldfish_rtc_write, > > > > > - .endianness = DEVICE_NATIVE_ENDIAN, > > > > > - .valid = { > > > > > - .min_access_size = 4, > > > > > - .max_access_size = 4 > > > > > - } > > > > > +static const MemoryRegionOps goldfish_rtc_ops[3] = { > > > > > + [DEVICE_NATIVE_ENDIAN] = { > > > > > + .read = goldfish_rtc_read, > > > > > + .write = goldfish_rtc_write, > > > > > + .endianness = DEVICE_NATIVE_ENDIAN, > > > > > + .valid = { > > > > > + .min_access_size = 4, > > > > > + .max_access_size = 4 > > > > > + } > > > > > + }, > > > > > + [DEVICE_LITTLE_ENDIAN] = { > > > > > + .read = goldfish_rtc_read, > > > > > + .write = goldfish_rtc_write, > > > > > + .endianness = DEVICE_LITTLE_ENDIAN, > > > > > + .valid = { > > > > > + .min_access_size = 4, > > > > > + .max_access_size = 4 > > > > > + } > > > > > + }, > > > > > + [DEVICE_BIG_ENDIAN] = { > > > > > + .read = goldfish_rtc_read, > > > > > + .write = goldfish_rtc_write, > > > > > + .endianness = DEVICE_BIG_ENDIAN, > > > > > + .valid = { > > > > > + .min_access_size = 4, > > > > > + .max_access_size = 4 > > > > > + } > > > > > + }, > > > > > }; > > > > > > > > You don't need 3 copies, only big and little. > > > > > > > > > +static Property goldfish_rtc_properties[] = { > > > > > + DEFINE_PROP_UINT8("endianness", GoldfishRTCState, endianness, > > > > > + DEVICE_NATIVE_ENDIAN), > > > > > + DEFINE_PROP_END_OF_LIST(), > > > > > +}; > > > > > > > > ... and I think the clear desire for default is little-endian. > > > > I would make the property be bool, and add a comment that this > > > > is only for m68k compatibility, so don't use it in new code. > > > > > > m68k doesn't really need this. > > > > > > kernel with the m68k virt machine and goldfish device supports > > > "native" mode so I think it's not needed to add another layer of > > > complexity for it. > > > > "Another level"? I'm talking about removing "native", and only having > > "big" and "little", which is less complexity. > > "Less complexity" is to keep only native. I'm not against the change, I'm > just saying it's not needed by m68k. Hi Laurent, I would agree if we only had m68k. But I am making this change so that OpenRISC (another big-endian architecture) could use this. In the OpenRISC case we want to use this as little-endian so no kernel updates would be needed. So in the end we will have the following qemu platforms: riscv{LE}--->goldfish_rtc{LE} mips-longsoon3{LE}-->goldfish_rtc{LE} openrisc{BE}>goldfish_rtc{LE} (LE to BE conversion done in driver) m68k{BE}>goldfish_rtc{BE} (only big-endian user) -Stafford
Re: [PATCH v2 03/11] goldfish_rtc: Add endianness property
On Mon, Jul 04, 2022 at 03:29:57PM +0530, Richard Henderson wrote: > On 7/4/22 02:58, Stafford Horne wrote: > > -static const MemoryRegionOps goldfish_rtc_ops = { > > -.read = goldfish_rtc_read, > > -.write = goldfish_rtc_write, > > -.endianness = DEVICE_NATIVE_ENDIAN, > > -.valid = { > > -.min_access_size = 4, > > -.max_access_size = 4 > > -} > > +static const MemoryRegionOps goldfish_rtc_ops[3] = { > > +[DEVICE_NATIVE_ENDIAN] = { > > +.read = goldfish_rtc_read, > > +.write = goldfish_rtc_write, > > +.endianness = DEVICE_NATIVE_ENDIAN, > > +.valid = { > > +.min_access_size = 4, > > +.max_access_size = 4 > > +} > > +}, > > +[DEVICE_LITTLE_ENDIAN] = { > > +.read = goldfish_rtc_read, > > +.write = goldfish_rtc_write, > > +.endianness = DEVICE_LITTLE_ENDIAN, > > +.valid = { > > +.min_access_size = 4, > > +.max_access_size = 4 > > +} > > +}, > > +[DEVICE_BIG_ENDIAN] = { > > +.read = goldfish_rtc_read, > > +.write = goldfish_rtc_write, > > +.endianness = DEVICE_BIG_ENDIAN, > > +.valid = { > > +.min_access_size = 4, > > +.max_access_size = 4 > > +} > > +}, > > }; > > You don't need 3 copies, only big and little. > > > +static Property goldfish_rtc_properties[] = { > > +DEFINE_PROP_UINT8("endianness", GoldfishRTCState, endianness, > > + DEVICE_NATIVE_ENDIAN), > > +DEFINE_PROP_END_OF_LIST(), > > +}; > > ... and I think the clear desire for default is little-endian. I would make > the property be bool, and add a comment that this is only for m68k > compatibility, so don't use it in new code. Yeah, that makes sense. -Stafford
Re: [PATCH v2 06/11] hw/openrisc: Initialize timer time at startupi
On Mon, Jul 04, 2022 at 03:33:26PM +0530, Richard Henderson wrote: > On 7/4/22 02:58, Stafford Horne wrote: > > The last_clk time was initialized at zero, this means when we calculate > > the first delta we will calculate 0 vs current time which could cause > > unnecessary hops. > > > > Initialize last_clk to the qemu clock on initialization. > > > > Signed-off-by: Stafford Horne > > --- > > hw/openrisc/cputimer.c | 1 + > > 1 file changed, 1 insertion(+) > > > > diff --git a/hw/openrisc/cputimer.c b/hw/openrisc/cputimer.c > > index 93268815d8..4dbba3a3d4 100644 > > --- a/hw/openrisc/cputimer.c > > +++ b/hw/openrisc/cputimer.c > > @@ -140,6 +140,7 @@ void cpu_openrisc_clock_init(OpenRISCCPU *cpu) > > if (or1k_timer == NULL) { > > or1k_timer = g_new0(OR1KTimerState, 1); > > +or1k_timer->last_clk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); > > vmstate_register(NULL, 0, _or1k_timer, or1k_timer); > > } > > } > > Init doesn't seem right. Should be in reset? Good point, I think reset would be better.
Re: [PATCH v2 08/11] target/openrisc: Enable MTTCG
On Mon, Jul 04, 2022 at 03:37:04PM +0530, Richard Henderson wrote: > On 7/4/22 02:58, Stafford Horne wrote: > > case TO_SPR(10, 1): /* TTCR */ > > -cpu_openrisc_count_update(cpu); > > +if (cpu_openrisc_timer_has_advanced(cpu)) { > > +qemu_mutex_lock_iothread(); > > +cpu_openrisc_count_update(cpu); > > +qemu_mutex_unlock_iothread(); > > +} > > Lock around the whole if, I think. Otherwise looks good. Well, actually the cpu_openrisc_timer_has_advanced read is done once outside the lock as an optimization to avoid taking the lock when it is not needed. i.e. if we have 4 cores that all try to update the clock at the same time in theory only one will have to take the lock and update the shared timer. But I do see that could be flawed as after it takes the lock the timer could have been updated by then. Ill move it inside and see if there is any perfromance hit / increase in the sync-profile. > Reviewed-by: Richard Henderson > > > r~
Re: [PATCH v2 07/11] target/openrisc: Add interrupted CPU to log
On Mon, Jul 04, 2022 at 03:34:52PM +0530, Richard Henderson wrote: > On 7/4/22 02:58, Stafford Horne wrote: > > When we are tracing it's helpful to know which CPU's are getting > > interrupted, att that detail to the log line. > > "at". > > Reviewed-by: Richard Henderson Actually it should be "add", thanks I fixed it. -Stafford
[PATCH v2 11/11] docs/system: openrisc: Add OpenRISC documentation
Signed-off-by: Stafford Horne --- docs/system/openrisc/cpu-features.rst | 15 ++ docs/system/openrisc/emulation.rst| 17 +++ docs/system/openrisc/or1k-sim.rst | 43 docs/system/openrisc/virt.rst | 50 +++ docs/system/target-openrisc.rst | 72 +++ docs/system/targets.rst | 1 + 6 files changed, 198 insertions(+) create mode 100644 docs/system/openrisc/cpu-features.rst create mode 100644 docs/system/openrisc/emulation.rst create mode 100644 docs/system/openrisc/or1k-sim.rst create mode 100644 docs/system/openrisc/virt.rst create mode 100644 docs/system/target-openrisc.rst diff --git a/docs/system/openrisc/cpu-features.rst b/docs/system/openrisc/cpu-features.rst new file mode 100644 index 00..aeb65e22ff --- /dev/null +++ b/docs/system/openrisc/cpu-features.rst @@ -0,0 +1,15 @@ +CPU Features + + +The QEMU emulation of the OpenRISC architecture provides following built in +features. + +- Shadow GPRs +- MMU TLB with 128 entries, 1 way +- Power Management (PM) +- Programmable Interrupt Controller (PIC) +- Tick Timer + +These features are on by default and the presence can be confirmed by checking +the contents of the Unit Presence Register (``UPR``) and CPU Configuration +Register (``CPUCFGR``). diff --git a/docs/system/openrisc/emulation.rst b/docs/system/openrisc/emulation.rst new file mode 100644 index 00..0af898ab20 --- /dev/null +++ b/docs/system/openrisc/emulation.rst @@ -0,0 +1,17 @@ +OpenRISC 1000 CPU architecture support +== + +QEMU's TCG emulation includes support for the OpenRISC or1200 implementation of +the OpenRISC 1000 cpu architecture. + +The or1200 cpu also has support for the following instruction subsets: + +- ORBIS32 (OpenRISC Basic Instruction Set) +- ORFPX32 (OpenRISC Floating-Point eXtension) + +In addition to the instruction subsets the QEMU TCG emulation also has support +for most Class II (optional) instructions. + +For information on all OpenRISC instructions please refer to the latest +architecture manual available on the OpenRISC website in the +`OpenRISC Architecture <https://openrisc.io/architecture>`_ section. diff --git a/docs/system/openrisc/or1k-sim.rst b/docs/system/openrisc/or1k-sim.rst new file mode 100644 index 00..ef10439737 --- /dev/null +++ b/docs/system/openrisc/or1k-sim.rst @@ -0,0 +1,43 @@ +Or1ksim board += + +The QEMU Or1ksim machine emulates the standard OpenRISC board simulator which is +also the standard SoC configuration. + +Supported devices +- + + * 16550A UART + * ETHOC Ethernet controller + * SMP (OpenRISC multicore using ompic) + +Boot options + + +The Or1ksim machine can be started using the ``-kernel`` and ``-initrd`` options +to load a Linux kernel and optional disk image. + +.. code-block:: bash + + $ qemu-system-or1k -cpu or1220 -M or1k-sim -nographic \ +-kernel vmlinux \ +-initrd initramfs.cpio.gz \ +-m 128 + +Linux guest kernel configuration +"""""""""""""""""""""""""""""""" + +The 'or1ksim_defconfig' for Linux openrisc kernels includes the right +drivers for the or1ksim machine. If you would like to run an SMP system +choose the 'simple_smp_defconfig' config. + +Hardware configuration information +"""""""""""""""""""""""""""""""""" + +The ``or1k-sim`` board automatically generates a device tree blob ("dtb") +which it passes to the guest. This provides information about the +addresses, interrupt lines and other configuration of the various devices +in the system. + +The location of the DTB will be passed in register ``r3`` to the guest operating +system. diff --git a/docs/system/openrisc/virt.rst b/docs/system/openrisc/virt.rst new file mode 100644 index 00..2fe61ac942 --- /dev/null +++ b/docs/system/openrisc/virt.rst @@ -0,0 +1,50 @@ +'virt' generic virtual platform +=== + +The ``virt`` board is a platform which does not correspond to any +real hardware; it is designed for use in virtual machines. +It is the recommended board type if you simply want to run +a guest such as Linux and do not care about reproducing the +idiosyncrasies and limitations of a particular bit of real-world +hardware. + +Supported devices +- + + * PCI/PCIe devices + * 8 virtio-mmio transport devices + * 16550A UART + * Goldfish RTC + * SiFive Test device for poweroff and reboot + * SMP (OpenRISC multicore using ompic) + +Boot options + + +The virt machine can be started using the ``-kernel`` and ``-initrd`` option
[PATCH v2 10/11] hw/openrisc: virt: pass random seed to fdt
From: "Jason A. Donenfeld" If the FDT contains /chosen/rng-seed, then the Linux RNG will use it to initialize early. Set this using the usual guest random number generation function. This is confirmed to successfully initialize the RNG on Linux 5.19-rc2. Cc: Stafford Horne Signed-off-by: Jason A. Donenfeld Signed-off-by: Stafford Horne --- hw/openrisc/virt.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c index f1d1293eeb..a301d0d769 100644 --- a/hw/openrisc/virt.c +++ b/hw/openrisc/virt.c @@ -8,6 +8,7 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" +#include "qemu/guest-random.h" #include "qapi/error.h" #include "cpu.h" #include "exec/address-spaces.h" @@ -130,6 +131,7 @@ static void openrisc_create_fdt(OR1KVirtState *state, void *fdt; int cpu; char *nodename; +uint8_t rng_seed[32]; fdt = state->fdt = create_device_tree(>fdt_size); if (!fdt) { @@ -186,6 +188,10 @@ static void openrisc_create_fdt(OR1KVirtState *state, qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline); } +/* Pass seed to RNG. */ +qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); +qemu_fdt_setprop(fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed)); + /* Create aliases node for use by devices. */ qemu_fdt_add_subnode(fdt, "/aliases"); } -- 2.36.1
[PATCH v2 08/11] target/openrisc: Enable MTTCG
This patch enables multithread TCG for OpenRISC. Since the or1k shared syncrhonized timer can be updated from each vCPU via helpers we use a mutex to synchronize updates. Signed-off-by: Stafford Horne --- configs/targets/or1k-softmmu.mak | 1 + hw/openrisc/cputimer.c | 17 + target/openrisc/cpu.h| 3 +++ target/openrisc/sys_helper.c | 11 +-- 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/configs/targets/or1k-softmmu.mak b/configs/targets/or1k-softmmu.mak index 263e970870..432f855a30 100644 --- a/configs/targets/or1k-softmmu.mak +++ b/configs/targets/or1k-softmmu.mak @@ -1,3 +1,4 @@ TARGET_ARCH=openrisc +TARGET_SUPPORTS_MTTCG=y TARGET_BIG_ENDIAN=y TARGET_NEED_FDT=y diff --git a/hw/openrisc/cputimer.c b/hw/openrisc/cputimer.c index 4dbba3a3d4..2298eff8b9 100644 --- a/hw/openrisc/cputimer.c +++ b/hw/openrisc/cputimer.c @@ -43,6 +43,23 @@ uint32_t cpu_openrisc_count_get(OpenRISCCPU *cpu) return or1k_timer->ttcr; } +/* + * Check to see if calling cpu_openrisc_count_update will + * actually advance the time. + * + * Used in hot spots to avoid taking expensive locks. + */ +bool cpu_openrisc_timer_has_advanced(OpenRISCCPU *cpu) +{ +uint64_t now; + +if (!cpu->env.is_counting) { +return false; +} +now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); +return (now - or1k_timer->last_clk) >= TIMER_PERIOD; +} + /* Add elapsed ticks to ttcr */ void cpu_openrisc_count_update(OpenRISCCPU *cpu) { diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index b9584f10d4..5354d681f5 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -25,6 +25,8 @@ #include "hw/core/cpu.h" #include "qom/object.h" +#define TCG_GUEST_DEFAULT_MO (0) + #define TYPE_OPENRISC_CPU "or1k-cpu" OBJECT_DECLARE_CPU_TYPE(OpenRISCCPU, OpenRISCCPUClass, OPENRISC_CPU) @@ -333,6 +335,7 @@ void cpu_openrisc_pic_init(OpenRISCCPU *cpu); /* hw/openrisc_timer.c */ void cpu_openrisc_clock_init(OpenRISCCPU *cpu); +bool cpu_openrisc_timer_has_advanced(OpenRISCCPU *cpu); uint32_t cpu_openrisc_count_get(OpenRISCCPU *cpu); void cpu_openrisc_count_set(OpenRISCCPU *cpu, uint32_t val); void cpu_openrisc_count_update(OpenRISCCPU *cpu); diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index 48674231e7..7c0d3d6187 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -145,6 +145,7 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) break; case TO_SPR(10, 0): /* TTMR */ { +qemu_mutex_lock_iothread(); if ((env->ttmr & TTMR_M) ^ (rb & TTMR_M)) { switch (rb & TTMR_M) { case TIMER_NONE: @@ -168,14 +169,16 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) env->ttmr = rb & ~TTMR_IP; cs->interrupt_request &= ~CPU_INTERRUPT_TIMER; } - cpu_openrisc_timer_update(cpu); +qemu_mutex_unlock_iothread(); } break; case TO_SPR(10, 1): /* TTCR */ +qemu_mutex_lock_iothread(); cpu_openrisc_count_set(cpu, rb); cpu_openrisc_timer_update(cpu); +qemu_mutex_unlock_iothread(); break; #endif @@ -303,7 +306,11 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, return env->ttmr; case TO_SPR(10, 1): /* TTCR */ -cpu_openrisc_count_update(cpu); +if (cpu_openrisc_timer_has_advanced(cpu)) { +qemu_mutex_lock_iothread(); +cpu_openrisc_count_update(cpu); +qemu_mutex_unlock_iothread(); +} return cpu_openrisc_count_get(cpu); #endif -- 2.36.1
[PATCH v2 09/11] target/openrisc: Interrupt handling fixes
When running SMP systems we sometimes were seeing lockups where IPI interrupts were being raised by never handled. This looks to be caused by 2 issues in the openrisc interrupt handling logic. 1. After clearing an interrupt the openrisc_cpu_set_irq handler will always clear PICSR. This is not correct as masked interrupts should still be visible in PICSR. 2. After setting PICMR (mask register) and exposed interrupts should cause an interrupt to be raised. This was not being done so add it. This patch fixes both issues. Signed-off-by: Stafford Horne --- target/openrisc/cpu.c| 1 - target/openrisc/sys_helper.c | 7 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index 41d1b2a24a..cb9f35f408 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -98,7 +98,6 @@ static void openrisc_cpu_set_irq(void *opaque, int irq, int level) cpu_interrupt(cs, CPU_INTERRUPT_HARD); } else { cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); -cpu->env.picsr = 0; } } #endif diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index 7c0d3d6187..5336110b5e 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -139,6 +139,13 @@ void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) break; case TO_SPR(9, 0): /* PICMR */ env->picmr = rb; +qemu_mutex_lock_iothread(); +if (env->picsr & env->picmr) { +cpu_interrupt(cs, CPU_INTERRUPT_HARD); +} else { +cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); +} +qemu_mutex_unlock_iothread(); break; case TO_SPR(9, 2): /* PICSR */ env->picsr &= ~rb; -- 2.36.1
[PATCH v2 04/11] hw/openrisc: Add the OpenRISC virtual machine
This patch adds the OpenRISC virtual machine 'virt' for OpenRISC. This platform allows for a convenient CI platform for toolchain, software ports and the OpenRISC linux kernel port. Much of this has been sourced from the m68k and riscv virt platforms. The platform provides: - OpenRISC SMP with up to 4 cpus - A virtio bus with up to 8 devices - Standard ns16550a serial - Goldfish RTC - SiFive TEST device for poweroff and reboot - Generated Device Tree to automatically configure the guest kernel Signed-off-by: Stafford Horne --- configs/devices/or1k-softmmu/default.mak | 1 + hw/openrisc/Kconfig | 9 + hw/openrisc/meson.build | 1 + hw/openrisc/virt.c | 424 +++ 4 files changed, 435 insertions(+) create mode 100644 hw/openrisc/virt.c diff --git a/configs/devices/or1k-softmmu/default.mak b/configs/devices/or1k-softmmu/default.mak index 168101c39a..89c39e3123 100644 --- a/configs/devices/or1k-softmmu/default.mak +++ b/configs/devices/or1k-softmmu/default.mak @@ -3,3 +3,4 @@ # Boards: # CONFIG_OR1K_SIM=y +CONFIG_OR1K_VIRT=y diff --git a/hw/openrisc/Kconfig b/hw/openrisc/Kconfig index 8f284f3ba0..202134668e 100644 --- a/hw/openrisc/Kconfig +++ b/hw/openrisc/Kconfig @@ -4,3 +4,12 @@ config OR1K_SIM select OPENCORES_ETH select OMPIC select SPLIT_IRQ + +config OR1K_VIRT +bool +imply VIRTIO_VGA +imply TEST_DEVICES +select GOLDFISH_RTC +select SERIAL +select SIFIVE_TEST +select VIRTIO_MMIO diff --git a/hw/openrisc/meson.build b/hw/openrisc/meson.build index ab563820c5..2dbc6365bb 100644 --- a/hw/openrisc/meson.build +++ b/hw/openrisc/meson.build @@ -2,5 +2,6 @@ openrisc_ss = ss.source_set() openrisc_ss.add(files('cputimer.c')) openrisc_ss.add(files('boot.c')) openrisc_ss.add(when: 'CONFIG_OR1K_SIM', if_true: [files('openrisc_sim.c'), fdt]) +openrisc_ss.add(when: 'CONFIG_OR1K_VIRT', if_true: [files('virt.c'), fdt]) hw_arch += {'openrisc': openrisc_ss} diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c new file mode 100644 index 00..bdb00f6e32 --- /dev/null +++ b/hw/openrisc/virt.c @@ -0,0 +1,424 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * OpenRISC QEMU virtual machine. + * + * (c) 2022 Stafford Horne + */ + +#include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "cpu.h" +#include "exec/address-spaces.h" +#include "hw/irq.h" +#include "hw/boards.h" +#include "hw/char/serial.h" +#include "hw/core/split-irq.h" +#include "hw/openrisc/boot.h" +#include "hw/misc/sifive_test.h" +#include "hw/qdev-properties.h" +#include "hw/rtc/goldfish_rtc.h" +#include "hw/sysbus.h" +#include "hw/virtio/virtio-mmio.h" +#include "sysemu/device_tree.h" +#include "sysemu/sysemu.h" +#include "sysemu/qtest.h" +#include "sysemu/reset.h" + +#include + +#define VIRT_CPUS_MAX 4 +#define VIRT_CLK_MHZ 2000 + +#define TYPE_VIRT_MACHINE MACHINE_TYPE_NAME("virt") +#define VIRT_MACHINE(obj) \ +OBJECT_CHECK(OR1KVirtState, (obj), TYPE_VIRT_MACHINE) + +typedef struct OR1KVirtState { +/*< private >*/ +MachineState parent_obj; + +/*< public >*/ +void *fdt; +int fdt_size; + +} OR1KVirtState; + +enum { +VIRT_DRAM, +VIRT_TEST, +VIRT_RTC, +VIRT_VIRTIO, +VIRT_UART, +VIRT_OMPIC, +}; + +enum { +VIRT_OMPIC_IRQ = 1, +VIRT_UART_IRQ = 2, +VIRT_RTC_IRQ = 3, +VIRT_VIRTIO_IRQ = 4, /* to 12 */ +VIRTIO_COUNT = 8, +}; + +static const struct MemmapEntry { +hwaddr base; +hwaddr size; +} virt_memmap[] = { +[VIRT_DRAM] = { 0x, 0 }, +[VIRT_UART] = { 0x9000, 0x100 }, +[VIRT_TEST] = { 0x9600,0x8 }, +[VIRT_RTC] = { 0x96005000, 0x1000 }, +[VIRT_VIRTIO] ={ 0x9700, 0x1000 }, +[VIRT_OMPIC] = { 0x9800, VIRT_CPUS_MAX * 8 }, +}; + +static struct openrisc_boot_info { +uint32_t bootstrap_pc; +uint32_t fdt_addr; +} boot_info; + +static void main_cpu_reset(void *opaque) +{ +OpenRISCCPU *cpu = opaque; +CPUState *cs = CPU(cpu); + +cpu_reset(CPU(cpu)); + +cpu_set_pc(cs, boot_info.bootstrap_pc); +cpu_set_gpr(>env, 3, boot_info.fdt_addr); +} + +static qemu_irq get_cpu_irq(OpenRISCCPU *cpus[], int cpunum, int irq_pin) +{ +return qdev_get_gpio_in_named(DEVICE(cpus[cpunum]), "IRQ", irq_pin); +} + +static qemu_irq get_per_cpu_irq(OpenRISCCPU *cpus[], int num_cpus, int irq_pin) +{ +int i; + +if (num_cpus > 1) { +DeviceState *splitter = qdev_new(TYPE_SPLIT_IRQ); +qdev_prop_set_uint32(splitter, "num-lines", num_cpus); +qdev_realize_and_unref(splitter, NULL, _fatal); +for (i = 0; i <
[PATCH v2 06/11] hw/openrisc: Initialize timer time at startup
The last_clk time was initialized at zero, this means when we calculate the first delta we will calculate 0 vs current time which could cause unnecessary hops. Initialize last_clk to the qemu clock on initialization. Signed-off-by: Stafford Horne --- hw/openrisc/cputimer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/openrisc/cputimer.c b/hw/openrisc/cputimer.c index 93268815d8..4dbba3a3d4 100644 --- a/hw/openrisc/cputimer.c +++ b/hw/openrisc/cputimer.c @@ -140,6 +140,7 @@ void cpu_openrisc_clock_init(OpenRISCCPU *cpu) if (or1k_timer == NULL) { or1k_timer = g_new0(OR1KTimerState, 1); +or1k_timer->last_clk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); vmstate_register(NULL, 0, _or1k_timer, or1k_timer); } } -- 2.36.1
[PATCH v2 07/11] target/openrisc: Add interrupted CPU to log
When we are tracing it's helpful to know which CPU's are getting interrupted, att that detail to the log line. Signed-off-by: Stafford Horne --- target/openrisc/interrupt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target/openrisc/interrupt.c b/target/openrisc/interrupt.c index e5724f5371..c31c6f12c4 100644 --- a/target/openrisc/interrupt.c +++ b/target/openrisc/interrupt.c @@ -83,7 +83,9 @@ void openrisc_cpu_do_interrupt(CPUState *cs) [EXCP_TRAP] = "TRAP", }; -qemu_log_mask(CPU_LOG_INT, "INT: %s\n", int_name[exception]); +qemu_log_mask(CPU_LOG_INT, "CPU: %d INT: %s\n", + cs->cpu_index, + int_name[exception]); hwaddr vect_pc = exception << 8; if (env->cpucfgr & CPUCFGR_EVBARP) { -- 2.36.1
[PATCH v2 05/11] hw/openrisc: Add PCI bus support to virt
This is mostly borrowed from xtensa and riscv as examples. The create_pcie_irq_map swizzle function is almost and exact copy but here we use a single cell interrupt, possibly we can make this generic. Signed-off-by: Stafford Horne --- hw/openrisc/Kconfig | 3 + hw/openrisc/virt.c | 160 ++-- 2 files changed, 157 insertions(+), 6 deletions(-) diff --git a/hw/openrisc/Kconfig b/hw/openrisc/Kconfig index 202134668e..97af258b55 100644 --- a/hw/openrisc/Kconfig +++ b/hw/openrisc/Kconfig @@ -7,8 +7,11 @@ config OR1K_SIM config OR1K_VIRT bool +imply PCI_DEVICES imply VIRTIO_VGA imply TEST_DEVICES +select PCI +select PCI_EXPRESS_GENERIC_BRIDGE select GOLDFISH_RTC select SERIAL select SIFIVE_TEST diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c index bdb00f6e32..f1d1293eeb 100644 --- a/hw/openrisc/virt.c +++ b/hw/openrisc/virt.c @@ -17,6 +17,8 @@ #include "hw/core/split-irq.h" #include "hw/openrisc/boot.h" #include "hw/misc/sifive_test.h" +#include "hw/pci/pci.h" +#include "hw/pci-host/gpex.h" #include "hw/qdev-properties.h" #include "hw/rtc/goldfish_rtc.h" #include "hw/sysbus.h" @@ -47,6 +49,9 @@ typedef struct OR1KVirtState { enum { VIRT_DRAM, +VIRT_ECAM, +VIRT_MMIO, +VIRT_PIO, VIRT_TEST, VIRT_RTC, VIRT_VIRTIO, @@ -60,6 +65,7 @@ enum { VIRT_RTC_IRQ = 3, VIRT_VIRTIO_IRQ = 4, /* to 12 */ VIRTIO_COUNT = 8, +VIRT_PCI_IRQ_BASE = 13, /* to 17 */ }; static const struct MemmapEntry { @@ -72,6 +78,9 @@ static const struct MemmapEntry { [VIRT_RTC] = { 0x96005000, 0x1000 }, [VIRT_VIRTIO] ={ 0x9700, 0x1000 }, [VIRT_OMPIC] = { 0x9800, VIRT_CPUS_MAX * 8 }, +[VIRT_ECAM] = { 0x9e00, 0x100 }, +[VIRT_PIO] = { 0x9f00, 0x100 }, +[VIRT_MMIO] = { 0xa000, 0x1000 }, }; static struct openrisc_boot_info { @@ -115,12 +124,12 @@ static qemu_irq get_per_cpu_irq(OpenRISCCPU *cpus[], int num_cpus, int irq_pin) static void openrisc_create_fdt(OR1KVirtState *state, const struct MemmapEntry *memmap, int num_cpus, uint64_t mem_size, -const char *cmdline) +const char *cmdline, +int32_t *pic_phandle) { void *fdt; int cpu; char *nodename; -int pic_ph; fdt = state->fdt = create_device_tree(>fdt_size); if (!fdt) { @@ -163,14 +172,14 @@ static void openrisc_create_fdt(OR1KVirtState *state, nodename = (char *)"/pic"; qemu_fdt_add_subnode(fdt, nodename); -pic_ph = qemu_fdt_alloc_phandle(fdt); +*pic_phandle = qemu_fdt_alloc_phandle(fdt); qemu_fdt_setprop_string(fdt, nodename, "compatible", "opencores,or1k-pic-level"); qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells", 1); qemu_fdt_setprop(fdt, nodename, "interrupt-controller", NULL, 0); -qemu_fdt_setprop_cell(fdt, nodename, "phandle", pic_ph); +qemu_fdt_setprop_cell(fdt, nodename, "phandle", *pic_phandle); -qemu_fdt_setprop_cell(fdt, "/", "interrupt-parent", pic_ph); +qemu_fdt_setprop_cell(fdt, "/", "interrupt-parent", *pic_phandle); qemu_fdt_add_subnode(fdt, "/chosen"); if (cmdline) { @@ -275,6 +284,7 @@ static void openrisc_virt_test_init(OR1KVirtState *state, hwaddr base, g_free(nodename); } + static void openrisc_virt_rtc_init(OR1KVirtState *state, hwaddr base, hwaddr size, int num_cpus, OpenRISCCPU *cpus[], int irq_pin) @@ -303,6 +313,134 @@ static void openrisc_virt_rtc_init(OR1KVirtState *state, hwaddr base, g_free(nodename); } + +static void create_pcie_irq_map(void *fdt, char *nodename, int irq_base, +uint32_t irqchip_phandle) +{ +int pin, dev; +uint32_t irq_map_stride = 0; +uint32_t full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS * 6] = {}; +uint32_t *irq_map = full_irq_map; + +/* + * This code creates a standard swizzle of interrupts such that + * each device's first interrupt is based on it's PCI_SLOT number. + * (See pci_swizzle_map_irq_fn()) + * + * We only need one entry per interrupt in the table (not one per + * possible slot) seeing the interrupt-map-mask will allow the table + * to wrap to any number of devices. + */ +for (dev = 0; dev < GPEX_NUM_IRQS; dev++) { +int devfn = dev << 3; + +for (pin = 0; pin < GPEX_NUM_IRQS; pin++) { +int irq_nr = irq_base + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS); +
[PATCH v2 03/11] goldfish_rtc: Add endianness property
Add an endianness property to allow configuring the RTC as either native, little or big endian. Cc: Laurent Vivier Signed-off-by: Stafford Horne --- hw/rtc/goldfish_rtc.c | 46 --- include/hw/rtc/goldfish_rtc.h | 2 ++ 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/hw/rtc/goldfish_rtc.c b/hw/rtc/goldfish_rtc.c index 35e493be31..24f6587086 100644 --- a/hw/rtc/goldfish_rtc.c +++ b/hw/rtc/goldfish_rtc.c @@ -216,14 +216,34 @@ static int goldfish_rtc_post_load(void *opaque, int version_id) return 0; } -static const MemoryRegionOps goldfish_rtc_ops = { -.read = goldfish_rtc_read, -.write = goldfish_rtc_write, -.endianness = DEVICE_NATIVE_ENDIAN, -.valid = { -.min_access_size = 4, -.max_access_size = 4 -} +static const MemoryRegionOps goldfish_rtc_ops[3] = { +[DEVICE_NATIVE_ENDIAN] = { +.read = goldfish_rtc_read, +.write = goldfish_rtc_write, +.endianness = DEVICE_NATIVE_ENDIAN, +.valid = { +.min_access_size = 4, +.max_access_size = 4 +} +}, +[DEVICE_LITTLE_ENDIAN] = { +.read = goldfish_rtc_read, +.write = goldfish_rtc_write, +.endianness = DEVICE_LITTLE_ENDIAN, +.valid = { +.min_access_size = 4, +.max_access_size = 4 +} +}, +[DEVICE_BIG_ENDIAN] = { +.read = goldfish_rtc_read, +.write = goldfish_rtc_write, +.endianness = DEVICE_BIG_ENDIAN, +.valid = { +.min_access_size = 4, +.max_access_size = 4 +} +}, }; static const VMStateDescription goldfish_rtc_vmstate = { @@ -265,7 +285,8 @@ static void goldfish_rtc_realize(DeviceState *d, Error **errp) SysBusDevice *dev = SYS_BUS_DEVICE(d); GoldfishRTCState *s = GOLDFISH_RTC(d); -memory_region_init_io(>iomem, OBJECT(s), _rtc_ops, s, +memory_region_init_io(>iomem, OBJECT(s), + _rtc_ops[s->endianness], s, "goldfish_rtc", 0x24); sysbus_init_mmio(dev, >iomem); @@ -274,10 +295,17 @@ static void goldfish_rtc_realize(DeviceState *d, Error **errp) s->timer = timer_new_ns(rtc_clock, goldfish_rtc_interrupt, s); } +static Property goldfish_rtc_properties[] = { +DEFINE_PROP_UINT8("endianness", GoldfishRTCState, endianness, + DEVICE_NATIVE_ENDIAN), +DEFINE_PROP_END_OF_LIST(), +}; + static void goldfish_rtc_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); +device_class_set_props(dc, goldfish_rtc_properties); dc->realize = goldfish_rtc_realize; dc->reset = goldfish_rtc_reset; dc->vmsd = _rtc_vmstate; diff --git a/include/hw/rtc/goldfish_rtc.h b/include/hw/rtc/goldfish_rtc.h index 79ca7daf5d..8e1aeb85e3 100644 --- a/include/hw/rtc/goldfish_rtc.h +++ b/include/hw/rtc/goldfish_rtc.h @@ -42,6 +42,8 @@ struct GoldfishRTCState { uint32_t irq_pending; uint32_t irq_enabled; uint32_t time_high; + +uint8_t endianness; }; #endif -- 2.36.1
[PATCH v2 00/11] OpenRISC Virtual Machine
Hello, This is the OpenRISC Virtual Machine plaform which we are now using for OpenRISC CI such as the wireguard testing that Jason has been working on. The first few patches help get OpenRISC QEMU ready for the virtual machine. There is one bug fix for GDB debugging there too. Next we have the Virt patch followed by a separate patch to add PCI support which is split out because it's a bit easier to review that way I thought. The next few patches are fixes to get the Multicore platform stable, such as adding MTTCG support and fixing some interrupt and timer related bugs. The platform is relatively stable now, but every few boots we get ~10 second soft lockups. My hunch is that this is another interrupt race condition where IPI's end up getting lost. However, overall the is much more stable than the SMP support we had before. So I want to submit this for review and maybe upstream it before tracking down these last issues which might take significant more time. This is being tested with my or1k-virt kernel branch here: https://github.com/stffrdhrn/linux/commits/or1k-virt This tree has support for: OpenRISC PCI and virt_defconfig and an irqchip bug fix. Changes since v1: - Dropped semihosting support - Added PCI support - Added OpenRISC documentation - Added OpenRISC support for MTTCG - Support Configurating Goldfish RTC endianness - Added a few bug fix patches -Stafford Jason A. Donenfeld (1): hw/openrisc: virt: pass random seed to fdt Stafford Horne (10): hw/openrisc: Split re-usable boot time apis out to boot.c target/openrisc: Fix memory reading in debugger goldfish_rtc: Add endianness property hw/openrisc: Add the OpenRISC virtual machine hw/openrisc: Add PCI bus support to virt hw/openrisc: Initialize timer time at startup target/openrisc: Add interrupted CPU to log target/openrisc: Enable MTTCG target/openrisc: Interrupt handling fixes docs/system: openrisc: Add OpenRISC documentation configs/devices/or1k-softmmu/default.mak | 1 + configs/targets/or1k-softmmu.mak | 1 + docs/system/openrisc/cpu-features.rst| 15 + docs/system/openrisc/emulation.rst | 17 + docs/system/openrisc/or1k-sim.rst| 43 ++ docs/system/openrisc/virt.rst| 50 ++ docs/system/target-openrisc.rst | 72 +++ docs/system/targets.rst | 1 + hw/openrisc/Kconfig | 12 + hw/openrisc/boot.c | 117 + hw/openrisc/cputimer.c | 18 + hw/openrisc/meson.build | 2 + hw/openrisc/openrisc_sim.c | 106 + hw/openrisc/virt.c | 578 +++ hw/rtc/goldfish_rtc.c| 46 +- include/hw/openrisc/boot.h | 34 ++ include/hw/rtc/goldfish_rtc.h| 2 + target/openrisc/cpu.c| 1 - target/openrisc/cpu.h| 3 + target/openrisc/interrupt.c | 4 +- target/openrisc/mmu.c| 8 +- target/openrisc/sys_helper.c | 18 +- 22 files changed, 1035 insertions(+), 114 deletions(-) create mode 100644 docs/system/openrisc/cpu-features.rst create mode 100644 docs/system/openrisc/emulation.rst create mode 100644 docs/system/openrisc/or1k-sim.rst create mode 100644 docs/system/openrisc/virt.rst create mode 100644 docs/system/target-openrisc.rst create mode 100644 hw/openrisc/boot.c create mode 100644 hw/openrisc/virt.c create mode 100644 include/hw/openrisc/boot.h -- 2.36.1
[PATCH v2 02/11] target/openrisc: Fix memory reading in debugger
In commit f0655423ca ("target/openrisc: Reorg tlb lookup") data and instruction TLB reads were combined. This, broke debugger reads where we first tried to map using the data tlb then fall back to the instruction tlb. This patch replicates this logic by first requesting a PAGE_READ protection mapping then falling back to PAGE_EXEC. Signed-off-by: Stafford Horne --- target/openrisc/mmu.c | 8 +++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/target/openrisc/mmu.c b/target/openrisc/mmu.c index d7e1320998..0b8afdbacf 100644 --- a/target/openrisc/mmu.c +++ b/target/openrisc/mmu.c @@ -148,7 +148,13 @@ hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) case SR_DME | SR_IME: /* The mmu is definitely enabled. */ excp = get_phys_mmu(cpu, _addr, , addr, -PAGE_EXEC | PAGE_READ | PAGE_WRITE, +PAGE_READ, +(sr & SR_SM) != 0); +if (!excp) { +return phys_addr; +} +excp = get_phys_mmu(cpu, _addr, , addr, +PAGE_EXEC, (sr & SR_SM) != 0); return excp ? -1 : phys_addr; -- 2.36.1
[PATCH v2 01/11] hw/openrisc: Split re-usable boot time apis out to boot.c
These will be shared with the virt platform. Reviewed-by: Richard Henderson Signed-off-by: Stafford Horne --- hw/openrisc/boot.c | 117 + hw/openrisc/meson.build| 1 + hw/openrisc/openrisc_sim.c | 106 ++--- include/hw/openrisc/boot.h | 34 +++ 4 files changed, 158 insertions(+), 100 deletions(-) create mode 100644 hw/openrisc/boot.c create mode 100644 include/hw/openrisc/boot.h diff --git a/hw/openrisc/boot.c b/hw/openrisc/boot.c new file mode 100644 index 00..ca773b385e --- /dev/null +++ b/hw/openrisc/boot.c @@ -0,0 +1,117 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * QEMU OpenRISC boot helpers. + * + * (c) 2022 Stafford Horne + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/cpu-defs.h" +#include "elf.h" +#include "hw/loader.h" +#include "hw/openrisc/boot.h" +#include "sysemu/device_tree.h" +#include "sysemu/qtest.h" + +#include + +#define KERNEL_LOAD_ADDR 0x100 + +hwaddr openrisc_load_kernel(ram_addr_t ram_size, +const char *kernel_filename, +uint32_t *bootstrap_pc) +{ +long kernel_size; +uint64_t elf_entry; +uint64_t high_addr; +hwaddr entry; + +if (kernel_filename && !qtest_enabled()) { +kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, + _entry, NULL, _addr, NULL, 1, + EM_OPENRISC, 1, 0); +entry = elf_entry; +if (kernel_size < 0) { +kernel_size = load_uimage(kernel_filename, + , NULL, NULL, NULL, NULL); +high_addr = entry + kernel_size; +} +if (kernel_size < 0) { +kernel_size = load_image_targphys(kernel_filename, + KERNEL_LOAD_ADDR, + ram_size - KERNEL_LOAD_ADDR); +high_addr = KERNEL_LOAD_ADDR + kernel_size; +} + +if (entry <= 0) { +entry = KERNEL_LOAD_ADDR; +} + +if (kernel_size < 0) { +error_report("couldn't load the kernel '%s'", kernel_filename); +exit(1); +} +*bootstrap_pc = entry; + +return high_addr; +} +return 0; +} + +hwaddr openrisc_load_initrd(void *fdt, const char *filename, +hwaddr load_start, uint64_t mem_size) +{ +int size; +hwaddr start; + +/* We put the initrd right after the kernel; page aligned. */ +start = TARGET_PAGE_ALIGN(load_start); + +size = load_ramdisk(filename, start, mem_size - start); +if (size < 0) { +size = load_image_targphys(filename, start, mem_size - start); +if (size < 0) { +error_report("could not load ramdisk '%s'", filename); +exit(1); +} +} + +if (fdt) { +qemu_fdt_setprop_cell(fdt, "/chosen", + "linux,initrd-start", start); +qemu_fdt_setprop_cell(fdt, "/chosen", + "linux,initrd-end", start + size); +} + +return start + size; +} + +uint32_t openrisc_load_fdt(void *fdt, hwaddr load_start, + uint64_t mem_size) +{ +uint32_t fdt_addr; +int ret; +int fdtsize = fdt_totalsize(fdt); + +if (fdtsize <= 0) { +error_report("invalid device-tree"); +exit(1); +} + +/* We put fdt right after the kernel and/or initrd. */ +fdt_addr = TARGET_PAGE_ALIGN(load_start); + +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); + +rom_add_blob_fixed_as("fdt", fdt, fdtsize, fdt_addr, + _space_memory); + +return fdt_addr; +} + diff --git a/hw/openrisc/meson.build b/hw/openrisc/meson.build index ec48172c9d..ab563820c5 100644 --- a/hw/openrisc/meson.build +++ b/hw/openrisc/meson.build @@ -1,5 +1,6 @@ openrisc_ss = ss.source_set() openrisc_ss.add(files('cputimer.c')) +openrisc_ss.add(files('boot.c')) openrisc_ss.add(when: 'CONFIG_OR1K_SIM', if_true: [files('openrisc_sim.c'), fdt]) hw_arch += {'openrisc': openrisc_ss} diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 35adce17ac..35da123aef 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -24,10 +24,9 @@ #include "cpu.h" #include "hw/irq.h" #include "hw/boards.h" -#include "elf.h" #include "hw/char/serial.h" #include "net/net.h" -#include "hw/loader.h" +#include "hw/openrisc/boot.h" #includ
Re: [PATCH v2] hw/openrisc: virt: pass random seed to fdt
On Wed, Jun 22, 2022 at 01:45:13PM +0200, Jason A. Donenfeld wrote: > If the FDT contains /chosen/rng-seed, then the Linux RNG will use it to > initialize early. Set this using the usual guest random number > generation function. This is confirmed to successfully initialize the > RNG on Linux 5.19-rc2. > > Cc: Stafford Horne > Signed-off-by: Jason A. Donenfeld > --- > Changes v1->v2: > - This is rebased on top of your "or1k-virt-2" branch. > - It makes the change to the new "virt" platform, since that's where it > makes most sense to have. Thanks I have placed this on my or1k-virt-2 branch. -Stafford
Re: [PATCH] hw/openrisc: pass random seed to fdt
On Sun, Jun 12, 2022 at 11:59:49PM +0200, Jason A. Donenfeld wrote: > If the FDT contains /chosen/rng-seed, then the Linux RNG will use it to > initialize early. Set this using the usual guest random number > generation function. This is confirmed to successfully initialize the > RNG on Linux 5.19-rc2. > > Cc: Stafford Horne > Signed-off-by: Jason A. Donenfeld > --- > hw/openrisc/openrisc_sim.c | 6 ++ > 1 file changed, 6 insertions(+) > > diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c > index 35adce17ac..41821b5f30 100644 > --- a/hw/openrisc/openrisc_sim.c > +++ b/hw/openrisc/openrisc_sim.c > @@ -20,6 +20,7 @@ > > #include "qemu/osdep.h" > #include "qemu/error-report.h" > +#include "qemu/guest-random.h" > #include "qapi/error.h" > #include "cpu.h" > #include "hw/irq.h" > @@ -115,6 +116,7 @@ static void openrisc_create_fdt(Or1ksimState *state, > int cpu; > char *nodename; > int pic_ph; > +uint8_t rng_seed[32]; > > fdt = state->fdt = create_device_tree(>fdt_size); > if (!fdt) { > @@ -165,6 +167,10 @@ static void openrisc_create_fdt(Or1ksimState *state, > qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline); > } > > +/* Pass seed to RNG. */ > +qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); > +qemu_fdt_setprop(fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed)); > + > /* Create aliases node for use by devices. */ > qemu_fdt_add_subnode(fdt, "/aliases"); > } This all looks fine to me. I will queue it with my current changes. Since this is only applying to openrisc_sim I would like to also apply it to virt. To do that I need to have a common core openrisc system creation api. That way I don't end up copying and pasting this to every platform. -Stafford
[PATCH] goldfish_rtc: Add endianness property
Add an endianness property to allow configuring the RTC as either native, little or big endian. Cc: Laurent Vivier Cc: Arnd Bergmann Signed-off-by: Stafford Horne --- In a recent mail thread[0] it was discussed that future users of goldfish devices should use little-endian rather than native endian. This is to avoid having to define special ioread/write routines in the Linux kernel as the default of the Linux kernel is to use little-endian. I have defined a property to allow us to make this change the endianness of the device at initialization time. For OpenRISC we can now set the qemu device endianness property to little-endian and the device works. For now I kept the default as DEVICE_NATIVE_ENDIAN for illustration purposes I could also do: - Add the "endianness" property to all goldfish devices. - Switch the default to LITTLE_ENDIAN and just set BIG_ENDIAN for m68k only. - Just the bare minimum, using this patch and also set little-endian in OpenRISC. - Just drop this patch and use BIG_ENDIAN access for goldfish in the kernel for OpenRISC like m68k does. I have tested this with the OpenRISC virt platform[1] available here (now with pci support). [0] https://lore.kernel.org/all/cak8p3a13ptsmexyxzm5szm3wbk-8honfjyoi19phmkkcjqm...@mail.gmail.com/ [1] https://github.com/stffrdhrn/qemu/commits/or1k-virt-2 hw/rtc/goldfish_rtc.c | 45 --- include/hw/rtc/goldfish_rtc.h | 2 ++ 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/hw/rtc/goldfish_rtc.c b/hw/rtc/goldfish_rtc.c index 35e493be31..ab1e15a3e2 100644 --- a/hw/rtc/goldfish_rtc.c +++ b/hw/rtc/goldfish_rtc.c @@ -216,14 +216,34 @@ static int goldfish_rtc_post_load(void *opaque, int version_id) return 0; } -static const MemoryRegionOps goldfish_rtc_ops = { -.read = goldfish_rtc_read, -.write = goldfish_rtc_write, -.endianness = DEVICE_NATIVE_ENDIAN, -.valid = { -.min_access_size = 4, -.max_access_size = 4 -} +static const MemoryRegionOps goldfish_rtc_ops[3] = { +[DEVICE_NATIVE_ENDIAN] = { +.read = goldfish_rtc_read, +.write = goldfish_rtc_write, +.endianness = DEVICE_NATIVE_ENDIAN, +.valid = { +.min_access_size = 4, +.max_access_size = 4 +} +}, +[DEVICE_LITTLE_ENDIAN] = { +.read = goldfish_rtc_read, +.write = goldfish_rtc_write, +.endianness = DEVICE_LITTLE_ENDIAN, +.valid = { +.min_access_size = 4, +.max_access_size = 4 +} +}, +[DEVICE_BIG_ENDIAN] = { +.read = goldfish_rtc_read, +.write = goldfish_rtc_write, +.endianness = DEVICE_BIG_ENDIAN, +.valid = { +.min_access_size = 4, +.max_access_size = 4 +} +}, }; static const VMStateDescription goldfish_rtc_vmstate = { @@ -265,7 +285,8 @@ static void goldfish_rtc_realize(DeviceState *d, Error **errp) SysBusDevice *dev = SYS_BUS_DEVICE(d); GoldfishRTCState *s = GOLDFISH_RTC(d); -memory_region_init_io(>iomem, OBJECT(s), _rtc_ops, s, +memory_region_init_io(>iomem, OBJECT(s), + _rtc_ops[s->endianness], s, "goldfish_rtc", 0x24); sysbus_init_mmio(dev, >iomem); @@ -274,10 +295,16 @@ static void goldfish_rtc_realize(DeviceState *d, Error **errp) s->timer = timer_new_ns(rtc_clock, goldfish_rtc_interrupt, s); } +static Property goldfish_rtc_properties[] = { +DEFINE_PROP_UINT8("endianness", GoldfishRTCState, endianness, DEVICE_NATIVE_ENDIAN), +DEFINE_PROP_END_OF_LIST(), +}; + static void goldfish_rtc_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); +device_class_set_props(dc, goldfish_rtc_properties); dc->realize = goldfish_rtc_realize; dc->reset = goldfish_rtc_reset; dc->vmsd = _rtc_vmstate; diff --git a/include/hw/rtc/goldfish_rtc.h b/include/hw/rtc/goldfish_rtc.h index 79ca7daf5d..8e1aeb85e3 100644 --- a/include/hw/rtc/goldfish_rtc.h +++ b/include/hw/rtc/goldfish_rtc.h @@ -42,6 +42,8 @@ struct GoldfishRTCState { uint32_t irq_pending; uint32_t irq_enabled; uint32_t time_high; + +uint8_t endianness; }; #endif -- 2.36.1
Re: [RFC PATCH 3/3] hw/openrisc: Add the OpenRISC virtual machine
On Tue, Jun 07, 2022 at 11:43:08AM +0100, Peter Maydell wrote: > So I don't have a strong view on whether these devices should > be DEVICE_NATIVE_ENDIAN or DEVICE_LITTLE_ENDIAN (except that > my impression is that a DEVICE_LITTLE_ENDIAN device on a > big-endian system is a bit weird, because it means the guest > has to byteswap everything. You see that with PCI devices because > the PCI spec mandates LE, but not often elsewhere). > > If there's an official-ish spec for how goldfish devices are > supposed to behave (does anybody have a pointer to one?) and it says > "always little-endian" then that would probably suggest that fixing > m68k would be nice if we can. I think there are some conflicting thoughts on this. In Geert's he mentioned: Using Goldfish devices as little-endian devices should be fine. In Arnd's mail he mentions: https://lore.kernel.org/lkml/CAK8P3a1oN8NrUjkh2X8jHQbyz42Xo6GSa=5n0gd6vqcxrjm...@mail.gmail.com/#t ... the device was clearly defined as having little-endian registers, Based on that I was thinking that switching to DEVICE_LITTLE_ENDIAN would make sense. However, in a followup mail from Laurent we see: https://lore.kernel.org/lkml/cb884368-0226-e913-80d2-62d2b7b2e...@vivier.eu/ The reference document[1] doesn't define the endianness of goldfish. [1] https://android.googlesource.com/platform/external/qemu/+/master/docs/GOLDFISH-VIRTUAL-HARDWARE.TXT The documentation does not clearly specify it. So maybe maybe or1k should just be updated on the linux side and add gf_ioread32/gf_iowrite32 big-endian accessors. -Stafford
Re: [RFC PATCH 3/3] hw/openrisc: Add the OpenRISC virtual machine
On Tue, Jun 07, 2022 at 10:42:08AM +0200, Arnd Bergmann wrote: > On Tue, Jun 7, 2022 at 10:11 AM Geert Uytterhoeven > wrote: > > On Sun, Jun 5, 2022 at 9:32 AM Stafford Horne wrote: > > > On Sun, Jun 05, 2022 at 10:58:14AM +0900, Stafford Horne wrote: > > > It might be a good idea to revisit the qemu implementation and make > > > sure that the extra byteswap is only inserted on m68k and not on > > > other targets, but hopefully there are no new targets based on > > > goldfish > > > anymore and we don't need to care. > > > > > > So, it seems that in addition to my patch we would need something in m68k > > > to > > > switch it back to 'native' (big) endian? > > > > > > Looking at the m68k kernel/qemu interface I see: > > > > > > Pre 5.19: > > >(data) <-- kernel(readl / little) <-- m68k qemu (native / big) - > > > RTC/PIC > > >(data) <-- kernel(__raw_readl / big) <-- m68k qemu (native / big) - TTY > > > > > > 5.19: > > >(data) <-- kernel(gf_ioread32 / big) <-- m68k qemu (native / big) - all > > > > > > The new fixes to add gf_ioread32/gf_iowrite32 fix this for goldfish and > > > m68k. > > > This wouldn't have been an issue for little-endian platforms where > > > readl/writel > > > were originally used. > > > > > > Why can't m68k switch to little-endian in qemu and the kernel? The m68k > > > virt > > > platform is not that old, 1 year? Are there a lot of users that this > > > would be a big > > > problem? > > > > > > [1] > > > https://lore.kernel.org/lkml/CAK8P3a1oN8NrUjkh2X8jHQbyz42Xo6GSa=5n0gd6vqcxrjm...@mail.gmail.com/ > > Goldfish is a very old platform, as far as I know only the kernel port is new. > I don't know when qemu started shipping goldfish, but changing it now would > surely break compatibility with whatever OS the port was originally made for. Hi Arnd, As far as I can tell goldfish in qemu is not very old. There are 3 devices, 2 were added for the m68k virt machine, and 1 for riscv virt. $ git lo -- hw/rtc/goldfish_rtc.c 2022-01-28 2f93d8b04a Peter Maydellrtc: Move RTC function prototypes to their own header 2021-03-04 6b9409ba5f Laurent Vivier goldfish_rtc: re-arm the alarm after migration 2020-10-13 16b66c5626 Laurent Vivier goldfish_rtc: change MemoryRegionOps endianness to DEVICE_NATIVE_ENDIAN 2020-07-22 8380b3a453 Jessica Clarke goldfish_rtc: Fix non-atomic read behaviour of TIME_LOW/TIME_HIGH 2020-02-10 9a5b40b842 Anup Patel hw: rtc: Add Goldfish RTC device $ git lo -- hw/char/goldfish_tty.c 2021-11-09 65b4c8c759 Philippe Mathieu-Daudé hw/m68k: Fix typo in SPDX tag 2021-03-15 8c6df16ff6 Laurent Vivier hw/char: add goldfish-tty $ git lo -- hw/intc/goldfish_pic.c 2021-11-09 65b4c8c759 Philippe Mathieu-Daudé hw/m68k: Fix typo in SPDX tag 2021-03-15 8785559390 Laurent Vivier hw/intc: add goldfish-pic The mips/loongson3_virt machine now also uses the goldfish_rtc. The problem with the goldfish device models is that they were defined as DEVICE_NATIVE_ENDIAN. $ grep endianness hw/*/goldfish* hw/char/goldfish_tty.c:.endianness = DEVICE_NATIVE_ENDIAN, hw/intc/goldfish_pic.c:.endianness = DEVICE_NATIVE_ENDIAN, hw/rtc/goldfish_rtc.c:.endianness = DEVICE_NATIVE_ENDIAN, RISC-V is little-endian so when it was added there was no problem with running linux goldfish drivers. MIPS Longson3, added last year, seems to be running as little-endian well, I understand MIPS can support both big and little endian. However according to this all Loongson cores are little-endian. https://en.wikipedia.org/wiki/Loongson As I understand when endianness of the devices in qemu are defined as DEVICE_NATIVE_ENDIAN the device endian takes the endian of the target CPU. This means that MIPS Loongson3 and RISC-V are affectively running as little-endian which is what would be expected. So it appears to me that in qemu that m68k is the only architecture that is providing goldfish devices on a big-endian architecture. Also, as far as I know Linux is the only OS that was updated to cater for that. If there are other firmware/bootloaders that expect that maybe they could be updated too? -Stafford
Re: [RFC PATCH 3/3] hw/openrisc: Add the OpenRISC virtual machine
On Sun, Jun 05, 2022 at 10:58:14AM +0900, Stafford Horne wrote: > On Fri, Jun 03, 2022 at 09:05:09AM +0200, Geert Uytterhoeven wrote: > > Hi Stafford, > > > > On Thu, Jun 2, 2022 at 9:59 PM Stafford Horne wrote: > > > On Thu, Jun 02, 2022 at 09:08:52PM +0200, Geert Uytterhoeven wrote: > > > > On Thu, Jun 2, 2022 at 1:42 PM Joel Stanley wrote: > > > > > On Fri, 27 May 2022 at 17:27, Stafford Horne wrote: > > > > > > This patch add the OpenRISC virtual machine 'virt' for OpenRISC. > > > > > > This > > > > > > platform allows for a convenient CI platform for toolchain, software > > > > > > ports and the OpenRISC linux kernel port. > > > > > > > > > > > > Much of this has been sourced from the m68k and riscv virt > > > > > > platforms. > > > > > > > > > I enabled the options: > > > > > > > > > > CONFIG_RTC_CLASS=y > > > > > # CONFIG_RTC_SYSTOHC is not set > > > > > # CONFIG_RTC_NVMEM is not set > > > > > CONFIG_RTC_DRV_GOLDFISH=y > > > > > > > > > > But it didn't work. It seems the goldfish rtc model doesn't handle a > > > > > big endian guest running on my little endian host. > > > > > > > > > > Doing this fixes it: > > > > > > > > > > -.endianness = DEVICE_NATIVE_ENDIAN, > > > > > +.endianness = DEVICE_HOST_ENDIAN, > > > > > > > > > > [0.19] goldfish_rtc 96005000.rtc: registered as rtc0 > > > > > [0.19] goldfish_rtc 96005000.rtc: setting system clock to > > > > > 2022-06-02T11:16:04 UTC (1654168564) > > > > > > > > > > But literally no other model in the tree does this, so I suspect it's > > > > > not the right fix. > > > > > > > > Goldfish devices are supposed to be little endian. > > > > Unfortunately m68k got this wrong, cfr. > > > > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=2e2ac4a3327479f7e2744cdd88a5c823f2057bad > > > > Please don't duplicate this bad behavior for new architectures > > > > > > Thanks for the pointer, I just wired in the goldfish RTC because I wanted > > > to > > > play with it. I was not attached to it. I can either remove it our find > > > another > > > RTC. > > > > Sorry for being too unclear: the mistake was not to use the Goldfish > > RTC, but to make its register accesses big-endian. > > Using Goldfish devices as little-endian devices should be fine. > > OK, then I would think this patch would be needed on Goldfish. I tested this > out and it seems to work: Sorry, it seems maybe I mis-understood this again. In Arnd's mail [1] he, at the end, mentions. It might be a good idea to revisit the qemu implementation and make sure that the extra byteswap is only inserted on m68k and not on other targets, but hopefully there are no new targets based on goldfish anymore and we don't need to care. So, it seems that in addition to my patch we would need something in m68k to switch it back to 'native' (big) endian? Looking at the m68k kernel/qemu interface I see: Pre 5.19: (data) <-- kernel(readl / little) <-- m68k qemu (native / big) - RTC/PIC (data) <-- kernel(__raw_readl / big) <-- m68k qemu (native / big) - TTY 5.19: (data) <-- kernel(gf_ioread32 / big) <-- m68k qemu (native / big) - all The new fixes to add gf_ioread32/gf_iowrite32 fix this for goldfish and m68k. This wouldn't have been an issue for little-endian platforms where readl/writel were originally used. Why can't m68k switch to little-endian in qemu and the kernel? The m68k virt platform is not that old, 1 year? Are there a lot of users that this would be a big problem? [1] https://lore.kernel.org/lkml/CAK8P3a1oN8NrUjkh2X8jHQbyz42Xo6GSa=5n0gd6vqcxrjm...@mail.gmail.com/ -Stafford > Patch: > > diff --git a/hw/rtc/goldfish_rtc.c b/hw/rtc/goldfish_rtc.c > index 35e493be31..f1dc5af297 100644 > --- a/hw/rtc/goldfish_rtc.c > +++ b/hw/rtc/goldfish_rtc.c > @@ -219,7 +219,7 @@ static int goldfish_rtc_post_load(void *opaque, int > version_id) > static const MemoryRegionOps goldfish_rtc_ops = { > .read = goldfish_rtc_read, > .write = goldfish_rtc_write, > -.endianness = DEVICE_NATIVE_ENDIAN, > +.endianness = DEVICE_LITTLE_ENDIAN, > .valid = { > .min_access_size = 4, > .max_access_size = 4 > > Boot Log: > > io scheduler mq-deadline registered > io scheduler kyber registered > Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled > 9000.serial: ttyS0 at MMIO 0x9000 (irq = 2, base_baud = 125) > is a 16550A > printk: console [ttyS0] enabled > loop: module loaded > virtio_blk virtio1: [vda] 32768 512-byte logical blocks (16.8 MB/16.0 MiB) > Freeing initrd memory: 1696K >*goldfish_rtc 96005000.rtc: registered as rtc0 >*goldfish_rtc 96005000.rtc: setting system clock to 2022-06-05T01:49:57 > UTC (1654393797) > NET: Registered PF_PACKET protocol family > random: fast init done > > -Stafford
Re: [RFC PATCH 3/3] hw/openrisc: Add the OpenRISC virtual machine
On Thu, Jun 02, 2022 at 11:42:30AM +, Joel Stanley wrote: > Hi Stafford, > > On Fri, 27 May 2022 at 17:27, Stafford Horne wrote: > > > > This patch add the OpenRISC virtual machine 'virt' for OpenRISC. This > > platform allows for a convenient CI platform for toolchain, software > > ports and the OpenRISC linux kernel port. > > > > Much of this has been sourced from the m68k and riscv virt platforms. > > It's a good idea! I did some playing around with your patch today. > > I'd suggest adding something to docs/system/target-openrsic.rst, > including an example command lines. Yeah, good idea, this is the command I am using: qemu-system-or1k -cpu or1200 -M virt \ -kernel /home/shorne/work/linux/vmlinux \ -initrd /home/shorne/work/linux/initramfs.cpio.gz \ -device virtio-net-device,netdev=user -netdev user,id=user,net=10.9.0.1/24,host=10.9.0.100 \ -serial mon:stdio -nographic \ -device virtio-blk-device,drive=d0 -drive file=/home/shorne/work/linux/virt.qcow2,id=d0,if=none,format=qcow2 \ -gdb tcp::10001 -smp cpus=2 -m 64 I should have mentioned it but the config I am using is here: https://github.com/stffrdhrn/linux/commits/or1k-virt > > > > The platform provides: > > - OpenRISC SMP with up to 8 cpus > > You have this: > > #define VIRT_CPUS_MAX 4 > i > I tried booting with -smp 4 and it locked up when starting userspace > (or I stopped getting serial output?): > > [0.06] smp: Brought up 1 node, 4 CPUs > ... > [0.96] Run /init as init process > > Running with -smp 2 and 3 worked. It does make booting much much slower. Right, it should be 4, I just write 8 from memory. You are also, right I have issues with running 4 CPU's. I will try richard's suggestion. I have some old patches to configure MTTCG also, but it had some limitations. I will dig those up and get this fixed for this series. > > - Generated RTC to automatically configure the guest kernel > > Did you mean device tree? Yeah, thats what I meant. > > > > Signed-off-by: Stafford Horne > > --- > > configs/devices/or1k-softmmu/default.mak | 1 + > > hw/openrisc/Kconfig | 9 + > > hw/openrisc/meson.build | 1 + > > hw/openrisc/virt.c | 429 +++ > > 4 files changed, 440 insertions(+) > > create mode 100644 hw/openrisc/virt.c > > > > diff --git a/configs/devices/or1k-softmmu/default.mak > > b/configs/devices/or1k-softmmu/default.mak > > index 5b3ac89491..f3bf816067 100644 > > --- a/configs/devices/or1k-softmmu/default.mak > > +++ b/configs/devices/or1k-softmmu/default.mak > > @@ -5,3 +5,4 @@ CONFIG_SEMIHOSTING=y > > # Boards: > > # > > CONFIG_OR1K_SIM=y > > +CONFIG_OR1K_VIRT=y > > diff --git a/hw/openrisc/Kconfig b/hw/openrisc/Kconfig > > index 8f284f3ba0..202134668e 100644 > > --- a/hw/openrisc/Kconfig > > +++ b/hw/openrisc/Kconfig > > @@ -4,3 +4,12 @@ config OR1K_SIM > > select OPENCORES_ETH > > select OMPIC > > select SPLIT_IRQ > > + > > +config OR1K_VIRT > > +bool > > +imply VIRTIO_VGA > > +imply TEST_DEVICES > > +select GOLDFISH_RTC > > +select SERIAL > > +select SIFIVE_TEST > > +select VIRTIO_MMIO > > You could include the liteeth device too if we merged that. I think we could add that with a litex machine. For that we would need at least the litex UART and SoC for reset. > > diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c > > new file mode 100644 > > index 00..147196fda3 > > --- /dev/null > > +++ b/hw/openrisc/virt.c > > @@ -0,0 +1,429 @@ > > +/* > > + * OpenRISC QEMU virtual machine. > > + * > > + * Copyright (c) 2022 Stafford Horne > > + * > > + * This library is free software; you can redistribute it and/or > > + * modify it under the terms of the GNU Lesser General Public > > + * License as published by the Free Software Foundation; either > > + * version 2.1 of the License, or (at your option) any later version. > > + * > > + * This library is distributed in the hope that it will be useful, > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > > + * Lesser General Public License for more details. > > + * > > + * You should have received a copy of the GNU Lesser General Public > > + * License along with this library; if not, see > > <http://www.gnu.org/licenses/>. > > I think you can use the SPDX tag here instead of
Re: [RFC PATCH 3/3] hw/openrisc: Add the OpenRISC virtual machine
On Fri, Jun 03, 2022 at 09:05:09AM +0200, Geert Uytterhoeven wrote: > Hi Stafford, > > On Thu, Jun 2, 2022 at 9:59 PM Stafford Horne wrote: > > On Thu, Jun 02, 2022 at 09:08:52PM +0200, Geert Uytterhoeven wrote: > > > On Thu, Jun 2, 2022 at 1:42 PM Joel Stanley wrote: > > > > On Fri, 27 May 2022 at 17:27, Stafford Horne wrote: > > > > > This patch add the OpenRISC virtual machine 'virt' for OpenRISC. This > > > > > platform allows for a convenient CI platform for toolchain, software > > > > > ports and the OpenRISC linux kernel port. > > > > > > > > > > Much of this has been sourced from the m68k and riscv virt platforms. > > > > > > > I enabled the options: > > > > > > > > CONFIG_RTC_CLASS=y > > > > # CONFIG_RTC_SYSTOHC is not set > > > > # CONFIG_RTC_NVMEM is not set > > > > CONFIG_RTC_DRV_GOLDFISH=y > > > > > > > > But it didn't work. It seems the goldfish rtc model doesn't handle a > > > > big endian guest running on my little endian host. > > > > > > > > Doing this fixes it: > > > > > > > > -.endianness = DEVICE_NATIVE_ENDIAN, > > > > +.endianness = DEVICE_HOST_ENDIAN, > > > > > > > > [0.19] goldfish_rtc 96005000.rtc: registered as rtc0 > > > > [0.19] goldfish_rtc 96005000.rtc: setting system clock to > > > > 2022-06-02T11:16:04 UTC (1654168564) > > > > > > > > But literally no other model in the tree does this, so I suspect it's > > > > not the right fix. > > > > > > Goldfish devices are supposed to be little endian. > > > Unfortunately m68k got this wrong, cfr. > > > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=2e2ac4a3327479f7e2744cdd88a5c823f2057bad > > > Please don't duplicate this bad behavior for new architectures > > > > Thanks for the pointer, I just wired in the goldfish RTC because I wanted to > > play with it. I was not attached to it. I can either remove it our find > > another > > RTC. > > Sorry for being too unclear: the mistake was not to use the Goldfish > RTC, but to make its register accesses big-endian. > Using Goldfish devices as little-endian devices should be fine. OK, then I would think this patch would be needed on Goldfish. I tested this out and it seems to work: Patch: diff --git a/hw/rtc/goldfish_rtc.c b/hw/rtc/goldfish_rtc.c index 35e493be31..f1dc5af297 100644 --- a/hw/rtc/goldfish_rtc.c +++ b/hw/rtc/goldfish_rtc.c @@ -219,7 +219,7 @@ static int goldfish_rtc_post_load(void *opaque, int version_id) static const MemoryRegionOps goldfish_rtc_ops = { .read = goldfish_rtc_read, .write = goldfish_rtc_write, -.endianness = DEVICE_NATIVE_ENDIAN, +.endianness = DEVICE_LITTLE_ENDIAN, .valid = { .min_access_size = 4, .max_access_size = 4 Boot Log: io scheduler mq-deadline registered io scheduler kyber registered Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled 9000.serial: ttyS0 at MMIO 0x9000 (irq = 2, base_baud = 125) is a 16550A printk: console [ttyS0] enabled loop: module loaded virtio_blk virtio1: [vda] 32768 512-byte logical blocks (16.8 MB/16.0 MiB) Freeing initrd memory: 1696K *goldfish_rtc 96005000.rtc: registered as rtc0 *goldfish_rtc 96005000.rtc: setting system clock to 2022-06-05T01:49:57 UTC (1654393797) NET: Registered PF_PACKET protocol family random: fast init done -Stafford
Re: [RFC PATCH 1/3] target/openrisc: Add basic support for semihosting
On Thu, Jun 02, 2022 at 08:39:21AM -0700, Richard Henderson wrote: > On 5/27/22 10:27, Stafford Horne wrote: > > +void do_or1k_semihosting(CPUOpenRISCState *env, uint32_t k); > ... > > +DEF_HELPER_FLAGS_2(nop, 0, void, env, i32) > > Just call the helper "semihosting" and be done with it. > And the helper wants an ifdef for system mode. > > > @@ -10,6 +10,7 @@ openrisc_ss.add(files( > > 'fpu_helper.c', > > 'gdbstub.c', > > 'interrupt_helper.c', > > + 'openrisc-semi.c', > > 'sys_helper.c', > > 'translate.c', > > )) > > You want to add the new file for system mode only. > Or, now that I think of it, conditional on CONFIG_SEMIHOSTING itself. That's right, I'll update it. > > +static void or1k_semi_return_u32(CPUOpenRISCState *env, uint32_t ret) > > +{ > > +cpu_set_gpr(env, 11, ret); > > +} > > Let's drop this until you actually use it. This appears to be attempting to > mirror other, more complete semihosting, but missing the third "error" > argument Sure, I did mention I kept these here for future (real) semihosting support. But I don't think that will happen. So I can remove. > > +void do_or1k_semihosting(CPUOpenRISCState *env, uint32_t k) > > +{ > > +uint32_t result; > > + > > +switch (k) { > > +case HOSTED_EXIT: > > +gdb_exit(cpu_get_gpr(env, 3)); > > +exit(cpu_get_gpr(env, 3)); > > +case HOSTED_RESET: > > +#ifndef CONFIG_USER_ONLY > > +qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); > > +return; > > +#endif > > Do you in fact want to exit to the main loop after asking for reset? > That's the only way that "no return value" makes sense to me... OK. I'll look at this more. > > +default: > > +qemu_log_mask(LOG_GUEST_ERROR, "or1k-semihosting: unsupported " > > + "semihosting syscall %d\n", k); > > %u. OK. > > static bool trans_l_nop(DisasContext *dc, arg_l_nop *a) > > { > > +if (semihosting_enabled() && > > +a->k != 0) { > > +gen_helper_nop(cpu_env, tcg_constant_i32(a->k)); > > +} > > Perhaps cleaner to move the semihosting dispatch switch here, instead of > leaving it to the runtime? The reason we have a runtime switch for other > guests is that the semihosting syscall number is in a register. This would > then be > > if (semihosting_enabled()) { > switch (a->k) { > case 0: > break; /* normal nop */ > case HOSTED_EXIT: > gen_helper_semihost_exit(cpu_R(dc, 3)); > break; > case HOSTED_RESET: > gen_helper_semihost_reset(); > tcg_gen_movi_tl(cpu_pc, dc->base.pc_next + 4); > > dc->base.is_jmp = DISAS_EXIT; > break; > ... > } > } Yeah, that makes sense. I had written it in a way that would allow expanding for real semi-hosting. But I don't think we will do that with OpenRISC, so this is good enough. I am not sure if you saw the cover letter. I sent this RFC series to help illustrate two options for providing OpenRISC targets that support poweroff and reset. One option being using these NOP's, the second is to create a virt target with reset/poweroff hardware. I am kind of leaning towards dropping the semi-hosting patches and only moving forward with the virt patches. The reason being that 1. we would not need to expand the architecture spec to support the qemu virt platform, and we would need to document the NOP's formally, and 2. OpenRISC doesn't really support the full "semihosting" facilities for file open/close/write etc. Any thoughts? I guess this "semihosting" patch is pretty trivial. But, maybe it causes more confusion compared to just going with the virt route. Also, if we have virt I can't imagine anyone using the semihosting much. -Stafford
Re: [RFC PATCH 3/3] hw/openrisc: Add the OpenRISC virtual machine
On Thu, Jun 02, 2022 at 09:08:52PM +0200, Geert Uytterhoeven wrote: > Hi Joel, > > On Thu, Jun 2, 2022 at 1:42 PM Joel Stanley wrote: > > On Fri, 27 May 2022 at 17:27, Stafford Horne wrote: > > > This patch add the OpenRISC virtual machine 'virt' for OpenRISC. This > > > platform allows for a convenient CI platform for toolchain, software > > > ports and the OpenRISC linux kernel port. > > > > > > Much of this has been sourced from the m68k and riscv virt platforms. > > > I enabled the options: > > > > CONFIG_RTC_CLASS=y > > # CONFIG_RTC_SYSTOHC is not set > > # CONFIG_RTC_NVMEM is not set > > CONFIG_RTC_DRV_GOLDFISH=y > > > > But it didn't work. It seems the goldfish rtc model doesn't handle a > > big endian guest running on my little endian host. > > > > Doing this fixes it: > > > > -.endianness = DEVICE_NATIVE_ENDIAN, > > +.endianness = DEVICE_HOST_ENDIAN, > > > > [0.19] goldfish_rtc 96005000.rtc: registered as rtc0 > > [0.19] goldfish_rtc 96005000.rtc: setting system clock to > > 2022-06-02T11:16:04 UTC (1654168564) > > > > But literally no other model in the tree does this, so I suspect it's > > not the right fix. > > Goldfish devices are supposed to be little endian. > Unfortunately m68k got this wrong, cfr. > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=2e2ac4a3327479f7e2744cdd88a5c823f2057bad > Please don't duplicate this bad behavior for new architectures Thanks for the pointer, I just wired in the goldfish RTC because I wanted to play with it. I was not attached to it. I can either remove it our find another RTC. -Stafford
[RFC PATCH 3/3] hw/openrisc: Add the OpenRISC virtual machine
This patch add the OpenRISC virtual machine 'virt' for OpenRISC. This platform allows for a convenient CI platform for toolchain, software ports and the OpenRISC linux kernel port. Much of this has been sourced from the m68k and riscv virt platforms. The platform provides: - OpenRISC SMP with up to 8 cpus - A virtio bus with up to 8 devices - Standard ns16550a serial - Goldfish RTC - SiFive TEST device for poweroff and reboot - Generated RTC to automatically configure the guest kernel Signed-off-by: Stafford Horne --- configs/devices/or1k-softmmu/default.mak | 1 + hw/openrisc/Kconfig | 9 + hw/openrisc/meson.build | 1 + hw/openrisc/virt.c | 429 +++ 4 files changed, 440 insertions(+) create mode 100644 hw/openrisc/virt.c diff --git a/configs/devices/or1k-softmmu/default.mak b/configs/devices/or1k-softmmu/default.mak index 5b3ac89491..f3bf816067 100644 --- a/configs/devices/or1k-softmmu/default.mak +++ b/configs/devices/or1k-softmmu/default.mak @@ -5,3 +5,4 @@ CONFIG_SEMIHOSTING=y # Boards: # CONFIG_OR1K_SIM=y +CONFIG_OR1K_VIRT=y diff --git a/hw/openrisc/Kconfig b/hw/openrisc/Kconfig index 8f284f3ba0..202134668e 100644 --- a/hw/openrisc/Kconfig +++ b/hw/openrisc/Kconfig @@ -4,3 +4,12 @@ config OR1K_SIM select OPENCORES_ETH select OMPIC select SPLIT_IRQ + +config OR1K_VIRT +bool +imply VIRTIO_VGA +imply TEST_DEVICES +select GOLDFISH_RTC +select SERIAL +select SIFIVE_TEST +select VIRTIO_MMIO diff --git a/hw/openrisc/meson.build b/hw/openrisc/meson.build index ab563820c5..2dbc6365bb 100644 --- a/hw/openrisc/meson.build +++ b/hw/openrisc/meson.build @@ -2,5 +2,6 @@ openrisc_ss = ss.source_set() openrisc_ss.add(files('cputimer.c')) openrisc_ss.add(files('boot.c')) openrisc_ss.add(when: 'CONFIG_OR1K_SIM', if_true: [files('openrisc_sim.c'), fdt]) +openrisc_ss.add(when: 'CONFIG_OR1K_VIRT', if_true: [files('virt.c'), fdt]) hw_arch += {'openrisc': openrisc_ss} diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c new file mode 100644 index 00..147196fda3 --- /dev/null +++ b/hw/openrisc/virt.c @@ -0,0 +1,429 @@ +/* + * OpenRISC QEMU virtual machine. + * + * Copyright (c) 2022 Stafford Horne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "qapi/error.h" +#include "cpu.h" +#include "hw/irq.h" +#include "hw/boards.h" +#include "hw/char/serial.h" +#include "hw/openrisc/boot.h" +#include "hw/misc/sifive_test.h" +#include "hw/qdev-properties.h" +#include "exec/address-spaces.h" +#include "sysemu/device_tree.h" +#include "sysemu/sysemu.h" +#include "hw/sysbus.h" +#include "sysemu/qtest.h" +#include "sysemu/reset.h" +#include "hw/core/split-irq.h" + +#include + +#define VIRT_CPUS_MAX 4 +#define VIRT_CLK_MHZ 2000 + +#define TYPE_VIRT_MACHINE MACHINE_TYPE_NAME("virt") +#define VIRT_MACHINE(obj) \ +OBJECT_CHECK(OR1KVirtState, (obj), TYPE_VIRT_MACHINE) + +typedef struct OR1KVirtState { +/*< private >*/ +MachineState parent_obj; + +/*< public >*/ +void *fdt; +int fdt_size; + +} OR1KVirtState; + +enum { +VIRT_DRAM, +VIRT_TEST, +VIRT_RTC, +VIRT_VIRTIO, +VIRT_UART, +VIRT_OMPIC, +}; + +enum { +VIRT_OMPIC_IRQ = 1, +VIRT_UART_IRQ = 2, +VIRT_RTC_IRQ = 3, +VIRT_VIRTIO_IRQ = 4, /* to 12 */ +VIRTIO_COUNT = 8, +}; + +static const struct MemmapEntry { +hwaddr base; +hwaddr size; +} virt_memmap[] = { +[VIRT_DRAM] = { 0x, 0 }, +[VIRT_UART] = { 0x9000, 0x100 }, +[VIRT_TEST] = { 0x9600,0x8 }, +[VIRT_RTC] = { 0x96005000, 0x1000 }, +[VIRT_VIRTIO] ={ 0x9700, 0x1000 }, +[VIRT_OMPIC] = { 0x9800, VIRT_CPUS_MAX * 8 }, +}; + +static struct openrisc_boot_info { +uint32_t bootstrap_pc; +uint32_t fdt_addr; +} boot_info; + +static void main_cpu_reset(void *opaque) +{ +OpenRISCCPU *cpu = opaque; +CPUState *cs = CPU(cpu); + +cpu_reset(CPU(cpu)); + +cpu_set_pc(cs, boot_info.bootstrap_pc); +
[RFC PATCH 1/3] target/openrisc: Add basic support for semihosting
For OpenRISC we currently only use semihosting for system exit and reset. This patch implements that. The implementation uses a helper to delegate to the semihosting facility. The helper is marked as having side effects but currently does not have any. I have defined it like this as our other unimplemented semihosting calls will have side effects and return results in register r11. Signed-off-by: Stafford Horne --- configs/devices/or1k-softmmu/default.mak | 2 + qemu-options.hx | 16 --- target/openrisc/cpu.h| 2 + target/openrisc/helper.h | 1 + target/openrisc/meson.build | 1 + target/openrisc/openrisc-semi.c | 54 target/openrisc/sys_helper.c | 5 +++ target/openrisc/translate.c | 6 +++ 8 files changed, 82 insertions(+), 5 deletions(-) create mode 100644 target/openrisc/openrisc-semi.c diff --git a/configs/devices/or1k-softmmu/default.mak b/configs/devices/or1k-softmmu/default.mak index 168101c39a..5b3ac89491 100644 --- a/configs/devices/or1k-softmmu/default.mak +++ b/configs/devices/or1k-softmmu/default.mak @@ -1,5 +1,7 @@ # Default configuration for or1k-softmmu +CONFIG_SEMIHOSTING=y + # Boards: # CONFIG_OR1K_SIM=y diff --git a/qemu-options.hx b/qemu-options.hx index b484640067..312c68b065 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4566,10 +4566,12 @@ ERST DEF("semihosting", 0, QEMU_OPTION_semihosting, "-semihostingsemihosting mode\n", QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | -QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV) +QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV | +QEMU_ARCH_OPENRISC) SRST ``-semihosting`` -Enable semihosting mode (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V only). +Enable semihosting mode (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V, +OpenRISC only). Note that this allows guest direct access to the host filesystem, so should only be used with a trusted guest OS. @@ -4581,11 +4583,12 @@ DEF("semihosting-config", HAS_ARG, QEMU_OPTION_semihosting_config, "-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]\n" \ "semihosting configuration\n", QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | -QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV) +QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV | +QEMU_ARCH_OPENRISC) SRST ``-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]`` -Enable and configure semihosting (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V -only). +Enable and configure semihosting (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V, +OpenRISC only). Note that this allows guest direct access to the host filesystem, so should only be used with a trusted guest OS. @@ -4601,6 +4604,9 @@ SRST On RISC-V this implements the standard semihosting API, version 0.2. +On OpenRISC this only supports providing simulation exit and reset +facilities. + ``target=native|gdb|auto`` Defines where the semihosting calls will be addressed, to QEMU (``native``) or to GDB (``gdb``). The default is ``auto``, which diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index b9584f10d4..4617f1272b 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -407,4 +407,6 @@ void cpu_set_fpcsr(CPUOpenRISCState *env, uint32_t val); #define CPU_INTERRUPT_TIMER CPU_INTERRUPT_TGT_INT_0 +void do_or1k_semihosting(CPUOpenRISCState *env, uint32_t k); + #endif /* OPENRISC_CPU_H */ diff --git a/target/openrisc/helper.h b/target/openrisc/helper.h index d847814a28..2fe3e4e4ca 100644 --- a/target/openrisc/helper.h +++ b/target/openrisc/helper.h @@ -64,3 +64,4 @@ DEF_HELPER_FLAGS_1(rfe, 0, void, env) /* sys */ DEF_HELPER_FLAGS_3(mtspr, 0, void, env, tl, tl) DEF_HELPER_FLAGS_3(mfspr, TCG_CALL_NO_WG, tl, env, tl, tl) +DEF_HELPER_FLAGS_2(nop, 0, void, env, i32) diff --git a/target/openrisc/meson.build b/target/openrisc/meson.build index 84322086ec..1c1758b846 100644 --- a/target/openrisc/meson.build +++ b/target/openrisc/meson.build @@ -10,6 +10,7 @@ openrisc_ss.add(files( 'fpu_helper.c', 'gdbstub.c', 'interrupt_helper.c', + 'openrisc-semi.c', 'sys_helper.c', 'translate.c', )) diff --git a/target/openrisc/openrisc-semi.c b/target/openrisc/openrisc-semi.c new file mode 100644 index 00..97d6aaacdb --- /dev/null +++ b/target/openrisc/openrisc-semi.c @@ -0,0 +1,54 @@ +/* + * OpenRISC Semihosting syscall interface. + * + * Copyright (c) 2022 Stafford Horne + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version
[RFC PATCH 2/3] hw/openrisc: Split re-usable boot time apis out to boot.c
These will be shared with the virt platform. Signed-off-by: Stafford Horne --- hw/openrisc/boot.c | 127 + hw/openrisc/meson.build| 1 + hw/openrisc/openrisc_sim.c | 106 ++- include/hw/openrisc/boot.h | 34 ++ 4 files changed, 168 insertions(+), 100 deletions(-) create mode 100644 hw/openrisc/boot.c create mode 100644 include/hw/openrisc/boot.h diff --git a/hw/openrisc/boot.c b/hw/openrisc/boot.c new file mode 100644 index 00..32f0925a8c --- /dev/null +++ b/hw/openrisc/boot.c @@ -0,0 +1,127 @@ +/* + * QEMU OpenRISC boot helpers. + * + * Copyright (c) 2022 Stafford Horne + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "exec/cpu-defs.h" +#include "elf.h" +#include "hw/loader.h" +#include "hw/openrisc/boot.h" +#include "sysemu/device_tree.h" +#include "sysemu/qtest.h" + +#include + +#define KERNEL_LOAD_ADDR 0x100 + +hwaddr openrisc_load_kernel(ram_addr_t ram_size, +const char *kernel_filename, +uint32_t *bootstrap_pc) +{ +long kernel_size; +uint64_t elf_entry; +uint64_t high_addr; +hwaddr entry; + +if (kernel_filename && !qtest_enabled()) { +kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, + _entry, NULL, _addr, NULL, 1, + EM_OPENRISC, 1, 0); +entry = elf_entry; +if (kernel_size < 0) { +kernel_size = load_uimage(kernel_filename, + , NULL, NULL, NULL, NULL); +high_addr = entry + kernel_size; +} +if (kernel_size < 0) { +kernel_size = load_image_targphys(kernel_filename, + KERNEL_LOAD_ADDR, + ram_size - KERNEL_LOAD_ADDR); +high_addr = KERNEL_LOAD_ADDR + kernel_size; +} + +if (entry <= 0) { +entry = KERNEL_LOAD_ADDR; +} + +if (kernel_size < 0) { +error_report("couldn't load the kernel '%s'", kernel_filename); +exit(1); +} +*bootstrap_pc = entry; + +return high_addr; +} +return 0; +} + +hwaddr openrisc_load_initrd(void *fdt, const char *filename, +hwaddr load_start, uint64_t mem_size) +{ +int size; +hwaddr start; + +/* We put the initrd right after the kernel; page aligned. */ +start = TARGET_PAGE_ALIGN(load_start); + +size = load_ramdisk(filename, start, mem_size - start); +if (size < 0) { +size = load_image_targphys(filename, start, mem_size - start); +if (size < 0) { +error_report("could not load ramdisk '%s'", filename); +exit(1); +} +} + +if (fdt) { +qemu_fdt_setprop_cell(fdt, "/chosen", + "linux,initrd-start", start); +qemu_fdt_setprop_cell(fdt, "/chosen", + "linux,initrd-end", start + size); +} + +return start + size; +} + +uint32_t openrisc_load_fdt(void *fdt, hwaddr load_start, + uint64_t mem_size) +{ +uint32_t fdt_addr; +int ret; +int fdtsize = fdt_totalsize(fdt); + +if (fdtsize <= 0) { +error_report("invalid device-tree"); +exit(1); +} + +/* We put fdt right after the kernel and/or initrd. */ +fdt_addr = TARGET_PAGE_ALIGN(load_start); + +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); + +rom_add_blob_fixed_as("fdt", fdt, fdtsize, fdt_addr, + _space_memory); + +return fdt_addr; +} + diff --git a/hw/openrisc/meson.build b/hw/openrisc/meson.build index ec48172c9d..ab563820c5 100644 --- a/hw/openrisc/meson.build +++ b/hw/openrisc/meson.build @@ -1,5 +1,6 @@ openrisc_ss = ss.source_set() openrisc_ss.add(files('cputimer.c')) +openrisc_ss.add(files('boot.c')) openrisc_ss.add(when: 'CONFIG_OR1K_SIM', if_true: [files('openris
[RFC PATCH 0/3] OpenRISC Semihosting and Virt
Hello, I provide 2 options here 2 help with OpenRISC CI testing sush as the wireguard testing that Jason has been working on. The two are: 1. Add semihosting to openrisc to handle l.nop based Halt and Reset 2. Define a new virt platform, this includes widing in the sifive test device that provides a syscon interface to allow for shutdown and reboot. We could upstream both of them or just one. I am leaning toward dropping the semi-hosting work and just going ahead with virt. The semi-hosting stuff was discussed here: - https://www.mail-archive.com/qemu-devel@nongnu.org/msg884560.html Also, I started to propose architecture changes here: - https://github.com/openrisc/openrisc.github.io/pull/18 However, looking at how other platforms define semihosting it seems the openrisc requirements are quite different. We do not use the open/close/write etc syscalls as riscv, arm etc do. Stafford Horne (3): target/openrisc: Add basic support for semihosting hw/openrisc: Split re-usable boot time apis out to boot.c hw/openrisc: Add the OpenRISC virtual machine configs/devices/or1k-softmmu/default.mak | 3 + hw/openrisc/Kconfig | 9 + hw/openrisc/boot.c | 127 +++ hw/openrisc/meson.build | 2 + hw/openrisc/openrisc_sim.c | 106 +- hw/openrisc/virt.c | 429 +++ include/hw/openrisc/boot.h | 34 ++ qemu-options.hx | 16 +- target/openrisc/cpu.h| 2 + target/openrisc/helper.h | 1 + target/openrisc/meson.build | 1 + target/openrisc/openrisc-semi.c | 54 +++ target/openrisc/sys_helper.c | 5 + target/openrisc/translate.c | 6 + 14 files changed, 690 insertions(+), 105 deletions(-) create mode 100644 hw/openrisc/boot.c create mode 100644 hw/openrisc/virt.c create mode 100644 include/hw/openrisc/boot.h create mode 100644 target/openrisc/openrisc-semi.c -- 2.31.1
Re: [PULL 0/4] OpenRISC fixes for QEMU 2022-05-15
On Sun, May 15, 2022 at 04:12:50PM -0700, Richard Henderson wrote: > On 5/14/22 18:39, Stafford Horne wrote: > > The following changes since commit 2e3408b3cc7de4e87a9adafc8c19bfce3abec947: > > > >Merge tag 'misc-pull-request' of gitlab.com:marcandre.lureau/qemu into > > staging (2022-05-03 09:13:17 -0700) > > > > are available in the Git repository at: > > > >https://github.com/stffrdhrn/qemu.git tags/or1k-pull-request-20220515 > > > > for you to fetch changes up to e8f0ab0cd674241cbab7231ce05ac1bfa0b4f5ed: > > > >target/openrisc: Do not reset delay slot flag on early tb exit > > (2022-05-15 10:33:01 +0900) > > > > > > OpenRISC Fixes for 7.0 > > > > - A few or1ksim fixes and enhancements > > - A fix for OpenRISC tcg backend around delay slot handling > > Applied, thanks. Please update https://wiki.qemu.org/ChangeLog/7.1 as > appropriate. > > The gpg key I have for you is expired. Have you refreshed the expiration > date and pushed the new copy somewhere? Hello Richard, I updated my PGP key (C3B31C2D5E6627E4) last year or so to extend the expiry day. It should be uploaded to pgp.mit.edu, but for some reason that server is not responding to searches for me right now. I have also just uploaded it to keyserver.ubuntu.com if that helps. - https://keyserver.ubuntu.com/pks/lookup?search=stafford+horne=on=index sec rsa4096/C3B31C2D5E6627E4 created: 2016-09-14 expires: never usage: SC If you still have any issue I can try to work it out. -Stafford
[PULL 4/4] target/openrisc: Do not reset delay slot flag on early tb exit
This was found when running linux crypto algorithm selftests used by wireguard. We found that randomly the tests would fail. We found through investigation that a combination of a tick timer interrupt, raised when executing a delay slot instruction at a page boundary caused the issue. This was caused when handling the TB_EXIT_REQUESTED case in cpu_tb_exec. On OpenRISC, which doesn't implement synchronize_from_tb, set_pc was being used as a fallback. The OpenRISC set_pc implementation clears dflag, which caused the exception handling logic to not account for the delay slot. This was the bug, because it meant when execution resumed after the interrupt was handling it resumed in the wrong place. Fix this by implementing synchronize_from_tb which simply updates pc, and not clear the delay slot flag. Reported-by: Jason A. Donenfeld Reviewed-by: Richard Henderson Signed-off-by: Stafford Horne --- target/openrisc/cpu.c | 11 +++ 1 file changed, 11 insertions(+) diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index dfbafc5236..41d1b2a24a 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -21,6 +21,7 @@ #include "qapi/error.h" #include "qemu/qemu-print.h" #include "cpu.h" +#include "exec/exec-all.h" static void openrisc_cpu_set_pc(CPUState *cs, vaddr value) { @@ -30,6 +31,15 @@ static void openrisc_cpu_set_pc(CPUState *cs, vaddr value) cpu->env.dflag = 0; } +static void openrisc_cpu_synchronize_from_tb(CPUState *cs, + const TranslationBlock *tb) +{ +OpenRISCCPU *cpu = OPENRISC_CPU(cs); + +cpu->env.pc = tb->pc; +} + + static bool openrisc_cpu_has_work(CPUState *cs) { return cs->interrupt_request & (CPU_INTERRUPT_HARD | @@ -186,6 +196,7 @@ static const struct SysemuCPUOps openrisc_sysemu_ops = { static const struct TCGCPUOps openrisc_tcg_ops = { .initialize = openrisc_translate_init, +.synchronize_from_tb = openrisc_cpu_synchronize_from_tb, #ifndef CONFIG_USER_ONLY .tlb_fill = openrisc_cpu_tlb_fill, -- 2.31.1
[PULL 2/4] hw/openrisc: support 4 serial ports in or1ksim
From: "Jason A. Donenfeld" The 8250 serial controller supports 4 serial ports, so wire them all up, so that we can have more than one basic I/O channel. Cc: Stafford Horne Signed-off-by: Jason A. Donenfeld [smh:Fixup indentation and lines over 80 chars] Signed-off-by: Stafford Horne --- hw/openrisc/openrisc_sim.c | 22 -- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 99b14940f4..6873124f74 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -71,6 +71,10 @@ enum { OR1KSIM_ETHOC_IRQ = 4, }; +enum { +OR1KSIM_UART_COUNT = 4 +}; + static const struct MemmapEntry { hwaddr base; hwaddr size; @@ -239,11 +243,13 @@ static void openrisc_sim_ompic_init(Or1ksimState *state, hwaddr base, static void openrisc_sim_serial_init(Or1ksimState *state, hwaddr base, hwaddr size, int num_cpus, - OpenRISCCPU *cpus[], int irq_pin) + OpenRISCCPU *cpus[], int irq_pin, + int uart_idx) { void *fdt = state->fdt; char *nodename; qemu_irq serial_irq; +char alias[sizeof("uart0")]; int i; if (num_cpus > 1) { @@ -258,7 +264,8 @@ static void openrisc_sim_serial_init(Or1ksimState *state, hwaddr base, serial_irq = get_cpu_irq(cpus, 0, irq_pin); } serial_mm_init(get_system_memory(), base, 0, serial_irq, 115200, - serial_hd(0), DEVICE_NATIVE_ENDIAN); + serial_hd(OR1KSIM_UART_COUNT - uart_idx - 1), + DEVICE_NATIVE_ENDIAN); /* Add device tree node for serial. */ nodename = g_strdup_printf("/serial@%" HWADDR_PRIx, base); @@ -271,7 +278,8 @@ static void openrisc_sim_serial_init(Or1ksimState *state, hwaddr base, /* The /chosen node is created during fdt creation. */ qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", nodename); -qemu_fdt_setprop_string(fdt, "/aliases", "uart0", nodename); +snprintf(alias, sizeof(alias), "uart%d", uart_idx); +qemu_fdt_setprop_string(fdt, "/aliases", alias, nodename); g_free(nodename); } @@ -414,9 +422,11 @@ static void openrisc_sim_init(MachineState *machine) smp_cpus, cpus, OR1KSIM_OMPIC_IRQ); } -openrisc_sim_serial_init(state, or1ksim_memmap[OR1KSIM_UART].base, - or1ksim_memmap[OR1KSIM_UART].size, smp_cpus, cpus, - OR1KSIM_UART_IRQ); +for (n = 0; n < OR1KSIM_UART_COUNT; ++n) +openrisc_sim_serial_init(state, or1ksim_memmap[OR1KSIM_UART].base + +or1ksim_memmap[OR1KSIM_UART].size * n, + or1ksim_memmap[OR1KSIM_UART].size, + smp_cpus, cpus, OR1KSIM_UART_IRQ, n); load_addr = openrisc_load_kernel(ram_size, kernel_filename); if (load_addr > 0) { -- 2.31.1
[PULL 3/4] hw/openrisc: use right OMPIC size variable
From: "Jason A. Donenfeld" This appears to be a copy and paste error. The UART size was used instead of the much smaller OMPIC size. But actually that smaller OMPIC size is wrong too and doesn't allow the IPI to work in Linux. So set it to the old value. Signed-off-by: Jason A. Donenfeld [smh:Updated OR1KSIM_OMPIC size to use OR1KSIM_CPUS_MAX] Signed-off-by: Stafford Horne --- hw/openrisc/openrisc_sim.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 6873124f74..35adce17ac 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -82,7 +82,7 @@ static const struct MemmapEntry { [OR1KSIM_DRAM] = { 0x, 0 }, [OR1KSIM_UART] = { 0x9000, 0x100 }, [OR1KSIM_ETHOC] = { 0x9200, 0x800 }, -[OR1KSIM_OMPIC] = { 0x9800, 16 }, +[OR1KSIM_OMPIC] = { 0x9800, OR1KSIM_CPUS_MAX * 8 }, }; static struct openrisc_boot_info { @@ -418,7 +418,7 @@ static void openrisc_sim_init(MachineState *machine) if (smp_cpus > 1) { openrisc_sim_ompic_init(state, or1ksim_memmap[OR1KSIM_OMPIC].base, -or1ksim_memmap[OR1KSIM_UART].size, +or1ksim_memmap[OR1KSIM_OMPIC].size, smp_cpus, cpus, OR1KSIM_OMPIC_IRQ); } -- 2.31.1
[PULL 1/4] hw/openrisc: page-align FDT address
From: "Jason A. Donenfeld" The QEMU-provided FDT was only being recognized by the kernel when it was used in conjunction with -initrd. Without it, the magic bytes wouldn't be there and the kernel couldn't load it. This patch fixes the issue by page aligning the provided FDT. Cc: Stafford Horne Cc: Peter Maydell Signed-off-by: Jason A. Donenfeld Signed-off-by: Stafford Horne --- hw/openrisc/openrisc_sim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 8184caa60b..99b14940f4 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -356,7 +356,7 @@ static uint32_t openrisc_load_fdt(Or1ksimState *state, hwaddr load_start, } /* We put fdt right after the kernel and/or initrd. */ -fdt_addr = ROUND_UP(load_start, 4); +fdt_addr = TARGET_PAGE_ALIGN(load_start); ret = fdt_pack(fdt); /* Should only fail if we've built a corrupted tree */ -- 2.31.1
[PULL 0/4] OpenRISC fixes for QEMU 2022-05-15
The following changes since commit 2e3408b3cc7de4e87a9adafc8c19bfce3abec947: Merge tag 'misc-pull-request' of gitlab.com:marcandre.lureau/qemu into staging (2022-05-03 09:13:17 -0700) are available in the Git repository at: https://github.com/stffrdhrn/qemu.git tags/or1k-pull-request-20220515 for you to fetch changes up to e8f0ab0cd674241cbab7231ce05ac1bfa0b4f5ed: target/openrisc: Do not reset delay slot flag on early tb exit (2022-05-15 10:33:01 +0900) OpenRISC Fixes for 7.0 - A few or1ksim fixes and enhancements - A fix for OpenRISC tcg backend around delay slot handling Jason A. Donenfeld (3): hw/openrisc: page-align FDT address hw/openrisc: support 4 serial ports in or1ksim hw/openrisc: use right OMPIC size variable Stafford Horne (1): target/openrisc: Do not reset delay slot flag on early tb exit hw/openrisc/openrisc_sim.c | 28 +++- target/openrisc/cpu.c | 11 +++ 2 files changed, 30 insertions(+), 9 deletions(-) Jason A. Donenfeld (3): hw/openrisc: page-align FDT address hw/openrisc: support 4 serial ports in or1ksim hw/openrisc: use right OMPIC size variable Stafford Horne (1): target/openrisc: Do not reset delay slot flag on early tb exit hw/openrisc/openrisc_sim.c | 28 +++- target/openrisc/cpu.c | 11 +++ 2 files changed, 30 insertions(+), 9 deletions(-) -- 2.31.1
Re: [PATCH] target/openrisc: Do not reset delay slot flag on early tb exit
On Wed, May 11, 2022 at 07:11:20PM -0700, Richard Henderson wrote: > On 5/11/22 15:34, Stafford Horne wrote: > > In this case I don't see how the tb->flag would be updated, ooh, I guess it > > would have been set earlier when the TB was generated. Maybe that is what > > I am > > missing. > > Correct, it should be unchanged (and correct) from generation. OK, its very clear now thanks. With that said, I am still not convinced we need something like: --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -37,6 +37,7 @@ static void openrisc_cpu_synchronize_from_tb(CPUState *cs, OpenRISCCPU *cpu = OPENRISC_CPU(cs); cpu->env.pc = tb->pc; +cpu->env.dflag = (tb->flags & TB_FLAGS_DFLAG) ? 1 : 0; } I will leave it out for now as I feel comfortable that the env.dflag will be correct. But if you think of something let me know. -Stafford
Re: [PATCH] target/openrisc: Do not reset delay slot flag on early tb exit
On Wed, May 11, 2022 at 02:56:37PM -0700, Richard Henderson wrote: > On 5/11/22 14:43, Stafford Horne wrote: > > At this point how would tb->flags have the right value? Would it always be > > set > > correctly by `cpu_get_tb_cpu_state` in the `lookup_tb_ptr`call? > > Well, it would be set by cpu_get_tb_cpu_state in cpu_exec, which is then > passed to tb_gen_code. If we go around a loop and look it up a second time, > we'll find a tb with a matching set of flags. Right, cpu_get_tb_cpu_state called in lookup_tb_ptr will not update tb->flags. What you mention, that is for when we have to generate a new TB, the tb->flags get set right before tb_gen_code. But for the case where we exit the delay-slot TB due to a pending exception I think the flow would go. TB chain: -> branch-TB : set env->flag 1 -> delay-slot-TB : exit_tb due to condition Exit: -> return to cpu_tb_exec -> tcg_ops->synchronize_from_tb In this case I don't see how the tb->flag would be updated, ooh, I guess it would have been set earlier when the TB was generated. Maybe that is what I am missing. -Stafford
Re: [PATCH] target/openrisc: Do not reset delay slot flag on early tb exit
On Wed, May 11, 2022 at 07:32:58AM -0700, Richard Henderson wrote: > On 5/11/22 05:05, Stafford Horne wrote: > > +static void openrisc_cpu_synchronize_from_tb(CPUState *cs, > > + const TranslationBlock *tb) > > +{ > > +OpenRISCCPU *cpu = OPENRISC_CPU(cs); > > + > > +cpu->env.pc = tb->pc; > > +} > > If mips is a guide, you'd want to set dflag based on > > tb->flags & TB_FLAGS_DFLAG > > as well. But I think openrisc is more careful to keep dflag up-to-date. I was thinking that too so I left it out. For example: 0xc01e3ffc: l.bf 3 0xc01e4000: l.ori r12, r0, 1 --- c01e3ffc movcond_i32 jmp_pc,sr_f,$0x0,$0xc01e4008,$0xc01e4004,ne sync: 0 dead: 0 1 2 3 4 pref=0x mov_i32 dflag,$0x1 sync: 0 dead: 0 1 pref=0x mov_i32 ppc,$0xc01e3ffc sync: 0 dead: 0 1 pref=0x mov_i32 pc,$0xc01e4000 sync: 0 dead: 0 1 pref=0x call lookup_tb_ptr,$0x6,$1,tmp7,env dead: 1 pref=none goto_ptr tmp7dead: 0 set_label $L0 exit_tb $0x7f7b047f3b43 --- ld_i32 tmp0,env,$0xfff0 pref=0x brcond_i32 tmp0,$0x0,lt,$L0 dead: 0 c01e4000 0001 mov_i32 r12,$0x1 sync: 0 dead: 0 1 pref=0x mov_i32 dflag,$0x0 sync: 0 dead: 0 1 pref=0x mov_i32 ppc,$0xc01e4000 sync: 0 dead: 0 1 pref=0x mov_i32 pc,jmp_pcsync: 0 dead: 0 1 pref=0x discard jmp_pc pref=none call lookup_tb_ptr,$0x6,$1,tmp4,env dead: 1 pref=none goto_ptr tmp4dead: 0 set_label $L0 exit_tb $0x7f7b047f3c83 This is an example of a branch followed by a branch delay slot. If we exit the branch delay slot via `exit_tb $0x7f7b047f3c83`. The `mov_i32 dflag,$0x1` instruction would have run from `c01e3ffc` having env already updated. At this point how would tb->flags have the right value? Would it always be set correctly by `cpu_get_tb_cpu_state` in the `lookup_tb_ptr`call? -Stafford
Re: [PULL 3/4] Normalize header guard symbol definition
On Wed, May 11, 2022 at 04:59:21PM +0200, Markus Armbruster wrote: > We commonly define the header guard symbol without an explicit value. > Normalize the exceptions. > > Done with scripts/clean-header-guards.pl. > > Signed-off-by: Markus Armbruster > Message-Id: <20220506134911.2856099-4-arm...@redhat.com> > Reviewed-by: Richard Henderson > --- > include/exec/memopidx.h | 2 +- > include/tcg/tcg-ldst.h| 2 +- > target/alpha/cpu-param.h | 2 +- > target/arm/cpu-param.h| 2 +- > target/cris/cpu-param.h | 2 +- > target/hppa/cpu-param.h | 2 +- > target/i386/cpu-param.h | 2 +- > target/m68k/cpu-param.h | 2 +- > target/microblaze/cpu-param.h | 2 +- > target/mips/cpu-param.h | 2 +- > target/nios2/cpu-param.h | 2 +- > target/openrisc/cpu-param.h | 2 +- > target/ppc/cpu-param.h| 2 +- > target/riscv/cpu-param.h | 2 +- > target/s390x/cpu-param.h | 2 +- > target/sh4/cpu-param.h| 2 +- > target/sparc/cpu-param.h | 2 +- > target/tricore/cpu-param.h| 2 +- > target/xtensa/cpu-param.h | 2 +- > tcg/tcg-internal.h| 2 +- > 20 files changed, 20 insertions(+), 20 deletions(-) I looked at this for the OpenRISC changes, but the whole patch looks ok to me. Reviewed-by: Stafford Horne
[PATCH] target/openrisc: Do not reset delay slot flag on early tb exit
This was found when running linux crypto algorithm selftests used by wireguard. We found that randomly the tests would fail. We found through investigation that a combination of a tick timer interrupt, raised when executing a delay slot instruction at a page boundary caused the issue. This was caused when handling the TB_EXIT_REQUESTED case in cpu_tb_exec. On OpenRISC, which doesn't implement synchronize_from_tb, set_pc was being used as a fallback. The OpenRISC set_pc implementation clears dflag, which caused the exception handling logic to not account for the delay slot. This was the bug, because it meant when execution resumed after the interrupt was handling it resumed in the wrong place. Fix this by implementing synchronize_from_tb which simply updates pc, and not clear the delay slot flag. Reported-by: Jason A. Donenfeld Signed-off-by: Stafford Horne --- target/openrisc/cpu.c | 11 +++ 1 file changed, 11 insertions(+) diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index dfbafc5236..41d1b2a24a 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -21,6 +21,7 @@ #include "qapi/error.h" #include "qemu/qemu-print.h" #include "cpu.h" +#include "exec/exec-all.h" static void openrisc_cpu_set_pc(CPUState *cs, vaddr value) { @@ -30,6 +31,15 @@ static void openrisc_cpu_set_pc(CPUState *cs, vaddr value) cpu->env.dflag = 0; } +static void openrisc_cpu_synchronize_from_tb(CPUState *cs, + const TranslationBlock *tb) +{ +OpenRISCCPU *cpu = OPENRISC_CPU(cs); + +cpu->env.pc = tb->pc; +} + + static bool openrisc_cpu_has_work(CPUState *cs) { return cs->interrupt_request & (CPU_INTERRUPT_HARD | @@ -186,6 +196,7 @@ static const struct SysemuCPUOps openrisc_sysemu_ops = { static const struct TCGCPUOps openrisc_tcg_ops = { .initialize = openrisc_translate_init, +.synchronize_from_tb = openrisc_cpu_synchronize_from_tb, #ifndef CONFIG_USER_ONLY .tlb_fill = openrisc_cpu_tlb_fill, -- 2.31.1
Re: [PATCH v2] hw/openrisc: use right OMPIC size variable
On Wed, May 04, 2022 at 01:10:04PM +0200, Jason A. Donenfeld wrote: > On Tue, May 3, 2022 at 10:22 PM Stafford Horne wrote: > > > > On Tue, May 03, 2022 at 11:45:33AM +0200, Jason A. Donenfeld wrote: > > > This appears to be a copy and paste error. The UART size was used > > > instead of the much smaller OMPIC size. But actually that smaller OMPIC > > > size is wrong too and doesn't allow the IPI to work in Linux. So set it > > > to the old value. > > > > > > Signed-off-by: Jason A. Donenfeld > > > --- > > > hw/openrisc/openrisc_sim.c | 4 ++-- > > > 1 file changed, 2 insertions(+), 2 deletions(-) > > > > > > diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c > > > index 99b14940f4..3218db6656 100644 > > > --- a/hw/openrisc/openrisc_sim.c > > > +++ b/hw/openrisc/openrisc_sim.c > > > @@ -78,7 +78,7 @@ static const struct MemmapEntry { > > > [OR1KSIM_DRAM] = { 0x, 0 }, > > > [OR1KSIM_UART] = { 0x9000, 0x100 }, > > > [OR1KSIM_ETHOC] = { 0x9200, 0x800 }, > > > -[OR1KSIM_OMPIC] = { 0x9800, 16 }, > > > +[OR1KSIM_OMPIC] = { 0x9800, 0x100 }, > > > > Right, I missed this as part of my series. OMPIC will allocate 2 32-bit > > registers per CPU. I documented this here: > > > > - > > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/irqchip/irq-ompic.c > > > > I think what we will want here is something like: > > > > [OR1KSIM_OMPIC] = { 0x9800, 8 * OR1KSIM_CPUS_MAX }, > > Do you want a v3 or are you going to fix it up yourself? I'll fix it up. -Stafford
Re: [PATCH v2] hw/openrisc: use right OMPIC size variable
On Tue, May 03, 2022 at 11:45:33AM +0200, Jason A. Donenfeld wrote: > This appears to be a copy and paste error. The UART size was used > instead of the much smaller OMPIC size. But actually that smaller OMPIC > size is wrong too and doesn't allow the IPI to work in Linux. So set it > to the old value. > > Signed-off-by: Jason A. Donenfeld > --- > hw/openrisc/openrisc_sim.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c > index 99b14940f4..3218db6656 100644 > --- a/hw/openrisc/openrisc_sim.c > +++ b/hw/openrisc/openrisc_sim.c > @@ -78,7 +78,7 @@ static const struct MemmapEntry { > [OR1KSIM_DRAM] = { 0x, 0 }, > [OR1KSIM_UART] = { 0x9000, 0x100 }, > [OR1KSIM_ETHOC] = { 0x9200, 0x800 }, > -[OR1KSIM_OMPIC] = { 0x9800, 16 }, > +[OR1KSIM_OMPIC] = { 0x9800, 0x100 }, Right, I missed this as part of my series. OMPIC will allocate 2 32-bit registers per CPU. I documented this here: - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/irqchip/irq-ompic.c I think what we will want here is something like: [OR1KSIM_OMPIC] = { 0x9800, 8 * OR1KSIM_CPUS_MAX }, > }; > > static struct openrisc_boot_info { > @@ -410,7 +410,7 @@ static void openrisc_sim_init(MachineState *machine) > > if (smp_cpus > 1) { > openrisc_sim_ompic_init(state, or1ksim_memmap[OR1KSIM_OMPIC].base, > -or1ksim_memmap[OR1KSIM_UART].size, > +or1ksim_memmap[OR1KSIM_OMPIC].size, > smp_cpus, cpus, OR1KSIM_OMPIC_IRQ); > } > > -- > 2.35.1 >