ppc: Add real mode CI load/store instructions for P7 and P8
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 <benh@kernel.crashing.org> [clg: fixed checkpatch.pl errors ] Signed-off-by: Cédric Le Goater <clg@kaod.org> Reviewed-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
parent
9b2fadda3e
commit
b781537560
@ -1912,6 +1912,8 @@ enum {
|
|||||||
PPC_POPCNTB = 0x0000000000001000ULL,
|
PPC_POPCNTB = 0x0000000000001000ULL,
|
||||||
/* string load / store */
|
/* string load / store */
|
||||||
PPC_STRING = 0x0000000000002000ULL,
|
PPC_STRING = 0x0000000000002000ULL,
|
||||||
|
/* real mode cache inhibited load / store */
|
||||||
|
PPC_CILDST = 0x0000000000004000ULL,
|
||||||
|
|
||||||
/* Floating-point unit extensions */
|
/* Floating-point unit extensions */
|
||||||
/* Optional floating point instructions */
|
/* Optional floating point instructions */
|
||||||
@ -2026,7 +2028,7 @@ enum {
|
|||||||
| PPC_MFAPIDI | PPC_TLBIVA | PPC_TLBIVAX \
|
| PPC_MFAPIDI | PPC_TLBIVA | PPC_TLBIVAX \
|
||||||
| PPC_4xx_COMMON | PPC_40x_ICBT | PPC_RFMCI \
|
| PPC_4xx_COMMON | PPC_40x_ICBT | PPC_RFMCI \
|
||||||
| PPC_RFDI | PPC_DCR | PPC_DCRX | PPC_DCRUX \
|
| PPC_RFDI | PPC_DCR | PPC_DCRX | PPC_DCRUX \
|
||||||
| PPC_POPCNTWD)
|
| PPC_POPCNTWD | PPC_CILDST)
|
||||||
|
|
||||||
/* extended type values */
|
/* extended type values */
|
||||||
|
|
||||||
|
@ -193,7 +193,7 @@ struct DisasContext {
|
|||||||
uint32_t opcode;
|
uint32_t opcode;
|
||||||
uint32_t exception;
|
uint32_t exception;
|
||||||
/* Routine used to access memory */
|
/* Routine used to access memory */
|
||||||
bool pr, hv;
|
bool pr, hv, dr;
|
||||||
bool lazy_tlb_flush;
|
bool lazy_tlb_flush;
|
||||||
int mem_idx;
|
int mem_idx;
|
||||||
int access_type;
|
int access_type;
|
||||||
@ -388,6 +388,7 @@ typedef struct opcode_t {
|
|||||||
#if defined(CONFIG_USER_ONLY)
|
#if defined(CONFIG_USER_ONLY)
|
||||||
#define CHK_HV GEN_PRIV
|
#define CHK_HV GEN_PRIV
|
||||||
#define CHK_SV GEN_PRIV
|
#define CHK_SV GEN_PRIV
|
||||||
|
#define CHK_HVRM GEN_PRIV
|
||||||
#else
|
#else
|
||||||
#define CHK_HV \
|
#define CHK_HV \
|
||||||
do { \
|
do { \
|
||||||
@ -401,6 +402,12 @@ typedef struct opcode_t {
|
|||||||
GEN_PRIV; \
|
GEN_PRIV; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
#define CHK_HVRM \
|
||||||
|
do { \
|
||||||
|
if (unlikely(ctx->pr || !ctx->hv || ctx->dr)) { \
|
||||||
|
GEN_PRIV; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define CHK_NONE
|
#define CHK_NONE
|
||||||
@ -2927,18 +2934,23 @@ static void glue(gen_, name##ux)(DisasContext *ctx)
|
|||||||
tcg_temp_free(EA); \
|
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) \
|
static void glue(gen_, name##x)(DisasContext *ctx) \
|
||||||
{ \
|
{ \
|
||||||
TCGv EA; \
|
TCGv EA; \
|
||||||
|
chk; \
|
||||||
gen_set_access_type(ctx, ACCESS_INT); \
|
gen_set_access_type(ctx, ACCESS_INT); \
|
||||||
EA = tcg_temp_new(); \
|
EA = tcg_temp_new(); \
|
||||||
gen_addr_reg_index(ctx, EA); \
|
gen_addr_reg_index(ctx, EA); \
|
||||||
gen_qemu_##ldop(ctx, cpu_gpr[rD(ctx->opcode)], EA); \
|
gen_qemu_##ldop(ctx, cpu_gpr[rD(ctx->opcode)], EA); \
|
||||||
tcg_temp_free(EA); \
|
tcg_temp_free(EA); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GEN_LDX(name, ldop, opc2, opc3, type) \
|
#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) \
|
#define GEN_LDS(name, ldop, op, type) \
|
||||||
GEN_LD(name, ldop, op | 0x20, type); \
|
GEN_LD(name, ldop, op | 0x20, type); \
|
||||||
@ -2964,6 +2976,12 @@ GEN_LDUX(ld, ld64, 0x15, 0x01, PPC_64B);
|
|||||||
/* ldx */
|
/* ldx */
|
||||||
GEN_LDX(ld, ld64, 0x15, 0x00, PPC_64B);
|
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)
|
static void gen_ld(DisasContext *ctx)
|
||||||
{
|
{
|
||||||
TCGv EA;
|
TCGv EA;
|
||||||
@ -3082,10 +3100,11 @@ static void glue(gen_, name##ux)(DisasContext *ctx)
|
|||||||
tcg_temp_free(EA); \
|
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) \
|
static void glue(gen_, name##x)(DisasContext *ctx) \
|
||||||
{ \
|
{ \
|
||||||
TCGv EA; \
|
TCGv EA; \
|
||||||
|
chk; \
|
||||||
gen_set_access_type(ctx, ACCESS_INT); \
|
gen_set_access_type(ctx, ACCESS_INT); \
|
||||||
EA = tcg_temp_new(); \
|
EA = tcg_temp_new(); \
|
||||||
gen_addr_reg_index(ctx, EA); \
|
gen_addr_reg_index(ctx, EA); \
|
||||||
@ -3093,7 +3112,10 @@ static void glue(gen_, name##x)(DisasContext *ctx) \
|
|||||||
tcg_temp_free(EA); \
|
tcg_temp_free(EA); \
|
||||||
}
|
}
|
||||||
#define GEN_STX(name, stop, opc2, opc3, type) \
|
#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) \
|
#define GEN_STS(name, stop, op, type) \
|
||||||
GEN_ST(name, stop, op | 0x20, type); \
|
GEN_ST(name, stop, op | 0x20, type); \
|
||||||
@ -3110,6 +3132,10 @@ GEN_STS(stw, st32, 0x04, PPC_INTEGER);
|
|||||||
#if defined(TARGET_PPC64)
|
#if defined(TARGET_PPC64)
|
||||||
GEN_STUX(std, st64, 0x15, 0x05, PPC_64B);
|
GEN_STUX(std, st64, 0x15, 0x05, PPC_64B);
|
||||||
GEN_STX(std, st64, 0x15, 0x04, 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)
|
static void gen_std(DisasContext *ctx)
|
||||||
{
|
{
|
||||||
@ -3198,7 +3224,7 @@ static inline void gen_qemu_ld64ur(DisasContext *ctx, TCGv arg1, TCGv arg2)
|
|||||||
TCGMemOp op = MO_Q | (ctx->default_tcg_memop_mask ^ MO_BSWAP);
|
TCGMemOp op = MO_Q | (ctx->default_tcg_memop_mask ^ MO_BSWAP);
|
||||||
tcg_gen_qemu_ld_i64(arg1, arg2, ctx->mem_idx, op);
|
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 */
|
#endif /* TARGET_PPC64 */
|
||||||
|
|
||||||
/* sthbrx */
|
/* sthbrx */
|
||||||
@ -3224,7 +3250,7 @@ static inline void gen_qemu_st64r(DisasContext *ctx, TCGv arg1, TCGv arg2)
|
|||||||
TCGMemOp op = MO_Q | (ctx->default_tcg_memop_mask ^ MO_BSWAP);
|
TCGMemOp op = MO_Q | (ctx->default_tcg_memop_mask ^ MO_BSWAP);
|
||||||
tcg_gen_qemu_st_i64(arg1, arg2, ctx->mem_idx, op);
|
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 */
|
#endif /* TARGET_PPC64 */
|
||||||
|
|
||||||
/*** Integer load and store multiple ***/
|
/*** Integer load and store multiple ***/
|
||||||
@ -10238,7 +10264,7 @@ GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type),
|
|||||||
GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type),
|
GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type),
|
||||||
#define GEN_LDUX(name, ldop, opc2, opc3, type) \
|
#define GEN_LDUX(name, ldop, opc2, opc3, type) \
|
||||||
GEN_HANDLER(name##ux, 0x1F, opc2, opc3, 0x00000001, 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),
|
GEN_HANDLER_E(name##x, 0x1F, opc2, opc3, 0x00000001, type, type2),
|
||||||
#define GEN_LDS(name, ldop, op, type) \
|
#define GEN_LDS(name, ldop, op, type) \
|
||||||
GEN_LD(name, ldop, op | 0x20, type) \
|
GEN_LD(name, ldop, op | 0x20, type) \
|
||||||
@ -10255,7 +10281,13 @@ GEN_LDUX(lwa, ld32s, 0x15, 0x0B, PPC_64B)
|
|||||||
GEN_LDX(lwa, ld32s, 0x15, 0x0A, PPC_64B)
|
GEN_LDX(lwa, ld32s, 0x15, 0x0A, PPC_64B)
|
||||||
GEN_LDUX(ld, ld64, 0x15, 0x01, PPC_64B)
|
GEN_LDUX(ld, ld64, 0x15, 0x01, PPC_64B)
|
||||||
GEN_LDX(ld, ld64, 0x15, 0x00, 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
|
#endif
|
||||||
GEN_LDX(lhbr, ld16ur, 0x16, 0x18, PPC_INTEGER)
|
GEN_LDX(lhbr, ld16ur, 0x16, 0x18, PPC_INTEGER)
|
||||||
GEN_LDX(lwbr, ld32ur, 0x16, 0x10, PPC_INTEGER)
|
GEN_LDX(lwbr, ld32ur, 0x16, 0x10, PPC_INTEGER)
|
||||||
@ -10271,7 +10303,7 @@ GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type),
|
|||||||
GEN_HANDLER(stop##u, opc, 0xFF, 0xFF, 0x00000000, type),
|
GEN_HANDLER(stop##u, opc, 0xFF, 0xFF, 0x00000000, type),
|
||||||
#define GEN_STUX(name, stop, opc2, opc3, type) \
|
#define GEN_STUX(name, stop, opc2, opc3, type) \
|
||||||
GEN_HANDLER(name##ux, 0x1F, opc2, opc3, 0x00000001, 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),
|
GEN_HANDLER_E(name##x, 0x1F, opc2, opc3, 0x00000001, type, type2),
|
||||||
#define GEN_STS(name, stop, op, type) \
|
#define GEN_STS(name, stop, op, type) \
|
||||||
GEN_ST(name, stop, op | 0x20, type) \
|
GEN_ST(name, stop, op | 0x20, type) \
|
||||||
@ -10285,7 +10317,11 @@ GEN_STS(stw, st32, 0x04, PPC_INTEGER)
|
|||||||
#if defined(TARGET_PPC64)
|
#if defined(TARGET_PPC64)
|
||||||
GEN_STUX(std, st64, 0x15, 0x05, PPC_64B)
|
GEN_STUX(std, st64, 0x15, 0x05, PPC_64B)
|
||||||
GEN_STX(std, st64, 0x15, 0x04, 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
|
#endif
|
||||||
GEN_STX(sthbr, st16r, 0x16, 0x1C, PPC_INTEGER)
|
GEN_STX(sthbr, st16r, 0x16, 0x1C, PPC_INTEGER)
|
||||||
GEN_STX(stwbr, st32r, 0x16, 0x14, PPC_INTEGER)
|
GEN_STX(stwbr, st32r, 0x16, 0x14, PPC_INTEGER)
|
||||||
@ -11453,6 +11489,7 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
|
|||||||
ctx.spr_cb = env->spr_cb;
|
ctx.spr_cb = env->spr_cb;
|
||||||
ctx.pr = msr_pr;
|
ctx.pr = msr_pr;
|
||||||
ctx.mem_idx = env->dmmu_idx;
|
ctx.mem_idx = env->dmmu_idx;
|
||||||
|
ctx.dr = msr_dr;
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
ctx.hv = msr_hv || !env->has_hv_mode;
|
ctx.hv = msr_hv || !env->has_hv_mode;
|
||||||
#endif
|
#endif
|
||||||
|
@ -8404,7 +8404,8 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
|
|||||||
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |
|
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |
|
||||||
PPC_64B | PPC_64H | PPC_64BX | PPC_ALTIVEC |
|
PPC_64B | PPC_64H | PPC_64BX | PPC_ALTIVEC |
|
||||||
PPC_SEGMENT_64B | PPC_SLBI |
|
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 |
|
pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX | PPC2_ISA205 |
|
||||||
PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 |
|
PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 |
|
||||||
PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 |
|
PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 |
|
||||||
@ -8485,7 +8486,8 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
|
|||||||
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |
|
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |
|
||||||
PPC_64B | PPC_64H | PPC_64BX | PPC_ALTIVEC |
|
PPC_64B | PPC_64H | PPC_64BX | PPC_ALTIVEC |
|
||||||
PPC_SEGMENT_64B | PPC_SLBI |
|
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 |
|
pcc->insns_flags2 = PPC2_VSX | PPC2_VSX207 | PPC2_DFP | PPC2_DBRX |
|
||||||
PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 |
|
PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 |
|
||||||
PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 |
|
PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 |
|
||||||
|
Loading…
Reference in New Issue
Block a user