aboutsummaryrefslogtreecommitdiff
path: root/target-ppc/helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'target-ppc/helper.c')
-rw-r--r--target-ppc/helper.c176
1 files changed, 50 insertions, 126 deletions
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 4b491012d7..2094ca36f9 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -672,85 +672,36 @@ static inline int find_pte(CPUState *env, mmu_ctx_t *ctx, int h, int rw,
}
#if defined(TARGET_PPC64)
-static ppc_slb_t *slb_get_entry(CPUPPCState *env, int nr)
-{
- ppc_slb_t *retval = &env->slb[nr];
-
-#if 0 // XXX implement bridge mode?
- if (env->spr[SPR_ASR] & 1) {
- target_phys_addr_t sr_base;
-
- sr_base = env->spr[SPR_ASR] & 0xfffffffffffff000;
- sr_base += (12 * nr);
-
- retval->tmp64 = ldq_phys(sr_base);
- retval->tmp = ldl_phys(sr_base + 8);
- }
-#endif
-
- return retval;
-}
-
-static void slb_set_entry(CPUPPCState *env, int nr, ppc_slb_t *slb)
-{
- ppc_slb_t *entry = &env->slb[nr];
-
- if (slb == entry)
- return;
-
- entry->tmp64 = slb->tmp64;
- entry->tmp = slb->tmp;
-}
-
-static inline int slb_is_valid(ppc_slb_t *slb)
-{
- return (int)(slb->tmp64 & 0x0000000008000000ULL);
-}
-
-static inline void slb_invalidate(ppc_slb_t *slb)
-{
- slb->tmp64 &= ~0x0000000008000000ULL;
-}
-
static inline int slb_lookup(CPUPPCState *env, target_ulong eaddr,
target_ulong *vsid, target_ulong *page_mask,
int *attr, int *target_page_bits)
{
- target_ulong mask;
- int n, ret;
+ uint64_t esid;
+ int n;
- ret = -5;
LOG_SLB("%s: eaddr " TARGET_FMT_lx "\n", __func__, eaddr);
- mask = 0x0000000000000000ULL; /* Avoid gcc warning */
+
+ esid = (eaddr & SEGMENT_MASK_256M) | SLB_ESID_V;
+
for (n = 0; n < env->slb_nr; n++) {
- ppc_slb_t *slb = slb_get_entry(env, n);
-
- LOG_SLB("%s: seg %d %016" PRIx64 " %08"
- PRIx32 "\n", __func__, n, slb->tmp64, slb->tmp);
- if (slb_is_valid(slb)) {
- /* SLB entry is valid */
- mask = 0xFFFFFFFFF0000000ULL;
- if (slb->tmp & 0x8) {
- /* 16 MB PTEs */
- if (target_page_bits)
- *target_page_bits = 24;
- } else {
- /* 4 KB PTEs */
- if (target_page_bits)
- *target_page_bits = TARGET_PAGE_BITS;
- }
- if ((eaddr & mask) == (slb->tmp64 & mask)) {
- /* SLB match */
- *vsid = ((slb->tmp64 << 24) | (slb->tmp >> 8)) & 0x0003FFFFFFFFFFFFULL;
- *page_mask = ~mask;
- *attr = slb->tmp & 0xFF;
- ret = n;
- break;
+ ppc_slb_t *slb = &env->slb[n];
+
+ LOG_SLB("%s: slot %d %016" PRIx64 " %016"
+ PRIx64 "\n", __func__, n, slb->esid, slb->vsid);
+ if (slb->esid == esid) {
+ *vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT;
+ *page_mask = ~SEGMENT_MASK_256M;
+ *attr = slb->vsid & SLB_VSID_ATTR;
+ if (target_page_bits) {
+ *target_page_bits = (slb->vsid & SLB_VSID_L)
+ ? TARGET_PAGE_BITS_16M
+ : TARGET_PAGE_BITS;
}
+ return n;
}
}
- return ret;
+ return -5;
}
void ppc_slb_invalidate_all (CPUPPCState *env)
@@ -760,11 +711,10 @@ void ppc_slb_invalidate_all (CPUPPCState *env)
do_invalidate = 0;
/* XXX: Warning: slbia never invalidates the first segment */
for (n = 1; n < env->slb_nr; n++) {
- ppc_slb_t *slb = slb_get_entry(env, n);
+ ppc_slb_t *slb = &env->slb[n];
- if (slb_is_valid(slb)) {
- slb_invalidate(slb);
- slb_set_entry(env, n, slb);
+ if (slb->esid & SLB_ESID_V) {
+ slb->esid &= ~SLB_ESID_V;
/* XXX: given the fact that segment size is 256 MB or 1TB,
* and we still don't have a tlb_flush_mask(env, n, mask)
* in Qemu, we just invalidate all TLBs
@@ -781,68 +731,44 @@ void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0)
target_ulong vsid, page_mask;
int attr;
int n;
+ ppc_slb_t *slb;
n = slb_lookup(env, T0, &vsid, &page_mask, &attr, NULL);
- if (n >= 0) {
- ppc_slb_t *slb = slb_get_entry(env, n);
-
- if (slb_is_valid(slb)) {
- slb_invalidate(slb);
- slb_set_entry(env, n, slb);
- /* XXX: given the fact that segment size is 256 MB or 1TB,
- * and we still don't have a tlb_flush_mask(env, n, mask)
- * in Qemu, we just invalidate all TLBs
- */
- tlb_flush(env, 1);
- }
+ if (n < 0) {
+ return;
}
-}
-target_ulong ppc_load_slb (CPUPPCState *env, int slb_nr)
-{
- target_ulong rt;
- ppc_slb_t *slb = slb_get_entry(env, slb_nr);
+ slb = &env->slb[n];
- if (slb_is_valid(slb)) {
- /* SLB entry is valid */
- /* Copy SLB bits 62:88 to Rt 37:63 (VSID 23:49) */
- rt = slb->tmp >> 8; /* 65:88 => 40:63 */
- rt |= (slb->tmp64 & 0x7) << 24; /* 62:64 => 37:39 */
- /* Copy SLB bits 89:92 to Rt 33:36 (KsKpNL) */
- rt |= ((slb->tmp >> 4) & 0xF) << 27;
- } else {
- rt = 0;
- }
- LOG_SLB("%s: %016" PRIx64 " %08" PRIx32 " => %d "
- TARGET_FMT_lx "\n", __func__, slb->tmp64, slb->tmp, slb_nr, rt);
+ if (slb->esid & SLB_ESID_V) {
+ slb->esid &= ~SLB_ESID_V;
- return rt;
+ /* XXX: given the fact that segment size is 256 MB or 1TB,
+ * and we still don't have a tlb_flush_mask(env, n, mask)
+ * in Qemu, we just invalidate all TLBs
+ */
+ tlb_flush(env, 1);
+ }
}
-void ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs)
+int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs)
{
- ppc_slb_t *slb;
-
- uint64_t vsid;
- uint64_t esid;
- int flags, valid, slb_nr;
-
- vsid = rs >> 12;
- flags = ((rs >> 8) & 0xf);
+ int slot = rb & 0xfff;
+ uint64_t esid = rb & ~0xfff;
+ ppc_slb_t *slb = &env->slb[slot];
- esid = rb >> 28;
- valid = (rb & (1 << 27));
- slb_nr = rb & 0xfff;
+ if (slot >= env->slb_nr) {
+ return -1;
+ }
- slb = slb_get_entry(env, slb_nr);
- slb->tmp64 = (esid << 28) | valid | (vsid >> 24);
- slb->tmp = (vsid << 8) | (flags << 3);
+ slb->esid = esid;
+ slb->vsid = rs;
LOG_SLB("%s: %d " TARGET_FMT_lx " - " TARGET_FMT_lx " => %016" PRIx64
- " %08" PRIx32 "\n", __func__, slb_nr, rb, rs, slb->tmp64,
- slb->tmp);
+ " %016" PRIx64 "\n", __func__, slot, rb, rs,
+ slb->esid, slb->vsid);
- slb_set_entry(env, slb_nr, slb);
+ return 0;
}
#endif /* defined(TARGET_PPC64) */
@@ -860,24 +786,22 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
{
target_phys_addr_t sdr, hash, mask, sdr_mask, htab_mask;
target_ulong sr, vsid, vsid_mask, pgidx, page_mask;
-#if defined(TARGET_PPC64)
- int attr;
-#endif
int ds, vsid_sh, sdr_sh, pr, target_page_bits;
int ret, ret2;
pr = msr_pr;
#if defined(TARGET_PPC64)
if (env->mmu_model & POWERPC_MMU_64) {
+ int attr;
+
LOG_MMU("Check SLBs\n");
ret = slb_lookup(env, eaddr, &vsid, &page_mask, &attr,
&target_page_bits);
if (ret < 0)
return ret;
- ctx->key = ((attr & 0x40) && (pr != 0)) ||
- ((attr & 0x80) && (pr == 0)) ? 1 : 0;
+ ctx->key = !!(pr ? (attr & SLB_VSID_KP) : (attr & SLB_VSID_KS));
ds = 0;
- ctx->nx = attr & 0x10 ? 1 : 0;
+ ctx->nx = !!(attr & SLB_VSID_N);
ctx->eaddr = eaddr;
vsid_mask = 0x00003FFFFFFFFF80ULL;
vsid_sh = 7;