ppc: Add "native" POWER8 platform
cover ppc: Add "native" POWER8 platform
This requires an OPAL firmware file which isn't included yet, will emulate enough to boot existing distros and run KVM inside TCG
PATCH 1/77 ppc: Remove MMU_MODEn_SUFFIX definitions
We don't use the resulting accessors and this gets in the way of the split I/D TLB work.
--- target-ppc/cpu.h | 3 --- 1 file changed, 3 deletions(-)
target-ppc/cpu.h +0 -3
@@ -1246,9 +1246,6 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val);#define cpu_list ppc_cpu_list/* MMU modes definitions */ -#define MMU_MODE0_SUFFIX _user -#define MMU_MODE1_SUFFIX _kernel -#define MMU_MODE2_SUFFIX _hypv#define MMU_USER_IDX 0static inline int cpu_mmu_index (CPUPPCState *env,bool ifetch) {
Signature · 1 line
2.5.0
PATCH 2/77 ppc: Use split I/D mmu modes to avoid flushes on interrupts
In reply to Benjamin HerrenschmidtWe rework the way the MMU indices are calculated, providing separate indices for I and D side based on MSR:IR and MSR:DR respectively, and thus no longer need to flush the TLB on context changes. This also adds correct support for HV as a separate address space.
--- target-ppc/cpu.h | 11 +++++++--- target-ppc/excp_helper.c | 11 ---------- target-ppc/helper_regs.h | 54 +++++++++++++++++++++++++++++++++++++++++------- target-ppc/machine.c | 4 +++- target-ppc/translate.c | 7 ++++--- 5 files changed, 62 insertions(+), 25 deletions(-)
target-ppc/cpu.h +8 -3
@@ -462,6 +462,8 @@ struct ppc_slb_t {#define MSR_EP 6/* Exception prefix on 601 */ #define MSR_IR 5/* Instruction relocate */ #define MSR_DR 4/* Data relocate */ +#define MSR_IS 5/* Instruction address space (BookE) */ +#define MSR_DS 4/* Data address space (BookE) */ #define MSR_PE 3/* Protection enable on 403 */ #define MSR_PX 2/* Protection exclusive on 403 x */ #define MSR_PMM 2/* Performance monitor mark on POWER x */
@@ -505,6 +507,8 @@ struct ppc_slb_t {#define msr_ep ((env->msr >> MSR_EP) & 1)#define msr_ir ((env->msr >> MSR_IR) & 1)#define msr_dr ((env->msr >> MSR_DR) & 1) +#define msr_is ((env->msr >> MSR_IS) & 1) +#define msr_ds ((env->msr >> MSR_DS) & 1)#define msr_pe ((env->msr >> MSR_PE) & 1)#define msr_px ((env->msr >> MSR_PX) & 1)#define msr_pmm ((env->msr >> MSR_PMM) & 1)
@@ -944,7 +948,7 @@ struct ppc_segment_page_sizes {/*****************************************************************************/ /* The whole PowerPC CPU context */ -#define NB_MMU_MODES 3 +#define NB_MMU_MODES 8#define PPC_CPU_OPCODES_LEN 0x40#define PPC_CPU_INDIRECT_OPCODES_LEN 0x20
@@ -1108,7 +1112,8 @@ struct CPUPPCState {/* Those resources are used only in QEMU core */ target_ulong hflags;/* hflags is a MSR & HFLAGS_MASK */ target_ulong hflags_nmsr;/* specific hflags, not coming from MSR */ -int mmu_idx;/* precomputed MMU index to speed up mem accesses */ +int immu_idx;/* precomputed MMU index to speed up insn access */ +int dmmu_idx;/* precomputed MMU index to speed up data accesses */ /* Power management */ int (*check_pow)(CPUPPCState *env);
@@ -1249,7 +1254,7 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val);#define MMU_USER_IDX 0static inline int cpu_mmu_index (CPUPPCState *env,bool ifetch) { -return env->mmu_idx; +return ifetch ? env->immu_idx : env->dmmu_idx; }#include "exec/cpu-all.h"
target-ppc/excp_helper.c +0 -11
@@ -623,9 +623,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)if (env->spr[SPR_LPCR ] &LPCR_AIL ) { new_msr |= (1 <<MSR_IR ) | (1 <<MSR_DR ); - }else if (msr & ((1 <<MSR_IR ) | (1 <<MSR_DR ))) { -/* If we disactivated any translation, flush TLBs */ -tlb_flush (cs,1 ); }#ifdef TARGET_PPC64
@@ -674,14 +671,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)/* Reset exception state */ cs->exception_index =POWERPC_EXCP_NONE ; env->error_code =0 ; - -if ((env->mmu_model ==POWERPC_MMU_BOOKE ) || - (env->mmu_model ==POWERPC_MMU_BOOKE206 )) { -/* XXX: The BookE changes address space when switching modes, -we should probably implement that as different MMU indexes, -but for the moment we do it the slow way and flush all. */ -tlb_flush (cs,1 ); - } }void ppc_cpu_do_interrupt (CPUState *cs)
target-ppc/helper_regs.h +47 -7
67 lines not on this page · raw message
target-ppc/machine.c +3 -1
@@ -90,9 +90,11 @@ static int cpu_load_old(QEMUFile *f, void *opaque, int version_id)qemu_get_betls (f, &env->nip);qemu_get_betls (f, &env->hflags);qemu_get_betls (f, &env->hflags_nmsr); -qemu_get_sbe32s (f, &env->mmu_idx);qemu_get_sbe32 (f);/* Discard unused power_mode */ +/* Ignore saved mmu_idx, recompute */ +hreg_compute_mem_idx (env); +return 0 ; }
target-ppc/translate.c +4 -3
@@ -11220,8 +11220,9 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, env->nip, env->lr, env->ctr,cpu_read_xer (env), cs->cpu_index);cpu_fprintf (f,"MSR " TARGET_FMT_lx" HID0 " TARGET_FMT_lx" HF " - TARGET_FMT_lx" idx %d\n" , env->msr, env->spr[SPR_HID0 ], - env->hflags, env->mmu_idx); + TARGET_FMT_lx" iidx %d didx %d\n" , + env->msr, env->spr[SPR_HID0 ], + env->hflags, env->immu_idx, env->dmmu_idx);#if !defined(NO_TIMER_DUMP ) cpu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64 #if !defined(CONFIG_USER_ONLY)
@@ -11426,7 +11427,7 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb) ctx.spr_cb = env->spr_cb; ctx.pr = msr_pr; ctx.hv = !msr_pr && msr_hv; - ctx.mem_idx = env->mmu_idx; + ctx.mem_idx = env->dmmu_idx; ctx.insns_flags = env->insns_flags; ctx.insns_flags2 = env->insns_flags2; ctx.access_type =-1 ;
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 02/77] ppc: Use split I/D mmu modes to avoid flushes on interrupts
Quoted 105 lines · Benjamin Herrenschmidt
We rework the way the MMU indices are calculated, providing separate indices for I and D side based on MSR:IR and MSR:DR respectively, and thus no longer need to flush the TLB on context changes. This also adds correct support for HV as a separate address space.
Signed-off-by Benjamin Herrenschmidt <[email protected]>--- target-ppc/cpu.h | 11 +++++++--- target-ppc/excp_helper.c | 11 ---------- target-ppc/helper_regs.h | 54 +++++++++++++++++++++++++++++++++++++++++------- target-ppc/machine.c | 4 +++- target-ppc/translate.c | 7 ++++--- 5 files changed, 62 insertions(+), 25 deletions(-)target-ppc/cpu.h +8
-3@@ -462,6 +462,8 @@ struct ppc_slb_t {#define MSR_EP 6/* Exception prefix on 601 */ #define MSR_IR 5/* Instruction relocate */ #define MSR_DR 4/* Data relocate */ +#define MSR_IS 5/* Instruction address space (BookE) */ +#define MSR_DS 4/* Data address space (BookE) */ #define MSR_PE 3/* Protection enable on 403 */ #define MSR_PX 2/* Protection exclusive on 403 x */ #define MSR_PMM 2/* Performance monitor mark on POWER x */ @@ -505,6 +507,8 @@ struct ppc_slb_t {#define msr_ep ((env->msr >> MSR_EP) & 1)#define msr_ir ((env->msr >> MSR_IR) & 1)#define msr_dr ((env->msr >> MSR_DR) & 1) +#define msr_is ((env->msr >> MSR_IS) & 1) +#define msr_ds ((env->msr >> MSR_DS) & 1)#define msr_pe ((env->msr >> MSR_PE) & 1)#define msr_px ((env->msr >> MSR_PX) & 1)#define msr_pmm ((env->msr >> MSR_PMM) & 1)@@ -944,7 +948,7 @@ struct ppc_segment_page_sizes {/*****************************************************************************/ /* The whole PowerPC CPU context */ -#define NB_MMU_MODES 3 +#define NB_MMU_MODES 8#define PPC_CPU_OPCODES_LEN 0x40#define PPC_CPU_INDIRECT_OPCODES_LEN 0x20@@ -1108,7 +1112,8 @@ struct CPUPPCState {/* Those resources are used only in QEMU core */ target_ulong hflags;/* hflags is a MSR & HFLAGS_MASK */ target_ulong hflags_nmsr;/* specific hflags, not coming from MSR */ -int mmu_idx;/* precomputed MMU index to speed up mem accesses */ +int immu_idx;/* precomputed MMU index to speed up insn access */ +int dmmu_idx;/* precomputed MMU index to speed up data accesses */ /* Power management */ int (*check_pow)(CPUPPCState *env);@@ -1249,7 +1254,7 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val);#define MMU_USER_IDX 0static inline int cpu_mmu_index (CPUPPCState *env,bool ifetch) { -return env->mmu_idx; +return ifetch ? env->immu_idx : env->dmmu_idx; }#include "exec/cpu-all.h" target-ppc/excp_helper.c +0
-11@@ -623,9 +623,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)if (env->spr[SPR_LPCR ] &LPCR_AIL ) { new_msr |= (1 <<MSR_IR ) | (1 <<MSR_DR ); - }else if (msr & ((1 <<MSR_IR ) | (1 <<MSR_DR ))) { -/* If we disactivated any translation, flush TLBs */ -tlb_flush (cs,1 ); }#ifdef TARGET_PPC64 @@ -674,14 +671,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)/* Reset exception state */ cs->exception_index =POWERPC_EXCP_NONE ; env->error_code =0 ; - -if ((env->mmu_model ==POWERPC_MMU_BOOKE ) || - (env->mmu_model ==POWERPC_MMU_BOOKE206 )) { -/* XXX: The BookE changes address space when switching modes, -we should probably implement that as different MMU indexes, -but for the moment we do it the slow way and flush all. */ -tlb_flush (cs,1 ); - } }void ppc_cpu_do_interrupt (CPUState *cs)target-ppc/helper_regs.h +1
-3@@ -41,11 +41,50 @@ static inline void hreg_swap_gpr_tgpr(CPUPPCState *env)static inline void hreg_compute_mem_idx (CPUPPCState *env) { -/* Precompute MMU index */ -if (msr_pr ==0 && msr_hv !=0 ) { - env->mmu_idx =2 ; +/* This is our encoding for server processors
target-ppc/helper_regs.h static inline void hreg_swap_gpr_tgpr(CPUPPCState *env) · line 54
Quoted 10 lines
target-ppc/helper_regs.h +10
-0+* +* 0 = Guest User space virtual mode +* 1 = Guest Kernel space virtual mode +* 2 = Guest Kernel space real mode +* 3 = HV User space virtual mode +* 4 = HV Kernel space virtual mode +* 5 = HV Kernel space real mode +* +* The combination PR=1 IR&DR=0 is invalid, we will treat +* it as IR=DR=1
Hmm.. so being in problem state with translation off would certainly be a bad idea, but would it actually behave this way on CPU hardware?
target-ppc/helper_regs.h static inline void hreg_swap_gpr_tgpr(CPUPPCState *env) · line 66
Quoted 12 lines
target-ppc/helper_regs.h +12
-0+* +* For BookE, we need 8 MMU modes as follow: +* +* 0 = AS 0 HV User space +* 1 = AS 0 HV Kernel space +* 2 = AS 1 HV User space +* 3 = AS 1 HV Kernel space +* 4 = AS 0 Guest User space +* 5 = AS 0 Guest Kernel space +* 6 = AS 1 Guest User space +* 7 = AS 1 Guest Kernel space +*/
I'm wondering if it might be simpler to unify these and allow all 8 theoretical possibilities (hv/guest * user/kernel * translationmode) for both server and BookE.
Quoted 44 lines
target-ppc/helper_regs.h +24
-4+if (env->mmu_model &POWERPC_MMU_BOOKE ) { + env->immu_idx = env->dmmu_idx = msr_pr ?0 :1 ; + env->immu_idx += msr_is ?2 :0 ; + env->dmmu_idx += msr_ds ?2 :0 ; + env->immu_idx += msr_gs ?4 :0 ; + env->dmmu_idx += msr_gs ?4 :0 ; }else { - env->mmu_idx =1 - msr_pr; +/* First calucalte a base value independent of HV */ +if (msr_pr !=0 ) { +/* User space, ignore IR and DR */ + env->immu_idx = env->dmmu_idx =0 ; + }else { +/* Kernel, setup a base I/D value */ + env->immu_idx = msr_ir ?1 :2 ; + env->dmmu_idx = msr_dr ?1 :2 ; + } +/* Then offset it for HV */ +if (msr_hv) { + env->immu_idx +=3 ; + env->dmmu_idx +=3 ; + } } }@@ -82,9 +121,10 @@ static inline int hreg_store_msr(CPUPPCState *env, target_ulong value, }if (((value >>MSR_IR ) &1 ) != msr_ir || ((value >>MSR_DR ) &1 ) != msr_dr) { -/* Flush all tlb when changing translation mode */ -tlb_flush (cs,1 ); - excp =POWERPC_EXCP_NONE ; + cs->interrupt_request |=CPU_INTERRUPT_EXITTB ; + } +if ((env->mmu_model &POWERPC_MMU_BOOKE ) && + ((value >>MSR_GS ) &1 ) != msr_gs) { cs->interrupt_request |=CPU_INTERRUPT_EXITTB ; } if (unlikely((env->flags & POWERPC_FLAG_TGPR) &&target-ppc/machine.c +0
-0
target-ppc/machine.c static int cpu_load_old(QEMUFile *f, void *opaque, int version_id) · line 93
Quoted 4 lines
target-ppc/machine.c +0
-1@@ -90,9 +90,11 @@ static int cpu_load_old(QEMUFile *f, void *opaque, int version_id)qemu_get_betls (f, &env->nip);qemu_get_betls (f, &env->hflags);qemu_get_betls (f, &env->hflags_nmsr); -qemu_get_sbe32s (f, &env->mmu_idx);
Have I missed something, or do you still need a read here to read the mmux_idx, even though you'll ignore it, otherwise you'll get out of sync and break migration from an old stream.
Quoted 33 lines
target-ppc/machine.c +3
-0qemu_get_sbe32 (f);/* Discard unused power_mode */ +/* Ignore saved mmu_idx, recompute */ +hreg_compute_mem_idx (env); +return 0 ; }target-ppc/translate.c +4
-3@@ -11220,8 +11220,9 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, env->nip, env->lr, env->ctr,cpu_read_xer (env), cs->cpu_index);cpu_fprintf (f,"MSR " TARGET_FMT_lx" HID0 " TARGET_FMT_lx" HF " - TARGET_FMT_lx" idx %d\n" , env->msr, env->spr[SPR_HID0 ], - env->hflags, env->mmu_idx); + TARGET_FMT_lx" iidx %d didx %d\n" , + env->msr, env->spr[SPR_HID0 ], + env->hflags, env->immu_idx, env->dmmu_idx);#if !defined(NO_TIMER_DUMP ) cpu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64 #if !defined(CONFIG_USER_ONLY)@@ -11426,7 +11427,7 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb) ctx.spr_cb = env->spr_cb; ctx.pr = msr_pr; ctx.hv = !msr_pr && msr_hv; - ctx.mem_idx = env->mmu_idx; + ctx.mem_idx = env->dmmu_idx; ctx.insns_flags = env->insns_flags; ctx.insns_flags2 = env->insns_flags2; ctx.access_type =-1 ;
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [Qemu-ppc] [PATCH 02/77] ppc: Use split I/D mmu modes to avoid flushes on interrupts
Thanks for reviewing !
Quoted 17 lines · David Gibson
Quoted 8 lines
static inline void
hreg_compute_mem_idx(CPUPPCState *env){
- /* Precompute MMU index */
- if (msr_pr== 0 &&msr_hv!= 0) {
- env->mmu_idx = 2;
+ /* This is our encoding for server processors + *
+ * 0 = Guest User space virtual modeQuoted 8 lines
+ * 1 = Guest Kernel space virtual mode
+ * 2 = Guest Kernel space real mode
+ * 3 = HV User space virtual mode
+ * 4 = HV Kernel space virtual mode
+ * 5 = HV Kernel space real mode
+ *
+ * The combination PR=1 IR&DR=0 is invalid, we will treat + * it as IR=DR=1
Quoted 2 lines
Hmm.. so being in problem state with translation off would certainly be a bad idea, but would it actually behave this way on CPU hardware?
No, it's not allowed in HW. I think (maybe in another patch) I enforce it. Architecturally, setting PR=1 will fore IR, DR and EE to 1
Quoted 13 lines
Quoted 4 lines
+ *
+ * For BookE, we need 8 MMU modes as follow:
+ *
+ * 0 = AS 0 HV User spaceQuoted 8 lines
+ * 1 = AS 0 HV Kernel space
+ * 2 = AS 1 HV User space
+ * 3 = AS 1 HV Kernel space
+ * 4 = AS 0 Guest User space
+ * 5 = AS 0 Guest Kernel space
+ * 6 = AS 1 Guest User space
+ * 7 = AS 1 Guest Kernel space
+ */
Quoted 3 lines
I'm wondering if it might be simpler to unify these and allow all 8 theoretical possibilities (hv/guest * user/kernel * translationmode) for both server and BookE.
I don't see the point. Server doesn't have "AS" and the distinction only appears in that single function...
Quoted 46 lines
Quoted 46 lines
+ if (
env->mmu_model&POWERPC_MMU_BOOKE) {
+ env->immu_idx =env->dmmu_idx=msr_pr? 0 : 1; + env->immu_idx +=msr_is? 2 : 0;
+ env->dmmu_idx +=msr_ds? 2 : 0;
+ env->immu_idx +=msr_gs? 4 : 0;
+ env->dmmu_idx +=msr_gs? 4 : 0;
} else {
- env->mmu_idx = 1 -msr_pr;
+ /* First calucalte a base value independent of HV */ + if (msr_pr!= 0) {
+ /* User space, ignore IR and DR */
+ env->immu_idx =env->dmmu_idx= 0;
+ } else {
+ /* Kernel, setup a base I/D value */
+ env->immu_idx =msr_ir? 1 : 2;
+ env->dmmu_idx =msr_dr? 1 : 2;
+ }
+ /* Then offset it for HV */
+ if (msr_hv) {
+ env->immu_idx += 3;
+ env->dmmu_idx += 3;
+ }
}
}(quoted diff) +0
-0@@ -82,9 +121,10 @@ static inline int hreg_store_msr(CPUPPCState *env, target_ulong value, }if (((value >>
MSR_IR) & 1) !=msr_ir|| ((value >>MSR_DR) & 1) !=msr_dr) {
- /* Flush all tlb when changing translation mode */ - tlb_flush(cs, 1);
- excp =POWERPC_EXCP_NONE;
+ cs->interrupt_request |=CPU_INTERRUPT_EXITTB; + }
+ if ((env->mmu_model&POWERPC_MMU_BOOKE) &&
+ ((value >>MSR_GS) & 1) !=msr_gs) {cs->interrupt_request|=CPU_INTERRUPT_EXITTB; }
if (unlikely((env->flags &POWERPC_FLAG_TGPR) &&target-ppc/machine.c +0
-0@@ -90,9 +90,11 @@ static int cpu_load_old(QEMUFile *f, void *opaque, int version_id)
Quoted 8 lines
target-ppc/machine.c static int cpu_load_old(QEMUFile *f, void *opaque, int version_id) · line 93
Quoted 4 lines
target-ppc/machine.c +0
-1qemu_get_betls(f, &env->nip); qemu_get_betls(f, &env->hflags); qemu_get_betls(f, &env->hflags_nmsr); - qemu_get_sbe32s(f, &env->mmu_idx);Have I missed something, or do you still need a read here to read the
mmux_idx, even though you'll ignore it, otherwise you'll get out of sync and break migration from an old stream.
I am not completely cognizant of the migration stuff, that's very possible yes. Do I need to read into a dummy local ? Or is there a way to just say "drop 4 bytes from stream" ?
Note that I have generally completely overlooked the migration impact of my patches, this is something that I need to do but I wouldn't mind your help identifying the parts.
Quoted 38 lines
Quoted 37 lines
qemu_get_sbe32(f); /* Discard unused
power_mode*/
+ /* Ignore savedmmu_idx, recompute */
+ hreg_compute_mem_idx(env);
+
return 0;
}target-ppc/translate.c +0
-0@@ -11220,8 +11220,9 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, env->nip, env->lr, env->ctr, cpu_read_xer(env), cs->cpu_index);cpu_fprintf(f, "MSR "
TARGET_FMT_lx" HID0 "TARGET_FMT_lx" HF "
- TARGET_FMT_lx " idx %d\n",env->msr, env-Quoted 1 line
spr[SPR_HID0],
- env->hflags,
env->mmu_idx);
+ TARGET_FMT_lx " iidx %d didx %d\n", + env->msr, env->spr[SPR_HID0],
+ env->hflags,env->immu_idx,env->dmmu_idx); #if !defined(NO_TIMER_DUMP)
cpu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64 #if !defined(CONFIG_USER_ONLY)target-ppc/translate.c +1
-1@@ -11426,7 +11427,7 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb) ctx.spr_cb = env->spr_cb; ctx.pr = msr_pr; ctx.hv = !msr_pr && msr_hv; - ctx.mem_idx = env->mmu_idx; + ctx.mem_idx = env->dmmu_idx; ctx.insns_flags = env->insns_flags; ctx.insns_flags2 = env->insns_flags2;ctx.access_type = -1;
Re: [Qemu-devel] [Qemu-ppc] [PATCH 02/77] ppc: Use split I/D mmu modes to avoid flushes on interrupts
Quoted 2 lines · Benjamin Herrenschmidt
Thanks for reviewing !
On Mon, 2015-11-16 at 15:49 +1100, David Gibson wrote:
[snip]
Quoted 15 lines
Quoted 6 lines
Quoted 6 lines
target-ppc/machine.c +0
-0@@ -90,9 +90,11 @@ static int cpu_load_old(QEMUFile *f, void *opaque, int version_id)Quoted 8 lines
target-ppc/machine.c static int cpu_load_old(QEMUFile *f, void *opaque, int version_id) · line 93
Quoted 4 lines
target-ppc/machine.c +0
-1qemu_get_betls(f, &env->nip); qemu_get_betls(f, &env->hflags); qemu_get_betls(f, &env->hflags_nmsr); - qemu_get_sbe32s(f, &env->mmu_idx);Have I missed something, or do you still need a read here to read the
mmux_idx, even though you'll ignore it, otherwise you'll get out of sync and break migration from an old stream.
Quoted 3 lines
I am not completely cognizant of the migration stuff, that's very possible yes. Do I need to read into a dummy local ? Or is there a way to just say "drop 4 bytes from stream" ?
There's actually an example of this just below :)
Quoted 3 lines
Note that I have generally completely overlooked the migration impact of my patches, this is something that I need to do but I wouldn't mind your help identifying the parts.
Ok, I'll do what I can.
Quoted 1 line
Quoted 1 line
Quoted 1 line
qemu_get_sbe32(f); /* Discard unused
power_mode*/
^^^
example of skipping a redundant value in the migration stream
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [Qemu-ppc] [PATCH 02/77] ppc: Use split I/D mmu modes to avoid flushes on interrupts
In reply to Benjamin HerrenschmidtQuoted 6 lines · Benjamin Herrenschmidt
We rework the way the MMU indices are calculated, providing separate indices for I and D side based on MSR:IR and MSR:DR respectively, and thus no longer need to flush the TLB on context changes. This also adds correct support for HV as a separate address space.
Signed-off-by Benjamin Herrenschmidt <[email protected]>
Paolo had a patch set poking at the same places a while back to speed up the ppc target by almost 10%.
Paolo, what happened to those patches? Would you prefer to rebase them on top of the HV bits or have Ben look into them while he's at it anyway? ;)
Alex
Quoted 203 lines
--- target-ppc/cpu.h | 11 +++++++--- target-ppc/excp_helper.c | 11 ---------- target-ppc/helper_regs.h | 54 +++++++++++++++++++++++++++++++++++++++++------- target-ppc/machine.c | 4 +++- target-ppc/translate.c | 7 ++++--- 5 files changed, 62 insertions(+), 25 deletions(-)target-ppc/cpu.h +8
-3@@ -462,6 +462,8 @@ struct ppc_slb_t {#define MSR_EP 6/* Exception prefix on 601 */ #define MSR_IR 5/* Instruction relocate */ #define MSR_DR 4/* Data relocate */ +#define MSR_IS 5/* Instruction address space (BookE) */ +#define MSR_DS 4/* Data address space (BookE) */ #define MSR_PE 3/* Protection enable on 403 */ #define MSR_PX 2/* Protection exclusive on 403 x */ #define MSR_PMM 2/* Performance monitor mark on POWER x */ @@ -505,6 +507,8 @@ struct ppc_slb_t {#define msr_ep ((env->msr >> MSR_EP) & 1)#define msr_ir ((env->msr >> MSR_IR) & 1)#define msr_dr ((env->msr >> MSR_DR) & 1) +#define msr_is ((env->msr >> MSR_IS) & 1) +#define msr_ds ((env->msr >> MSR_DS) & 1)#define msr_pe ((env->msr >> MSR_PE) & 1)#define msr_px ((env->msr >> MSR_PX) & 1)#define msr_pmm ((env->msr >> MSR_PMM) & 1)@@ -944,7 +948,7 @@ struct ppc_segment_page_sizes {/*****************************************************************************/ /* The whole PowerPC CPU context */ -#define NB_MMU_MODES 3 +#define NB_MMU_MODES 8#define PPC_CPU_OPCODES_LEN 0x40#define PPC_CPU_INDIRECT_OPCODES_LEN 0x20@@ -1108,7 +1112,8 @@ struct CPUPPCState {/* Those resources are used only in QEMU core */ target_ulong hflags;/* hflags is a MSR & HFLAGS_MASK */ target_ulong hflags_nmsr;/* specific hflags, not coming from MSR */ -int mmu_idx;/* precomputed MMU index to speed up mem accesses */ +int immu_idx;/* precomputed MMU index to speed up insn access */ +int dmmu_idx;/* precomputed MMU index to speed up data accesses */ /* Power management */ int (*check_pow)(CPUPPCState *env);@@ -1249,7 +1254,7 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val);#define MMU_USER_IDX 0static inline int cpu_mmu_index (CPUPPCState *env,bool ifetch) { -return env->mmu_idx; +return ifetch ? env->immu_idx : env->dmmu_idx; }#include "exec/cpu-all.h" target-ppc/excp_helper.c +0
-11@@ -623,9 +623,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)if (env->spr[SPR_LPCR ] &LPCR_AIL ) { new_msr |= (1 <<MSR_IR ) | (1 <<MSR_DR ); - }else if (msr & ((1 <<MSR_IR ) | (1 <<MSR_DR ))) { -/* If we disactivated any translation, flush TLBs */ -tlb_flush (cs,1 ); }#ifdef TARGET_PPC64 @@ -674,14 +671,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)/* Reset exception state */ cs->exception_index =POWERPC_EXCP_NONE ; env->error_code =0 ; - -if ((env->mmu_model ==POWERPC_MMU_BOOKE ) || - (env->mmu_model ==POWERPC_MMU_BOOKE206 )) { -/* XXX: The BookE changes address space when switching modes, -we should probably implement that as different MMU indexes, -but for the moment we do it the slow way and flush all. */ -tlb_flush (cs,1 ); - } }void ppc_cpu_do_interrupt (CPUState *cs)target-ppc/helper_regs.h +47
-7@@ -41,11 +41,50 @@ static inline void hreg_swap_gpr_tgpr(CPUPPCState *env)static inline void hreg_compute_mem_idx (CPUPPCState *env) { -/* Precompute MMU index */ -if (msr_pr ==0 && msr_hv !=0 ) { - env->mmu_idx =2 ; +/* This is our encoding for server processors +* +* 0 = Guest User space virtual mode +* 1 = Guest Kernel space virtual mode +* 2 = Guest Kernel space real mode +* 3 = HV User space virtual mode +* 4 = HV Kernel space virtual mode +* 5 = HV Kernel space real mode +* +* The combination PR=1 IR&DR=0 is invalid, we will treat +* it as IR=DR=1 +* +* For BookE, we need 8 MMU modes as follow: +* +* 0 = AS 0 HV User space +* 1 = AS 0 HV Kernel space +* 2 = AS 1 HV User space +* 3 = AS 1 HV Kernel space +* 4 = AS 0 Guest User space +* 5 = AS 0 Guest Kernel space +* 6 = AS 1 Guest User space +* 7 = AS 1 Guest Kernel space +*/ +if (env->mmu_model &POWERPC_MMU_BOOKE ) { + env->immu_idx = env->dmmu_idx = msr_pr ?0 :1 ; + env->immu_idx += msr_is ?2 :0 ; + env->dmmu_idx += msr_ds ?2 :0 ; + env->immu_idx += msr_gs ?4 :0 ; + env->dmmu_idx += msr_gs ?4 :0 ; }else { - env->mmu_idx =1 - msr_pr; +/* First calucalte a base value independent of HV */ +if (msr_pr !=0 ) { +/* User space, ignore IR and DR */ + env->immu_idx = env->dmmu_idx =0 ; + }else { +/* Kernel, setup a base I/D value */ + env->immu_idx = msr_ir ?1 :2 ; + env->dmmu_idx = msr_dr ?1 :2 ; + } +/* Then offset it for HV */ +if (msr_hv) { + env->immu_idx +=3 ; + env->dmmu_idx +=3 ; + } } }@@ -82,9 +121,10 @@ static inline int hreg_store_msr(CPUPPCState *env, target_ulong value, }if (((value >>MSR_IR ) &1 ) != msr_ir || ((value >>MSR_DR ) &1 ) != msr_dr) { -/* Flush all tlb when changing translation mode */ -tlb_flush (cs,1 ); - excp =POWERPC_EXCP_NONE ; + cs->interrupt_request |=CPU_INTERRUPT_EXITTB ; + } +if ((env->mmu_model &POWERPC_MMU_BOOKE ) && + ((value >>MSR_GS ) &1 ) != msr_gs) { cs->interrupt_request |=CPU_INTERRUPT_EXITTB ; } if (unlikely((env->flags & POWERPC_FLAG_TGPR) &&target-ppc/machine.c +3
-1@@ -90,9 +90,11 @@ static int cpu_load_old(QEMUFile *f, void *opaque, int version_id)qemu_get_betls (f, &env->nip);qemu_get_betls (f, &env->hflags);qemu_get_betls (f, &env->hflags_nmsr); -qemu_get_sbe32s (f, &env->mmu_idx);qemu_get_sbe32 (f);/* Discard unused power_mode */ +/* Ignore saved mmu_idx, recompute */ +hreg_compute_mem_idx (env); +return 0 ; }target-ppc/translate.c +4
-3@@ -11220,8 +11220,9 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, env->nip, env->lr, env->ctr,cpu_read_xer (env), cs->cpu_index);cpu_fprintf (f,"MSR " TARGET_FMT_lx" HID0 " TARGET_FMT_lx" HF " - TARGET_FMT_lx" idx %d\n" , env->msr, env->spr[SPR_HID0 ], - env->hflags, env->mmu_idx); + TARGET_FMT_lx" iidx %d didx %d\n" , + env->msr, env->spr[SPR_HID0 ], + env->hflags, env->immu_idx, env->dmmu_idx);#if !defined(NO_TIMER_DUMP ) cpu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64 #if !defined(CONFIG_USER_ONLY)@@ -11426,7 +11427,7 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb) ctx.spr_cb = env->spr_cb; ctx.pr = msr_pr; ctx.hv = !msr_pr && msr_hv; - ctx.mem_idx = env->mmu_idx; + ctx.mem_idx = env->dmmu_idx; ctx.insns_flags = env->insns_flags; ctx.insns_flags2 = env->insns_flags2; ctx.access_type =-1 ;
Re: [Qemu-devel] [Qemu-ppc] [PATCH 02/77] ppc: Use split I/D mmu modes to avoid flushes on interrupts
Quoted 5 lines · Alexander Graf
Quoted 5 lines
We rework the way the MMU indices are calculated, providing separate indices for I and D side based on MSR:IR and MSR:DR respectively, and thus no longer need to flush the TLB on context changes. This also adds correct support for HV as a separate address space.
Quoted 7 lines
Quoted 1 line
Signed-off-by Benjamin Herrenschmidt <[email protected]>Paolo had a patch set poking at the same places a while back to speed up the ppc target by almost 10%.
Paolo, what happened to those patches? Would you prefer to rebase them on top of the HV bits or have Ben look into them while he's at it anyway? ;)
Ben decided to do it this way, which avoids a proliferation of MMU modes. The net effect of his patches is the same if not better.
Paolo
PATCH 3/77 ppc: Do some batching of TCG tlb flushes
In reply to Benjamin HerrenschmidtOn ppc64 especially, we flush the tlb on any slbie or tlbie instruction.
However, those instructions often come in bursts of 3 or more (context switch will favor a series of slbie's for example to an slbia if the SLB has less than a certain number of entries in it, and tlbie's can happen in a series, with PAPR, H_BULK_REMOVE can remove up to 4 entries at a time.
Doing a tlb_flush() each time is a waste of time. We end up doing a memset of the whole TLB, reloading it for the next instruction, memset'ing again, etc...
Those instructions don't have to take effect immediately. For slbie, they can wait for the next context synchronizing event. For tlbie, the next tlbsync.
This implements batching by keeping a flag that indicates that we have a TLB in need of flushing. We check it on interrupts, rfi's, isync's and tlbsync and flush the TLB if needed.
This reduces the number of tlb_flush() on a boot to a ubuntu installer first dialog screen from roughly 360K down to 36K.
--- hw/ppc/spapr_hcall.c | 12 +++++++++--- target-ppc/cpu.h | 2 ++ target-ppc/excp_helper.c | 9 +++++++++ target-ppc/helper.h | 1 + target-ppc/helper_regs.h | 13 +++++++++++++ target-ppc/mmu-hash64.c | 12 +++--------- target-ppc/mmu_helper.c | 9 ++++++++- target-ppc/translate.c | 39 ++++++++++++++++++++++++++++++++++++--- 8 files changed, 81 insertions(+), 16 deletions(-)
hw/ppc/spapr_hcall.c +9 -3
@@ -220,6 +220,7 @@ static target_ulong h_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr,switch (ret) {case REMOVE_SUCCESS : +check_tlb_flush (env);return H_SUCCESS ;case REMOVE_NOT_FOUND :
@@ -257,6 +258,7 @@ static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong opcode, target_ulong *args) { CPUPPCState *env = &cpu->env; +target_ulong rc =H_SUCCESS ;int i;for (i =0 ; i <H_BULK_REMOVE_MAX_BATCH ; i++) {
@@ -290,14 +292,18 @@ static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr,break ;case REMOVE_PARM : -return H_PARAMETER ; + rc =H_PARAMETER ; + goto exit;case REMOVE_HW : -return H_HARDWARE ; + rc =H_HARDWARE ; + goto exit; } } + exit: +check_tlb_flush (env); -return H_SUCCESS ; +return rc; } static target_ulong h_protect(PowerPCCPU *cpu, sPAPRMachineState *spapr,
target-ppc/cpu.h +2 -0
@@ -1013,6 +1013,8 @@ struct CPUPPCState {/* PowerPC 64 SLB area */ ppc_slb_t slb[MAX_SLB_ENTRIES ];int32_t slb_nr; +/* tcg TLB needs flush (deferred slb inval instruction typically) */ +uint32_t tlb_need_flush;#endif /* segment registers */ hwaddr htab_base;
target-ppc/excp_helper.c +9 -0
@@ -671,6 +671,11 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)/* Reset exception state */ cs->exception_index =POWERPC_EXCP_NONE ; env->error_code =0 ; + +/* Any interrupt is context synchronizing, check if TCG TLB +* needs a delayed flush on ppc64 +*/ +check_tlb_flush (env); }void ppc_cpu_do_interrupt (CPUState *cs)
@@ -692,6 +697,7 @@ static void ppc_hw_interrupt(CPUPPCState *env) __func__, env, env->pending_interrupts, cs->interrupt_request, (int)msr_me, (int)msr_ee);#endif +/* External reset */ if (env->pending_interrupts & (1 <<PPC_INTERRUPT_RESET )) { env->pending_interrupts &= ~(1 <<PPC_INTERRUPT_RESET );
@@ -896,6 +902,9 @@ static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr,* as rfi is always the last insn of a TB */ cs->interrupt_request |=CPU_INTERRUPT_EXITTB ; + +/* Context synchronizing: check if TCG TLB needs flush */ +check_tlb_flush (env); }void helper_rfi (CPUPPCState *env)
target-ppc/helper.h +1 -0
@@ -16,6 +16,7 @@ DEF_HELPER_1(rfmci, void, env) DEF_HELPER_1(rfid, void, env) DEF_HELPER_1(hrfid, void, env)#endif +DEF_HELPER_1(check_tlb_flush, void, env)#endif DEF_HELPER_3 (lmw, void, env, tl, i32)
target-ppc/helper_regs.h +13 -0
@@ -151,4 +151,17 @@ static inline int hreg_store_msr(CPUPPCState *env, target_ulong value, return excp; } +#if !defined(CONFIG_USER_ONLY ) && defined(TARGET_PPC64 ) +static inline void check_tlb_flush (CPUPPCState *env) +{ +CPUState *cs =CPU (ppc_env_get_cpu (env)); +if (env->tlb_need_flush) { + env->tlb_need_flush =0 ; +tlb_flush (cs,1 ); + } +} +#else +static inline void check_tlb_flush (CPUPPCState *env) { } +#endif +#endif /* !defined(__HELPER_REGS_H__) */
target-ppc/mmu-hash64.c +3 -9
@@ -97,10 +97,8 @@ void dump_slb(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)void helper_slbia (CPUPPCState *env) { -PowerPCCPU *cpu =ppc_env_get_cpu (env); -int n, do_invalidate; +int n; - do_invalidate =0 ;/* XXX: Warning: slbia never invalidates the first segment */ for (n =1 ; n < env->slb_nr; n++) {ppc_slb_t *slb = &env->slb[n];
@@ -111,17 +109,13 @@ void helper_slbia(CPUPPCState *env)* and we still don't have a tlb_flush_mask(env, n, mask) * in QEMU, we just invalidate all TLBs */ - do_invalidate =1 ; + env->tlb_need_flush = true; } } -if (do_invalidate) { -tlb_flush (CPU (cpu),1 ); - } }void helper_slbie (CPUPPCState *env,target_ulong addr) { -PowerPCCPU *cpu =ppc_env_get_cpu (env);ppc_slb_t *slb; slb =slb_lookup (env, addr);
@@ -136,7 +130,7 @@ void helper_slbie(CPUPPCState *env, target_ulong addr)* and we still don't have a tlb_flush_mask(env, n, mask) * in QEMU, we just invalidate all TLBs */ -tlb_flush (CPU (cpu),1 ); + env->tlb_need_flush = true; } }
target-ppc/mmu_helper.c +8 -1
@@ -23,6 +23,7 @@#include "mmu-hash64.h" #include "mmu-hash32.h" #include "exec/cpu_ldst.h" +#include "helper_regs.h" //#define DEBUG_MMU //#define DEBUG_BATS
@@ -1940,6 +1941,7 @@ void ppc_tlb_invalidate_all(CPUPPCState *env)case POWERPC_MMU_2_03 :case POWERPC_MMU_2_06 :case POWERPC_MMU_2_07 : + env->tlb_need_flush =0 ;#endif /* defined(TARGET_PPC64) */ tlb_flush (CPU (cpu),1 );break ;
@@ -2019,7 +2021,7 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)* and we still don't have a tlb_flush_mask(env, n, mask) in QEMU, * we just invalidate all TLBs */ -tlb_flush (CPU (cpu),1 ); + env->tlb_need_flush =1 ;break ;#endif /* defined(TARGET_PPC64) */ default :
@@ -2904,6 +2906,11 @@ void helper_booke206_tlbflush(CPUPPCState *env, target_ulong type) } +void helper_check_tlb_flush (CPUPPCState *env) +{ +check_tlb_flush (env); +} +/*****************************************************************************/ /* try to fill the TLB and return an exception if error. If retaddr is
target-ppc/translate.c +36 -3
@@ -3299,9 +3299,32 @@ static void gen_eieio(DisasContext *ctx) { } +#if !defined(CONFIG_USER_ONLY ) && defined(TARGET_PPC64 ) +static inline void gen_check_tlb_flush (DisasContext *ctx) +{ +TCGv_i32 t =tcg_temp_new_i32 (); +TCGLabel *l =gen_new_label (); + +tcg_gen_ld_i32 (t, cpu_env, offsetof(CPUPPCState , tlb_need_flush)); +tcg_gen_brcondi_i32 (TCG_COND_EQ , t,0 , l); +gen_helper_check_tlb_flush (cpu_env); +gen_set_label (l); +tcg_temp_free_i32 (t); +} +#else +static inline void gen_check_tlb_flush (DisasContext *ctx) { } +#endif +/* isync */ static void gen_isync (DisasContext *ctx) { +/* +* We need to check for a pending TLB flush. This can only happen in +* kernel mode however so check MSR_PR +*/ +if (!ctx->pr) { +gen_check_tlb_flush (ctx); + }gen_stop_exception (ctx); }
@@ -3458,6 +3481,15 @@ STCX(stqcx_, 16);/* sync */ static void gen_sync (DisasContext *ctx) { +uint32_t l = (ctx->opcode >>21 ) &3 ; + +/* +* For l == 2, it's a ptesync, We need to check for a pending TLB flush. +* This can only happen in kernel mode however so check MSR_PR as well. +*/ +if (l ==2 && !ctx->pr) { +gen_check_tlb_flush (ctx); + } }/* wait */
@@ -4851,10 +4883,11 @@ static void gen_tlbsync(DisasContext *ctx)gen_inval_exception (ctx,POWERPC_EXCP_PRIV_OPC ); return; } -/* This has no effect: it should ensure that all previous -* tlbie have completed +/* tlbsync is a nop for server, ptesync handles delayed tlb flush, +* embedded however needs to deal with tlbsync. We don't try to be +* fancy and swallow the overhead of checking for both. */ -gen_stop_exception (ctx); +gen_check_tlb_flush (ctx);#endif }
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 03/77] ppc: Do some batching of TCG tlb flushes
Quoted 215 lines · Benjamin Herrenschmidt
On ppc64 especially, we flush the tlb on any slbie or tlbie instruction.
However, those instructions often come in bursts of 3 or more (context switch will favor a series of slbie's for example to an slbia if the SLB has less than a certain number of entries in it, and tlbie's can happen in a series, with PAPR,
H_BULK_REMOVEcan remove up to 4 entries at a time.Doing a
tlb_flush()each time is a waste of time. We end up doing a memset of the whole TLB, reloading it for the next instruction, memset'ing again, etc...Those instructions don't have to take effect immediately. For slbie, they can wait for the next context synchronizing event. For tlbie, the next tlbsync.
This implements batching by keeping a flag that indicates that we have a TLB in need of flushing. We check it on interrupts, rfi's, isync's and tlbsync and flush the TLB if needed.
This reduces the number of
tlb_flush()on a boot to a ubuntu installer first dialog screen from roughly 360K down to 36K.Signed-off-by Benjamin Herrenschmidt <[email protected]>--- hw/ppc/spapr_hcall.c | 12 +++++++++--- target-ppc/cpu.h | 2 ++ target-ppc/excp_helper.c | 9 +++++++++ target-ppc/helper.h | 1 + target-ppc/helper_regs.h | 13 +++++++++++++ target-ppc/mmu-hash64.c | 12 +++--------- target-ppc/mmu_helper.c | 9 ++++++++- target-ppc/translate.c | 39 ++++++++++++++++++++++++++++++++++++--- 8 files changed, 81 insertions(+), 16 deletions(-)hw/ppc/spapr_hcall.c +9
-3@@ -220,6 +220,7 @@ static target_ulong h_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr,switch (ret) {case REMOVE_SUCCESS : +check_tlb_flush (env);return H_SUCCESS ;case REMOVE_NOT_FOUND :@@ -257,6 +258,7 @@ static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong opcode, target_ulong *args) { CPUPPCState *env = &cpu->env; +target_ulong rc =H_SUCCESS ;int i;for (i =0 ; i <H_BULK_REMOVE_MAX_BATCH ; i++) {@@ -290,14 +292,18 @@ static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPRMachineState *spapr,break ;case REMOVE_PARM : -return H_PARAMETER ; + rc =H_PARAMETER ; + goto exit;case REMOVE_HW : -return H_HARDWARE ; + rc =H_HARDWARE ; + goto exit; } } + exit: +check_tlb_flush (env); -return H_SUCCESS ; +return rc; } static target_ulong h_protect(PowerPCCPU *cpu, sPAPRMachineState *spapr,target-ppc/cpu.h +2
-0@@ -1013,6 +1013,8 @@ struct CPUPPCState {/* PowerPC 64 SLB area */ ppc_slb_t slb[MAX_SLB_ENTRIES ];int32_t slb_nr; +/* tcg TLB needs flush (deferred slb inval instruction typically) */ +uint32_t tlb_need_flush;#endif /* segment registers */ hwaddr htab_base;target-ppc/excp_helper.c +9
-0@@ -671,6 +671,11 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)/* Reset exception state */ cs->exception_index =POWERPC_EXCP_NONE ; env->error_code =0 ; + +/* Any interrupt is context synchronizing, check if TCG TLB +* needs a delayed flush on ppc64 +*/ +check_tlb_flush (env); }void ppc_cpu_do_interrupt (CPUState *cs)@@ -692,6 +697,7 @@ static void ppc_hw_interrupt(CPUPPCState *env) __func__, env, env->pending_interrupts, cs->interrupt_request, (int)msr_me, (int)msr_ee);#endif +/* External reset */ if (env->pending_interrupts & (1 <<PPC_INTERRUPT_RESET )) { env->pending_interrupts &= ~(1 <<PPC_INTERRUPT_RESET );@@ -896,6 +902,9 @@ static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr,* as rfi is always the last insn of a TB */ cs->interrupt_request |=CPU_INTERRUPT_EXITTB ; + +/* Context synchronizing: check if TCG TLB needs flush */ +check_tlb_flush (env); }void helper_rfi (CPUPPCState *env)target-ppc/helper.h +1
-0@@ -16,6 +16,7 @@ DEF_HELPER_1(rfmci, void, env) DEF_HELPER_1(rfid, void, env) DEF_HELPER_1(hrfid, void, env)#endif +DEF_HELPER_1(check_tlb_flush, void, env)#endif DEF_HELPER_3 (lmw, void, env, tl, i32)target-ppc/helper_regs.h +13
-0@@ -151,4 +151,17 @@ static inline int hreg_store_msr(CPUPPCState *env, target_ulong value, return excp; } +#if !defined(CONFIG_USER_ONLY ) && defined(TARGET_PPC64 ) +static inline void check_tlb_flush (CPUPPCState *env) +{ +CPUState *cs =CPU (ppc_env_get_cpu (env)); +if (env->tlb_need_flush) { + env->tlb_need_flush =0 ; +tlb_flush (cs,1 ); + } +} +#else +static inline void check_tlb_flush (CPUPPCState *env) { } +#endif +#endif /* !defined(__HELPER_REGS_H__) */ target-ppc/mmu-hash64.c +3
-9@@ -97,10 +97,8 @@ void dump_slb(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)void helper_slbia (CPUPPCState *env) { -PowerPCCPU *cpu =ppc_env_get_cpu (env); -int n, do_invalidate; +int n; - do_invalidate =0 ;/* XXX: Warning: slbia never invalidates the first segment */ for (n =1 ; n < env->slb_nr; n++) {ppc_slb_t *slb = &env->slb[n];@@ -111,17 +109,13 @@ void helper_slbia(CPUPPCState *env)* and we still don't have a tlb_flush_mask(env, n, mask) * in QEMU, we just invalidate all TLBs */ - do_invalidate =1 ; + env->tlb_need_flush = true; } } -if (do_invalidate) { -tlb_flush (CPU (cpu),1 ); - } }void helper_slbie (CPUPPCState *env,target_ulong addr) { -PowerPCCPU *cpu =ppc_env_get_cpu (env);ppc_slb_t *slb; slb =slb_lookup (env, addr);@@ -136,7 +130,7 @@ void helper_slbie(CPUPPCState *env, target_ulong addr)* and we still don't have a tlb_flush_mask(env, n, mask) * in QEMU, we just invalidate all TLBs */ -tlb_flush (CPU (cpu),1 ); + env->tlb_need_flush = true; } }target-ppc/mmu_helper.c +1
-0@@ -23,6 +23,7 @@#include "mmu-hash64.h" #include "mmu-hash32.h" #include "exec/cpu_ldst.h" +#include "helper_regs.h" //#define DEBUG_MMU //#define DEBUG_BATS
target-ppc/mmu_helper.c void ppc_tlb_invalidate_all(CPUPPCState *env) · line 1947
Quoted 7 lines
target-ppc/mmu_helper.c +1
-0@@ -1940,6 +1941,7 @@ void ppc_tlb_invalidate_all(CPUPPCState *env)case POWERPC_MMU_2_03 :case POWERPC_MMU_2_06 :case POWERPC_MMU_2_07 : + env->tlb_need_flush =0 ;#endif /* defined(TARGET_PPC64) */ tlb_flush (CPU (cpu),1 );break ;
Any particular reason you're leaving this one as an immediate rather than deferred flush?
Quoted 79 lines
target-ppc/mmu_helper.c +6
-1@@ -2019,7 +2021,7 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)* and we still don't have a tlb_flush_mask(env, n, mask) in QEMU, * we just invalidate all TLBs */ -tlb_flush (CPU (cpu),1 ); + env->tlb_need_flush =1 ;break ;#endif /* defined(TARGET_PPC64) */ default :@@ -2904,6 +2906,11 @@ void helper_booke206_tlbflush(CPUPPCState *env, target_ulong type) } +void helper_check_tlb_flush (CPUPPCState *env) +{ +check_tlb_flush (env); +} +/*****************************************************************************/ /* try to fill the TLB and return an exception if error. If retaddr is target-ppc/translate.c +32
-1@@ -3299,9 +3299,32 @@ static void gen_eieio(DisasContext *ctx) { } +#if !defined(CONFIG_USER_ONLY ) && defined(TARGET_PPC64 ) +static inline void gen_check_tlb_flush (DisasContext *ctx) +{ +TCGv_i32 t =tcg_temp_new_i32 (); +TCGLabel *l =gen_new_label (); + +tcg_gen_ld_i32 (t, cpu_env, offsetof(CPUPPCState , tlb_need_flush)); +tcg_gen_brcondi_i32 (TCG_COND_EQ , t,0 , l); +gen_helper_check_tlb_flush (cpu_env); +gen_set_label (l); +tcg_temp_free_i32 (t); +} +#else +static inline void gen_check_tlb_flush (DisasContext *ctx) { } +#endif +/* isync */ static void gen_isync (DisasContext *ctx) { +/* +* We need to check for a pending TLB flush. This can only happen in +* kernel mode however so check MSR_PR +*/ +if (!ctx->pr) { +gen_check_tlb_flush (ctx); + }gen_stop_exception (ctx); }@@ -3458,6 +3481,15 @@ STCX(stqcx_, 16);/* sync */ static void gen_sync (DisasContext *ctx) { +uint32_t l = (ctx->opcode >>21 ) &3 ; + +/* +* For l == 2, it's a ptesync, We need to check for a pending TLB flush. +* This can only happen in kernel mode however so check MSR_PR as well. +*/ +if (l ==2 && !ctx->pr) { +gen_check_tlb_flush (ctx); + } }/* wait */ @@ -4851,10 +4883,11 @@ static void gen_tlbsync(DisasContext *ctx)gen_inval_exception (ctx,POWERPC_EXCP_PRIV_OPC );return ; } -/* This has no effect: it should ensure that all previous
target-ppc/translate.c static void gen_tlbsync(DisasContext *ctx) · line 4893
Quoted 10 lines
target-ppc/translate.c +4
-2-* tlbie have completed +/* tlbsync is a nop for server, ptesync handles delayed tlb flush, +* embedded however needs to deal with tlbsync. We don't try to be +* fancy and swallow the overhead of checking for both. */ -gen_stop_exception (ctx); +gen_check_tlb_flush (ctx);#endif }
Should you be clearing the pending flush flag cpu_reset()?
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [Qemu-ppc] [PATCH 03/77] ppc: Do some batching of TCG tlb flushes
Quoted 14 lines · David Gibson
Quoted 10 lines
//#define
DEBUG_MMU
//#defineDEBUG_BATS(quoted diff) +0
-0@@ -1940,6 +1941,7 @@ void ppc_tlb_invalidate_all(CPUPPCState *env)case
POWERPC_MMU_2_03:
casePOWERPC_MMU_2_06:
casePOWERPC_MMU_2_07:
+ env->tlb_need_flush = 0;
#endif /*defined(TARGET_PPC64)*/
tlb_flush(CPU(cpu), 1);
break;Any particular reason you're leaving this one as an immediate rather than deferred flush?
A couple yes. It's mostly unused on server CPUs (we don't do tlbia), and it's used by ppc_cpu_reset(). In that latter case, I like having everything really cleaned up ...
Quoted 1 line
Should you be clearing the pending flush flag
cpu_reset()?
That should happen as a result of the above.
Cheers,
Ben.
Re: [Qemu-devel] [Qemu-ppc] [PATCH 03/77] ppc: Do some batching of TCG tlb flushes
Quoted 16 lines · Benjamin Herrenschmidt
Quoted 14 lines · David Gibson
Quoted 10 lines
//#define
DEBUG_MMU
//#defineDEBUG_BATS(quoted diff) +0
-0@@ -1940,6 +1941,7 @@ void ppc_tlb_invalidate_all(CPUPPCState *env)case
POWERPC_MMU_2_03:
casePOWERPC_MMU_2_06:
casePOWERPC_MMU_2_07:
+ env->tlb_need_flush = 0;
#endif /*defined(TARGET_PPC64)*/
tlb_flush(CPU(cpu), 1);
break;Any particular reason you're leaving this one as an immediate rather than deferred flush?
Quoted 7 lines
A couple yes. It's mostly unused on server CPUs (we don't do tlbia), and it's used by
ppc_cpu_reset(). In that latter case, I like having everything really cleaned up ...Quoted 1 line
Should you be clearing the pending flush flag
cpu_reset()?That should happen as a result of the above.
Ok.
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 4/77 target-ppc: Use sensible POWER8/POWER8E versions
In reply to Benjamin HerrenschmidtWe never released anything older than POWER8 DD2.0 and POWER8E DD2.1, so let's use these versions, without that some firmware or Linux code might fail to use some HW features that were non functional in earlier internal only spins of the chip.
--- target-ppc/cpu-models.c | 12 ++++++------ target-ppc/cpu-models.h | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-)
target-ppc/cpu-models.c +6 -6
@@ -1138,10 +1138,10 @@ "POWER7 v2.3") POWERPC_DEF("POWER7+_v2.1", CPU_POWERPC_POWER7P_v21, POWER7, "POWER7+ v2.1") - POWERPC_DEF("POWER8E_v1.0", CPU_POWERPC_POWER8E_v10, POWER8, - "POWER8E v1.0") - POWERPC_DEF("POWER8_v1.0", CPU_POWERPC_POWER8_v10, POWER8, - "POWER8 v1.0") + POWERPC_DEF("POWER8E_v2.1", CPU_POWERPC_POWER8E_v21, POWER8, + "POWER8E v2.1") + POWERPC_DEF("POWER8_v2.0", CPU_POWERPC_POWER8_v20, POWER8, + "POWER8 v2.0") POWERPC_DEF("970_v2.2", CPU_POWERPC_970_v22, 970, "PowerPC 970 v2.2") POWERPC_DEF("970fx_v1.0", CPU_POWERPC_970FX_v10, 970,
@@ -1389,8 +1389,8 @@ PowerPCCPUAlias ppc_cpu_aliases[] = { { "POWER5gs", "POWER5+_v2.1" }, { "POWER7", "POWER7_v2.3" }, { "POWER7+", "POWER7+_v2.1" }, - { "POWER8E", "POWER8E_v1.0" }, - { "POWER8", "POWER8_v1.0" }, + { "POWER8E", "POWER8E_v2.1" }, + { "POWER8", "POWER8_v2.0" }, { "970", "970_v2.2" }, { "970fx", "970fx_v3.1" }, { "970mp", "970mp_v1.1" },
target-ppc/cpu-models.h +2 -2
@@ -557,9 +557,9 @@ enum {CPU_POWERPC_POWER7P_BASE =0x004A0000 , CPU_POWERPC_POWER7P_v21 =0x004A0201 ,CPU_POWERPC_POWER8E_BASE =0x004B0000 , - CPU_POWERPC_POWER8E_v10 =0x004B0100 , + CPU_POWERPC_POWER8E_v21 =0x004B0201 ,CPU_POWERPC_POWER8_BASE =0x004D0000 , - CPU_POWERPC_POWER8_v10 =0x004D0100 , + CPU_POWERPC_POWER8_v20 =0x004D0200 , CPU_POWERPC_970_v22 =0x00390202 , CPU_POWERPC_970FX_v10 =0x00391100 , CPU_POWERPC_970FX_v20 = 0x003C0200,
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 04/77] target-ppc: Use sensible POWER8/POWER8E versions
Quoted 4 lines · Benjamin Herrenschmidt
We never released anything older than POWER8 DD2.0 and POWER8E DD2.1, so let's use these versions, without that some firmware or Linux code might fail to use some HW features that were non functional in earlier internal only spins of the chip.
We were getting it wrong with mambo a while ago and it caused some oddness. There's zero reason for anyone to use pre-production processors these days, so:
Re: [Qemu-devel] [Qemu-ppc] [PATCH 04/77] target-ppc: Use sensible POWER8/POWER8E versions
In reply to Benjamin HerrenschmidtQuoted 6 lines · Benjamin Herrenschmidt
We never released anything older than POWER8 DD2.0 and POWER8E DD2.1, so let's use these versions, without that some firmware or Linux code might fail to use some HW features that were non functional in earlier internal only spins of the chip.
Signed-off-by Benjamin Herrenschmidt <[email protected]>
Hmm, I'm just wondering if replacing the old CPU models could have implications for migration from old images.
Quoted 51 lines
--- target-ppc/cpu-models.c | 12 ++++++------ target-ppc/cpu-models.h | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-)target-ppc/cpu-models.c +6
-6@@ -1138,10 +1138,10 @@ "POWER7 v2.3") POWERPC_DEF("POWER7+_v2.1", CPU_POWERPC_POWER7P_v21, POWER7, "POWER7+ v2.1") - POWERPC_DEF("POWER8E_v1.0", CPU_POWERPC_POWER8E_v10, POWER8, - "POWER8E v1.0") - POWERPC_DEF("POWER8_v1.0", CPU_POWERPC_POWER8_v10, POWER8, - "POWER8 v1.0") + POWERPC_DEF("POWER8E_v2.1", CPU_POWERPC_POWER8E_v21, POWER8, + "POWER8E v2.1") + POWERPC_DEF("POWER8_v2.0", CPU_POWERPC_POWER8_v20, POWER8, + "POWER8 v2.0") POWERPC_DEF("970_v2.2", CPU_POWERPC_970_v22, 970, "PowerPC 970 v2.2") POWERPC_DEF("970fx_v1.0", CPU_POWERPC_970FX_v10, 970,@@ -1389,8 +1389,8 @@ PowerPCCPUAlias ppc_cpu_aliases[] = { { "POWER5gs", "POWER5+_v2.1" }, { "POWER7", "POWER7_v2.3" }, { "POWER7+", "POWER7+_v2.1" }, - { "POWER8E", "POWER8E_v1.0" }, - { "POWER8", "POWER8_v1.0" }, + { "POWER8E", "POWER8E_v2.1" }, + { "POWER8", "POWER8_v2.0" }, { "970", "970_v2.2" }, { "970fx", "970fx_v3.1" }, { "970mp", "970mp_v1.1" },target-ppc/cpu-models.h +2
-2@@ -557,9 +557,9 @@ enum {CPU_POWERPC_POWER7P_BASE =0x004A0000 , CPU_POWERPC_POWER7P_v21 =0x004A0201 ,CPU_POWERPC_POWER8E_BASE =0x004B0000 , - CPU_POWERPC_POWER8E_v10 =0x004B0100 , + CPU_POWERPC_POWER8E_v21 =0x004B0201 ,CPU_POWERPC_POWER8_BASE =0x004D0000 , - CPU_POWERPC_POWER8_v10 =0x004D0100 , + CPU_POWERPC_POWER8_v20 =0x004D0200 , CPU_POWERPC_970_v22 =0x00390202 , CPU_POWERPC_970FX_v10 =0x00391100 , CPU_POWERPC_970FX_v20 = 0x003C0200,
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [Qemu-ppc] [PATCH 04/77] target-ppc: Use sensible POWER8/POWER8E versions
Quoted 10 lines · David Gibson
Quoted 6 lines · Benjamin Herrenschmidt
We never released anything older than POWER8 DD2.0 and POWER8E DD2.1, so let's use these versions, without that some firmware or Linux code might fail to use some HW features that were non functional in earlier internal only spins of the chip.
Signed-off-by Benjamin Herrenschmidt <[email protected]>Hmm, I'm just wondering if replacing the old CPU models could have implications for migration from old images.
I don't know, I'm not that familiar with migration. Alexey, what do you reckon ? I'd think KVM images use the real PVR so should be a non- issue, does anybody actually cares about migration of old TCG images ?
Quoted 52 lines
Quoted 51 lines
---
target-ppc/cpu-models.c | 12 ++++++------
target-ppc/cpu-models.h | 4 ++--2 files changed, 8 insertions(+), 8 deletions(-)target-ppc/cpu-models.c +6
-6@@ -1138,10 +1138,10 @@ "POWER7 v2.3") POWERPC_DEF("POWER7+_v2.1", CPU_POWERPC_POWER7P_v21, POWER7, "POWER7+ v2.1") - POWERPC_DEF("POWER8E_v1.0", CPU_POWERPC_POWER8E_v10, POWER8, - "POWER8E v1.0") - POWERPC_DEF("POWER8_v1.0", CPU_POWERPC_POWER8_v10, POWER8, - "POWER8 v1.0") + POWERPC_DEF("POWER8E_v2.1", CPU_POWERPC_POWER8E_v21, POWER8, + "POWER8E v2.1") + POWERPC_DEF("POWER8_v2.0", CPU_POWERPC_POWER8_v20, POWER8, + "POWER8 v2.0") POWERPC_DEF("970_v2.2", CPU_POWERPC_970_v22, 970, "PowerPC 970 v2.2") POWERPC_DEF("970fx_v1.0", CPU_POWERPC_970FX_v10, 970,@@ -1389,8 +1389,8 @@ PowerPCCPUAlias ppc_cpu_aliases[] = { { "POWER5gs", "POWER5+_v2.1" }, { "POWER7", "POWER7_v2.3" }, { "POWER7+", "POWER7+_v2.1" }, - { "POWER8E", "POWER8E_v1.0" }, - { "POWER8", "POWER8_v1.0" }, + { "POWER8E", "POWER8E_v2.1" }, + { "POWER8", "POWER8_v2.0" }, { "970", "970_v2.2" }, { "970fx", "970fx_v3.1" }, { "970mp", "970mp_v1.1" },target-ppc/cpu-models.h +2
-2@@ -557,9 +557,9 @@ enum { CPU_POWERPC_POWER7P_BASE = 0x004A0000, CPU_POWERPC_POWER7P_v21 = 0x004A0201, CPU_POWERPC_POWER8E_BASE = 0x004B0000, - CPU_POWERPC_POWER8E_v10 = 0x004B0100, + CPU_POWERPC_POWER8E_v21 = 0x004B0201, CPU_POWERPC_POWER8_BASE = 0x004D0000, - CPU_POWERPC_POWER8_v10 = 0x004D0100, + CPU_POWERPC_POWER8_v20 = 0x004D0200, CPU_POWERPC_970_v22 = 0x00390202, CPU_POWERPC_970FX_v10 = 0x00391100, CPU_POWERPC_970FX_v20 = 0x003C0200,
Re: [Qemu-devel] [Qemu-ppc] [PATCH 04/77] target-ppc: Use sensible POWER8/POWER8E versions
Quoted 7 lines · Benjamin Herrenschmidt
Quoted 6 lines · David Gibson
Quoted 5 lines · Benjamin Herrenschmidt
We never released anything older than POWER8 DD2.0 and POWER8E DD2.1, so let's use these versions, without that some firmware or Linux code might fail to use some HW features that were non functional in earlier internal only spins of the chip.
Quoted 8 lines
Quoted 4 lines
Quoted 1 line
Signed-off-by Benjamin Herrenschmidt <[email protected]>Hmm, I'm just wondering if replacing the old CPU models could have implications for migration from old images.
I don't know, I'm not that familiar with migration. Alexey, what do you reckon ? I'd think KVM images use the real PVR so should be a non- issue, does anybody actually cares about migration of old TCG images ?
I have never heard of anyone testing migration of TCG guests. KVM guests use host PVR anyway.
I just wonder that we "never released anything older than" but we still support them in the kernel - why do not we wipe these there too?
Quoted 53 lines
Quoted 53 lines
Quoted 52 lines
--- target-ppc/cpu-models.c | 12 ++++++------ target-ppc/cpu-models.h | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-)target-ppc/cpu-models.c +6
-6@@ -1138,10 +1138,10 @@ "POWER7 v2.3") POWERPC_DEF("POWER7+_v2.1", CPU_POWERPC_POWER7P_v21, POWER7, "POWER7+ v2.1") - POWERPC_DEF("POWER8E_v1.0", CPU_POWERPC_POWER8E_v10, POWER8, - "POWER8E v1.0") - POWERPC_DEF("POWER8_v1.0", CPU_POWERPC_POWER8_v10, POWER8, - "POWER8 v1.0") + POWERPC_DEF("POWER8E_v2.1", CPU_POWERPC_POWER8E_v21, POWER8, + "POWER8E v2.1") + POWERPC_DEF("POWER8_v2.0", CPU_POWERPC_POWER8_v20, POWER8, + "POWER8 v2.0") POWERPC_DEF("970_v2.2", CPU_POWERPC_970_v22, 970, "PowerPC 970 v2.2") POWERPC_DEF("970fx_v1.0", CPU_POWERPC_970FX_v10, 970,@@ -1389,8 +1389,8 @@ PowerPCCPUAlias ppc_cpu_aliases[] = { { "POWER5gs", "POWER5+_v2.1" }, { "POWER7", "POWER7_v2.3" }, { "POWER7+", "POWER7+_v2.1" }, - { "POWER8E", "POWER8E_v1.0" }, - { "POWER8", "POWER8_v1.0" }, + { "POWER8E", "POWER8E_v2.1" }, + { "POWER8", "POWER8_v2.0" }, { "970", "970_v2.2" }, { "970fx", "970fx_v3.1" }, { "970mp", "970mp_v1.1" },target-ppc/cpu-models.h +2
-2@@ -557,9 +557,9 @@ enum {CPU_POWERPC_POWER7P_BASE =0x004A0000 , CPU_POWERPC_POWER7P_v21 =0x004A0201 ,CPU_POWERPC_POWER8E_BASE =0x004B0000 , - CPU_POWERPC_POWER8E_v10 =0x004B0100 , + CPU_POWERPC_POWER8E_v21 =0x004B0201 ,CPU_POWERPC_POWER8_BASE =0x004D0000 , - CPU_POWERPC_POWER8_v10 =0x004D0100 , + CPU_POWERPC_POWER8_v20 =0x004D0200 , CPU_POWERPC_970_v22 =0x00390202 , CPU_POWERPC_970FX_v10 =0x00391100 , CPU_POWERPC_970FX_v20 = 0x003C0200,
Signature · 1 line
Alexey
Re: [Qemu-devel] [Qemu-ppc] [PATCH 04/77] target-ppc: Use sensible POWER8/POWER8E versions
Quoted 6 lines · Alexey Kardashevskiy
I have never heard of anyone testing migration of TCG guests. KVM guests use host PVR anyway.
I just wonder that we "never released anything older than" but we still support them in the kernel - why do not we wipe these there too?
We could... it was handy in the early days when some selected partners had access to pre-release systems, to tell them to use upstream kernels :)
In the case of qemu, however, it's more harmful than anything else.
Cheers,
Ben.
PATCH 5/77 ppc: Update SPR definitions
In reply to Benjamin HerrenschmidtAdd definitions for additional SPR numbers and SPR bit definitions that will be relevant for subsequent improvements to POWER8 emulation
Also fix the definition of LPIDR which was incorrect (and is different for server and embedded).
--- target-ppc/cpu.h | 54 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 7 deletions(-)
target-ppc/cpu.h +47 -7
@@ -470,9 +470,17 @@ struct ppc_slb_t {#define MSR_RI 1/* Recoverable interrupt 1 */ #define MSR_LE 0/* Little-endian mode 1 hflags */ -#define LPCR_ILE (1 << (63-38)) -#define LPCR_AIL_SHIFT (63-40)/* Alternate interrupt location */ -#define LPCR_AIL (3 << LPCR_AIL_SHIFT) +/* LPCR bits */ +#define LPCR_VPM0 (1ull << (63-0)) +#define LPCR_VPM1 (1ull << (63-1)) +#define LPCR_ISL (1ull << (63-2)) +#define LPCR_KBV (1ull << (63-3)) +#define LPCR_ILE (1ull << (63-38)) +#define LPCR_MER (1ull << (63-52)) +#define LPCR_LPES0 (1ull << (63-60)) +#define LPCR_LPES1 (1ull << (63-61)) +#define LPCR_AIL_SHIFT (63-40)/* Alternate interrupt location */ +#define LPCR_AIL (3ull << LPCR_AIL_SHIFT)#define msr_sf ((env->msr >> MSR_SF) & 1)#define msr_isf ((env->msr >> MSR_ISF) & 1)
@@ -1338,6 +1346,10 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)#define SPR_UAMOR (0x09D)#define SPR_MPC_ICTRL (0x09E)#define SPR_MPC_BAR (0x09F) +#define SPR_DAWR (0x0B4) +#define SPR_RPR (0x0BA) +#define SPR_DAWRX (0x0BC) +#define SPR_HFSCR (0x0BE)#define SPR_VRSAVE (0x100)#define SPR_USPRG0 (0x100)#define SPR_USPRG1 (0x101)
@@ -1392,19 +1404,25 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)#define SPR_HSRR1 (0x13B)#define SPR_BOOKE_IAC4 (0x13B)#define SPR_BOOKE_DAC1 (0x13C) -#define SPR_LPIDR (0x13D) +#define SPR_MMCRH (0x13C)#define SPR_DABR2 (0x13D)#define SPR_BOOKE_DAC2 (0x13D) +#define SPR_TFMR (0x13D)#define SPR_BOOKE_DVC1 (0x13E)#define SPR_LPCR (0x13E)#define SPR_BOOKE_DVC2 (0x13F) +#define SPR_LPIDR (0x13F)#define SPR_BOOKE_TSR (0x150) +#define SPR_HMER (0x150) +#define SPR_HMEER (0x151)#define SPR_PCR (0x152) +#define SPR_BOOKE_LPIDR (0x152)#define SPR_BOOKE_TCR (0x154)#define SPR_BOOKE_TLB0PS (0x158)#define SPR_BOOKE_TLB1PS (0x159)#define SPR_BOOKE_TLB2PS (0x15A)#define SPR_BOOKE_TLB3PS (0x15B) +#define SPR_AMOR (0x15D)#define SPR_BOOKE_MAS7_MAS3 (0x174)#define SPR_BOOKE_IVOR0 (0x190)#define SPR_BOOKE_IVOR1 (0x191)
@@ -1622,6 +1640,7 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)#define SPR_RCPU_L2U_RA3 (0x32B)#define SPR_TAR (0x32F)#define SPR_VTB (0x351) +#define SPR_MMCRC (0x353)#define SPR_440_INV0 (0x370)#define SPR_440_INV1 (0x371)#define SPR_440_INV2 (0x372)
@@ -1655,6 +1674,7 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)#define SPR_440_DVLIM (0x398)#define SPR_750_WPAR (0x399)#define SPR_440_IVLIM (0x399) +#define SPR_TSCR (0x399)#define SPR_750_DMAU (0x39A)#define SPR_750_DMAL (0x39B)#define SPR_440_RSTCFG (0x39B)
@@ -1829,9 +1849,10 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)#define L1CSR1_ICE 0x00000001/* Instruction Cache Enable */ /* HID0 bits */ -#define HID0_DEEPNAP (1 << 24) -#define HID0_DOZE (1 << 23) -#define HID0_NAP (1 << 22) +#define HID0_DEEPNAP (1 << 24)/* pre-2.06 */ +#define HID0_DOZE (1 << 23)/* pre-2.06 */ +#define HID0_NAP (1 << 22)/* pre-2.06 */ +#define HID0_HILE (1ull << (63-19))/* POWER8 */ /*****************************************************************************/ /* PowerPC Instructions types definitions */
@@ -2180,6 +2201,25 @@ enum { PCR_TM_DIS = 1ull << (63-2), /* Trans. memory disable (POWER8) */ }; +/* HMER/HMEER */ +enum { +HMER_MALFUNCTION_ALERT =1ull << (63 -0 ), +HMER_PROC_RECV_DONE =1ull << (63 -2 ), +HMER_PROC_RECV_ERROR_MASKED =1ull << (63 -3 ), +HMER_TFAC_ERROR =1ull << (63 -4 ), +HMER_TFMR_PARITY_ERROR =1ull << (63 -5 ), +HMER_XSCOM_FAIL =1ull << (63 -8 ), +HMER_XSCOM_DONE =1ull << (63 -9 ), +HMER_PROC_RECV_AGAIN =1ull << (63 -11 ), +HMER_WARN_RISE =1ull << (63 -14 ), +HMER_WARN_FALL =1ull << (63 -15 ), +HMER_SCOM_FIR_HMI =1ull << (63 -16 ), +HMER_TRIG_FIR_HMI =1ull << (63 -17 ), +HMER_HYP_RESOURCE_ERR =1ull << (63 -20 ), +HMER_XSCOM_STATUS_MASK =7ull << (63 -23 ), +HMER_XSCOM_STATUS_LSH = (63 -23 ), +}; +/*****************************************************************************/ static inline target_ulong cpu_read_xer (CPUPPCState *env)
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 05/77] ppc: Update SPR definitions
Quoted 105 lines · Benjamin Herrenschmidt
Add definitions for additional SPR numbers and SPR bit definitions that will be relevant for subsequent improvements to POWER8 emulation
Also fix the definition of LPIDR which was incorrect (and is different for server and embedded).
Signed-off-by Benjamin Herrenschmidt <[email protected]>--- target-ppc/cpu.h | 54 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 7 deletions(-)target-ppc/cpu.h +28
-7@@ -470,9 +470,17 @@ struct ppc_slb_t {#define MSR_RI 1/* Recoverable interrupt 1 */ #define MSR_LE 0/* Little-endian mode 1 hflags */ -#define LPCR_ILE (1 << (63-38)) -#define LPCR_AIL_SHIFT (63-40)/* Alternate interrupt location */ -#define LPCR_AIL (3 << LPCR_AIL_SHIFT) +/* LPCR bits */ +#define LPCR_VPM0 (1ull << (63-0)) +#define LPCR_VPM1 (1ull << (63-1)) +#define LPCR_ISL (1ull << (63-2)) +#define LPCR_KBV (1ull << (63-3)) +#define LPCR_ILE (1ull << (63-38)) +#define LPCR_MER (1ull << (63-52)) +#define LPCR_LPES0 (1ull << (63-60)) +#define LPCR_LPES1 (1ull << (63-61)) +#define LPCR_AIL_SHIFT (63-40)/* Alternate interrupt location */ +#define LPCR_AIL (3ull << LPCR_AIL_SHIFT)#define msr_sf ((env->msr >> MSR_SF) & 1)#define msr_isf ((env->msr >> MSR_ISF) & 1)@@ -1338,6 +1346,10 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)#define SPR_UAMOR (0x09D)#define SPR_MPC_ICTRL (0x09E)#define SPR_MPC_BAR (0x09F) +#define SPR_DAWR (0x0B4) +#define SPR_RPR (0x0BA) +#define SPR_DAWRX (0x0BC) +#define SPR_HFSCR (0x0BE)#define SPR_VRSAVE (0x100)#define SPR_USPRG0 (0x100)#define SPR_USPRG1 (0x101)@@ -1392,19 +1404,25 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)#define SPR_HSRR1 (0x13B)#define SPR_BOOKE_IAC4 (0x13B)#define SPR_BOOKE_DAC1 (0x13C) -#define SPR_LPIDR (0x13D) +#define SPR_MMCRH (0x13C)#define SPR_DABR2 (0x13D)#define SPR_BOOKE_DAC2 (0x13D) +#define SPR_TFMR (0x13D)#define SPR_BOOKE_DVC1 (0x13E)#define SPR_LPCR (0x13E)#define SPR_BOOKE_DVC2 (0x13F) +#define SPR_LPIDR (0x13F)#define SPR_BOOKE_TSR (0x150) +#define SPR_HMER (0x150) +#define SPR_HMEER (0x151)#define SPR_PCR (0x152) +#define SPR_BOOKE_LPIDR (0x152)#define SPR_BOOKE_TCR (0x154)#define SPR_BOOKE_TLB0PS (0x158)#define SPR_BOOKE_TLB1PS (0x159)#define SPR_BOOKE_TLB2PS (0x15A)#define SPR_BOOKE_TLB3PS (0x15B) +#define SPR_AMOR (0x15D)#define SPR_BOOKE_MAS7_MAS3 (0x174)#define SPR_BOOKE_IVOR0 (0x190)#define SPR_BOOKE_IVOR1 (0x191)@@ -1622,6 +1640,7 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)#define SPR_RCPU_L2U_RA3 (0x32B)#define SPR_TAR (0x32F)#define SPR_VTB (0x351) +#define SPR_MMCRC (0x353)#define SPR_440_INV0 (0x370)#define SPR_440_INV1 (0x371)#define SPR_440_INV2 (0x372)@@ -1655,6 +1674,7 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)#define SPR_440_DVLIM (0x398)#define SPR_750_WPAR (0x399)#define SPR_440_IVLIM (0x399) +#define SPR_TSCR (0x399)#define SPR_750_DMAU (0x39A)#define SPR_750_DMAL (0x39B)#define SPR_440_RSTCFG (0x39B)@@ -1829,9 +1849,10 @@ static inline int cpu_mmu_index (CPUPPCState *env, bool ifetch)#define L1CSR1_ICE 0x00000001/* Instruction Cache Enable */ /* HID0 bits */ -#define HID0_DEEPNAP (1 << 24) -#define HID0_DOZE (1 << 23) -#define HID0_NAP (1 << 22) +#define HID0_DEEPNAP (1 << 24)/* pre-2.06 */ +#define HID0_DOZE (1 << 23)/* pre-2.06 */ +#define HID0_NAP (1 << 22)/* pre-2.06 */ +#define HID0_HILE (1ull << (63-19))/* POWER8 */ /*****************************************************************************/ /* PowerPC Instructions types definitions */
target-ppc/cpu.h enum { · line 2205
Quoted 5 lines
target-ppc/cpu.h +2
-0@@ -2180,6 +2201,25 @@ enum { PCR_TM_DIS = 1ull << (63-2), /* Trans. memory disable (POWER8) */ }; +/* HMER/HMEER */ +enum {
Any particular reason for using an enum rather than defines like the rest?
Quoted 5 lines
target-ppc/cpu.h +5
-0+HMER_MALFUNCTION_ALERT =1ull << (63 -0 ), +HMER_PROC_RECV_DONE =1ull << (63 -2 ), +HMER_PROC_RECV_ERROR_MASKED =1ull << (63 -3 ), +HMER_TFAC_ERROR =1ull << (63 -4 ), + HMER_TFMR_PARITY_ERROR = 1ull << (63-5),
target-ppc/cpu.h enum { · line 2220
Quoted 10 lines
target-ppc/cpu.h +10
-0+HMER_XSCOM_FAIL =1ull << (63 -8 ), +HMER_XSCOM_DONE =1ull << (63 -9 ), +HMER_PROC_RECV_AGAIN =1ull << (63 -11 ), +HMER_WARN_RISE =1ull << (63 -14 ), +HMER_WARN_FALL =1ull << (63 -15 ), +HMER_SCOM_FIR_HMI =1ull << (63 -16 ), +HMER_TRIG_FIR_HMI =1ull << (63 -17 ), +HMER_HYP_RESOURCE_ERR =1ull << (63 -20 ), +HMER_XSCOM_STATUS_MASK =7ull << (63 -23 ), + HMER_XSCOM_STATUS_LSH = (63-23),
Is that last one correct?
Quoted 5 lines
target-ppc/cpu.h +2
-0+}; +/*****************************************************************************/ static inline target_ulong cpu_read_xer (CPUPPCState *env)
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 6/77 ppc: Add macros to register hypervisor mode SPRs
In reply to Benjamin HerrenschmidtThe current set of spr_register_* macros only take the user and supervisor function pointers. To make the transition easy, we don't change that but we add "_hv" variants that can be used to register all 3 sets.
To simplify the transition, users of the "old" macro will set the hypervisor callback to be the same as the supervisor one. The new registration function only needs to be used for registers that are either hypervisor only or behave differently in HV mode.
--- target-ppc/translate.c | 26 ++++++++++++++++---------- target-ppc/translate_init.c | 35 +++++++++++++++++++++++++++++++---- 2 files changed, 47 insertions(+), 14 deletions(-)
target-ppc/translate.c +16 -10
@@ -4299,14 +4299,17 @@ static inline void gen_op_mfspr(DisasContext *ctx)void (*read_cb)(DisasContext *ctx,int gprn,int sprn);uint32_t sprn =SPR (ctx->opcode); -#if !defined(CONFIG_USER_ONLY ) -if (ctx->hv) +#if defined(CONFIG_USER_ONLY ) + read_cb = ctx->spr_cb[sprn].uea_read; +#else +if (ctx->pr) { + read_cb = ctx->spr_cb[sprn].uea_read; + }else if (ctx->hv) { read_cb = ctx->spr_cb[sprn].hea_read; -else if (!ctx->pr) + }else if (!ctx->pr) { read_cb = ctx->spr_cb[sprn].oea_read; - else + }#endif - read_cb = ctx->spr_cb[sprn].uea_read;if (likely (read_cb !=NULL )) {if (likely (read_cb !=SPR_NOACCESS )) { (*read_cb)(ctx,rD (ctx->opcode), sprn);
@@ -4450,14 +4453,17 @@ static void gen_mtspr(DisasContext *ctx)void (*write_cb)(DisasContext *ctx,int sprn,int gprn);uint32_t sprn =SPR (ctx->opcode); -#if !defined(CONFIG_USER_ONLY ) -if (ctx->hv) +#if defined(CONFIG_USER_ONLY ) + write_cb = ctx->spr_cb[sprn].uea_write; +#else +if (ctx->pr) { + write_cb = ctx->spr_cb[sprn].uea_write; + }else if (ctx->hv) { write_cb = ctx->spr_cb[sprn].hea_write; -else if (!ctx->pr) + }else { write_cb = ctx->spr_cb[sprn].oea_write; - else + }#endif - write_cb = ctx->spr_cb[sprn].uea_write;if (likely (write_cb !=NULL )) {if (likely (write_cb !=SPR_NOACCESS )) { (*write_cb)(ctx, sprn,rS (ctx->opcode));
target-ppc/translate_init.c +31 -4
@@ -578,17 +578,33 @@ static inline void vscr_init (CPUPPCState *env, uint32_t val)#define spr_register_kvm (env, num, name, uea_read, uea_write, \ oea_read, oea_write, one_reg_id, initial_value) \ _spr_register(env, num, name, uea_read, uea_write, initial_value) +#define spr_register_kvm_hv (env, num, name, uea_read, uea_write, \ + oea_read, oea_write, hea_read, hea_write, \ + one_reg_id, initial_value) \ + _spr_register(env, num, name, uea_read, uea_write, initial_value)#else #if !defined(CONFIG_KVM )#define spr_register_kvm (env, num, name, uea_read, uea_write, \ - oea_read, oea_write, one_reg_id, initial_value) \ + oea_read, oea_write, one_reg_id, initial_value) \ + _spr_register(env, num, name, uea_read, uea_write, \ + oea_read, oea_write, oea_read, oea_write, initial_value) +#define spr_register_kvm_hv (env, num, name, uea_read, uea_write, \ + oea_read, oea_write, hea_read, hea_write, \ + one_reg_id, initial_value) \ _spr_register(env, num, name, uea_read, uea_write, \ - oea_read, oea_write, initial_value) + oea_read, oea_write, hea_read, hea_write, initial_value)#else #define spr_register_kvm (env, num, name, uea_read, uea_write, \ - oea_read, oea_write, one_reg_id, initial_value) \ + oea_read, oea_write, one_reg_id, initial_value) \ + _spr_register(env, num, name, uea_read, uea_write, \ + oea_read, oea_write, oea_read, oea_write, \ + one_reg_id, initial_value) +#define spr_register_kvm_hv (env, num, name, uea_read, uea_write, \ + oea_read, oea_write, hea_read, hea_write, \ + one_reg_id, initial_value) \ _spr_register(env, num, name, uea_read, uea_write, \ - oea_read, oea_write, one_reg_id, initial_value) + oea_read, oea_write, hea_read, hea_write, \ + one_reg_id, initial_value)#endif #endif
@@ -597,6 +613,13 @@ static inline void vscr_init (CPUPPCState *env, uint32_t val)spr_register_kvm (env, num, name, uea_read, uea_write, \ oea_read, oea_write, 0, initial_value) +#define spr_register_hv (env, num, name, uea_read, uea_write, \ + oea_read, oea_write, hea_read, hea_write, \ + initial_value) \ + spr_register_kvm_hv(env, num, name, uea_read, uea_write, \ + oea_read, oea_write, hea_read, hea_write, \ + 0, initial_value) + static inline void _spr_register(CPUPPCState *env, int num, const char *name, void (*uea_read)(DisasContext *ctx, int gprn, int sprn),
@@ -605,6 +628,8 @@ static inline void _spr_register(CPUPPCState *env, int num,void (*oea_read)(DisasContext *ctx,int gprn,int sprn), void (*oea_write)(DisasContext *ctx, int sprn, int gprn), + void (*hea_read)(DisasContext *opaque, int gprn, int sprn), + void (*hea_write)(DisasContext *opaque, int sprn, int gprn), #endif #if defined(CONFIG_KVM) uint64_t one_reg_id,
@@ -632,6 +657,8 @@ static inline void _spr_register(CPUPPCState *env, int num,#if !defined(CONFIG_USER_ONLY ) spr->oea_read = oea_read; spr->oea_write = oea_write; + spr->hea_read = hea_read; + spr->hea_write = hea_write;#endif #if defined(CONFIG_KVM ) spr->one_reg_id = one_reg_id,
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 06/77] ppc: Add macros to register hypervisor mode SPRs
Quoted 11 lines · Benjamin Herrenschmidt
The current set of spr_register_* macros only take the user and supervisor function pointers. To make the transition easy, we don't change that but we add "
_hv" variants that can be used to register all 3 sets.To simplify the transition, users of the "old" macro will set the hypervisor callback to be the same as the supervisor one. The new registration function only needs to be used for registers that are either hypervisor only or behave differently in HV mode.
Signed-off-by Benjamin Herrenschmidt <[email protected]>
Quoted 129 lines
--- target-ppc/translate.c | 26 ++++++++++++++++---------- target-ppc/translate_init.c | 35 +++++++++++++++++++++++++++++++---- 2 files changed, 47 insertions(+), 14 deletions(-)target-ppc/translate.c +16
-10@@ -4299,14 +4299,17 @@ static inline void gen_op_mfspr(DisasContext *ctx)void (*read_cb)(DisasContext *ctx,int gprn,int sprn);uint32_t sprn =SPR (ctx->opcode); -#if !defined(CONFIG_USER_ONLY ) -if (ctx->hv) +#if defined(CONFIG_USER_ONLY ) + read_cb = ctx->spr_cb[sprn].uea_read; +#else +if (ctx->pr) { + read_cb = ctx->spr_cb[sprn].uea_read; + }else if (ctx->hv) { read_cb = ctx->spr_cb[sprn].hea_read; -else if (!ctx->pr) + }else if (!ctx->pr) { read_cb = ctx->spr_cb[sprn].oea_read; - else + }#endif - read_cb = ctx->spr_cb[sprn].uea_read;if (likely (read_cb !=NULL )) {if (likely (read_cb !=SPR_NOACCESS )) { (*read_cb)(ctx,rD (ctx->opcode), sprn);@@ -4450,14 +4453,17 @@ static void gen_mtspr(DisasContext *ctx)void (*write_cb)(DisasContext *ctx,int sprn,int gprn);uint32_t sprn =SPR (ctx->opcode); -#if !defined(CONFIG_USER_ONLY ) -if (ctx->hv) +#if defined(CONFIG_USER_ONLY ) + write_cb = ctx->spr_cb[sprn].uea_write; +#else +if (ctx->pr) { + write_cb = ctx->spr_cb[sprn].uea_write; + }else if (ctx->hv) { write_cb = ctx->spr_cb[sprn].hea_write; -else if (!ctx->pr) + }else { write_cb = ctx->spr_cb[sprn].oea_write; - else + }#endif - write_cb = ctx->spr_cb[sprn].uea_write;if (likely (write_cb !=NULL )) {if (likely (write_cb !=SPR_NOACCESS )) { (*write_cb)(ctx, sprn,rS (ctx->opcode));target-ppc/translate_init.c +31
-4@@ -578,17 +578,33 @@ static inline void vscr_init (CPUPPCState *env, uint32_t val)#define spr_register_kvm (env, num, name, uea_read, uea_write, \ oea_read, oea_write, one_reg_id, initial_value) \ _spr_register(env, num, name, uea_read, uea_write, initial_value) +#define spr_register_kvm_hv (env, num, name, uea_read, uea_write, \ + oea_read, oea_write, hea_read, hea_write, \ + one_reg_id, initial_value) \ + _spr_register(env, num, name, uea_read, uea_write, initial_value)#else #if !defined(CONFIG_KVM )#define spr_register_kvm (env, num, name, uea_read, uea_write, \ - oea_read, oea_write, one_reg_id, initial_value) \ + oea_read, oea_write, one_reg_id, initial_value) \ + _spr_register(env, num, name, uea_read, uea_write, \ + oea_read, oea_write, oea_read, oea_write, initial_value) +#define spr_register_kvm_hv (env, num, name, uea_read, uea_write, \ + oea_read, oea_write, hea_read, hea_write, \ + one_reg_id, initial_value) \ _spr_register(env, num, name, uea_read, uea_write, \ - oea_read, oea_write, initial_value) + oea_read, oea_write, hea_read, hea_write, initial_value)#else #define spr_register_kvm (env, num, name, uea_read, uea_write, \ - oea_read, oea_write, one_reg_id, initial_value) \ + oea_read, oea_write, one_reg_id, initial_value) \ + _spr_register(env, num, name, uea_read, uea_write, \ + oea_read, oea_write, oea_read, oea_write, \ + one_reg_id, initial_value) +#define spr_register_kvm_hv (env, num, name, uea_read, uea_write, \ + oea_read, oea_write, hea_read, hea_write, \ + one_reg_id, initial_value) \ _spr_register(env, num, name, uea_read, uea_write, \ - oea_read, oea_write, one_reg_id, initial_value) + oea_read, oea_write, hea_read, hea_write, \ + one_reg_id, initial_value)#endif #endif @@ -597,6 +613,13 @@ static inline void vscr_init (CPUPPCState *env, uint32_t val)spr_register_kvm (env, num, name, uea_read, uea_write, \ oea_read, oea_write, 0, initial_value) +#define spr_register_hv (env, num, name, uea_read, uea_write, \ + oea_read, oea_write, hea_read, hea_write, \ + initial_value) \ + spr_register_kvm_hv(env, num, name, uea_read, uea_write, \ + oea_read, oea_write, hea_read, hea_write, \ + 0, initial_value) + static inline void _spr_register(CPUPPCState *env, int num, const char *name, void (*uea_read)(DisasContext *ctx, int gprn, int sprn),@@ -605,6 +628,8 @@ static inline void _spr_register(CPUPPCState *env, int num,void (*oea_read)(DisasContext *ctx,int gprn,int sprn), void (*oea_write)(DisasContext *ctx, int sprn, int gprn), + void (*hea_read)(DisasContext *opaque, int gprn, int sprn), + void (*hea_write)(DisasContext *opaque, int sprn, int gprn), #endif #if defined(CONFIG_KVM) uint64_t one_reg_id,@@ -632,6 +657,8 @@ static inline void _spr_register(CPUPPCState *env, int num,#if !defined(CONFIG_USER_ONLY ) spr->oea_read = oea_read; spr->oea_write = oea_write; + spr->hea_read = hea_read; + spr->hea_write = hea_write;#endif #if defined(CONFIG_KVM ) spr->one_reg_id = one_reg_id,
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 7/77 ppc: Add a bunch of hypervisor SPRs to Book3s
In reply to Benjamin HerrenschmidtWe don't give them a KVM reg number yet as no current KVM version supports HV mode.
--- target-ppc/translate_init.c | 140 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 137 insertions(+), 3 deletions(-)
target-ppc/translate_init.c +137 -3
@@ -1104,6 +1104,11 @@ static void gen_spr_amr (CPUPPCState *env)SPR_NOACCESS ,SPR_NOACCESS , &spr_read_generic, &spr_write_generic, KVM_REG_PPC_UAMOR, 0); +spr_register_hv (env,SPR_AMOR ,"AMOR" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0 ); #endif /* !CONFIG_USER_ONLY */ }#endif /* TARGET_PPC64 */
@@ -7490,6 +7495,20 @@ static void gen_spr_book3s_dbg(CPUPPCState *env) KVM_REG_PPC_DABRX, 0x00000000); } +static void gen_spr_book3s_207_dbg (CPUPPCState *env) +{ +spr_register_hv (env,SPR_DAWR ,"DAWR" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_DAWRX ,"DAWRX" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +} +static void gen_spr_970_dbg (CPUPPCState *env) {/* Breakpoints */
@@ -7654,15 +7673,116 @@ static void gen_spr_power5p_lpar(CPUPPCState *env)spr_register_kvm (env,SPR_LPCR ,"LPCR" ,SPR_NOACCESS ,SPR_NOACCESS , &spr_read_generic, &spr_write_generic, -KVM_REG_PPC_LPCR ,0x00000000 ); +KVM_REG_PPC_LPCR ,LPCR_LPES0 |LPCR_LPES1 ); } +#if !defined(CONFIG_USER_ONLY ) +static void spr_write_hmer (DisasContext *ctx,int sprn,int gprn) +{ +TCGv hmer =tcg_temp_new (); + +gen_load_spr (hmer, sprn); +tcg_gen_and_tl (hmer, cpu_gpr[gprn], hmer); +gen_store_spr (sprn, hmer); +spr_store_dump_spr (sprn); +tcg_temp_free (hmer); +} +#endif +static void gen_spr_book3s_ids (CPUPPCState *env) { +/* FIXME: Will need to deal with thread vs core only SPRs */ +/* Processor identification */ -spr_register (env,SPR_PIR ,"PIR" , +spr_register_hv (env,SPR_PIR ,"PIR" ,SPR_NOACCESS ,SPR_NOACCESS , - &spr_read_generic, &spr_write_pir, +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic,NULL , +0x00000000 ); +spr_register_hv (env,SPR_HID0 ,"HID0" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_TSCR ,"TSCR" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_HMER ,"HMER" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_hmer, +0x00000000 ); +spr_register_hv (env,SPR_HMEER ,"HMEER" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_TFMR ,"TFMR" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_LPIDR ,"LPIDR" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_HFSCR ,"HFSCR" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_MMCRC ,"MMCRC" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_MMCRH ,"MMCRH" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_HSPRG0 ,"HSPRG0" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_HSPRG1 ,"HSPRG1" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_HSRR0 ,"HSRR0" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_HSRR1 ,"HSRR1" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_HDAR ,"HDAR" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_HDSISR ,"HDSISR" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_RMOR ,"RMOR" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_HRMOR ,"HRMOR" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic,0x00000000 ); }
@@ -7868,6 +7988,17 @@ static void gen_spr_power8_fscr(CPUPPCState *env) KVM_REG_PPC_FSCR, initval); } +static void gen_spr_power8_rpr (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY ) +spr_register_hv (env,SPR_RPR ,"RPR" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000103070F1F3F ); +#endif +} +static void init_proc_book3s_64 (CPUPPCState *env,int version) {gen_spr_ne_601 (env);
@@ -7919,9 +8050,12 @@ static void init_proc_book3s_64(CPUPPCState *env, int version)gen_spr_power8_pmu_user (env);gen_spr_power8_tm (env);gen_spr_vtb (env); +gen_spr_power8_rpr (env); }if (version <BOOK3S_CPU_POWER8 ) {gen_spr_book3s_dbg (env); + }else { +gen_spr_book3s_207_dbg (env); }#if !defined(CONFIG_USER_ONLY )switch (version) {
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 07/77] ppc: Add a bunch of hypervisor SPRs to Book3s
Quoted 4 lines · Benjamin Herrenschmidt
We don't give them a KVM reg number yet as no current KVM version supports HV mode.
Signed-off-by Benjamin Herrenschmidt <[email protected]>
Looks sane, though I haven't explicitly checked each of the implementations against the architecture.
Quoted 192 lines
--- target-ppc/translate_init.c | 140 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 137 insertions(+), 3 deletions(-)target-ppc/translate_init.c +137
-3@@ -1104,6 +1104,11 @@ static void gen_spr_amr (CPUPPCState *env)SPR_NOACCESS ,SPR_NOACCESS , &spr_read_generic, &spr_write_generic, KVM_REG_PPC_UAMOR, 0); +spr_register_hv (env,SPR_AMOR ,"AMOR" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0 ); #endif /* !CONFIG_USER_ONLY */ }#endif /* TARGET_PPC64 */ @@ -7490,6 +7495,20 @@ static void gen_spr_book3s_dbg(CPUPPCState *env) KVM_REG_PPC_DABRX, 0x00000000); } +static void gen_spr_book3s_207_dbg (CPUPPCState *env) +{ +spr_register_hv (env,SPR_DAWR ,"DAWR" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_DAWRX ,"DAWRX" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +} +static void gen_spr_970_dbg (CPUPPCState *env) {/* Breakpoints */ @@ -7654,15 +7673,116 @@ static void gen_spr_power5p_lpar(CPUPPCState *env)spr_register_kvm (env,SPR_LPCR ,"LPCR" ,SPR_NOACCESS ,SPR_NOACCESS , &spr_read_generic, &spr_write_generic, -KVM_REG_PPC_LPCR ,0x00000000 ); +KVM_REG_PPC_LPCR ,LPCR_LPES0 |LPCR_LPES1 ); } +#if !defined(CONFIG_USER_ONLY ) +static void spr_write_hmer (DisasContext *ctx,int sprn,int gprn) +{ +TCGv hmer =tcg_temp_new (); + +gen_load_spr (hmer, sprn); +tcg_gen_and_tl (hmer, cpu_gpr[gprn], hmer); +gen_store_spr (sprn, hmer); +spr_store_dump_spr (sprn); +tcg_temp_free (hmer); +} +#endif +static void gen_spr_book3s_ids (CPUPPCState *env) { +/* FIXME: Will need to deal with thread vs core only SPRs */ +/* Processor identification */ -spr_register (env,SPR_PIR ,"PIR" , +spr_register_hv (env,SPR_PIR ,"PIR" ,SPR_NOACCESS ,SPR_NOACCESS , - &spr_read_generic, &spr_write_pir, +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic,NULL , +0x00000000 ); +spr_register_hv (env,SPR_HID0 ,"HID0" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_TSCR ,"TSCR" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_HMER ,"HMER" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_hmer, +0x00000000 ); +spr_register_hv (env,SPR_HMEER ,"HMEER" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_TFMR ,"TFMR" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_LPIDR ,"LPIDR" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_HFSCR ,"HFSCR" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_MMCRC ,"MMCRC" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_MMCRH ,"MMCRH" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_HSPRG0 ,"HSPRG0" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_HSPRG1 ,"HSPRG1" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_HSRR0 ,"HSRR0" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_HSRR1 ,"HSRR1" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_HDAR ,"HDAR" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_HDSISR ,"HDSISR" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_RMOR ,"RMOR" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000000 ); +spr_register_hv (env,SPR_HRMOR ,"HRMOR" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic,0x00000000 ); }@@ -7868,6 +7988,17 @@ static void gen_spr_power8_fscr(CPUPPCState *env) KVM_REG_PPC_FSCR, initval); } +static void gen_spr_power8_rpr (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY ) +spr_register_hv (env,SPR_RPR ,"RPR" , +SPR_NOACCESS ,SPR_NOACCESS , +SPR_NOACCESS ,SPR_NOACCESS , + &spr_read_generic, &spr_write_generic, +0x00000103070F1F3F ); +#endif +} +static void init_proc_book3s_64 (CPUPPCState *env,int version) {gen_spr_ne_601 (env);@@ -7919,9 +8050,12 @@ static void init_proc_book3s_64(CPUPPCState *env, int version)gen_spr_power8_pmu_user (env);gen_spr_power8_tm (env);gen_spr_vtb (env); +gen_spr_power8_rpr (env); }if (version <BOOK3S_CPU_POWER8 ) {gen_spr_book3s_dbg (env); + }else { +gen_spr_book3s_207_dbg (env); }#if !defined(CONFIG_USER_ONLY )switch (version) {
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [Qemu-ppc] [PATCH 07/77] ppc: Add a bunch of hypervisor SPRs to Book3s
Quoted 9 lines · David Gibson
Quoted 4 lines · Benjamin Herrenschmidt
We don't give them a KVM reg number yet as no current KVM version supports HV mode.
Signed-off-by Benjamin Herrenschmidt <[email protected]>Looks sane, though I haven't explicitly checked each of the implementations against the architecture.
Almost all of those are just "placeholders". IE, we just read and write whatever is passed into the SPR array. What might be interesting is to what extend we actually use the values later on, which happens by bits and pieces in separate patches, or in many cases, not at all.
I think it might be worth adding to the SPR array a bitmask of the implemented bits though, so that we force the unimplemented ones to 0 rather than storing them, and possibly warn on attempts to write 1 to an unimplemented one.
Something to put on the TODO list...
Cheers,
Ben.
Quoted 199 lines
Quoted 198 lines
---
target-ppc/translate_init.c | 140
+++++++++++++++++++++++++++++++++++++++++++-1 file changed, 137 insertions(+), 3 deletions(-)target- renamed from target-ppc/translate_init.c +0
-0
ppc/translate_init.c
index 30a03ce..c743eb1 100644target-ppc/translate_init.c +5
-0@@ -1104,6 +1104,11 @@ static void gen_spr_amr (CPUPPCState *env) SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, KVM_REG_PPC_UAMOR, 0); + spr_register_hv(env, SPR_AMOR, "AMOR", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0); #endif /* !CONFIG_USER_ONLY */ } #endif /* TARGET_PPC64 */@@ -7490,6 +7495,20 @@ static void gen_spr_book3s_dbg(CPUPPCState *env) KVM_REG_PPC_DABRX, 0x00000000); }target-ppc/translate_init.c +14
-0+static void gen_spr_book3s_207_dbg (CPUPPCState *env) +{ + spr_register_hv(env, SPR_DAWR, "DAWR", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register_hv(env, SPR_DAWRX, "DAWRX", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} +static void
gen_spr_970_dbg(CPUPPCState *env)
{
/* Breakpoints */target-ppc/translate_init.c +1
-1@@ -7654,15 +7673,116 @@ static void gen_spr_power5p_lpar(CPUPPCState *env) spr_register_kvm(env, SPR_LPCR, "LPCR", SPR_NOACCESS, SPR_NOACCESS, &spr_read_generic, &spr_write_generic, - KVM_REG_PPC_LPCR, 0x00000000); + KVM_REG_PPC_LPCR, LPCR_LPES0 | LPCR_LPES1); }target-ppc/translate_init.c +13
-0+#if !defined(CONFIG_USER_ONLY ) +static void spr_write_hmer (DisasContext *ctx,int sprn,int gprn) +{ + TCGv hmer = tcg_temp_new(); + + gen_load_spr(hmer, sprn); + tcg_gen_and_tl(hmer, cpu_gpr[gprn], hmer); + gen_store_spr(sprn, hmer); + spr_store_dump_spr(sprn); + tcg_temp_free(hmer); +} +#endif +static void
gen_spr_book3s_ids(CPUPPCState *env)
{
+ /* FIXME: Will need to deal with thread vs core only SPRs */ +
/* Processor identification */
- spr_register(env,SPR_PIR, "PIR",
+ spr_register_hv(env,SPR_PIR, "PIR",
SPR_NOACCESS,SPR_NOACCESS,
- &spr_read_generic,&spr_write_pir,
+ SPR_NOACCESS,SPR_NOACCESS,
+ &spr_read_generic, NULL,
+ 0x00000000);
+ spr_register_hv(env,SPR_HID0, "HID0",
+ SPR_NOACCESS,SPR_NOACCESS,
+ SPR_NOACCESS,SPR_NOACCESS,
+ &spr_read_generic,&spr_write_generic, + 0x00000000);
+ spr_register_hv(env,SPR_TSCR, "TSCR",
+ SPR_NOACCESS,SPR_NOACCESS,
+ SPR_NOACCESS,SPR_NOACCESS,
+ &spr_read_generic,&spr_write_generic, + 0x00000000);
+ spr_register_hv(env,SPR_HMER, "HMER",
+ SPR_NOACCESS,SPR_NOACCESS,
+ SPR_NOACCESS,SPR_NOACCESS,
+ &spr_read_generic,&spr_write_hmer,
+ 0x00000000);
+ spr_register_hv(env,SPR_HMEER, "HMEER",
+ SPR_NOACCESS,SPR_NOACCESS,
+ SPR_NOACCESS,SPR_NOACCESS,
+ &spr_read_generic,&spr_write_generic, + 0x00000000);
+ spr_register_hv(env,SPR_TFMR, "TFMR",
+ SPR_NOACCESS,SPR_NOACCESS,
+ SPR_NOACCESS,SPR_NOACCESS,
+ &spr_read_generic,&spr_write_generic, + 0x00000000);
+ spr_register_hv(env,SPR_LPIDR, "LPIDR",
+ SPR_NOACCESS,SPR_NOACCESS,
+ SPR_NOACCESS,SPR_NOACCESS,
+ &spr_read_generic,&spr_write_generic, + 0x00000000);
+ spr_register_hv(env,SPR_HFSCR, "HFSCR",
+ SPR_NOACCESS,SPR_NOACCESS,
+ SPR_NOACCESS,SPR_NOACCESS,
+ &spr_read_generic,&spr_write_generic, + 0x00000000);
+ spr_register_hv(env,SPR_MMCRC, "MMCRC",
+ SPR_NOACCESS,SPR_NOACCESS,
+ SPR_NOACCESS,SPR_NOACCESS,
+ &spr_read_generic,&spr_write_generic, + 0x00000000);
+ spr_register_hv(env,SPR_MMCRH, "MMCRH",
+ SPR_NOACCESS,SPR_NOACCESS,
+ SPR_NOACCESS,SPR_NOACCESS,
+ &spr_read_generic,&spr_write_generic, + 0x00000000);
+ spr_register_hv(env,SPR_HSPRG0, "HSPRG0",
+ SPR_NOACCESS,SPR_NOACCESS,
+ SPR_NOACCESS,SPR_NOACCESS,
+ &spr_read_generic,&spr_write_generic, + 0x00000000);
+ spr_register_hv(env,SPR_HSPRG1, "HSPRG1",
+ SPR_NOACCESS,SPR_NOACCESS,
+ SPR_NOACCESS,SPR_NOACCESS,
+ &spr_read_generic,&spr_write_generic, + 0x00000000);
+ spr_register_hv(env,SPR_HSRR0, "HSRR0",
+ SPR_NOACCESS,SPR_NOACCESS,
+ SPR_NOACCESS,SPR_NOACCESS,
+ &spr_read_generic,&spr_write_generic, + 0x00000000);
+ spr_register_hv(env,SPR_HSRR1, "HSRR1",
+ SPR_NOACCESS,SPR_NOACCESS,
+ SPR_NOACCESS,SPR_NOACCESS,
+ &spr_read_generic,&spr_write_generic, + 0x00000000);
+ spr_register_hv(env,SPR_HDAR, "HDAR",
+ SPR_NOACCESS,SPR_NOACCESS,
+ SPR_NOACCESS,SPR_NOACCESS,
+ &spr_read_generic,&spr_write_generic, + 0x00000000);
+ spr_register_hv(env,SPR_HDSISR, "HDSISR",
+ SPR_NOACCESS,SPR_NOACCESS,
+ SPR_NOACCESS,SPR_NOACCESS,
+ &spr_read_generic,&spr_write_generic, + 0x00000000);
+ spr_register_hv(env,SPR_RMOR, "RMOR",
+ SPR_NOACCESS,SPR_NOACCESS,
+ SPR_NOACCESS,SPR_NOACCESS,
+ &spr_read_generic,&spr_write_generic, + 0x00000000);
+ spr_register_hv(env,SPR_HRMOR, "HRMOR",
+ SPR_NOACCESS,SPR_NOACCESS,
+ SPR_NOACCESS,SPR_NOACCESS,
+ &spr_read_generic,&spr_write_generic,0x00000000);
}target-ppc/translate_init.c +0
-0@@ -7868,6 +7988,17 @@ static void gen_spr_power8_fscr(CPUPPCState *env) KVM_REG_PPC_FSCR, initval); }target-ppc/translate_init.c +11
-0+static void gen_spr_power8_rpr (CPUPPCState *env) +{ +#if !defined(CONFIG_USER_ONLY ) + spr_register_hv(env, SPR_RPR, "RPR", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000103070F1F3F); +#endif +} +static void
init_proc_book3s_64(CPUPPCState *env, int version){
gen_spr_ne_601(env);target-ppc/translate_init.c +3
-0@@ -7919,9 +8050,12 @@ static void init_proc_book3s_64(CPUPPCState *env, int version) gen_spr_power8_pmu_user(env); gen_spr_power8_tm(env); gen_spr_vtb(env); + gen_spr_power8_rpr(env); } if (version < BOOK3S_CPU_POWER8) { gen_spr_book3s_dbg(env); + } else { + gen_spr_book3s_207_dbg(env); } #if !defined(CONFIG_USER_ONLY)switch (version) {
PATCH 8/77 ppc: Add number of threads per core to the processor definition
In reply to Benjamin HerrenschmidtAlso use it to clamp the max SMT mode and ensure that the cpu_dt_id are offset by that value in order to preserve consistency with the HW implementations.
--- target-ppc/cpu-qom.h | 1 + target-ppc/translate_init.c | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-)
target-ppc/cpu-qom.h +1 -0
@@ -68,6 +68,7 @@ typedef struct PowerPCCPUClass {uint32_t flags;int bfd_mach;uint32_t l1_dcache_size, l1_icache_size; +uint32_t threads_per_core;#if defined(TARGET_PPC64 )const struct ppc_segment_page_sizes *sps;#endif
target-ppc/translate_init.c +7 -1
@@ -8193,6 +8193,7 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data)POWERPC_FLAG_BUS_CLK ; pcc->l1_dcache_size =0x8000 ; pcc->l1_icache_size =0x10000 ; + pcc->threads_per_core =2 ; } static void powerpc_get_compat(Object *obj, Visitor *v,
@@ -8339,6 +8340,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) pcc->l1_dcache_size =0x8000 ; pcc->l1_icache_size =0x8000 ; pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr; + pcc->threads_per_core =4 ; }static void init_proc_POWER8 (CPUPPCState *env)
@@ -8419,6 +8421,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) pcc->l1_dcache_size =0x8000 ; pcc->l1_icache_size =0x8000 ; pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr; + pcc->threads_per_core = 8; }#endif /* defined (TARGET_PPC64) */
@@ -9074,6 +9077,9 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp)#endif #if !defined(CONFIG_USER_ONLY ) +if (max_smt > pcc->threads_per_core) { + max_smt = pcc->threads_per_core; + }if (smp_threads > max_smt) {error_setg (errp,"Cannot support more than %d threads on PPC with %s" , max_smt,kvm_enabled () ?"KVM" :"TCG" );
@@ -9094,7 +9100,7 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp) }#if !defined(CONFIG_USER_ONLY ) - cpu->cpu_dt_id = (cs->cpu_index / smp_threads) * max_smt + cpu->cpu_dt_id = (cs->cpu_index / smp_threads) * pcc->threads_per_core + (cs->cpu_index % smp_threads);#endif
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 08/77] ppc: Add number of threads per core to the processor definition
Quoted 5 lines · Benjamin Herrenschmidt
Also use it to clamp the max SMT mode and ensure that the
cpu_dt_idare offset by that value in order to preserve consistency with the HW implementations.Signed-off-by Benjamin Herrenschmidt <[email protected]>
Quoted 64 lines
--- target-ppc/cpu-qom.h | 1 + target-ppc/translate_init.c | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-)target-ppc/cpu-qom.h +1
-0@@ -68,6 +68,7 @@ typedef struct PowerPCCPUClass {uint32_t flags;int bfd_mach;uint32_t l1_dcache_size, l1_icache_size; +uint32_t threads_per_core;#if defined(TARGET_PPC64 )const struct ppc_segment_page_sizes *sps;#endif target-ppc/translate_init.c +7
-1@@ -8193,6 +8193,7 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data)POWERPC_FLAG_BUS_CLK ; pcc->l1_dcache_size =0x8000 ; pcc->l1_icache_size =0x10000 ; + pcc->threads_per_core =2 ; } static void powerpc_get_compat(Object *obj, Visitor *v,@@ -8339,6 +8340,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) pcc->l1_dcache_size =0x8000 ; pcc->l1_icache_size =0x8000 ; pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr; + pcc->threads_per_core =4 ; }static void init_proc_POWER8 (CPUPPCState *env)@@ -8419,6 +8421,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) pcc->l1_dcache_size =0x8000 ; pcc->l1_icache_size =0x8000 ; pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr; + pcc->threads_per_core = 8; }#endif /* defined (TARGET_PPC64) */ @@ -9074,6 +9077,9 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp)#endif #if !defined(CONFIG_USER_ONLY ) +if (max_smt > pcc->threads_per_core) { + max_smt = pcc->threads_per_core; + }if (smp_threads > max_smt) {error_setg (errp,"Cannot support more than %d threads on PPC with %s" , max_smt,kvm_enabled () ?"KVM" :"TCG" );@@ -9094,7 +9100,7 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp) }#if !defined(CONFIG_USER_ONLY ) - cpu->cpu_dt_id = (cs->cpu_index / smp_threads) * max_smt + cpu->cpu_dt_id = (cs->cpu_index / smp_threads) * pcc->threads_per_core + (cs->cpu_index % smp_threads);#endif
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [Qemu-ppc] [PATCH 08/77] ppc: Add number of threads per core to the processor definition
Quoted 9 lines · David Gibson
Quoted 5 lines · Benjamin Herrenschmidt
Also use it to clamp the max SMT mode and ensure that the
cpu_dt_idare offset by that value in order to preserve consistency with the HW implementations.Signed-off-by Benjamin Herrenschmidt <[email protected]>Reviewed-by David Gibson <[email protected]>
In fact this is broken ;-) All the CPUs without thread get 0 in the new field which trips at init time since we can create 0 threads :-) It broke for example 32-bit stuff. I've fixed that in github.
Quoted 75 lines
Quoted 74 lines
---
target-ppc/cpu-qom.h | 1 +
target-ppc/translate_init.c | 8 +++++++-2 files changed, 8 insertions(+), 1 deletion(-)target-ppc/cpu-qom.h +1
-0@@ -68,6 +68,7 @@ typedef struct PowerPCCPUClass { uint32_t flags; int bfd_mach; uint32_t l1_dcache_size, l1_icache_size; + uint32_t threads_per_core; #if defined(TARGET_PPC64) const struct ppc_segment_page_sizes *sps; #endiftarget- renamed from target-ppc/translate_init.c +0
-0
ppc/translate_init.c
index c743eb1..1d402e1 100644target-ppc/translate_init.c +1
-0@@ -8193,6 +8193,7 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data) POWERPC_FLAG_BUS_CLK; pcc->l1_dcache_size = 0x8000; pcc->l1_icache_size = 0x10000; + pcc->threads_per_core = 2; }
static void powerpc_get_compat(Object *obj, Visitor *v,target-ppc/translate_init.c +0
-0@@ -8339,6 +8340,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) pcc->l1_dcache_size = 0x8000; pcc->l1_icache_size = 0x8000;pcc->interrupts_big_endian =
ppc_cpu_interrupts_big_endian_lpcr;
+ pcc->threads_per_core = 4;
}
static voidinit_proc_POWER8(CPUPPCState *env)target-ppc/translate_init.c +0
-0@@ -8419,6 +8421,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) pcc->l1_dcache_size = 0x8000; pcc->l1_icache_size = 0x8000;pcc->interrupts_big_endian =
ppc_cpu_interrupts_big_endian_lpcr;
+ pcc->threads_per_core = 8;
}
#endif /* defined (TARGET_PPC64) */target-ppc/translate_init.c +0
-0@@ -9074,6 +9077,9 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp) #endif
#if !defined(CONFIG_USER_ONLY)
+ if (max_smt>pcc->threads_per_core) {
+ max_smt =pcc->threads_per_core;
+ }
if (smp_threads>max_smt) {
error_setg(errp, "Cannot support more than %d threads on PPC with %s",
max_smt,kvm_enabled()? "KVM" : "TCG");target-ppc/translate_init.c +0
-0@@ -9094,7 +9100,7 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp) }
#if !defined(CONFIG_USER_ONLY)
- cpu->cpu_dt_id = (cs->cpu_index/smp_threads) *max_smt+ cpu->cpu_dt_id = (cs->cpu_index/smp_threads) * pcc-Quoted 1 line
threads_per_core+ (
cs->cpu_index%smp_threads);
#endif
PATCH 9/77 ppc: Fix do_rfi() for rfi emulation
In reply to Benjamin HerrenschmidtXXX This patch needs double checking... It fixed 32-bit userspace but I'm not sure it's right. I wonder whether msr_is_64bit() should be applied to env->msr, not msr, but I need to double check the architecture.
--- target-ppc/excp_helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
target-ppc/excp_helper.c +2 -2
@@ -878,13 +878,13 @@ static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr,CPUState *cs =CPU (ppc_env_get_cpu (env));#if defined(TARGET_PPC64 ) + msr = msr & msrm;if (msr_is_64bit (env, msr)) { nip = (uint64_t )nip; - msr &= (uint64_t )msrm; }else { nip = (uint32_t )nip; - msr = (uint32_t )(msr & msrm);if (keep_msrh) { + msr &=0xffffffff ; msr |= env->msr & ~((uint64_t )0xFFFFFFFF ); } }
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 09/77] ppc: Fix do_rfi() for rfi emulation
Quoted 4 lines · Benjamin Herrenschmidt
XXX This patch needs double checking... It fixed 32-bit userspace but I'm not sure it's right. I wonder whether
msr_is_64bit()should be applied toenv->msr, not msr, but I need to double check the architecture.
Hrm, I'm not really sure where I'd look in the arch, but msr_is_64bit(env->msr) seems like it would make more sense to me. The current logic means that rfi, ostensibly a 32-bit instruction will have different behaviour depending on the upper bits of SRR1, which seems a unexpected.
Quoted 26 lines
Signed-off-by Benjamin Herrenschmidt <[email protected]>--- target-ppc/excp_helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)target-ppc/excp_helper.c +2
-2@@ -878,13 +878,13 @@ static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr,CPUState *cs =CPU (ppc_env_get_cpu (env));#if defined(TARGET_PPC64 ) + msr = msr & msrm;if (msr_is_64bit (env, msr)) { nip = (uint64_t )nip; - msr &= (uint64_t )msrm; }else { nip = (uint32_t )nip; - msr = (uint32_t )(msr & msrm);if (keep_msrh) { + msr &=0xffffffff ; msr |= env->msr & ~((uint64_t )0xFFFFFFFF ); } }
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [Qemu-ppc] [PATCH 09/77] ppc: Fix do_rfi() for rfi emulation
Quoted 7 lines · David Gibson
Quoted 4 lines · Benjamin Herrenschmidt
XXX This patch needs double checking... It fixed 32-bit userspace but I'm not sure it's right. I wonder whether
msr_is_64bit()should be applied toenv->msr, not msr, but I need to double check the architecture.
Quoted 6 lines
Hrm, I'm not really sure where I'd look in the arch, but
msr_is_64bit(env->msr)seems like it would make more sense to me. The current logic means that rfi, ostensibly a 32-bit instruction will
have different behaviour depending on the upper bits of SRR1, which seems a unexpected.
I only just discovered that rfi is actually gone from arch 2.07 :-)
I'll dig a bit more tomorrow.
Cheers,
Ben.
Quoted 29 lines
Quoted 28 lines
Signed-off-by Benjamin Herrenschmidt <[email protected]>---
target-ppc/excp_helper.c | 4 ++--1 file changed, 2 insertions(+), 2 deletions(-)target-ppc/excp_helper.c +0
-0@@ -878,13 +878,13 @@ static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr, CPUState *cs = CPU(ppc_env_get_cpu(env));
#ifdefined(TARGET_PPC64)
+ msr = msr & msrm;
if (msr_is_64bit(env, msr)) {
nip = (uint64_t)nip;
- msr &= (uint64_t)msrm;
} else {
nip = (uint32_t)nip;
- msr = (uint32_t)(msr & msrm);
if (keep_msrh) {target-ppc/excp_helper.c +1
-0+ msr &= 0xffffffff;msr |=
env->msr& ~((uint64_t)0xFFFFFFFF); }
}
Re: [Qemu-devel] [Qemu-ppc] [PATCH 09/77] ppc: Fix do_rfi() for rfi emulation
Quoted 4 lines · Benjamin Herrenschmidt
I only just discovered that rfi is actually gone from arch 2.07 :-)I'll dig a bit more tomorrow.
Ok, so I had a closer look and tore that stuff appart even more :-)
If you are curious, feel free to check out github. I've removed the MSR mask completely, I can't figure out what it's supposed to be about. I've quickly tested 64-bit powernv/pseries, 32-bit userspace on 64-bit pseries kernel, and 32-bit Mac99 (ubuntu).
Cheers,
Ben.
Quoted 31 lines
Cheers,
Ben.Quoted 28 lines
Quoted 28 lines
Signed-off-by Benjamin Herrenschmidt <[email protected]>---
target-ppc/excp_helper.c | 4 ++--1 file changed, 2 insertions(+), 2 deletions(-)target-ppc/excp_helper.c +0
-0@@ -878,13 +878,13 @@ static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr, CPUState *cs = CPU(ppc_env_get_cpu(env));
#ifdefined(TARGET_PPC64)
+ msr = msr & msrm;
if (msr_is_64bit(env, msr)) {
nip = (uint64_t)nip;
- msr &= (uint64_t)msrm;
} else {
nip = (uint32_t)nip;
- msr = (uint32_t)(msr & msrm);
if (keep_msrh) {target-ppc/excp_helper.c +1
-0+ msr &= 0xffffffff;msr |=
env->msr& ~((uint64_t)0xFFFFFFFF); }
}
PATCH 10/77 ppc: Fix hreg_store_msr() so that non-HV mode cannot alter MSR:HV
In reply to Benjamin HerrenschmidtThis helper is only used by the various instructions that can alter MSR and not interrupts. Add a comment to that effect to the interrupt code as well in case somebody wants to change this
--- target-ppc/excp_helper.c | 8 ++++++-- target-ppc/helper_regs.h | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-)
target-ppc/excp_helper.c +6 -2
@@ -662,8 +662,12 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) } }#endif -/* XXX: we don't use hreg_store_msr here as already have treated -* any special case that could occur. Just store MSR and update hflags +/* We don't use hreg_store_msr here as already have treated +* any special case that could occur. Just store MSR and update hflags +* +* Note: We *MUST* not use hreg_store_msr() as-is anyway because it +* will prevent setting of the HV bit which some exceptions might need +* to do. */ env->msr = new_msr & env->msr_mask;hreg_compute_hflags (env);
target-ppc/helper_regs.h +2 -2
@@ -114,8 +114,8 @@ static inline int hreg_store_msr(CPUPPCState *env, target_ulong value, excp =0 ; value &= env->msr_mask;#if !defined(CONFIG_USER_ONLY ) -if (!alter_hv) { -/* mtmsr cannot alter the hypervisor state */ +/* Neither mtmsr nor guest state can alter HV */ +if (!alter_hv || !(env->msr &MSR_HVB )) { value &= ~MSR_HVB ; value |= env->msr &MSR_HVB ; }
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 10/77] ppc: Fix hreg_store_msr() so that non-HV mode cannot alter MSR:HV
Quoted 5 lines · Benjamin Herrenschmidt
This helper is only used by the various instructions that can alter MSR and not interrupts. Add a comment to that effect to the interrupt code as well in case somebody wants to change this
Signed-off-by Benjamin Herrenschmidt <[email protected]>
Quoted 39 lines
--- target-ppc/excp_helper.c | 8 ++++++-- target-ppc/helper_regs.h | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-)target-ppc/excp_helper.c +6
-2@@ -662,8 +662,12 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) } }#endif -/* XXX: we don't use hreg_store_msr here as already have treated -* any special case that could occur. Just store MSR and update hflags +/* We don't use hreg_store_msr here as already have treated +* any special case that could occur. Just store MSR and update hflags +* +* Note: We *MUST* not use hreg_store_msr() as-is anyway because it +* will prevent setting of the HV bit which some exceptions might need +* to do. */ env->msr = new_msr & env->msr_mask;hreg_compute_hflags (env);target-ppc/helper_regs.h +2
-2@@ -114,8 +114,8 @@ static inline int hreg_store_msr(CPUPPCState *env, target_ulong value, excp =0 ; value &= env->msr_mask;#if !defined(CONFIG_USER_ONLY ) -if (!alter_hv) { -/* mtmsr cannot alter the hypervisor state */ +/* Neither mtmsr nor guest state can alter HV */ +if (!alter_hv || !(env->msr &MSR_HVB )) { value &= ~MSR_HVB ; value |= env->msr &MSR_HVB ; }
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 11/77 ppc: Create cpu_ppc_set_papr() helper
In reply to Benjamin HerrenschmidtAnd move the code adjusting the MSR mask and calling kvmppc_set_papr() to it. This allows us to add a few more things such as disabling setting of MSR:HV and appropriate LPCR bits which will be used when fixing the exception model.
--- hw/ppc/spapr.c | 12 +++--------- target-ppc/cpu.h | 1 + target-ppc/translate_init.c | 37 ++++++++++++++++++++++++++++++++++++- 3 files changed, 40 insertions(+), 10 deletions(-)
hw/ppc/spapr.c +3 -9
@@ -1606,15 +1606,8 @@ static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu)/* Set time-base frequency to 512 MHz */ cpu_ppc_tb_init (env,TIMEBASE_FREQ ); -/* PAPR always has exception vectors in RAM not ROM. To ensure this, -* MSR[IP] should never be set. -*/ - env->msr_mask &= ~(1 <<6 ); - -/* Tell KVM that we're in PAPR mode */ -if (kvm_enabled ()) { -kvmppc_set_papr (cpu); - } +/* Enable PAPR mode in TCG or KVM */ +cpu_ppc_set_papr (cpu);if (cpu->max_compat) {if (ppc_set_compat (cpu, cpu->max_compat) <0 ) {
@@ -1791,6 +1784,7 @@ static void ppc_spapr_init(MachineState *machine)fprintf (stderr,"Unable to find PowerPC CPU definition\n" );exit (1 ); } +spapr_cpu_init (spapr, cpu); }
target-ppc/cpu.h +1 -0
@@ -1229,6 +1229,7 @@ void store_booke_tcr (CPUPPCState *env, target_ulong val);void store_booke_tsr (CPUPPCState *env,target_ulong val);void ppc_tlb_invalidate_all (CPUPPCState *env);void ppc_tlb_invalidate_one (CPUPPCState *env,target_ulong addr); +void cpu_ppc_set_papr (PowerPCCPU *cpu);#endif #endif
target-ppc/translate_init.c +36 -1
@@ -8423,8 +8423,43 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr; pcc->threads_per_core = 8; } -#endif /* defined (TARGET_PPC64) */ +#if !defined(CONFIG_USER_ONLY ) + +void cpu_ppc_set_papr (PowerPCCPU *cpu) +{ +CPUPPCState *env = &cpu->env; +ppc_spr_t *lpcr = &env->spr_cb[SPR_LPCR ]; + +/* PAPR always has exception vectors in RAM not ROM. To ensure this, +* MSR[IP] should never be set. +* +* We also disallow setting of MSR_HV +*/ + env->msr_mask &= ~((1ull <<MSR_EP ) |MSR_HVB ); + +/* Set emulated LPCR to not send interrupts to hypervisor. Note that +* under KVM, the actual HW LPCR will be set differently by KVM itself, +* the settings below ensure proper operations with TCG in absence of +* a real hypervisor +*/ + lpcr->default_value &= ~(LPCR_VPM0 |LPCR_VPM1 |LPCR_ISL |LPCR_KBV ); + lpcr->default_value |=LPCR_LPES0 |LPCR_LPES1 ; + +/* We should be followed by a CPU reset but update the active value +* just in case... +*/ + env->spr[SPR_LPCR ] = lpcr->default_value; + +/* Tell KVM that we're in PAPR mode */ +if (kvm_enabled ()) { +kvmppc_set_papr (cpu); + } +} + +#endif /* !defined(CONFIG_USER_ONLY) */ + +#endif /* defined (TARGET_PPC64) */ /*****************************************************************************/ /* Generic CPU instantiation routine */
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 11/77] ppc: Create cpu_ppc_set_papr() helper
Quoted 6 lines · Benjamin Herrenschmidt
And move the code adjusting the MSR mask and calling
kvmppc_set_papr()to it. This allows us to add a few more things such as disabling setting of MSR:HV and appropriate LPCR bits which will be used when fixing the exception model.Signed-off-by Benjamin Herrenschmidt <[email protected]>
Quoted 97 lines
--- hw/ppc/spapr.c | 12 +++--------- target-ppc/cpu.h | 1 + target-ppc/translate_init.c | 37 ++++++++++++++++++++++++++++++++++++- 3 files changed, 40 insertions(+), 10 deletions(-)hw/ppc/spapr.c +3
-9@@ -1606,15 +1606,8 @@ static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu)/* Set time-base frequency to 512 MHz */ cpu_ppc_tb_init (env,TIMEBASE_FREQ ); -/* PAPR always has exception vectors in RAM not ROM. To ensure this, -* MSR[IP] should never be set. -*/ - env->msr_mask &= ~(1 <<6 ); - -/* Tell KVM that we're in PAPR mode */ -if (kvm_enabled ()) { -kvmppc_set_papr (cpu); - } +/* Enable PAPR mode in TCG or KVM */ +cpu_ppc_set_papr (cpu);if (cpu->max_compat) {if (ppc_set_compat (cpu, cpu->max_compat) <0 ) {@@ -1791,6 +1784,7 @@ static void ppc_spapr_init(MachineState *machine)fprintf (stderr,"Unable to find PowerPC CPU definition\n" );exit (1 ); } +spapr_cpu_init (spapr, cpu); }target-ppc/cpu.h +1
-0@@ -1229,6 +1229,7 @@ void store_booke_tcr (CPUPPCState *env, target_ulong val);void store_booke_tsr (CPUPPCState *env,target_ulong val);void ppc_tlb_invalidate_all (CPUPPCState *env);void ppc_tlb_invalidate_one (CPUPPCState *env,target_ulong addr); +void cpu_ppc_set_papr (PowerPCCPU *cpu);#endif #endif target-ppc/translate_init.c +36
-1@@ -8423,8 +8423,43 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr; pcc->threads_per_core = 8; } -#endif /* defined (TARGET_PPC64) */ +#if !defined(CONFIG_USER_ONLY ) + +void cpu_ppc_set_papr (PowerPCCPU *cpu) +{ +CPUPPCState *env = &cpu->env; +ppc_spr_t *lpcr = &env->spr_cb[SPR_LPCR ]; + +/* PAPR always has exception vectors in RAM not ROM. To ensure this, +* MSR[IP] should never be set. +* +* We also disallow setting of MSR_HV +*/ + env->msr_mask &= ~((1ull <<MSR_EP ) |MSR_HVB ); + +/* Set emulated LPCR to not send interrupts to hypervisor. Note that +* under KVM, the actual HW LPCR will be set differently by KVM itself, +* the settings below ensure proper operations with TCG in absence of +* a real hypervisor +*/ + lpcr->default_value &= ~(LPCR_VPM0 |LPCR_VPM1 |LPCR_ISL |LPCR_KBV ); + lpcr->default_value |=LPCR_LPES0 |LPCR_LPES1 ; + +/* We should be followed by a CPU reset but update the active value +* just in case... +*/ + env->spr[SPR_LPCR ] = lpcr->default_value; + +/* Tell KVM that we're in PAPR mode */ +if (kvm_enabled ()) { +kvmppc_set_papr (cpu); + } +} + +#endif /* !defined(CONFIG_USER_ONLY) */ + +#endif /* defined (TARGET_PPC64) */ /*****************************************************************************/ /* Generic CPU instantiation routine */
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 12/77 ppc: Better figure out if processor has HV mode
In reply to Benjamin HerrenschmidtWe use an env. flag which is set to the initial value of MSR_HVB in the msr_mask. We also adjust the POWER8 mask to set SHV.
Also use this to adjust ctx.hv so that it is *set* when the processor doesn't have an HV mode (970 with Apple mode for example), thus enabling hypervisor instructions/SPRs.
--- target-ppc/cpu.h | 4 ++++ target-ppc/translate.c | 4 +++- target-ppc/translate_init.c | 21 ++++++++++++++++----- 3 files changed, 23 insertions(+), 6 deletions(-)
target-ppc/cpu.h +4 -0
@@ -1113,6 +1113,10 @@ struct CPUPPCState {hwaddr mpic_iack;/* true when the external proxy facility mode is enabled */ bool mpic_proxy; +/* set when the processor has an HV mode, thus HV priv +* instructions and SPRs are diallowed if MSR:HV is 0 +*/ +bool has_hv_mode;#endif /* Those resources are used only during code translation */
target-ppc/translate.c +3 -1
@@ -11465,8 +11465,10 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb) ctx.exception =POWERPC_EXCP_NONE ; ctx.spr_cb = env->spr_cb; ctx.pr = msr_pr; - ctx.hv = !msr_pr && msr_hv; ctx.mem_idx = env->dmmu_idx; +#if !defined(CONFIG_USER_ONLY ) + ctx.hv = !msr_pr && (msr_hv || !env->has_hv_mode); +#endif ctx.insns_flags = env->insns_flags; ctx.insns_flags2 = env->insns_flags2; ctx.access_type =-1 ;
target-ppc/translate_init.c +16 -5
@@ -8391,7 +8391,8 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)PPC2_ISA205 |PPC2_ISA207S |PPC2_FP_CVT_S64 |PPC2_TM ; pcc->msr_mask = (1ull <<MSR_SF ) | - (1ull <<MSR_TM ) | + (1ull <<MSR_SHV ) | + (1ull <<MSR_TM ) | (1ull <<MSR_VR ) | (1ull <<MSR_VSX ) | (1ull << MSR_EE) |
@@ -9748,10 +9749,7 @@ static void ppc_cpu_reset(CPUState *s) pcc->parent_reset (s); msr = (target_ulong )0 ; -if (0 ) { -/* XXX: find a suitable condition to enable the hypervisor mode */ - msr |= (target_ulong )MSR_HVB ; - } + msr |= (target_ulong )MSR_HVB ; msr |= (target_ulong )0 <<MSR_AP ;/* TO BE CHECKED */ msr |= (target_ulong )0 <<MSR_SA ;/* TO BE CHECKED */ msr |= (target_ulong )1 <<MSR_EP ;
@@ -9852,6 +9850,19 @@ static void ppc_cpu_initfn(Object *obj) env->bfd_mach = pcc->bfd_mach; env->check_pow = pcc->check_pow; +/* Mark HV mode as supported if the CPU has an MSR_HV bit +* in the msr_mask. The mask can later be cleared by PAPR +* mode but the hv mode support will remain, thus enforcing +* that we cannot use priv. instructions in guest in PAPR +* mode. For 970 we currently simply don't set HV in msr_mask +* thus simulating an "Apple mode" 970. If we ever want to +* support 970 HV mode, we'll have to add a processor attribute +* of some sort. +*/ +#if !defined(CONFIG_USER_ONLY ) + env->has_hv_mode = !!(env->msr_mask &MSR_HVB ); +#endif +#if defined(TARGET_PPC64 )if (pcc->sps) { env->sps = *pcc->sps;
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 12/77] ppc: Better figure out if processor has HV mode
Quoted 8 lines · Benjamin Herrenschmidt
We use an env. flag which is set to the initial value of
MSR_HVBin themsr_mask. We also adjust the POWER8 mask to set SHV.Also use this to adjust ctx.hv so that it is *set* when the processor doesn't have an HV mode (970 with Apple mode for example), thus enabling hypervisor instructions/SPRs.
Signed-off-by Benjamin Herrenschmidt <[email protected]>
Quoted 83 lines
--- target-ppc/cpu.h | 4 ++++ target-ppc/translate.c | 4 +++- target-ppc/translate_init.c | 21 ++++++++++++++++----- 3 files changed, 23 insertions(+), 6 deletions(-)target-ppc/cpu.h +4
-0@@ -1113,6 +1113,10 @@ struct CPUPPCState {hwaddr mpic_iack;/* true when the external proxy facility mode is enabled */ bool mpic_proxy; +/* set when the processor has an HV mode, thus HV priv +* instructions and SPRs are diallowed if MSR:HV is 0 +*/ +bool has_hv_mode;#endif /* Those resources are used only during code translation */ target-ppc/translate.c +3
-1@@ -11465,8 +11465,10 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb) ctx.exception =POWERPC_EXCP_NONE ; ctx.spr_cb = env->spr_cb; ctx.pr = msr_pr; - ctx.hv = !msr_pr && msr_hv; ctx.mem_idx = env->dmmu_idx; +#if !defined(CONFIG_USER_ONLY ) + ctx.hv = !msr_pr && (msr_hv || !env->has_hv_mode); +#endif ctx.insns_flags = env->insns_flags; ctx.insns_flags2 = env->insns_flags2; ctx.access_type =-1 ;target-ppc/translate_init.c +16
-5@@ -8391,7 +8391,8 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)PPC2_ISA205 |PPC2_ISA207S |PPC2_FP_CVT_S64 |PPC2_TM ; pcc->msr_mask = (1ull <<MSR_SF ) | - (1ull <<MSR_TM ) | + (1ull <<MSR_SHV ) | + (1ull <<MSR_TM ) | (1ull <<MSR_VR ) | (1ull <<MSR_VSX ) | (1ull << MSR_EE) |@@ -9748,10 +9749,7 @@ static void ppc_cpu_reset(CPUState *s) pcc->parent_reset (s); msr = (target_ulong )0 ; -if (0 ) { -/* XXX: find a suitable condition to enable the hypervisor mode */ - msr |= (target_ulong )MSR_HVB ; - } + msr |= (target_ulong )MSR_HVB ; msr |= (target_ulong )0 <<MSR_AP ;/* TO BE CHECKED */ msr |= (target_ulong )0 <<MSR_SA ;/* TO BE CHECKED */ msr |= (target_ulong )1 <<MSR_EP ;@@ -9852,6 +9850,19 @@ static void ppc_cpu_initfn(Object *obj) env->bfd_mach = pcc->bfd_mach; env->check_pow = pcc->check_pow; +/* Mark HV mode as supported if the CPU has an MSR_HV bit +* in the msr_mask. The mask can later be cleared by PAPR +* mode but the hv mode support will remain, thus enforcing +* that we cannot use priv. instructions in guest in PAPR +* mode. For 970 we currently simply don't set HV in msr_mask +* thus simulating an "Apple mode" 970. If we ever want to +* support 970 HV mode, we'll have to add a processor attribute +* of some sort. +*/ +#if !defined(CONFIG_USER_ONLY ) + env->has_hv_mode = !!(env->msr_mask &MSR_HVB ); +#endif +#if defined(TARGET_PPC64 )if (pcc->sps) { env->sps = *pcc->sps;
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 13/77 ppc: tlbie, tlbia and tlbisync are HV only
In reply to Benjamin HerrenschmidtNot that anything remotely recent supports tlbia but ...
--- target-ppc/translate.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
target-ppc/translate.c +3 -3
@@ -4836,7 +4836,7 @@ static void gen_tlbia(DisasContext *ctx)#if defined(CONFIG_USER_ONLY )gen_inval_exception (ctx,POWERPC_EXCP_PRIV_OPC );#else -if (unlikely (ctx->pr)) { +if (unlikely (ctx->pr || !ctx->hv)) {gen_inval_exception (ctx,POWERPC_EXCP_PRIV_OPC );return ; }
@@ -4850,7 +4850,7 @@ static void gen_tlbiel(DisasContext *ctx)#if defined(CONFIG_USER_ONLY )gen_inval_exception (ctx,POWERPC_EXCP_PRIV_OPC );#else -if (unlikely (ctx->pr)) { +if (unlikely (ctx->pr || !ctx->hv)) {gen_inval_exception (ctx,POWERPC_EXCP_PRIV_OPC );return ; }
@@ -4864,7 +4864,7 @@ static void gen_tlbie(DisasContext *ctx)#if defined(CONFIG_USER_ONLY )gen_inval_exception (ctx,POWERPC_EXCP_PRIV_OPC );#else -if (unlikely (ctx->pr)) { +if (unlikely (ctx->pr || !ctx->hv)) {gen_inval_exception (ctx,POWERPC_EXCP_PRIV_OPC );return ; }
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 13/77] ppc: tlbie, tlbia and tlbisync are HV only
Quoted 12 lines · Benjamin Herrenschmidt
Not that anything remotely recent supports tlbia but ...
Signed-off-by Benjamin Herrenschmidt <[email protected]>--- target-ppc/translate.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)target-ppc/translate.c +0
-0
target-ppc/translate.c static void gen_tlbia(DisasContext *ctx) · line 4839
Quoted 5 lines
target-ppc/translate.c +1
-1@@ -4836,7 +4836,7 @@ static void gen_tlbia(DisasContext *ctx)#if defined(CONFIG_USER_ONLY )gen_inval_exception (ctx,POWERPC_EXCP_PRIV_OPC );#else -if (unlikely (ctx->pr)) { +if (unlikely (ctx->pr || !ctx->hv)) {
If I'm reading your previous patch correctly, ctx->hv won't be set with in problem state, so I think the ctx->pr check is redundant.
Quoted 21 lines
target-ppc/translate.c +2
-2gen_inval_exception (ctx,POWERPC_EXCP_PRIV_OPC );return ; }@@ -4850,7 +4850,7 @@ static void gen_tlbiel(DisasContext *ctx)#if defined(CONFIG_USER_ONLY )gen_inval_exception (ctx,POWERPC_EXCP_PRIV_OPC );#else -if (unlikely (ctx->pr)) { +if (unlikely (ctx->pr || !ctx->hv)) {gen_inval_exception (ctx,POWERPC_EXCP_PRIV_OPC );return ; }@@ -4864,7 +4864,7 @@ static void gen_tlbie(DisasContext *ctx)#if defined(CONFIG_USER_ONLY )gen_inval_exception (ctx,POWERPC_EXCP_PRIV_OPC );#else -if (unlikely (ctx->pr)) { +if (unlikely (ctx->pr || !ctx->hv)) {gen_inval_exception (ctx,POWERPC_EXCP_PRIV_OPC );return ; }
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [Qemu-ppc] [PATCH 13/77] ppc: tlbie, tlbia and tlbisync are HV only
Quoted 9 lines · David Gibson
Quoted 7 lines · Benjamin Herrenschmidt
Not that anything remotely recent supports tlbia but ...
Signed-off-by Benjamin Herrenschmidt <[email protected]>---
target-ppc/translate.c | 6 +++---1 file changed, 3 insertions(+), 3 deletions(-)
Quoted 13 lines
target-ppc/translate.c static void gen_tlbia(DisasContext *ctx) · line 4839
Quoted 10 lines
target-ppc/translate.c +1
-1@@ -4836,7 +4836,7 @@ static void gen_tlbia(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(ctx->pr)) { + if (unlikely(ctx->pr || !ctx->hv)) {If I'm reading your previous patch correctly,
ctx->hvwon't be set with in problem state, so I think thectx->prcheck is redundant.
Ah you are right. I do have second thoughts about that previous patch now that you mention it however. In the real MSR, HV and PR are independant, I wonder if I'm better off making the check explicit...
The reason I did it this way is that afaik, there is no such thing as a usermode hypervisor resource in the architecture, so any hypervisor resource is also a supervisor mode one, but having ctx->hv be 0 when MSR:HV=1 + MSR:PR=1 might make it easy to write incorrect code in other places when deciding for example how to direct interrupts.
I'll need to think a bit more about this one.
Quoted 22 lines
Quoted 21 lines
target-ppc/translate.c +2
-2gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; }@@ -4850,7 +4850,7 @@ static void gen_tlbiel(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(ctx->pr)) { + if (unlikely(ctx->pr || !ctx->hv)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; }@@ -4864,7 +4864,7 @@ static void gen_tlbie(DisasContext *ctx) #if defined(CONFIG_USER_ONLY) gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); #else - if (unlikely(ctx->pr)) { + if (unlikely(ctx->pr || !ctx->hv)) { gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); return; }
Re: [Qemu-devel] [Qemu-ppc] [PATCH 13/77] ppc: tlbie, tlbia and tlbisync are HV only
Quoted 13 lines · Benjamin Herrenschmidt
Ah you are right. I do have second thoughts about that previous patch now that you mention it however. In the real MSR, HV and PR are independant, I wonder if I'm better off making the check explicit...
The reason I did it this way is that afaik, there is no such thing as a usermode hypervisor resource in the architecture, so any hypervisor resource is also a supervisor mode one, but having
ctx->hvbe 0 when MSR:HV=1 + MSR:PR=1 might make it easy to write incorrect code in other places when deciding for example how to direct
interrupts.
Quoted 1 line
I'll need to think a bit more about this one.
So I took out that bit in the previous patch, since we already seem to check ctx.pr explicitly in most places anyway. There was one where we didn't which I fixed (in the SMT ops).
Cheers,
Ben.
PATCH 14/77 ppc: Change 'invalid' bit mask of tlbiel and tlbie
In reply to Benjamin HerrenschmidtOtherwise it will trip on the forms used in recent architecture.
Ideally, we should have different handlers for different architecture levels but our current implementation of TLB flushing is dumb enough that this will do for now.
--- target-ppc/translate.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
target-ppc/translate.c +4 -2
@@ -9952,8 +9952,10 @@ GEN_HANDLER2(slbmfee, "slbmfee", 0x1F, 0x13, 0x1C, 0x001F0001, PPC_SEGMENT_64B), GEN_HANDLER2(slbmfev, "slbmfev", 0x1F, 0x13, 0x1A, 0x001F0001, PPC_SEGMENT_64B), #endif GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA), -GEN_HANDLER(tlbiel, 0x1F, 0x12, 0x08, 0x03FF0001, PPC_MEM_TLBIE), -GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM_TLBIE), +/* XXX Those instructions will need to be handled differently for + * different ISA versions */ +GEN_HANDLER(tlbiel, 0x1F, 0x12, 0x08, 0x001F0001, PPC_MEM_TLBIE), +GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x001F0001, PPC_MEM_TLBIE), GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM_TLBSYNC), #if defined(TARGET_PPC64) GEN_HANDLER(slbia, 0x1F, 0x12, 0x0F, 0x03FFFC01, PPC_SLBI),
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 14/77] ppc: Change 'invalid' bit mask of tlbiel and tlbie
Quoted 7 lines · Benjamin Herrenschmidt
Otherwise it will trip on the forms used in recent architecture.
Ideally, we should have different handlers for different architecture levels but our current implementation of TLB flushing is dumb enough that this will do for now.
Signed-off-by Benjamin Herrenschmidt <[email protected]>
Quoted 21 lines
--- target-ppc/translate.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)target-ppc/translate.c +4
-2@@ -9952,8 +9952,10 @@ GEN_HANDLER2(slbmfee, "slbmfee", 0x1F, 0x13, 0x1C, 0x001F0001, PPC_SEGMENT_64B), GEN_HANDLER2(slbmfev, "slbmfev", 0x1F, 0x13, 0x1A, 0x001F0001, PPC_SEGMENT_64B), #endif GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA), -GEN_HANDLER(tlbiel, 0x1F, 0x12, 0x08, 0x03FF0001, PPC_MEM_TLBIE), -GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM_TLBIE), +/* XXX Those instructions will need to be handled differently for + * different ISA versions */ +GEN_HANDLER(tlbiel, 0x1F, 0x12, 0x08, 0x001F0001, PPC_MEM_TLBIE), +GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x001F0001, PPC_MEM_TLBIE), GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM_TLBSYNC), #if defined(TARGET_PPC64) GEN_HANDLER(slbia, 0x1F, 0x12, 0x0F, 0x03FFFC01, PPC_SLBI),
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 15/77 ppc: Fix sign extension issue in mtmsr(d) emulation
In reply to Benjamin HerrenschmidtFrom: Michael Neuling <[email protected]>
--- target-ppc/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
target-ppc/translate.c +2 -2
@@ -4391,7 +4391,7 @@ static void gen_mtmsrd(DisasContext *ctx)/* Special form that does not need any synchronisation */ TCGv t0 =tcg_temp_new ();tcg_gen_andi_tl (t0, cpu_gpr[rS (ctx->opcode)], (1 <<MSR_RI ) | (1 <<MSR_EE )); -tcg_gen_andi_tl (cpu_msr, cpu_msr, ~((1 <<MSR_RI ) | (1 <<MSR_EE ))); +tcg_gen_andi_tl (cpu_msr, cpu_msr, ~(target_ulong)((1 <<MSR_RI ) | (1 <<MSR_EE )));tcg_gen_or_tl (cpu_msr, cpu_msr, t0);tcg_temp_free (t0); }else {
@@ -4422,7 +4422,7 @@ static void gen_mtmsr(DisasContext *ctx)/* Special form that does not need any synchronisation */ TCGv t0 =tcg_temp_new ();tcg_gen_andi_tl (t0, cpu_gpr[rS (ctx->opcode)], (1 <<MSR_RI ) | (1 <<MSR_EE )); -tcg_gen_andi_tl (cpu_msr, cpu_msr, ~((1 <<MSR_RI ) | (1 <<MSR_EE ))); +tcg_gen_andi_tl (cpu_msr, cpu_msr, ~(target_ulong)((1 <<MSR_RI ) | (1 <<MSR_EE )));tcg_gen_or_tl (cpu_msr, cpu_msr, t0);tcg_temp_free (t0); }else {
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 15/77] ppc: Fix sign extension issue in mtmsr(d) emulation
Quoted 4 lines · Benjamin Herrenschmidt
From: Michael Neuling <[email protected]>
Signed-off-by Michael Neuling <[email protected]>Signed-off-by Benjamin Herrenschmidt <[email protected]>
Looks correct, though my memory of C promotion rules is obviously a bit stale, since I'm not immediately seeing why the original was wrong.
Quoted 26 lines
--- target-ppc/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)target-ppc/translate.c +2
-2@@ -4391,7 +4391,7 @@ static void gen_mtmsrd(DisasContext *ctx)/* Special form that does not need any synchronisation */ TCGv t0 =tcg_temp_new ();tcg_gen_andi_tl (t0, cpu_gpr[rS (ctx->opcode)], (1 <<MSR_RI ) | (1 <<MSR_EE )); -tcg_gen_andi_tl (cpu_msr, cpu_msr, ~((1 <<MSR_RI ) | (1 <<MSR_EE ))); +tcg_gen_andi_tl (cpu_msr, cpu_msr, ~(target_ulong)((1 <<MSR_RI ) | (1 <<MSR_EE )));tcg_gen_or_tl (cpu_msr, cpu_msr, t0);tcg_temp_free (t0); }else {@@ -4422,7 +4422,7 @@ static void gen_mtmsr(DisasContext *ctx)/* Special form that does not need any synchronisation */ TCGv t0 =tcg_temp_new ();tcg_gen_andi_tl (t0, cpu_gpr[rS (ctx->opcode)], (1 <<MSR_RI ) | (1 <<MSR_EE )); -tcg_gen_andi_tl (cpu_msr, cpu_msr, ~((1 <<MSR_RI ) | (1 <<MSR_EE ))); +tcg_gen_andi_tl (cpu_msr, cpu_msr, ~(target_ulong)((1 <<MSR_RI ) | (1 <<MSR_EE )));tcg_gen_or_tl (cpu_msr, cpu_msr, t0);tcg_temp_free (t0); }else {
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [Qemu-ppc] [PATCH 15/77] ppc: Fix sign extension issue in mtmsr(d) emulation
Quoted 4 lines · David Gibson
Quoted 2 lines · Benjamin Herrenschmidt
From: Michael Neuling <[email protected]>
Quoted 8 lines
Quoted 2 lines
Signed-off-by Michael Neuling <[email protected]>Signed-off-by Benjamin Herrenschmidt <[email protected]>Reviewed-by David Gibson <[email protected]>Looks correct, though my memory of C promotion rules is obviously a bit stale, since I'm not immediately seeing why the original was wrong.
Well, at least it makes things work :-)
Quoted 33 lines
Quoted 32 lines
---
target-ppc/translate.c | 4 ++--1 file changed, 2 insertions(+), 2 deletions(-)target-ppc/translate.c +0
-0@@ -4391,7 +4391,7 @@ static void gen_mtmsrd(DisasContext *ctx) /* Special form that does not need any synchronisation */ TCGv t0 = tcg_temp_new();tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], (1 <<
MSR_RI) | (1 <<MSR_EE));
- tcg_gen_andi_tl(cpu_msr,cpu_msr, ~((1 <<MSR_RI) | (1 <<MSR_EE)));
+ tcg_gen_andi_tl(cpu_msr,cpu_msr, ~(target_ulong)((1 <<MSR_RI) | (1 <<MSR_EE)));
tcg_gen_or_tl(cpu_msr,cpu_msr, t0);tcg_temp_free(t0);
} else {target-ppc/translate.c +0
-0@@ -4422,7 +4422,7 @@ static void gen_mtmsr(DisasContext *ctx) /* Special form that does not need any synchronisation */ TCGv t0 = tcg_temp_new();tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], (1 <<
MSR_RI) | (1 <<MSR_EE));
- tcg_gen_andi_tl(cpu_msr,cpu_msr, ~((1 <<MSR_RI) | (1 <<MSR_EE)));
+ tcg_gen_andi_tl(cpu_msr,cpu_msr, ~(target_ulong)((1 <<MSR_RI) | (1 <<MSR_EE)));
tcg_gen_or_tl(cpu_msr,cpu_msr, t0);tcg_temp_free(t0);
} else {
PATCH 16/77 ppc: Get out of emulation on SMT "OR" ops
In reply to Benjamin HerrenschmidtOtherwise tight loops at smt_low for example, which OPAL does, eat so much CPU that we can't boot a kernel anymore. With that, I can boot 8 CPUs just fine with powernv.
--- target-ppc/translate.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)
target-ppc/translate.c +17 -2
@@ -1396,6 +1396,19 @@ GEN_LOGICAL2(nand, tcg_gen_nand_tl, 0x0E, PPC_INTEGER);/* nor & nor. */ GEN_LOGICAL2 (nor, tcg_gen_nor_tl,0x03 ,PPC_INTEGER ); +#if defined(TARGET_PPC64 ) +static void gen_pause (DisasContext *ctx) +{ +TCGv_i32 t0 =tcg_const_i32 (0 ); +tcg_gen_st_i32 (t0, cpu_env, + -offsetof(PowerPCCPU , env) + offsetof(CPUState , halted)); +tcg_temp_free_i32 (t0); + +/* Stop translation, this gives other CPUs a chance to run */ +gen_exception_err (ctx,EXCP_HLT ,1 ); +} +#endif /* defined(TARGET_PPC64) */ +/* or & or. */ static void gen_or (DisasContext *ctx) {
@@ -1468,6 +1481,10 @@ static void gen_or(DisasContext *ctx)tcg_gen_ori_tl (t0, t0, ((uint64_t )prio) <<50 );gen_store_spr (SPR_PPR , t0);tcg_temp_free (t0); +/* Pause us out of TCG otherwise spin loops with smt_low +* eat too much CPU and the kernel hangs +*/ + gen_pause(ctx); }#endif }
@@ -1493,8 +1510,6 @@ static void gen_ori(DisasContext *ctx)target_ulong uimm =UIMM (ctx->opcode);if (rS (ctx->opcode) ==rA (ctx->opcode) && uimm ==0 ) { -/* NOP */ -/* XXX: should handle special NOPs for POWER series */ return ; }tcg_gen_ori_tl (cpu_gpr[rA (ctx->opcode)], cpu_gpr[rS (ctx->opcode)], uimm);
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 16/77] ppc: Get out of emulation on SMT "OR" ops
Quoted 5 lines · Benjamin Herrenschmidt
Otherwise tight loops at
smt_lowfor example, which OPAL does, eat so much CPU that we can't boot a kernel anymore. With that, I can boot 8 CPUs just fine with powernv.Signed-off-by Benjamin Herrenschmidt <[email protected]>
Quoted 48 lines
--- target-ppc/translate.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)target-ppc/translate.c +17
-2@@ -1396,6 +1396,19 @@ GEN_LOGICAL2(nand, tcg_gen_nand_tl, 0x0E, PPC_INTEGER);/* nor & nor. */ GEN_LOGICAL2 (nor, tcg_gen_nor_tl,0x03 ,PPC_INTEGER ); +#if defined(TARGET_PPC64 ) +static void gen_pause (DisasContext *ctx) +{ +TCGv_i32 t0 =tcg_const_i32 (0 ); +tcg_gen_st_i32 (t0, cpu_env, + -offsetof(PowerPCCPU , env) + offsetof(CPUState , halted)); +tcg_temp_free_i32 (t0); + +/* Stop translation, this gives other CPUs a chance to run */ +gen_exception_err (ctx,EXCP_HLT ,1 ); +} +#endif /* defined(TARGET_PPC64) */ +/* or & or. */ static void gen_or (DisasContext *ctx) {@@ -1468,6 +1481,10 @@ static void gen_or(DisasContext *ctx)tcg_gen_ori_tl (t0, t0, ((uint64_t )prio) <<50 );gen_store_spr (SPR_PPR , t0);tcg_temp_free (t0); +/* Pause us out of TCG otherwise spin loops with smt_low +* eat too much CPU and the kernel hangs +*/ + gen_pause(ctx); }#endif }@@ -1493,8 +1510,6 @@ static void gen_ori(DisasContext *ctx)target_ulong uimm =UIMM (ctx->opcode);if (rS (ctx->opcode) ==rA (ctx->opcode) && uimm ==0 ) { -/* NOP */ -/* XXX: should handle special NOPs for POWER series */ return ; }tcg_gen_ori_tl (cpu_gpr[rA (ctx->opcode)], cpu_gpr[rS (ctx->opcode)], uimm);
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 17/77 ppc: Add PPC_64H instruction flag to POWER7 and POWER8
In reply to Benjamin HerrenschmidtThis will enable decoding of hrfid
--- target-ppc/translate_init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
target-ppc/translate_init.c +2 -2
@@ -8303,7 +8303,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)PPC_CACHE |PPC_CACHE_ICBI |PPC_CACHE_DCBZ |PPC_MEM_SYNC |PPC_MEM_EIEIO |PPC_MEM_TLBIE |PPC_MEM_TLBSYNC | -PPC_64B |PPC_ALTIVEC | +PPC_64B |PPC_64H |PPC_ALTIVEC |PPC_SEGMENT_64B |PPC_SLBI |PPC_POPCNTB |PPC_POPCNTWD ; pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX | PPC2_ISA205 |
@@ -8380,7 +8380,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)PPC_CACHE |PPC_CACHE_ICBI |PPC_CACHE_DCBZ |PPC_MEM_SYNC |PPC_MEM_EIEIO |PPC_MEM_TLBIE |PPC_MEM_TLBSYNC | -PPC_64B |PPC_64BX |PPC_ALTIVEC | +PPC_64B |PPC_64H |PPC_64BX |PPC_ALTIVEC |PPC_SEGMENT_64B |PPC_SLBI |PPC_POPCNTB |PPC_POPCNTWD ; pcc->insns_flags2 = PPC2_VSX | PPC2_VSX207 | PPC2_DFP | PPC2_DBRX |
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 17/77] ppc: Add PPC_64H instruction flag to POWER7 and POWER8
Quoted 3 lines · Benjamin Herrenschmidt
This will enable decoding of hrfid
Signed-off-by Benjamin Herrenschmidt <[email protected]>
Quoted 26 lines
--- target-ppc/translate_init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)target-ppc/translate_init.c +2
-2@@ -8303,7 +8303,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)PPC_CACHE |PPC_CACHE_ICBI |PPC_CACHE_DCBZ |PPC_MEM_SYNC |PPC_MEM_EIEIO |PPC_MEM_TLBIE |PPC_MEM_TLBSYNC | -PPC_64B |PPC_ALTIVEC | +PPC_64B |PPC_64H |PPC_ALTIVEC |PPC_SEGMENT_64B |PPC_SLBI |PPC_POPCNTB |PPC_POPCNTWD ; pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX | PPC2_ISA205 |@@ -8380,7 +8380,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)PPC_CACHE |PPC_CACHE_ICBI |PPC_CACHE_DCBZ |PPC_MEM_SYNC |PPC_MEM_EIEIO |PPC_MEM_TLBIE |PPC_MEM_TLBSYNC | -PPC_64B |PPC_64BX |PPC_ALTIVEC | +PPC_64B |PPC_64H |PPC_64BX |PPC_ALTIVEC |PPC_SEGMENT_64B |PPC_SLBI |PPC_POPCNTB |PPC_POPCNTWD ; pcc->insns_flags2 = PPC2_VSX | PPC2_VSX207 | PPC2_DFP | PPC2_DBRX |
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 18/77 ppc: Rework POWER7 & POWER8 exception model
In reply to Benjamin HerrenschmidtProperly implement LPES0/1 handling for HV vs. !HV mode and fix AIL implementation.
--- target-ppc/cpu.h | 2 + target-ppc/excp_helper.c | 175 ++++++++++++++++++++++---------------------- target-ppc/translate_init.c | 2 +- 3 files changed, 92 insertions(+), 87 deletions(-)
target-ppc/cpu.h +2 -0
@@ -162,6 +162,8 @@ enum powerpc_excp_t {POWERPC_EXCP_970 ,/* POWER7 exception model */ POWERPC_EXCP_POWER7 , +/* POWER8 exception model */ + POWERPC_EXCP_POWER8, #endif /* defined(TARGET_PPC64) */ };
target-ppc/excp_helper.c +89 -86
348 lines not on this page · raw message
target-ppc/translate_init.c +1 -1
@@ -8412,7 +8412,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)#if defined(CONFIG_SOFTMMU ) pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;#endif - pcc->excp_model =POWERPC_EXCP_POWER7 ; + pcc->excp_model =POWERPC_EXCP_POWER8 ; pcc->bus_model =PPC_FLAGS_INPUT_POWER7 ; pcc->bfd_mach = bfd_mach_ppc64; pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE |
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 18/77] ppc: Rework POWER7 & POWER8 exception model
Quoted 54 lines · Benjamin Herrenschmidt
Properly implement LPES0/1 handling for HV vs. !HV mode and fix AIL implementation.
Signed-off-by Benjamin Herrenschmidt <[email protected]>--- target-ppc/cpu.h | 2 + target-ppc/excp_helper.c | 175 ++++++++++++++++++++++---------------------- target-ppc/translate_init.c | 2 +- 3 files changed, 92 insertions(+), 87 deletions(-)target-ppc/cpu.h +2
-0@@ -162,6 +162,8 @@ enum powerpc_excp_t {POWERPC_EXCP_970 ,/* POWER7 exception model */ POWERPC_EXCP_POWER7 , +/* POWER8 exception model */ + POWERPC_EXCP_POWER8, #endif /* defined(TARGET_PPC64) */ };target-ppc/excp_helper.c +3
-11@@ -74,22 +74,14 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)CPUState *cs =CPU (cpu);CPUPPCState *env = &cpu->env;target_ulong msr, new_msr, vector; -int srr0, srr1, asrr0, asrr1; -int lpes0, lpes1, lev; +int srr0, srr1, asrr0, asrr1, lev, ail; +bool lpes0; -if (0 ) { -/* XXX: find a suitable condition to enable the hypervisor mode */ - lpes0 = (env->spr[SPR_LPCR ] >>1 ) &1 ; - lpes1 = (env->spr[SPR_LPCR ] >>2 ) &1 ; - }else { -/* Those values ensure we won't enter the hypervisor mode */ - lpes0 =0 ; - lpes1 =1 ; - }qemu_log_mask (CPU_LOG_INT ,"Raise exception at " TARGET_FMT_lx" => %08x (%02x)\n" , env->nip, excp, env->error_code); +/* new srr1 value excluding must-be-zero bits */ if (excp_model ==POWERPC_EXCP_BOOKE ) { msr = env->msr;
target-ppc/excp_helper.c static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) · line 95
Quoted 9 lines
target-ppc/excp_helper.c +4
-2@@ -97,8 +89,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) msr = env->msr & ~0x783f0000ULL ; } -/* new interrupt handler msr */ - new_msr = env->msr & ((target_ulong )1 <<MSR_ME ); +/* new interrupt handler msr preserves existing HV and ME unless +* explicitly overriden +*/ + new_msr = env->msr & (((target_ulong )1 <<MSR_ME ) |MSR_HVB );
Ouch. The fact that MSR_ME is a bit number, but MSR_HVB is a mask is certainly confusing, but that's a pre-existing problem.
Quoted 180 lines
target-ppc/excp_helper.c +38
-44/* target registers */ srr0 =SPR_SRR0 ;@@ -106,6 +100,33 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) asrr0 =-1 ; asrr1 =-1 ; +/* Exception targetting modifiers +* +* LPES0 is supported on POWER7/8 +* LPES1 is not supported (old iSeries mode) +* +* On anything else, we behave as if LPES0 is 1 +* (externals don't alter MSR:HV) +* +* AIL is initialized here but can be cleared by +* selected exceptions +*/ +#if defined(TARGET_PPC64 ) +if (excp_model ==POWERPC_EXCP_POWER7 || + excp_model ==POWERPC_EXCP_POWER8 ) { + lpes0 = !!(env->spr[SPR_LPCR ] &LPCR_LPES0 ); +if (excp_model ==POWERPC_EXCP_POWER8 ) { + ail = (env->spr[SPR_LPCR ] &LPCR_AIL ) >>LPCR_AIL_SHIFT ; + }else { + ail =0 ; + } + } else +#endif /* defined(TARGET_PPC64) */ + { + lpes0 = true; + ail =0 ; + } +switch (excp) {case POWERPC_EXCP_NONE :/* Should never happen */ @@ -141,10 +162,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) cs->halted =1 ; cs->interrupt_request |=CPU_INTERRUPT_EXITTB ; } -if (0 ) { -/* XXX: find a suitable condition to enable the hypervisor mode */ - new_msr |= (target_ulong )MSR_HVB ; - } + new_msr |= (target_ulong )MSR_HVB ; + ail =0 ;/* machine check exceptions don't have ME set */ new_msr &= ~((target_ulong )1 <<MSR_ME );@@ -169,23 +188,20 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)case POWERPC_EXCP_DSI :/* Data storage exception */ LOG_EXCP ("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx"\n" , env->spr[SPR_DSISR ], env->spr[SPR_DAR ]); -if (lpes1 ==0 ) { - new_msr |= (target_ulong )MSR_HVB ; - } goto store_next;case POWERPC_EXCP_ISI :/* Instruction storage exception */ LOG_EXCP ("ISI exception: msr=" TARGET_FMT_lx", nip=" TARGET_FMT_lx"\n" , msr, env->nip); -if (lpes1 ==0 ) { - new_msr |= (target_ulong )MSR_HVB ; - } msr |= env->error_code; goto store_next;case POWERPC_EXCP_EXTERNAL :/* External input */ cs =CPU (cpu); -if (lpes0 ==1 ) { +if (!lpes0) { new_msr |= (target_ulong )MSR_HVB ; + new_msr |= env->msr & ((target_ulong )1 <<MSR_RI ); + srr0 =SPR_HSRR0 ; + srr1 =SPR_HSRR1 ; }if (env->mpic_proxy) {/* IACK the IRQ on delivery */ @@ -193,9 +209,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) } goto store_next;case POWERPC_EXCP_ALIGN :/* Alignment exception */ -if (lpes1 ==0 ) { - new_msr |= (target_ulong )MSR_HVB ; - }/* XXX: this is false */ /* Get rS/rD and rA from faulting opcode */ env->spr[SPR_DSISR] |= (cpu_ldl_code(env, (env->nip - 4))@@ -210,9 +223,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) env->error_code =0 ;return ; } -if (lpes1 ==0 ) { - new_msr |= (target_ulong )MSR_HVB ; - } msr |=0x00100000 ;if (msr_fe0 == msr_fe1) { goto store_next;@@ -221,23 +231,14 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)break ;case POWERPC_EXCP_INVAL :LOG_EXCP ("Invalid instruction at " TARGET_FMT_lx"\n" , env->nip); -if (lpes1 ==0 ) { - new_msr |= (target_ulong )MSR_HVB ; - } msr |=0x00080000 ; env->spr[SPR_BOOKE_ESR ] =ESR_PIL ;break ;case POWERPC_EXCP_PRIV : -if (lpes1 ==0 ) { - new_msr |= (target_ulong )MSR_HVB ; - } msr |=0x00040000 ; env->spr[SPR_BOOKE_ESR ] =ESR_PPR ;break ;case POWERPC_EXCP_TRAP : -if (lpes1 ==0 ) { - new_msr |= (target_ulong )MSR_HVB ; - } msr |=0x00020000 ; env->spr[SPR_BOOKE_ESR ] =ESR_PTR ;break ;@@ -249,27 +250,23 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) } goto store_current;case POWERPC_EXCP_FPU :/* Floating-point unavailable exception */ -if (lpes1 ==0 ) { - new_msr |= (target_ulong )MSR_HVB ; - } goto store_current;case POWERPC_EXCP_SYSCALL :/* System call exception */ dump_syscall (env); lev = env->error_code; + +/* "PAPR mode" built-in hypercall emulation */ if ((lev ==1 ) && cpu_ppc_hypercall) {cpu_ppc_hypercall (cpu);return ; } -if (lev ==1 || (lpes0 ==0 && lpes1 ==0 )) { +if (lev ==1 ) { new_msr |= (target_ulong )MSR_HVB ; } goto store_next;case POWERPC_EXCP_APU :/* Auxiliary processor unavailable */ goto store_current;case POWERPC_EXCP_DECR :/* Decrementer exception */ -if (lpes1 ==0 ) { - new_msr |= (target_ulong )MSR_HVB ; - } goto store_next;case POWERPC_EXCP_FIT :/* Fixed-interval timer interrupt */ /* FIT on 4xx */ @@ -338,21 +335,12 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) }else { new_msr &= ~((target_ulong )1 <<MSR_ME ); } - -if (0 ) { -/* XXX: find a suitable condition to enable the hypervisor mode */ - new_msr |= (target_ulong )MSR_HVB ; - } + new_msr |= (target_ulong )MSR_HVB ; + ail =0 ; goto store_next;case POWERPC_EXCP_DSEG :/* Data segment exception */ -if (lpes1 ==0 ) { - new_msr |= (target_ulong )MSR_HVB ; - } goto store_next;case POWERPC_EXCP_ISEG :/* Instruction segment exception */ -if (lpes1 ==0 ) { - new_msr |= (target_ulong )MSR_HVB ; - } goto store_next;case POWERPC_EXCP_HDECR :/* Hypervisor decrementer exception */ srr0 =SPR_HSRR0 ;@@ -361,21 +349,20 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) new_msr |= env->msr & ((target_ulong )1 <<MSR_RI ); goto store_next;case POWERPC_EXCP_TRACE :/* Trace exception */
target-ppc/excp_helper.c static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) · line 358
Quoted 10 lines
target-ppc/excp_helper.c +1
-3-if (lpes1 ==0 ) { - new_msr |= (target_ulong )MSR_HVB ; - } goto store_next;case POWERPC_EXCP_HDSI :/* Hypervisor data storage exception */ srr0 =SPR_HSRR0 ; srr1 =SPR_HSRR1 ; new_msr |= (target_ulong )MSR_HVB ; new_msr |= env->msr & ((target_ulong )1 <<MSR_RI ); + ail =0 ;
Do you need to set ail explicitly here, given the general ail logic below?
Quoted 153 lines
target-ppc/excp_helper.c +43
-26goto store_next;case POWERPC_EXCP_HISI :/* Hypervisor instruction storage exception */ srr0 =SPR_HSRR0 ; srr1 =SPR_HSRR1 ; new_msr |= (target_ulong )MSR_HVB ; new_msr |= env->msr & ((target_ulong )1 <<MSR_RI ); + ail =0 ; goto store_next;case POWERPC_EXCP_HDSEG :/* Hypervisor data segment exception */ srr0 =SPR_HSRR0 ;@@ -390,19 +377,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) new_msr |= env->msr & ((target_ulong )1 <<MSR_RI ); goto store_next;case POWERPC_EXCP_VPU :/* Vector unavailable exception */ -if (lpes1 ==0 ) { - new_msr |= (target_ulong )MSR_HVB ; - } goto store_current;case POWERPC_EXCP_VSXU :/* VSX unavailable exception */ -if (lpes1 ==0 ) { - new_msr |= (target_ulong )MSR_HVB ; - } goto store_current;case POWERPC_EXCP_FU :/* Facility unavailable exception */ -if (lpes1 ==0 ) { - new_msr |= (target_ulong )MSR_HVB ; - } goto store_current;case POWERPC_EXCP_PIT :/* Programmable interval timer interrupt */ LOG_EXCP ("PIT exception\n" );@@ -421,9 +399,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) "is not implemented yet !\n"); goto store_next;case POWERPC_EXCP_IFTLB :/* Instruction fetch TLB error */ -if (lpes1 ==0 ) {/* XXX: check this */ - new_msr |= (target_ulong )MSR_HVB ; - }switch (excp_model) {case POWERPC_EXCP_602 :case POWERPC_EXCP_603 :@@ -440,9 +415,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) }break ;case POWERPC_EXCP_DLTLB :/* Data load TLB miss */ -if (lpes1 ==0 ) {/* XXX: check this */ - new_msr |= (target_ulong )MSR_HVB ; - }switch (excp_model) {case POWERPC_EXCP_602 :case POWERPC_EXCP_603 :@@ -459,9 +431,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) }break ;case POWERPC_EXCP_DSTLB :/* Data store TLB miss */ -if (lpes1 ==0 ) {/* XXX: check this */ - new_msr |= (target_ulong )MSR_HVB ; - }switch (excp_model) {case POWERPC_EXCP_602 :case POWERPC_EXCP_603 :@@ -567,9 +536,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) "is not implemented yet !\n"); goto store_next;case POWERPC_EXCP_PERFM :/* Embedded performance monitor interrupt */ -if (lpes1 ==0 ) { - new_msr |= (target_ulong )MSR_HVB ; - }/* XXX: TODO */ cpu_abort (cs,"Performance counter exception is not implemented yet !\n" );@@ -613,6 +579,12 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) }/* Save MSR */ env->spr[srr1] = msr; + +/* Sanity check */ +if (!(env->msr_mask &MSR_HVB ) && (srr0 ==SPR_HSRR0 )) { +cpu_abort (cs,"Trying to deliver HV exception %d with no HV support\n" , excp); + } +/* If any alternate SRR register are defined, duplicate saved values */ if (asrr0 !=-1 ) { env->spr[asrr0] = env->spr[srr0];@@ -621,13 +593,20 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) env->spr[asrr1] = env->spr[srr1]; } -if (env->spr[SPR_LPCR ] &LPCR_AIL ) { - new_msr |= (1 <<MSR_IR ) | (1 <<MSR_DR ); - } - +/* Sort out endianness of interrupt, this differs depending on the +* CPU, the HV mode, etc... +*/ #ifdef TARGET_PPC64 if (excp_model == POWERPC_EXCP_POWER7) { -if (env->spr[SPR_LPCR ] &LPCR_ILE ) { + if (!(new_msr & MSR_HVB) && (env->spr[SPR_LPCR] & LPCR_ILE)) { + new_msr |= (target_ulong)1 << MSR_LE; + } + } else if (excp_model == POWERPC_EXCP_POWER8) { + if (new_msr & MSR_HVB) { + if (env->spr[SPR_HID0] & HID0_HILE) { + new_msr |= (target_ulong)1 << MSR_LE; + } + } else if (env->spr[SPR_LPCR] & LPCR_ILE) { new_msr |= (target_ulong)1 << MSR_LE; } } else if (msr_ile) {@@ -646,6 +625,30 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) excp); } vector |= env->excp_prefix; + +/* AIL only works if there is no HV transition and we are running with +* translations enabled +*/ +if (!((msr >>MSR_IR ) &1 ) || !((msr >>MSR_DR ) &1 ) || + ((new_msr &MSR_HVB ) && !(msr &MSR_HVB ))) { + ail =0 ; + } +/* Handle AIL */ +if (ail) { + new_msr |= (1 <<MSR_IR ) | (1 <<MSR_DR ); +switch (ail) { +case 2 : + vector |=0x18000 ; +break ; +case 3 : + vector |=0xc000000000004000ull ; +break ; +default : +cpu_abort (cs,"Invalid AIL combination %d\n" , ail); +break ; + } + } +#if defined(TARGET_PPC64 )if (excp_model ==POWERPC_EXCP_BOOKE ) {if (env->spr[SPR_BOOKE_EPCR ] &EPCR_ICM ) {target-ppc/translate_init.c +1
-1@@ -8412,7 +8412,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)#if defined(CONFIG_SOFTMMU ) pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;#endif - pcc->excp_model =POWERPC_EXCP_POWER7 ; + pcc->excp_model =POWERPC_EXCP_POWER8 ; pcc->bus_model =PPC_FLAGS_INPUT_POWER7 ; pcc->bfd_mach = bfd_mach_ppc64; pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE |
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [Qemu-ppc] [PATCH 18/77] ppc: Rework POWER7 & POWER8 exception model
Quoted 10 lines · David Gibson
Quoted 7 lines
- /* new interrupt handler msr */
- new_msr =env->msr& ((target_ulong)1 <<MSR_ME);
+ /* new interrupt handler msr preserves existing HV and ME unless + * explicitly overriden
+ */
+ new_msr =env->msr& (((target_ulong)1 <<MSR_ME) |MSR_HVB);Ouch. The fact that
MSR_MEis a bit number, butMSR_HVBis a mask is certainly confusing, but that's a pre-existing problem.
That shit bit me more than once indeed, but it's a fix for another day.
.../...
Quoted 9 lines
Quoted 7 lines
case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */ srr0 =
SPR_HSRR0;
srr1 =SPR_HSRR1;
new_msr |= (target_ulong)MSR_HVB;
new_msr |=env->msr& ((target_ulong)1 <<MSR_RI);
+ ail = 0;Do you need to set ail explicitly here, given the general ail logic below?
Not on this indeed. I think that's a remnant of how that patch evolved. We do need to clear unconditionally on other things like machine checks, I'll give that another sweep.
Cheers,
Ben.
PATCH 19/77 ppc: Fix POWER7 and POWER8 exception definitions
In reply to Benjamin HerrenschmidtWe were initializing unused ones and missing some
--- target-ppc/cpu.h | 11 ++++++++++- target-ppc/translate_init.c | 27 +++++++++++++++++++++------ 2 files changed, 31 insertions(+), 7 deletions(-)
target-ppc/cpu.h +10 -1
@@ -200,6 +200,9 @@ enum { POWERPC_EXCP_HYPPRIV = 41, /* Embedded hypervisor priv instruction *//* Vectors 42 to 63 are reserved */ /* Exceptions defined in the PowerPC server specification */ +/* Server doorbell variants */ +#define POWERPC_EXCP_SDOOR POWERPC_EXCP_GDOORI +#define POWERPC_EXCP_SDOOR_HV POWERPC_EXCP_DOORIPOWERPC_EXCP_RESET =64 ,/* System reset exception */ POWERPC_EXCP_DSEG =65 ,/* Data segment exception */ POWERPC_EXCP_ISEG = 66, /* Instruction segment exception */
@@ -242,8 +245,12 @@ enum {/* VSX Unavailable (Power ISA 2.06 and later) */ POWERPC_EXCP_VSXU =94 ,/* VSX Unavailable */ POWERPC_EXCP_FU =95 ,/* Facility Unavailable */ +/* Additional ISA 2.06 and later server exceptions */ +POWERPC_EXCP_HV_EMU =96 ,/* HV emulation assistance */ +POWERPC_EXCP_HV_MAINT =97 ,/* HMI */ +POWERPC_EXCP_HV_FU =98 ,/* Hypervisor Facility unavailable */ /* EOL */ -POWERPC_EXCP_NB =96 , +POWERPC_EXCP_NB =99 ,/* QEMU exceptions: used internally during code translation */ POWERPC_EXCP_STOP =0x200 ,/* stop translation */ POWERPC_EXCP_BRANCH = 0x201, /* branch instruction */
@@ -2197,6 +2204,8 @@ enum {PPC_INTERRUPT_CDOORBELL ,/* Critical doorbell interrupt */ PPC_INTERRUPT_DOORBELL ,/* Doorbell interrupt */ PPC_INTERRUPT_PERFM ,/* Performance monitor interrupt */ +PPC_INTERRUPT_HMI ,/* Hypervisor Maintainance interrupt */ + PPC_INTERRUPT_HDOORBELL, /* Hypervisor Doorbell interrupt */ };/* Processor Compatibility mask (PCR) */
target-ppc/translate_init.c +21 -6
@@ -3105,18 +3105,30 @@ static void init_excp_POWER7 (CPUPPCState *env) env->excp_vectors[POWERPC_EXCP_HDECR ] =0x00000980 ; env->excp_vectors[POWERPC_EXCP_SYSCALL ] =0x00000C00 ; env->excp_vectors[POWERPC_EXCP_TRACE ] =0x00000D00 ; + env->excp_vectors[POWERPC_EXCP_HDSI ] =0x00000E00 ; + env->excp_vectors[POWERPC_EXCP_HISI ] =0x00000E20 ; + env->excp_vectors[POWERPC_EXCP_HV_EMU ] =0x00000E40 ; + env->excp_vectors[POWERPC_EXCP_HV_MAINT ] =0x00000E60 ; env->excp_vectors[POWERPC_EXCP_PERFM ] =0x00000F00 ; env->excp_vectors[POWERPC_EXCP_VPU ] =0x00000F20 ; env->excp_vectors[POWERPC_EXCP_VSXU ] =0x00000F40 ; - env->excp_vectors[POWERPC_EXCP_FU ] =0x00000F60 ; - env->excp_vectors[POWERPC_EXCP_IABR ] =0x00001300 ; - env->excp_vectors[POWERPC_EXCP_MAINT ] =0x00001600 ; - env->excp_vectors[POWERPC_EXCP_VPUA ] =0x00001700 ; - env->excp_vectors[POWERPC_EXCP_THERM ] =0x00001800 ;/* Hardware reset vector */ env->hreset_vector =0x0000000000000100ULL ; #endif } + +static void init_excp_POWER8 (CPUPPCState *env) +{ +init_excp_POWER7 (env); + +#if !defined(CONFIG_USER_ONLY ) + env->excp_vectors[POWERPC_EXCP_SDOOR ] =0x00000A00 ; + env->excp_vectors[POWERPC_EXCP_FU ] =0x00000F60 ; + env->excp_vectors[POWERPC_EXCP_HV_FU ] =0x00000F80 ; + env->excp_vectors[POWERPC_EXCP_SDOOR_HV ] =0x00000E80 ; +#endif +} +#endif /*****************************************************************************/
@@ -8078,10 +8090,13 @@ static void init_proc_book3s_64(CPUPPCState *env, int version)ppc970_irq_init (env);break ;case BOOK3S_CPU_POWER7 : -case BOOK3S_CPU_POWER8 :init_excp_POWER7 (env);ppcPOWER7_irq_init (env);break ; +case BOOK3S_CPU_POWER8 : +init_excp_POWER8 (env); +ppcPOWER7_irq_init (env); +break ;default :g_assert_not_reached (); }
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 19/77] ppc: Fix POWER7 and POWER8 exception definitions
Quoted 3 lines · Benjamin Herrenschmidt
We were initializing unused ones and missing some
Signed-off-by Benjamin Herrenschmidt <[email protected]>
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 20/77 ppc: Fix generation if ISI/DSI vs. HV mode
In reply to Benjamin HerrenschmidtUnder some circumstances, we need to direct ISI and DSI interrupts at the hypervisor, turning them into HISI/HDSI, and using different SPRs (HDSISR and HDAR) depending on the combination of MSR_DR and the corresponding VPM bits in LPCR.
This moves part of the code into helpers that are fixed to select the right exception type and registers. On pre-P7 processors, LPCR is 0 which provides the old behaviour of directing the interrupts at the supervisor.
Thanks to Andrei Warkentin for finding a bug when HV=1
--- target-ppc/mmu-hash64.c | 66 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 19 deletions(-)
target-ppc/mmu-hash64.c +47 -19
@@ -466,6 +466,44 @@ static hwaddr ppc_hash64_pte_raddr(ppc_slb_t *slb, ppc_hash_pte64_t pte,return (rpn & ~mask) | (eaddr & mask); } +static void ppc_hash64_set_isi (CPUState *cs,CPUPPCState *env,uint64_t error_code) +{ +bool vpm; + +if (msr_ir) { + vpm = !!(env->spr[SPR_LPCR ] &LPCR_VPM1 ); + }else { + vpm = !!(env->spr[SPR_LPCR ] &LPCR_VPM0 ); + } +if (vpm && !msr_hv) { + cs->exception_index =POWERPC_EXCP_HISI ; + }else { + cs->exception_index =POWERPC_EXCP_ISI ; + } + env->error_code = error_code; +} + +static void ppc_hash64_set_dsi (CPUState *cs,CPUPPCState *env,uint64_t dar,uint64_t dsisr) +{ +bool vpm; + +if (msr_dr) { + vpm = !!(env->spr[SPR_LPCR ] &LPCR_VPM1 ); + }else { + vpm = !!(env->spr[SPR_LPCR ] &LPCR_VPM0 ); + } +if (vpm && msr_hv) { + cs->exception_index =POWERPC_EXCP_HDSI ; + env->spr[SPR_HDAR ] = dar; + env->spr[SPR_HDSISR ] = dsisr; + }else { + cs->exception_index =POWERPC_EXCP_DSI ; + env->spr[SPR_DAR ] = dar; + env->spr[SPR_DSISR ] = dsisr; + } + env->error_code =0 ; +} +int ppc_hash64_handle_mmu_fault (PowerPCCPU *cpu,target_ulong eaddr,int rwx,int mmu_idx) {
@@ -475,7 +513,7 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, target_ulong eaddr,hwaddr pte_offset;ppc_hash_pte64_t pte;int pp_prot, amr_prot, prot; -uint64_t new_pte1; +uint64_t new_pte1, dsisr;const int need_prot[] = {PAGE_READ ,PAGE_WRITE ,PAGE_EXEC };hwaddr raddr;
@@ -509,26 +547,21 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, target_ulong eaddr,/* 3. Check for segment level no-execute violation */ if ((rwx ==2 ) && (slb->vsid &SLB_VSID_N )) { - cs->exception_index =POWERPC_EXCP_ISI ; - env->error_code =0x10000000 ; +ppc_hash64_set_isi (cs, env,0x10000000 );return 1 ; }/* 4. Locate the PTE in the hash table */ pte_offset =ppc_hash64_htab_lookup (env, slb, eaddr, &pte);if (pte_offset ==-1 ) { + dsisr =0x40000000 ;if (rwx ==2 ) { - cs->exception_index =POWERPC_EXCP_ISI ; - env->error_code =0x40000000 ; +ppc_hash64_set_isi (cs, env, dsisr); }else { - cs->exception_index =POWERPC_EXCP_DSI ; - env->error_code =0 ; - env->spr[SPR_DAR ] = eaddr;if (rwx ==1 ) { - env->spr[SPR_DSISR ] =0x42000000 ; - }else { - env->spr[SPR_DSISR ] =0x40000000 ; + dsisr |=0x02000000 ; } +ppc_hash64_set_dsi (cs, env, eaddr, dsisr); }return 1 ; }
@@ -545,14 +578,9 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, target_ulong eaddr,/* Access right violation */ qemu_log_mask (CPU_LOG_MMU ,"PTE access rejected\n" );if (rwx ==2 ) { - cs->exception_index =POWERPC_EXCP_ISI ; - env->error_code =0x08000000 ; +ppc_hash64_set_isi (cs, env,0x08000000 ); }else { -target_ulong dsisr =0 ; - - cs->exception_index =POWERPC_EXCP_DSI ; - env->error_code =0 ; - env->spr[SPR_DAR ] = eaddr; + dsisr =0 ;if (need_prot[rwx] & ~pp_prot) { dsisr |=0x08000000 ; }
@@ -562,7 +590,7 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, target_ulong eaddr,if (need_prot[rwx] & ~amr_prot) { dsisr |=0x00200000 ; } - env->spr[SPR_DSISR ] = dsisr; +ppc_hash64_set_dsi (cs, env, eaddr, dsisr); }return 1 ; }
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 20/77] ppc: Fix generation if ISI/DSI vs. HV mode
Quoted 5 lines · Benjamin Herrenschmidt
Under some circumstances, we need to direct ISI and DSI interrupts at the hypervisor, turning them into HISI/HDSI, and using different SPRs (HDSISR and HDAR) depending on the combination of
MSR_DRand the corresponding VPM bits in LPCR.
Quoted 8 lines
This moves part of the code into helpers that are fixed to select the right exception type and registers. On pre-P7 processors, LPCR is 0 which provides the old behaviour of directing the interrupts at the supervisor.
Thanks to Andrei Warkentin for finding a bug when HV=1
Signed-off-by Benjamin Herrenschmidt <[email protected]>
Quoted 120 lines
--- target-ppc/mmu-hash64.c | 66 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 19 deletions(-)target-ppc/mmu-hash64.c +47
-19@@ -466,6 +466,44 @@ static hwaddr ppc_hash64_pte_raddr(ppc_slb_t *slb, ppc_hash_pte64_t pte,return (rpn & ~mask) | (eaddr & mask); } +static void ppc_hash64_set_isi (CPUState *cs,CPUPPCState *env,uint64_t error_code) +{ +bool vpm; + +if (msr_ir) { + vpm = !!(env->spr[SPR_LPCR ] &LPCR_VPM1 ); + }else { + vpm = !!(env->spr[SPR_LPCR ] &LPCR_VPM0 ); + } +if (vpm && !msr_hv) { + cs->exception_index =POWERPC_EXCP_HISI ; + }else { + cs->exception_index =POWERPC_EXCP_ISI ; + } + env->error_code = error_code; +} + +static void ppc_hash64_set_dsi (CPUState *cs,CPUPPCState *env,uint64_t dar,uint64_t dsisr) +{ +bool vpm; + +if (msr_dr) { + vpm = !!(env->spr[SPR_LPCR ] &LPCR_VPM1 ); + }else { + vpm = !!(env->spr[SPR_LPCR ] &LPCR_VPM0 ); + } +if (vpm && msr_hv) { + cs->exception_index =POWERPC_EXCP_HDSI ; + env->spr[SPR_HDAR ] = dar; + env->spr[SPR_HDSISR ] = dsisr; + }else { + cs->exception_index =POWERPC_EXCP_DSI ; + env->spr[SPR_DAR ] = dar; + env->spr[SPR_DSISR ] = dsisr; + } + env->error_code =0 ; +} +int ppc_hash64_handle_mmu_fault (PowerPCCPU *cpu,target_ulong eaddr,int rwx,int mmu_idx) {@@ -475,7 +513,7 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, target_ulong eaddr,hwaddr pte_offset;ppc_hash_pte64_t pte;int pp_prot, amr_prot, prot; -uint64_t new_pte1; +uint64_t new_pte1, dsisr;const int need_prot[] = {PAGE_READ ,PAGE_WRITE ,PAGE_EXEC };hwaddr raddr;@@ -509,26 +547,21 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, target_ulong eaddr,/* 3. Check for segment level no-execute violation */ if ((rwx ==2 ) && (slb->vsid &SLB_VSID_N )) { - cs->exception_index =POWERPC_EXCP_ISI ; - env->error_code =0x10000000 ; +ppc_hash64_set_isi (cs, env,0x10000000 );return 1 ; }/* 4. Locate the PTE in the hash table */ pte_offset =ppc_hash64_htab_lookup (env, slb, eaddr, &pte);if (pte_offset ==-1 ) { + dsisr =0x40000000 ;if (rwx ==2 ) { - cs->exception_index =POWERPC_EXCP_ISI ; - env->error_code =0x40000000 ; +ppc_hash64_set_isi (cs, env, dsisr); }else { - cs->exception_index =POWERPC_EXCP_DSI ; - env->error_code =0 ; - env->spr[SPR_DAR ] = eaddr;if (rwx ==1 ) { - env->spr[SPR_DSISR ] =0x42000000 ; - }else { - env->spr[SPR_DSISR ] =0x40000000 ; + dsisr |=0x02000000 ; } +ppc_hash64_set_dsi (cs, env, eaddr, dsisr); }return 1 ; }@@ -545,14 +578,9 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, target_ulong eaddr,/* Access right violation */ qemu_log_mask (CPU_LOG_MMU ,"PTE access rejected\n" );if (rwx ==2 ) { - cs->exception_index =POWERPC_EXCP_ISI ; - env->error_code =0x08000000 ; +ppc_hash64_set_isi (cs, env,0x08000000 ); }else { -target_ulong dsisr =0 ; - - cs->exception_index =POWERPC_EXCP_DSI ; - env->error_code =0 ; - env->spr[SPR_DAR ] = eaddr; + dsisr =0 ;if (need_prot[rwx] & ~pp_prot) { dsisr |=0x08000000 ; }@@ -562,7 +590,7 @@ int ppc_hash64_handle_mmu_fault(PowerPCCPU *cpu, target_ulong eaddr,if (need_prot[rwx] & ~amr_prot) { dsisr |=0x00200000 ; } - env->spr[SPR_DSISR ] = dsisr; +ppc_hash64_set_dsi (cs, env, eaddr, dsisr); }return 1 ; }
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 21/77 ppc: Rework generation of priv and inval interrupts
In reply to Benjamin HerrenschmidtRecent server processors use the Hypervisor Emulation Assistance interrupt for illegal instructions and *some* type of SPR accesses.
Also the code was always generating inval instructions even for priv violations due to setting the wrong flags
Finally, the checking for PR/HV was open coded everywhere.
This reworks it all, using little helper macros for checking, and adding the HV interrupt (which gets converted back to program check in the slow path of excp_helper.c on CPUs that don't want it).
--- linux-user/main.c | 1 + target-ppc/excp_helper.c | 19 ++ target-ppc/translate.c | 678 ++++++++++++++++++++--------------------------- 3 files changed, 302 insertions(+), 396 deletions(-)
linux-user/main.c +1 -0
@@ -1654,6 +1654,7 @@ void cpu_loop(CPUPPCState *env)queue_signal (env, info.si_signo, &info);break ;case POWERPC_EXCP_PROGRAM :/* Program exception */ +case POWERPC_EXCP_HV_EMU :/* HV emulation */ /* XXX: check this */ switch (env->error_code & ~0xF ) {case POWERPC_EXCP_FP :
target-ppc/excp_helper.c +19 -0
@@ -127,6 +127,19 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) ail =0 ; } +/* Hypervisor emulation assistance interrupt only exists on server +* arch 2.05 server or later. We also don't want to generate it if +* we don't have HVB in msr_mask (PAPR mode). +*/ + if (excp == POWERPC_EXCP_HV_EMU +#if defined(TARGET_PPC64 ) + && !((env->mmu_model & POWERPC_MMU_64) && (env->msr_mask & MSR_HVB)) +#endif /* defined(TARGET_PPC64) */ + + ) { + excp =POWERPC_EXCP_PROGRAM ; + } +switch (excp) {case POWERPC_EXCP_NONE :/* Should never happen */
@@ -249,6 +262,12 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)break ; } goto store_current; +case POWERPC_EXCP_HV_EMU : + srr0 =SPR_HSRR0 ; + srr1 =SPR_HSRR1 ; + new_msr |= (target_ulong )MSR_HVB ; + new_msr |= env->msr & ((target_ulong )1 <<MSR_RI ); + goto store_current;case POWERPC_EXCP_FPU :/* Floating-point unavailable exception */ goto store_current;case POWERPC_EXCP_SYSCALL :/* System call exception */
target-ppc/translate.c +282 -396
1,376 lines not on this page · raw message
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 21/77] ppc: Rework generation of priv and inval interrupts
Quoted 13 lines · Benjamin Herrenschmidt
Recent server processors use the Hypervisor Emulation Assistance interrupt for illegal instructions and *some* type of SPR accesses.
Also the code was always generating inval instructions even for priv violations due to setting the wrong flags
Finally, the checking for PR/HV was open coded everywhere.
This reworks it all, using little helper macros for checking, and adding the HV interrupt (which gets converted back to program check in the slow path of
excp_helper.con CPUs that don't want it).Signed-off-by Benjamin Herrenschmidt <[email protected]>
[snip]
Quoted 11 lines
static void
spr_noaccess(DisasContext *ctx, int gprn, int sprn)target-ppc/translate.c +1
-1@@ -4340,7 +4350,7 @@ static inline void gen_op_mfspr(DisasContext *ctx)printf ("Trying to read privileged spr %d (0x%03x) at " TARGET_FMT_lx"\n" , sprn, sprn, ctx->nip -4 ); } -gen_inval_exception (ctx,POWERPC_EXCP_PRIV_REG ); +gen_priv_exception (ctx,POWERPC_EXCP_PRIV_REG ); } }else {/* Not defined */
target-ppc/translate.c static inline void gen_op_mfspr(DisasContext *ctx) · line 4360
Quoted 3 lines
target-ppc/translate.c +0
-0@@ -4348,7 +4358,25 @@ static inline void gen_op_mfspr(DisasContext *ctx) TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4);printf ("Trying to read invalid spr %d (0x%03x) at " TARGET_FMT_lx"\n" , sprn, sprn, ctx->nip -4 );
So, I'm not 100% following the logic below, but it looks like the existing code used SPR_NOACCESS to mark things which generated a privilege exception compared to NULL for things which generated an invalid instruction exception. Using that encoding, can you simplify the logic here? Alternatively can you use the logic here to avoid the SPR_NOACESS encoding?
Quoted 9 lines
target-ppc/translate.c +8
-1-gen_inval_exception (ctx,POWERPC_EXCP_INVAL_SPR ); + +/* The behaviour depends on MSR:PR and SPR# bit 0x10, +* it can generate a priv, a hv emu or a no-op +*/ +if (sprn &0x10 ) { +if (ctx->pr) { +gen_priv_exception (ctx,POWERPC_EXCP_INVAL_SPR ); + }
target-ppc/translate.c static inline void gen_op_mfspr(DisasContext *ctx) · line 4378
Quoted 10 lines
target-ppc/translate.c +10
-0+ }else { +if (ctx->pr || sprn ==0 || sprn ==4 || sprn ==5 || sprn ==6 ) { +gen_hvpriv_exception (ctx,POWERPC_EXCP_INVAL_SPR ); + } + } +#if !defined(CONFIG_USER_ONLY ) +/* HV priv */ +if (ctx->spr_cb[sprn].hea_read) { +gen_priv_exception (ctx,POWERPC_EXCP_INVAL_SPR ); + }
If you're in PR mode, and it's an SPR with an hea_read function and has the 0x10 bit set, won't this call gen_priv_exception twice?
I also see no path here which will call gen_inval_exception(), is that right? If you're in HV mode and it's a truly invalid SPRN, isn't that what you'd want?
Quoted 74 lines
target-ppc/translate.c +20
-19+#endif } }@@ -4395,13 +4423,9 @@ static void gen_mtcrf(DisasContext *ctx)#if defined(TARGET_PPC64 )static void gen_mtmsrd (DisasContext *ctx) { -#if defined(CONFIG_USER_ONLY ) -gen_inval_exception (ctx,POWERPC_EXCP_PRIV_REG ); -#else -if (unlikely (ctx->pr)) { -gen_inval_exception (ctx,POWERPC_EXCP_PRIV_REG ); -return ; - } +CHK_SV ; + +#if !defined(CONFIG_USER_ONLY )if (ctx->opcode &0x00010000 ) {/* Special form that does not need any synchronisation */ TCGv t0 =tcg_temp_new ();@@ -4420,20 +4444,16 @@ static void gen_mtmsrd(DisasContext *ctx)/* Note that mtmsr is not always defined as context-synchronizing */ gen_stop_exception (ctx); } -#endif +#endif /* !defined(CONFIG_USER_ONLY) */ } -#endif +#endif /* defined(TARGET_PPC64) */ static void gen_mtmsr (DisasContext *ctx) { -#if defined(CONFIG_USER_ONLY ) -gen_inval_exception (ctx,POWERPC_EXCP_PRIV_REG ); -#else -if (unlikely (ctx->pr)) { -gen_inval_exception (ctx,POWERPC_EXCP_PRIV_REG ); -return ; - } -if (ctx->opcode &0x00010000 ) { +CHK_SV ; + +#if !defined(CONFIG_USER_ONLY ) +if (ctx->opcode &0x00010000 ) {/* Special form that does not need any synchronisation */ TCGv t0 =tcg_temp_new ();tcg_gen_andi_tl (t0, cpu_gpr[rS (ctx->opcode)], (1 <<MSR_RI ) | (1 <<MSR_EE ));@@ -4488,7 +4508,7 @@ static void gen_mtspr(DisasContext *ctx) TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4);printf ("Trying to write privileged spr %d (0x%03x) at " TARGET_FMT_lx"\n" , sprn, sprn, ctx->nip -4 ); -gen_inval_exception (ctx,POWERPC_EXCP_PRIV_REG ); +gen_priv_exception (ctx,POWERPC_EXCP_PRIV_REG ); } }else {/* Not defined */ @@ -4496,7 +4516,25 @@ static void gen_mtspr(DisasContext *ctx) TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4);printf ("Trying to write invalid spr %d (0x%03x) at " TARGET_FMT_lx"\n" , sprn, sprn, ctx->nip -4 ); -gen_inval_exception (ctx,POWERPC_EXCP_INVAL_SPR ); + +/* The behaviour depends on MSR:PR and SPR# bit 0x10, +* it can generate a priv, a hv emu or a no-op +*/ +if (sprn &0x10 ) { +if (ctx->pr) { +gen_priv_exception (ctx,POWERPC_EXCP_INVAL_SPR ); + } + }else {
target-ppc/translate.c static void gen_mtspr(DisasContext *ctx) · line 4537
Quoted 10 lines
target-ppc/translate.c +10
-0+if (ctx->pr || sprn ==0 ) { +gen_hvpriv_exception (ctx,POWERPC_EXCP_INVAL_SPR ); + } + } +#if !defined(CONFIG_USER_ONLY ) +/* HV priv */ +if (ctx->spr_cb[sprn].hea_write) { +gen_priv_exception (ctx,POWERPC_EXCP_INVAL_SPR ); + } +#endif
Same concerns here as for mfspr.
[snip]
target-ppc/translate.c static void gen_slbmfev(DisasContext *ctx) · line 4880
Quoted 12 lines
target-ppc/translate.c +0
-0/* tlbiel */ static void gen_tlbiel (DisasContext *ctx) {#if
defined(CONFIG_USER_ONLY)target-ppc/translate.c +2
-5-gen_inval_exception (ctx,POWERPC_EXCP_PRIV_OPC ); +GEN_PRIV ;#else -if (unlikely (ctx->pr || !ctx->hv)) { -gen_inval_exception (ctx,POWERPC_EXCP_PRIV_OPC ); -return ; - } +CHK_SV ;
You have CHK_SV here, but the original code checks for HV, as does your new code for tlbia and tlbiel, is that right?
[snip]
Quoted 4 lines
/* tlbsync */
static voidgen_tlbsync(DisasContext *ctx)
{
#ifdefined(CONFIG_USER_ONLY)
target-ppc/translate.c static void gen_tlbie(DisasContext *ctx) · line 4912
Quoted 10 lines
target-ppc/translate.c +4
-6-gen_inval_exception (ctx,POWERPC_EXCP_PRIV_OPC ); -#else -if (unlikely (ctx->pr)) { -gen_inval_exception (ctx,POWERPC_EXCP_PRIV_OPC ); -return ; - } +GEN_PRIV ; +#else +CHK_HV ; +
Old code didn't check for HV, mode, but AFAICT it should have, so this looks correct.
[snip]
Quoted 4 lines
target-ppc/translate.c +0
-0@@ -5941,18 +5921,16 @@ static void gen_mfapidi(DisasContext *ctx)static void gen_tlbiva (DisasContext *ctx) {#if defined(CONFIG_USER_ONLY )
target-ppc/translate.c static void gen_mfapidi(DisasContext *ctx) · line 5928
Quoted 10 lines
target-ppc/translate.c +3
-5-gen_inval_exception (ctx,POWERPC_EXCP_PRIV_OPC ); +GEN_PRIV ;#else TCGv t0; -if (unlikely (ctx->pr)) { -gen_inval_exception (ctx,POWERPC_EXCP_PRIV_OPC ); -return ; - } + +CHK_SV ;
Is the same thing as tlbivax, or some ancient instruction? AFAICT the ISA says tlbivax is hypervisor privileged.
Quoted 7 lines
target-ppc/translate.c +1
-1t0 =tcg_temp_new ();gen_addr_reg_index (ctx, t0);gen_helper_tlbie (cpu_env, cpu_gpr[rB (ctx->opcode)]);tcg_temp_free (t0); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ }
[snip]
target-ppc/translate.c static void gen_mfsri(DisasContext *ctx) · line 5767
Quoted 13 lines
static void
gen_tlbivax_booke206(DisasContext *ctx){
#ifdefined(CONFIG_USER_ONLY)target-ppc/translate.c +2
-5-gen_inval_exception (ctx,POWERPC_EXCP_PRIV_OPC ); +GEN_PRIV ;#else TCGv t0; -if (unlikely (ctx->pr)) { -gen_inval_exception (ctx,POWERPC_EXCP_PRIV_OPC ); -return ; - } +CHK_SV ;
ISA says tlbivax is hypervisor privileged when the CPU has a hypervisor mode, which I guess booke206 probably doesn't?
Quoted 12 lines
t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0);target-ppc/translate.c +1
-2-gen_helper_booke206_tlbivax (cpu_env, t0);tcg_temp_free (t0); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ }static void gen_tlbilx_booke206 (DisasContext *ctx) {#if defined(CONFIG_USER_ONLY )
target-ppc/translate.c static void gen_tlbsx_booke206(DisasContext *ctx) · line 6557
Quoted 10 lines
target-ppc/translate.c +2
-5-gen_inval_exception (ctx,POWERPC_EXCP_PRIV_OPC ); +GEN_PRIV ;#else TCGv t0; -if (unlikely (ctx->pr)) { -gen_inval_exception (ctx,POWERPC_EXCP_PRIV_OPC ); -return ; - } +CHK_SV ;
And apparently hv vs. sv privilege of tlbilx depends on the EPCR register. Again, may not be relevant for 2.06.
Quoted 10 lines
t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0);target-ppc/translate.c +1
-1@@ -6672,7 +6574,7 @@ static void gen_tlbilx_booke206(DisasContext *ctx) }tcg_temp_free (t0); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ }
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [Qemu-ppc] [PATCH 21/77] ppc: Rework generation of priv and inval interrupts
Quoted 7 lines · David Gibson
So, I'm not 100% following the logic below, but it looks like the existing code usedSPR_NOACCESSto mark things which generated a privilege exception compared to NULL for things which generated an invalid instruction exception. Using that encoding, can you simplify the logic here? Alternatively can you use the logic here to avoid theSPR_NOACESSencoding?
Well, so the SPR_NOACCESS has to do with how you react to a known SPR who has explicit access permissions. The logic below is described in the ISA for an unknown SPR number.
I don't know whether the access permission of "known" SPRs always honor the 0x10 bit trick, and changing that in qemu would be a fairly large patch. So I'd rather stick to the logic here for "unknown" SPRs which matches the ISA definition.
I'll update the patch though for arch 2.07 as it defines a few reserved SPRs as no-ops.
However:
Quoted 12 lines
Quoted 12 lines
- gen_inval_exception(ctx,
POWERPC_EXCP_INVAL_SPR); +
+ /* The behaviour depends on MSR:PR and SPR# bit0x10, + * it can generate a priv, a hv emu or a no-op + */
+ if (sprn &0x10) {
+ if (ctx->pr) {
+ gen_priv_exception(ctx,POWERPC_EXCP_INVAL_SPR); + }
+ } else {
+ if (ctx->pr|| sprn == 0 || sprn == 4 || sprn == 5 || sprn == 6) {
Quoted 8 lines
Quoted 8 lines
+ gen_hvpriv_exception(ctx,
POWERPC_EXCP_INVAL_SPR); + }
+ }
+#if !defined(CONFIG_USER_ONLY)
+ /* HV priv */
+ if (ctx->spr_cb[sprn].hea_read) {
+ gen_priv_exception(ctx,POWERPC_EXCP_INVAL_SPR); + }
That latest bit is bogus.
Quoted 2 lines
If you're in PR mode, and it's an SPR with an
hea_readfunction and has the0x10bit set, won't this callgen_priv_exceptiontwice?
Yes, I've removed it. It should be handled by the SPR_NOACCESS.
Quoted 5 lines
I also see no path here which will call
gen_inval_exception(), is that
right? If you're in HV mode and it's a truly invalid SPRN, isn't that
what you'd want?
No, the ISA says it's a nop.
Cheers,
Ben.
Quoted 212 lines
Quoted 78 lines
+#endif
}
}target-ppc/translate.c +3
-7@@ -4395,13 +4423,9 @@ static void gen_mtcrf(DisasContext *ctx) #if defined(TARGET_PPC64) static void gen_mtmsrd(DisasContext *ctx) { -#if defined(CONFIG_USER_ONLY ) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); -#else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); - return; - } + CHK_SV; + +#if !defined(CONFIG_USER_ONLY ) if (ctx->opcode & 0x00010000) { /* Special form that does not need any synchronisation */ TCGv t0 = tcg_temp_new();@@ -4420,20 +4444,16 @@ static void gen_mtmsrd(DisasContext *ctx) /* Note that mtmsr is not always defined as context-synchronizing */
gen_stop_exception(ctx);
}target-ppc/translate.c +1
-1-#endif +#endif /* !defined(CONFIG_USER_ONLY) */ }
(quoted diff) +1
-1-#endif +#endif /* defined(TARGET_PPC64) */
static voidgen_mtmsr(DisasContext *ctx)
{target-ppc/translate.c +4
-8-#if defined(CONFIG_USER_ONLY ) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); -#else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG); - return; - } - if (ctx->opcode & 0x00010000) { + CHK_SV; + +#if !defined(CONFIG_USER_ONLY ) + if (ctx->opcode & 0x00010000) {/* Special form that does not need any synchronisation */ TCGv t0 =
tcg_temp_new();
tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], (1 <<MSR_RI) | (1 <<MSR_EE));(quoted diff) +0
-0@@ -4488,7 +4508,7 @@ static void gen_mtspr(DisasContext *ctx)TARGET_FMT_lx "\n", sprn, sprn,
ctx->nip- 4);
printf("Trying to write privileged spr %d (0x%03x) at "
TARGET_FMT_lx "\n", sprn, sprn,ctx->nip- 4); - gen_inval_exception(ctx,POWERPC_EXCP_PRIV_REG); + gen_priv_exception(ctx,POWERPC_EXCP_PRIV_REG); }
} else {
/* Not defined */(quoted diff) +0
-0@@ -4496,7 +4516,25 @@ static void gen_mtspr(DisasContext *ctx) TARGET_FMT_lx "\n", sprn, sprn, ctx->nip - 4);printf("Trying to write invalid spr %d (0x%03x) at "
TARGET_FMT_lx"\n", sprn, sprn,ctx->nip- 4); - gen_inval_exception(ctx,POWERPC_EXCP_INVAL_SPR);target-ppc/translate.c +9
-0+ + /* The behaviour depends on MSR:PR and SPR# bit 0x10, + * it can generate a priv, a hv emu or a no-op + */ + if (sprn & 0x10) { + if (ctx->pr) { + gen_priv_exception(ctx, POWERPC_EXCP_INVAL_SPR); + } + } else {target-ppc/translate.c static void gen_mtspr(DisasContext *ctx) · line 4537
Quoted 10 lines
target-ppc/translate.c +10
-0+ if (ctx->pr || sprn == 0) { + gen_hvpriv_exception(ctx, POWERPC_EXCP_INVAL_SPR); + } + } +#if !defined(CONFIG_USER_ONLY ) + /* HV priv */ + if (ctx->spr_cb[sprn].hea_write) { + gen_priv_exception(ctx, POWERPC_EXCP_INVAL_SPR); + } +#endif Same concerns here as for mfspr.
[snip]
Quoted 4 lines
/* tlbiel */
static voidgen_tlbiel(DisasContext *ctx)
{
#ifdefined(CONFIG_USER_ONLY)Quoted 8 lines
- gen_inval_exception(ctx,
POWERPC_EXCP_PRIV_OPC); + GEN_PRIV;
#else
- if (unlikely(ctx->pr || !ctx->hv)) {
- gen_inval_exception(ctx,POWERPC_EXCP_PRIV_OPC); - return;
- }
+ CHK_SV;You have
CHK_SVhere, but the original code checks for HV, as does your new code for tlbia and tlbiel, is that right?[snip]
Quoted 5 lines
/* tlbsync */
static voidgen_tlbsync(DisasContext *ctx)
{
#ifdefined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx,POWERPC_EXCP_PRIV_OPC);target-ppc/translate.c static void gen_tlbie(DisasContext *ctx) · line 4912
Quoted 9 lines
target-ppc/translate.c +4
-5-#else - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + GEN_PRIV; +#else + CHK_HV; +Old code didn't check for HV, mode, but AFAICT it should have, so this
looks correct.[snip]
Quoted 4 lines
target-ppc/translate.c +0
-0@@ -5941,18 +5921,16 @@ static void gen_mfapidi(DisasContext *ctx) static void gen_tlbiva(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY)target-ppc/translate.c static void gen_mfapidi(DisasContext *ctx) · line 5928
Quoted 10 lines
target-ppc/translate.c +3
-5- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else TCGv t0; - if (unlikely(ctx->pr)) { - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + + CHK_SV;Is the same thing as tlbivax, or some ancient instruction? AFAICT the
ISA says tlbivax is hypervisor privileged.Quoted 7 lines
target-ppc/translate.c +1
-1t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); gen_helper_tlbie(cpu_env, cpu_gpr[rB(ctx->opcode)]); tcg_temp_free(t0); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ }[snip]
Quoted 5 lines
static void
gen_tlbivax_booke206(DisasContext *ctx){
#ifdefined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx,POWERPC_EXCP_PRIV_OPC); + GEN_PRIV;Quoted 8 lines
#else
TCGv t0;
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx,POWERPC_EXCP_PRIV_OPC); - return;
- }
+ CHK_SV;ISA says tlbivax is hypervisor privileged when the CPU has a hypervisor mode, which I guess booke206 probably doesn't?
Quoted 14 lines
t0 =
tcg_temp_new();
gen_addr_reg_index(ctx, t0);
-
gen_helper_booke206_tlbivax(cpu_env, t0);
tcg_temp_free(t0);(quoted diff) +1
-1-#endif +#endif /* defined(CONFIG_USER_ONLY) */}
static voidgen_tlbilx_booke206(DisasContext *ctx){
#ifdefined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx,POWERPC_EXCP_PRIV_OPC); + GEN_PRIV;Quoted 8 lines
#else
TCGv t0;
- if (unlikely(ctx->pr)) {
- gen_inval_exception(ctx,POWERPC_EXCP_PRIV_OPC); - return;
- }
+ CHK_SV;And apparently hv vs. sv privilege of tlbilx depends on the EPCR register. Again, may not be relevant for 2.06.
Quoted 11 lines
t0 =
tcg_temp_new();
gen_addr_reg_index(ctx, t0);(quoted diff) +0
-0@@ -6672,7 +6574,7 @@ static void gen_tlbilx_booke206(DisasContext *ctx) }
tcg_temp_free(t0);(quoted diff) +1
-1-#endif +#endif /* defined(CONFIG_USER_ONLY) */}
Re: [Qemu-devel] [Qemu-ppc] [PATCH 21/77] ppc: Rework generation of priv and inval interrupts
Quoted 13 lines · Benjamin Herrenschmidt
Quoted 7 lines · David Gibson
So, I'm not 100% following the logic below, but it looks like the existing code usedSPR_NOACCESSto mark things which generated a privilege exception compared to NULL for things which generated an invalid instruction exception. Using that encoding, can you simplify the logic here? Alternatively can you use the logic here to avoid theSPR_NOACESSencoding?Well, so the
SPR_NOACCESShas to do with how you react to a known SPR who has explicit access permissions. The logic below is described in the ISA for an unknown SPR number.
Quoted 7 lines
I don't know whether the access permission of "known" SPRs always honor the
0x10bit trick, and changing that in qemu would be a fairly large patch. So I'd rather stick to the logic here for "unknown" SPRs which matches the ISA definition.I'll update the patch though for arch 2.07 as it defines a few reserved SPRs as no-ops.
Ok, that makes sense.
Quoted 30 lines
However:
Quoted 12 lines
Quoted 12 lines
- gen_inval_exception(ctx,
POWERPC_EXCP_INVAL_SPR); +
+ /* The behaviour depends on MSR:PR and SPR# bit0x10, + * it can generate a priv, a hv emu or a no-op + */
+ if (sprn &0x10) {
+ if (ctx->pr) {
+ gen_priv_exception(ctx,POWERPC_EXCP_INVAL_SPR); + }
+ } else {
+ if (ctx->pr|| sprn == 0 || sprn == 4 || sprn == 5 || sprn == 6) {Quoted 8 lines
Quoted 8 lines
+ gen_hvpriv_exception(ctx,
POWERPC_EXCP_INVAL_SPR); + }
+ }
+#if !defined(CONFIG_USER_ONLY)
+ /* HV priv */
+ if (ctx->spr_cb[sprn].hea_read) {
+ gen_priv_exception(ctx,POWERPC_EXCP_INVAL_SPR); + }That latest bit is bogus.
Quoted 2 lines
If you're in PR mode, and it's an SPR with an
hea_readfunction and has the0x10bit set, won't this callgen_priv_exceptiontwice?Yes, I've removed it. It should be handled by the
SPR_NOACCESS.
Quoted 7 lines
Quoted 5 lines
I also see no path here which will call
gen_inval_exception(), is that
right? If you're in HV mode and it's a truly invalid SPRN, isn't that
what you'd want?No, the ISA says it's a nop.
Huh, ok.
Some comments referencing the ISA might be useful here.
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [Qemu-ppc] [PATCH 21/77] ppc: Rework generation of priv and inval interrupts
In reply to David GibsonQuoted 14 lines · David Gibson
snip]
Quoted 4 lines
/* tlbiel */
static voidgen_tlbiel(DisasContext *ctx)
{
#ifdefined(CONFIG_USER_ONLY)Quoted 8 lines
-
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); +GEN_PRIV;
#else
- if (unlikely(ctx->pr || !ctx->hv)) {
-gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return;
- }
+CHK_SV;
Quoted 2 lines
You have
CHK_SVhere, but the original code checks for HV, as does your new code for tlbia and tlbiel, is that right?
Yes. tlbiel is supervisor accessible (for weird reasons).
Quoted 10 lines
[snip]
Quoted 9 lines
/* tlbsync */
static voidgen_tlbsync(DisasContext *ctx)
{
#ifdefined(CONFIG_USER_ONLY)
-gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); -#else
- if (unlikely(ctx->pr)) {
-gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return;
Quoted 8 lines
target-ppc/translate.c static void gen_tlbie(DisasContext *ctx) · line 4912
Quoted 5 lines
- }
+GEN_PRIV;target-ppc/translate.c +3
-0+#else + CHK_HV; +Old code didn't check for HV, mode, but AFAICT it should have, so this looks correct.
Yes, this is a hypervisor instruction.
Quoted 10 lines
[snip]
Quoted 9 lines
target-ppc/translate.c +1
-2@@ -5941,18 +5921,16 @@ static void gen_mfapidi(DisasContext *ctx) static void gen_tlbiva(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else TCGv t0; - if (unlikely(ctx->pr)) {
Quoted 8 lines
target-ppc/translate.c static void gen_dcbf(DisasContext *ctx) · line 4563
Quoted 5 lines
target-ppc/translate.c +2
-3- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + + CHK_SV;Is the same thing as tlbivax, or some ancient instruction? AFAICT the ISA says tlbivax is hypervisor privileged.
"tlbiva" is the 4xx variant, there is no hypervisor mode on these things.
Quoted 23 lines
Quoted 7 lines
target-ppc/translate.c +1
-1t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); gen_helper_tlbie(cpu_env, cpu_gpr[rB(ctx->opcode)]); tcg_temp_free(t0); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ }[snip]
Quoted 5 lines
static void
gen_tlbivax_booke206(DisasContext *ctx){
#ifdefined(CONFIG_USER_ONLY)
-gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); +GEN_PRIV;Quoted 8 lines
#else
TCGv t0;
- if (unlikely(ctx->pr)) {
-gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return;
- }
+CHK_SV;
Quoted 2 lines
ISA says tlbivax is hypervisor privileged when the CPU has a hypervisor mode, which I guess booke206 probably doesn't?
Right so here, the "problem" is that afaik, TCG doesn't implement the BookE hypervisor mode. So with my limited BookE testing ability I prefer sticking to a mechanical replacement that matches the existing code. It can be fixed later if necessary.
Quoted 17 lines
Quoted 17 lines
t0 =
tcg_temp_new();
gen_addr_reg_index(ctx, t0);
-
gen_helper_booke206_tlbivax(cpu_env, t0);
tcg_temp_free(t0);(quoted diff) +1
-1-#endif +#endif /* defined(CONFIG_USER_ONLY) */}
static voidgen_tlbilx_booke206(DisasContext *ctx){
#ifdefined(CONFIG_USER_ONLY)
-gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); +GEN_PRIV;
#else
TCGv t0;
- if (unlikely(ctx->pr)) {
Quoted 8 lines
Quoted 5 lines
-
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return;
- }
+CHK_SV;And apparently hv vs. sv privilege of tlbilx depends on the EPCR register. Again, may not be relevant for 2.06.
Well, here too, I basically preserve existing BookE TCG behaviour, whether it's correct or not. That can be fixed separately if somebody cares about BookE HV mode.
Quoted 12 lines
Review static void gen_tlbilx_booke206(DisasContext
Quoted 4 lines
t0 =
tcg_temp_new();
gen_addr_reg_index(ctx, t0);(quoted diff) +0
-0@@ -6672,7 +6574,7 @@ static void gen_tlbilx_booke206(DisasContext*ctx)
Quoted 6 lines
(quoted diff) +0
-0}
tcg_temp_free(t0);(quoted diff) +1
-1-#endif +#endif /* defined(CONFIG_USER_ONLY) */}
Re: [Qemu-devel] [Qemu-ppc] [PATCH 21/77] ppc: Rework generation of priv and inval interrupts
Quoted 86 lines · Benjamin Herrenschmidt
Quoted 14 lines · David Gibson
snip]
Quoted 4 lines
/* tlbiel */
static voidgen_tlbiel(DisasContext *ctx)
{
#ifdefined(CONFIG_USER_ONLY)Quoted 8 lines
-
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); +GEN_PRIV;
#else
- if (unlikely(ctx->pr || !ctx->hv)) {
-gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return;
- }
+CHK_SV;Quoted 2 lines
You have
CHK_SVhere, but the original code checks for HV, as does your new code for tlbia and tlbiel, is that right?Yes. tlbiel is supervisor accessible (for weird reasons).
Quoted 10 lines
[snip]
Quoted 9 lines
/* tlbsync */
static voidgen_tlbsync(DisasContext *ctx)
{
#ifdefined(CONFIG_USER_ONLY)
-gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); -#else
- if (unlikely(ctx->pr)) {
-gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return;Quoted 8 lines
target-ppc/translate.c static void gen_tlbie(DisasContext *ctx) · line 4912
Quoted 5 lines
- }
+GEN_PRIV;target-ppc/translate.c +3
-0+#else + CHK_HV; +Old code didn't check for HV, mode, but AFAICT it should have, so this looks correct.
Yes, this is a hypervisor instruction.
Quoted 10 lines
[snip]
Quoted 9 lines
target-ppc/translate.c +1
-2@@ -5941,18 +5921,16 @@ static void gen_mfapidi(DisasContext *ctx) static void gen_tlbiva(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) - gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); + GEN_PRIV; #else TCGv t0; - if (unlikely(ctx->pr)) {Quoted 8 lines
target-ppc/translate.c static void gen_dcbf(DisasContext *ctx) · line 4563
Quoted 5 lines
target-ppc/translate.c +2
-3- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return; - } + + CHK_SV;Is the same thing as tlbivax, or some ancient instruction? AFAICT the ISA says tlbivax is hypervisor privileged.
"tlbiva" is the 4xx variant, there is no hypervisor mode on these things.
Quoted 23 lines
Quoted 7 lines
target-ppc/translate.c +1
-1t0 = tcg_temp_new(); gen_addr_reg_index(ctx, t0); gen_helper_tlbie(cpu_env, cpu_gpr[rB(ctx->opcode)]); tcg_temp_free(t0); -#endif +#endif /* defined(CONFIG_USER_ONLY) */ }[snip]
Quoted 13 lines
static void
gen_tlbivax_booke206(DisasContext *ctx){
#ifdefined(CONFIG_USER_ONLY)
-gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); +GEN_PRIV;
#else
TCGv t0;
- if (unlikely(ctx->pr)) {
-gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return;
- }
+CHK_SV;
Quoted 7 lines
Quoted 2 lines
ISA says tlbivax is hypervisor privileged when the CPU has a hypervisor mode, which I guess booke206 probably doesn't?
Right so here, the "problem" is that afaik, TCG doesn't implement the BookE hypervisor mode. So with my limited BookE testing ability I prefer sticking to a mechanical replacement that matches the existing code. It can be fixed later if necessary.
Fair enough.
Quoted 43 lines
Quoted 17 lines
Quoted 17 lines
t0 =
tcg_temp_new();
gen_addr_reg_index(ctx, t0);
-
gen_helper_booke206_tlbivax(cpu_env, t0);
tcg_temp_free(t0);(quoted diff) +1
-1-#endif +#endif /* defined(CONFIG_USER_ONLY) */}
static voidgen_tlbilx_booke206(DisasContext *ctx){
#ifdefined(CONFIG_USER_ONLY)
-gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); +GEN_PRIV;
#else
TCGv t0;
- if (unlikely(ctx->pr)) {Quoted 8 lines
Quoted 5 lines
-
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); - return;
- }
+CHK_SV;And apparently hv vs. sv privilege of tlbilx depends on the EPCR register. Again, may not be relevant for 2.06.
Well, here too, I basically preserve existing BookE TCG behaviour, whether it's correct or not. That can be fixed separately if somebody cares about BookE HV mode.
Quoted 12 lines
Review static void gen_tlbilx_booke206(DisasContext
Quoted 4 lines
t0 =
tcg_temp_new();
gen_addr_reg_index(ctx, t0);(quoted diff) +0
-0@@ -6672,7 +6574,7 @@ static void gen_tlbilx_booke206(DisasContext*ctx)
Quoted 6 lines
(quoted diff) +0
-0}
tcg_temp_free(t0);(quoted diff) +1
-1-#endif +#endif /* defined(CONFIG_USER_ONLY) */}
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 22/77 ppc: Add real mode CI load/store instructions for P7 and P8
In reply to Benjamin HerrenschmidtThose instructions are only available in hypervisor real mode and allow cache inhibited garded access to devices in that mode.
--- target-ppc/cpu.h | 4 +++- target-ppc/translate.c | 56 +++++++++++++++++++++++++++++++++++---------- target-ppc/translate_init.c | 6 +++-- 3 files changed, 51 insertions(+), 15 deletions(-)
target-ppc/cpu.h +3 -1
@@ -1913,6 +1913,8 @@ enum {PPC_POPCNTB =0x0000000000001000ULL ,/* string load / store */ PPC_STRING =0x0000000000002000ULL , +/* real mode cache inhibited load / store */ + PPC_CILDST = 0x0000000000004000ULL,/* Floating-point unit extensions */ /* Optional floating point instructions */
@@ -2027,7 +2029,7 @@ enum { | PPC_MFAPIDI | PPC_TLBIVA | PPC_TLBIVAX \ | PPC_4xx_COMMON | PPC_40x_ICBT |PPC_RFMCI \ |PPC_RFDI |PPC_DCR |PPC_DCRX |PPC_DCRUX \ - | PPC_POPCNTWD) + | PPC_POPCNTWD | PPC_CILDST)/* extended type values */
target-ppc/translate.c +44 -12
162 lines not on this page · raw message
target-ppc/translate_init.c +4 -2
@@ -8320,7 +8320,8 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)PPC_MEM_TLBIE |PPC_MEM_TLBSYNC |PPC_64B |PPC_64H |PPC_ALTIVEC |PPC_SEGMENT_64B |PPC_SLBI | -PPC_POPCNTB |PPC_POPCNTWD ; +PPC_POPCNTB |PPC_POPCNTWD | +PPC_CILDST ; pcc->insns_flags2 =PPC2_VSX |PPC2_DFP |PPC2_DBRX |PPC2_ISA205 |PPC2_PERM_ISA206 |PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 |
@@ -8397,7 +8398,8 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)PPC_MEM_TLBIE |PPC_MEM_TLBSYNC |PPC_64B |PPC_64H |PPC_64BX |PPC_ALTIVEC |PPC_SEGMENT_64B |PPC_SLBI | -PPC_POPCNTB |PPC_POPCNTWD ; +PPC_POPCNTB |PPC_POPCNTWD | +PPC_CILDST ; pcc->insns_flags2 =PPC2_VSX |PPC2_VSX207 |PPC2_DFP |PPC2_DBRX |PPC2_PERM_ISA206 |PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 |
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 22/77] ppc: Add real mode CI load/store instructions for P7 and P8
Quoted 46 lines · Benjamin Herrenschmidt
Those instructions are only available in hypervisor real mode and allow cache inhibited garded access to devices in that mode.
Signed-off-by Benjamin Herrenschmidt <[email protected]>--- target-ppc/cpu.h | 4 +++- target-ppc/translate.c | 56 +++++++++++++++++++++++++++++++++++---------- target-ppc/translate_init.c | 6 +++-- 3 files changed, 51 insertions(+), 15 deletions(-)target-ppc/cpu.h +3
-1@@ -1913,6 +1913,8 @@ enum {PPC_POPCNTB =0x0000000000001000ULL ,/* string load / store */ PPC_STRING =0x0000000000002000ULL , +/* real mode cache inhibited load / store */ + PPC_CILDST = 0x0000000000004000ULL,/* Floating-point unit extensions */ /* Optional floating point instructions */ @@ -2027,7 +2029,7 @@ enum { | PPC_MFAPIDI | PPC_TLBIVA | PPC_TLBIVAX \ | PPC_4xx_COMMON | PPC_40x_ICBT |PPC_RFMCI \ |PPC_RFDI |PPC_DCR |PPC_DCRX |PPC_DCRUX \ - | PPC_POPCNTWD) + | PPC_POPCNTWD | PPC_CILDST)/* extended type values */ target-ppc/translate.c +1
-1@@ -189,7 +189,7 @@ struct DisasContext {uint32_t opcode;uint32_t exception;/* Routine used to access memory */ -bool pr, hv; +bool pr, hv, dr;int mem_idx;int access_type;/* Translation flags */
target-ppc/translate.c typedef struct opcode_t { · line 383
Quoted 4 lines
target-ppc/translate.c +1
-0@@ -380,9 +380,11 @@ typedef struct opcode_t {#if defined(CONFIG_USER_ONLY )#define CHK_HV GEN_PRIV#define CHK_SV GEN_PRIV +#define CHK_HVDR GEN_PRIV
I'm guessing this is supposed to be CHK_HVRM as below.
target-ppc/translate.c static void glue(gen_, name##u)(DisasContext *ctx) · line 2892
Quoted 13 lines
target-ppc/translate.c +2
-1#else #define CHK_HV do { if (unlikely(ctx->pr || !ctx->hv)) GEN_PRIV; } while(0)#define CHK_SV do { if (unlikely(ctx->pr)) GEN_PRIV; } while(0) +#define CHK_HVRM do { if (unlikely(ctx->pr || !ctx->hv || ctx->dr)) GEN_PRIV; } while(0)#endif #define CHK_NONE @@ -2887,7 +2889,7 @@ static void glue(gen_, name##u)(DisasContext *ctx) }#define GEN_LDUX (name, ldop, opc2, opc3, type) \ -static void glue(gen_, name##ux)(DisasContext *ctx) \ +static void glue(gen_, name##ux)(DisasContext *ctx) \
Extraneous change.
Quoted 174 lines
target-ppc/translate.c +40
-10{ \TCGv EA ; \ if (unlikely(rA(ctx->opcode) == 0 || \@@ -2903,18 +2905,23 @@ static void glue(gen_, name##ux)(DisasContext *ctx)tcg_temp_free (EA ); \ } -#define GEN_LDX_E (name, ldop, opc2, opc3, type, type2) \ +#define GEN_LDX_E (name, ldop, opc2, opc3, type, type2, chk) \ static void glue(gen_, name##x)(DisasContext *ctx) \ { \ TCGv EA; \ + chk; \ gen_set_access_type(ctx, ACCESS_INT); \ EA = tcg_temp_new(); \ gen_addr_reg_index(ctx, EA); \ gen_qemu_##ldop(ctx, cpu_gpr[rD(ctx->opcode)], EA); \ tcg_temp_free(EA); \ } +#define GEN_LDX (name, ldop, opc2, opc3, type) \ - GEN_LDX_E(name, ldop, opc2, opc3, type, PPC_NONE) + GEN_LDX_E(name, ldop, opc2, opc3, type, PPC_NONE, CHK_NONE) + +#define GEN_LDX_HVRM (name, ldop, opc2, opc3, type) \ + GEN_LDX_E(name, ldop, opc2, opc3, type, PPC_NONE, CHK_HVRM)#define GEN_LDS (name, ldop, op, type) \ GEN_LD(name, ldop, op | 0x20, type); \@@ -2940,6 +2947,12 @@ GEN_LDUX(ld, ld64, 0x15, 0x01, PPC_64B);/* ldx */ GEN_LDX (ld, ld64,0x15 ,0x00 ,PPC_64B ); +/* CI load/store variants */ +GEN_LDX_HVRM(ldcix, ld64, 0x15, 0x1b, PPC_CILDST) +GEN_LDX_HVRM(lwzcix, ld32u, 0x15, 0x15, PPC_CILDST) +GEN_LDX_HVRM(lhzcix, ld16u, 0x15, 0x19, PPC_CILDST) +GEN_LDX_HVRM(lbzcix, ld8u, 0x15, 0x1a, PPC_CILDST) +static void gen_ld (DisasContext *ctx) {TCGv EA ;@@ -3058,10 +3071,11 @@ static void glue(gen_, name##ux)(DisasContext *ctx)tcg_temp_free (EA ); \ } -#define GEN_STX_E (name, stop, opc2, opc3, type, type2) \ +#define GEN_STX_E (name, stop, opc2, opc3, type, type2, chk) \ static void glue(gen_, name##x)(DisasContext *ctx) \ { \ TCGv EA; \ + chk; \ gen_set_access_type(ctx, ACCESS_INT); \ EA = tcg_temp_new(); \ gen_addr_reg_index(ctx, EA); \@@ -3069,7 +3083,10 @@ static void glue(gen_, name##x)(DisasContext *ctx) \tcg_temp_free (EA ); \ }#define GEN_STX (name, stop, opc2, opc3, type) \ - GEN_STX_E(name, stop, opc2, opc3, type, PPC_NONE) + GEN_STX_E(name, stop, opc2, opc3, type, PPC_NONE, CHK_NONE) + +#define GEN_STX_HVRM (name, stop, opc2, opc3, type) \ + GEN_STX_E(name, stop, opc2, opc3, type, PPC_NONE, CHK_HVRM)#define GEN_STS (name, stop, op, type) \ GEN_ST(name, stop, op | 0x20, type); \@@ -3086,6 +3103,10 @@ GEN_STS(stw, st32, 0x04, PPC_INTEGER);#if defined(TARGET_PPC64 )GEN_STUX (std, st64,0x15 ,0x05 ,PPC_64B );GEN_STX (std, st64,0x15 ,0x04 ,PPC_64B ); +GEN_STX_HVRM(stdcix, st64, 0x15, 0x1f, PPC_CILDST) +GEN_STX_HVRM(stwcix, st32, 0x15, 0x1c, PPC_CILDST) +GEN_STX_HVRM(sthcix, st16, 0x15, 0x1d, PPC_CILDST) +GEN_STX_HVRM(stbcix, st8, 0x15, 0x1e, PPC_CILDST)static void gen_std (DisasContext *ctx) {@@ -3171,7 +3192,7 @@ static inline void gen_qemu_ld64ur(DisasContext *ctx, TCGv arg1, TCGv arg2)TCGMemOp op =MO_Q | (ctx->default_tcg_memop_mask ^MO_BSWAP ); tcg_gen_qemu_ld_i64(arg1, arg2, ctx->mem_idx, op); } -GEN_LDX_E (ldbr, ld64ur,0x14 ,0x10 ,PPC_NONE ,PPC2_DBRX ); +GEN_LDX_E (ldbr, ld64ur,0x14 ,0x10 ,PPC_NONE ,PPC2_DBRX ,CHK_NONE );#endif /* TARGET_PPC64 */ /* sthbrx */ @@ -3197,7 +3218,7 @@ static inline void gen_qemu_st64r(DisasContext *ctx, TCGv arg1, TCGv arg2)TCGMemOp op =MO_Q | (ctx->default_tcg_memop_mask ^MO_BSWAP ); tcg_gen_qemu_st_i64(arg1, arg2, ctx->mem_idx, op); } -GEN_STX_E (stdbr, st64r,0x14 ,0x14 ,PPC_NONE ,PPC2_DBRX ); +GEN_STX_E (stdbr, st64r,0x14 ,0x14 ,PPC_NONE ,PPC2_DBRX ,CHK_NONE );#endif /* TARGET_PPC64 */ /*** Integer load and store multiple ***/ @@ -10156,7 +10177,7 @@ GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type), GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type),#define GEN_LDUX (name, ldop, opc2, opc3, type) \ GEN_HANDLER(name##ux, 0x1F, opc2, opc3, 0x00000001, type), -#define GEN_LDX_E (name, ldop, opc2, opc3, type, type2) \ +#define GEN_LDX_E (name, ldop, opc2, opc3, type, type2, chk) \ GEN_HANDLER_E(name##x, 0x1F, opc2, opc3, 0x00000001, type, type2),#define GEN_LDS (name, ldop, op, type) \ GEN_LD(name, ldop, op | 0x20, type) \@@ -10173,7 +10194,13 @@ GEN_LDUX(lwa, ld32s, 0x15, 0x0B, PPC_64B) GEN_LDX(lwa, ld32s, 0x15, 0x0A, PPC_64B) GEN_LDUX(ld, ld64, 0x15, 0x01, PPC_64B) GEN_LDX(ld, ld64, 0x15, 0x00, PPC_64B) -GEN_LDX_E(ldbr, ld64ur, 0x14, 0x10, PPC_NONE, PPC2_DBRX) +GEN_LDX_E (ldbr, ld64ur,0x14 ,0x10 ,PPC_NONE ,PPC2_DBRX ,CHK_NONE ) + +/* HV/P7 and later only */ +GEN_LDX_HVRM(ldcix, ld64, 0x15, 0x1b, PPC_CILDST) +GEN_LDX_HVRM(lwzcix, ld32u, 0x15, 0x18, PPC_CILDST) +GEN_LDX_HVRM(lhzcix, ld16u, 0x15, 0x19, PPC_CILDST) +GEN_LDX_HVRM(lbzcix, ld8u, 0x15, 0x1a, PPC_CILDST)#endif GEN_LDX(lhbr, ld16ur, 0x16, 0x18, PPC_INTEGER)GEN_LDX (lwbr, ld32ur,0x16 ,0x10 ,PPC_INTEGER )@@ -10189,7 +10216,7 @@ GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type), GEN_HANDLER(stop##u, opc, 0xFF, 0xFF, 0x00000000, type),#define GEN_STUX (name, stop, opc2, opc3, type) \ GEN_HANDLER(name##ux, 0x1F, opc2, opc3, 0x00000001, type), -#define GEN_STX_E (name, stop, opc2, opc3, type, type2) \ +#define GEN_STX_E (name, stop, opc2, opc3, type, type2, chk) \ GEN_HANDLER_E(name##x, 0x1F, opc2, opc3, 0x00000001, type, type2),#define GEN_STS (name, stop, op, type) \ GEN_ST(name, stop, op | 0x20, type) \@@ -10203,7 +10230,11 @@ GEN_STS(stw, st32, 0x04, PPC_INTEGER)#if defined(TARGET_PPC64 ) GEN_STUX(std, st64, 0x15, 0x05, PPC_64B) GEN_STX(std, st64, 0x15, 0x04, PPC_64B) -GEN_STX_E(stdbr, st64r, 0x14, 0x14, PPC_NONE, PPC2_DBRX) +GEN_STX_E(stdbr, st64r, 0x14, 0x14, PPC_NONE, PPC2_DBRX, CHK_NONE) +GEN_STX_HVRM(stdcix, st64, 0x15, 0x1f, PPC_CILDST) +GEN_STX_HVRM(stwcix, st32, 0x15, 0x1c, PPC_CILDST) +GEN_STX_HVRM(sthcix, st16, 0x15, 0x1d, PPC_CILDST) +GEN_STX_HVRM(stbcix, st8, 0x15, 0x1e, PPC_CILDST)#endif GEN_STX(sthbr, st16r, 0x16, 0x1C, PPC_INTEGER)GEN_STX (stwbr, st32r,0x16 ,0x14 ,PPC_INTEGER )@@ -11369,6 +11400,7 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb) ctx.spr_cb = env->spr_cb; ctx.pr = msr_pr; ctx.mem_idx = env->dmmu_idx; + ctx.dr = msr_dr;#if !defined(CONFIG_USER_ONLY ) ctx.hv = !msr_pr && (msr_hv || !env->has_hv_mode);#endif target-ppc/translate_init.c +4
-2@@ -8320,7 +8320,8 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)PPC_MEM_TLBIE |PPC_MEM_TLBSYNC |PPC_64B |PPC_64H |PPC_ALTIVEC |PPC_SEGMENT_64B |PPC_SLBI | -PPC_POPCNTB |PPC_POPCNTWD ; +PPC_POPCNTB |PPC_POPCNTWD | +PPC_CILDST ; pcc->insns_flags2 =PPC2_VSX |PPC2_DFP |PPC2_DBRX |PPC2_ISA205 |PPC2_PERM_ISA206 |PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 |@@ -8397,7 +8398,8 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)PPC_MEM_TLBIE |PPC_MEM_TLBSYNC |PPC_64B |PPC_64H |PPC_64BX |PPC_ALTIVEC |PPC_SEGMENT_64B |PPC_SLBI | -PPC_POPCNTB |PPC_POPCNTWD ; +PPC_POPCNTB |PPC_POPCNTWD | +PPC_CILDST ; pcc->insns_flags2 =PPC2_VSX |PPC2_VSX207 |PPC2_DFP |PPC2_DBRX |PPC2_PERM_ISA206 |PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 |
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [Qemu-ppc] [PATCH 22/77] ppc: Add real mode CI load/store instructions for P7 and P8
Quoted 8 lines · David Gibson
target-ppc/translate.c typedef struct opcode_t { · line 383
Quoted 6 lines
target-ppc/translate.c +1
-0@@ -380,9 +380,11 @@ typedef struct opcode_t { #if defined(CONFIG_USER_ONLY) #define CHK_HV GEN_PRIV #define CHK_SV GEN_PRIV +#define CHK_HVDR GEN_PRIVI'm guessing this is supposed to be
CHK_HVRMas below.
Indeed. I had test built ... odd.
Quoted 7 lines
Quoted 7 lines
target-ppc/translate.c +1
-0#else #define CHK_HV do { if (unlikely(ctx->pr || !ctx->hv)) GEN_PRIV; } while(0) #define CHK_SV do { if (unlikely(ctx->pr)) GEN_PRIV; } while(0) +#define CHK_HVRM do { if (unlikely(ctx->pr || !ctx->hv || ctx->dr)) GEN_PRIV; } while(0) #endif
#defineCHK_NONE
Quoted 8 lines
target-ppc/translate.c static void glue(gen_, name##u)(DisasContext *ctx) · line 2892
Quoted 6 lines
(quoted diff) +0
-0@@ -2887,7 +2889,7 @@ static void glue(gen_, name##u)(DisasContext *ctx) }
#defineGEN_LDUX(name, ldop, opc2, opc3, type)\target-ppc/translate.c +1
-1-static void glue(gen_, name##ux)(DisasContext *ctx) \ +static void glue(gen_, name##ux)(DisasContext *ctx) \Extraneous change.
Fixed. Thanks.
Cheers,
Ben.
PATCH 23/77 ppc: Turn a bunch of booleans from int to bool
In reply to Benjamin Herrenschmidt--- target-ppc/translate.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-)
target-ppc/translate.c +19 -20
@@ -189,21 +189,20 @@ struct DisasContext {uint32_t opcode;uint32_t exception;/* Routine used to access memory */ -bool pr, hv, dr; +bool pr, hv, dr, le_mode;int mem_idx;int access_type;/* Translation flags */ -int le_mode;TCGMemOp default_tcg_memop_mask;#if defined(TARGET_PPC64 ) -int sf_mode; -int has_cfar; +bool sf_mode; +bool has_cfar;#endif -int fpu_enabled; -int altivec_enabled; -int vsx_enabled; -int spe_enabled; -int tm_enabled; +bool fpu_enabled; +bool altivec_enabled; +bool vsx_enabled; +bool spe_enabled; +bool tm_enabled;ppc_spr_t *spr_cb;/* Needed to check rights for mfspr/mtspr */ int singlestep_enabled;uint64_t insns_flags;
@@ -380,7 +379,7 @@ typedef struct opcode_t {#if defined(CONFIG_USER_ONLY )#define CHK_HV GEN_PRIV#define CHK_SV GEN_PRIV -#define CHK_HVDR GEN_PRIV +#define CHK_HVRM GEN_PRIV#else #define CHK_HV do { if (unlikely(ctx->pr || !ctx->hv)) GEN_PRIV; } while(0)#define CHK_SV do { if (unlikely(ctx->pr)) GEN_PRIV; } while(0)
@@ -11407,31 +11406,31 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb) ctx.insns_flags = env->insns_flags; ctx.insns_flags2 = env->insns_flags2; ctx.access_type =-1 ; - ctx.le_mode = env->hflags & (1 <<MSR_LE ) ?1 :0 ; + ctx.le_mode = !!(env->hflags & (1 <<MSR_LE )); ctx.default_tcg_memop_mask = ctx.le_mode ?MO_LE :MO_BE ;#if defined(TARGET_PPC64 ) ctx.sf_mode =msr_is_64bit (env, env->msr); ctx.has_cfar = !!(env->flags &POWERPC_FLAG_CFAR );#endif - ctx.fpu_enabled = msr_fp; + ctx.fpu_enabled = !!msr_fp;if ((env->flags &POWERPC_FLAG_SPE ) && msr_spe) - ctx.spe_enabled = msr_spe; + ctx.spe_enabled = !!msr_spe;else - ctx.spe_enabled =0 ; + ctx.spe_enabled = false;if ((env->flags &POWERPC_FLAG_VRE ) && msr_vr) - ctx.altivec_enabled = msr_vr; + ctx.altivec_enabled = !!msr_vr;else - ctx.altivec_enabled =0 ; + ctx.altivec_enabled = false;if ((env->flags &POWERPC_FLAG_VSX ) && msr_vsx) { - ctx.vsx_enabled = msr_vsx; + ctx.vsx_enabled = !!msr_vsx; }else { - ctx.vsx_enabled =0 ; + ctx.vsx_enabled = false; }#if defined(TARGET_PPC64 )if ((env->flags &POWERPC_FLAG_TM ) && msr_tm) { - ctx.tm_enabled = msr_tm; + ctx.tm_enabled = !!msr_tm; }else { - ctx.tm_enabled =0 ; + ctx.tm_enabled = false; }#endif if ((env->flags &POWERPC_FLAG_SE ) && msr_se)
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 23/77] ppc: Turn a bunch of booleans from int to bool
Quoted 1 line · Benjamin Herrenschmidt
Signed-off-by Benjamin Herrenschmidt <[email protected]>
Quoted 89 lines
--- target-ppc/translate.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-)target-ppc/translate.c +19
-20@@ -189,21 +189,20 @@ struct DisasContext {uint32_t opcode;uint32_t exception;/* Routine used to access memory */ -bool pr, hv, dr; +bool pr, hv, dr, le_mode;int mem_idx;int access_type;/* Translation flags */ -int le_mode;TCGMemOp default_tcg_memop_mask;#if defined(TARGET_PPC64 ) -int sf_mode; -int has_cfar; +bool sf_mode; +bool has_cfar;#endif -int fpu_enabled; -int altivec_enabled; -int vsx_enabled; -int spe_enabled; -int tm_enabled; +bool fpu_enabled; +bool altivec_enabled; +bool vsx_enabled; +bool spe_enabled; +bool tm_enabled;ppc_spr_t *spr_cb;/* Needed to check rights for mfspr/mtspr */ int singlestep_enabled;uint64_t insns_flags;@@ -380,7 +379,7 @@ typedef struct opcode_t {#if defined(CONFIG_USER_ONLY )#define CHK_HV GEN_PRIV#define CHK_SV GEN_PRIV -#define CHK_HVDR GEN_PRIV +#define CHK_HVRM GEN_PRIV#else #define CHK_HV do { if (unlikely(ctx->pr || !ctx->hv)) GEN_PRIV; } while(0)#define CHK_SV do { if (unlikely(ctx->pr)) GEN_PRIV; } while(0)@@ -11407,31 +11406,31 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb) ctx.insns_flags = env->insns_flags; ctx.insns_flags2 = env->insns_flags2; ctx.access_type =-1 ; - ctx.le_mode = env->hflags & (1 <<MSR_LE ) ?1 :0 ; + ctx.le_mode = !!(env->hflags & (1 <<MSR_LE )); ctx.default_tcg_memop_mask = ctx.le_mode ?MO_LE :MO_BE ;#if defined(TARGET_PPC64 ) ctx.sf_mode =msr_is_64bit (env, env->msr); ctx.has_cfar = !!(env->flags &POWERPC_FLAG_CFAR );#endif - ctx.fpu_enabled = msr_fp; + ctx.fpu_enabled = !!msr_fp;if ((env->flags &POWERPC_FLAG_SPE ) && msr_spe) - ctx.spe_enabled = msr_spe; + ctx.spe_enabled = !!msr_spe;else - ctx.spe_enabled =0 ; + ctx.spe_enabled = false;if ((env->flags &POWERPC_FLAG_VRE ) && msr_vr) - ctx.altivec_enabled = msr_vr; + ctx.altivec_enabled = !!msr_vr;else - ctx.altivec_enabled =0 ; + ctx.altivec_enabled = false;if ((env->flags &POWERPC_FLAG_VSX ) && msr_vsx) { - ctx.vsx_enabled = msr_vsx; + ctx.vsx_enabled = !!msr_vsx; }else { - ctx.vsx_enabled =0 ; + ctx.vsx_enabled = false; }#if defined(TARGET_PPC64 )if ((env->flags &POWERPC_FLAG_TM ) && msr_tm) { - ctx.tm_enabled = msr_tm; + ctx.tm_enabled = !!msr_tm; }else { - ctx.tm_enabled =0 ; + ctx.tm_enabled = false; }#endif if ((env->flags &POWERPC_FLAG_SE ) && msr_se)
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 24/77 ppc: Move exception generation code out of line
In reply to Benjamin HerrenschmidtThere's no point inlining this, if you hit the exception case you exit anyway, and not inlining saves about 100K of code size (and cache footprint).
--- target-ppc/translate.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
target-ppc/translate.c +6 -3
@@ -279,7 +279,8 @@ void gen_update_current_nip(void *opaque)tcg_gen_movi_tl (cpu_nip, ctx->nip); } -static inline void gen_exception_err (DisasContext *ctx,uint32_t excp,uint32_t error) +static void __attribute__((noinline)) +gen_exception_err (DisasContext *ctx,uint32_t excp,uint32_t error) {TCGv_i32 t0, t1;if (ctx->exception ==POWERPC_EXCP_NONE ) {
@@ -293,7 +294,8 @@ static inline void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t ctx->exception = (excp); } -static inline void gen_exception (DisasContext *ctx,uint32_t excp) +static void __attribute__((noinline)) +gen_exception (DisasContext *ctx,uint32_t excp) {TCGv_i32 t0;if (ctx->exception ==POWERPC_EXCP_NONE ) {
@@ -305,7 +307,8 @@ static inline void gen_exception(DisasContext *ctx, uint32_t excp) ctx->exception = (excp); } -static inline void gen_debug_exception (DisasContext *ctx) +static void __attribute__((noinline)) +gen_debug_exception (DisasContext *ctx) {TCGv_i32 t0;
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 24/77] ppc: Move exception generation code out of line
Quoted 2 lines · Benjamin Herrenschmidt
There's no point inlining this, if you hit the exception case you exit anyway,
That doesn't quite seem relevant - IIUC this is affecting inlining in the code generation path, rather than the code execution path.
Quoted 2 lines
and not inlining saves about 100K of code size (and cache footprint).
That sounds like a win, though.
Quoted 11 lines
Signed-off-by Benjamin Herrenschmidt <[email protected]>--- target-ppc/translate.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)target-ppc/translate.c +0
-0
target-ppc/translate.c void gen_update_current_nip(void *opaque) · line 283
Quoted 6 lines
target-ppc/translate.c +2
-1@@ -279,7 +279,8 @@ void gen_update_current_nip(void *opaque)tcg_gen_movi_tl (cpu_nip, ctx->nip); } -static inline void gen_exception_err (DisasContext *ctx,uint32_t excp,uint32_t error) +static void __attribute__((noinline)) +gen_exception_err (DisasContext *ctx,uint32_t excp,uint32_t error)
I thought we generally avoided bare gcc attributes in qemu, but I don't see a helper macro for it and I do see it used in a few other places, so I guess its ok.
Quoted 23 lines
target-ppc/translate.c +4
-2{TCGv_i32 t0, t1;if (ctx->exception ==POWERPC_EXCP_NONE ) {@@ -293,7 +294,8 @@ static inline void gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t ctx->exception = (excp); } -static inline void gen_exception (DisasContext *ctx,uint32_t excp) +static void __attribute__((noinline)) +gen_exception (DisasContext *ctx,uint32_t excp) {TCGv_i32 t0;if (ctx->exception ==POWERPC_EXCP_NONE ) {@@ -305,7 +307,8 @@ static inline void gen_exception(DisasContext *ctx, uint32_t excp) ctx->exception = (excp); } -static inline void gen_debug_exception (DisasContext *ctx) +static void __attribute__((noinline)) +gen_debug_exception (DisasContext *ctx) {TCGv_i32 t0;
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [Qemu-ppc] [PATCH 24/77] ppc: Move exception generation code out of line
Quoted 7 lines · David Gibson
Quoted 2 lines · Benjamin Herrenschmidt
There's no point inlining this, if you hit the exception case you exit anyway,
That doesn't quite seem relevant - IIUC this is affecting inlining in the code generation path, rather than the code execution path.
Well, the generation path is also slightly performance sensitive. My point was making the error path inline wasn't buying us anything.
Quoted 4 lines
Quoted 2 lines
and not inlining saves about 100K of code size (and cache footprint).
That sounds like a win, though.
Yup.
.../...
Quoted 9 lines
Quoted 5 lines
-static inline void
gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_t error)(quoted diff) +2
-0+static void __attribute__((noinline)) +gen_exception_err(DisasContext *ctx, uint32_t excp, uint32_terror)
I thought we generally avoided bare gcc attributes in qemu, but I don't see a helper macro for it and I do see it used in a few other places, so I guess its ok.
That was my guess too...
Quoted 26 lines
Quoted 25 lines
{
TCGv_i32 t0, t1;
if (ctx->exception==POWERPC_EXCP_NONE) {(quoted diff) +0
-0@@ -293,7 +294,8 @@ static inline voidgen_exception_err(DisasContext *ctx,
uint32_texcp,uint32_tctx->exception= (excp);
}target-ppc/translate.c +2
-1-static inline void gen_exception (DisasContext *ctx,uint32_t excp) +static void __attribute__((noinline)) +gen_exception (DisasContext *ctx,uint32_t excp){
TCGv_i32 t0;
if (ctx->exception==POWERPC_EXCP_NONE) {target-ppc/translate.c +0
-0@@ -305,7 +307,8 @@ static inline void gen_exception(DisasContext *ctx, uint32_t excp) ctx->exception = (excp); }target-ppc/translate.c +2
-1-static inline void gen_debug_exception (DisasContext *ctx) +static void __attribute__((noinline)) +gen_debug_exception (DisasContext *ctx){
TCGv_i32 t0;
PATCH 25/77 ppc: Add P7/P8 Power Management instructions
In reply to Benjamin HerrenschmidtThis adds the ISA 2.06 and later power management instructions (doze, nap, sleep and rvwinkle) and associated wakeup cause testing in LPCR
--- target-ppc/cpu.h | 26 ++++++++++++- target-ppc/excp_helper.c | 59 +++++++++++++++++++++++++++++ target-ppc/helper.h | 1 + target-ppc/translate.c | 66 ++++++++++++++++++++++++++++++++ target-ppc/translate_init.c | 92 ++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 241 insertions(+), 3 deletions(-)
target-ppc/cpu.h +25 -1
@@ -300,6 +300,15 @@ enum { };/*****************************************************************************/ +/* PM instructions */ +typedef enum { +PPC_PM_DOZE , +PPC_PM_NAP , +PPC_PM_SLEEP , +PPC_PM_RVWINKLE , +}powerpc_pm_insn_t ; + +/*****************************************************************************/ /* Input pins model */ typedef enum powerpc_input_t powerpc_input_t ;enum powerpc_input_t {
@@ -490,6 +499,14 @@ struct ppc_slb_t {#define LPCR_LPES1 (1ull << (63-61))#define LPCR_AIL_SHIFT (63-40)/* Alternate interrupt location */ #define LPCR_AIL (3ull << LPCR_AIL_SHIFT) +#define LPCR_P7_PECE0 (1ull << (63-49)) +#define LPCR_P7_PECE1 (1ull << (63-50)) +#define LPCR_P7_PECE2 (1ull << (63-51)) +#define LPCR_P8_PECE0 (1ull << (63-47)) +#define LPCR_P8_PECE1 (1ull << (63-48)) +#define LPCR_P8_PECE2 (1ull << (63-49)) +#define LPCR_P8_PECE3 (1ull << (63-50)) +#define LPCR_P8_PECE4 (1ull << (63-51))#define msr_sf ((env->msr >> MSR_SF) & 1)#define msr_isf ((env->msr >> MSR_ISF) & 1)
@@ -1126,6 +1143,11 @@ struct CPUPPCState {* instructions and SPRs are diallowed if MSR:HV is 0 */ bool has_hv_mode; +/* On P7/P8, set when in PM state, we need to handle resume +* in a special way (such as routing some resume causes to +* 0x100), so flag this here. +*/ +bool in_pm_state;#endif /* Those resources are used only during code translation */
@@ -2069,6 +2091,8 @@ enum {PPC2_FP_CVT_S64 =0x0000000000010000ULL ,/* Transactional Memory (ISA 2.07, Book II) */ PPC2_TM =0x0000000000020000ULL , +/* Server PM instructgions (ISA 2.06, Book III) */ +PPC2_PM_ISA206 =0x0000000000040000ULL , #define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_VSX | PPC2_PRCNTL | PPC2_DBRX | \ PPC2_ISA205 | PPC2_VSX207 | PPC2_PERM_ISA206 | \
@@ -2076,7 +2100,7 @@ enum {PPC2_FP_CVT_ISA206 |PPC2_FP_TST_ISA206 | \PPC2_BCTAR_ISA207 |PPC2_LSQ_ISA207 | \PPC2_ALTIVEC_207 |PPC2_ISA207S |PPC2_DFP | \ - PPC2_FP_CVT_S64 | PPC2_TM) + PPC2_FP_CVT_S64 | PPC2_TM | PPC2_PM_ISA206) };/*****************************************************************************/
target-ppc/excp_helper.c +59 -0
71 lines not on this page · raw message
target-ppc/helper.h +1 -0
@@ -13,6 +13,7 @@ DEF_HELPER_1(rfci, void, env) DEF_HELPER_1(rfdi, void, env) DEF_HELPER_1(rfmci, void, env)#if defined(TARGET_PPC64 ) +DEF_HELPER_2(pminsn, void, env, i32) DEF_HELPER_1(rfid, void, env) DEF_HELPER_1(hrfid, void, env)#endif
target-ppc/translate.c +66 -0
78 lines not on this page · raw message
target-ppc/translate_init.c +90 -2
142 lines not on this page · raw message
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 25/77] ppc: Add P7/P8 Power Management instructions
Quoted 5 lines · Benjamin Herrenschmidt
This adds the ISA 2.06 and later power management instructions (doze, nap, sleep and rvwinkle) and associated wakeup cause testing in LPCR
Signed-off-by Benjamin Herrenschmidt <[email protected]>
Looks fine, though I haven't checked against the ISA in detail.
Quoted 399 lines
--- target-ppc/cpu.h | 26 ++++++++++++- target-ppc/excp_helper.c | 59 +++++++++++++++++++++++++++++ target-ppc/helper.h | 1 + target-ppc/translate.c | 66 ++++++++++++++++++++++++++++++++ target-ppc/translate_init.c | 92 ++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 241 insertions(+), 3 deletions(-)target-ppc/cpu.h +25
-1@@ -300,6 +300,15 @@ enum { };/*****************************************************************************/ +/* PM instructions */ +typedef enum { +PPC_PM_DOZE , +PPC_PM_NAP , +PPC_PM_SLEEP , +PPC_PM_RVWINKLE , +}powerpc_pm_insn_t ; + +/*****************************************************************************/ /* Input pins model */ typedef enum powerpc_input_t powerpc_input_t ;enum powerpc_input_t {@@ -490,6 +499,14 @@ struct ppc_slb_t {#define LPCR_LPES1 (1ull << (63-61))#define LPCR_AIL_SHIFT (63-40)/* Alternate interrupt location */ #define LPCR_AIL (3ull << LPCR_AIL_SHIFT) +#define LPCR_P7_PECE0 (1ull << (63-49)) +#define LPCR_P7_PECE1 (1ull << (63-50)) +#define LPCR_P7_PECE2 (1ull << (63-51)) +#define LPCR_P8_PECE0 (1ull << (63-47)) +#define LPCR_P8_PECE1 (1ull << (63-48)) +#define LPCR_P8_PECE2 (1ull << (63-49)) +#define LPCR_P8_PECE3 (1ull << (63-50)) +#define LPCR_P8_PECE4 (1ull << (63-51))#define msr_sf ((env->msr >> MSR_SF) & 1)#define msr_isf ((env->msr >> MSR_ISF) & 1)@@ -1126,6 +1143,11 @@ struct CPUPPCState {* instructions and SPRs are diallowed if MSR:HV is 0 */ bool has_hv_mode; +/* On P7/P8, set when in PM state, we need to handle resume +* in a special way (such as routing some resume causes to +* 0x100), so flag this here. +*/ +bool in_pm_state;#endif /* Those resources are used only during code translation */ @@ -2069,6 +2091,8 @@ enum {PPC2_FP_CVT_S64 =0x0000000000010000ULL ,/* Transactional Memory (ISA 2.07, Book II) */ PPC2_TM =0x0000000000020000ULL , +/* Server PM instructgions (ISA 2.06, Book III) */ +PPC2_PM_ISA206 =0x0000000000040000ULL , #define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_VSX | PPC2_PRCNTL | PPC2_DBRX | \ PPC2_ISA205 | PPC2_VSX207 | PPC2_PERM_ISA206 | \@@ -2076,7 +2100,7 @@ enum {PPC2_FP_CVT_ISA206 |PPC2_FP_TST_ISA206 | \PPC2_BCTAR_ISA207 |PPC2_LSQ_ISA207 | \PPC2_ALTIVEC_207 |PPC2_ISA207S |PPC2_DFP | \ - PPC2_FP_CVT_S64 | PPC2_TM) + PPC2_FP_CVT_S64 | PPC2_TM | PPC2_PM_ISA206) };/*****************************************************************************/ target-ppc/excp_helper.c +59
-0@@ -100,6 +100,44 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp) asrr0 =-1 ; asrr1 =-1 ; +/* check for special resume at 0x100 from doze/nap/sleep/winkle on P7/P8 */ +if (env->in_pm_state) { + env->in_pm_state = false; + +/* Pretend to be returning from doze always as we don't lose state */ + msr |= (0x1ull << (63 -47 )); + +/* Non-machine check are routed to 0x100 with a wakeup cause +* encoded in SRR1 +*/ +if (excp !=POWERPC_EXCP_MCHECK ) { +switch (excp) { +case POWERPC_EXCP_RESET : + msr |=0x4ull << (63 -45 ); +break ; +case POWERPC_EXCP_EXTERNAL : + msr |=0x8ull << (63 -45 ); +break ; +case POWERPC_EXCP_DECR : + msr |=0x6ull << (63 -45 ); +break ; +case POWERPC_EXCP_SDOOR : + msr |=0x5ull << (63 -45 ); +break ; +case POWERPC_EXCP_SDOOR_HV : + msr |=0x3ull << (63 -45 ); +break ; +case POWERPC_EXCP_HV_MAINT : + msr |=0xaull << (63 -45 ); +break ; +default : +cpu_abort (cs,"Unsupported exception %d in Power Save mode\n" , + excp); + } + excp =POWERPC_EXCP_RESET ; + } + } +/* Exception targetting modifiers * * LPES0 is supported on POWER7/8 @@ -898,6 +936,27 @@ void helper_store_msr(CPUPPCState *env, target_ulong val) } } +#if defined(TARGET_PPC64 ) +void helper_pminsn (CPUPPCState *env,powerpc_pm_insn_t insn) +{ +CPUState *cs; + + cs =CPU (ppc_env_get_cpu (env)); + cs->halted =1 ; + env->in_pm_state = true; + +/* Technically, nap doesn't set EE, but if we don't set it +* then ppc_hw_interrupt() won't deliver. We could add some +* other tests there based on LPCR but it's simpler to just +* whack EE in. It will be cleared by the 0x100 at wakeup +* anyway. It will still be observable by the guest in SRR1 +* but this doesn't seem to be a problem. +*/ + env->msr |= (1ull <<MSR_EE ); +helper_raise_exception (env,EXCP_HLT ); +} +#endif /* defined(TARGET_PPC64) */ +static inline void do_rfi (CPUPPCState *env,target_ulong nip,target_ulong msr,target_ulong msrm,int keep_msrh) {target-ppc/helper.h +1
-0@@ -13,6 +13,7 @@ DEF_HELPER_1(rfci, void, env) DEF_HELPER_1(rfdi, void, env) DEF_HELPER_1(rfmci, void, env)#if defined(TARGET_PPC64 ) +DEF_HELPER_2(pminsn, void, env, i32) DEF_HELPER_1(rfid, void, env) DEF_HELPER_1(hrfid, void, env)#endif target-ppc/translate.c +66
-0@@ -3567,6 +3567,68 @@ static void gen_wait(DisasContext *ctx)gen_exception_err (ctx,EXCP_HLT ,1 ); } +#if defined(TARGET_PPC64 ) +static void gen_doze (DisasContext *ctx) +{ +#if defined(CONFIG_USER_ONLY ) +GEN_PRIV ; +#else +TCGv_i32 t; + +CHK_HV ; + t =tcg_const_i32 (PPC_PM_DOZE ); +gen_helper_pminsn (cpu_env, t); +tcg_temp_free_i32 (t); +gen_stop_exception (ctx); +#endif /* defined(CONFIG_USER_ONLY) */ +} + +static void gen_nap (DisasContext *ctx) +{ +#if defined(CONFIG_USER_ONLY ) +GEN_PRIV ; +#else +TCGv_i32 t; + +CHK_HV ; + t =tcg_const_i32 (PPC_PM_NAP ); +gen_helper_pminsn (cpu_env, t); +tcg_temp_free_i32 (t); +gen_stop_exception (ctx); +#endif /* defined(CONFIG_USER_ONLY) */ +} + +static void gen_sleep (DisasContext *ctx) +{ +#if defined(CONFIG_USER_ONLY ) +GEN_PRIV ; +#else +TCGv_i32 t; + +CHK_HV ; + t =tcg_const_i32 (PPC_PM_SLEEP ); +gen_helper_pminsn (cpu_env, t); +tcg_temp_free_i32 (t); +gen_stop_exception (ctx); +#endif /* defined(CONFIG_USER_ONLY) */ +} + +static void gen_rvwinkle (DisasContext *ctx) +{ +#if defined(CONFIG_USER_ONLY ) +GEN_PRIV ; +#else +TCGv_i32 t; + +CHK_HV ; + t =tcg_const_i32 (PPC_PM_RVWINKLE ); +gen_helper_pminsn (cpu_env, t); +tcg_temp_free_i32 (t); +gen_stop_exception (ctx); +#endif /* defined(CONFIG_USER_ONLY) */ +} +#endif /* #if defined(TARGET_PPC64) */ +/*** Floating-point load ***/ #define GEN_LDF (name, ldop, opc, type) \ static void glue(gen_, name)(DisasContext *ctx) \@@ -9828,6 +9890,10 @@ GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER), GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW),#if defined(TARGET_PPC64 )GEN_HANDLER (rfid,0x13 ,0x12 ,0x00 ,0x03FF8001 ,PPC_64B ), +GEN_HANDLER_E (doze,0x13 ,0x12 ,0x0c ,0x03FFF801 ,PPC_NONE ,PPC2_PM_ISA206 ), +GEN_HANDLER_E (nap,0x13 ,0x12 ,0x0d ,0x03FFF801 ,PPC_NONE ,PPC2_PM_ISA206 ), +GEN_HANDLER_E (sleep,0x13 ,0x12 ,0x0e ,0x03FFF801 ,PPC_NONE ,PPC2_PM_ISA206 ), +GEN_HANDLER_E (rvwinkle,0x13 ,0x12 ,0x0f ,0x03FFF801 ,PPC_NONE ,PPC2_PM_ISA206 ),GEN_HANDLER (hrfid,0x13 ,0x12 ,0x08 ,0x03FF8001 ,PPC_64H ), #endif GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFF01D, PPC_FLOW),target-ppc/translate_init.c +90
-2@@ -8297,10 +8297,45 @@ static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, uint32_t pvr)return false; } +static bool cpu_has_work_POWER7 (CPUState *cs) +{ +PowerPCCPU *cpu =POWERPC_CPU (cs); +CPUPPCState *env = &cpu->env; + +if (cs->halted) { +if (!(cs->interrupt_request &CPU_INTERRUPT_HARD )) { +return false; + } +if ((env->pending_interrupts & (1u <<PPC_INTERRUPT_EXT )) && + (env->spr[SPR_LPCR ] &LPCR_P7_PECE0 )) { +return true; + } +if ((env->pending_interrupts & (1u <<PPC_INTERRUPT_DECR )) && + (env->spr[SPR_LPCR ] &LPCR_P7_PECE1 )) { +return true; + } +if ((env->pending_interrupts & (1u <<PPC_INTERRUPT_MCK )) && + (env->spr[SPR_LPCR ] &LPCR_P7_PECE2 )) { +return true; + } +if ((env->pending_interrupts & (1u <<PPC_INTERRUPT_HMI )) && + (env->spr[SPR_LPCR ] &LPCR_P7_PECE2 )) { +return true; + } +if (env->pending_interrupts & (1u <<PPC_INTERRUPT_RESET )) { +return true; + } +return false; + }else { +return msr_ee && (cs->interrupt_request &CPU_INTERRUPT_HARD ); + } +} +POWERPC_FAMILY (POWER7 )(ObjectClass *oc,void *data) {DeviceClass *dc =DEVICE_CLASS (oc);PowerPCCPUClass *pcc =POWERPC_CPU_CLASS (oc); +CPUClass *cc =CPU_CLASS (oc); dc->fw_name ="PowerPC,POWER7" ; dc->desc ="POWER7" ;@@ -8309,6 +8344,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) pcc->pcr_mask =PCR_COMPAT_2_05 |PCR_COMPAT_2_06 ; pcc->init_proc = init_proc_POWER7; pcc->check_pow = check_pow_nocheck; + cc->has_work = cpu_has_work_POWER7; pcc->insns_flags =PPC_INSNS_BASE |PPC_ISEL |PPC_STRING |PPC_MFTB |PPC_FLOAT |PPC_FLOAT_FSEL |PPC_FLOAT_FRES | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |@@ -8325,7 +8361,8 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) pcc->insns_flags2 =PPC2_VSX |PPC2_DFP |PPC2_DBRX |PPC2_ISA205 |PPC2_PERM_ISA206 |PPC2_DIVE_ISA206 |PPC2_ATOMIC_ISA206 |PPC2_FP_CVT_ISA206 | -PPC2_FP_TST_ISA206 |PPC2_FP_CVT_S64 ; +PPC2_FP_TST_ISA206 |PPC2_FP_CVT_S64 | +PPC2_PM_ISA206 ; pcc->msr_mask = (1ull <<MSR_SF ) | (1ull <<MSR_VR ) | (1ull << MSR_VSX) |@@ -8375,10 +8412,53 @@ static bool ppc_pvr_match_power8(PowerPCCPUClass *pcc, uint32_t pvr)return false; } +static bool cpu_has_work_POWER8 (CPUState *cs) +{ +PowerPCCPU *cpu =POWERPC_CPU (cs); +CPUPPCState *env = &cpu->env; + +if (cs->halted) { +if (!(cs->interrupt_request &CPU_INTERRUPT_HARD )) { +return false; + } +if ((env->pending_interrupts & (1u <<PPC_INTERRUPT_EXT )) && + (env->spr[SPR_LPCR ] &LPCR_P8_PECE2 )) { +return true; + } +if ((env->pending_interrupts & (1u <<PPC_INTERRUPT_DECR )) && + (env->spr[SPR_LPCR ] &LPCR_P8_PECE3 )) { +return true; + } +if ((env->pending_interrupts & (1u <<PPC_INTERRUPT_MCK )) && + (env->spr[SPR_LPCR ] &LPCR_P8_PECE4 )) { +return true; + } +if ((env->pending_interrupts & (1u <<PPC_INTERRUPT_HMI )) && + (env->spr[SPR_LPCR ] &LPCR_P8_PECE4 )) { +return true; + } +if ((env->pending_interrupts & (1u <<PPC_INTERRUPT_DOORBELL )) && + (env->spr[SPR_LPCR ] &LPCR_P8_PECE0 )) { +return true; + } +if ((env->pending_interrupts & (1u <<PPC_INTERRUPT_HDOORBELL )) && + (env->spr[SPR_LPCR ] &LPCR_P8_PECE1 )) { +return true; + } +if (env->pending_interrupts & (1u <<PPC_INTERRUPT_RESET )) { +return true; + } +return false; + }else { +return msr_ee && (cs->interrupt_request &CPU_INTERRUPT_HARD ); + } +} +POWERPC_FAMILY (POWER8 )(ObjectClass *oc,void *data) {DeviceClass *dc =DEVICE_CLASS (oc);PowerPCCPUClass *pcc =POWERPC_CPU_CLASS (oc); +CPUClass *cc =CPU_CLASS (oc); dc->fw_name ="PowerPC,POWER8" ; dc->desc ="POWER8" ;@@ -8387,6 +8467,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) pcc->pcr_mask =PCR_COMPAT_2_05 |PCR_COMPAT_2_06 ; pcc->init_proc = init_proc_POWER8; pcc->check_pow = check_pow_nocheck; + cc->has_work = cpu_has_work_POWER8; pcc->insns_flags =PPC_INSNS_BASE |PPC_ISEL |PPC_STRING |PPC_MFTB |PPC_FLOAT |PPC_FLOAT_FSEL |PPC_FLOAT_FRES | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |@@ -8406,7 +8487,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)PPC2_FP_TST_ISA206 |PPC2_BCTAR_ISA207 |PPC2_LSQ_ISA207 |PPC2_ALTIVEC_207 |PPC2_ISA205 |PPC2_ISA207S |PPC2_FP_CVT_S64 | -PPC2_TM ; +PPC2_TM |PPC2_PM_ISA206 ; pcc->msr_mask = (1ull <<MSR_SF ) | (1ull <<MSR_SHV ) | (1ull << MSR_TM) |@@ -8464,6 +8545,13 @@ void cpu_ppc_set_papr(PowerPCCPU *cpu) lpcr->default_value &= ~(LPCR_VPM0 |LPCR_VPM1 |LPCR_ISL |LPCR_KBV ); lpcr->default_value |=LPCR_LPES0 |LPCR_LPES1 ; +/* P7 and P8 has slightly different PECE bits, mostly because P8 adds +* bit 47 and 48 which are reserved on P7. Here we set them all, which +* will work as expected for both implementations +*/ + lpcr->default_value |=LPCR_P8_PECE0 |LPCR_P8_PECE1 |LPCR_P8_PECE2 | +LPCR_P8_PECE3 |LPCR_P8_PECE4 ; +/* We should be followed by a CPU reset but update the active value * just in case... */
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 26/77 ppc/pnv: Add skeletton PowerNV platform
In reply to Benjamin HerrenschmidtNo devices yet, not even an interrupt controller, just to get started.
--- default-configs/ppc64-softmmu.mak | 1 + hw/ppc/Makefile.objs | 2 + hw/ppc/pnv.c | 600 ++++++++++++++++++++++++++++++++++++++ include/hw/ppc/pnv.h | 36 +++ 4 files changed, 639 insertions(+) create mode 100644 hw/ppc/pnv.c create mode 100644 include/hw/ppc/pnv.h
default-configs/ppc64-softmmu.mak +1 -0
@@ -40,6 +40,7 @@ CONFIG_I8259=y CONFIG_XILINX=y CONFIG_XILINX_ETHLITE=y CONFIG_PSERIES=y +CONFIG_POWERNV=y CONFIG_PREP=y CONFIG_MAC=y CONFIG_E500=y
hw/ppc/Makefile.objs +2 -0
@@ -4,6 +4,8 @@ obj-y += ppc.o ppc_booke.o obj-$(CONFIG_PSERIES) += spapr.o spapr_vio.o spapr_events.o obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_rtc.o spapr_drc.o spapr_rng.o +# IBM PowerNV +obj-$(CONFIG_POWERNV) += pnv.o ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy) obj-y += spapr_pci_vfio.o endif
hw/ppc/pnv.c new file +600 -0
600 lines not on this page · raw message
include/hw/ppc/pnv.h new file +36 -0
@@ -0,0 +1,36 @@ +#ifndef _HW_LPC_H +#define _HW_LPC_H +/* +* QEMU PowerNV various definitions +* +* Copyright (c) 2014 BenH +* +* 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 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 "hw/hw.h" + +/* Should we turn that into a QOjb of some sort ? */ +typedef struct PnvChip { +uint32_t chip_id; +}PnvChip ; + +typedef struct PnvSystem { +uint32_t num_chips; +#define PNV_MAX_CHIPS 1 +PnvChip chips[PNV_MAX_CHIPS ]; +}PnvSystem ; + +#endif /* _HW_PNV_LPC_H */ +
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 26/77] ppc/pnv: Add skeletton PowerNV platform
Quoted 3 lines · Benjamin Herrenschmidt
hw/ppc/pnv.c new file +0
-0@@ -0,0 +1,600 @@
<snip>
Quoted 2 lines
hw/ppc/pnv.c new file +2
-0+static void *powernv_create_fdt (PnvSystem *sys,uint32_t initrd_base,uint32_t initrd_size) +{
<snip>
hw/ppc/pnv.c
Quoted 6 lines
hw/ppc/pnv.c new file +6
-0+_FDT ((fdt_begin_node (fdt,"chosen" ))); +_FDT ((fdt_property (fdt,"linux,initrd-start" , + &start_prop,sizeof (start_prop)))); +_FDT ((fdt_property (fdt,"linux,initrd-end" , + &end_prop,sizeof (end_prop)))); +_FDT ((fdt_end_node (fdt)));
(this time replying to list as well)
This misses out kernel command line, which means -append doesn't work.
This patch fixes that:
hw/ppc/pnv.c +6 -2
@@ -379,7 +379,7 @@ static void powernv_create_cpu_node(void *fdt, CPUState *cs, int smt_threads)_FDT ((fdt_end_node (fdt))); } -static void *powernv_create_fdt (PnvSystem *sys,uint32_t initrd_base,uint32_t initrd_size) +static void *powernv_create_fdt (PnvSystem *sys,const char *kernel_cmdline,uint32_t initrd_base,uint32_t initrd_size) {void *fdt;CPUState *cs;
@@ -423,6 +423,9 @@ static void *powernv_create_fdt(PnvSystem *sys, uint32_t initrd_base, uint32_t ig_free (buf);_FDT ((fdt_begin_node (fdt,"chosen" ))); +if (kernel_cmdline) { +_FDT ((fdt_property_string (fdt,"bootargs" , kernel_cmdline))); + }_FDT ((fdt_property (fdt,"linux,initrd-start" , &start_prop,sizeof (start_prop)))); _FDT((fdt_property(fdt, "linux,initrd-end",
@@ -781,7 +784,8 @@ static void ppc_powernv_init(MachineState *machine) initrd_base =0 ; initrd_size =0 ; } - fdt =powernv_create_fdt (sys, initrd_base, initrd_size); + fdt =powernv_create_fdt (sys, machine->kernel_cmdline, + initrd_base, initrd_size);cpu_physical_memory_write (FDT_ADDR , fdt,fdt_totalsize (fdt)); }
Re: [Qemu-devel] [Qemu-ppc] [PATCH 26/77] ppc/pnv: Add skeletton PowerNV platform
In reply to Benjamin HerrenschmidtQuoted 4 lines · Benjamin Herrenschmidt
No devices yet, not even an interrupt controller, just to get started.
Signed-off-by Benjamin Herrenschmidt <[email protected]>
Quoted 8 lines
--- default-configs/ppc64-softmmu.mak | 1 + hw/ppc/Makefile.objs | 2 + hw/ppc/pnv.c | 600 ++++++++++++++++++++++++++++++++++++++ include/hw/ppc/pnv.h | 36 +++ 4 files changed, 639 insertions(+) create mode 100644 hw/ppc/pnv.c create mode 100644 include/hw/ppc/pnv.h
Many of my comments below may be made irrelevant by later patches in the series.
Quoted 145 lines
default-configs/ppc64-softmmu.mak +1
-0@@ -40,6 +40,7 @@ CONFIG_I8259=y CONFIG_XILINX=y CONFIG_XILINX_ETHLITE=y CONFIG_PSERIES=y +CONFIG_POWERNV=y CONFIG_PREP=y CONFIG_MAC=y CONFIG_E500=yhw/ppc/Makefile.objs +2
-0@@ -4,6 +4,8 @@ obj-y += ppc.o ppc_booke.o obj-$(CONFIG_PSERIES) += spapr.o spapr_vio.o spapr_events.o obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_rtc.o spapr_drc.o spapr_rng.o +# IBM PowerNV +obj-$(CONFIG_POWERNV) += pnv.o ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy) obj-y += spapr_pci_vfio.o endifhw/ppc/pnv.c new file +114
-0@@ -0,0 +1,600 @@ +/* +* QEMU PowerPC PowerNV model +* +* Copyright (c) 2004-2007 Fabrice Bellard +* Copyright (c) 2007 Jocelyn Mayer +* Copyright (c) 2010 David Gibson, IBM Corporation. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +* +*/ +#include "sysemu/sysemu.h" +#include "hw/hw.h" +#include "hw/fw-path-provider.h" +#include "elf.h" +#include "net/net.h" +#include "sysemu/block-backend.h" +#include "sysemu/cpus.h" +#include "sysemu/kvm.h" +#include "sysemu/numa.h" +#include "kvm_ppc.h" +#include "mmu-hash64.h" +#include "qom/cpu.h" + +#include "hw/boards.h" +#include "hw/ppc/ppc.h" +#include "hw/ppc/pnv.h" +#include "hw/loader.h" + +#include "exec/address-spaces.h" +#include "qemu/config-file.h" +#include "qemu/error-report.h" +#include "trace.h" +#include "hw/nmi.h" + +#include "hw/compat.h" + +#include <libfdt.h> + +#define FDT_ADDR 0x01000000 +#define FDT_MAX_SIZE 0x00100000 +#define FW_MAX_SIZE 0x00400000 +#define FW_FILE_NAME "skiboot.lid" +#define KERNEL_FILE_NAME "skiroot.lid" +#define KERNEL_LOAD_ADDR 0x20000000 + +#define TIMEBASE_FREQ 512000000ULL + +#define MAX_CPUS 255 + +#define PHANDLE_XICP 0x00001111 + +typedef struct sPowerNVMachineState sPowerNVMachineState ; + +#define TYPE_POWERNV_MACHINE "powernv-machine" +#define POWERNV_MACHINE (obj) \ + OBJECT_CHECK(sPowerNVMachineState, (obj), TYPE_POWERNV_MACHINE) + +/** +* sPowerNVMachineState: +*/ +struct sPowerNVMachineState { +/*< private >*/ +MachineState parent_obj; +PnvSystem sys; +}; + +static size_t create_page_sizes_prop (CPUPPCState *env,uint32_t *prop, +size_t maxsize) +{ +size_t maxcells = maxsize /sizeof (uint32_t ); +int i, j, count; +uint32_t *p = prop; + +for (i =0 ; i <PPC_PAGE_SIZES_MAX_SZ ; i++) { +struct ppc_one_seg_page_size *sps = &env->sps.sps[i]; + +if (!sps->page_shift) { +break ; + } +for (count =0 ; count <PPC_PAGE_SIZES_MAX_SZ ; count++) { +if (sps->enc[count].page_shift ==0 ) { +break ; + } + } +if ((p - prop) >= (maxcells -3 - count *2 )) { +break ; + } + *(p++) =cpu_to_be32 (sps->page_shift); + *(p++) =cpu_to_be32 (sps->slb_enc); + *(p++) =cpu_to_be32 (count); +for (j =0 ; j < count; j++) { + *(p++) =cpu_to_be32 (sps->enc[j].page_shift); + *(p++) =cpu_to_be32 (sps->enc[j].pte_enc); + } + } + +return (p - prop) *sizeof (uint32_t ); +}
hw/ppc/pnv.c line 124
Quoted 10 lines
hw/ppc/pnv.c new file +10
-0+ +#define _FDT (exp) \ + do { \ + int ret = (exp); \ + if (ret < 0) { \ + fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \ + #exp, fdt_strerror(ret)); \ + exit(1); \ + } \ + } while (0)
We should probably make a file where helper routines used by both spapr.c and pnv.c can live.
Quoted 101 lines
hw/ppc/pnv.c new file +101
-0+ +static void powernv_populate_memory_node (void *fdt,int nodeid,hwaddr start, +hwaddr size) +{ +/* Probablly bogus, need to match with what's going on in CPU nodes */ +uint32_t chip_id[] = { +cpu_to_be32 (0x0 ),cpu_to_be32 (nodeid) + }; +char *mem_name; +uint64_t mem_reg_property[2 ]; + + mem_reg_property[0 ] =cpu_to_be64 (start); + mem_reg_property[1 ] =cpu_to_be64 (size); + + mem_name =g_strdup_printf ("memory@" TARGET_FMT_lx, start); +_FDT ((fdt_begin_node (fdt, mem_name))); +g_free (mem_name); +_FDT ((fdt_property_string (fdt,"device_type" ,"memory" ))); +_FDT ((fdt_property (fdt,"reg" , mem_reg_property, +sizeof (mem_reg_property)))); +_FDT ((fdt_property (fdt,"ibm,chip-id" , chip_id,sizeof (chip_id)))); +_FDT ((fdt_end_node (fdt))); +} + +static int powernv_populate_memory (void *fdt) +{ +hwaddr mem_start, node_size; +int i, nb_nodes = nb_numa_nodes; +NodeInfo *nodes = numa_info; +NodeInfo ramnode; + +/* No NUMA nodes, assume there is just one node with whole RAM */ +if (!nb_numa_nodes) { + nb_nodes =1 ; + ramnode.node_mem = ram_size; + nodes = &ramnode; + } + +for (i =0 , mem_start =0 ; i < nb_nodes; ++i) { +if (!nodes[i].node_mem) { +continue ; + } +if (mem_start >= ram_size) { + node_size =0 ; + }else { + node_size = nodes[i].node_mem; +if (node_size > ram_size - mem_start) { + node_size = ram_size - mem_start; + } + } +for ( ; node_size; ) { +hwaddr sizetmp =pow2floor (node_size); + +/* mem_start != 0 here */ +if (ctzl (mem_start) <ctzl (sizetmp)) { + sizetmp =1ULL <<ctzl (mem_start); + } + +powernv_populate_memory_node (fdt, i, mem_start, sizetmp); + node_size -= sizetmp; + mem_start += sizetmp; + } + } + +return 0 ; +} + +static void powernv_create_cpu_node (void *fdt,CPUState *cs,int smt_threads) +{ +PowerPCCPU *cpu =POWERPC_CPU (cs); +CPUPPCState *env = &cpu->env; +DeviceClass *dc =DEVICE_GET_CLASS (cs); +PowerPCCPUClass *pcc =POWERPC_CPU_GET_CLASS (cs); +uint32_t servers_prop[smt_threads]; +uint32_t gservers_prop[smt_threads *2 ]; +int i, index =ppc_get_vcpu_dt_id (cpu); +uint32_t segs[] = {cpu_to_be32 (28 ),cpu_to_be32 (40 ), +0xffffffff ,0xffffffff }; +uint32_t tbfreq =kvm_enabled () ?kvmppc_get_tbfreq () :TIMEBASE_FREQ ; +uint32_t cpufreq =kvm_enabled () ?kvmppc_get_clockfreq () :1000000000 ; +uint32_t page_sizes_prop[64 ]; +size_t page_sizes_prop_size; +char *nodename; + +if ((index % smt_threads) !=0 ) { +return ; + } + + nodename =g_strdup_printf ("%s@%x" , dc->fw_name, index); + +_FDT ((fdt_begin_node (fdt, nodename))); + +g_free (nodename); + +_FDT ((fdt_property_cell (fdt,"reg" , index))); +_FDT ((fdt_property_string (fdt,"device_type" ,"cpu" ))); + +_FDT ((fdt_property_cell (fdt,"cpu-version" , env->spr[SPR_PVR ]))); +_FDT ((fdt_property_cell (fdt,"d-cache-block-size" , + env->dcache_line_size))); + _FDT((fdt_property_cell(fdt, "d-cache-line-size",
hw/ppc/pnv.c line 235
Quoted 10 lines
hw/ppc/pnv.c new file +10
-0+ env->dcache_line_size))); +_FDT ((fdt_property_cell (fdt,"i-cache-block-size" , + env->icache_line_size))); +_FDT ((fdt_property_cell (fdt,"i-cache-line-size" , + env->icache_line_size))); + +if (pcc->l1_dcache_size) { +_FDT ((fdt_property_cell (fdt,"d-cache-size" , pcc->l1_dcache_size))); + }else { +fprintf (stderr,"Warning: Unknown L1 dcache size for cpu\n" );
Hmm (note to self) should probably change a bunch of these both in spapr.c and pnv.c from explicit fprintfs() to modern error_report() and similar.
Quoted 60 lines
hw/ppc/pnv.c new file +60
-0+ } +if (pcc->l1_icache_size) { +_FDT ((fdt_property_cell (fdt,"i-cache-size" , pcc->l1_icache_size))); + }else { +fprintf (stderr,"Warning: Unknown L1 icache size for cpu\n" ); + } + +_FDT ((fdt_property_cell (fdt,"timebase-frequency" , tbfreq))); +_FDT ((fdt_property_cell (fdt,"clock-frequency" , cpufreq))); +_FDT ((fdt_property_cell (fdt,"ibm,slb-size" , env->slb_nr))); +_FDT ((fdt_property_string (fdt,"status" ,"okay" ))); +_FDT ((fdt_property (fdt,"64-bit" ,NULL ,0 ))); + +if (env->spr_cb[SPR_PURR ].oea_read) { +_FDT ((fdt_property (fdt,"ibm,purr" ,NULL ,0 ))); + } + +if (env->mmu_model &POWERPC_MMU_1TSEG ) { +_FDT ((fdt_property (fdt,"ibm,processor-segment-sizes" , + segs,sizeof (segs)))); + } + +/* Advertise VMX/VSX (vector extensions) if available +* 0 / no property == no vector extensions +* 1 == VMX / Altivec available +* 2 == VSX available */ +if (env->insns_flags &PPC_ALTIVEC ) { +uint32_t vmx = (env->insns_flags2 &PPC2_VSX ) ?2 :1 ; + +_FDT ((fdt_property_cell (fdt,"ibm,vmx" , vmx))); + } + +/* Advertise DFP (Decimal Floating Point) if available +* 0 / no property == no DFP +* 1 == DFP available */ +if (env->insns_flags2 &PPC2_DFP ) { +_FDT ((fdt_property_cell (fdt,"ibm,dfp" ,1 ))); + } + + page_sizes_prop_size =create_page_sizes_prop (env, page_sizes_prop, +sizeof (page_sizes_prop)); +if (page_sizes_prop_size) { +_FDT ((fdt_property (fdt,"ibm,segment-page-sizes" , + page_sizes_prop, page_sizes_prop_size))); + } + +/* XXX Just a hack for now */ +_FDT ((fdt_property_cell (fdt,"ibm,chip-id" ,0 ))); + +if (cpu->cpu_version) { +_FDT ((fdt_property_cell (fdt,"cpu-version" , cpu->cpu_version))); + } + +/* Build interrupt servers and gservers properties */ +for (i =0 ; i < smt_threads; i++) { + servers_prop[i] =cpu_to_be32 (index + i); +/* Hack, direct the group queues back to cpu 0 */ + gservers_prop[i*2 ] =cpu_to_be32 (index + i); + gservers_prop[i*2 +1 ] =0 ; + }
hw/ppc/pnv.c line 305
Quoted 10 lines
hw/ppc/pnv.c new file +10
-0+_FDT ((fdt_property (fdt,"ibm,ppc-interrupt-server#s" , + servers_prop,sizeof (servers_prop)))); +_FDT ((fdt_property (fdt,"ibm,ppc-interrupt-gserver#s" , + gservers_prop,sizeof (gservers_prop)))); + +_FDT ((fdt_end_node (fdt))); +} + +static void *powernv_create_fdt (PnvSystem *sys,uint32_t initrd_base,uint32_t initrd_size) +{
So.. does it make sense for qemu to create a device tree for powernv, rather than leaving it to Opal?
Quoted 19 lines
hw/ppc/pnv.c new file +19
-0+void *fdt; +CPUState *cs; +int smt =kvmppc_smt_threads (); +uint32_t start_prop =cpu_to_be32 (initrd_base); +uint32_t end_prop =cpu_to_be32 (initrd_base + initrd_size); +char *buf; +const char plat_compat[] ="qemu,powernv\0ibm,powernv" ; + + fdt =g_malloc0 (FDT_MAX_SIZE ); +_FDT ((fdt_create (fdt,FDT_MAX_SIZE ))); +_FDT ((fdt_finish_reservemap (fdt))); + +/* Root node */ +_FDT ((fdt_begin_node (fdt,"" ))); +_FDT ((fdt_property_string (fdt,"model" ,"IBM PowerNV (emulated by qemu)" ))); +_FDT ((fdt_property (fdt,"compatible" , plat_compat,sizeof (plat_compat)))); + +/* +* Add info to guest to indentify which host is it being run on
hw/ppc/pnv.c line 334
Quoted 10 lines
hw/ppc/pnv.c new file +10
-0+* and what is the uuid of the guest +*/ +if (kvmppc_get_host_model (&buf)) { +_FDT ((fdt_property_string (fdt,"host-model" , buf))); +g_free (buf); + } +if (kvmppc_get_host_serial (&buf)) { +_FDT ((fdt_property_string (fdt,"host-serial" , buf))); +g_free (buf); + }
Since you're emulating a "bare metal" machine, surely the host properties aren't relevant here.
Quoted 44 lines
hw/ppc/pnv.c new file +44
-0+ + buf =g_strdup_printf (UUID_FMT , qemu_uuid[0 ], qemu_uuid[1 ], + qemu_uuid[2 ], qemu_uuid[3 ], qemu_uuid[4 ], + qemu_uuid[5 ], qemu_uuid[6 ], qemu_uuid[7 ], + qemu_uuid[8 ], qemu_uuid[9 ], qemu_uuid[10 ], + qemu_uuid[11 ], qemu_uuid[12 ], qemu_uuid[13 ], + qemu_uuid[14 ], qemu_uuid[15 ]); + +_FDT ((fdt_property_string (fdt,"vm,uuid" , buf))); +g_free (buf); + +_FDT ((fdt_begin_node (fdt,"chosen" ))); +_FDT ((fdt_property (fdt,"linux,initrd-start" , + &start_prop,sizeof (start_prop)))); +_FDT ((fdt_property (fdt,"linux,initrd-end" , + &end_prop,sizeof (end_prop)))); +_FDT ((fdt_end_node (fdt))); + +_FDT ((fdt_property_cell (fdt,"#address-cells" ,0x2 ))); +_FDT ((fdt_property_cell (fdt,"#size-cells" ,0x2 ))); + +/* cpus */ +_FDT ((fdt_begin_node (fdt,"cpus" ))); +_FDT ((fdt_property_cell (fdt,"#address-cells" ,0x1 ))); +_FDT ((fdt_property_cell (fdt,"#size-cells" ,0x0 ))); + +CPU_FOREACH (cs) { +powernv_create_cpu_node (fdt, cs, smt); + } + +_FDT ((fdt_end_node (fdt))); + +/* Memory */ +_FDT ((powernv_populate_memory (fdt))); + +/* /hypervisor node */ +if (kvm_enabled ()) { +uint8_t hypercall[16 ]; + +/* indicate KVM hypercall interface */ +_FDT ((fdt_begin_node (fdt,"hypervisor" ))); +_FDT ((fdt_property_string (fdt,"compatible" ,"linux,kvm" ))); +if (kvmppc_has_cap_fixup_hcalls ()) { +/*
hw/ppc/pnv.c line 388
Quoted 10 lines
hw/ppc/pnv.c new file +10
-0+* Older KVM versions with older guest kernels were broken with the +* magic page, don't allow the guest to map it. +*/ +kvmppc_get_hypercall (first_cpu->env_ptr, hypercall, +sizeof (hypercall)); +_FDT ((fdt_property (fdt,"hcall-instructions" , hypercall, +sizeof (hypercall)))); + } +_FDT ((fdt_end_node (fdt))); + }
And a hypercall interface surely doesn't make sense for powernv.
Quoted 11 lines
hw/ppc/pnv.c new file +11
-0+ +_FDT ((fdt_end_node (fdt)));/* close root node */ +_FDT ((fdt_finish (fdt))); + +return fdt; +} + +static void powernv_cpu_reset (void *opaque) +{ +PowerPCCPU *cpu = opaque; +CPUState *cs =CPU (cpu);
hw/ppc/pnv.c line 409
Quoted 10 lines
hw/ppc/pnv.c new file +10
-0+CPUPPCState *env = &cpu->env; + +cpu_reset (cs); + + env->spr[SPR_PIR ] =ppc_get_vcpu_dt_id (cpu); + env->spr[SPR_HIOR ] =0 ; + env->gpr[3 ] =FDT_ADDR ; + env->nip =0x10 ; + env->msr |=MSR_HVB ; +}
So, I believe the qemu-ishly correct way of doing this is to have the cpu initialization in the cpu code, rather than the platform code, as much as possible. On PAPR we kind of get away with initialization in the platform code on the grounds that it's a paravirt platform, but powernv doesn't have that excuse.
But this may well be stuff that changes in later patches, so..
hw/ppc/pnv.c line 415
Quoted 5 lines
hw/ppc/pnv.c new file +5
-0+static const VMStateDescription vmstate_powernv = { + .name ="powernv" , + .version_id =1 , + .minimum_version_id =1 , +};
It might be best to leave out the vmstate entirely until you're ready to implement migration, rather than having a partial, probably not working migration implementation.
hw/ppc/pnv.c line 426
Quoted 11 lines
hw/ppc/pnv.c new file +11
-0+ +static void pnv_create_chip (PnvSystem *sys,unsigned int chip_no) +{ +PnvChip *chip = &sys->chips[chip_no]; + +if (chip_no >=PNV_MAX_CHIPS ) { +return ; + } + +/* XXX Improve chip numbering to better match HW */ + chip->chip_id = chip_no;
I think modern qemu conventions would suggest creating the chips as QOM objects rather than having a fixed array.
Quoted 74 lines
hw/ppc/pnv.c new file +74
-0+} + +static void ppc_powernv_init (MachineState *machine) +{ +ram_addr_t ram_size = machine->ram_size; +const char *cpu_model = machine->cpu_model; +const char *kernel_filename = machine->kernel_filename; +const char *initrd_filename = machine->initrd_filename; +uint32_t initrd_base =0 ; +long initrd_size =0 ; +PowerPCCPU *cpu; +CPUPPCState *env; +MemoryRegion *sysmem =get_system_memory (); +MemoryRegion *ram =g_new (MemoryRegion,1 ); +sPowerNVMachineState *pnv_machine =POWERNV_MACHINE (machine); +PnvSystem *sys = &pnv_machine->sys; +long fw_size; +char *filename; +void *fdt; +int i; + +/* init CPUs */ +if (cpu_model ==NULL ) { + cpu_model =kvm_enabled () ?"host" :"POWER8" ; + } + +for (i =0 ; i < smp_cpus; i++) { + cpu =cpu_ppc_init (cpu_model); +if (cpu ==NULL ) { +fprintf (stderr,"Unable to find PowerPC CPU definition\n" ); +exit (1 ); + } + env = &cpu->env; + +/* Set time-base frequency to 512 MHz */ +cpu_ppc_tb_init (env,TIMEBASE_FREQ ); + +/* MSR[IP] doesn't exist nowadays */ + env->msr_mask &= ~(1 <<6 ); + +qemu_register_reset (powernv_cpu_reset, cpu); + } + +/* allocate RAM */ +memory_region_allocate_system_memory (ram,NULL ,"ppc_powernv.ram" , ram_size); +memory_region_add_subregion (sysmem,0 , ram); + +/* XXX We should decide how many chips to create based on #cores and +* Venice vs. Murano vs. Naples chip type etc..., for now, just create +* one chip. Also creation of the CPUs should be done per-chip +*/ + sys->num_chips =1 ; + +/* Create only one PHB for now until I figure out what's wrong +* when I create more (resource assignment failures in Linux) +*/ +pnv_create_chip (sys,0 ); + +if (bios_name ==NULL ) { + bios_name =FW_FILE_NAME ; + } + filename =qemu_find_file (QEMU_FILE_TYPE_BIOS , bios_name); + fw_size =load_image_targphys (filename,0 ,FW_MAX_SIZE ); +if (fw_size <0 ) { +hw_error ("qemu: could not load OPAL '%s'\n" , filename); +exit (1 ); + } +g_free (filename); + + +if (kernel_filename ==NULL ) { + kernel_filename =KERNEL_FILE_NAME ; + } + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS,
Quoted 1 line
kernel_filename);
The commit withe Opal image should go in before this, no?
Quoted 142 lines
hw/ppc/pnv.c new file +100
-0+ fw_size =load_image_targphys (filename,0x20000000 ,0x2000000 ); +if (fw_size <0 ) { +hw_error ("qemu: could not load kernel'%s'\n" , filename); +exit (1 ); + } +g_free (filename); + +/* load initrd */ +if (initrd_filename) { +/* Try to locate the initrd in the gap between the kernel +* and the firmware. Add a bit of space just in case +*/ + initrd_base =0x40000000 ; + initrd_size =load_image_targphys (initrd_filename, initrd_base, +0x10000000 );// 128MB max +if (initrd_size <0 ) { +fprintf (stderr,"qemu: could not load initial ram disk '%s'\n" , + initrd_filename); +exit (1 ); + } + }else { + initrd_base =0 ; + initrd_size =0 ; + } + fdt =powernv_create_fdt (sys, initrd_base, initrd_size); +cpu_physical_memory_write (FDT_ADDR , fdt,fdt_totalsize (fdt)); +} + +static int powernv_kvm_type (const char *vm_type) +{ +/* Always force PR KVM */ +return 2 ; +} + +static void ppc_cpu_do_nmi_on_cpu (void *arg) +{ +CPUState *cs = arg; + +cpu_synchronize_state (cs); +ppc_cpu_do_system_reset (cs); +} + +static void powernv_nmi (NMIState *n,int cpu_index,Error **errp) +{ +CPUState *cs; + +CPU_FOREACH (cs) { +async_run_on_cpu (cs, ppc_cpu_do_nmi_on_cpu, cs); + } +} + +static void powernv_machine_class_init (ObjectClass *oc,void *data) +{ +MachineClass *mc =MACHINE_CLASS (oc); +NMIClass *nc =NMI_CLASS (oc); + + mc->init = ppc_powernv_init; + mc->block_default_type =IF_SCSI ; + mc->max_cpus =MAX_CPUS ; + mc->no_parallel =1 ; + mc->default_boot_order =NULL ; + mc->kvm_type = powernv_kvm_type; + + nc->nmi_monitor_handler = powernv_nmi; +} + +static const TypeInfo powernv_machine_info = { + .name =TYPE_POWERNV_MACHINE , + .parent =TYPE_MACHINE , + .abstract = true, + .instance_size =sizeof (sPowerNVMachineState), + .class_init = powernv_machine_class_init, + .interfaces = (InterfaceInfo []) { + {TYPE_NMI }, + { } + }, +}; + +static void powernv_machine_2_5_class_init (ObjectClass *oc,void *data) +{ +MachineClass *mc =MACHINE_CLASS (oc); + + mc->name ="powernv-2.5" ; + mc->desc ="PowerNV v2.5" ; + mc->alias ="powernv" ; +} + +static const TypeInfo powernv_machine_2_5_info = { + .name =MACHINE_TYPE_NAME ("powernv-2.5" ), + .parent =TYPE_POWERNV_MACHINE , + .class_init = powernv_machine_2_5_class_init, +}; + +static void powernv_machine_register_types (void ) +{ +type_register_static (&powernv_machine_info); +type_register_static (&powernv_machine_2_5_info); +} + +type_init (powernv_machine_register_types)include/hw/ppc/pnv.h new file +36
-0@@ -0,0 +1,36 @@ +#ifndef _HW_LPC_H +#define _HW_LPC_H +/* +* QEMU PowerNV various definitions +* +* Copyright (c) 2014 BenH +* +* 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 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 "hw/hw.h" + +/* Should we turn that into a QOjb of some sort ? */ +typedef struct PnvChip { +uint32_t chip_id; +}PnvChip ; + +typedef struct PnvSystem { +uint32_t num_chips; +#define PNV_MAX_CHIPS 1 +PnvChip chips[PNV_MAX_CHIPS ]; +}PnvSystem ; + +#endif /* _HW_PNV_LPC_H */ +
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [Qemu-ppc] [PATCH 26/77] ppc/pnv: Add skeletton PowerNV platform
Quoted 16 lines · David Gibson
Quoted 10 lines · Benjamin Herrenschmidt
No devices yet, not even an interrupt controller, just to get started.
Signed-off-by Benjamin Herrenschmidt <[email protected]>---
default-configs/ppc64-softmmu.mak | 1 +
hw/ppc/Makefile.objs | 2 +
hw/ppc/pnv.c | 600
++++++++++++++++++++++++++++++++++++++
include/hw/ppc/pnv.h | 36 +++Quoted 3 lines
4 files changed, 639 insertions(+)create mode 100644
hw/ppc/pnv.c
create mode 100644include/hw/ppc/pnv.h
Quoted 2 lines
Many of my comments below may be made irrelevant by later patches in the series.
Heh, well there is where the "meat" of the new platform starts showing up :-)
.../...
Quoted 10 lines
Quoted 9 lines
+#define
_FDT(exp)\
+ do { \
+ int ret = (exp); \
+ if (ret < 0) { \
+ fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \
+ #exp, fdt_strerror(ret)); \
+ exit(1); \
+ } \
+ } while (0)
Quoted 2 lines
We should probably make a file where helper routines used by both
spapr.candpnv.ccan live.
Probably but I'd see that as a later cleanup rather than doing it in this series...
.../...
Quoted 8 lines
Quoted 4 lines
+ if (
pcc->l1_dcache_size) {
+ _FDT((fdt_property_cell(fdt, "d-cache-size",pcc->l1_dcache_size))); + } else {
+ fprintf(stderr, "Warning: Unknown L1 dcache size for cpu\n");Hmm (note to self) should probably change a bunch of these both in
spapr.candpnv.cfrom explicitfprintfs()to modernerror_report()and similar.
That's a train I completely missed, but yes.
.../...
Quoted 6 lines
Quoted 6 lines
+ }
+ _FDT((fdt_property(fdt, "ibm,ppc-interrupt-server#s", + servers_prop,sizeof(servers_prop)))); + _FDT((fdt_property(fdt, "ibm,ppc-interrupt-gserver#s", + gservers_prop,sizeof(gservers_prop)))); +
Quoted 8 lines
hw/ppc/pnv.c line 305
Quoted 5 lines
+ _FDT((fdt_end_node(fdt)));
hw/ppc/pnv.c new file +4
-0+} + +static void *powernv_create_fdt (PnvSystem *sys,uint32_t initrd_base,uint32_t initrd_size) +{So.. does it make sense for qemu to create a device tree for powernv, rather than leaving it to Opal?
Well, OPAL only creates a device-tree if you are on an FSP machine in which case it expects a complex data structure (HDAT) coming from the FSP to use as a source of info.
On OpenPower machines, which is closer to what we simulate here, we do get a device-tree as an input in OPAL, it's generated by HostBoot.
Now, I am not running HostBoot in qemu because most of what it does is completely irrelevant to an emulated system (training the various links, initializing the memory buffer chips, etc...).
However we do need to pass a number of platform information to OPAL which HB does via the device-tree, such as which cores are enabled, the memory map configured for PCI, which PHBs are enabled, etc... so creating a DT in qemu makes sense, it mimmics HB in essence.
OPAL will enrich that device-tree before starting Linux.
Quoted 13 lines
Quoted 4 lines
+ /*
+ * Add info to guest to indentify which host is it being run on + * and what is the uuid of the guest
+ */Quoted 8 lines
+ if (
kvmppc_get_host_model(&buf)) {
+ _FDT((fdt_property_string(fdt, "host-model", buf))); + g_free(buf);
+ }
+ if (kvmppc_get_host_serial(&buf)) {
+ _FDT((fdt_property_string(fdt, "host-serial", buf))); + g_free(buf);
+ }
Quoted 2 lines
Since you're emulating a "bare metal" machine, surely the host properties aren't relevant here.
They may or may not. But yes, I can take that out.
Quoted 47 lines
Quoted 47 lines
+ buf = g_strdup_printf(UUID_FMT, qemu_uuid[0], qemu_uuid[1], + qemu_uuid[2], qemu_uuid[3], qemu_uuid[4], + qemu_uuid[5], qemu_uuid[6], qemu_uuid[7], + qemu_uuid[8], qemu_uuid[9], qemu_uuid[10], + qemu_uuid[11], qemu_uuid[12], qemu_uuid[13], + qemu_uuid[14], qemu_uuid[15]);
hw/ppc/pnv.c new file +41
-0+ + _FDT((fdt_property_string(fdt, "vm,uuid", buf))); + g_free(buf); + + _FDT((fdt_begin_node(fdt, "chosen"))); + _FDT((fdt_property(fdt, "linux,initrd-start", + &start_prop, sizeof(start_prop)))); + _FDT((fdt_property(fdt, "linux,initrd-end", + &end_prop, sizeof(end_prop)))); + _FDT((fdt_end_node(fdt))); + + _FDT((fdt_property_cell(fdt, "#address-cells", 0x2))); + _FDT((fdt_property_cell(fdt, "#size-cells", 0x2))); + + /* cpus */ + _FDT((fdt_begin_node(fdt, "cpus"))); + _FDT((fdt_property_cell(fdt, "#address-cells", 0x1))); + _FDT((fdt_property_cell(fdt, "#size-cells", 0x0))); + + CPU_FOREACH(cs) { + powernv_create_cpu_node(fdt, cs, smt); + } + + _FDT((fdt_end_node(fdt))); + + /* Memory */ + _FDT((powernv_populate_memory(fdt))); + + /* /hypervisor node */ + if (kvm_enabled()) { + uint8_t hypercall[16]; + + /* indicate KVM hypercall interface */ + _FDT((fdt_begin_node(fdt, "hypervisor"))); + _FDT((fdt_property_string(fdt, "compatible", "linux,kvm"))); + if (kvmppc_has_cap_fixup_hcalls()) { + /* + * Older KVM versions with older guest kernels were broken with the + * magic page, don't allow the guest to map it. + */ + kvmppc_get_hypercall(first_cpu->env_ptr, hypercall,
Quoted 8 lines
Quoted 6 lines
+ sizeof(hypercall));
+ _FDT((fdt_property(fdt, "hcall-instructions", hypercall, + sizeof(hypercall))));
+ }
+ _FDT((fdt_end_node(fdt)));
+ }And a hypercall interface surely doesn't make sense for powernv.
It's qemu paravirt, it exist on G5 too :-) It's for PR KVM, it allows to speed up some bits and pieces. But yeah we don't yet really "support" it at this point. However we might.
Quoted 28 lines
Quoted 11 lines
hw/ppc/pnv.c new file +11
-0+ + _FDT((fdt_end_node(fdt))); /* close root node */ + _FDT((fdt_finish(fdt))); + + return fdt; +} + +static void powernv_cpu_reset (void *opaque) +{ + PowerPCCPU *cpu = opaque; + CPUState *cs = CPU(cpu);hw/ppc/pnv.c line 409
Quoted 10 lines
hw/ppc/pnv.c new file +10
-0+ CPUPPCState *env = &cpu->env; + + cpu_reset(cs); + + env->spr[SPR_PIR] = ppc_get_vcpu_dt_id(cpu); + env->spr[SPR_HIOR] = 0; + env->gpr[3] = FDT_ADDR; + env->nip = 0x10; + env->msr |= MSR_HVB; +}So, I believe the qemu-ishly correct way of doing this is to have the cpu initialization in the cpu code, rather than the platform code, as much as possible. On PAPR we kind of get away with initialization in the platform code on the grounds that it's a paravirt platform, but powernv doesn't have that excuse.
Quoted 1 line
But this may well be stuff that changes in later patches, so..
Well no, not really. But here too, we mimmic the state as coming out of HostBoot, which isn't quite the same thing. We need to provide the FDT entry, etc...
The "real" reset state of a P8 isn't something we can easily simulate...
It runs some microcode from a SEEPROM with a small microcontroller which initializes a core, which then runs some HB code off it's L3 cache etc... really not something we want to do in qemu at least for now.
So the initial state here is somewhat in between full virt and paravirt, we simulate a platform that has been partially initialized by HostBoot, to the state it has when it enters OPAL.
Quoted 9 lines
hw/ppc/pnv.c line 415
Quoted 5 lines
hw/ppc/pnv.c new file +5
-0+static const VMStateDescription vmstate_powernv = { + .name = "powernv", + .version_id = 1, + .minimum_version_id = 1, +};It might be best to leave out the vmstate entirely until you're ready to implement migration, rather than having a partial, probably not working migration implementation.
Ok.
Quoted 6 lines
Quoted 6 lines
hw/ppc/pnv.c new file +6
-0+ +static void pnv_create_chip (PnvSystem *sys,unsigned int chip_no) +{ + PnvChip *chip = &sys->chips[chip_no]; + + if (chip_no >= PNV_MAX_CHIPS) {
Quoted 8 lines
Quoted 5 lines
+ return;
+ }
+
+ /* XXX Improve chip numbering to better match HW */ + chip->chip_id =chip_no;I think modern qemu conventions would suggest creating the chips as QOM objects rather than having a fixed array.
Yeah, more code & much larger memory footprint for the same result :-)
I can look into it but it's low priority. I still want to rework some of that chip stuff in future patches anyway.
Quoted 69 lines
Quoted 69 lines
hw/ppc/pnv.c new file +69
-0+} + +static void ppc_powernv_init (MachineState *machine) +{ + ram_addr_t ram_size = machine->ram_size; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; + const char *initrd_filename = machine->initrd_filename; + uint32_t initrd_base = 0; + long initrd_size = 0; + PowerPCCPU *cpu; + CPUPPCState *env; + MemoryRegion *sysmem = get_system_memory(); + MemoryRegion *ram = g_new(MemoryRegion, 1); + sPowerNVMachineState *pnv_machine = POWERNV_MACHINE(machine); + PnvSystem *sys = &pnv_machine->sys; + long fw_size; + char *filename; + void *fdt; + int i; + + /* init CPUs */ + if (cpu_model == NULL) { + cpu_model = kvm_enabled() ? "host" : "POWER8"; + } + + for (i = 0; i < smp_cpus; i++) { + cpu = cpu_ppc_init(cpu_model); + if (cpu == NULL) { + fprintf(stderr, "Unable to find PowerPC CPU definition\n"); + exit(1); + } + env = &cpu->env; + + /* Set time-base frequency to 512 MHz */ + cpu_ppc_tb_init(env, TIMEBASE_FREQ); + + /* MSR[IP] doesn't exist nowadays */ + env->msr_mask &= ~(1 << 6); + + qemu_register_reset(powernv_cpu_reset, cpu); + } + + /* allocate RAM */ + memory_region_allocate_system_memory(ram, NULL, "ppc_powernv.ram", ram_size); + memory_region_add_subregion(sysmem, 0, ram); + + /* XXX We should decide how many chips to create based on #cores and + * Venice vs. Murano vs. Naples chip type etc..., for now, just create + * one chip. Also creation of the CPUs should be done per-chip + */ + sys->num_chips = 1; + + /* Create only one PHB for now until I figure out what's wrong + * when I create more (resource assignment failures in Linux) + */ + pnv_create_chip(sys, 0); + + if (bios_name == NULL) { + bios_name = FW_FILE_NAME; + } + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE); + if (fw_size < 0) { + hw_error("qemu: could not load OPAL '%s'\n", filename); + exit(1); + } + g_free(filename); +
Quoted 8 lines
Quoted 6 lines
+
+ if (kernel_filename== NULL) {
+ kernel_filename =KERNEL_FILE_NAME; + }
+ filename =qemu_find_file(QEMU_FILE_TYPE_BIOS, kernel_filename);The commit withe Opal image should go in before this, no?
Now this is a bit of an open discussion at the moment :-)
The way OPAL is built on OPP machines today is by essentially building a complete flash image which contains HostBoot, OPAL and the petitboot- based bootloader which contains a Linux kernel etc...
We could create a target without HB and with a slimmed down Linux but it would still probably be about 12MB I reckon, if not more. It feels a bit "big" to ship as a binary as part of qemu...
We would also have to add code to qemu to "find" OPAL in that image, and then add a model for the flash controller.
The other option is to bundle just OPAL itself. However that means you can't go anywhere without a -kernel argument, which would then be either a petitboot-based bootloader or your actual target kernel.
Cheers,
Ben.
Re: [Qemu-devel] [Qemu-ppc] [PATCH 26/77] ppc/pnv: Add skeletton PowerNV platform
Quoted 35 lines · Benjamin Herrenschmidt
Quoted 16 lines · David Gibson
Quoted 10 lines · Benjamin Herrenschmidt
No devices yet, not even an interrupt controller, just to get started.
Signed-off-by Benjamin Herrenschmidt <[email protected]>---
default-configs/ppc64-softmmu.mak | 1 +
hw/ppc/Makefile.objs | 2 +
hw/ppc/pnv.c | 600
++++++++++++++++++++++++++++++++++++++
include/hw/ppc/pnv.h | 36 +++Quoted 3 lines
4 files changed, 639 insertions(+)create mode 100644
hw/ppc/pnv.c
create mode 100644include/hw/ppc/pnv.hQuoted 2 lines
Many of my comments below may be made irrelevant by later patches in the series.
Heh, well there is where the "meat" of the new platform starts showing up :-)
.../...
Quoted 10 lines
Quoted 9 lines
+#define
_FDT(exp)\
+ do { \
+ int ret = (exp); \
+ if (ret < 0) { \
+ fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \
+ #exp, fdt_strerror(ret)); \
+ exit(1); \
+ } \
+ } while (0)
Quoted 5 lines
Quoted 2 lines
We should probably make a file where helper routines used by both
spapr.candpnv.ccan live.Probably but I'd see that as a later cleanup rather than doing it in this series...
Ok.
Quoted 42 lines
.../...
Quoted 8 lines
Quoted 4 lines
+ if (
pcc->l1_dcache_size) {
+ _FDT((fdt_property_cell(fdt, "d-cache-size",pcc->l1_dcache_size))); + } else {
+ fprintf(stderr, "Warning: Unknown L1 dcache size for cpu\n");Hmm (note to self) should probably change a bunch of these both in
spapr.candpnv.cfrom explicitfprintfs()to modernerror_report()and similar.That's a train I completely missed, but yes.
.../...
Quoted 6 lines
Quoted 6 lines
+ }
+ _FDT((fdt_property(fdt, "ibm,ppc-interrupt-server#s", + servers_prop,sizeof(servers_prop)))); + _FDT((fdt_property(fdt, "ibm,ppc-interrupt-gserver#s", + gservers_prop,sizeof(gservers_prop)))); +Quoted 8 lines
hw/ppc/pnv.c line 305
Quoted 5 lines
+ _FDT((fdt_end_node(fdt)));
hw/ppc/pnv.c new file +4
-0+} + +static void *powernv_create_fdt (PnvSystem *sys,uint32_t initrd_base,uint32_t initrd_size) +{So.. does it make sense for qemu to create a device tree for powernv, rather than leaving it to Opal?
Well, OPAL only creates a device-tree if you are on an FSP machine in which case it expects a complex data structure (HDAT) coming from the FSP to use as a source of info.
On OpenPower machines, which is closer to what we simulate here, we do get a device-tree as an input in OPAL, it's generated by HostBoot.
Now, I am not running HostBoot in qemu because most of what it does is completely irrelevant to an emulated system (training the various links, initializing the memory buffer chips, etc...).
Quoted 6 lines
However we do need to pass a number of platform information to OPAL which HB does via the device-tree, such as which cores are enabled, the memory map configured for PCI, which PHBs are enabled, etc... so creating a DT in qemu makes sense, it mimmics HB in essence.
OPAL will enrich that device-tree before starting Linux.
Ok. Some comments mentioning that you're simulating the exit state from HostBoot would be good then.
Quoted 74 lines
Quoted 13 lines
Quoted 4 lines
+ /*
+ * Add info to guest to indentify which host is it being run on + * and what is the uuid of the guest
+ */Quoted 8 lines
+ if (
kvmppc_get_host_model(&buf)) {
+ _FDT((fdt_property_string(fdt, "host-model", buf))); + g_free(buf);
+ }
+ if (kvmppc_get_host_serial(&buf)) {
+ _FDT((fdt_property_string(fdt, "host-serial", buf))); + g_free(buf);
+ }Quoted 2 lines
Since you're emulating a "bare metal" machine, surely the host properties aren't relevant here.
They may or may not. But yes, I can take that out.
Quoted 47 lines
Quoted 47 lines
+ buf = g_strdup_printf(UUID_FMT, qemu_uuid[0], qemu_uuid[1], + qemu_uuid[2], qemu_uuid[3], qemu_uuid[4], + qemu_uuid[5], qemu_uuid[6], qemu_uuid[7], + qemu_uuid[8], qemu_uuid[9], qemu_uuid[10], + qemu_uuid[11], qemu_uuid[12], qemu_uuid[13], + qemu_uuid[14], qemu_uuid[15]);
hw/ppc/pnv.c new file +41
-0+ + _FDT((fdt_property_string(fdt, "vm,uuid", buf))); + g_free(buf); + + _FDT((fdt_begin_node(fdt, "chosen"))); + _FDT((fdt_property(fdt, "linux,initrd-start", + &start_prop, sizeof(start_prop)))); + _FDT((fdt_property(fdt, "linux,initrd-end", + &end_prop, sizeof(end_prop)))); + _FDT((fdt_end_node(fdt))); + + _FDT((fdt_property_cell(fdt, "#address-cells", 0x2))); + _FDT((fdt_property_cell(fdt, "#size-cells", 0x2))); + + /* cpus */ + _FDT((fdt_begin_node(fdt, "cpus"))); + _FDT((fdt_property_cell(fdt, "#address-cells", 0x1))); + _FDT((fdt_property_cell(fdt, "#size-cells", 0x0))); + + CPU_FOREACH(cs) { + powernv_create_cpu_node(fdt, cs, smt); + } + + _FDT((fdt_end_node(fdt))); + + /* Memory */ + _FDT((powernv_populate_memory(fdt))); + + /* /hypervisor node */ + if (kvm_enabled()) { + uint8_t hypercall[16]; + + /* indicate KVM hypercall interface */ + _FDT((fdt_begin_node(fdt, "hypervisor"))); + _FDT((fdt_property_string(fdt, "compatible", "linux,kvm"))); + if (kvmppc_has_cap_fixup_hcalls()) { + /* + * Older KVM versions with older guest kernels were broken with the + * magic page, don't allow the guest to map it. + */ + kvmppc_get_hypercall(first_cpu->env_ptr, hypercall,Quoted 8 lines
Quoted 6 lines
+ sizeof(hypercall));
+ _FDT((fdt_property(fdt, "hcall-instructions", hypercall, + sizeof(hypercall))));
+ }
+ _FDT((fdt_end_node(fdt)));
+ }And a hypercall interface surely doesn't make sense for powernv.
Quoted 3 lines
It's qemu paravirt, it exist on G5 too :-) It's for PR KVM, it allows to speed up some bits and pieces. But yeah we don't yet really "support" it at this point. However we might.
Ah, yes, I forgot about that.
Quoted 37 lines
Quoted 28 lines
Quoted 11 lines
hw/ppc/pnv.c new file +11
-0+ + _FDT((fdt_end_node(fdt))); /* close root node */ + _FDT((fdt_finish(fdt))); + + return fdt; +} + +static void powernv_cpu_reset (void *opaque) +{ + PowerPCCPU *cpu = opaque; + CPUState *cs = CPU(cpu);hw/ppc/pnv.c line 409
Quoted 10 lines
hw/ppc/pnv.c new file +10
-0+ CPUPPCState *env = &cpu->env; + + cpu_reset(cs); + + env->spr[SPR_PIR] = ppc_get_vcpu_dt_id(cpu); + env->spr[SPR_HIOR] = 0; + env->gpr[3] = FDT_ADDR; + env->nip = 0x10; + env->msr |= MSR_HVB; +}So, I believe the qemu-ishly correct way of doing this is to have the cpu initialization in the cpu code, rather than the platform code, as much as possible. On PAPR we kind of get away with initialization in the platform code on the grounds that it's a paravirt platform, but powernv doesn't have that excuse.
Quoted 1 line
But this may well be stuff that changes in later patches, so..
Well no, not really. But here too, we mimmic the state as coming out of HostBoot, which isn't quite the same thing. We need to provide the FDT entry, etc...
The "real" reset state of a P8 isn't something we can easily simulate...
Quoted 8 lines
It runs some microcode from a SEEPROM with a small microcontroller which initializes a core, which then runs some HB code off it's L3 cache etc... really not something we want to do in qemu at least for now.
So the initial state here is somewhat in between full virt and paravirt, we simulate a platform that has been partially initialized by HostBoot, to the state it has when it enters OPAL.
Ok, that makes sense, but I think it needs a bit more explanation in the code to that effect.
Quoted 120 lines
Quoted 9 lines
hw/ppc/pnv.c line 415
Quoted 5 lines
hw/ppc/pnv.c new file +5
-0+static const VMStateDescription vmstate_powernv = { + .name = "powernv", + .version_id = 1, + .minimum_version_id = 1, +};It might be best to leave out the vmstate entirely until you're ready to implement migration, rather than having a partial, probably not working migration implementation.
Ok.
Quoted 6 lines
Quoted 6 lines
hw/ppc/pnv.c new file +6
-0+ +static void pnv_create_chip (PnvSystem *sys,unsigned int chip_no) +{ + PnvChip *chip = &sys->chips[chip_no]; + + if (chip_no >= PNV_MAX_CHIPS) {Quoted 8 lines
Quoted 5 lines
+ return;
+ }
+
+ /* XXX Improve chip numbering to better match HW */ + chip->chip_id =chip_no;I think modern qemu conventions would suggest creating the chips as QOM objects rather than having a fixed array.
Yeah, more code & much larger memory footprint for the same result :-)
I can look into it but it's low priority. I still want to rework some of that chip stuff in future patches anyway.
Quoted 69 lines
Quoted 69 lines
hw/ppc/pnv.c new file +69
-0+} + +static void ppc_powernv_init (MachineState *machine) +{ + ram_addr_t ram_size = machine->ram_size; + const char *cpu_model = machine->cpu_model; + const char *kernel_filename = machine->kernel_filename; + const char *initrd_filename = machine->initrd_filename; + uint32_t initrd_base = 0; + long initrd_size = 0; + PowerPCCPU *cpu; + CPUPPCState *env; + MemoryRegion *sysmem = get_system_memory(); + MemoryRegion *ram = g_new(MemoryRegion, 1); + sPowerNVMachineState *pnv_machine = POWERNV_MACHINE(machine); + PnvSystem *sys = &pnv_machine->sys; + long fw_size; + char *filename; + void *fdt; + int i; + + /* init CPUs */ + if (cpu_model == NULL) { + cpu_model = kvm_enabled() ? "host" : "POWER8"; + } + + for (i = 0; i < smp_cpus; i++) { + cpu = cpu_ppc_init(cpu_model); + if (cpu == NULL) { + fprintf(stderr, "Unable to find PowerPC CPU definition\n"); + exit(1); + } + env = &cpu->env; + + /* Set time-base frequency to 512 MHz */ + cpu_ppc_tb_init(env, TIMEBASE_FREQ); + + /* MSR[IP] doesn't exist nowadays */ + env->msr_mask &= ~(1 << 6); + + qemu_register_reset(powernv_cpu_reset, cpu); + } + + /* allocate RAM */ + memory_region_allocate_system_memory(ram, NULL, "ppc_powernv.ram", ram_size); + memory_region_add_subregion(sysmem, 0, ram); + + /* XXX We should decide how many chips to create based on #cores and + * Venice vs. Murano vs. Naples chip type etc..., for now, just create + * one chip. Also creation of the CPUs should be done per-chip + */ + sys->num_chips = 1; + + /* Create only one PHB for now until I figure out what's wrong + * when I create more (resource assignment failures in Linux) + */ + pnv_create_chip(sys, 0); + + if (bios_name == NULL) { + bios_name = FW_FILE_NAME; + } + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE); + if (fw_size < 0) { + hw_error("qemu: could not load OPAL '%s'\n", filename); + exit(1); + } + g_free(filename); +Quoted 8 lines
Quoted 6 lines
+
+ if (kernel_filename== NULL) {
+ kernel_filename =KERNEL_FILE_NAME; + }
+ filename =qemu_find_file(QEMU_FILE_TYPE_BIOS, kernel_filename);The commit withe Opal image should go in before this, no?
Now this is a bit of an open discussion at the moment :-)
The way OPAL is built on OPP machines today is by essentially building a complete flash image which contains HostBoot, OPAL and the petitboot- based bootloader which contains a Linux kernel etc...
We could create a target without HB and with a slimmed down Linux but it would still probably be about 12MB I reckon, if not more. It feels a bit "big" to ship as a binary as part of qemu...
Quoted 6 lines
We would also have to add code to qemu to "find" OPAL in that image, and then add a model for the flash controller.
The other option is to bundle just OPAL itself. However that means you can't go anywhere without a -kernel argument, which would then be either a petitboot-based bootloader or your actual target kernel.
Hm, ok. But in order for this to be usable, we need some way to get a suitable image. So medium term, I think it makes sense to include both opal and PetitBoot, so you can boot the guest like a real machine.
However, including only Opal and requiring -kernel would be a reasonable interim step.
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 27/77 ppc/pnv: Add XSCOM infrastructure
In reply to Benjamin HerrenschmidtXSCOM is an interface to a sideband bus provided by the POWER8 chip pervasive unit, which gives access to a number of facilities in the chip that are needed by the OPAL firmware and to a lesser extent, Linux. This is among others how the PCI Host bridges get configured at boot or how the LPC bus is accessed.
This provides a simple bus and device type for devices sitting on XSCOM along with some facilities to optionally generate corresponding device-tree nodes
--- hw/ppc/Makefile.objs | 2 +- hw/ppc/pnv.c | 11 ++ hw/ppc/pnv_xscom.c | 415 +++++++++++++++++++++++++++++++++++++++++++++ include/hw/ppc/pnv.h | 2 + include/hw/ppc/pnv_xscom.h | 73 ++++++++ 5 files changed, 502 insertions(+), 1 deletion(-) create mode 100644 hw/ppc/pnv_xscom.c create mode 100644 include/hw/ppc/pnv_xscom.h
hw/ppc/Makefile.objs +1 -1
@@ -5,7 +5,7 @@ obj-$(CONFIG_PSERIES) += spapr.o spapr_vio.o spapr_events.o obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_rtc.o spapr_drc.o spapr_rng.o # IBM PowerNV -obj-$(CONFIG_POWERNV) += pnv.o +obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy) obj-y += spapr_pci_vfio.o endif
hw/ppc/pnv.c +11 -0
@@ -41,6 +41,7 @@#include "hw/ppc/ppc.h" #include "hw/ppc/pnv.h" #include "hw/loader.h" +#include "hw/ppc/pnv_xscom.h" #include "exec/address-spaces.h" #include "qemu/config-file.h"
@@ -310,6 +311,7 @@ static void *powernv_create_fdt(PnvSystem *sys, uint32_t initrd_base, uint32_t iuint32_t end_prop =cpu_to_be32 (initrd_base + initrd_size);char *buf;const char plat_compat[] ="qemu,powernv\0ibm,powernv" ; +unsigned int i; fdt =g_malloc0 (FDT_MAX_SIZE );_FDT ((fdt_create (fdt,FDT_MAX_SIZE )));
@@ -367,6 +369,12 @@ static void *powernv_create_fdt(PnvSystem *sys, uint32_t initrd_base, uint32_t i/* Memory */ _FDT ((powernv_populate_memory (fdt))); +/* For each chip */ +for (i =0 ; i < sys->num_chips; i++) { +/* Populate XSCOM */ +_FDT ((xscom_populate_fdt (sys->chips[i].xscom, fdt))); + } +/* /hypervisor node */ if (kvm_enabled ()) {uint8_t hypercall[16 ];
@@ -424,6 +432,9 @@ static void pnv_create_chip(PnvSystem *sys, unsigned int chip_no)/* XXX Improve chip numbering to better match HW */ chip->chip_id = chip_no; + +/* Set up XSCOM bus */ +xscom_create (chip); }static void ppc_powernv_init (MachineState *machine)
hw/ppc/pnv_xscom.c new file +415 -0
415 lines not on this page · raw message
include/hw/ppc/pnv.h +2 -0
@@ -20,10 +20,12 @@*/ #include "hw/hw.h" +typedef struct XScomBus XScomBus ;/* Should we turn that into a QOjb of some sort ? */ typedef struct PnvChip {uint32_t chip_id; +XScomBus *xscom; }PnvChip ; typedef struct PnvSystem {
include/hw/ppc/pnv_xscom.h new file +73 -0
73 lines not on this page · raw message
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 27/77] ppc/pnv: Add XSCOM infrastructure
Quoted 68 lines · Benjamin Herrenschmidt
XSCOM is an interface to a sideband bus provided by the POWER8 chip pervasive unit, which gives access to a number of facilities in the chip that are needed by the OPAL firmware and to a lesser extent, Linux. This is among others how the PCI Host bridges get configured at boot or how the LPC bus is accessed.
This provides a simple bus and device type for devices sitting on XSCOM along with some facilities to optionally generate corresponding device-tree nodes
Signed-off-by Benjamin Herrenschmidt <[email protected]>--- hw/ppc/Makefile.objs | 2 +- hw/ppc/pnv.c | 11 ++ hw/ppc/pnv_xscom.c | 415 +++++++++++++++++++++++++++++++++++++++++++++ include/hw/ppc/pnv.h | 2 + include/hw/ppc/pnv_xscom.h | 73 ++++++++ 5 files changed, 502 insertions(+), 1 deletion(-) create mode 100644 hw/ppc/pnv_xscom.c create mode 100644 include/hw/ppc/pnv_xscom.hhw/ppc/Makefile.objs +1
-1@@ -5,7 +5,7 @@ obj-$(CONFIG_PSERIES) += spapr.o spapr_vio.o spapr_events.o obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_rtc.o spapr_drc.o spapr_rng.o # IBM PowerNV -obj-$(CONFIG_POWERNV) += pnv.o +obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy) obj-y += spapr_pci_vfio.o endifhw/ppc/pnv.c +8
-0@@ -41,6 +41,7 @@#include "hw/ppc/ppc.h" #include "hw/ppc/pnv.h" #include "hw/loader.h" +#include "hw/ppc/pnv_xscom.h" #include "exec/address-spaces.h" #include "qemu/config-file.h" @@ -310,6 +311,7 @@ static void *powernv_create_fdt(PnvSystem *sys, uint32_t initrd_base, uint32_t iuint32_t end_prop =cpu_to_be32 (initrd_base + initrd_size);char *buf;const char plat_compat[] ="qemu,powernv\0ibm,powernv" ; +unsigned int i; fdt =g_malloc0 (FDT_MAX_SIZE );_FDT ((fdt_create (fdt,FDT_MAX_SIZE )));@@ -367,6 +369,12 @@ static void *powernv_create_fdt(PnvSystem *sys, uint32_t initrd_base, uint32_t i/* Memory */ _FDT ((powernv_populate_memory (fdt))); +/* For each chip */ +for (i =0 ; i < sys->num_chips; i++) { +/* Populate XSCOM */ +_FDT ((xscom_populate_fdt (sys->chips[i].xscom, fdt))); + } +/* /hypervisor node */ if (kvm_enabled ()) {uint8_t hypercall[16 ];
hw/ppc/pnv.c static void pnv_create_chip(PnvSystem *sys, unsigned int chip_no) · line 437
Quoted 6 lines
hw/ppc/pnv.c +3
-0@@ -424,6 +432,9 @@ static void pnv_create_chip(PnvSystem *sys, unsigned int chip_no)/* XXX Improve chip numbering to better match HW */ chip->chip_id = chip_no; + +/* Set up XSCOM bus */ +xscom_create (chip);
Hmm.. I'm thinking it probably makes sense to unify the representation of "chip" and "xscom" since there's a 1:1 correspondance. To be QOMishly correct, I think the right way would be a SysBusDevice for each chip, implementing the xscom MMIOs, then an array of link properties under the Machine object to find the right scoms by chip id.
Quoted 64 lines
hw/ppc/pnv.c +0
-0}static void ppc_powernv_init (MachineState *machine)hw/ppc/pnv_xscom.c new file +55
-0@@ -0,0 +1,415 @@ + +/* +* QEMU PowerNV XSCOM bus definitions +* +* Copyright (c) 2010 David Gibson, IBM Corporation <[email protected]> +* Based on the s390 virtio bus code: +* Copyright (c) 2009 Alexander Graf <[email protected]> +* +* 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 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/>. +*/ + +/* TODO: Add some infrastructure for "random stuff" and FIRs that +* various units might want to deal with without creating actual +* XSCOM devices. +* +* For example, HB LPC XSCOM in the PIBAM +*/ +#include "hw/hw.h" +#include "sysemu/sysemu.h" +#include "hw/boards.h" +#include "monitor/monitor.h" +#include "hw/loader.h" +#include "elf.h" +#include "hw/sysbus.h" +#include "sysemu/kvm.h" +#include "sysemu/device_tree.h" +#include "kvm_ppc.h" + +#include "hw/ppc/pnv_xscom.h" + +#include <libfdt.h> + +#define TYPE_XSCOM "xscom" +#define XSCOM (obj) OBJECT_CHECK(XScomState, (obj), TYPE_XSCOM) + +#define XSCOM_SIZE 0x800000000ull +#define XSCOM_BASE (chip) (0x3fc0000000000ull + ((uint64_t)(chip)) * XSCOM_SIZE) + +//#define TRACE_SCOMS + +typedef struct XScomState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/
hw/ppc/pnv_xscom.c line 65
Quoted 10 lines
hw/ppc/pnv_xscom.c new file +10
-0+ +MemoryRegion mem; +int32_t chip_id; +XScomBus *bus; +} XScomState; + +static uint32_t xscom_to_pcb_addr (uint64_t addr) +{ + addr &= (XSCOM_SIZE -1 ); +return ((addr >>4 ) & ~0xfull ) | ((addr >>3 ) &0xf );
Wow, that's a pretty weird address transform.
hw/ppc/pnv_xscom.c line 78
Quoted 13 lines
hw/ppc/pnv_xscom.c new file +13
-0+} + +static void xscom_complete (uint64_t hmer_bits) +{ +CPUState *cs = current_cpu; +PowerPCCPU *cpu =POWERPC_CPU (cs); +CPUPPCState *env = &cpu->env; + +cpu_synchronize_state (cs); + env->spr[SPR_HMER ] |= hmer_bits; + +/* XXX Need a CPU helper to set HMER, also handle gneeration +* of HMIs
Not sure what you're referring to here. Nothing more should be needed to set the HMER - because you've called cpu_synchronize_state() it will be marked dirty and flushed back to KVM before re-entry.
Quoted 10 lines
hw/ppc/pnv_xscom.c new file +10
-0+*/ +} + +static XScomDevice *xscom_find_target (XScomState *s,uint32_t pcb_addr,uint32_t *range) +{ +BusChild *bc; + + QTAILQ_FOREACH(bc, &s->bus->bus.children, sibling) { +DeviceState *qd = bc->child; +XScomDevice *xd =XSCOM_DEVICE (qd);
hw/ppc/pnv_xscom.c line 98
Quoted 10 lines
hw/ppc/pnv_xscom.c new file +10
-0+unsigned int i; + +for (i =0 ; i <MAX_XSCOM_RANGES ; i++) { +if (xd->ranges[i].addr <= pcb_addr && + (xd->ranges[i].addr + xd->ranges[i].size) > pcb_addr) { + *range = i; +return xd; + } + } + }
I'm wondering if it makes sense to construct a custom AddressSpace and use the existing address space lookup logic from exec.c and memory.c rather than implementing your own.
Quoted 38 lines
hw/ppc/pnv_xscom.c new file +38
-0+return NULL ; +} + +static bool xscom_dispatch_read (XScomState *s,uint32_t pcb_addr,uint64_t *out_val) +{ +uint32_t range, offset; +struct XScomDevice *xd =xscom_find_target (s, pcb_addr, &range); +XScomDeviceClass *xc; + +if (!xd) { +return false; + } + xc =XSCOM_DEVICE_GET_CLASS (xd); +if (!xc->read) { +return false; + } + offset = pcb_addr - xd->ranges[range].addr; +return xc->read (xd, range, offset, out_val); +} + +static bool xscom_dispatch_write (XScomState *s,uint32_t pcb_addr,uint64_t val) +{ +uint32_t range, offset; +struct XScomDevice *xd =xscom_find_target (s, pcb_addr, &range); +XScomDeviceClass *xc; + +if (!xd) { +return false; + } + xc =XSCOM_DEVICE_GET_CLASS (xd); +if (!xc->write) { +return false; + } + offset = pcb_addr - xd->ranges[range].addr; +return xc->write (xd, range, offset, val); +} + +static uint64_t xscom_read (void *opaque,hwaddr addr,unsigned width)
hw/ppc/pnv_xscom.c line 146
Quoted 10 lines
hw/ppc/pnv_xscom.c new file +10
-0+{ +XScomState *s = opaque; +uint32_t pcba =xscom_to_pcb_addr (addr); +uint64_t val; + +assert (width ==8 ); + +#ifdef TRACE_SCOMS +printf ("XSCOM_READ(0x%x:0x%x)\n" , s->chip_id, pcba); +#endif
You should be using the built in trace infrastructure here - it's really not that much of a pain. Put
trace_xscom_read(s->chip_id, pcba)
here, put a suitable format in trace-events, and ./configure --enable-trace-backends=stderr
Quoted 85 lines
hw/ppc/pnv_xscom.c new file +85
-0+ +/* Handle some SCOMs here before dispatch */ +switch (pcba) { +case 0xf000f : + val =0x221EF04980000000 ; +break ; +case 0x1010c00 :/* PIBAM FIR */ +case 0x1010c03 :/* PIBAM FIR MASK */ +case 0x2020007 :/* ADU stuff */ +case 0x2020009 :/* ADU stuff */ +case 0x202000f :/* ADU stuff */ + val =0 ; +break ; +case 0x2013f00 :/* PBA stuff */ +case 0x2013f01 :/* PBA stuff */ +case 0x2013f02 :/* PBA stuff */ +case 0x2013f03 :/* PBA stuff */ +case 0x2013f04 :/* PBA stuff */ +case 0x2013f05 :/* PBA stuff */ +case 0x2013f06 :/* PBA stuff */ +case 0x2013f07 :/* PBA stuff */ + val =0 ; +break ; +default : +if (!xscom_dispatch_read (s, pcba, &val)) { +xscom_complete (HMER_XSCOM_FAIL |HMER_XSCOM_DONE ); +return 0 ; + } + } + +xscom_complete (HMER_XSCOM_DONE ); +return val; +} + +static void xscom_write (void *opaque,hwaddr addr,uint64_t val, +unsigned width) +{ +XScomState *s = opaque; +uint32_t pcba =xscom_to_pcb_addr (addr); + +assert (width ==8 ); + +#ifdef TRACE_SCOMS +printf ("XSCOM_WRITE(0x%x:0x%x, 0x%016llx)\n" , + s->chip_id, pcba, (unsigned long long )val); +#endif +/* Handle some SCOMs here before dispatch */ +switch (pcba) { +/* We ignore writes to these */ +case 0xf000f :/* chip id is RO */ +case 0x1010c00 :/* PIBAM FIR */ +case 0x1010c01 :/* PIBAM FIR */ +case 0x1010c02 :/* PIBAM FIR */ +case 0x1010c03 :/* PIBAM FIR MASK */ +case 0x1010c04 :/* PIBAM FIR MASK */ +case 0x1010c05 :/* PIBAM FIR MASK */ +case 0x2020007 :/* ADU stuff */ +case 0x2020009 :/* ADU stuff */ +case 0x202000f :/* ADU stuff */ +break ; +default : +if (!xscom_dispatch_write (s, pcba, val)) { +xscom_complete (HMER_XSCOM_FAIL |HMER_XSCOM_DONE ); +return ; + } + } + +xscom_complete (HMER_XSCOM_DONE ); +} + +static const MemoryRegionOps xscom_ops = { + .read = xscom_read, + .write = xscom_write, + .valid.min_access_size =8 , + .valid.max_access_size =8 , + .impl.min_access_size =8 , + .impl.max_access_size =8 , + .endianness =DEVICE_BIG_ENDIAN , +}; + +static int xscom_init (SysBusDevice *dev) +{ +XScomState *s =XSCOM (dev); + + s->chip_id =-1 ;
hw/ppc/pnv_xscom.c line 241
Quoted 10 lines
hw/ppc/pnv_xscom.c new file +10
-0+return 0 ; +} + +static void xscom_realize (DeviceState *dev,Error **errp) +{ +SysBusDevice *sbd =SYS_BUS_DEVICE (dev); +XScomState *s =XSCOM (dev); +char *name; + +assert (s->chip_id >=0 );
So, this assert could be tripped if the user explicitly instantiated an xscom device which they probably shouldn't do, but could. So, it probably makes sense to use error_setg() here instead of assert().
Quoted 47 lines
hw/ppc/pnv_xscom.c new file +47
-0+ name =g_strdup_printf ("xscom-%x" , s->chip_id); +memory_region_init_io (&s->mem,OBJECT (s), &xscom_ops, s, name,XSCOM_SIZE ); +sysbus_init_mmio (sbd, &s->mem); +sysbus_mmio_map (sbd,0 ,XSCOM_BASE (s->chip_id)); +} + +static Property xscom_properties[] = { +DEFINE_PROP_INT32 ("chip_id" , XScomState, chip_id,0 ), +DEFINE_PROP_END_OF_LIST (), +}; + +static void xscom_class_init (ObjectClass *klass,void *data) +{ +SysBusDeviceClass *k =SYS_BUS_DEVICE_CLASS (klass); +DeviceClass *dc =DEVICE_CLASS (klass); + + dc->props = xscom_properties; + dc->realize = xscom_realize; + k->init = xscom_init; +} + +static const TypeInfo xscom_info = { + .name =TYPE_XSCOM , + .parent =TYPE_SYS_BUS_DEVICE , + .instance_size =sizeof (XScomState), + .class_init = xscom_class_init, +}; + +static void xscom_bus_class_init (ObjectClass *klass,void *data) +{ +} + +static const TypeInfo xscom_bus_info = { + .name =TYPE_XSCOM_BUS , + .parent =TYPE_BUS , + .class_init = xscom_bus_class_init, + .instance_size =sizeof (XScomBus), +}; + +void xscom_create (PnvChip *chip) +{ +DeviceState *dev; +XScomState *xdev; +BusState *qbus; +XScomBus *xb; + + dev =qdev_create (NULL ,TYPE_XSCOM );
hw/ppc/pnv_xscom.c line 298
Quoted 10 lines
hw/ppc/pnv_xscom.c new file +10
-0+qdev_prop_set_uint32 (dev,"chip_id" , chip->chip_id); +qdev_init_nofail (dev); + +/* Create bus on bridge device */ + qbus =qbus_create (TYPE_XSCOM_BUS , dev,"xscom" ); + xb =DO_UPCAST (XScomBus, bus, qbus); + xb->chip_id = chip->chip_id; + xdev =XSCOM (dev); + xdev->bus = xb; + chip->xscom = xb;
I believe the qbus_create() is usually invoked by the bridge's init function, rather than externally.
Quoted 213 lines
hw/ppc/pnv_xscom.c new file +117
-0+} + +#define _FDT (exp) \ + do { \ + int ret = (exp); \ + if (ret < 0) { \ + fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \ + #exp, fdt_strerror(ret)); \ + exit(1); \ + } \ + } while (0) + + +int xscom_populate_fdt (XScomBus *xb,void *fdt) +{ +BusChild *bc; +char *name; +const char compat[] ="ibm,power8-xscom\0ibm,xscom" ; +uint64_t reg[] = {cpu_to_be64 (XSCOM_BASE (xb->chip_id)), +cpu_to_be64 (XSCOM_SIZE ) }; + + name =g_strdup_printf ("xscom@%llx" , (unsigned long long )be64_to_cpu (reg[0 ])); +_FDT ((fdt_begin_node (fdt, name))); +g_free (name); +_FDT ((fdt_property_cell (fdt,"ibm,chip-id" , xb->chip_id))); +_FDT ((fdt_property_cell (fdt,"#address-cells" ,1 ))); +_FDT ((fdt_property_cell (fdt,"#size-cells" ,1 ))); +_FDT ((fdt_property (fdt,"reg" , reg,sizeof (reg)))); +_FDT ((fdt_property (fdt,"compatible" , compat,sizeof (compat)))); +_FDT ((fdt_property (fdt,"scom-controller" ,NULL ,0 ))); + + QTAILQ_FOREACH(bc, &xb->bus.children, sibling) { +DeviceState *qd = bc->child; +XScomDevice *xd =XSCOM_DEVICE (qd); +XScomDeviceClass *xc =XSCOM_DEVICE_GET_CLASS (xd); +uint32_t reg[MAX_XSCOM_RANGES *2 ]; +unsigned int i, sz =0 ; +void *cp, *p; + +/* Some XSCOM slaves may not be represented in the DT */ +if (!xc->dt_name) { +continue ; + } + name =g_strdup_printf ("%s@%x" , xc->dt_name, xd->ranges[0 ].addr); +_FDT ((fdt_begin_node (fdt, name))); +g_free (name); +for (i =0 ; i <MAX_XSCOM_RANGES ; i++) { +if (xd->ranges[i].size ==0 ) { +break ; + } + reg[sz++] =cpu_to_be32 (xd->ranges[i].addr); + reg[sz++] =cpu_to_be32 (xd->ranges[i].size); + } +_FDT ((fdt_property (fdt,"reg" , reg, sz *4 ))); +if (xc->devnode) { +_FDT ((xc->devnode (xd, fdt))); + } +#define MAX_COMPATIBLE_PROP 1024 + cp = p =g_malloc0 (MAX_COMPATIBLE_PROP ); + i =0 ; +while ((p - cp) <MAX_COMPATIBLE_PROP ) { +int l; +if (xc->dt_compatible[i] ==NULL ) { +break ; + } + l =strlen (xc->dt_compatible[i]); +if (l >= (MAX_COMPATIBLE_PROP - i)) { +break ; + } +strcpy (p, xc->dt_compatible[i++]); + p += l +1 ; + } +_FDT ((fdt_property (fdt,"compatible" , cp, p - cp))); +_FDT ((fdt_end_node (fdt))); + } + +_FDT ((fdt_end_node (fdt))); + +return 0 ; +} + +static int xscom_qdev_init (DeviceState *qdev) +{ +XScomDevice *xdev = (XScomDevice *)qdev; +XScomDeviceClass *xc =XSCOM_DEVICE_GET_CLASS (xdev); + +if (xc->init) { +return xc->init (xdev); + } +return 0 ; +} + +static void xscom_device_class_init (ObjectClass *klass,void *data) +{ +DeviceClass *k =DEVICE_CLASS (klass); + k->init = xscom_qdev_init; + k->bus_type =TYPE_XSCOM_BUS ; +} + +static const TypeInfo xscom_dev_info = { + .name =TYPE_XSCOM_DEVICE , + .parent =TYPE_DEVICE , + .instance_size =sizeof (XScomDevice), + .abstract = true, + .class_size =sizeof (XScomDeviceClass), + .class_init = xscom_device_class_init, +}; + +static void xscom_register_types (void ) +{ +type_register_static (&xscom_info); +type_register_static (&xscom_bus_info); +type_register_static (&xscom_dev_info); +} + +type_init (xscom_register_types) +include/hw/ppc/pnv.h +2
-0@@ -20,10 +20,12 @@*/ #include "hw/hw.h" +typedef struct XScomBus XScomBus ;/* Should we turn that into a QOjb of some sort ? */ typedef struct PnvChip {uint32_t chip_id; +XScomBus *xscom; }PnvChip ; typedef struct PnvSystem {include/hw/ppc/pnv_xscom.h new file +73
-0@@ -0,0 +1,73 @@ +#ifndef _HW_XSCOM_H +#define _HW_XSCOM_H +/* +* QEMU PowerNV XSCOM bus definitions +* +* Copyright (c) 2010 David Gibson, IBM Corporation <[email protected]> +* Based on the s390 virtio bus definitions: +* Copyright (c) 2009 Alexander Graf <[email protected]> +* +* 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 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 <hw/ppc/pnv.h> + +#define TYPE_XSCOM_DEVICE "xscom-device" +#define XSCOM_DEVICE (obj) \ + OBJECT_CHECK(XScomDevice, (obj), TYPE_XSCOM_DEVICE) +#define XSCOM_DEVICE_CLASS (klass) \ + OBJECT_CLASS_CHECK(XScomDeviceClass, (klass), TYPE_XSCOM_DEVICE) +#define XSCOM_DEVICE_GET_CLASS (obj) \ + OBJECT_GET_CLASS(XScomDeviceClass, (obj), TYPE_XSCOM_DEVICE) + +#define TYPE_XSCOM_BUS "xscom-bus" +#define XSCOM_BUS (obj) OBJECT_CHECK(XScomBus, (obj), TYPE_XSCOM_BUS) + +typedef struct XScomDevice XScomDevice ; +typedef struct XScomBus XScomBus ; + +typedef struct XScomDeviceClass { +DeviceClass parent_class; + +const char *dt_name; +const char **dt_compatible; +int (*init)(XScomDevice *dev); +int (*devnode)(XScomDevice *dev,void *fdt); + +/* Actual XScom accesses */ +bool (*read)(XScomDevice *dev,uint32_t range,uint32_t offset,uint64_t *out_val); +bool (*write)(XScomDevice *dev,uint32_t range,uint32_t offset,uint64_t val); +}XScomDeviceClass ; + +typedef struct XScomRange { +uint32_t addr; +uint32_t size; +}XScomRange ; + +struct XScomDevice { +DeviceState qdev; +#define MAX_XSCOM_RANGES 4 +struct XScomRange ranges[MAX_XSCOM_RANGES ]; +}; + +struct XScomBus { +BusState bus; +uint32_t chip_id; +}; + +extern void xscom_create (PnvChip *chip); +extern int xscom_populate_fdt (XScomBus *xscom,void *fdt); + + +#endif /* _HW_XSCOM_H */
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [Qemu-ppc] [PATCH 27/77] ppc/pnv: Add XSCOM infrastructure
Quoted 5 lines · David Gibson
Hmm.. I'm thinking it probably makes sense to unify the representation of "chip" and "xscom" since there's a 1:1 correspondance. To be QOMishly correct, I think the right way would be a SysBusDevice for each chip, implementing the xscom MMIOs, then an array of link properties under the Machine object to find the right scoms by chip id.
But there is more than xscom's under each chip ... there's PHBs, LPC controllers (though those are currently under XSCOM) and possibly other completely unrelated things...
To be honest I've never been a big fan of that whole QOM business and am a bit confused as to how that would all work together.
Cheers,
Ben.
Re: [Qemu-devel] [Qemu-ppc] [PATCH 27/77] ppc/pnv: Add XSCOM infrastructure
In reply to David GibsonQuoted 7 lines · David Gibson
hw/ppc/pnv_xscom.c line 65
Quoted 5 lines
hw/ppc/pnv_xscom.c new file +4
-0+static uint32_t xscom_to_pcb_addr (uint64_t addr) +{ + addr &= (XSCOM_SIZE - 1); + return ((addr >> 4) & ~0xfull) | ((addr >> 3) & 0xf);Wow, that's a pretty weird address transform.
Indeed :-) That's how it is in HW. It's also a bit different between chip generations.
Quoted 10 lines
Quoted 10 lines
hw/ppc/pnv_xscom.c new file +10
-0+} + +static void xscom_complete (uint64_t hmer_bits) +{ + CPUState *cs = current_cpu; + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + + cpu_synchronize_state(cs); + env->spr[SPR_HMER] |= hmer_bits;
Quoted 8 lines
Quoted 3 lines
+
+ /* XXX Need a CPU helper to set HMER, also handle gneeration + * of HMIsNot sure what you're referring to here. Nothing more should be needed to set the HMER - because you've called
cpu_synchronize_state()it will be marked dirty and flushed back to KVM before re-entry.
No it's not that. Setting HMER can potentially generate an HMI interrupt (if enabled in HMEER). We never use the interrupt corresponding to XSCOMs in FW though, so that's why I haven't bothered yet.
Quoted 17 lines
Quoted 17 lines
+ */
hw/ppc/pnv_xscom.c new file +16
-0+} + +static XScomDevice *xscom_find_target (XScomState *s,uint32_t pcb_addr,uint32_t *range) +{ + BusChild *bc; + + QTAILQ_FOREACH(bc, &s->bus->bus.children, sibling) { + DeviceState *qd = bc->child; + XScomDevice *xd = XSCOM_DEVICE(qd); + unsigned int i; + + for (i = 0; i < MAX_XSCOM_RANGES; i++) { + if (xd->ranges[i].addr <= pcb_addr && + (xd->ranges[i].addr + xd->ranges[i].size) > pcb_addr) { + *range = i; + return xd;
Quoted 8 lines
Quoted 3 lines
+ }
+ }
+ }I'm wondering if it makes sense to construct a custom AddressSpace and
use the existing address space lookup logic fromexec.candmemory.crather than implementing your own.
Maybe but we'd then have to shift everything by 3 bits, which means the "XSCOM addresses" would no longer match the doc unless we use some kind of macro to do the shifting.
Quoted 46 lines
Quoted 46 lines
+ return NULL;
hw/ppc/pnv_xscom.c new file +45
-0+} + +static bool xscom_dispatch_read (XScomState *s,uint32_t pcb_addr,uint64_t *out_val) +{ + uint32_t range, offset; + struct XScomDevice *xd = xscom_find_target(s, pcb_addr, &range); + XScomDeviceClass *xc; + + if (!xd) { + return false; + } + xc = XSCOM_DEVICE_GET_CLASS(xd); + if (!xc->read) { + return false; + } + offset = pcb_addr - xd->ranges[range].addr; + return xc->read(xd, range, offset, out_val); +} + +static bool xscom_dispatch_write (XScomState *s,uint32_t pcb_addr,uint64_t val) +{ + uint32_t range, offset; + struct XScomDevice *xd = xscom_find_target(s, pcb_addr, &range); + XScomDeviceClass *xc; + + if (!xd) { + return false; + } + xc = XSCOM_DEVICE_GET_CLASS(xd); + if (!xc->write) { + return false; + } + offset = pcb_addr - xd->ranges[range].addr; + return xc->write(xd, range, offset, val); +} + +static uint64_t xscom_read (void *opaque,hwaddr addr,unsigned width) +{ + XScomState *s = opaque; + uint32_t pcba = xscom_to_pcb_addr(addr); + uint64_t val; + + assert(width == 8); + +#ifdef TRACE_SCOMS
Quoted 8 lines
Quoted 2 lines
+
printf("XSCOM_READ(0x%x:0x%x)\n", s->chip_id, pcba); +#endifYou should be using the built in trace infrastructure here - it's really not that much of a pain. Put
trace_xscom_read(s->chip_id, pcba)
here, put a suitable format in trace-events, and ./configure --enable-trace-backends=stderr
I'll investigate this.
Quoted 91 lines
Quoted 91 lines
hw/ppc/pnv_xscom.c new file +91
-0+ + /* Handle some SCOMs here before dispatch */ + switch(pcba) { + case 0xf000f: + val = 0x221EF04980000000; + break; + case 0x1010c00: /* PIBAM FIR */ + case 0x1010c03: /* PIBAM FIR MASK */ + case 0x2020007: /* ADU stuff */ + case 0x2020009: /* ADU stuff */ + case 0x202000f: /* ADU stuff */ + val = 0; + break; + case 0x2013f00: /* PBA stuff */ + case 0x2013f01: /* PBA stuff */ + case 0x2013f02: /* PBA stuff */ + case 0x2013f03: /* PBA stuff */ + case 0x2013f04: /* PBA stuff */ + case 0x2013f05: /* PBA stuff */ + case 0x2013f06: /* PBA stuff */ + case 0x2013f07: /* PBA stuff */ + val = 0; + break; + default: + if (!xscom_dispatch_read(s, pcba, &val)) { + xscom_complete(HMER_XSCOM_FAIL | HMER_XSCOM_DONE); + return 0; + } + } + + xscom_complete(HMER_XSCOM_DONE); + return val; +} + +static void xscom_write (void *opaque,hwaddr addr,uint64_t val, + unsigned width) +{ + XScomState *s = opaque; + uint32_t pcba = xscom_to_pcb_addr(addr); + + assert(width == 8); + +#ifdef TRACE_SCOMS + printf("XSCOM_WRITE(0x%x:0x%x, 0x%016llx)\n", + s->chip_id, pcba, (unsigned long long)val); +#endif + /* Handle some SCOMs here before dispatch */ + switch(pcba) { + /* We ignore writes to these */ + case 0xf000f: /* chip id is RO */ + case 0x1010c00: /* PIBAM FIR */ + case 0x1010c01: /* PIBAM FIR */ + case 0x1010c02: /* PIBAM FIR */ + case 0x1010c03: /* PIBAM FIR MASK */ + case 0x1010c04: /* PIBAM FIR MASK */ + case 0x1010c05: /* PIBAM FIR MASK */ + case 0x2020007: /* ADU stuff */ + case 0x2020009: /* ADU stuff */ + case 0x202000f: /* ADU stuff */ + break; + default: + if (!xscom_dispatch_write(s, pcba, val)) { + xscom_complete(HMER_XSCOM_FAIL | HMER_XSCOM_DONE); + return; + } + } + + xscom_complete(HMER_XSCOM_DONE); +} + +static const MemoryRegionOps xscom_ops = { + .read = xscom_read, + .write = xscom_write, + .valid.min_access_size = 8, + .valid.max_access_size = 8, + .impl.min_access_size = 8, + .impl.max_access_size = 8, + .endianness = DEVICE_BIG_ENDIAN, +}; + +static int xscom_init (SysBusDevice *dev) +{ + XScomState *s = XSCOM(dev); + + s->chip_id = -1; + return 0; +} + +static void xscom_realize (DeviceState *dev,Error **errp) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
Quoted 8 lines
Quoted 4 lines
+ XScomState *s = XSCOM(dev);
+ char *name;
+
+assert(s->chip_id >= 0);So, this assert could be tripped if the user explicitly instantiated an xscom device which they probably shouldn't do, but could. So, it probably makes sense to use
error_setg()here instead ofassert().
No idea what error_setg() is, I'll look into it :)
Quoted 53 lines
Quoted 2 lines
+ name =
g_strdup_printf("xscom-%x", s->chip_id);
+ memory_region_init_io(&s->mem, OBJECT(s),&xscom_ops, s, name,
XSCOM_SIZE);Quoted 50 lines
+
sysbus_init_mmio(sbd, &s->mem);
+sysbus_mmio_map(sbd, 0, XSCOM_BASE(s->chip_id));hw/ppc/pnv_xscom.c new file +48
-0+} + +static Property xscom_properties[] = { + DEFINE_PROP_INT32("chip_id", XScomState, chip_id, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void xscom_class_init (ObjectClass *klass,void *data) +{ + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->props = xscom_properties; + dc->realize = xscom_realize; + k->init = xscom_init; +} + +static const TypeInfo xscom_info = { + .name = TYPE_XSCOM, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(XScomState), + .class_init = xscom_class_init, +}; + +static void xscom_bus_class_init (ObjectClass *klass,void *data) +{ +} + +static const TypeInfo xscom_bus_info = { + .name = TYPE_XSCOM_BUS, + .parent = TYPE_BUS, + .class_init = xscom_bus_class_init, + .instance_size = sizeof(XScomBus), +}; + +void xscom_create (PnvChip *chip) +{ + DeviceState *dev; + XScomState *xdev; + BusState *qbus; + XScomBus *xb; + + dev = qdev_create(NULL, TYPE_XSCOM); + qdev_prop_set_uint32(dev, "chip_id", chip->chip_id); + qdev_init_nofail(dev); + + /* Create bus on bridge device */ + qbus = qbus_create(TYPE_XSCOM_BUS, dev, "xscom");
Quoted 8 lines
Quoted 5 lines
+ xb =
DO_UPCAST(XScomBus, bus, qbus);
+xb->chip_id=chip->chip_id;
+ xdev = XSCOM(dev);
+xdev->bus= xb;
+chip->xscom= xb;I believe the
qbus_create()is usually invoked by the bridge's init function, rather than externally.
Init or realize ?
Cheers,
Ben.
PATCH 28/77 ppc/xics: Rename existing XICS classe to XICS_SPAPR
In reply to Benjamin HerrenschmidtThe common class doesn't change, the KVM one is SPAPR specific, this is a preliminary change to make it easier to support "native" XICS.
--- hw/intc/xics.c | 26 +++++++++++++------------- hw/intc/xics_kvm.c | 6 +++--- hw/ppc/spapr.c | 6 +++--- hw/ppc/spapr_events.c | 2 +- hw/ppc/spapr_pci.c | 8 ++++---- hw/ppc/spapr_vio.c | 2 +- include/hw/ppc/xics.h | 25 +++++++++++++------------ 7 files changed, 38 insertions(+), 37 deletions(-)
hw/intc/xics.c +13 -13
@@ -711,7 +711,7 @@ static int ics_find_free_block(ICSState *ics, int num, int alignnum)return -1 ; } -int xics_alloc (XICSState *icp,int src,int irq_hint,bool lsi) +int xics_spapr_alloc (XICSState *icp,int src,int irq_hint,bool lsi) {ICSState *ics = &icp->ics[src];int irq;
@@ -742,7 +742,7 @@ int xics_alloc(XICSState *icp, int src, int irq_hint, bool lsi)* Allocate block of consecutive IRQs, and return the number of the first IRQ in the block. * If align==true, aligns the first IRQ number to num. */ -int xics_alloc_block (XICSState *icp,int src,int num,bool lsi,bool align) +int xics_spapr_alloc_block (XICSState *icp,int src,int num,bool lsi,bool align) {int i, first =-1 ;ICSState *ics = &icp->ics[src];
@@ -787,7 +787,7 @@ static void ics_free(ICSState *ics, int srcno, int num) } } -void xics_free (XICSState *icp,int irq,int num) +void xics_spapr_free (XICSState *icp,int irq,int num) {int src =xics_find_source (icp, irq);
@@ -1006,7 +1006,7 @@ static void xics_set_nr_servers(XICSState *icp, uint32_t nr_servers, } } -static void xics_realize (DeviceState *dev,Error **errp) +static void xics_spapr_realize (DeviceState *dev,Error **errp) {XICSState *icp =XICS (dev);Error *error =NULL ;
@@ -1045,7 +1045,7 @@ static void xics_realize(DeviceState *dev, Error **errp) } } -static void xics_initfn (Object *obj) +static void xics_spapr_initfn (Object *obj) {XICSState *xics =XICS (obj);
@@ -1054,29 +1054,29 @@ static void xics_initfn(Object *obj) xics->ics->icp = xics; } -static void xics_class_init (ObjectClass *oc,void *data) +static void xics_spapr_class_init (ObjectClass *oc,void *data) {DeviceClass *dc =DEVICE_CLASS (oc); -XICSStateClass *xsc =XICS_CLASS (oc); +XICSStateClass *xsc =XICS_SPAPR_CLASS (oc); - dc->realize = xics_realize; + dc->realize = xics_spapr_realize; xsc->set_nr_irqs = xics_set_nr_irqs; xsc->set_nr_servers = xics_set_nr_servers; } -static const TypeInfo xics_info = { - .name =TYPE_XICS , +static const TypeInfo xics_spapr_info = { + .name =TYPE_XICS_SPAPR , .parent =TYPE_XICS_COMMON , .instance_size =sizeof (XICSState), .class_size =sizeof (XICSStateClass), - .class_init = xics_class_init, - .instance_init = xics_initfn, + .class_init = xics_spapr_class_init, + .instance_init = xics_spapr_initfn, };static void xics_register_types (void ) {type_register_static (&xics_common_info); -type_register_static (&xics_info); +type_register_static (&xics_spapr_info);type_register_static (&ics_info);type_register_static (&icp_info); }
hw/intc/xics_kvm.c +3 -3
@@ -490,8 +490,8 @@ static void xics_kvm_class_init(ObjectClass *oc, void *data) xsc->set_nr_servers = xics_kvm_set_nr_servers; } -static const TypeInfo xics_kvm_info = { - .name =TYPE_KVM_XICS , +static const TypeInfo xics_spapr_kvm_info = { + .name =TYPE_XICS_SPAPR_KVM , .parent =TYPE_XICS_COMMON , .instance_size =sizeof (KVMXICSState), .class_init = xics_kvm_class_init,
@@ -500,7 +500,7 @@ static const TypeInfo xics_kvm_info = {static void xics_kvm_register_types (void ) { -type_register_static (&xics_kvm_info); +type_register_static (&xics_spapr_kvm_info);type_register_static (&ics_kvm_info);type_register_static (&icp_kvm_info); }
hw/ppc/spapr.c +3 -3
@@ -119,7 +119,7 @@ static XICSState *xics_system_init(MachineState *machine,Error *err =NULL ;if (machine_kernel_irqchip_allowed (machine)) { - icp =try_create_xics (TYPE_KVM_XICS , nr_servers, nr_irqs, &err); + icp =try_create_xics (TYPE_XICS_SPAPR_KVM , nr_servers, nr_irqs, &err); }if (machine_kernel_irqchip_required (machine) && !icp) { error_report("kernel_irqchip requested but unavailable: %s",
@@ -128,7 +128,7 @@ static XICSState *xics_system_init(MachineState *machine, }if (!icp) { - icp =try_create_xics (TYPE_XICS , nr_servers, nr_irqs, &error_abort); + icp =try_create_xics (TYPE_XICS_SPAPR , nr_servers, nr_irqs, &error_abort); }return icp;
@@ -1768,7 +1768,7 @@ static void ppc_spapr_init(MachineState *machine) spapr->icp =xics_system_init (machine,DIV_ROUND_UP (max_cpus *kvmppc_smt_threads (), smp_threads), -XICS_IRQS ); +XICS_IRQS_SPAPR );if (smc->dr_lmb_enabled) {spapr_validate_node_memory (machine);
hw/ppc/spapr_events.c +1 -1
@@ -587,7 +587,7 @@ out_no_events:void spapr_events_init (sPAPRMachineState *spapr) {QTAILQ_INIT (&spapr->pending_events); - spapr->check_exception_irq =xics_alloc (spapr->icp,0 ,0 , false); + spapr->check_exception_irq =xics_spapr_alloc (spapr->icp,0 ,0 , false); spapr->epow_notifier.notify = spapr_powerdown_req;qemu_register_powerdown_notifier (&spapr->epow_notifier); spapr_rtas_register(RTAS_CHECK_EXCEPTION, "check-exception",
hw/ppc/spapr_pci.c +4 -4
@@ -313,7 +313,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,return ; } -xics_free (spapr->icp, msi->first_irq, msi->num); +xics_spapr_free (spapr->icp, msi->first_irq, msi->num);if (msi_present (pdev)) {spapr_msi_setmsg (pdev,0 , false,0 , num); }
@@ -351,7 +351,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr, }/* Allocate MSIs */ - irq =xics_alloc_block (spapr->icp,0 , req_num, false, + irq =xics_spapr_alloc_block (spapr->icp,0 , req_num, false, ret_intr_type ==RTAS_TYPE_MSI );if (!irq) {error_report ("Cannot allocate MSIs for device %x" , config_addr);
@@ -1360,7 +1360,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)for (i =0 ; i <PCI_NUM_PINS ; i++) {uint32_t irq; - irq =xics_alloc_block (spapr->icp,0 ,1 , true, false); + irq =xics_spapr_alloc_block (spapr->icp,0 ,1 , true, false);if (!irq) {error_setg (errp,"spapr_allocate_lsi failed" );return ;
@@ -1717,7 +1717,7 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb,_FDT (fdt_setprop (fdt, bus_off,"ranges" , &ranges, sizeof_ranges));_FDT (fdt_setprop (fdt, bus_off,"reg" , &bus_reg,sizeof (bus_reg)));_FDT (fdt_setprop_cell (fdt, bus_off,"ibm,pci-config-space-type" ,0x1 )); -_FDT (fdt_setprop_cell (fdt, bus_off,"ibm,pe-total-#msi" ,XICS_IRQS )); +_FDT (fdt_setprop_cell (fdt, bus_off,"ibm,pe-total-#msi" ,XICS_IRQS_SPAPR ));/* Build the interrupt-map, this must matches what is done * in pci_spapr_map_irq
hw/ppc/spapr_vio.c +1 -1
@@ -462,7 +462,7 @@ static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp) dev->qdev.id = id; } - dev->irq =xics_alloc (spapr->icp,0 , dev->irq, false); + dev->irq =xics_spapr_alloc (spapr->icp,0 , dev->irq, false);if (!dev->irq) {error_setg (errp,"can't allocate IRQ" );return ;
include/hw/ppc/xics.h +13 -12
@@ -32,20 +32,20 @@#define TYPE_XICS_COMMON "xics-common"#define XICS_COMMON (obj) OBJECT_CHECK(XICSState, (obj), TYPE_XICS_COMMON) -#define TYPE_XICS "xics" -#define XICS (obj) OBJECT_CHECK(XICSState, (obj), TYPE_XICS) +#define TYPE_XICS_SPAPR "xics-spapr" +#define XICS (obj) OBJECT_CHECK(XICSState, (obj), TYPE_XICS_SPAPR) -#define TYPE_KVM_XICS "xics-kvm" -#define KVM_XICS (obj) OBJECT_CHECK(KVMXICSState, (obj), TYPE_KVM_XICS) +#define TYPE_XICS_SPAPR_KVM "xics-spapr-kvm" +#define KVM_XICS (obj) OBJECT_CHECK(KVMXICSState, (obj), TYPE_XICS_SPAPR_KVM)#define XICS_COMMON_CLASS (klass) \ OBJECT_CLASS_CHECK(XICSStateClass, (klass), TYPE_XICS_COMMON) -#define XICS_CLASS (klass) \ - OBJECT_CLASS_CHECK(XICSStateClass, (klass), TYPE_XICS) +#define XICS_SPAPR_CLASS (klass) \ + OBJECT_CLASS_CHECK(XICSStateClass, (klass), TYPE_XICS_SPAPR)#define XICS_COMMON_GET_CLASS (obj) \ OBJECT_GET_CLASS(XICSStateClass, (obj), TYPE_XICS_COMMON) -#define XICS_GET_CLASS (obj) \ - OBJECT_GET_CLASS(XICSStateClass, (obj), TYPE_XICS) +#define XICS_SPAPR_GET_CLASS (obj) \ + OBJECT_GET_CLASS(XICSStateClass, (obj), TYPE_XICS_SPAPR)#define XICS_IPI 0x2#define XICS_BUID 0x1
@@ -157,13 +157,14 @@ struct ICSIRQState {uint8_t flags; }; -#define XICS_IRQS 1024 +#define XICS_IRQS_SPAPR 1024qemu_irq xics_get_qirq (XICSState *icp,int irq);void xics_set_irq_type (XICSState *icp,int irq,bool lsi); -int xics_alloc (XICSState *icp,int src,int irq_hint,bool lsi); -int xics_alloc_block (XICSState *icp,int src,int num,bool lsi,bool align); -void xics_free (XICSState *icp,int irq,int num); + +int xics_spapr_alloc (XICSState *icp,int src,int irq_hint,bool lsi); +int xics_spapr_alloc_block (XICSState *icp,int src,int num,bool lsi,bool align); +void xics_spapr_free (XICSState *icp,int irq,int num);void xics_cpu_setup (XICSState *icp,PowerPCCPU *cpu);
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 28/77] ppc/xics: Rename existing XICS classe to XICS_SPAPR
Quoted 4 lines · Benjamin Herrenschmidt
The common class doesn't change, the KVM one is SPAPR specific, this is a preliminary change to make it easier to support "native" XICS.
Signed-off-by Benjamin Herrenschmidt <[email protected]>
So changing the variable names is fine, but I believe actually changing the type name from "xics" to "xics-spapr" will break migration for existing sPAPR guests. There are some ways to wangle that, but I think it's going to be much simpler to leave the existing name as "xics" and add a new "xics-native".
You can still change the name of the TYPE_XICS macro to TYPE_XICS_SPAPR if you want.
Quoted 270 lines
--- hw/intc/xics.c | 26 +++++++++++++------------- hw/intc/xics_kvm.c | 6 +++--- hw/ppc/spapr.c | 6 +++--- hw/ppc/spapr_events.c | 2 +- hw/ppc/spapr_pci.c | 8 ++++---- hw/ppc/spapr_vio.c | 2 +- include/hw/ppc/xics.h | 25 +++++++++++++------------ 7 files changed, 38 insertions(+), 37 deletions(-)hw/intc/xics.c +13
-13@@ -711,7 +711,7 @@ static int ics_find_free_block(ICSState *ics, int num, int alignnum)return -1 ; } -int xics_alloc (XICSState *icp,int src,int irq_hint,bool lsi) +int xics_spapr_alloc (XICSState *icp,int src,int irq_hint,bool lsi) {ICSState *ics = &icp->ics[src];int irq;@@ -742,7 +742,7 @@ int xics_alloc(XICSState *icp, int src, int irq_hint, bool lsi)* Allocate block of consecutive IRQs, and return the number of the first IRQ in the block. * If align==true, aligns the first IRQ number to num. */ -int xics_alloc_block (XICSState *icp,int src,int num,bool lsi,bool align) +int xics_spapr_alloc_block (XICSState *icp,int src,int num,bool lsi,bool align) {int i, first =-1 ;ICSState *ics = &icp->ics[src];@@ -787,7 +787,7 @@ static void ics_free(ICSState *ics, int srcno, int num) } } -void xics_free (XICSState *icp,int irq,int num) +void xics_spapr_free (XICSState *icp,int irq,int num) {int src =xics_find_source (icp, irq);@@ -1006,7 +1006,7 @@ static void xics_set_nr_servers(XICSState *icp, uint32_t nr_servers, } } -static void xics_realize (DeviceState *dev,Error **errp) +static void xics_spapr_realize (DeviceState *dev,Error **errp) {XICSState *icp =XICS (dev);Error *error =NULL ;@@ -1045,7 +1045,7 @@ static void xics_realize(DeviceState *dev, Error **errp) } } -static void xics_initfn (Object *obj) +static void xics_spapr_initfn (Object *obj) {XICSState *xics =XICS (obj);@@ -1054,29 +1054,29 @@ static void xics_initfn(Object *obj) xics->ics->icp = xics; } -static void xics_class_init (ObjectClass *oc,void *data) +static void xics_spapr_class_init (ObjectClass *oc,void *data) {DeviceClass *dc =DEVICE_CLASS (oc); -XICSStateClass *xsc =XICS_CLASS (oc); +XICSStateClass *xsc =XICS_SPAPR_CLASS (oc); - dc->realize = xics_realize; + dc->realize = xics_spapr_realize; xsc->set_nr_irqs = xics_set_nr_irqs; xsc->set_nr_servers = xics_set_nr_servers; } -static const TypeInfo xics_info = { - .name =TYPE_XICS , +static const TypeInfo xics_spapr_info = { + .name =TYPE_XICS_SPAPR , .parent =TYPE_XICS_COMMON , .instance_size =sizeof (XICSState), .class_size =sizeof (XICSStateClass), - .class_init = xics_class_init, - .instance_init = xics_initfn, + .class_init = xics_spapr_class_init, + .instance_init = xics_spapr_initfn, };static void xics_register_types (void ) {type_register_static (&xics_common_info); -type_register_static (&xics_info); +type_register_static (&xics_spapr_info);type_register_static (&ics_info);type_register_static (&icp_info); }hw/intc/xics_kvm.c +3
-3@@ -490,8 +490,8 @@ static void xics_kvm_class_init(ObjectClass *oc, void *data) xsc->set_nr_servers = xics_kvm_set_nr_servers; } -static const TypeInfo xics_kvm_info = { - .name =TYPE_KVM_XICS , +static const TypeInfo xics_spapr_kvm_info = { + .name =TYPE_XICS_SPAPR_KVM , .parent =TYPE_XICS_COMMON , .instance_size =sizeof (KVMXICSState), .class_init = xics_kvm_class_init,@@ -500,7 +500,7 @@ static const TypeInfo xics_kvm_info = {static void xics_kvm_register_types (void ) { -type_register_static (&xics_kvm_info); +type_register_static (&xics_spapr_kvm_info);type_register_static (&ics_kvm_info);type_register_static (&icp_kvm_info); }hw/ppc/spapr.c +3
-3@@ -119,7 +119,7 @@ static XICSState *xics_system_init(MachineState *machine,Error *err =NULL ;if (machine_kernel_irqchip_allowed (machine)) { - icp =try_create_xics (TYPE_KVM_XICS , nr_servers, nr_irqs, &err); + icp =try_create_xics (TYPE_XICS_SPAPR_KVM , nr_servers, nr_irqs, &err); }if (machine_kernel_irqchip_required (machine) && !icp) { error_report("kernel_irqchip requested but unavailable: %s",@@ -128,7 +128,7 @@ static XICSState *xics_system_init(MachineState *machine, }if (!icp) { - icp =try_create_xics (TYPE_XICS , nr_servers, nr_irqs, &error_abort); + icp =try_create_xics (TYPE_XICS_SPAPR , nr_servers, nr_irqs, &error_abort); }return icp;@@ -1768,7 +1768,7 @@ static void ppc_spapr_init(MachineState *machine) spapr->icp =xics_system_init (machine,DIV_ROUND_UP (max_cpus *kvmppc_smt_threads (), smp_threads), -XICS_IRQS ); +XICS_IRQS_SPAPR );if (smc->dr_lmb_enabled) {spapr_validate_node_memory (machine);hw/ppc/spapr_events.c +1
-1@@ -587,7 +587,7 @@ out_no_events:void spapr_events_init (sPAPRMachineState *spapr) {QTAILQ_INIT (&spapr->pending_events); - spapr->check_exception_irq =xics_alloc (spapr->icp,0 ,0 , false); + spapr->check_exception_irq =xics_spapr_alloc (spapr->icp,0 ,0 , false); spapr->epow_notifier.notify = spapr_powerdown_req;qemu_register_powerdown_notifier (&spapr->epow_notifier); spapr_rtas_register(RTAS_CHECK_EXCEPTION, "check-exception",hw/ppc/spapr_pci.c +4
-4@@ -313,7 +313,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,return ; } -xics_free (spapr->icp, msi->first_irq, msi->num); +xics_spapr_free (spapr->icp, msi->first_irq, msi->num);if (msi_present (pdev)) {spapr_msi_setmsg (pdev,0 , false,0 , num); }@@ -351,7 +351,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr, }/* Allocate MSIs */ - irq =xics_alloc_block (spapr->icp,0 , req_num, false, + irq =xics_spapr_alloc_block (spapr->icp,0 , req_num, false, ret_intr_type ==RTAS_TYPE_MSI );if (!irq) {error_report ("Cannot allocate MSIs for device %x" , config_addr);@@ -1360,7 +1360,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)for (i =0 ; i <PCI_NUM_PINS ; i++) {uint32_t irq; - irq =xics_alloc_block (spapr->icp,0 ,1 , true, false); + irq =xics_spapr_alloc_block (spapr->icp,0 ,1 , true, false);if (!irq) {error_setg (errp,"spapr_allocate_lsi failed" );return ;@@ -1717,7 +1717,7 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb,_FDT (fdt_setprop (fdt, bus_off,"ranges" , &ranges, sizeof_ranges));_FDT (fdt_setprop (fdt, bus_off,"reg" , &bus_reg,sizeof (bus_reg)));_FDT (fdt_setprop_cell (fdt, bus_off,"ibm,pci-config-space-type" ,0x1 )); -_FDT (fdt_setprop_cell (fdt, bus_off,"ibm,pe-total-#msi" ,XICS_IRQS )); +_FDT (fdt_setprop_cell (fdt, bus_off,"ibm,pe-total-#msi" ,XICS_IRQS_SPAPR ));/* Build the interrupt-map, this must matches what is done * in pci_spapr_map_irq hw/ppc/spapr_vio.c +1
-1@@ -462,7 +462,7 @@ static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp) dev->qdev.id = id; } - dev->irq =xics_alloc (spapr->icp,0 , dev->irq, false); + dev->irq =xics_spapr_alloc (spapr->icp,0 , dev->irq, false);if (!dev->irq) {error_setg (errp,"can't allocate IRQ" );return ;include/hw/ppc/xics.h +13
-12@@ -32,20 +32,20 @@#define TYPE_XICS_COMMON "xics-common"#define XICS_COMMON (obj) OBJECT_CHECK(XICSState, (obj), TYPE_XICS_COMMON) -#define TYPE_XICS "xics" -#define XICS (obj) OBJECT_CHECK(XICSState, (obj), TYPE_XICS) +#define TYPE_XICS_SPAPR "xics-spapr" +#define XICS (obj) OBJECT_CHECK(XICSState, (obj), TYPE_XICS_SPAPR) -#define TYPE_KVM_XICS "xics-kvm" -#define KVM_XICS (obj) OBJECT_CHECK(KVMXICSState, (obj), TYPE_KVM_XICS) +#define TYPE_XICS_SPAPR_KVM "xics-spapr-kvm" +#define KVM_XICS (obj) OBJECT_CHECK(KVMXICSState, (obj), TYPE_XICS_SPAPR_KVM)#define XICS_COMMON_CLASS (klass) \ OBJECT_CLASS_CHECK(XICSStateClass, (klass), TYPE_XICS_COMMON) -#define XICS_CLASS (klass) \ - OBJECT_CLASS_CHECK(XICSStateClass, (klass), TYPE_XICS) +#define XICS_SPAPR_CLASS (klass) \ + OBJECT_CLASS_CHECK(XICSStateClass, (klass), TYPE_XICS_SPAPR)#define XICS_COMMON_GET_CLASS (obj) \ OBJECT_GET_CLASS(XICSStateClass, (obj), TYPE_XICS_COMMON) -#define XICS_GET_CLASS (obj) \ - OBJECT_GET_CLASS(XICSStateClass, (obj), TYPE_XICS) +#define XICS_SPAPR_GET_CLASS (obj) \ + OBJECT_GET_CLASS(XICSStateClass, (obj), TYPE_XICS_SPAPR)#define XICS_IPI 0x2#define XICS_BUID 0x1@@ -157,13 +157,14 @@ struct ICSIRQState {uint8_t flags; }; -#define XICS_IRQS 1024 +#define XICS_IRQS_SPAPR 1024qemu_irq xics_get_qirq (XICSState *icp,int irq);void xics_set_irq_type (XICSState *icp,int irq,bool lsi); -int xics_alloc (XICSState *icp,int src,int irq_hint,bool lsi); -int xics_alloc_block (XICSState *icp,int src,int num,bool lsi,bool align); -void xics_free (XICSState *icp,int irq,int num); + +int xics_spapr_alloc (XICSState *icp,int src,int irq_hint,bool lsi); +int xics_spapr_alloc_block (XICSState *icp,int src,int num,bool lsi,bool align); +void xics_spapr_free (XICSState *icp,int irq,int num);void xics_cpu_setup (XICSState *icp,PowerPCCPU *cpu);
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 29/77 ppc/xics: Move SPAPR specific code to a separate file
In reply to Benjamin HerrenschmidtLeave the core ICP/ICS logic in xics.c and move the top level class wrapper, hypercall and RTAS handlers to xics_spapr.c
--- default-configs/ppc64-softmmu.mak | 1 + hw/intc/Makefile.objs | 1 + hw/intc/xics.c | 390 ++---------------------------------- hw/intc/xics_spapr.c | 401 ++++++++++++++++++++++++++++++++++++++ include/hw/ppc/xics.h | 23 +++ 5 files changed, 437 insertions(+), 379 deletions(-) create mode 100644 hw/intc/xics_spapr.c
default-configs/ppc64-softmmu.mak +1 -0
@@ -50,6 +50,7 @@ CONFIG_ETSEC=y CONFIG_LIBDECNUMBER=y # For pSeries CONFIG_XICS=$(CONFIG_PSERIES) +CONFIG_XICS_SPAPR=$(CONFIG_PSERIES) CONFIG_XICS_KVM=$(and $(CONFIG_PSERIES),$(CONFIG_KVM)) # For PReP CONFIG_MC146818RTC=y
hw/intc/Makefile.objs +1 -0
@@ -26,6 +26,7 @@ obj-$(CONFIG_OMAP) += omap_intc.o obj-$(CONFIG_OPENPIC_KVM) += openpic_kvm.o obj-$(CONFIG_SH4) += sh_intc.o obj-$(CONFIG_XICS) += xics.o +obj-$(CONFIG_XICS_SPAPR) += xics_spapr.o obj-$(CONFIG_XICS_KVM) += xics_kvm.o obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o obj-$(CONFIG_S390_FLIC) += s390_flic.o
hw/intc/xics.c +11 -379
467 lines not on this page · raw message
hw/intc/xics_spapr.c new file +401 -0
401 lines not on this page · raw message
include/hw/ppc/xics.h +23 -0
@@ -141,6 +141,12 @@ struct ICSState {XICSState *icp; }; +static inline bool ics_valid_irq (ICSState *ics,uint32_t nr) +{ +return (nr >= ics->offset) + && (nr < (ics->offset + ics->nr_irqs)); +} +struct ICSIRQState {uint32_t server;uint8_t priority;
@@ -168,4 +174,21 @@ void xics_spapr_free(XICSState *icp, int irq, int num);void xics_cpu_setup (XICSState *icp,PowerPCCPU *cpu); +/* Internal XICS interfaces */ +int get_cpu_index_by_dt_id (int cpu_dt_id); + +void icp_set_cppr (XICSState *icp,int server,uint8_t cppr); +void icp_set_mfrr (XICSState *icp,int server,uint8_t mfrr); +uint32_t icp_accept (ICPState *ss); +void icp_eoi (XICSState *icp,int server,uint32_t xirr); + +void ics_write_xive (ICSState *ics,int nr,int server, +uint8_t priority,uint8_t saved_priority); + +void ics_set_irq_type (ICSState *ics,int srcno,bool lsi); + +void xics_set_nr_irqs (XICSState *icp,uint32_t nr_irqs,Error **errp); +void xics_set_nr_servers (XICSState *icp,uint32_t nr_servers,Error **errp); +int xics_find_source (XICSState *icp,int irq); +#endif /* __XICS_H__ */
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 29/77] ppc/xics: Move SPAPR specific code to a separate file
Quoted 4 lines · Benjamin Herrenschmidt
Leave the core ICP/ICS logic in
xics.cand move the top level class wrapper, hypercall and RTAS handlers toxics_spapr.cSigned-off-by Benjamin Herrenschmidt <[email protected]>
Concept looks fine.
Quoted 961 lines
--- default-configs/ppc64-softmmu.mak | 1 + hw/intc/Makefile.objs | 1 + hw/intc/xics.c | 390 ++---------------------------------- hw/intc/xics_spapr.c | 401 ++++++++++++++++++++++++++++++++++++++ include/hw/ppc/xics.h | 23 +++ 5 files changed, 437 insertions(+), 379 deletions(-) create mode 100644 hw/intc/xics_spapr.cdefault-configs/ppc64-softmmu.mak +1
-0@@ -50,6 +50,7 @@ CONFIG_ETSEC=y CONFIG_LIBDECNUMBER=y # For pSeries CONFIG_XICS=$(CONFIG_PSERIES) +CONFIG_XICS_SPAPR=$(CONFIG_PSERIES) CONFIG_XICS_KVM=$(and $(CONFIG_PSERIES),$(CONFIG_KVM)) # For PReP CONFIG_MC146818RTC=yhw/intc/Makefile.objs +1
-0@@ -26,6 +26,7 @@ obj-$(CONFIG_OMAP) += omap_intc.o obj-$(CONFIG_OPENPIC_KVM) += openpic_kvm.o obj-$(CONFIG_SH4) += sh_intc.o obj-$(CONFIG_XICS) += xics.o +obj-$(CONFIG_XICS_SPAPR) += xics_spapr.o obj-$(CONFIG_XICS_KVM) += xics_kvm.o obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o obj-$(CONFIG_S390_FLIC) += s390_flic.ohw/intc/xics.c +11
-379@@ -33,7 +33,7 @@#include "qemu/error-report.h" #include "qapi/visitor.h" -static int get_cpu_index_by_dt_id (int cpu_dt_id) +int get_cpu_index_by_dt_id (int cpu_dt_id) {PowerPCCPU *cpu =ppc_get_vcpu_by_dt_id (cpu_dt_id);@@ -224,7 +224,7 @@ static void icp_resend(XICSState *icp, int server)ics_resend (icp->ics); } -static void icp_set_cppr (XICSState *icp,int server,uint8_t cppr) +void icp_set_cppr (XICSState *icp,int server,uint8_t cppr) {ICPState *ss = icp->ss + server;uint8_t old_cppr;@@ -248,7 +248,7 @@ static void icp_set_cppr(XICSState *icp, int server, uint8_t cppr) } } -static void icp_set_mfrr (XICSState *icp,int server,uint8_t mfrr) +void icp_set_mfrr (XICSState *icp,int server,uint8_t mfrr) {ICPState *ss = icp->ss + server;@@ -258,7 +258,7 @@ static void icp_set_mfrr(XICSState *icp, int server, uint8_t mfrr) } } -static uint32_t icp_accept (ICPState *ss) +uint32_t icp_accept (ICPState *ss) {uint32_t xirr = ss->xirr;@@ -271,7 +271,7 @@ static uint32_t icp_accept(ICPState *ss)return xirr; } -static void icp_eoi (XICSState *icp,int server,uint32_t xirr) +void icp_eoi (XICSState *icp,int server,uint32_t xirr) {ICPState *ss = icp->ss + server;@@ -372,12 +372,6 @@ static const TypeInfo icp_info = {/* * ICS: Source layer */ -static int ics_valid_irq (ICSState *ics,uint32_t nr) -{ -return (nr >= ics->offset) - && (nr < (ics->offset + ics->nr_irqs)); -} -static void resend_msi (ICSState *ics,int srcno) {ICSIRQState *irq = ics->irqs + srcno;@@ -462,8 +456,8 @@ static void write_xive_lsi(ICSState *ics, int srcno)resend_lsi (ics, srcno); } -static void ics_write_xive (ICSState *ics,int nr,int server, -uint8_t priority,uint8_t saved_priority) +void ics_write_xive (ICSState *ics,int nr,int server, +uint8_t priority,uint8_t saved_priority) {int srcno = nr - ics->offset;ICSIRQState *irq = ics->irqs + srcno;@@ -640,7 +634,7 @@ static const TypeInfo ics_info = {/* * Exported functions */ -static int xics_find_source (XICSState *icp,int irq) +int xics_find_source (XICSState *icp,int irq) {int sources =1 ;int src;@@ -668,7 +662,7 @@ qemu_irq xics_get_qirq(XICSState *icp, int irq)return NULL ; } -static void ics_set_irq_type (ICSState *ics,int srcno,bool lsi) +void ics_set_irq_type (ICSState *ics,int srcno,bool lsi) {assert (!(ics->irqs[srcno].flags &XICS_FLAGS_IRQ_MASK ));@@ -687,310 +681,16 @@ void xics_set_irq_type(XICSState *icp, int irq, bool lsi)ics_set_irq_type (ics, irq - ics->offset, lsi); } -#define ICS_IRQ_FREE (ics, srcno) \ - (!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK))) - -static int ics_find_free_block (ICSState *ics,int num,int alignnum) -{ -int first, i; - -for (first =0 ; first < ics->nr_irqs; first += alignnum) { -if (num > (ics->nr_irqs - first)) { -return -1 ; - } -for (i = first; i < first + num; ++i) { -if (!ICS_IRQ_FREE (ics, i)) { -break ; - } - } -if (i == (first + num)) { -return first; - } - } - -return -1 ; -} - -int xics_spapr_alloc (XICSState *icp,int src,int irq_hint,bool lsi) -{ -ICSState *ics = &icp->ics[src]; -int irq; - -if (irq_hint) { -assert (src ==xics_find_source (icp, irq_hint)); -if (!ICS_IRQ_FREE (ics, irq_hint - ics->offset)) { -trace_xics_alloc_failed_hint (src, irq_hint); -return -1 ; - } - irq = irq_hint; - }else { - irq =ics_find_free_block (ics,1 ,1 ); -if (irq <0 ) { -trace_xics_alloc_failed_no_left (src); -return -1 ; - } - irq += ics->offset; - } - -ics_set_irq_type (ics, irq - ics->offset, lsi); -trace_xics_alloc (src, irq); - -return irq; -} - -/* -* Allocate block of consecutive IRQs, and return the number of the first IRQ in the block. -* If align==true, aligns the first IRQ number to num. -*/ -int xics_spapr_alloc_block (XICSState *icp,int src,int num,bool lsi,bool align) -{ -int i, first =-1 ; -ICSState *ics = &icp->ics[src]; - -assert (src ==0 ); -/* -* MSIMesage::data is used for storing VIRQ so -* it has to be aligned to num to support multiple -* MSI vectors. MSI-X is not affected by this. -* The hint is used for the first IRQ, the rest should -* be allocated continuously. -*/ -if (align) { -assert ((num ==1 ) || (num ==2 ) || (num ==4 ) || - (num ==8 ) || (num ==16 ) || (num ==32 )); - first =ics_find_free_block (ics, num, num); - }else { - first =ics_find_free_block (ics, num,1 ); - } - -if (first >=0 ) { -for (i = first; i < first + num; ++i) { -ics_set_irq_type (ics, i, lsi); - } - } - first += ics->offset; - -trace_xics_alloc_block (src, first, num, lsi, align); - -return first; -} - -static void ics_free (ICSState *ics,int srcno,int num) -{ -int i; - -for (i = srcno; i < srcno + num; ++i) { -if (ICS_IRQ_FREE (ics, i)) { -trace_xics_ics_free_warn (ics - ics->icp->ics, i + ics->offset); - } -memset (&ics->irqs[i],0 ,sizeof (ICSIRQState)); - } -} - -void xics_spapr_free (XICSState *icp,int irq,int num) -{ -int src =xics_find_source (icp, irq); - -if (src >=0 ) { -ICSState *ics = &icp->ics[src]; - -/* FIXME: implement multiple sources */ -assert (src ==0 ); - -trace_xics_ics_free (ics - icp->ics, irq, num); -ics_free (ics, irq - ics->offset, num); - } -} - -/* -* Guest interfaces -*/ - -static target_ulong h_cppr (PowerPCCPU *cpu,sPAPRMachineState *spapr, -target_ulong opcode,target_ulong *args) -{ -CPUState *cs =CPU (cpu); -target_ulong cppr = args[0 ]; - -icp_set_cppr (spapr->icp, cs->cpu_index, cppr); -return H_SUCCESS ; -} - -static target_ulong h_ipi (PowerPCCPU *cpu,sPAPRMachineState *spapr, -target_ulong opcode,target_ulong *args) -{ -target_ulong server =get_cpu_index_by_dt_id (args[0 ]); -target_ulong mfrr = args[1 ]; - -if (server >= spapr->icp->nr_servers) { -return H_PARAMETER ; - } - -icp_set_mfrr (spapr->icp, server, mfrr); -return H_SUCCESS ; -} - -static target_ulong h_xirr (PowerPCCPU *cpu,sPAPRMachineState *spapr, -target_ulong opcode,target_ulong *args) -{ -CPUState *cs =CPU (cpu); -uint32_t xirr =icp_accept (spapr->icp->ss + cs->cpu_index); - - args[0 ] = xirr; -return H_SUCCESS ; -} - -static target_ulong h_xirr_x (PowerPCCPU *cpu,sPAPRMachineState *spapr, -target_ulong opcode,target_ulong *args) -{ -CPUState *cs =CPU (cpu); -ICPState *ss = &spapr->icp->ss[cs->cpu_index]; -uint32_t xirr =icp_accept (ss); - - args[0 ] = xirr; - args[1 ] =cpu_get_host_ticks (); -return H_SUCCESS ; -} - -static target_ulong h_eoi (PowerPCCPU *cpu,sPAPRMachineState *spapr, -target_ulong opcode,target_ulong *args) -{ -CPUState *cs =CPU (cpu); -target_ulong xirr = args[0 ]; - -icp_eoi (spapr->icp, cs->cpu_index, xirr); -return H_SUCCESS ; -} - -static target_ulong h_ipoll (PowerPCCPU *cpu,sPAPRMachineState *spapr, -target_ulong opcode,target_ulong *args) -{ -CPUState *cs =CPU (cpu); -ICPState *ss = &spapr->icp->ss[cs->cpu_index]; - - args[0 ] = ss->xirr; - args[1 ] = ss->mfrr; - -return H_SUCCESS ; -} - -static void rtas_set_xive (PowerPCCPU *cpu,sPAPRMachineState *spapr, -uint32_t token, -uint32_t nargs,target_ulong args, -uint32_t nret,target_ulong rets) -{ -ICSState *ics = spapr->icp->ics; -uint32_t nr, server, priority; - -if ((nargs !=3 ) || (nret !=1 )) { -rtas_st (rets,0 ,RTAS_OUT_PARAM_ERROR ); -return ; - } - - nr =rtas_ld (args,0 ); - server =get_cpu_index_by_dt_id (rtas_ld (args,1 )); - priority =rtas_ld (args,2 ); - -if (!ics_valid_irq (ics, nr) || (server >= ics->icp->nr_servers) - || (priority >0xff )) { -rtas_st (rets,0 ,RTAS_OUT_PARAM_ERROR ); -return ; - } - -ics_write_xive (ics, nr, server, priority, priority); - -rtas_st (rets,0 ,RTAS_OUT_SUCCESS ); -} - -static void rtas_get_xive (PowerPCCPU *cpu,sPAPRMachineState *spapr, -uint32_t token, -uint32_t nargs,target_ulong args, -uint32_t nret,target_ulong rets) -{ -ICSState *ics = spapr->icp->ics; -uint32_t nr; - -if ((nargs !=1 ) || (nret !=3 )) { -rtas_st (rets,0 ,RTAS_OUT_PARAM_ERROR ); -return ; - } - - nr =rtas_ld (args,0 ); - -if (!ics_valid_irq (ics, nr)) { -rtas_st (rets,0 ,RTAS_OUT_PARAM_ERROR ); -return ; - } - -rtas_st (rets,0 ,RTAS_OUT_SUCCESS ); -rtas_st (rets,1 , ics->irqs[nr - ics->offset].server); -rtas_st (rets,2 , ics->irqs[nr - ics->offset].priority); -} - -static void rtas_int_off (PowerPCCPU *cpu,sPAPRMachineState *spapr, -uint32_t token, -uint32_t nargs,target_ulong args, -uint32_t nret,target_ulong rets) -{ -ICSState *ics = spapr->icp->ics; -uint32_t nr; - -if ((nargs !=1 ) || (nret !=1 )) { -rtas_st (rets,0 ,RTAS_OUT_PARAM_ERROR ); -return ; - } - - nr =rtas_ld (args,0 ); - -if (!ics_valid_irq (ics, nr)) { -rtas_st (rets,0 ,RTAS_OUT_PARAM_ERROR ); -return ; - } - -ics_write_xive (ics, nr, ics->irqs[nr - ics->offset].server,0xff , - ics->irqs[nr - ics->offset].priority); - -rtas_st (rets,0 ,RTAS_OUT_SUCCESS ); -} - -static void rtas_int_on (PowerPCCPU *cpu,sPAPRMachineState *spapr, -uint32_t token, -uint32_t nargs,target_ulong args, -uint32_t nret,target_ulong rets) -{ -ICSState *ics = spapr->icp->ics; -uint32_t nr; - -if ((nargs !=1 ) || (nret !=1 )) { -rtas_st (rets,0 ,RTAS_OUT_PARAM_ERROR ); -return ; - } - - nr =rtas_ld (args,0 ); - -if (!ics_valid_irq (ics, nr)) { -rtas_st (rets,0 ,RTAS_OUT_PARAM_ERROR ); -return ; - } - -ics_write_xive (ics, nr, ics->irqs[nr - ics->offset].server, - ics->irqs[nr - ics->offset].saved_priority, - ics->irqs[nr - ics->offset].saved_priority); - -rtas_st (rets,0 ,RTAS_OUT_SUCCESS ); -} -/* * XICS */ -static void xics_set_nr_irqs (XICSState *icp,uint32_t nr_irqs,Error **errp) +void xics_set_nr_irqs (XICSState *icp,uint32_t nr_irqs,Error **errp) { icp->nr_irqs = icp->ics->nr_irqs = nr_irqs; } -static void xics_set_nr_servers (XICSState *icp,uint32_t nr_servers, -Error **errp) +void xics_set_nr_servers (XICSState *icp,uint32_t nr_servers,Error **errp) {int i;@@ -1006,77 +706,9 @@ static void xics_set_nr_servers(XICSState *icp, uint32_t nr_servers, } } -static void xics_spapr_realize (DeviceState *dev,Error **errp) -{ -XICSState *icp =XICS (dev); -Error *error =NULL ; -int i; - -if (!icp->nr_servers) { -error_setg (errp,"Number of servers needs to be greater 0" ); -return ; - } - -/* Registration of global state belongs into realize */ -spapr_rtas_register (RTAS_IBM_SET_XIVE ,"ibm,set-xive" , rtas_set_xive); -spapr_rtas_register (RTAS_IBM_GET_XIVE ,"ibm,get-xive" , rtas_get_xive); -spapr_rtas_register (RTAS_IBM_INT_OFF ,"ibm,int-off" , rtas_int_off); -spapr_rtas_register (RTAS_IBM_INT_ON ,"ibm,int-on" , rtas_int_on); - -spapr_register_hypercall (H_CPPR , h_cppr); -spapr_register_hypercall (H_IPI , h_ipi); -spapr_register_hypercall (H_XIRR , h_xirr); -spapr_register_hypercall (H_XIRR_X , h_xirr_x); -spapr_register_hypercall (H_EOI , h_eoi); -spapr_register_hypercall (H_IPOLL , h_ipoll); - -object_property_set_bool (OBJECT (icp->ics), true,"realized" , &error); -if (error) { -error_propagate (errp, error); -return ; - } - -for (i =0 ; i < icp->nr_servers; i++) { -object_property_set_bool (OBJECT (&icp->ss[i]), true,"realized" , &error); -if (error) { -error_propagate (errp, error); -return ; - } - } -} - -static void xics_spapr_initfn (Object *obj) -{ -XICSState *xics =XICS (obj); - - xics->ics =ICS (object_new (TYPE_ICS )); -object_property_add_child (obj,"ics" ,OBJECT (xics->ics),NULL ); - xics->ics->icp = xics; -} - -static void xics_spapr_class_init (ObjectClass *oc,void *data) -{ -DeviceClass *dc =DEVICE_CLASS (oc); -XICSStateClass *xsc =XICS_SPAPR_CLASS (oc); - - dc->realize = xics_spapr_realize; - xsc->set_nr_irqs = xics_set_nr_irqs; - xsc->set_nr_servers = xics_set_nr_servers; -} - -static const TypeInfo xics_spapr_info = { - .name =TYPE_XICS_SPAPR , - .parent =TYPE_XICS_COMMON , - .instance_size =sizeof (XICSState), - .class_size =sizeof (XICSStateClass), - .class_init = xics_spapr_class_init, - .instance_init = xics_spapr_initfn, -}; -static void xics_register_types (void ) {type_register_static (&xics_common_info); -type_register_static (&xics_spapr_info);type_register_static (&ics_info);type_register_static (&icp_info); }hw/intc/xics_spapr.c new file +401
-0@@ -0,0 +1,401 @@ +/* +* QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator +* +* PAPR Virtualized Interrupt System, aka ICS/ICP aka xics +* +* Copyright (c) 2010,2011 David Gibson, IBM Corporation. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +* +*/ + +#include "hw/hw.h" +#include "trace.h" +#include "qemu/timer.h" +#include "hw/ppc/spapr.h" +#include "hw/ppc/xics.h" +#include "qemu/error-report.h" +#include "qapi/visitor.h" + +/* +* Guest interfaces +*/ + +static target_ulong h_cppr (PowerPCCPU *cpu,sPAPRMachineState *spapr, +target_ulong opcode,target_ulong *args) +{ +CPUState *cs =CPU (cpu); +target_ulong cppr = args[0 ]; + +icp_set_cppr (spapr->icp, cs->cpu_index, cppr); +return H_SUCCESS ; +} + +static target_ulong h_ipi (PowerPCCPU *cpu,sPAPRMachineState *spapr, +target_ulong opcode,target_ulong *args) +{ +target_ulong server =get_cpu_index_by_dt_id (args[0 ]); +target_ulong mfrr = args[1 ]; + +if (server >= spapr->icp->nr_servers) { +return H_PARAMETER ; + } + +icp_set_mfrr (spapr->icp, server, mfrr); +return H_SUCCESS ; +} + +static target_ulong h_xirr (PowerPCCPU *cpu,sPAPRMachineState *spapr, +target_ulong opcode,target_ulong *args) +{ +CPUState *cs =CPU (cpu); +uint32_t xirr =icp_accept (spapr->icp->ss + cs->cpu_index); + + args[0 ] = xirr; +return H_SUCCESS ; +} + +static target_ulong h_xirr_x (PowerPCCPU *cpu,sPAPRMachineState *spapr, +target_ulong opcode,target_ulong *args) +{ +CPUState *cs =CPU (cpu); +ICPState *ss = &spapr->icp->ss[cs->cpu_index]; +uint32_t xirr =icp_accept (ss); + + args[0 ] = xirr; + args[1 ] =cpu_get_host_ticks (); +return H_SUCCESS ; +} + +static target_ulong h_eoi (PowerPCCPU *cpu,sPAPRMachineState *spapr, +target_ulong opcode,target_ulong *args) +{ +CPUState *cs =CPU (cpu); +target_ulong xirr = args[0 ]; + +icp_eoi (spapr->icp, cs->cpu_index, xirr); +return H_SUCCESS ; +} + +static target_ulong h_ipoll (PowerPCCPU *cpu,sPAPRMachineState *spapr, +target_ulong opcode,target_ulong *args) +{ +CPUState *cs =CPU (cpu); +ICPState *ss = &spapr->icp->ss[cs->cpu_index]; + + args[0 ] = ss->xirr; + args[1 ] = ss->mfrr; + +return H_SUCCESS ; +} + +static void rtas_set_xive (PowerPCCPU *cpu,sPAPRMachineState *spapr, +uint32_t token, +uint32_t nargs,target_ulong args, +uint32_t nret,target_ulong rets) +{ +ICSState *ics = spapr->icp->ics; +uint32_t nr, server, priority; + +if ((nargs !=3 ) || (nret !=1 )) { +rtas_st (rets,0 ,RTAS_OUT_PARAM_ERROR ); +return ; + } + + nr =rtas_ld (args,0 ); + server =get_cpu_index_by_dt_id (rtas_ld (args,1 )); + priority =rtas_ld (args,2 ); + +if (!ics_valid_irq (ics, nr) || (server >= ics->icp->nr_servers) + || (priority >0xff )) { +rtas_st (rets,0 ,RTAS_OUT_PARAM_ERROR ); +return ; + } + +ics_write_xive (ics, nr, server, priority, priority); + +rtas_st (rets,0 ,RTAS_OUT_SUCCESS ); +} + +static void rtas_get_xive (PowerPCCPU *cpu,sPAPRMachineState *spapr, +uint32_t token, +uint32_t nargs,target_ulong args, +uint32_t nret,target_ulong rets) +{ +ICSState *ics = spapr->icp->ics; +uint32_t nr; + +if ((nargs !=1 ) || (nret !=3 )) { +rtas_st (rets,0 ,RTAS_OUT_PARAM_ERROR ); +return ; + } + + nr =rtas_ld (args,0 ); + +if (!ics_valid_irq (ics, nr)) { +rtas_st (rets,0 ,RTAS_OUT_PARAM_ERROR ); +return ; + } + +rtas_st (rets,0 ,RTAS_OUT_SUCCESS ); +rtas_st (rets,1 , ics->irqs[nr - ics->offset].server); +rtas_st (rets,2 , ics->irqs[nr - ics->offset].priority); +} + +static void rtas_int_off (PowerPCCPU *cpu,sPAPRMachineState *spapr, +uint32_t token, +uint32_t nargs,target_ulong args, +uint32_t nret,target_ulong rets) +{ +ICSState *ics = spapr->icp->ics; +uint32_t nr; + +if ((nargs !=1 ) || (nret !=1 )) { +rtas_st (rets,0 ,RTAS_OUT_PARAM_ERROR ); +return ; + } + + nr =rtas_ld (args,0 ); + +if (!ics_valid_irq (ics, nr)) { +rtas_st (rets,0 ,RTAS_OUT_PARAM_ERROR ); +return ; + } + +ics_write_xive (ics, nr, ics->irqs[nr - ics->offset].server,0xff , + ics->irqs[nr - ics->offset].priority); + +rtas_st (rets,0 ,RTAS_OUT_SUCCESS ); +} + +static void rtas_int_on (PowerPCCPU *cpu,sPAPRMachineState *spapr, +uint32_t token, +uint32_t nargs,target_ulong args, +uint32_t nret,target_ulong rets) +{ +ICSState *ics = spapr->icp->ics; +uint32_t nr; + +if ((nargs !=1 ) || (nret !=1 )) { +rtas_st (rets,0 ,RTAS_OUT_PARAM_ERROR ); +return ; + } + + nr =rtas_ld (args,0 ); + +if (!ics_valid_irq (ics, nr)) { +rtas_st (rets,0 ,RTAS_OUT_PARAM_ERROR ); +return ; + } + +ics_write_xive (ics, nr, ics->irqs[nr - ics->offset].server, + ics->irqs[nr - ics->offset].saved_priority, + ics->irqs[nr - ics->offset].saved_priority); + +rtas_st (rets,0 ,RTAS_OUT_SUCCESS ); +} + +static void xics_spapr_realize (DeviceState *dev,Error **errp) +{ +XICSState *icp =XICS (dev); +Error *error =NULL ; +int i; + +if (!icp->nr_servers) { +error_setg (errp,"Number of servers needs to be greater 0" ); +return ; + } + +/* Registration of global state belongs into realize */ +spapr_rtas_register (RTAS_IBM_SET_XIVE ,"ibm,set-xive" , rtas_set_xive); +spapr_rtas_register (RTAS_IBM_GET_XIVE ,"ibm,get-xive" , rtas_get_xive); +spapr_rtas_register (RTAS_IBM_INT_OFF ,"ibm,int-off" , rtas_int_off); +spapr_rtas_register (RTAS_IBM_INT_ON ,"ibm,int-on" , rtas_int_on); + +spapr_register_hypercall (H_CPPR , h_cppr); +spapr_register_hypercall (H_IPI , h_ipi); +spapr_register_hypercall (H_XIRR , h_xirr); +spapr_register_hypercall (H_XIRR_X , h_xirr_x); +spapr_register_hypercall (H_EOI , h_eoi); +spapr_register_hypercall (H_IPOLL , h_ipoll); + +object_property_set_bool (OBJECT (icp->ics), true,"realized" , &error); +if (error) { +error_propagate (errp, error); +return ; + } + +for (i =0 ; i < icp->nr_servers; i++) { +object_property_set_bool (OBJECT (&icp->ss[i]), true,"realized" , &error); +if (error) { +error_propagate (errp, error); +return ; + } + } +} + +static void xics_spapr_initfn (Object *obj) +{ +XICSState *xics =XICS (obj); + + xics->ics =ICS (object_new (TYPE_ICS )); +object_property_add_child (obj,"ics" ,OBJECT (xics->ics),NULL ); + xics->ics->icp = xics; +} + +static void xics_spapr_class_init (ObjectClass *oc,void *data) +{ +DeviceClass *dc =DEVICE_CLASS (oc); +XICSStateClass *xsc =XICS_SPAPR_CLASS (oc); + + dc->realize = xics_spapr_realize; + xsc->set_nr_irqs = xics_set_nr_irqs; + xsc->set_nr_servers = xics_set_nr_servers; +} + +static const TypeInfo xics_spapr_info = { + .name =TYPE_XICS_SPAPR , + .parent =TYPE_XICS_COMMON , + .instance_size =sizeof (XICSState), + .class_size =sizeof (XICSStateClass), + .class_init = xics_spapr_class_init, + .instance_init = xics_spapr_initfn, +}; + +#define ICS_IRQ_FREE (ics, srcno) \ + (!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK))) + +static int ics_find_free_block (ICSState *ics,int num,int alignnum) +{ +int first, i; + +for (first =0 ; first < ics->nr_irqs; first += alignnum) { +if (num > (ics->nr_irqs - first)) { +return -1 ; + } +for (i = first; i < first + num; ++i) { +if (!ICS_IRQ_FREE (ics, i)) { +break ; + } + } +if (i == (first + num)) { +return first; + } + } + +return -1 ; +} + +int xics_spapr_alloc (XICSState *icp,int src,int irq_hint,bool lsi) +{ +ICSState *ics = &icp->ics[src]; +int irq; + +if (irq_hint) { +assert (src ==xics_find_source (icp, irq_hint)); +if (!ICS_IRQ_FREE (ics, irq_hint - ics->offset)) { +trace_xics_alloc_failed_hint (src, irq_hint); +return -1 ; + } + irq = irq_hint; + }else { + irq =ics_find_free_block (ics,1 ,1 ); +if (irq <0 ) { +trace_xics_alloc_failed_no_left (src); +return -1 ; + } + irq += ics->offset; + } + +ics_set_irq_type (ics, irq - ics->offset, lsi); +trace_xics_alloc (src, irq); + +return irq; +} + +/* +* Allocate block of consecutive IRQs, and return the number of the first IRQ in the block. +* If align==true, aligns the first IRQ number to num. +*/ +int xics_spapr_alloc_block (XICSState *icp,int src,int num,bool lsi,bool align) +{ +int i, first =-1 ; +ICSState *ics = &icp->ics[src]; + +assert (src ==0 ); +/* +* MSIMesage::data is used for storing VIRQ so +* it has to be aligned to num to support multiple +* MSI vectors. MSI-X is not affected by this. +* The hint is used for the first IRQ, the rest should +* be allocated continuously. +*/ +if (align) { +assert ((num ==1 ) || (num ==2 ) || (num ==4 ) || + (num ==8 ) || (num ==16 ) || (num ==32 )); + first =ics_find_free_block (ics, num, num); + }else { + first =ics_find_free_block (ics, num,1 ); + } + +if (first >=0 ) { +for (i = first; i < first + num; ++i) { +ics_set_irq_type (ics, i, lsi); + } + } + first += ics->offset; + +trace_xics_alloc_block (src, first, num, lsi, align); + +return first; +} + +static void ics_free (ICSState *ics,int srcno,int num) +{ +int i; + +for (i = srcno; i < srcno + num; ++i) { +if (ICS_IRQ_FREE (ics, i)) { +trace_xics_ics_free_warn (ics - ics->icp->ics, i + ics->offset); + } +memset (&ics->irqs[i],0 ,sizeof (ICSIRQState)); + } +} + +void xics_spapr_free (XICSState *icp,int irq,int num) +{ +int src =xics_find_source (icp, irq); + +if (src >=0 ) { +ICSState *ics = &icp->ics[src]; + +/* FIXME: implement multiple sources */ +assert (src ==0 ); + +trace_xics_ics_free (ics - icp->ics, irq, num); +ics_free (ics, irq - ics->offset, num); + } +} + +static void xics_spapr_register_types (void ) +{ +type_register_static (&xics_spapr_info); +} + +type_init (xics_spapr_register_types)include/hw/ppc/xics.h +23
-0@@ -141,6 +141,12 @@ struct ICSState {XICSState *icp; }; +static inline bool ics_valid_irq (ICSState *ics,uint32_t nr) +{ +return (nr >= ics->offset) + && (nr < (ics->offset + ics->nr_irqs)); +} +struct ICSIRQState {uint32_t server;uint8_t priority;@@ -168,4 +174,21 @@ void xics_spapr_free(XICSState *icp, int irq, int num);void xics_cpu_setup (XICSState *icp,PowerPCCPU *cpu); +/* Internal XICS interfaces */ +int get_cpu_index_by_dt_id (int cpu_dt_id); + +void icp_set_cppr (XICSState *icp,int server,uint8_t cppr); +void icp_set_mfrr (XICSState *icp,int server,uint8_t mfrr); +uint32_t icp_accept (ICPState *ss); +void icp_eoi (XICSState *icp,int server,uint32_t xirr); + +void ics_write_xive (ICSState *ics,int nr,int server, +uint8_t priority,uint8_t saved_priority); + +void ics_set_irq_type (ICSState *ics,int srcno,bool lsi); + +void xics_set_nr_irqs (XICSState *icp,uint32_t nr_irqs,Error **errp); +void xics_set_nr_servers (XICSState *icp,uint32_t nr_servers,Error **errp); +int xics_find_source (XICSState *icp,int irq); +#endif /* __XICS_H__ */
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 30/77 ppc/xics: Implement H_IPOLL using an accessor
In reply to Benjamin HerrenschmidtNone of the other presenter functions directly mucks with the internal state, so don't do it there either.
--- hw/intc/xics.c | 8 ++++++++ hw/intc/xics_spapr.c | 7 ++++--- include/hw/ppc/xics.h | 1 + 3 files changed, 13 insertions(+), 3 deletions(-)
hw/intc/xics.c +8 -0
@@ -271,6 +271,14 @@ uint32_t icp_accept(ICPState *ss)return xirr; } +uint32_t icp_ipoll (ICPState *ss,uint32_t *mfrr) +{ +if (mfrr) { + *mfrr = ss->mfrr; + } +return ss->xirr; +} +void icp_eoi (XICSState *icp,int server,uint32_t xirr) {ICPState *ss = icp->ss + server;
hw/intc/xics_spapr.c +4 -3
@@ -97,10 +97,11 @@ static target_ulong h_ipoll(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong opcode, target_ulong *args) { CPUState *cs = CPU(cpu); -ICPState *ss = &spapr->icp->ss[cs->cpu_index]; +uint32_t mfrr; +uint32_t xirr =icp_ipoll (spapr->icp->ss + cs->cpu_index, &mfrr); - args[0 ] = ss->xirr; - args[1 ] = ss->mfrr; + args[0 ] = xirr; + args[1 ] = mfrr;return H_SUCCESS ; }
include/hw/ppc/xics.h +1 -0
@@ -180,6 +180,7 @@ int get_cpu_index_by_dt_id(int cpu_dt_id);void icp_set_cppr (XICSState *icp,int server,uint8_t cppr);void icp_set_mfrr (XICSState *icp,int server,uint8_t mfrr);uint32_t icp_accept (ICPState *ss); +uint32_t icp_ipoll (ICPState *ss,uint32_t *mfrr);void icp_eoi (XICSState *icp,int server,uint32_t xirr); void ics_write_xive(ICSState *ics, int nr, int server,
Signature · 1 line
2.5.0
PATCH 31/77 ppc/xics: Remove unused xics_set_irq_type()
In reply to Benjamin Herrenschmidt--- hw/intc/xics.c | 11 ----------- include/hw/ppc/xics.h | 1 - 2 files changed, 12 deletions(-)
hw/intc/xics.c +0 -11
@@ -678,17 +678,6 @@ void ics_set_irq_type(ICSState *ics, int srcno, bool lsi) lsi ?XICS_FLAGS_IRQ_LSI :XICS_FLAGS_IRQ_MSI ; } -void xics_set_irq_type (XICSState *icp,int irq,bool lsi) -{ -int src =xics_find_source (icp, irq); -ICSState *ics; - -assert (src >=0 ); - - ics = &icp->ics[src]; -ics_set_irq_type (ics, irq - ics->offset, lsi); -} -/* * XICS */
include/hw/ppc/xics.h +0 -1
@@ -166,7 +166,6 @@ struct ICSIRQState {#define XICS_IRQS_SPAPR 1024qemu_irq xics_get_qirq (XICSState *icp,int irq); -void xics_set_irq_type (XICSState *icp,int irq,bool lsi);int xics_spapr_alloc (XICSState *icp,int src,int irq_hint,bool lsi);int xics_spapr_alloc_block (XICSState *icp,int src,int num,bool lsi,bool align);
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 31/77] ppc/xics: Remove unused xics_set_irq_type()
Quoted 1 line · Benjamin Herrenschmidt
Signed-off-by Benjamin Herrenschmidt <[email protected]>
In fact, this is a sufficiently good clean up that I think I'll merge it shortly, regardless of what happens with the rest of the pnv series.
Quoted 39 lines
--- hw/intc/xics.c | 11 ----------- include/hw/ppc/xics.h | 1 - 2 files changed, 12 deletions(-)hw/intc/xics.c +0
-11@@ -678,17 +678,6 @@ void ics_set_irq_type(ICSState *ics, int srcno, bool lsi) lsi ?XICS_FLAGS_IRQ_LSI :XICS_FLAGS_IRQ_MSI ; } -void xics_set_irq_type (XICSState *icp,int irq,bool lsi) -{ -int src =xics_find_source (icp, irq); -ICSState *ics; - -assert (src >=0 ); - - ics = &icp->ics[src]; -ics_set_irq_type (ics, irq - ics->offset, lsi); -} -/* * XICS */ include/hw/ppc/xics.h +0
-1@@ -166,7 +166,6 @@ struct ICSIRQState {#define XICS_IRQS_SPAPR 1024qemu_irq xics_get_qirq (XICSState *icp,int irq); -void xics_set_irq_type (XICSState *icp,int irq,bool lsi);int xics_spapr_alloc (XICSState *icp,int src,int irq_hint,bool lsi);int xics_spapr_alloc_block (XICSState *icp,int src,int num,bool lsi,bool align);
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 32/77 ppc/xics: Replace "icp" with "xics" in most places
In reply to Benjamin HerrenschmidtThe "ICP" is a different object than the "XICS". For historical reasons, we have a number of places where we name a variable "icp" while it contains a XICSState pointer. There *is* an ICPState structure too so this makes the code really confusing.
This is a mechanical replacement of all those instances to use the name "xics" instead. There should be no functional change.
--- hw/intc/xics.c | 132 ++++++++++++++++++++++---------------------- hw/intc/xics_kvm.c | 54 +++++++++--------- hw/intc/xics_spapr.c | 56 +++++++++---------- hw/ppc/spapr.c | 22 ++++---- hw/ppc/spapr_events.c | 8 +-- hw/ppc/spapr_pci.c | 8 +-- hw/ppc/spapr_vio.c | 2 +- include/hw/pci-host/spapr.h | 2 +- include/hw/ppc/spapr.h | 2 +- include/hw/ppc/spapr_vio.h | 2 +- include/hw/ppc/xics.h | 2 +- 11 files changed, 145 insertions(+), 145 deletions(-)
hw/intc/xics.c +66 -66
@@ -44,17 +44,17 @@ int get_cpu_index_by_dt_id(int cpu_dt_id)return -1 ; } -void xics_cpu_setup (XICSState *icp,PowerPCCPU *cpu) +void xics_cpu_setup (XICSState *xics,PowerPCCPU *cpu) {CPUState *cs =CPU (cpu);CPUPPCState *env = &cpu->env; -ICPState *ss = &icp->ss[cs->cpu_index]; -XICSStateClass *info =XICS_COMMON_GET_CLASS (icp); +ICPState *ss = &xics->ss[cs->cpu_index]; +XICSStateClass *info =XICS_COMMON_GET_CLASS (xics); -assert (cs->cpu_index < icp->nr_servers); +assert (cs->cpu_index < xics->nr_servers);if (info->cpu_setup) { - info->cpu_setup (icp, cpu); + info->cpu_setup (xics, cpu); }switch (PPC_INPUT (env)) {
@@ -78,21 +78,21 @@ void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu)*/ static void xics_common_reset (DeviceState *d) { -XICSState *icp =XICS_COMMON (d); +XICSState *xics =XICS_COMMON (d);int i; -for (i =0 ; i < icp->nr_servers; i++) { -device_reset (DEVICE (&icp->ss[i])); +for (i =0 ; i < xics->nr_servers; i++) { +device_reset (DEVICE (&xics->ss[i])); } -device_reset (DEVICE (icp->ics)); +device_reset (DEVICE (xics->ics)); }static void xics_prop_get_nr_irqs (Object *obj,Visitor *v,void *opaque,const char *name,Error **errp) { -XICSState *icp =XICS_COMMON (obj); -int64_t value = icp->nr_irqs; +XICSState *xics =XICS_COMMON (obj); +int64_t value = xics->nr_irqs;visit_type_int (v, &value, name, errp); }
@@ -100,8 +100,8 @@ static void xics_prop_get_nr_irqs(Object *obj, Visitor *v,static void xics_prop_set_nr_irqs (Object *obj,Visitor *v,void *opaque,const char *name,Error **errp) { -XICSState *icp =XICS_COMMON (obj); -XICSStateClass *info =XICS_COMMON_GET_CLASS (icp); +XICSState *xics =XICS_COMMON (obj); +XICSStateClass *info =XICS_COMMON_GET_CLASS (xics);Error *error =NULL ;int64_t value;
@@ -110,23 +110,23 @@ static void xics_prop_set_nr_irqs(Object *obj, Visitor *v,error_propagate (errp, error);return ; } -if (icp->nr_irqs) { +if (xics->nr_irqs) {error_setg (errp,"Number of interrupts is already set to %u" , - icp->nr_irqs); + xics->nr_irqs);return ; }assert (info->set_nr_irqs); -assert (icp->ics); - info->set_nr_irqs (icp, value, errp); +assert (xics->ics); + info->set_nr_irqs (xics, value, errp); }static void xics_prop_get_nr_servers (Object *obj,Visitor *v,void *opaque,const char *name,Error **errp) { -XICSState *icp =XICS_COMMON (obj); -int64_t value = icp->nr_servers; +XICSState *xics =XICS_COMMON (obj); +int64_t value = xics->nr_servers;visit_type_int (v, &value, name, errp); }
@@ -135,8 +135,8 @@ static void xics_prop_set_nr_servers(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { - XICSState *icp = XICS_COMMON(obj); -XICSStateClass *info =XICS_COMMON_GET_CLASS (icp); + XICSState *xics = XICS_COMMON(obj); +XICSStateClass *info =XICS_COMMON_GET_CLASS (xics);Error *error =NULL ;int64_t value;
@@ -145,14 +145,14 @@ static void xics_prop_set_nr_servers(Object *obj, Visitor *v,error_propagate (errp, error);return ; } -if (icp->nr_servers) { +if (xics->nr_servers) {error_setg (errp,"Number of servers is already set to %u" , - icp->nr_servers); + xics->nr_servers);return ; }assert (info->set_nr_servers); - info->set_nr_servers (icp, value, errp); + info->set_nr_servers (xics, value, errp); }static void xics_common_initfn (Object *obj)
@@ -195,9 +195,9 @@ static void ics_reject(ICSState *ics, int nr);static void ics_resend (ICSState *ics);static void ics_eoi (ICSState *ics,int nr); -static void icp_check_ipi (XICSState *icp,int server) +static void icp_check_ipi (XICSState *xics,int server) { -ICPState *ss = icp->ss + server; +ICPState *ss = xics->ss + server;if (XISR (ss) && (ss->pending_priority <= ss->mfrr)) {return ;
@@ -206,7 +206,7 @@ static void icp_check_ipi(XICSState *icp, int server)trace_xics_icp_check_ipi (server, ss->mfrr);if (XISR (ss)) { -ics_reject (icp->ics,XISR (ss)); +ics_reject (xics->ics,XISR (ss)); } ss->xirr = (ss->xirr & ~XISR_MASK ) |XICS_IPI ;
@@ -214,19 +214,19 @@ static void icp_check_ipi(XICSState *icp, int server)qemu_irq_raise (ss->output); } -static void icp_resend (XICSState *icp,int server) +static void icp_resend (XICSState *xics,int server) { -ICPState *ss = icp->ss + server; +ICPState *ss = xics->ss + server;if (ss->mfrr <CPPR (ss)) { -icp_check_ipi (icp, server); +icp_check_ipi (xics, server); } -ics_resend (icp->ics); +ics_resend (xics->ics); } -void icp_set_cppr (XICSState *icp,int server,uint8_t cppr) +void icp_set_cppr (XICSState *xics,int server,uint8_t cppr) { -ICPState *ss = icp->ss + server; +ICPState *ss = xics->ss + server;uint8_t old_cppr;uint32_t old_xisr;
@@ -239,22 +239,22 @@ void icp_set_cppr(XICSState *icp, int server, uint8_t cppr) ss->xirr &= ~XISR_MASK ;/* Clear XISR */ ss->pending_priority =0xff ;qemu_irq_lower (ss->output); -ics_reject (icp->ics, old_xisr); +ics_reject (xics->ics, old_xisr); } }else {if (!XISR (ss)) { -icp_resend (icp, server); +icp_resend (xics, server); } } } -void icp_set_mfrr (XICSState *icp,int server,uint8_t mfrr) +void icp_set_mfrr (XICSState *xics,int server,uint8_t mfrr) { -ICPState *ss = icp->ss + server; +ICPState *ss = xics->ss + server; ss->mfrr = mfrr;if (mfrr <CPPR (ss)) { -icp_check_ipi (icp, server); +icp_check_ipi (xics, server); } }
@@ -279,31 +279,31 @@ uint32_t icp_ipoll(ICPState *ss, uint32_t *mfrr)return ss->xirr; } -void icp_eoi (XICSState *icp,int server,uint32_t xirr) +void icp_eoi (XICSState *xics,int server,uint32_t xirr) { -ICPState *ss = icp->ss + server; +ICPState *ss = xics->ss + server;/* Send EOI -> ICS */ ss->xirr = (ss->xirr & ~CPPR_MASK ) | (xirr &CPPR_MASK );trace_xics_icp_eoi (server, xirr, ss->xirr); -ics_eoi (icp->ics, xirr &XISR_MASK ); +ics_eoi (xics->ics, xirr &XISR_MASK );if (!XISR (ss)) { -icp_resend (icp, server); +icp_resend (xics, server); } } -static void icp_irq (XICSState *icp,int server,int nr,uint8_t priority) +static void icp_irq (XICSState *xics,int server,int nr,uint8_t priority) { -ICPState *ss = icp->ss + server; +ICPState *ss = xics->ss + server;trace_xics_icp_irq (server, nr, priority);if ((priority >=CPPR (ss)) || (XISR (ss) && (ss->pending_priority <= priority))) { -ics_reject (icp->ics, nr); +ics_reject (xics->ics, nr); }else {if (XISR (ss)) { -ics_reject (icp->ics,XISR (ss)); +ics_reject (xics->ics,XISR (ss)); } ss->xirr = (ss->xirr & ~XISR_MASK ) | (nr &XISR_MASK ); ss->pending_priority = priority;
@@ -388,7 +388,7 @@ static void resend_msi(ICSState *ics, int srcno)if (irq->status &XICS_STATUS_REJECTED ) { irq->status &= ~XICS_STATUS_REJECTED ;if (irq->priority !=0xff ) { -icp_irq (ics->icp, irq->server, srcno + ics->offset, +icp_irq (ics->xics, irq->server, srcno + ics->offset, irq->priority); } }
@@ -402,7 +402,7 @@ static void resend_lsi(ICSState *ics, int srcno) && (irq->status & XICS_STATUS_ASSERTED) && !(irq->status & XICS_STATUS_SENT)) { irq->status |=XICS_STATUS_SENT ; -icp_irq (ics->icp, irq->server, srcno + ics->offset, irq->priority); +icp_irq (ics->xics, irq->server, srcno + ics->offset, irq->priority); } }
@@ -417,7 +417,7 @@ static void set_irq_msi(ICSState *ics, int srcno, int val) irq->status |=XICS_STATUS_MASKED_PENDING ;trace_xics_masked_pending (); }else { -icp_irq (ics->icp, irq->server, srcno + ics->offset, irq->priority); +icp_irq (ics->xics, irq->server, srcno + ics->offset, irq->priority); } } }
@@ -456,7 +456,7 @@ static void write_xive_msi(ICSState *ics, int srcno) } irq->status &= ~XICS_STATUS_MASKED_PENDING ; -icp_irq (ics->icp, irq->server, srcno + ics->offset, irq->priority); +icp_irq (ics->xics, irq->server, srcno + ics->offset, irq->priority); }static void write_xive_lsi (ICSState *ics,int srcno)
@@ -465,7 +465,7 @@ static void write_xive_lsi(ICSState *ics, int srcno) }void ics_write_xive (ICSState *ics,int nr,int server, -uint8_t priority,uint8_t saved_priority) +uint8_t priority,uint8_t saved_priority) {int srcno = nr - ics->offset;ICSIRQState *irq = ics->irqs + srcno;
@@ -541,8 +541,8 @@ static int ics_post_load(ICSState *ics, int version_id) {int i; -for (i =0 ; i < ics->icp->nr_servers; i++) { -icp_resend (ics->icp, i); +for (i =0 ; i < ics->xics->nr_servers; i++) { +icp_resend (ics->xics, i); }return 0 ;
@@ -642,14 +642,14 @@ static const TypeInfo ics_info = {/* * Exported functions */ -int xics_find_source (XICSState *icp,int irq) +int xics_find_source (XICSState *xics,int irq) {int sources =1 ;int src;/* FIXME: implement multiple sources */ for (src =0 ; src < sources; ++src) { -ICSState *ics = &icp->ics[src]; +ICSState *ics = &xics->ics[src];if (ics_valid_irq (ics, irq)) {return src; }
@@ -658,12 +658,12 @@ int xics_find_source(XICSState *icp, int irq)return -1 ; } -qemu_irq xics_get_qirq (XICSState *icp,int irq) +qemu_irq xics_get_qirq (XICSState *xics,int irq) { -int src =xics_find_source (icp, irq); +int src =xics_find_source (xics, irq);if (src >=0 ) { -ICSState *ics = &icp->ics[src]; +ICSState *ics = &xics->ics[src];return ics->qirqs[irq - ics->offset]; }
@@ -682,23 +682,23 @@ void ics_set_irq_type(ICSState *ics, int srcno, bool lsi)* XICS */ -void xics_set_nr_irqs (XICSState *icp,uint32_t nr_irqs,Error **errp) +void xics_set_nr_irqs (XICSState *xics,uint32_t nr_irqs,Error **errp) { - icp->nr_irqs = icp->ics->nr_irqs = nr_irqs; + xics->nr_irqs = xics->ics->nr_irqs = nr_irqs; } -void xics_set_nr_servers (XICSState *icp,uint32_t nr_servers,Error **errp) +void xics_set_nr_servers (XICSState *xics,uint32_t nr_servers,Error **errp) {int i; - icp->nr_servers = nr_servers; + xics->nr_servers = nr_servers; - icp->ss =g_malloc0 (icp->nr_servers*sizeof (ICPState)); -for (i =0 ; i < icp->nr_servers; i++) { + xics->ss =g_malloc0 (xics->nr_servers*sizeof (ICPState)); +for (i =0 ; i < xics->nr_servers; i++) {char buffer[32 ]; -object_initialize (&icp->ss[i],sizeof (icp->ss[i]),TYPE_ICP ); +object_initialize (&xics->ss[i],sizeof (xics->ss[i]),TYPE_ICP );snprintf (buffer,sizeof (buffer),"icp[%d]" , i); -object_property_add_child (OBJECT (icp), buffer,OBJECT (&icp->ss[i]), +object_property_add_child (OBJECT (xics), buffer,OBJECT (&xics->ss[i]), errp); } }
hw/intc/xics_kvm.c +27 -27
141 lines not on this page · raw message
hw/intc/xics_spapr.c +28 -28
187 lines not on this page · raw message
hw/ppc/spapr.c +11 -11
@@ -113,25 +113,25 @@ static XICSState *try_create_xics(const char *type, int nr_servers,static XICSState *xics_system_init (MachineState *machine,int nr_servers,int nr_irqs) { -XICSState *icp =NULL ; +XICSState *xics =NULL ;if (kvm_enabled ()) {Error *err =NULL ;if (machine_kernel_irqchip_allowed (machine)) { - icp =try_create_xics (TYPE_XICS_SPAPR_KVM , nr_servers, nr_irqs, &err); + xics =try_create_xics (TYPE_XICS_SPAPR_KVM , nr_servers, nr_irqs, &err); } -if (machine_kernel_irqchip_required (machine) && !icp) { +if (machine_kernel_irqchip_required (machine) && !xics) {error_report ("kernel_irqchip requested but unavailable: %s" ,error_get_pretty (err)); } } -if (!icp) { - icp =try_create_xics (TYPE_XICS_SPAPR , nr_servers, nr_irqs, &error_abort); +if (!xics) { + xics =try_create_xics (TYPE_XICS_SPAPR , nr_servers, nr_irqs, &error_abort); } -return icp; +return xics; } static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
@@ -1615,7 +1615,7 @@ static void spapr_cpu_init(sPAPRMachineState *spapr, PowerPCCPU *cpu) } } -xics_cpu_setup (spapr->icp, cpu); +xics_cpu_setup (spapr->xics, cpu);qemu_register_reset (spapr_cpu_reset, cpu); }
@@ -1765,10 +1765,10 @@ static void ppc_spapr_init(MachineState *machine)spapr_alloc_htab (spapr);/* Set up Interrupt Controller before we create the VCPUs */ - spapr->icp =xics_system_init (machine, -DIV_ROUND_UP (max_cpus *kvmppc_smt_threads (), - smp_threads), -XICS_IRQS_SPAPR ); + spapr->xics =xics_system_init (machine, +DIV_ROUND_UP (max_cpus *kvmppc_smt_threads (), + smp_threads), +XICS_IRQS_SPAPR );if (smc->dr_lmb_enabled) {spapr_validate_node_memory (machine);
hw/ppc/spapr_events.c +4 -4
@@ -383,7 +383,7 @@ static void spapr_powerdown_req(Notifier *n, void *opaque)rtas_event_log_queue (RTAS_LOG_TYPE_EPOW , new_epow, true); -qemu_irq_pulse (xics_get_qirq (spapr->icp, spapr->check_exception_irq)); +qemu_irq_pulse (xics_get_qirq (spapr->xics, spapr->check_exception_irq)); } static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action,
@@ -452,7 +452,7 @@ static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action,rtas_event_log_queue (RTAS_LOG_TYPE_HOTPLUG , new_hp, true); -qemu_irq_pulse (xics_get_qirq (spapr->icp, spapr->check_exception_irq)); +qemu_irq_pulse (xics_get_qirq (spapr->xics, spapr->check_exception_irq)); }void spapr_hotplug_req_add_by_index (sPAPRDRConnector *drc)
@@ -535,7 +535,7 @@ static void check_exception(PowerPCCPU *cpu, sPAPRMachineState *spapr,* interrupts. */ if (rtas_event_log_contains (mask, true)) { -qemu_irq_pulse (xics_get_qirq (spapr->icp, spapr->check_exception_irq)); +qemu_irq_pulse (xics_get_qirq (spapr->xics, spapr->check_exception_irq)); }return ;
@@ -587,7 +587,7 @@ out_no_events:void spapr_events_init (sPAPRMachineState *spapr) {QTAILQ_INIT (&spapr->pending_events); - spapr->check_exception_irq =xics_spapr_alloc (spapr->icp,0 ,0 , false); + spapr->check_exception_irq =xics_spapr_alloc (spapr->xics,0 ,0 , false); spapr->epow_notifier.notify = spapr_powerdown_req;qemu_register_powerdown_notifier (&spapr->epow_notifier); spapr_rtas_register(RTAS_CHECK_EXCEPTION, "check-exception",
hw/ppc/spapr_pci.c +4 -4
@@ -313,7 +313,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,return ; } -xics_spapr_free (spapr->icp, msi->first_irq, msi->num); +xics_spapr_free (spapr->xics, msi->first_irq, msi->num);if (msi_present (pdev)) {spapr_msi_setmsg (pdev,0 , false,0 , num); }
@@ -351,7 +351,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr, }/* Allocate MSIs */ - irq =xics_spapr_alloc_block (spapr->icp,0 , req_num, false, + irq =xics_spapr_alloc_block (spapr->xics,0 , req_num, false, ret_intr_type ==RTAS_TYPE_MSI );if (!irq) {error_report ("Cannot allocate MSIs for device %x" , config_addr);
@@ -729,7 +729,7 @@ static void spapr_msi_write(void *opaque, hwaddr addr,trace_spapr_pci_msi_write (addr, data, irq); -qemu_irq_pulse (xics_get_qirq (spapr->icp, irq)); +qemu_irq_pulse (xics_get_qirq (spapr->xics, irq)); }static const MemoryRegionOps spapr_msi_ops = {
@@ -1360,7 +1360,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)for (i =0 ; i <PCI_NUM_PINS ; i++) {uint32_t irq; - irq =xics_spapr_alloc_block (spapr->icp,0 ,1 , true, false); + irq =xics_spapr_alloc_block (spapr->xics,0 ,1 , true, false);if (!irq) {error_setg (errp,"spapr_allocate_lsi failed" );return ;
hw/ppc/spapr_vio.c +1 -1
@@ -462,7 +462,7 @@ static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp) dev->qdev.id = id; } - dev->irq =xics_spapr_alloc (spapr->icp,0 , dev->irq, false); + dev->irq =xics_spapr_alloc (spapr->xics,0 , dev->irq, false);if (!dev->irq) {error_setg (errp,"can't allocate IRQ" );return ;
include/hw/pci-host/spapr.h +1 -1
@@ -120,7 +120,7 @@ static inline qemu_irq spapr_phb_lsi_qirq(struct sPAPRPHBState *phb, int pin) {sPAPRMachineState *spapr =SPAPR_MACHINE (qdev_get_machine ()); -return xics_get_qirq (spapr->icp, phb->lsi_table[pin].irq); +return xics_get_qirq (spapr->xics, phb->lsi_table[pin].irq); }PCIHostState *spapr_create_phb (sPAPRMachineState *spapr,int index);
include/hw/ppc/spapr.h +1 -1
@@ -48,7 +48,7 @@ struct sPAPRMachineState {struct VIOsPAPRBus *vio_bus; QLIST_HEAD(, sPAPRPHBState) phbs;struct sPAPRNVRAM *nvram; -XICSState *icp; +XICSState *xics;DeviceState *rtc;void *htab;
include/hw/ppc/spapr_vio.h +1 -1
@@ -90,7 +90,7 @@ static inline qemu_irq spapr_vio_qirq(VIOsPAPRDevice *dev) {sPAPRMachineState *spapr =SPAPR_MACHINE (qdev_get_machine ()); -return xics_get_qirq (spapr->icp, dev->irq); +return xics_get_qirq (spapr->xics, dev->irq); } static inline bool spapr_vio_dma_valid(VIOsPAPRDevice *dev, uint64_t taddr,
include/hw/ppc/xics.h +1 -1
@@ -138,7 +138,7 @@ struct ICSState {uint32_t offset;qemu_irq *qirqs;ICSIRQState *irqs; -XICSState *icp; +XICSState *xics; };static inline bool ics_valid_irq (ICSState *ics,uint32_t nr)
Signature · 1 line
2.5.0
Re: [Qemu-devel] [Qemu-ppc] [PATCH 32/77] ppc/xics: Replace "icp" with "xics" in most places
Quoted 9 lines · Benjamin Herrenschmidt
The "ICP" is a different object than the "XICS". For historical reasons, we have a number of places where we name a variable "icp" while it contains a XICSState pointer. There *is* an ICPState structure too so this makes the code really confusing.
This is a mechanical replacement of all those instances to use the name "xics" instead. There should be no functional change.
Signed-off-by Benjamin Herrenschmidt <[email protected]>
Ah, good idea. I think I'll take this one independently as well.
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
PATCH 33/77 ppc/xics: Make the ICSState a list
In reply to Benjamin HerrenschmidtInstead of an array of fixed sized blocks, use a list, as we will need to have sources with variable number of interrupts. SPAPR only uses a single entry. Native will create more. If performance becomes an issue we can add some hashed lookup but for now this will do fine.
--- hw/intc/xics.c | 86 +++++++++++++++++++++++++++++++-------------------- hw/intc/xics_kvm.c | 28 +++++++++-------- hw/intc/xics_spapr.c | 75 ++++++++++++++++++++++++-------------------- hw/ppc/spapr_events.c | 2 +- hw/ppc/spapr_pci.c | 4 +-- hw/ppc/spapr_vio.c | 2 +- include/hw/ppc/xics.h | 10 +++--- 7 files changed, 118 insertions(+), 89 deletions(-)
hw/intc/xics.c +52 -34
@@ -79,13 +79,16 @@ void xics_cpu_setup(XICSState *xics, PowerPCCPU *cpu)static void xics_common_reset (DeviceState *d) {XICSState *xics =XICS_COMMON (d); +ICSState *ics;int i;for (i =0 ; i < xics->nr_servers; i++) {device_reset (DEVICE (&xics->ss[i])); } -device_reset (DEVICE (xics->ics)); + QLIST_FOREACH(ics, &xics->ics, list) { +device_reset (DEVICE (ics)); + } } static void xics_prop_get_nr_irqs(Object *obj, Visitor *v,
@@ -117,7 +120,6 @@ static void xics_prop_set_nr_irqs(Object *obj, Visitor *v, }assert (info->set_nr_irqs); -assert (xics->ics); info->set_nr_irqs (xics, value, errp); }
@@ -195,33 +197,35 @@ static void ics_reject(ICSState *ics, int nr);static void ics_resend (ICSState *ics);static void ics_eoi (ICSState *ics,int nr); -static void icp_check_ipi (XICSState *xics,int server) +static void icp_check_ipi (ICPState *ss,int server) { -ICPState *ss = xics->ss + server; -if (XISR (ss) && (ss->pending_priority <= ss->mfrr)) {return ; }trace_xics_icp_check_ipi (server, ss->mfrr); -if (XISR (ss)) { -ics_reject (xics->ics,XISR (ss)); +if (XISR (ss) && ss->xirr_owner) { +ics_reject (ss->xirr_owner,XISR (ss)); } ss->xirr = (ss->xirr & ~XISR_MASK ) |XICS_IPI ; ss->pending_priority = ss->mfrr; + ss->xirr_owner =NULL ;qemu_irq_raise (ss->output); }static void icp_resend (XICSState *xics,int server) {ICPState *ss = xics->ss + server; +ICSState *ics;if (ss->mfrr <CPPR (ss)) { -icp_check_ipi (xics, server); +icp_check_ipi (ss, server); + } + QLIST_FOREACH(ics, &xics->ics, list) { +ics_resend (ics); } -ics_resend (xics->ics); }void icp_set_cppr (XICSState *xics,int server,uint8_t cppr)
@@ -239,7 +243,10 @@ void icp_set_cppr(XICSState *xics, int server, uint8_t cppr) ss->xirr &= ~XISR_MASK ;/* Clear XISR */ ss->pending_priority =0xff ;qemu_irq_lower (ss->output); -ics_reject (xics->ics, old_xisr); +if (ss->xirr_owner) { +ics_reject (ss->xirr_owner, old_xisr); + ss->xirr_owner =NULL ; + } } }else {if (!XISR (ss)) {
@@ -254,7 +261,7 @@ void icp_set_mfrr(XICSState *xics, int server, uint8_t mfrr) ss->mfrr = mfrr;if (mfrr <CPPR (ss)) { -icp_check_ipi (xics, server); +icp_check_ipi (ss, server); } }
@@ -265,6 +272,7 @@ uint32_t icp_accept(ICPState *ss)qemu_irq_lower (ss->output); ss->xirr = ss->pending_priority <<24 ; ss->pending_priority =0xff ; + ss->xirr_owner =NULL ;trace_xics_icp_accept (xirr, ss->xirr);
@@ -282,30 +290,40 @@ uint32_t icp_ipoll(ICPState *ss, uint32_t *mfrr)void icp_eoi (XICSState *xics,int server,uint32_t xirr) {ICPState *ss = xics->ss + server; +ICSState *ics; +uint32_t irq;/* Send EOI -> ICS */ ss->xirr = (ss->xirr & ~CPPR_MASK ) | (xirr &CPPR_MASK );trace_xics_icp_eoi (server, xirr, ss->xirr); -ics_eoi (xics->ics, xirr &XISR_MASK ); + irq = xirr &XISR_MASK ; + QLIST_FOREACH(ics, &xics->ics, list) { +if (ics_valid_irq (ics, irq)) { +ics_eoi (ics, irq); + } + }if (!XISR (ss)) {icp_resend (xics, server); } } -static void icp_irq (XICSState *xics,int server,int nr,uint8_t priority) +static void icp_irq (ICSState *ics,int server,int nr,uint8_t priority) { +XICSState *xics = ics->xics;ICPState *ss = xics->ss + server;trace_xics_icp_irq (server, nr, priority);if ((priority >=CPPR (ss)) || (XISR (ss) && (ss->pending_priority <= priority))) { -ics_reject (xics->ics, nr); +ics_reject (ics, nr); }else { -if (XISR (ss)) { -ics_reject (xics->ics,XISR (ss)); +if (XISR (ss) && ss->xirr_owner) { +ics_reject (ss->xirr_owner,XISR (ss)); + ss->xirr_owner =NULL ; } ss->xirr = (ss->xirr & ~XISR_MASK ) | (nr &XISR_MASK ); + ss->xirr_owner = ics; ss->pending_priority = priority;trace_xics_icp_raise (ss->xirr, ss->pending_priority);qemu_irq_raise (ss->output);
@@ -388,8 +406,7 @@ static void resend_msi(ICSState *ics, int srcno)if (irq->status &XICS_STATUS_REJECTED ) { irq->status &= ~XICS_STATUS_REJECTED ;if (irq->priority !=0xff ) { -icp_irq (ics->xics, irq->server, srcno + ics->offset, - irq->priority); +icp_irq (ics, irq->server, srcno + ics->offset, irq->priority); } } }
@@ -402,7 +419,7 @@ static void resend_lsi(ICSState *ics, int srcno) && (irq->status & XICS_STATUS_ASSERTED) && !(irq->status & XICS_STATUS_SENT)) { irq->status |=XICS_STATUS_SENT ; -icp_irq (ics->xics, irq->server, srcno + ics->offset, irq->priority); +icp_irq (ics, irq->server, srcno + ics->offset, irq->priority); } }
@@ -417,7 +434,7 @@ static void set_irq_msi(ICSState *ics, int srcno, int val) irq->status |=XICS_STATUS_MASKED_PENDING ;trace_xics_masked_pending (); }else { -icp_irq (ics->xics, irq->server, srcno + ics->offset, irq->priority); +icp_irq (ics, irq->server, srcno + ics->offset, irq->priority); } } }
@@ -456,7 +473,7 @@ static void write_xive_msi(ICSState *ics, int srcno) } irq->status &= ~XICS_STATUS_MASKED_PENDING ; -icp_irq (ics->xics, irq->server, srcno + ics->offset, irq->priority); +icp_irq (ics, irq->server, srcno + ics->offset, irq->priority); }static void write_xive_lsi (ICSState *ics,int srcno)
@@ -642,28 +659,23 @@ static const TypeInfo ics_info = {/* * Exported functions */ -int xics_find_source (XICSState *xics,int irq) +ICSState *xics_find_source (XICSState *xics,int irq) { -int sources =1 ; -int src; +ICSState *ics; -/* FIXME: implement multiple sources */ -for (src =0 ; src < sources; ++src) { -ICSState *ics = &xics->ics[src]; + QLIST_FOREACH(ics, &xics->ics, list) {if (ics_valid_irq (ics, irq)) { -return src; +return ics; } } - -return -1 ; +return NULL ; }qemu_irq xics_get_qirq (XICSState *xics,int irq) { -int src =xics_find_source (xics, irq); +ICSState *ics =xics_find_source (xics, irq); -if (src >=0 ) { -ICSState *ics = &xics->ics[src]; +if (ics) {return ics->qirqs[irq - ics->offset]; }
@@ -684,7 +696,13 @@ void ics_set_irq_type(ICSState *ics, int srcno, bool lsi)void xics_set_nr_irqs (XICSState *xics,uint32_t nr_irqs,Error **errp) { - xics->nr_irqs = xics->ics->nr_irqs = nr_irqs; +ICSState *ics =QLIST_FIRST (&xics->ics); + +/* This needs to be deprecated ... */ + xics->nr_irqs = nr_irqs; +if (ics) { + ics->nr_irqs = nr_irqs; + } }void xics_set_nr_servers (XICSState *xics,uint32_t nr_servers,Error **errp)
hw/intc/xics_kvm.c +15 -13
@@ -356,11 +356,6 @@ static void xics_kvm_cpu_setup(XICSState *xics, PowerPCCPU *cpu) } } -static void xics_kvm_set_nr_irqs (XICSState *xics,uint32_t nr_irqs,Error **errp) -{ - xics->nr_irqs = xics->ics->nr_irqs = nr_irqs; -} -static void xics_kvm_set_nr_servers (XICSState *xics,uint32_t nr_servers,Error **errp) {
@@ -391,6 +386,7 @@ static void xics_kvm_realize(DeviceState *dev, Error **errp) {KVMXICSState *xicskvm =KVM_XICS (dev);XICSState *xics =XICS_COMMON (dev); +ICSState *ics;int i, rc;Error *error =NULL ;struct kvm_create_device xics_create_device = {
@@ -442,10 +438,12 @@ static void xics_kvm_realize(DeviceState *dev, Error **errp) xicskvm->kernel_xics_fd = xics_create_device.fd; -object_property_set_bool (OBJECT (xics->ics), true,"realized" , &error); -if (error) { -error_propagate (errp, error); - goto fail; + QLIST_FOREACH(ics, &xics->ics, list) { +object_property_set_bool (OBJECT (ics), true,"realized" , &error); +if (error) { +error_propagate (errp, error); + goto fail; + } }assert (xics->nr_servers);
@@ -473,10 +471,14 @@ fail:static void xics_kvm_initfn (Object *obj) {XICSState *xics =XICS_COMMON (obj); +ICSState *ics; + +QLIST_INIT (&xics->ics); - xics->ics =ICS (object_new (TYPE_KVM_ICS )); -object_property_add_child (obj,"ics" ,OBJECT (xics->ics),NULL ); - xics->ics->xics = xics; + ics =ICS (object_new (TYPE_KVM_ICS )); +object_property_add_child (obj,"ics" ,OBJECT (ics),NULL ); + ics->xics = xics; +QLIST_INSERT_HEAD (&xics->ics, ics, list); }static void xics_kvm_class_init (ObjectClass *oc,void *data)
@@ -486,7 +488,7 @@ static void xics_kvm_class_init(ObjectClass *oc, void *data) dc->realize = xics_kvm_realize; xsc->cpu_setup = xics_kvm_cpu_setup; - xsc->set_nr_irqs = xics_kvm_set_nr_irqs; + xsc->set_nr_irqs = xics_set_nr_irqs; xsc->set_nr_servers = xics_kvm_set_nr_servers; }
hw/intc/xics_spapr.c +41 -34
177 lines not on this page · raw message
hw/ppc/spapr_events.c +1 -1
@@ -587,7 +587,7 @@ out_no_events:void spapr_events_init (sPAPRMachineState *spapr) {QTAILQ_INIT (&spapr->pending_events); - spapr->check_exception_irq =xics_spapr_alloc (spapr->xics,0 ,0 , false); + spapr->check_exception_irq =xics_spapr_alloc (spapr->xics,0 , false); spapr->epow_notifier.notify = spapr_powerdown_req;qemu_register_powerdown_notifier (&spapr->epow_notifier); spapr_rtas_register(RTAS_CHECK_EXCEPTION, "check-exception",
hw/ppc/spapr_pci.c +2 -2
@@ -351,7 +351,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr, }/* Allocate MSIs */ - irq =xics_spapr_alloc_block (spapr->xics,0 , req_num, false, + irq =xics_spapr_alloc_block (spapr->xics, req_num, false, ret_intr_type ==RTAS_TYPE_MSI );if (!irq) {error_report ("Cannot allocate MSIs for device %x" , config_addr);
@@ -1360,7 +1360,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)for (i =0 ; i <PCI_NUM_PINS ; i++) {uint32_t irq; - irq =xics_spapr_alloc_block (spapr->xics,0 ,1 , true, false); + irq =xics_spapr_alloc_block (spapr->xics,1 , true, false);if (!irq) {error_setg (errp,"spapr_allocate_lsi failed" );return ;
hw/ppc/spapr_vio.c +1 -1
@@ -462,7 +462,7 @@ static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp) dev->qdev.id = id; } - dev->irq =xics_spapr_alloc (spapr->xics,0 , dev->irq, false); + dev->irq =xics_spapr_alloc (spapr->xics, dev->irq, false);if (!dev->irq) {error_setg (errp,"can't allocate IRQ" );return ;
include/hw/ppc/xics.h +6 -4
@@ -79,7 +79,7 @@ struct XICSState {uint32_t nr_servers;uint32_t nr_irqs;ICPState *ss; -ICSState *ics; + QLIST_HEAD(, ICSState) ics; };#define TYPE_ICP "icp"
@@ -105,6 +105,7 @@ struct ICPState {DeviceState parent_obj;/*< public >*/ CPUState *cs; +ICSState *xirr_owner;uint32_t xirr;uint8_t pending_priority;uint8_t mfrr;
@@ -139,6 +140,7 @@ struct ICSState {qemu_irq *qirqs;ICSIRQState *irqs;XICSState *xics; +QLIST_ENTRY (ICSState) list; };static inline bool ics_valid_irq (ICSState *ics,uint32_t nr)
@@ -167,8 +169,8 @@ struct ICSIRQState {qemu_irq xics_get_qirq (XICSState *icp,int irq); -int xics_spapr_alloc (XICSState *icp,int src,int irq_hint,bool lsi); -int xics_spapr_alloc_block (XICSState *icp,int src,int num,bool lsi,bool align); +int xics_spapr_alloc (XICSState *icp,int irq_hint,bool lsi); +int xics_spapr_alloc_block (XICSState *icp,int num,bool lsi,bool align);void xics_spapr_free (XICSState *icp,int irq,int num);void xics_cpu_setup (XICSState *icp,PowerPCCPU *cpu);
@@ -189,6 +191,6 @@ void ics_set_irq_type(ICSState *ics, int srcno, bool lsi);void xics_set_nr_irqs (XICSState *icp,uint32_t nr_irqs,Error **errp);void xics_set_nr_servers (XICSState *icp,uint32_t nr_servers,Error **errp); -int xics_find_source (XICSState *icp,int irq); +ICSState *xics_find_source (XICSState *icp,int irq);#endif /* __XICS_H__ */
Signature · 1 line
2.5.0