On Tue, Mar 17, 2020 at 03:49:18PM +1000, Nicholas Piggin wrote: > POWER9 adds scv and rfscv instructions and the system call vectored > interrupt. Linux does not support this instruction yet but it has > been tested with a modified kernel that runs on real hardware. > > Signed-off-by: Nicholas Piggin <npig...@gmail.com>
Applied to ppc-for-5.1. > --- > Since v2: > - Rebased on top of FWNMI series > > linux-user/ppc/cpu_loop.c | 1 + > target/ppc/cpu.h | 7 ++- > target/ppc/excp_helper.c | 98 ++++++++++++++++++++++++--------- > target/ppc/helper.h | 1 + > target/ppc/translate.c | 46 +++++++++++++++- > target/ppc/translate_init.inc.c | 3 +- > 6 files changed, 126 insertions(+), 30 deletions(-) > > diff --git a/linux-user/ppc/cpu_loop.c b/linux-user/ppc/cpu_loop.c > index 5b27f8603e..df71e15a25 100644 > --- a/linux-user/ppc/cpu_loop.c > +++ b/linux-user/ppc/cpu_loop.c > @@ -267,6 +267,7 @@ void cpu_loop(CPUPPCState *env) > queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); > break; > case POWERPC_EXCP_SYSCALL: /* System call exception > */ > + case POWERPC_EXCP_SYSCALL_VECTORED: > cpu_abort(cs, "Syscall exception while in user mode. " > "Aborting\n"); > break; > diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h > index ed8d2015bd..992f0a49e8 100644 > --- a/target/ppc/cpu.h > +++ b/target/ppc/cpu.h > @@ -127,8 +127,9 @@ enum { > POWERPC_EXCP_SDOOR_HV = 100, > /* ISA 3.00 additions */ > POWERPC_EXCP_HVIRT = 101, > + POWERPC_EXCP_SYSCALL_VECTORED = 102, /* scv exception > */ > /* EOL > */ > - POWERPC_EXCP_NB = 102, > + POWERPC_EXCP_NB = 103, > /* QEMU exceptions: used internally during code translation > */ > POWERPC_EXCP_STOP = 0x200, /* stop translation > */ > POWERPC_EXCP_BRANCH = 0x201, /* branch instruction > */ > @@ -475,6 +476,7 @@ typedef struct ppc_v3_pate_t { > /* Facility Status and Control (FSCR) bits */ > #define FSCR_EBB (63 - 56) /* Event-Based Branch Facility */ > #define FSCR_TAR (63 - 55) /* Target Address Register */ > +#define FSCR_SCV (63 - 51) /* System call vectored */ > /* Interrupt cause mask and position in FSCR. HFSCR has the same format */ > #define FSCR_IC_MASK (0xFFULL) > #define FSCR_IC_POS (63 - 7) > @@ -484,6 +486,7 @@ typedef struct ppc_v3_pate_t { > #define FSCR_IC_TM 5 > #define FSCR_IC_EBB 7 > #define FSCR_IC_TAR 8 > +#define FSCR_IC_SCV 12 > > /* Exception state register bits definition > */ > #define ESR_PIL PPC_BIT(36) /* Illegal Instruction */ > @@ -551,6 +554,8 @@ enum { > POWERPC_FLAG_VSX = 0x00080000, > /* Has Transaction Memory (ISA 2.07) > */ > POWERPC_FLAG_TM = 0x00100000, > + /* Has SCV (ISA 3.00) > */ > + POWERPC_FLAG_SCV = 0x00200000, > }; > > > /*****************************************************************************/ > diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c > index 81ee19ebae..73b5c28d03 100644 > --- a/target/ppc/excp_helper.c > +++ b/target/ppc/excp_helper.c > @@ -67,6 +67,18 @@ static inline void dump_syscall(CPUPPCState *env) > ppc_dump_gpr(env, 8), env->nip); > } > > +static inline void dump_syscall_vectored(CPUPPCState *env) > +{ > + qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 > + " r3=%016" PRIx64 " r4=%016" PRIx64 " r5=%016" PRIx64 > + " r6=%016" PRIx64 " r7=%016" PRIx64 " r8=%016" PRIx64 > + " nip=" TARGET_FMT_lx "\n", > + ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3), > + ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5), > + ppc_dump_gpr(env, 6), ppc_dump_gpr(env, 7), > + ppc_dump_gpr(env, 8), env->nip); > +} > + > static inline void dump_hcall(CPUPPCState *env) > { > qemu_log_mask(CPU_LOG_INT, "hypercall r3=%016" PRIx64 > @@ -185,7 +197,7 @@ 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, lev, ail; > + int srr0, srr1, asrr0, asrr1, lev = -1, ail; > bool lpes0; > > qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx > @@ -421,6 +433,13 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int > excp_model, int excp) > new_msr |= (target_ulong)MSR_HVB; > } > break; > + case POWERPC_EXCP_SYSCALL_VECTORED: /* scv exception > */ > + lev = env->error_code; > + dump_syscall_vectored(env); > + env->nip += 4; > + new_msr |= env->msr & ((target_ulong)1 << MSR_EE); > + new_msr |= env->msr & ((target_ulong)1 << MSR_RI); > + break; > case POWERPC_EXCP_FPU: /* Floating-point unavailable exception > */ > case POWERPC_EXCP_APU: /* Auxiliary processor unavailable > */ > case POWERPC_EXCP_DECR: /* Decrementer exception > */ > @@ -723,12 +742,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int > excp_model, int excp) > break; > } > > - /* Save PC */ > - env->spr[srr0] = env->nip; > - > - /* Save MSR */ > - env->spr[srr1] = msr; > - > /* Sanity check */ > if (!(env->msr_mask & MSR_HVB)) { > if (new_msr & MSR_HVB) { > @@ -741,14 +754,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int > excp_model, int excp) > } > } > > - /* If any alternate SRR register are defined, duplicate saved values */ > - if (asrr0 != -1) { > - env->spr[asrr0] = env->spr[srr0]; > - } > - if (asrr1 != -1) { > - env->spr[asrr1] = env->spr[srr1]; > - } > - > /* > * Sort out endianness of interrupt, this differs depending on the > * CPU, the HV mode, etc... > @@ -783,14 +788,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int > excp_model, int excp) > } > #endif > > - /* Jump to handler */ > - vector = env->excp_vectors[excp]; > - if (vector == (target_ulong)-1ULL) { > - cpu_abort(cs, "Raised an exception without defined vector %d\n", > - excp); > - } > - vector |= env->excp_prefix; > - > /* > * AIL only works if there is no HV transition and we are running > * with translations enabled > @@ -799,10 +796,21 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int > excp_model, int excp) > ((new_msr & MSR_HVB) && !(msr & MSR_HVB))) { > ail = 0; > } > - /* Handle AIL */ > - if (ail) { > - new_msr |= (1 << MSR_IR) | (1 << MSR_DR); > - vector |= ppc_excp_vector_offset(cs, ail); > + > + vector = env->excp_vectors[excp]; > + if (vector == (target_ulong)-1ULL) { > + cpu_abort(cs, "Raised an exception without defined vector %d\n", > + excp); > + } > + > + vector |= env->excp_prefix; > + > + /* If any alternate SRR register are defined, duplicate saved values */ > + if (asrr0 != -1) { > + env->spr[asrr0] = env->nip; > + } > + if (asrr1 != -1) { > + env->spr[asrr1] = msr; > } > > #if defined(TARGET_PPC64) > @@ -822,6 +830,37 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int > excp_model, int excp) > } > #endif > > + if (excp != POWERPC_EXCP_SYSCALL_VECTORED) { > + /* Save PC */ > + env->spr[srr0] = env->nip; > + > + /* Save MSR */ > + env->spr[srr1] = msr; > + > + /* Handle AIL */ > + if (ail) { > + new_msr |= (1 << MSR_IR) | (1 << MSR_DR); > + vector |= ppc_excp_vector_offset(cs, ail); > + } > + > +#if defined(TARGET_PPC64) > + } else { > + /* scv AIL is a little different */ > + if (ail) { > + new_msr |= (1 << MSR_IR) | (1 << MSR_DR); > + } > + if (ail == AIL_C000_0000_0000_4000) { > + vector |= 0xc000000000003000ull; > + } else { > + vector |= 0x0000000000017000ull; > + } > + vector += lev * 0x20; > + > + env->lr = env->nip; > + env->ctr = msr; > +#endif > + } > + > powerpc_set_excp_state(cpu, vector, new_msr); > } > > @@ -1162,6 +1201,11 @@ void helper_rfid(CPUPPCState *env) > do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1]); > } > > +void helper_rfscv(CPUPPCState *env) > +{ > + do_rfi(env, env->lr, env->ctr); > +} > + > void helper_hrfid(CPUPPCState *env) > { > do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1]); > diff --git a/target/ppc/helper.h b/target/ppc/helper.h > index cfb4c07085..ee1498050d 100644 > --- a/target/ppc/helper.h > +++ b/target/ppc/helper.h > @@ -15,6 +15,7 @@ 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(rfscv, void, env) > DEF_HELPER_1(hrfid, void, env) > DEF_HELPER_2(store_lpcr, void, env, tl) > DEF_HELPER_2(store_pcr, void, env, tl) > diff --git a/target/ppc/translate.c b/target/ppc/translate.c > index 127c82a24e..eb0ddba850 100644 > --- a/target/ppc/translate.c > +++ b/target/ppc/translate.c > @@ -173,6 +173,7 @@ struct DisasContext { > bool vsx_enabled; > bool spe_enabled; > bool tm_enabled; > + bool scv_enabled; > bool gtse; > ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */ > int singlestep_enabled; > @@ -4012,6 +4013,22 @@ static void gen_rfid(DisasContext *ctx) > #endif > } > > +static void gen_rfscv(DisasContext *ctx) > +{ > +#if defined(CONFIG_USER_ONLY) > + GEN_PRIV; > +#else > + /* Restore CPU state */ > + CHK_SV; > + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { > + gen_io_start(); > + } > + gen_update_cfar(ctx, ctx->base.pc_next - 4); > + gen_helper_rfscv(cpu_env); > + gen_sync_exception(ctx); > +#endif > +} > + > static void gen_hrfid(DisasContext *ctx) > { > #if defined(CONFIG_USER_ONLY) > @@ -4030,6 +4047,7 @@ static void gen_hrfid(DisasContext *ctx) > #define POWERPC_SYSCALL POWERPC_EXCP_SYSCALL_USER > #else > #define POWERPC_SYSCALL POWERPC_EXCP_SYSCALL > +#define POWERPC_SYSCALL_VECTORED POWERPC_EXCP_SYSCALL_VECTORED > #endif > static void gen_sc(DisasContext *ctx) > { > @@ -4039,6 +4057,21 @@ static void gen_sc(DisasContext *ctx) > gen_exception_err(ctx, POWERPC_SYSCALL, lev); > } > > +#if defined(TARGET_PPC64) > +static void gen_scv(DisasContext *ctx) > +{ > + uint32_t lev; > + > + if (unlikely(!ctx->scv_enabled)) { > + gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_SCV); > + return; > + } > + > + lev = (ctx->opcode >> 5) & 0x7F; > + gen_exception_err(ctx, POWERPC_SYSCALL_VECTORED, lev); > +} > +#endif > + > /*** Trap > ***/ > > /* Check for unconditional traps (always or never) */ > @@ -7019,6 +7052,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), > +/* Top bit of opc2 corresponds with low bit of LEV, so use two handlers */ > +GEN_HANDLER_E(scv, 0x11, 0x10, 0xFF, 0x03FFF01E, PPC_NONE, PPC2_ISA300), > +GEN_HANDLER_E(scv, 0x11, 0x00, 0xFF, 0x03FFF01E, PPC_NONE, PPC2_ISA300), > +GEN_HANDLER_E(rfscv, 0x13, 0x12, 0x02, 0x03FF8001, PPC_NONE, PPC2_ISA300), > GEN_HANDLER_E(stop, 0x13, 0x12, 0x0b, 0x03FFF801, PPC_NONE, PPC2_ISA300), > 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), > @@ -7026,7 +7063,9 @@ 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), > +/* Top bit of opc2 corresponds with low bit of LEV, so use two handlers */ > +GEN_HANDLER(sc, 0x11, 0x11, 0xFF, 0x03FFF01D, PPC_FLOW), > +GEN_HANDLER(sc, 0x11, 0x01, 0xFF, 0x03FFF01D, PPC_FLOW), > GEN_HANDLER(tw, 0x1F, 0x04, 0x00, 0x00000001, PPC_FLOW), > GEN_HANDLER(twi, 0x03, 0xFF, 0xFF, 0x00000000, PPC_FLOW), > #if defined(TARGET_PPC64) > @@ -7805,6 +7844,11 @@ static void ppc_tr_init_disas_context(DisasContextBase > *dcbase, CPUState *cs) > } else { > ctx->vsx_enabled = false; > } > + if ((env->flags & POWERPC_FLAG_SCV) && (env->spr[SPR_FSCR] & (1ull << > FSCR_SCV))) { > + ctx->scv_enabled = true; > + } else { > + ctx->scv_enabled = false; > + } > #if defined(TARGET_PPC64) > if ((env->flags & POWERPC_FLAG_TM) && msr_tm) { > ctx->tm_enabled = !!msr_tm; > diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c > index 0ae145e18d..15025cd5ea 100644 > --- a/target/ppc/translate_init.inc.c > +++ b/target/ppc/translate_init.inc.c > @@ -3382,6 +3382,7 @@ static void init_excp_POWER9(CPUPPCState *env) > > #if !defined(CONFIG_USER_ONLY) > env->excp_vectors[POWERPC_EXCP_HVIRT] = 0x00000EA0; > + env->excp_vectors[POWERPC_EXCP_SYSCALL_VECTORED] = 0x00000000; > #endif > } > > @@ -9030,7 +9031,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data) > pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | > POWERPC_FLAG_BE | POWERPC_FLAG_PMM | > POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR | > - POWERPC_FLAG_VSX | POWERPC_FLAG_TM; > + POWERPC_FLAG_VSX | POWERPC_FLAG_TM | POWERPC_FLAG_SCV; > pcc->l1_dcache_size = 0x8000; > pcc->l1_icache_size = 0x8000; > pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr; -- 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
signature.asc
Description: PGP signature