Skip to content

Lrcoutinho slbiag #89

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: lrcoutinho-master
Choose a base branch
from
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
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 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];

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