Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions target/ppc/cpu_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -6368,7 +6368,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
PPC_FLOAT_EXT |
PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |
PPC_MEM_SYNC | PPC_MEM_EIEIO |
PPC_MEM_TLBSYNC |
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |
PPC_64B | PPC_64H | PPC_64BX | PPC_ALTIVEC |
PPC_SEGMENT_64B | PPC_SLBI |
PPC_POPCNTB | PPC_POPCNTWD |
Expand Down Expand Up @@ -6585,7 +6585,7 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data)
PPC_FLOAT_EXT |
PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |
PPC_MEM_SYNC | PPC_MEM_EIEIO |
PPC_MEM_TLBSYNC |
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |
PPC_64B | PPC_64H | PPC_64BX | PPC_ALTIVEC |
PPC_SEGMENT_64B | PPC_SLBI |
PPC_POPCNTB | PPC_POPCNTWD |
Expand Down
33 changes: 26 additions & 7 deletions target/ppc/helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -664,13 +664,32 @@ DEF_HELPER_FLAGS_1(tlbia, TCG_CALL_NO_RWG, void, env)
DEF_HELPER_FLAGS_2(tlbie, TCG_CALL_NO_RWG, void, env, tl)
DEF_HELPER_FLAGS_2(tlbiva, TCG_CALL_NO_RWG, void, env, tl)
#if defined(TARGET_PPC64)
DEF_HELPER_FLAGS_3(store_slb, TCG_CALL_NO_RWG, void, env, tl, tl)
DEF_HELPER_2(load_slb_esid, tl, env, tl)
DEF_HELPER_2(load_slb_vsid, tl, env, tl)
DEF_HELPER_2(find_slb_vsid, tl, env, tl)
DEF_HELPER_FLAGS_2(slbia, TCG_CALL_NO_RWG, void, env, i32)
DEF_HELPER_FLAGS_2(slbie, TCG_CALL_NO_RWG, void, env, tl)
DEF_HELPER_FLAGS_2(slbieg, TCG_CALL_NO_RWG, void, env, tl)

/*
* tlbie[l] helper flags
*
* RIC, PRS, R and local are passed as flags in the last argument.
*/
#define TLBIE_F_RIC_SHIFT 0
#define TLBIE_F_PRS_SHIFT 2
#define TLBIE_F_R_SHIFT 3
#define TLBIE_F_LOCAL_SHIFT 4

#define TLBIE_F_RIC_MASK (3 << TLBIE_F_RIC_SHIFT)
#define TLBIE_F_PRS (1 << TLBIE_F_PRS_SHIFT)
#define TLBIE_F_R (1 << TLBIE_F_R_SHIFT)
#define TLBIE_F_LOCAL (1 << TLBIE_F_LOCAL_SHIFT)

DEF_HELPER_FLAGS_4(tlbie_isa300, TCG_CALL_NO_WG, void, \
env, tl, tl, i32)
DEF_HELPER_FLAGS_3(SLBMTE, TCG_CALL_NO_RWG, void, env, tl, tl)
DEF_HELPER_2(SLBMFEE, tl, env, tl)
DEF_HELPER_2(SLBMFEV, tl, env, tl)
DEF_HELPER_2(SLBFEE, tl, env, tl)
DEF_HELPER_FLAGS_2(SLBIA, TCG_CALL_NO_RWG, void, env, i32)
DEF_HELPER_FLAGS_3(SLBIAG, TCG_CALL_NO_RWG, void, env, tl, i32)
DEF_HELPER_FLAGS_2(SLBIE, TCG_CALL_NO_RWG, void, env, tl)
DEF_HELPER_FLAGS_2(SLBIEG, TCG_CALL_NO_RWG, void, env, tl)
#endif
DEF_HELPER_FLAGS_2(load_sr, TCG_CALL_NO_RWG, tl, env, tl)
DEF_HELPER_FLAGS_3(store_sr, TCG_CALL_NO_RWG, void, env, tl, tl)
Expand Down
34 changes: 34 additions & 0 deletions target/ppc/insn32.decode
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,15 @@
&X_imm8 xt imm:uint8_t
@X_imm8 ...... ..... .. imm:8 .......... . &X_imm8 xt=%x_xt

&X_ih ih:uint8_t
@X_ih ...... .. ih:3 ..... ..... .......... . &X_ih

&X_rb rb
@X_rb ...... ..... ..... rb:5 .......... . &X_rb

&X_rs_l rs l:bool
@X_rs_l ...... rs:5 .... l:1 ..... .......... . &X_rs_l

&X_uim5 xt uim:uint8_t
@X_uim5 ...... ..... ..... uim:5 .......... . &X_uim5 xt=%x_xt

Expand Down Expand Up @@ -745,6 +754,31 @@ XVTLSBB 111100 ... -- 00010 ..... 111011011 . - @XX2_bf_xb
@XL_s ......-------------- s:1 .......... - &XL_s
RFEBB 010011-------------- . 0010010010 - @XL_s

## SLB Management Instructions

SLBIE 011111 ----- ----- ..... 0110110010 - @X_rb
SLBIEG 011111 ..... ----- ..... 0111010010 - @X_tb

SLBIA 011111 --... ----- ----- 0111110010 - @X_ih
SLBIAG 011111 ..... ----. ----- 1101010010 - @X_rs_l

SLBMTE 011111 ..... ----- ..... 0110010010 - @X_tb

SLBMFEV 011111 ..... ----- ..... 1101010011 - @X_tb
SLBMFEE 011111 ..... ----- ..... 1110010011 - @X_tb

SLBFEE 011111 ..... ----- ..... 1111010011 1 @X_tb

SLBSYNC 011111 ----- ----- ----- 0101010010 -

## TLB Management Instructions

&X_tlbie rb rs ric prs:bool r:bool
@X_tlbie ...... rs:5 - ric:2 prs:1 r:1 rb:5 .......... . &X_tlbie

TLBIE 011111 ..... - .. . . ..... 0100110010 - @X_tlbie
TLBIEL 011111 ..... - .. . . ..... 0100010010 - @X_tlbie

## Accumulator Instructions

XXMFACC 011111 ... -- 00000 ----- 0010110001 - @X_a
Expand Down
41 changes: 34 additions & 7 deletions target/ppc/mmu-hash64.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ void dump_slb(PowerPCCPU *cpu)
}

#ifdef CONFIG_TCG
void helper_slbia(CPUPPCState *env, uint32_t ih)
void helper_SLBIA(CPUPPCState *env, uint32_t ih)
{
PowerPCCPU *cpu = env_archcpu(env);
int starting_entry;
Expand Down Expand Up @@ -173,6 +173,33 @@ void helper_slbia(CPUPPCState *env, uint32_t ih)
}
}

#if defined(TARGET_PPC64)
void helper_SLBIAG(CPUPPCState *env, target_ulong rs, uint32_t l)
{
PowerPCCPU *cpu = env_archcpu(env);
int n;

/*
* slbiag must always flush all TLB (which is equivalent to ERAT in ppc
* architecture). Matching on SLB_ESID_V is not good enough, because slbmte
* can overwrite a valid SLB without flushing its lookaside information.
*
* It would be possible to keep the TLB in synch with the SLB by flushing
* when a valid entry is overwritten by slbmte, and therefore slbiag would
* not have to flush unless it evicts a valid SLB entry. However it is
* expected that slbmte is more common than slbiag, and slbiag is usually
* going to evict valid SLB entries, so that tradeoff is unlikely to be a
* good one.
*/
env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;

for (n = 0; n < cpu->hash64_opts->slb_size; n++) {
ppc_slb_t *slb = &env->slb[n];
slb->esid &= ~SLB_ESID_V;
}
}
#endif

static void __helper_slbie(CPUPPCState *env, target_ulong addr,
target_ulong global)
{
Expand All @@ -197,12 +224,12 @@ static void __helper_slbie(CPUPPCState *env, target_ulong addr,
}
}

void helper_slbie(CPUPPCState *env, target_ulong addr)
void helper_SLBIE(CPUPPCState *env, target_ulong addr)
{
__helper_slbie(env, addr, false);
}

void helper_slbieg(CPUPPCState *env, target_ulong addr)
void helper_SLBIEG(CPUPPCState *env, target_ulong addr)
{
__helper_slbie(env, addr, true);
}
Expand Down Expand Up @@ -309,7 +336,7 @@ static int ppc_find_slb_vsid(PowerPCCPU *cpu, target_ulong rb,
return 0;
}

void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
void helper_SLBMTE(CPUPPCState *env, target_ulong rb, target_ulong rs)
{
PowerPCCPU *cpu = env_archcpu(env);

Expand All @@ -319,7 +346,7 @@ void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
}
}

target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb)
target_ulong helper_SLBMFEE(CPUPPCState *env, target_ulong rb)
{
PowerPCCPU *cpu = env_archcpu(env);
target_ulong rt = 0;
Expand All @@ -331,7 +358,7 @@ target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb)
return rt;
}

target_ulong helper_find_slb_vsid(CPUPPCState *env, target_ulong rb)
target_ulong helper_SLBFEE(CPUPPCState *env, target_ulong rb)
{
PowerPCCPU *cpu = env_archcpu(env);
target_ulong rt = 0;
Expand All @@ -343,7 +370,7 @@ target_ulong helper_find_slb_vsid(CPUPPCState *env, target_ulong rb)
return rt;
}

target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
target_ulong helper_SLBMFEV(CPUPPCState *env, target_ulong rb)
{
PowerPCCPU *cpu = env_archcpu(env);
target_ulong rt = 0;
Expand Down
154 changes: 154 additions & 0 deletions target/ppc/mmu_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,160 @@ void helper_tlbie(CPUPPCState *env, target_ulong addr)
ppc_tlb_invalidate_one(env, addr);
}

#if defined(TARGET_PPC64)

/* Invalidation Selector */
#define TLBIE_IS_VA 0
#define TLBIE_IS_PID 1
#define TLBIE_IS_LPID 2
#define TLBIE_IS_ALL 3

/* Radix Invalidation Control */
#define TLBIE_RIC_TLB 0
#define TLBIE_RIC_PWC 1
#define TLBIE_RIC_ALL 2
#define TLBIE_RIC_GRP 3

/* Radix Actual Page sizes */
#define TLBIE_R_AP_4K 0
#define TLBIE_R_AP_64K 5
#define TLBIE_R_AP_2M 1
#define TLBIE_R_AP_1G 2

/* RB field masks */
#define TLBIE_RB_EPN_MASK PPC_BITMASK(0, 51)
#define TLBIE_RB_IS_MASK PPC_BITMASK(52, 53)
#define TLBIE_RB_AP_MASK PPC_BITMASK(56, 58)

void helper_tlbie_isa300(CPUPPCState *env, target_ulong rb, target_ulong rs,
uint32_t flags)
{
unsigned ric = (flags & TLBIE_F_RIC_MASK) >> TLBIE_F_RIC_SHIFT;
/*
* With the exception of the checks for invalid instruction forms,
* PRS is currently ignored, because we don't know if a given TLB entry
* is process or partition scoped.
*/
bool prs = flags & TLBIE_F_PRS;
bool r = flags & TLBIE_F_R;
bool local = flags & TLBIE_F_LOCAL;
bool effR;
unsigned is = extract64(rb, PPC_BIT_NR(53), 2), set;
unsigned ap; /* actual page size */
target_ulong addr, pgoffs_mask;

qemu_log_mask(CPU_LOG_MMU,
"%s: local=%d addr=" TARGET_FMT_lx " ric=%u prs=%d r=%d is=%u\n",
__func__, local, rb & TARGET_PAGE_MASK, ric, prs, r, is);

effR = FIELD_EX64(env->msr, MSR, HV) ? r : env->spr[SPR_LPCR] & LPCR_HR;

/* Partial TLB invalidation is supported for Radix only for now. */
if (!effR) {
goto inval_all;
}

/* Check for invalid instruction forms (effR=1). */
if (unlikely(ric == TLBIE_RIC_GRP ||
((ric == TLBIE_RIC_PWC || ric == TLBIE_RIC_ALL) &&
is == TLBIE_IS_VA) ||
(!prs && is == TLBIE_IS_PID))) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: invalid instruction form: ric=%u prs=%d r=%d is=%u\n",
__func__, ric, prs, r, is);
goto invalid;
}

/* We don't cache Page Walks. */
if (ric == TLBIE_RIC_PWC) {
if (local) {
set = extract64(rb, PPC_BIT_NR(51), 12);
if (set != 0) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid set: %d\n",
__func__, set);
goto invalid;
}
}
return;
}

/*
* Invalidation by LPID or PID is not supported, so fallback
* to full TLB flush in these cases.
*/
if (is != TLBIE_IS_VA) {
goto inval_all;
}

/*
* The results of an attempt to invalidate a translation outside of
* quadrant 0 for Radix Tree translation (effR=1, RIC=0, PRS=1, IS=0,
* and EA 0:1 != 0b00) are boundedly undefined.
*/
if (unlikely(ric == TLBIE_RIC_TLB && prs && is == TLBIE_IS_VA &&
(rb & R_EADDR_QUADRANT) != R_EADDR_QUADRANT0)) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: attempt to invalidate a translation outside of quadrant 0\n",
__func__);
goto inval_all;
}

assert(is == TLBIE_IS_VA);
assert(ric == TLBIE_RIC_TLB || ric == TLBIE_RIC_ALL);

ap = extract64(rb, PPC_BIT_NR(58), 3);
switch (ap) {
case TLBIE_R_AP_4K:
pgoffs_mask = 0xfffull;
break;

case TLBIE_R_AP_64K:
pgoffs_mask = 0xffffull;
break;

case TLBIE_R_AP_2M:
pgoffs_mask = 0x1fffffull;
break;

case TLBIE_R_AP_1G:
pgoffs_mask = 0x3fffffffull;
break;

default:
/*
* If the value specified in RS 0:31, RS 32:63, RB 54:55, RB 56:58,
* RB 44:51, or RB 56:63, when it is needed to perform the specified
* operation, is not supported by the implementation, the instruction
* is treated as if the instruction form were invalid.
*/
qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid AP: %d\n", __func__, ap);
goto invalid;
}

addr = rb & TLBIE_RB_EPN_MASK & ~pgoffs_mask;

if (local) {
tlb_flush_page(env_cpu(env), addr);
} else {
tlb_flush_page_all_cpus(env_cpu(env), addr);
}
return;

inval_all:
env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
if (!local) {
env->tlb_need_flush |= TLB_NEED_GLOBAL_FLUSH;
}
return;

invalid:
raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
POWERPC_EXCP_INVAL |
POWERPC_EXCP_INVAL_INVAL, GETPC());
}

#endif

void helper_tlbiva(CPUPPCState *env, target_ulong addr)
{
/* tlbiva instruction only exists on BookE */
Expand Down
Loading