aboutsummaryrefslogtreecommitdiff
path: root/target-ppc
diff options
context:
space:
mode:
Diffstat (limited to 'target-ppc')
-rw-r--r--target-ppc/cpu.h7
-rw-r--r--target-ppc/helper.c132
-rw-r--r--target-ppc/translate_init.c2
3 files changed, 77 insertions, 64 deletions
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 1c0b753f88..77cf6de71e 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -344,6 +344,12 @@ union ppc_tlb_t {
ppcemb_tlb_t tlbe;
};
+typedef struct ppc_slb_t ppc_slb_t;
+struct ppc_slb_t {
+ uint64_t tmp64;
+ uint32_t tmp;
+};
+
/*****************************************************************************/
/* Machine state register bits definition */
#define MSR_SF 63 /* Sixty-four-bit mode hflags */
@@ -584,6 +590,7 @@ struct CPUPPCState {
/* Address space register */
target_ulong asr;
/* PowerPC 64 SLB area */
+ ppc_slb_t slb[64];
int slb_nr;
#endif
/* segment registers */
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index f2dc011206..73b091f826 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -693,14 +693,44 @@ static always_inline int find_pte (CPUState *env, mmu_ctx_t *ctx,
}
#if defined(TARGET_PPC64)
-static always_inline int slb_is_valid (uint64_t slb64)
+static ppc_slb_t *slb_get_entry(CPUPPCState *env, int nr)
{
- return slb64 & 0x0000000008000000ULL ? 1 : 0;
+ 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 always_inline int slb_is_valid (ppc_slb_t *slb)
+{
+ return (int)(slb->tmp64 & 0x0000000008000000ULL);
}
-static always_inline void slb_invalidate (uint64_t *slb64)
+static always_inline void slb_invalidate (ppc_slb_t *slb)
{
- *slb64 &= ~0x0000000008000000ULL;
+ slb->tmp64 &= ~0x0000000008000000ULL;
}
static always_inline int slb_lookup (CPUPPCState *env, target_ulong eaddr,
@@ -708,25 +738,20 @@ static always_inline int slb_lookup (CPUPPCState *env, target_ulong eaddr,
target_ulong *page_mask, int *attr,
int *target_page_bits)
{
- target_phys_addr_t sr_base;
target_ulong mask;
- uint64_t tmp64;
- uint32_t tmp;
int n, ret;
ret = -5;
- sr_base = env->spr[SPR_ASR];
- LOG_SLB("%s: eaddr " ADDRX " base " PADDRX "\n",
- __func__, eaddr, sr_base);
+ LOG_SLB("%s: eaddr " ADDRX "\n", __func__, eaddr);
mask = 0x0000000000000000ULL; /* Avoid gcc warning */
for (n = 0; n < env->slb_nr; n++) {
- tmp64 = ldq_phys(sr_base);
- tmp = ldl_phys(sr_base + 8);
- LOG_SLB("%s: seg %d " PADDRX " %016" PRIx64 " %08"
- PRIx32 "\n", __func__, n, sr_base, tmp64, tmp);
- if (slb_is_valid(tmp64)) {
+ 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 */
- if (tmp & 0x8) {
+ if (slb->tmp & 0x8) {
/* 1 TB Segment */
mask = 0xFFFF000000000000ULL;
if (target_page_bits)
@@ -737,16 +762,15 @@ static always_inline int slb_lookup (CPUPPCState *env, target_ulong eaddr,
if (target_page_bits)
*target_page_bits = TARGET_PAGE_BITS;
}
- if ((eaddr & mask) == (tmp64 & mask)) {
+ if ((eaddr & mask) == (slb->tmp64 & mask)) {
/* SLB match */
- *vsid = ((tmp64 << 24) | (tmp >> 8)) & 0x0003FFFFFFFFFFFFULL;
+ *vsid = ((slb->tmp64 << 24) | (slb->tmp >> 8)) & 0x0003FFFFFFFFFFFFULL;
*page_mask = ~mask;
- *attr = tmp & 0xFF;
+ *attr = slb->tmp & 0xFF;
ret = n;
break;
}
}
- sr_base += 12;
}
return ret;
@@ -754,25 +778,22 @@ static always_inline int slb_lookup (CPUPPCState *env, target_ulong eaddr,
void ppc_slb_invalidate_all (CPUPPCState *env)
{
- target_phys_addr_t sr_base;
- uint64_t tmp64;
int n, do_invalidate;
do_invalidate = 0;
- sr_base = env->spr[SPR_ASR];
/* XXX: Warning: slbia never invalidates the first segment */
for (n = 1; n < env->slb_nr; n++) {
- tmp64 = ldq_phys(sr_base);
- if (slb_is_valid(tmp64)) {
- slb_invalidate(&tmp64);
- stq_phys(sr_base, tmp64);
+ 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
*/
do_invalidate = 1;
}
- sr_base += 12;
}
if (do_invalidate)
tlb_flush(env, 1);
@@ -780,20 +801,17 @@ void ppc_slb_invalidate_all (CPUPPCState *env)
void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0)
{
- target_phys_addr_t sr_base;
target_ulong vsid, page_mask;
- uint64_t tmp64;
int attr;
int n;
n = slb_lookup(env, T0, &vsid, &page_mask, &attr, NULL);
if (n >= 0) {
- sr_base = env->spr[SPR_ASR];
- sr_base += 12 * n;
- tmp64 = ldq_phys(sr_base);
- if (slb_is_valid(tmp64)) {
- slb_invalidate(&tmp64);
- stq_phys(sr_base, tmp64);
+ 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
@@ -805,36 +823,28 @@ void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0)
target_ulong ppc_load_slb (CPUPPCState *env, int slb_nr)
{
- target_phys_addr_t sr_base;
target_ulong rt;
- uint64_t tmp64;
- uint32_t tmp;
-
- sr_base = env->spr[SPR_ASR];
- sr_base += 12 * slb_nr;
- tmp64 = ldq_phys(sr_base);
- tmp = ldl_phys(sr_base + 8);
- if (tmp64 & 0x0000000008000000ULL) {
+ ppc_slb_t *slb = slb_get_entry(env, slb_nr);
+
+ if (slb_is_valid(slb)) {
/* SLB entry is valid */
/* Copy SLB bits 62:88 to Rt 37:63 (VSID 23:49) */
- rt = tmp >> 8; /* 65:88 => 40:63 */
- rt |= (tmp64 & 0x7) << 24; /* 62:64 => 37:39 */
+ 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 |= ((tmp >> 4) & 0xF) << 27;
+ rt |= ((slb->tmp >> 4) & 0xF) << 27;
} else {
rt = 0;
}
- LOG_SLB("%s: " PADDRX " %016" PRIx64 " %08" PRIx32 " => %d "
- ADDRX "\n", __func__, sr_base, tmp64, tmp, slb_nr, rt);
+ LOG_SLB("%s: %016" PRIx64 " %08" PRIx32 " => %d "
+ ADDRX "\n", __func__, slb->tmp64, slb->tmp, slb_nr, rt);
return rt;
}
void ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs)
{
- target_phys_addr_t sr_base;
- uint64_t tmp64;
- uint32_t tmp;
+ ppc_slb_t *slb;
uint64_t vsid;
uint64_t esid;
@@ -847,19 +857,15 @@ void ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs)
valid = (rb & (1 << 27));
slb_nr = rb & 0xfff;
- tmp64 = (esid << 28) | valid | (vsid >> 24);
- tmp = (vsid << 8) | (flags << 3);
-
- /* Write SLB entry to memory */
- sr_base = env->spr[SPR_ASR];
- sr_base += 12 * slb_nr;
+ slb = slb_get_entry(env, slb_nr);
+ slb->tmp64 = (esid << 28) | valid | (vsid >> 24);
+ slb->tmp = (vsid << 8) | (flags << 3);
- LOG_SLB("%s: %d " ADDRX " - " ADDRX " => " PADDRX " %016" PRIx64
+ LOG_SLB("%s: %d " ADDRX " - " ADDRX " => %016" PRIx64
" %08" PRIx32 "\n", __func__,
- slb_nr, rb, rs, sr_base, tmp64, tmp);
+ slb_nr, rb, rs, tmp64, tmp);
- stq_phys(sr_base, tmp64);
- stl_phys(sr_base + 8, tmp);
+ slb_set_entry(env, slb_nr, slb);
}
#endif /* defined(TARGET_PPC64) */
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 42e62be292..2fa65153f2 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -6056,7 +6056,7 @@ static void init_proc_970FX (CPUPPCState *env)
&spr_read_generic, &spr_write_generic,
0x00000000);
#if !defined(CONFIG_USER_ONLY)
- env->slb_nr = 32;
+ env->slb_nr = 64;
#endif
init_excp_970(env);
env->dcache_line_size = 128;