Skip to content
Open
Show file tree
Hide file tree
Changes from 9 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
19 changes: 19 additions & 0 deletions target/ppc/helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -631,11 +631,30 @@ 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)

/*
* 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_RWG, void, \
env, tl, tl, i32)
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_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
Expand Down
34 changes: 34 additions & 0 deletions target/ppc/insn32.decode
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,15 @@

@Z23_te_tbp ...... ....0 te:5 ....0 rmc:2 ........ rc:1 &Z23_te_tb frt=%z23_frtp frb=%z23_frbp

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

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

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

### Fixed-Point Load Instructions

LBZ 100010 ..... ..... ................ @D
Expand Down Expand Up @@ -710,3 +719,28 @@ XVTLSBB 111100 ... -- 00010 ..... 111011011 . - @XX2_bf_xb
&XL_s s:uint8_t
@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
32 changes: 32 additions & 0 deletions target/ppc/mmu-hash64.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,38 @@ 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 slbia would
* not have to flush unless it evicts a valid SLB entry. However it is
* expected that slbmte is more common than slbia, and slbia 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];

if (!(slb->esid & SLB_ESID_V)) {
continue;
}

slb->esid &= ~SLB_ESID_V;
}
}
#endif

static void __helper_slbie(CPUPPCState *env, target_ulong addr,
target_ulong global)
{
Expand Down
153 changes: 153 additions & 0 deletions target/ppc/mmu_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,159 @@ 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))) {
Comment on lines +488 to +489

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see your intention with this indentation, but it looks weird
Might be better to remove it and merge the lines

((ric == TLBIE_RIC_PWC || ric == TLBIE_RIC_ALL) &&
 is == TLBIE_IS_VA) || (!prs && is == TLBIE_IS_PID))) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or even better (if it fits the 80 cols)

if (unlikely(ric == TLBIE_RIC_GRP ||
    ((ric == TLBIE_RIC_PWC || ric == TLBIE_RIC_ALL) && is == TLBIE_IS_VA) ||
    (!prs && is == TLBIE_IS_PID))) {

IIRC the style guide isn't strict about aligning with the most internal parenthesis, so I think we can align with the if parenthesis

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change actually came from #88. It was already sent to the mailing list.

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