target/ppc: add external PID support

External PID is a mechanism present on BookE 2.06 that enables application to
store/load data from different address spaces. There are special version of some
instructions, which operate on alternate address space, which is specified in
the EPLC/EPSC regiser.

This implementation uses two additional MMU modes (mmu_idx) to provide the
address space for the load and store instructions. The QEMU TLB fill code was
modified to recognize these MMU modes and use the values in EPLC/EPSC to find
the proper entry in he PPC TLB. These two QEMU TLBs are also flushed on each
write to EPLC/EPSC.

Following instructions are implemented: dcbfep dcbstep dcbtep dcbtstep dcbzep
dcbzlep icbiep lbepx ldepx lfdepx lhepx lwepx stbepx stdepx stfdepx sthepx
stwepx.

Following vector instructions are not: evlddepx evstddepx lvepx lvepxl stvepx
stvepxl.

Signed-off-by: Roman Kapl <rka@sysgo.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
Roman Kapl 2018-09-21 08:59:07 +02:00 committed by David Gibson
parent 4de6bb0c02
commit 50728199c5
8 changed files with 387 additions and 45 deletions

View file

@ -2579,6 +2579,26 @@ GEN_LDS(lha, ld16s, 0x0A, PPC_INTEGER);
GEN_LDS(lhz, ld16u, 0x08, PPC_INTEGER);
/* lwz lwzu lwzux lwzx */
GEN_LDS(lwz, ld32u, 0x00, PPC_INTEGER);
#define GEN_LDEPX(name, ldop, opc2, opc3) \
static void glue(gen_, name##epx)(DisasContext *ctx) \
{ \
TCGv EA; \
CHK_SV; \
gen_set_access_type(ctx, ACCESS_INT); \
EA = tcg_temp_new(); \
gen_addr_reg_index(ctx, EA); \
tcg_gen_qemu_ld_tl(cpu_gpr[rD(ctx->opcode)], EA, PPC_TLB_EPID_LOAD, ldop);\
tcg_temp_free(EA); \
}
GEN_LDEPX(lb, DEF_MEMOP(MO_UB), 0x1F, 0x02)
GEN_LDEPX(lh, DEF_MEMOP(MO_UW), 0x1F, 0x08)
GEN_LDEPX(lw, DEF_MEMOP(MO_UL), 0x1F, 0x00)
#if defined(TARGET_PPC64)
GEN_LDEPX(ld, DEF_MEMOP(MO_Q), 0x1D, 0x00)
#endif
#if defined(TARGET_PPC64)
/* lwaux */
GEN_LDUX(lwa, ld32s, 0x15, 0x0B, PPC_64B);
@ -2760,6 +2780,27 @@ GEN_STS(stb, st8, 0x06, PPC_INTEGER);
GEN_STS(sth, st16, 0x0C, PPC_INTEGER);
/* stw stwu stwux stwx */
GEN_STS(stw, st32, 0x04, PPC_INTEGER);
#define GEN_STEPX(name, stop, opc2, opc3) \
static void glue(gen_, name##epx)(DisasContext *ctx) \
{ \
TCGv EA; \
CHK_SV; \
gen_set_access_type(ctx, ACCESS_INT); \
EA = tcg_temp_new(); \
gen_addr_reg_index(ctx, EA); \
tcg_gen_qemu_st_tl( \
cpu_gpr[rD(ctx->opcode)], EA, PPC_TLB_EPID_STORE, stop); \
tcg_temp_free(EA); \
}
GEN_STEPX(stb, DEF_MEMOP(MO_UB), 0x1F, 0x06)
GEN_STEPX(sth, DEF_MEMOP(MO_UW), 0x1F, 0x0C)
GEN_STEPX(stw, DEF_MEMOP(MO_UL), 0x1F, 0x04)
#if defined(TARGET_PPC64)
GEN_STEPX(std, DEF_MEMOP(MO_Q), 0x1d, 0x04)
#endif
#if defined(TARGET_PPC64)
GEN_STUX(std, st64_i64, 0x15, 0x05, PPC_64B);
GEN_STX(std, st64_i64, 0x15, 0x04, PPC_64B);
@ -4392,6 +4433,19 @@ static void gen_dcbf(DisasContext *ctx)
tcg_temp_free(t0);
}
/* dcbfep (external PID dcbf) */
static void gen_dcbfep(DisasContext *ctx)
{
/* XXX: specification says this is treated as a load by the MMU */
TCGv t0;
CHK_SV;
gen_set_access_type(ctx, ACCESS_CACHE);
t0 = tcg_temp_new();
gen_addr_reg_index(ctx, t0);
tcg_gen_qemu_ld_tl(t0, t0, PPC_TLB_EPID_LOAD, DEF_MEMOP(MO_UB));
tcg_temp_free(t0);
}
/* dcbi (Supervisor only) */
static void gen_dcbi(DisasContext *ctx)
{
@ -4425,6 +4479,18 @@ static void gen_dcbst(DisasContext *ctx)
tcg_temp_free(t0);
}
/* dcbstep (dcbstep External PID version) */
static void gen_dcbstep(DisasContext *ctx)
{
/* XXX: specification say this is treated as a load by the MMU */
TCGv t0;
gen_set_access_type(ctx, ACCESS_CACHE);
t0 = tcg_temp_new();
gen_addr_reg_index(ctx, t0);
tcg_gen_qemu_ld_tl(t0, t0, PPC_TLB_EPID_LOAD, DEF_MEMOP(MO_UB));
tcg_temp_free(t0);
}
/* dcbt */
static void gen_dcbt(DisasContext *ctx)
{
@ -4434,6 +4500,15 @@ static void gen_dcbt(DisasContext *ctx)
*/
}
/* dcbtep */
static void gen_dcbtep(DisasContext *ctx)
{
/* interpreted as no-op */
/* XXX: specification say this is treated as a load by the MMU
* but does not generate any exception
*/
}
/* dcbtst */
static void gen_dcbtst(DisasContext *ctx)
{
@ -4443,6 +4518,15 @@ static void gen_dcbtst(DisasContext *ctx)
*/
}
/* dcbtstep */
static void gen_dcbtstep(DisasContext *ctx)
{
/* interpreted as no-op */
/* XXX: specification say this is treated as a load by the MMU
* but does not generate any exception
*/
}
/* dcbtls */
static void gen_dcbtls(DisasContext *ctx)
{
@ -4469,6 +4553,21 @@ static void gen_dcbz(DisasContext *ctx)
tcg_temp_free_i32(tcgv_op);
}
/* dcbzep */
static void gen_dcbzep(DisasContext *ctx)
{
TCGv tcgv_addr;
TCGv_i32 tcgv_op;
gen_set_access_type(ctx, ACCESS_CACHE);
tcgv_addr = tcg_temp_new();
tcgv_op = tcg_const_i32(ctx->opcode & 0x03FF000);
gen_addr_reg_index(ctx, tcgv_addr);
gen_helper_dcbzep(cpu_env, tcgv_addr, tcgv_op);
tcg_temp_free(tcgv_addr);
tcg_temp_free_i32(tcgv_op);
}
/* dst / dstt */
static void gen_dst(DisasContext *ctx)
{
@ -4507,6 +4606,17 @@ static void gen_icbi(DisasContext *ctx)
tcg_temp_free(t0);
}
/* icbiep */
static void gen_icbiep(DisasContext *ctx)
{
TCGv t0;
gen_set_access_type(ctx, ACCESS_CACHE);
t0 = tcg_temp_new();
gen_addr_reg_index(ctx, t0);
gen_helper_icbiep(cpu_env, t0);
tcg_temp_free(t0);
}
/* Optional: */
/* dcba */
static void gen_dcba(DisasContext *ctx)
@ -6774,16 +6884,22 @@ GEN_HANDLER_E(mcrxrx, 0x1F, 0x00, 0x12, 0x007FF801, PPC_NONE, PPC2_ISA300),
GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001EF801, PPC_MISC),
GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000000, PPC_MISC),
GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03C00001, PPC_CACHE),
GEN_HANDLER_E(dcbfep, 0x1F, 0x1F, 0x03, 0x03C00001, PPC_NONE, PPC2_BOOKE206),
GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE),
GEN_HANDLER(dcbst, 0x1F, 0x16, 0x01, 0x03E00001, PPC_CACHE),
GEN_HANDLER_E(dcbstep, 0x1F, 0x1F, 0x01, 0x03E00001, PPC_NONE, PPC2_BOOKE206),
GEN_HANDLER(dcbt, 0x1F, 0x16, 0x08, 0x00000001, PPC_CACHE),
GEN_HANDLER_E(dcbtep, 0x1F, 0x1F, 0x09, 0x00000001, PPC_NONE, PPC2_BOOKE206),
GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x00000001, PPC_CACHE),
GEN_HANDLER_E(dcbtstep, 0x1F, 0x1F, 0x07, 0x00000001, PPC_NONE, PPC2_BOOKE206),
GEN_HANDLER_E(dcbtls, 0x1F, 0x06, 0x05, 0x02000001, PPC_BOOKE, PPC2_BOOKE206),
GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03C00001, PPC_CACHE_DCBZ),
GEN_HANDLER_E(dcbzep, 0x1F, 0x1F, 0x1F, 0x03C00001, PPC_NONE, PPC2_BOOKE206),
GEN_HANDLER(dst, 0x1F, 0x16, 0x0A, 0x01800001, PPC_ALTIVEC),
GEN_HANDLER(dstst, 0x1F, 0x16, 0x0B, 0x01800001, PPC_ALTIVEC),
GEN_HANDLER(dss, 0x1F, 0x16, 0x19, 0x019FF801, PPC_ALTIVEC),
GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE_ICBI),
GEN_HANDLER_E(icbiep, 0x1F, 0x1F, 0x1E, 0x03E00001, PPC_NONE, PPC2_BOOKE206),
GEN_HANDLER(dcba, 0x1F, 0x16, 0x17, 0x03E00001, PPC_CACHE_DCBA),
GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT),
GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT),
@ -7086,6 +7202,19 @@ GEN_LDX_HVRM(lbzcix, ld8u, 0x15, 0x1a, PPC_CILDST)
GEN_LDX(lhbr, ld16ur, 0x16, 0x18, PPC_INTEGER)
GEN_LDX(lwbr, ld32ur, 0x16, 0x10, PPC_INTEGER)
/* External PID based load */
#undef GEN_LDEPX
#define GEN_LDEPX(name, ldop, opc2, opc3) \
GEN_HANDLER_E(name##epx, 0x1F, opc2, opc3, \
0x00000001, PPC_NONE, PPC2_BOOKE206),
GEN_LDEPX(lb, DEF_MEMOP(MO_UB), 0x1F, 0x02)
GEN_LDEPX(lh, DEF_MEMOP(MO_UW), 0x1F, 0x08)
GEN_LDEPX(lw, DEF_MEMOP(MO_UL), 0x1F, 0x00)
#if defined(TARGET_PPC64)
GEN_LDEPX(ld, DEF_MEMOP(MO_Q), 0x1D, 0x00)
#endif
#undef GEN_ST
#undef GEN_STU
#undef GEN_STUX
@ -7120,6 +7249,18 @@ GEN_STX_HVRM(stbcix, st8, 0x15, 0x1e, PPC_CILDST)
GEN_STX(sthbr, st16r, 0x16, 0x1C, PPC_INTEGER)
GEN_STX(stwbr, st32r, 0x16, 0x14, PPC_INTEGER)
#undef GEN_STEPX
#define GEN_STEPX(name, ldop, opc2, opc3) \
GEN_HANDLER_E(name##epx, 0x1F, opc2, opc3, \
0x00000001, PPC_NONE, PPC2_BOOKE206),
GEN_STEPX(stb, DEF_MEMOP(MO_UB), 0x1F, 0x06)
GEN_STEPX(sth, DEF_MEMOP(MO_UW), 0x1F, 0x0C)
GEN_STEPX(stw, DEF_MEMOP(MO_UL), 0x1F, 0x04)
#if defined(TARGET_PPC64)
GEN_STEPX(std, DEF_MEMOP(MO_Q), 0x1D, 0x04)
#endif
#undef GEN_CRLOGIC
#define GEN_CRLOGIC(name, tcg_op, opc) \
GEN_HANDLER(name, 0x13, 0x01, opc, 0x00000001, PPC_INTEGER)