PPC: Implement e500 (FSL) MMU

Most of the code to support e500 style MMUs is already in place, but
we're missing on some of the special TLB0-TLB1 handling code and slightly
different TLB modification.

This patch adds support for the FSL style MMU.

Signed-off-by: Alexander Graf <agraf@suse.de>
This commit is contained in:
Alexander Graf 2011-04-30 23:34:58 +02:00
parent a5858d7af0
commit 01662f3e51
6 changed files with 1022 additions and 115 deletions

View File

@ -108,8 +108,8 @@ enum powerpc_mmu_t {
POWERPC_MMU_MPC8xx = 0x00000007, POWERPC_MMU_MPC8xx = 0x00000007,
/* BookE MMU model */ /* BookE MMU model */
POWERPC_MMU_BOOKE = 0x00000008, POWERPC_MMU_BOOKE = 0x00000008,
/* BookE FSL MMU model */ /* BookE 2.06 MMU model */
POWERPC_MMU_BOOKE_FSL = 0x00000009, POWERPC_MMU_BOOKE206 = 0x00000009,
/* PowerPC 601 MMU model (specific BATs format) */ /* PowerPC 601 MMU model (specific BATs format) */
POWERPC_MMU_601 = 0x0000000A, POWERPC_MMU_601 = 0x0000000A,
#if defined(TARGET_PPC64) #if defined(TARGET_PPC64)
@ -607,6 +607,224 @@ enum {
#define vscr_nj (((env->vscr) >> VSCR_NJ) & 0x1) #define vscr_nj (((env->vscr) >> VSCR_NJ) & 0x1)
#define vscr_sat (((env->vscr) >> VSCR_SAT) & 0x1) #define vscr_sat (((env->vscr) >> VSCR_SAT) & 0x1)
/*****************************************************************************/
/* BookE e500 MMU registers */
#define MAS0_NV_SHIFT 0
#define MAS0_NV_MASK (0xfff << MAS0_NV_SHIFT)
#define MAS0_WQ_SHIFT 12
#define MAS0_WQ_MASK (3 << MAS0_WQ_SHIFT)
/* Write TLB entry regardless of reservation */
#define MAS0_WQ_ALWAYS (0 << MAS0_WQ_SHIFT)
/* Write TLB entry only already in use */
#define MAS0_WQ_COND (1 << MAS0_WQ_SHIFT)
/* Clear TLB entry */
#define MAS0_WQ_CLR_RSRV (2 << MAS0_WQ_SHIFT)
#define MAS0_HES_SHIFT 14
#define MAS0_HES (1 << MAS0_HES_SHIFT)
#define MAS0_ESEL_SHIFT 16
#define MAS0_ESEL_MASK (0xfff << MAS0_ESEL_SHIFT)
#define MAS0_TLBSEL_SHIFT 28
#define MAS0_TLBSEL_MASK (3 << MAS0_TLBSEL_SHIFT)
#define MAS0_TLBSEL_TLB0 (0 << MAS0_TLBSEL_SHIFT)
#define MAS0_TLBSEL_TLB1 (1 << MAS0_TLBSEL_SHIFT)
#define MAS0_TLBSEL_TLB2 (2 << MAS0_TLBSEL_SHIFT)
#define MAS0_TLBSEL_TLB3 (3 << MAS0_TLBSEL_SHIFT)
#define MAS0_ATSEL_SHIFT 31
#define MAS0_ATSEL (1 << MAS0_ATSEL_SHIFT)
#define MAS0_ATSEL_TLB 0
#define MAS0_ATSEL_LRAT MAS0_ATSEL
#define MAS1_TSIZE_SHIFT 8
#define MAS1_TSIZE_MASK (0xf << MAS1_TSIZE_SHIFT)
#define MAS1_TS_SHIFT 12
#define MAS1_TS (1 << MAS1_TS_SHIFT)
#define MAS1_IND_SHIFT 13
#define MAS1_IND (1 << MAS1_IND_SHIFT)
#define MAS1_TID_SHIFT 16
#define MAS1_TID_MASK (0x3fff << MAS1_TID_SHIFT)
#define MAS1_IPROT_SHIFT 30
#define MAS1_IPROT (1 << MAS1_IPROT_SHIFT)
#define MAS1_VALID_SHIFT 31
#define MAS1_VALID 0x80000000
#define MAS2_EPN_SHIFT 12
#define MAS2_EPN_MASK (0xfffff << MAS2_EPN_SHIFT)
#define MAS2_ACM_SHIFT 6
#define MAS2_ACM (1 << MAS2_ACM_SHIFT)
#define MAS2_VLE_SHIFT 5
#define MAS2_VLE (1 << MAS2_VLE_SHIFT)
#define MAS2_W_SHIFT 4
#define MAS2_W (1 << MAS2_W_SHIFT)
#define MAS2_I_SHIFT 3
#define MAS2_I (1 << MAS2_I_SHIFT)
#define MAS2_M_SHIFT 2
#define MAS2_M (1 << MAS2_M_SHIFT)
#define MAS2_G_SHIFT 1
#define MAS2_G (1 << MAS2_G_SHIFT)
#define MAS2_E_SHIFT 0
#define MAS2_E (1 << MAS2_E_SHIFT)
#define MAS3_RPN_SHIFT 12
#define MAS3_RPN_MASK (0xfffff << MAS3_RPN_SHIFT)
#define MAS3_U0 0x00000200
#define MAS3_U1 0x00000100
#define MAS3_U2 0x00000080
#define MAS3_U3 0x00000040
#define MAS3_UX 0x00000020
#define MAS3_SX 0x00000010
#define MAS3_UW 0x00000008
#define MAS3_SW 0x00000004
#define MAS3_UR 0x00000002
#define MAS3_SR 0x00000001
#define MAS3_SPSIZE_SHIFT 1
#define MAS3_SPSIZE_MASK (0x3e << MAS3_SPSIZE_SHIFT)
#define MAS4_TLBSELD_SHIFT MAS0_TLBSEL_SHIFT
#define MAS4_TLBSELD_MASK MAS0_TLBSEL_MASK
#define MAS4_TIDSELD_MASK 0x00030000
#define MAS4_TIDSELD_PID0 0x00000000
#define MAS4_TIDSELD_PID1 0x00010000
#define MAS4_TIDSELD_PID2 0x00020000
#define MAS4_TIDSELD_PIDZ 0x00030000
#define MAS4_INDD 0x00008000 /* Default IND */
#define MAS4_TSIZED_SHIFT MAS1_TSIZE_SHIFT
#define MAS4_TSIZED_MASK MAS1_TSIZE_MASK
#define MAS4_ACMD 0x00000040
#define MAS4_VLED 0x00000020
#define MAS4_WD 0x00000010
#define MAS4_ID 0x00000008
#define MAS4_MD 0x00000004
#define MAS4_GD 0x00000002
#define MAS4_ED 0x00000001
#define MAS4_WIMGED_MASK 0x0000001f /* Default WIMGE */
#define MAS4_WIMGED_SHIFT 0
#define MAS5_SGS 0x80000000
#define MAS5_SLPID_MASK 0x00000fff
#define MAS6_SPID0 0x3fff0000
#define MAS6_SPID1 0x00007ffe
#define MAS6_ISIZE(x) MAS1_TSIZE(x)
#define MAS6_SAS 0x00000001
#define MAS6_SPID MAS6_SPID0
#define MAS6_SIND 0x00000002 /* Indirect page */
#define MAS6_SIND_SHIFT 1
#define MAS6_SPID_MASK 0x3fff0000
#define MAS6_SPID_SHIFT 16
#define MAS6_ISIZE_MASK 0x00000f80
#define MAS6_ISIZE_SHIFT 7
#define MAS7_RPN 0xffffffff
#define MAS8_TGS 0x80000000
#define MAS8_VF 0x40000000
#define MAS8_TLBPID 0x00000fff
/* Bit definitions for MMUCFG */
#define MMUCFG_MAVN 0x00000003 /* MMU Architecture Version Number */
#define MMUCFG_MAVN_V1 0x00000000 /* v1.0 */
#define MMUCFG_MAVN_V2 0x00000001 /* v2.0 */
#define MMUCFG_NTLBS 0x0000000c /* Number of TLBs */
#define MMUCFG_PIDSIZE 0x000007c0 /* PID Reg Size */
#define MMUCFG_TWC 0x00008000 /* TLB Write Conditional (v2.0) */
#define MMUCFG_LRAT 0x00010000 /* LRAT Supported (v2.0) */
#define MMUCFG_RASIZE 0x00fe0000 /* Real Addr Size */
#define MMUCFG_LPIDSIZE 0x0f000000 /* LPID Reg Size */
/* Bit definitions for MMUCSR0 */
#define MMUCSR0_TLB1FI 0x00000002 /* TLB1 Flash invalidate */
#define MMUCSR0_TLB0FI 0x00000004 /* TLB0 Flash invalidate */
#define MMUCSR0_TLB2FI 0x00000040 /* TLB2 Flash invalidate */
#define MMUCSR0_TLB3FI 0x00000020 /* TLB3 Flash invalidate */
#define MMUCSR0_TLBFI (MMUCSR0_TLB0FI | MMUCSR0_TLB1FI | \
MMUCSR0_TLB2FI | MMUCSR0_TLB3FI)
#define MMUCSR0_TLB0PS 0x00000780 /* TLB0 Page Size */
#define MMUCSR0_TLB1PS 0x00007800 /* TLB1 Page Size */
#define MMUCSR0_TLB2PS 0x00078000 /* TLB2 Page Size */
#define MMUCSR0_TLB3PS 0x00780000 /* TLB3 Page Size */
/* TLBnCFG encoding */
#define TLBnCFG_N_ENTRY 0x00000fff /* number of entries */
#define TLBnCFG_HES 0x00002000 /* HW select supported */
#define TLBnCFG_AVAIL 0x00004000 /* variable page size */
#define TLBnCFG_IPROT 0x00008000 /* IPROT supported */
#define TLBnCFG_GTWE 0x00010000 /* Guest can write */
#define TLBnCFG_IND 0x00020000 /* IND entries supported */
#define TLBnCFG_PT 0x00040000 /* Can load from page table */
#define TLBnCFG_MINSIZE 0x00f00000 /* Minimum Page Size (v1.0) */
#define TLBnCFG_MINSIZE_SHIFT 20
#define TLBnCFG_MAXSIZE 0x000f0000 /* Maximum Page Size (v1.0) */
#define TLBnCFG_MAXSIZE_SHIFT 16
#define TLBnCFG_ASSOC 0xff000000 /* Associativity */
#define TLBnCFG_ASSOC_SHIFT 24
/* TLBnPS encoding */
#define TLBnPS_4K 0x00000004
#define TLBnPS_8K 0x00000008
#define TLBnPS_16K 0x00000010
#define TLBnPS_32K 0x00000020
#define TLBnPS_64K 0x00000040
#define TLBnPS_128K 0x00000080
#define TLBnPS_256K 0x00000100
#define TLBnPS_512K 0x00000200
#define TLBnPS_1M 0x00000400
#define TLBnPS_2M 0x00000800
#define TLBnPS_4M 0x00001000
#define TLBnPS_8M 0x00002000
#define TLBnPS_16M 0x00004000
#define TLBnPS_32M 0x00008000
#define TLBnPS_64M 0x00010000
#define TLBnPS_128M 0x00020000
#define TLBnPS_256M 0x00040000
#define TLBnPS_512M 0x00080000
#define TLBnPS_1G 0x00100000
#define TLBnPS_2G 0x00200000
#define TLBnPS_4G 0x00400000
#define TLBnPS_8G 0x00800000
#define TLBnPS_16G 0x01000000
#define TLBnPS_32G 0x02000000
#define TLBnPS_64G 0x04000000
#define TLBnPS_128G 0x08000000
#define TLBnPS_256G 0x10000000
/* tlbilx action encoding */
#define TLBILX_T_ALL 0
#define TLBILX_T_TID 1
#define TLBILX_T_FULLMATCH 3
#define TLBILX_T_CLASS0 4
#define TLBILX_T_CLASS1 5
#define TLBILX_T_CLASS2 6
#define TLBILX_T_CLASS3 7
/* BookE 2.06 helper defines */
#define BOOKE206_FLUSH_TLB0 (1 << 0)
#define BOOKE206_FLUSH_TLB1 (1 << 1)
#define BOOKE206_FLUSH_TLB2 (1 << 2)
#define BOOKE206_FLUSH_TLB3 (1 << 3)
/* number of possible TLBs */
#define BOOKE206_MAX_TLBN 4
/*****************************************************************************/ /*****************************************************************************/
/* The whole PowerPC CPU context */ /* The whole PowerPC CPU context */
#define NB_MMU_MODES 3 #define NB_MMU_MODES 3
@ -678,7 +896,7 @@ struct CPUPPCState {
int nb_BATs; int nb_BATs;
target_ulong DBAT[2][8]; target_ulong DBAT[2][8];
target_ulong IBAT[2][8]; target_ulong IBAT[2][8];
/* PowerPC TLB registers (for 4xx and 60x software driven TLBs) */ /* PowerPC TLB registers (for 4xx, e500 and 60x software driven TLBs) */
int nb_tlb; /* Total number of TLB */ int nb_tlb; /* Total number of TLB */
int tlb_per_way; /* Speed-up helper: used to avoid divisions at run time */ int tlb_per_way; /* Speed-up helper: used to avoid divisions at run time */
int nb_ways; /* Number of ways in the TLB set */ int nb_ways; /* Number of ways in the TLB set */
@ -856,6 +1074,10 @@ void store_40x_dbcr0 (CPUPPCState *env, uint32_t val);
void store_40x_sler (CPUPPCState *env, uint32_t val); void store_40x_sler (CPUPPCState *env, uint32_t val);
void store_booke_tcr (CPUPPCState *env, target_ulong val); void store_booke_tcr (CPUPPCState *env, target_ulong val);
void store_booke_tsr (CPUPPCState *env, target_ulong val); void store_booke_tsr (CPUPPCState *env, target_ulong val);
void booke206_flush_tlb(CPUState *env, int flags, const int check_iprot);
int ppcemb_tlb_check(CPUState *env, ppcemb_tlb_t *tlb,
target_phys_addr_t *raddrp, target_ulong address,
uint32_t pid, int ext, int i);
void ppc_tlb_invalidate_all (CPUPPCState *env); void ppc_tlb_invalidate_all (CPUPPCState *env);
void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr); void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr);
#if defined(TARGET_PPC64) #if defined(TARGET_PPC64)
@ -1547,6 +1769,11 @@ enum {
PPC_DCRUX = 0x4000000000000000ULL, PPC_DCRUX = 0x4000000000000000ULL,
/* popcntw and popcntd instructions */ /* popcntw and popcntd instructions */
PPC_POPCNTWD = 0x8000000000000000ULL, PPC_POPCNTWD = 0x8000000000000000ULL,
/* extended type values */
/* BookE 2.06 PowerPC specification */
PPC2_BOOKE206 = 0x0000000000000001ULL,
}; };
/*****************************************************************************/ /*****************************************************************************/
@ -1699,6 +1926,77 @@ static inline void cpu_set_tls(CPUState *env, target_ulong newtls)
#endif #endif
} }
#if !defined(CONFIG_USER_ONLY)
static inline int booke206_tlbe_id(CPUState *env, ppcemb_tlb_t *tlbe)
{
ulong tlbel = (ulong)tlbe;
ulong tlbl = (ulong)env->tlb;
return (tlbel - tlbl) / sizeof(env->tlb[0]);
}
static inline int booke206_tlb_size(CPUState *env, int tlbn)
{
uint32_t tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
int r = tlbncfg & TLBnCFG_N_ENTRY;
return r;
}
static inline int booke206_tlb_ways(CPUState *env, int tlbn)
{
uint32_t tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
int r = tlbncfg >> TLBnCFG_ASSOC_SHIFT;
return r;
}
static inline int booke206_tlbe_to_tlbn(CPUState *env, ppcemb_tlb_t *tlbe)
{
int id = booke206_tlbe_id(env, tlbe);
int end = 0;
int i;
for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
end += booke206_tlb_size(env, i);
if (id < end) {
return i;
}
}
cpu_abort(env, "Unknown TLBe: %d\n", id);
return 0;
}
static inline int booke206_tlbe_to_way(CPUState *env, ppcemb_tlb_t *tlb)
{
int tlbn = booke206_tlbe_to_tlbn(env, tlb);
int tlbid = booke206_tlbe_id(env, tlb);
return tlbid & (booke206_tlb_ways(env, tlbn) - 1);
}
static inline ppcemb_tlb_t *booke206_get_tlbe(CPUState *env, const int tlbn,
target_ulong ea, int way)
{
int r;
uint32_t ways = booke206_tlb_ways(env, tlbn);
int ways_bits = ffs(ways) - 1;
int tlb_bits = ffs(booke206_tlb_size(env, tlbn)) - 1;
int i;
way &= ways - 1;
ea >>= MAS2_EPN_SHIFT;
ea &= (1 << (tlb_bits - ways_bits)) - 1;
r = (ea << ways_bits) | way;
/* bump up to tlbn index */
for (i = 0; i < tlbn; i++) {
r += booke206_tlb_size(env, i);
}
return &env->tlb[r].tlbe;
}
#endif
extern void (*cpu_ppc_hypercall)(CPUState *); extern void (*cpu_ppc_hypercall)(CPUState *);
#endif /* !defined (__CPU_PPC_H__) */ #endif /* !defined (__CPU_PPC_H__) */

View File

@ -993,10 +993,10 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
} }
/* Generic TLB check function for embedded PowerPC implementations */ /* Generic TLB check function for embedded PowerPC implementations */
static inline int ppcemb_tlb_check(CPUState *env, ppcemb_tlb_t *tlb, int ppcemb_tlb_check(CPUState *env, ppcemb_tlb_t *tlb,
target_phys_addr_t *raddrp, target_phys_addr_t *raddrp,
target_ulong address, uint32_t pid, int ext, target_ulong address, uint32_t pid, int ext,
int i) int i)
{ {
target_ulong mask; target_ulong mask;
@ -1006,8 +1006,8 @@ static inline int ppcemb_tlb_check(CPUState *env, ppcemb_tlb_t *tlb,
} }
mask = ~(tlb->size - 1); mask = ~(tlb->size - 1);
LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx
" " TARGET_FMT_lx " %u\n", __func__, i, address, pid, tlb->EPN, " " TARGET_FMT_lx " %u %x\n", __func__, i, address, pid, tlb->EPN,
mask, (uint32_t)tlb->PID); mask, (uint32_t)tlb->PID, tlb->prot);
/* Check PID */ /* Check PID */
if (tlb->PID != 0 && tlb->PID != pid) if (tlb->PID != 0 && tlb->PID != pid)
return -1; return -1;
@ -1153,48 +1153,164 @@ void store_40x_sler (CPUPPCState *env, uint32_t val)
env->spr[SPR_405_SLER] = val; env->spr[SPR_405_SLER] = val;
} }
static inline int mmubooke_check_tlb (CPUState *env, ppcemb_tlb_t *tlb,
target_phys_addr_t *raddr, int *prot,
target_ulong address, int rw,
int access_type, int i)
{
int ret, _prot;
if (ppcemb_tlb_check(env, tlb, raddr, address,
env->spr[SPR_BOOKE_PID],
!env->nb_pids, i) >= 0) {
goto found_tlb;
}
if (env->spr[SPR_BOOKE_PID1] &&
ppcemb_tlb_check(env, tlb, raddr, address,
env->spr[SPR_BOOKE_PID1], 0, i) >= 0) {
goto found_tlb;
}
if (env->spr[SPR_BOOKE_PID2] &&
ppcemb_tlb_check(env, tlb, raddr, address,
env->spr[SPR_BOOKE_PID2], 0, i) >= 0) {
goto found_tlb;
}
LOG_SWTLB("%s: TLB entry not found\n", __func__);
return -1;
found_tlb:
if (msr_pr != 0) {
_prot = tlb->prot & 0xF;
} else {
_prot = (tlb->prot >> 4) & 0xF;
}
/* Check the address space */
if (access_type == ACCESS_CODE) {
if (msr_ir != (tlb->attr & 1)) {
LOG_SWTLB("%s: AS doesn't match\n", __func__);
return -1;
}
*prot = _prot;
if (_prot & PAGE_EXEC) {
LOG_SWTLB("%s: good TLB!\n", __func__);
return 0;
}
LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, _prot);
ret = -3;
} else {
if (msr_dr != (tlb->attr & 1)) {
LOG_SWTLB("%s: AS doesn't match\n", __func__);
return -1;
}
*prot = _prot;
if ((!rw && _prot & PAGE_READ) || (rw && (_prot & PAGE_WRITE))) {
LOG_SWTLB("%s: found TLB!\n", __func__);
return 0;
}
LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, _prot);
ret = -2;
}
return ret;
}
static int mmubooke_get_physical_address (CPUState *env, mmu_ctx_t *ctx, static int mmubooke_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
target_ulong address, int rw, target_ulong address, int rw,
int access_type) int access_type)
{ {
ppcemb_tlb_t *tlb; ppcemb_tlb_t *tlb;
target_phys_addr_t raddr; target_phys_addr_t raddr;
int i, prot, ret; int i, ret;
ret = -1; ret = -1;
raddr = (target_phys_addr_t)-1ULL; raddr = (target_phys_addr_t)-1ULL;
for (i = 0; i < env->nb_tlb; i++) { for (i = 0; i < env->nb_tlb; i++) {
tlb = &env->tlb[i].tlbe; tlb = &env->tlb[i].tlbe;
if (ppcemb_tlb_check(env, tlb, &raddr, address, ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
env->spr[SPR_BOOKE_PID], 1, i) < 0) access_type, i);
continue; if (!ret) {
if (msr_pr != 0) break;
prot = tlb->prot & 0xF;
else
prot = (tlb->prot >> 4) & 0xF;
/* Check the address space */
if (access_type == ACCESS_CODE) {
if (msr_ir != (tlb->attr & 1))
continue;
ctx->prot = prot;
if (prot & PAGE_EXEC) {
ret = 0;
break;
}
ret = -3;
} else {
if (msr_dr != (tlb->attr & 1))
continue;
ctx->prot = prot;
if ((!rw && prot & PAGE_READ) || (rw && (prot & PAGE_WRITE))) {
ret = 0;
break;
}
ret = -2;
} }
} }
if (ret >= 0)
if (ret >= 0) {
ctx->raddr = raddr; ctx->raddr = raddr;
LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
" %d %d\n", __func__, address, ctx->raddr, ctx->prot,
ret);
} else {
LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
" %d %d\n", __func__, address, raddr, ctx->prot, ret);
}
return ret;
}
void booke206_flush_tlb(CPUState *env, int flags, const int check_iprot)
{
int tlb_size;
int i, j;
ppc_tlb_t *tlb = env->tlb;
for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
if (flags & (1 << i)) {
tlb_size = booke206_tlb_size(env, i);
for (j = 0; j < tlb_size; j++) {
if (!check_iprot || !(tlb[j].tlbe.attr & MAS1_IPROT)) {
tlb[j].tlbe.prot = 0;
}
}
}
tlb += booke206_tlb_size(env, i);
}
tlb_flush(env, 1);
}
static int mmubooke206_get_physical_address(CPUState *env, mmu_ctx_t *ctx,
target_ulong address, int rw,
int access_type)
{
ppcemb_tlb_t *tlb;
target_phys_addr_t raddr;
int i, j, ret;
ret = -1;
raddr = (target_phys_addr_t)-1ULL;
for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
int ways = booke206_tlb_ways(env, i);
for (j = 0; j < ways; j++) {
tlb = booke206_get_tlbe(env, i, address, j);
ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
access_type, j);
if (ret != -1) {
goto found_tlb;
}
}
}
found_tlb:
if (ret >= 0) {
ctx->raddr = raddr;
LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
" %d %d\n", __func__, address, ctx->raddr, ctx->prot,
ret);
} else {
LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
" %d %d\n", __func__, address, raddr, ctx->prot, ret);
}
return ret; return ret;
} }
@ -1254,9 +1370,8 @@ static inline int check_physical(CPUState *env, mmu_ctx_t *ctx,
/* XXX: TODO */ /* XXX: TODO */
cpu_abort(env, "MPC8xx MMU model is not implemented\n"); cpu_abort(env, "MPC8xx MMU model is not implemented\n");
break; break;
case POWERPC_MMU_BOOKE_FSL: case POWERPC_MMU_BOOKE206:
/* XXX: TODO */ cpu_abort(env, "BookE 2.06 MMU doesn't have physical real mode\n");
cpu_abort(env, "BookE FSL MMU model not implemented\n");
break; break;
default: default:
cpu_abort(env, "Unknown or invalid MMU model\n"); cpu_abort(env, "Unknown or invalid MMU model\n");
@ -1281,6 +1396,9 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
IS and DS bits only affect the address space. */ IS and DS bits only affect the address space. */
ret = mmubooke_get_physical_address(env, ctx, eaddr, ret = mmubooke_get_physical_address(env, ctx, eaddr,
rw, access_type); rw, access_type);
} else if (env->mmu_model == POWERPC_MMU_BOOKE206) {
ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
access_type);
} else { } else {
/* No address translation. */ /* No address translation. */
ret = check_physical(env, ctx, eaddr, rw); ret = check_physical(env, ctx, eaddr, rw);
@ -1314,14 +1432,14 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
ret = mmubooke_get_physical_address(env, ctx, eaddr, ret = mmubooke_get_physical_address(env, ctx, eaddr,
rw, access_type); rw, access_type);
break; break;
case POWERPC_MMU_BOOKE206:
ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
access_type);
break;
case POWERPC_MMU_MPC8xx: case POWERPC_MMU_MPC8xx:
/* XXX: TODO */ /* XXX: TODO */
cpu_abort(env, "MPC8xx MMU model is not implemented\n"); cpu_abort(env, "MPC8xx MMU model is not implemented\n");
break; break;
case POWERPC_MMU_BOOKE_FSL:
/* XXX: TODO */
cpu_abort(env, "BookE FSL MMU model not implemented\n");
return -1;
case POWERPC_MMU_REAL: case POWERPC_MMU_REAL:
cpu_abort(env, "PowerPC in real mode do not do any translation\n"); cpu_abort(env, "PowerPC in real mode do not do any translation\n");
return -1; return -1;
@ -1348,6 +1466,46 @@ target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
return ctx.raddr & TARGET_PAGE_MASK; return ctx.raddr & TARGET_PAGE_MASK;
} }
static void booke206_update_mas_tlb_miss(CPUState *env, target_ulong address,
int rw)
{
env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
env->spr[SPR_BOOKE_MAS3] = 0;
env->spr[SPR_BOOKE_MAS6] = 0;
env->spr[SPR_BOOKE_MAS7] = 0;
/* AS */
if (((rw == 2) && msr_ir) || ((rw != 2) && msr_dr)) {
env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
}
env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
case MAS4_TIDSELD_PID0:
env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID] << MAS1_TID_SHIFT;
break;
case MAS4_TIDSELD_PID1:
env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID1] << MAS1_TID_SHIFT;
break;
case MAS4_TIDSELD_PID2:
env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID2] << MAS1_TID_SHIFT;
break;
}
env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
/* next victim logic */
env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
env->last_way++;
env->last_way &= booke206_tlb_ways(env, 0) - 1;
env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
}
/* Perform address translation */ /* Perform address translation */
int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
int mmu_idx, int is_softmmu) int mmu_idx, int is_softmmu)
@ -1403,15 +1561,14 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
env->exception_index = POWERPC_EXCP_ISI; env->exception_index = POWERPC_EXCP_ISI;
env->error_code = 0x40000000; env->error_code = 0x40000000;
break; break;
case POWERPC_MMU_BOOKE206:
booke206_update_mas_tlb_miss(env, address, rw);
/* fall through */
case POWERPC_MMU_BOOKE: case POWERPC_MMU_BOOKE:
env->exception_index = POWERPC_EXCP_ITLB; env->exception_index = POWERPC_EXCP_ITLB;
env->error_code = 0; env->error_code = 0;
env->spr[SPR_BOOKE_DEAR] = address; env->spr[SPR_BOOKE_DEAR] = address;
return -1; return -1;
case POWERPC_MMU_BOOKE_FSL:
/* XXX: TODO */
cpu_abort(env, "BookE FSL MMU model is not implemented\n");
return -1;
case POWERPC_MMU_MPC8xx: case POWERPC_MMU_MPC8xx:
/* XXX: TODO */ /* XXX: TODO */
cpu_abort(env, "MPC8xx MMU model is not implemented\n"); cpu_abort(env, "MPC8xx MMU model is not implemented\n");
@ -1432,7 +1589,8 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
break; break;
case -3: case -3:
/* No execute protection violation */ /* No execute protection violation */
if (env->mmu_model == POWERPC_MMU_BOOKE) { if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
(env->mmu_model == POWERPC_MMU_BOOKE206)) {
env->spr[SPR_BOOKE_ESR] = 0x00000000; env->spr[SPR_BOOKE_ESR] = 0x00000000;
} }
env->exception_index = POWERPC_EXCP_ISI; env->exception_index = POWERPC_EXCP_ISI;
@ -1522,16 +1680,15 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
/* XXX: TODO */ /* XXX: TODO */
cpu_abort(env, "MPC8xx MMU model is not implemented\n"); cpu_abort(env, "MPC8xx MMU model is not implemented\n");
break; break;
case POWERPC_MMU_BOOKE206:
booke206_update_mas_tlb_miss(env, address, rw);
/* fall through */
case POWERPC_MMU_BOOKE: case POWERPC_MMU_BOOKE:
env->exception_index = POWERPC_EXCP_DTLB; env->exception_index = POWERPC_EXCP_DTLB;
env->error_code = 0; env->error_code = 0;
env->spr[SPR_BOOKE_DEAR] = address; env->spr[SPR_BOOKE_DEAR] = address;
env->spr[SPR_BOOKE_ESR] = rw ? 1 << ESR_ST : 0; env->spr[SPR_BOOKE_ESR] = rw ? 1 << ESR_ST : 0;
return -1; return -1;
case POWERPC_MMU_BOOKE_FSL:
/* XXX: TODO */
cpu_abort(env, "BookE FSL MMU model is not implemented\n");
return -1;
case POWERPC_MMU_REAL: case POWERPC_MMU_REAL:
cpu_abort(env, "PowerPC in real mode should never raise " cpu_abort(env, "PowerPC in real mode should never raise "
"any MMU exceptions\n"); "any MMU exceptions\n");
@ -1551,7 +1708,8 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
if (rw) { if (rw) {
env->spr[SPR_40x_ESR] |= 0x00800000; env->spr[SPR_40x_ESR] |= 0x00800000;
} }
} else if (env->mmu_model == POWERPC_MMU_BOOKE) { } else if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
(env->mmu_model == POWERPC_MMU_BOOKE206)) {
env->spr[SPR_BOOKE_DEAR] = address; env->spr[SPR_BOOKE_DEAR] = address;
env->spr[SPR_BOOKE_ESR] = rw ? 1 << ESR_ST : 0; env->spr[SPR_BOOKE_ESR] = rw ? 1 << ESR_ST : 0;
} else { } else {
@ -1822,10 +1980,8 @@ void ppc_tlb_invalidate_all (CPUPPCState *env)
case POWERPC_MMU_BOOKE: case POWERPC_MMU_BOOKE:
tlb_flush(env, 1); tlb_flush(env, 1);
break; break;
case POWERPC_MMU_BOOKE_FSL: case POWERPC_MMU_BOOKE206:
/* XXX: TODO */ booke206_flush_tlb(env, -1, 0);
if (!kvm_enabled())
cpu_abort(env, "BookE MMU model is not implemented\n");
break; break;
case POWERPC_MMU_32B: case POWERPC_MMU_32B:
case POWERPC_MMU_601: case POWERPC_MMU_601:
@ -1869,9 +2025,9 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
/* XXX: TODO */ /* XXX: TODO */
cpu_abort(env, "BookE MMU model is not implemented\n"); cpu_abort(env, "BookE MMU model is not implemented\n");
break; break;
case POWERPC_MMU_BOOKE_FSL: case POWERPC_MMU_BOOKE206:
/* XXX: TODO */ /* XXX: TODO */
cpu_abort(env, "BookE FSL MMU model is not implemented\n"); cpu_abort(env, "BookE 2.06 MMU model is not implemented\n");
break; break;
case POWERPC_MMU_32B: case POWERPC_MMU_32B:
case POWERPC_MMU_601: case POWERPC_MMU_601:
@ -2589,7 +2745,8 @@ static inline void powerpc_excp(CPUState *env, int excp_model, int excp)
env->exception_index = POWERPC_EXCP_NONE; env->exception_index = POWERPC_EXCP_NONE;
env->error_code = 0; env->error_code = 0;
if (env->mmu_model == POWERPC_MMU_BOOKE) { if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
(env->mmu_model == POWERPC_MMU_BOOKE206)) {
/* XXX: The BookE changes address space when switching modes, /* XXX: The BookE changes address space when switching modes,
we should probably implement that as different MMU indexes, we should probably implement that as different MMU indexes,
but for the moment we do it the slow way and flush all. */ but for the moment we do it the slow way and flush all. */

View File

@ -334,6 +334,12 @@ DEF_HELPER_1(4xx_tlbsx, tl, tl)
DEF_HELPER_2(440_tlbre, tl, i32, tl) DEF_HELPER_2(440_tlbre, tl, i32, tl)
DEF_HELPER_3(440_tlbwe, void, i32, tl, tl) DEF_HELPER_3(440_tlbwe, void, i32, tl, tl)
DEF_HELPER_1(440_tlbsx, tl, tl) DEF_HELPER_1(440_tlbsx, tl, tl)
DEF_HELPER_0(booke206_tlbre, void)
DEF_HELPER_0(booke206_tlbwe, void)
DEF_HELPER_1(booke206_tlbsx, void, tl)
DEF_HELPER_1(booke206_tlbivax, void, tl)
DEF_HELPER_1(booke206_tlbflush, void, i32)
DEF_HELPER_2(booke_setpid, void, i32, tl)
DEF_HELPER_1(6xx_tlbd, void, tl) DEF_HELPER_1(6xx_tlbd, void, tl)
DEF_HELPER_1(6xx_tlbi, void, tl) DEF_HELPER_1(6xx_tlbi, void, tl)
DEF_HELPER_1(74xx_tlbd, void, tl) DEF_HELPER_1(74xx_tlbd, void, tl)

View File

@ -4206,4 +4206,300 @@ target_ulong helper_440_tlbsx (target_ulong address)
return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF); return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
} }
/* PowerPC BookE 2.06 TLB management */
static ppcemb_tlb_t *booke206_cur_tlb(CPUState *env)
{
uint32_t tlbncfg = 0;
int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
int tlb;
tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
cpu_abort(env, "we don't support HES yet\n");
}
return booke206_get_tlbe(env, tlb, ea, esel);
}
static inline target_phys_addr_t booke206_tlb_to_page_size(int size)
{
return (1 << (size << 1)) << 10;
}
static inline target_phys_addr_t booke206_page_size_to_tlb(uint64_t size)
{
return (ffs(size >> 10) - 1) >> 1;
}
void helper_booke_setpid(uint32_t pidn, target_ulong pid)
{
env->spr[pidn] = pid;
/* changing PIDs mean we're in a different address space now */
tlb_flush(env, 1);
}
void helper_booke206_tlbwe(void)
{
uint32_t tlbncfg, tlbn;
ppcemb_tlb_t *tlb;
target_phys_addr_t rpn;
int tlbe_size;
switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
case MAS0_WQ_ALWAYS:
/* good to go, write that entry */
break;
case MAS0_WQ_COND:
/* XXX check if reserved */
if (0) {
return;
}
break;
case MAS0_WQ_CLR_RSRV:
/* XXX clear entry */
return;
default:
/* no idea what to do */
return;
}
if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
!msr_gs) {
/* XXX we don't support direct LRAT setting yet */
fprintf(stderr, "cpu: don't support LRAT setting yet\n");
return;
}
tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
tlb = booke206_cur_tlb(env);
if (msr_gs) {
cpu_abort(env, "missing HV implementation\n");
} else {
rpn = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
(env->spr[SPR_BOOKE_MAS3] & 0xfffff000);
}
tlb->RPN = rpn;
tlb->PID = (env->spr[SPR_BOOKE_MAS1] & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
if (tlbncfg & TLBnCFG_AVAIL) {
tlbe_size = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK)
>> MAS1_TSIZE_SHIFT;
} else {
tlbe_size = (tlbncfg & TLBnCFG_MINSIZE) >> TLBnCFG_MINSIZE_SHIFT;
}
tlb->size = booke206_tlb_to_page_size(tlbe_size);
tlb->EPN = (uint32_t)(env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
tlb->attr = env->spr[SPR_BOOKE_MAS2] & (MAS2_ACM | MAS2_VLE | MAS2_W |
MAS2_I | MAS2_M | MAS2_G | MAS2_E)
<< 1;
if (tlbncfg & TLBnCFG_IPROT) {
tlb->attr |= env->spr[SPR_BOOKE_MAS1] & MAS1_IPROT;
}
tlb->attr |= (env->spr[SPR_BOOKE_MAS3] &
((MAS3_U0 | MAS3_U1 | MAS3_U2 | MAS3_U3)) << 8);
if (env->spr[SPR_BOOKE_MAS1] & MAS1_TS) {
tlb->attr |= 1;
}
tlb->prot = 0;
if (env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) {
tlb->prot |= PAGE_VALID;
}
if (env->spr[SPR_BOOKE_MAS3] & MAS3_UX) {
tlb->prot |= PAGE_EXEC;
}
if (env->spr[SPR_BOOKE_MAS3] & MAS3_SX) {
tlb->prot |= PAGE_EXEC << 4;
}
if (env->spr[SPR_BOOKE_MAS3] & MAS3_UW) {
tlb->prot |= PAGE_WRITE;
}
if (env->spr[SPR_BOOKE_MAS3] & MAS3_SW) {
tlb->prot |= PAGE_WRITE << 4;
}
if (env->spr[SPR_BOOKE_MAS3] & MAS3_UR) {
tlb->prot |= PAGE_READ;
}
if (env->spr[SPR_BOOKE_MAS3] & MAS3_SR) {
tlb->prot |= PAGE_READ << 4;
}
if (tlb->size == TARGET_PAGE_SIZE) {
tlb_flush_page(env, tlb->EPN);
} else {
tlb_flush(env, 1);
}
}
static inline void booke206_tlb_to_mas(CPUState *env, ppcemb_tlb_t *tlb)
{
int tlbn = booke206_tlbe_to_tlbn(env, tlb);
int way = booke206_tlbe_to_way(env, tlb);
env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT;
env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT;
env->spr[SPR_BOOKE_MAS1] = MAS1_VALID;
env->spr[SPR_BOOKE_MAS2] = 0;
env->spr[SPR_BOOKE_MAS7] = (uint64_t)tlb->RPN >> 32;
env->spr[SPR_BOOKE_MAS3] = tlb->RPN;
env->spr[SPR_BOOKE_MAS1] |= tlb->PID << MAS1_TID_SHIFT;
env->spr[SPR_BOOKE_MAS1] |= booke206_page_size_to_tlb(tlb->size)
<< MAS1_TSIZE_SHIFT;
env->spr[SPR_BOOKE_MAS1] |= tlb->attr & MAS1_IPROT;
if (tlb->attr & 1) {
env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
}
env->spr[SPR_BOOKE_MAS2] = tlb->EPN;
env->spr[SPR_BOOKE_MAS2] |= (tlb->attr >> 1) &
(MAS2_ACM | MAS2_VLE | MAS2_W | MAS2_I | MAS2_M | MAS2_G | MAS2_E);
if (tlb->prot & PAGE_EXEC) {
env->spr[SPR_BOOKE_MAS3] |= MAS3_UX;
}
if (tlb->prot & (PAGE_EXEC << 4)) {
env->spr[SPR_BOOKE_MAS3] |= MAS3_SX;
}
if (tlb->prot & PAGE_WRITE) {
env->spr[SPR_BOOKE_MAS3] |= MAS3_UW;
}
if (tlb->prot & (PAGE_WRITE << 4)) {
env->spr[SPR_BOOKE_MAS3] |= MAS3_SW;
}
if (tlb->prot & PAGE_READ) {
env->spr[SPR_BOOKE_MAS3] |= MAS3_UR;
}
if (tlb->prot & (PAGE_READ << 4)) {
env->spr[SPR_BOOKE_MAS3] |= MAS3_SR;
}
env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
}
void helper_booke206_tlbre(void)
{
ppcemb_tlb_t *tlb = NULL;
tlb = booke206_cur_tlb(env);
booke206_tlb_to_mas(env, tlb);
}
void helper_booke206_tlbsx(target_ulong address)
{
ppcemb_tlb_t *tlb = NULL;
int i, j;
target_phys_addr_t raddr;
uint32_t spid, sas;
spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
int ways = booke206_tlb_ways(env, i);
for (j = 0; j < ways; j++) {
tlb = booke206_get_tlbe(env, i, address, j);
if (ppcemb_tlb_check(env, tlb, &raddr, address, spid, 0, j)) {
continue;
}
if (sas != (tlb->attr & MAS6_SAS)) {
continue;
}
booke206_tlb_to_mas(env, tlb);
return;
}
}
/* no entry found, fill with defaults */
env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
env->spr[SPR_BOOKE_MAS3] = 0;
env->spr[SPR_BOOKE_MAS7] = 0;
if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
}
env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
<< MAS1_TID_SHIFT;
/* next victim logic */
env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
env->last_way++;
env->last_way &= booke206_tlb_ways(env, 0) - 1;
env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
}
static inline void booke206_invalidate_ea_tlb(CPUState *env, int tlbn,
uint32_t ea)
{
int i;
int ways = booke206_tlb_ways(env, tlbn);
for (i = 0; i < ways; i++) {
ppcemb_tlb_t *tlb = booke206_get_tlbe(env, tlbn, ea, i);
target_phys_addr_t masked_ea = ea & ~(tlb->size - 1);
if ((tlb->EPN == (masked_ea >> MAS2_EPN_SHIFT)) &&
!(tlb->attr & MAS1_IPROT)) {
tlb->prot = 0;
}
}
}
void helper_booke206_tlbivax(target_ulong address)
{
if (address & 0x4) {
/* flush all entries */
if (address & 0x8) {
/* flush all of TLB1 */
booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1);
} else {
/* flush all of TLB0 */
booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0);
}
return;
}
if (address & 0x8) {
/* flush TLB1 entries */
booke206_invalidate_ea_tlb(env, 1, address);
tlb_flush(env, 1);
} else {
/* flush TLB0 entries */
booke206_invalidate_ea_tlb(env, 0, address);
tlb_flush_page(env, address & MAS2_EPN_MASK);
}
}
void helper_booke206_tlbflush(uint32_t type)
{
int flags = 0;
if (type & 2) {
flags |= BOOKE206_FLUSH_TLB1;
}
if (type & 4) {
flags |= BOOKE206_FLUSH_TLB0;
}
booke206_flush_tlb(env, flags, 1);
}
#endif /* !CONFIG_USER_ONLY */ #endif /* !CONFIG_USER_ONLY */

View File

@ -5988,6 +5988,80 @@ static void gen_tlbwe_440(DisasContext *ctx)
#endif #endif
} }
/* TLB management - PowerPC BookE 2.06 implementation */
/* tlbre */
static void gen_tlbre_booke206(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
#else
if (unlikely(!ctx->mem_idx)) {
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
return;
}
gen_helper_booke206_tlbre();
#endif
}
/* tlbsx - tlbsx. */
static void gen_tlbsx_booke206(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
#else
TCGv t0;
if (unlikely(!ctx->mem_idx)) {
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
return;
}
if (rA(ctx->opcode)) {
t0 = tcg_temp_new();
tcg_gen_mov_tl(t0, cpu_gpr[rD(ctx->opcode)]);
} else {
t0 = tcg_const_tl(0);
}
tcg_gen_add_tl(t0, t0, cpu_gpr[rB(ctx->opcode)]);
gen_helper_booke206_tlbsx(t0);
#endif
}
/* tlbwe */
static void gen_tlbwe_booke206(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
#else
if (unlikely(!ctx->mem_idx)) {
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
return;
}
gen_helper_booke206_tlbwe();
#endif
}
static void gen_tlbivax_booke206(DisasContext *ctx)
{
#if defined(CONFIG_USER_ONLY)
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
#else
TCGv t0;
if (unlikely(!ctx->mem_idx)) {
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
return;
}
t0 = tcg_temp_new();
gen_addr_reg_index(ctx, t0);
gen_helper_booke206_tlbivax(t0);
#endif
}
/* wrtee */ /* wrtee */
static void gen_wrtee(DisasContext *ctx) static void gen_wrtee(DisasContext *ctx)
{ {
@ -8434,7 +8508,7 @@ GEN_HANDLER2(icbt_40x, "icbt", 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_ICBT),
GEN_HANDLER(iccci, 0x1F, 0x06, 0x1E, 0x00000001, PPC_4xx_COMMON), GEN_HANDLER(iccci, 0x1F, 0x06, 0x1E, 0x00000001, PPC_4xx_COMMON),
GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON), GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON),
GEN_HANDLER2(rfci_40x, "rfci", 0x13, 0x13, 0x01, 0x03FF8001, PPC_40x_EXCP), GEN_HANDLER2(rfci_40x, "rfci", 0x13, 0x13, 0x01, 0x03FF8001, PPC_40x_EXCP),
GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE), GEN_HANDLER_E(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE, PPC2_BOOKE206),
GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_RFDI), GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_RFDI),
GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_RFMCI), GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_RFMCI),
GEN_HANDLER2(tlbre_40x, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_TLB), GEN_HANDLER2(tlbre_40x, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_TLB),
@ -8443,12 +8517,23 @@ GEN_HANDLER2(tlbwe_40x, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_TLB),
GEN_HANDLER2(tlbre_440, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE), GEN_HANDLER2(tlbre_440, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE),
GEN_HANDLER2(tlbsx_440, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE), GEN_HANDLER2(tlbsx_440, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE),
GEN_HANDLER2(tlbwe_440, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE), GEN_HANDLER2(tlbwe_440, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE),
GEN_HANDLER2_E(tlbre_booke206, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001,
PPC_NONE, PPC2_BOOKE206),
GEN_HANDLER2_E(tlbsx_booke206, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000,
PPC_NONE, PPC2_BOOKE206),
GEN_HANDLER2_E(tlbwe_booke206, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001,
PPC_NONE, PPC2_BOOKE206),
GEN_HANDLER2_E(tlbivax_booke206, "tlbivax", 0x1F, 0x12, 0x18, 0x00000001,
PPC_NONE, PPC2_BOOKE206),
GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE), GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE),
GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000E7C01, PPC_WRTEE), GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000E7C01, PPC_WRTEE),
GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC), GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC),
GEN_HANDLER(mbar, 0x1F, 0x16, 0x1a, 0x001FF801, PPC_BOOKE), GEN_HANDLER_E(mbar, 0x1F, 0x16, 0x1a, 0x001FF801,
GEN_HANDLER(msync, 0x1F, 0x16, 0x12, 0x03FFF801, PPC_BOOKE), PPC_BOOKE, PPC2_BOOKE206),
GEN_HANDLER2(icbt_440, "icbt", 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE), GEN_HANDLER_E(msync, 0x1F, 0x16, 0x12, 0x03FFF801,
PPC_BOOKE, PPC2_BOOKE206),
GEN_HANDLER2_E(icbt_440, "icbt", 0x1F, 0x16, 0x00, 0x03E00001,
PPC_BOOKE, PPC2_BOOKE206),
GEN_HANDLER(lvsl, 0x1f, 0x06, 0x00, 0x00000001, PPC_ALTIVEC), GEN_HANDLER(lvsl, 0x1f, 0x06, 0x00, 0x00000001, PPC_ALTIVEC),
GEN_HANDLER(lvsr, 0x1f, 0x06, 0x01, 0x00000001, PPC_ALTIVEC), GEN_HANDLER(lvsr, 0x1f, 0x06, 0x01, 0x00000001, PPC_ALTIVEC),
GEN_HANDLER(mfvscr, 0x04, 0x2, 0x18, 0x001ff800, PPC_ALTIVEC), GEN_HANDLER(mfvscr, 0x04, 0x2, 0x18, 0x001ff800, PPC_ALTIVEC),
@ -9197,7 +9282,7 @@ void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
#endif #endif
cpu_fprintf(f, " SDR1 " TARGET_FMT_lx "\n", env->spr[SPR_SDR1]); cpu_fprintf(f, " SDR1 " TARGET_FMT_lx "\n", env->spr[SPR_SDR1]);
break; break;
case POWERPC_MMU_BOOKE_FSL: case POWERPC_MMU_BOOKE206:
cpu_fprintf(f, " MAS0 " TARGET_FMT_lx " MAS1 " TARGET_FMT_lx cpu_fprintf(f, " MAS0 " TARGET_FMT_lx " MAS1 " TARGET_FMT_lx
" MAS2 " TARGET_FMT_lx " MAS3 " TARGET_FMT_lx "\n", " MAS2 " TARGET_FMT_lx " MAS3 " TARGET_FMT_lx "\n",
env->spr[SPR_BOOKE_MAS0], env->spr[SPR_BOOKE_MAS1], env->spr[SPR_BOOKE_MAS0], env->spr[SPR_BOOKE_MAS1],

View File

@ -1355,6 +1355,31 @@ static void gen_74xx_soft_tlb (CPUPPCState *env, int nb_tlbs, int nb_ways)
#endif #endif
} }
#if !defined(CONFIG_USER_ONLY)
static void spr_write_e500_l1csr0 (void *opaque, int sprn, int gprn)
{
TCGv t0 = tcg_temp_new();
tcg_gen_andi_tl(t0, cpu_gpr[gprn], ~256);
gen_store_spr(sprn, t0);
tcg_temp_free(t0);
}
static void spr_write_booke206_mmucsr0 (void *opaque, int sprn, int gprn)
{
TCGv t0 = tcg_const_i32(sprn);
gen_helper_booke206_tlbflush(t0);
tcg_temp_free(t0);
}
static void spr_write_booke_pid (void *opaque, int sprn, int gprn)
{
TCGv t0 = tcg_const_i32(sprn);
gen_helper_booke_setpid(t0, cpu_gpr[gprn]);
tcg_temp_free(t0);
}
#endif
static void gen_spr_usprgh (CPUPPCState *env) static void gen_spr_usprgh (CPUPPCState *env)
{ {
spr_register(env, SPR_USPRG4, "USPRG4", spr_register(env, SPR_USPRG4, "USPRG4",
@ -1494,7 +1519,7 @@ static void gen_spr_BookE (CPUPPCState *env, uint64_t ivor_mask)
} }
spr_register(env, SPR_BOOKE_PID, "PID", spr_register(env, SPR_BOOKE_PID, "PID",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_write_booke_pid,
0x00000000); 0x00000000);
spr_register(env, SPR_BOOKE_TCR, "TCR", spr_register(env, SPR_BOOKE_TCR, "TCR",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
@ -1536,8 +1561,19 @@ static void gen_spr_BookE (CPUPPCState *env, uint64_t ivor_mask)
0x00000000); 0x00000000);
} }
/* FSL storage control registers */ static inline uint32_t gen_tlbncfg(uint32_t assoc, uint32_t minsize,
static void gen_spr_BookE_FSL (CPUPPCState *env, uint32_t mas_mask) uint32_t maxsize, uint32_t flags,
uint32_t nentries)
{
return (assoc << TLBnCFG_ASSOC_SHIFT) |
(minsize << TLBnCFG_MINSIZE_SHIFT) |
(maxsize << TLBnCFG_MAXSIZE_SHIFT) |
flags | nentries;
}
/* BookE 2.06 storage control registers */
static void gen_spr_BookE206(CPUPPCState *env, uint32_t mas_mask,
uint32_t *tlbncfg)
{ {
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
const char *mas_names[8] = { const char *mas_names[8] = {
@ -1563,14 +1599,14 @@ static void gen_spr_BookE_FSL (CPUPPCState *env, uint32_t mas_mask)
/* XXX : not implemented */ /* XXX : not implemented */
spr_register(env, SPR_BOOKE_PID1, "PID1", spr_register(env, SPR_BOOKE_PID1, "PID1",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_write_booke_pid,
0x00000000); 0x00000000);
} }
if (env->nb_pids > 2) { if (env->nb_pids > 2) {
/* XXX : not implemented */ /* XXX : not implemented */
spr_register(env, SPR_BOOKE_PID2, "PID2", spr_register(env, SPR_BOOKE_PID2, "PID2",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_write_booke_pid,
0x00000000); 0x00000000);
} }
/* XXX : not implemented */ /* XXX : not implemented */
@ -1578,45 +1614,38 @@ static void gen_spr_BookE_FSL (CPUPPCState *env, uint32_t mas_mask)
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS,
0x00000000); /* TOFIX */ 0x00000000); /* TOFIX */
/* XXX : not implemented */
spr_register(env, SPR_MMUCSR0, "MMUCSR0",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000); /* TOFIX */
switch (env->nb_ways) { switch (env->nb_ways) {
case 4: case 4:
/* XXX : not implemented */
spr_register(env, SPR_BOOKE_TLB3CFG, "TLB3CFG", spr_register(env, SPR_BOOKE_TLB3CFG, "TLB3CFG",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS,
0x00000000); /* TOFIX */ tlbncfg[3]);
/* Fallthru */ /* Fallthru */
case 3: case 3:
/* XXX : not implemented */
spr_register(env, SPR_BOOKE_TLB2CFG, "TLB2CFG", spr_register(env, SPR_BOOKE_TLB2CFG, "TLB2CFG",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS,
0x00000000); /* TOFIX */ tlbncfg[2]);
/* Fallthru */ /* Fallthru */
case 2: case 2:
/* XXX : not implemented */
spr_register(env, SPR_BOOKE_TLB1CFG, "TLB1CFG", spr_register(env, SPR_BOOKE_TLB1CFG, "TLB1CFG",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS,
0x00000000); /* TOFIX */ tlbncfg[1]);
/* Fallthru */ /* Fallthru */
case 1: case 1:
/* XXX : not implemented */
spr_register(env, SPR_BOOKE_TLB0CFG, "TLB0CFG", spr_register(env, SPR_BOOKE_TLB0CFG, "TLB0CFG",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS,
0x00000000); /* TOFIX */ tlbncfg[0]);
/* Fallthru */ /* Fallthru */
case 0: case 0:
default: default:
break; break;
} }
#endif #endif
gen_spr_usprgh(env);
} }
/* SPR specific to PowerPC 440 implementation */ /* SPR specific to PowerPC 440 implementation */
@ -4113,7 +4142,7 @@ static void init_proc_G2LE (CPUPPCState *env)
PPC_BOOKE) PPC_BOOKE)
#define POWERPC_INSNS2_e200 (PPC_NONE) #define POWERPC_INSNS2_e200 (PPC_NONE)
#define POWERPC_MSRM_e200 (0x000000000606FF30ULL) #define POWERPC_MSRM_e200 (0x000000000606FF30ULL)
#define POWERPC_MMU_e200 (POWERPC_MMU_BOOKE_FSL) #define POWERPC_MMU_e200 (POWERPC_MMU_BOOKE206)
#define POWERPC_EXCP_e200 (POWERPC_EXCP_BOOKE) #define POWERPC_EXCP_e200 (POWERPC_EXCP_BOOKE)
#define POWERPC_INPUT_e200 (PPC_FLAGS_INPUT_BookE) #define POWERPC_INPUT_e200 (PPC_FLAGS_INPUT_BookE)
#define POWERPC_BFDM_e200 (bfd_mach_ppc_860) #define POWERPC_BFDM_e200 (bfd_mach_ppc_860)
@ -4134,7 +4163,7 @@ static void init_proc_e200 (CPUPPCState *env)
&spr_read_spefscr, &spr_write_spefscr, &spr_read_spefscr, &spr_write_spefscr,
0x00000000); 0x00000000);
/* Memory management */ /* Memory management */
gen_spr_BookE_FSL(env, 0x0000005D); gen_spr_BookE206(env, 0x0000005D, NULL);
/* XXX : not implemented */ /* XXX : not implemented */
spr_register(env, SPR_HID0, "HID0", spr_register(env, SPR_HID0, "HID0",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
@ -4205,6 +4234,11 @@ static void init_proc_e200 (CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_write_generic,
0x00000000); 0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_MMUCSR0, "MMUCSR0",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000); /* TOFIX */
spr_register(env, SPR_BOOKE_DSRR0, "DSRR0", spr_register(env, SPR_BOOKE_DSRR0, "DSRR0",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_write_generic,
@ -4282,11 +4316,10 @@ static void init_proc_e300 (CPUPPCState *env)
PPC_WRTEE | PPC_RFDI | \ PPC_WRTEE | PPC_RFDI | \
PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \ PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \
PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \
PPC_MEM_TLBSYNC | PPC_TLBIVAX | \ PPC_MEM_TLBSYNC | PPC_TLBIVAX)
PPC_BOOKE) #define POWERPC_INSNS2_e500v1 (PPC2_BOOKE206)
#define POWERPC_INSNS2_e500v1 (PPC_NONE)
#define POWERPC_MSRM_e500v1 (0x000000000606FF30ULL) #define POWERPC_MSRM_e500v1 (0x000000000606FF30ULL)
#define POWERPC_MMU_e500v1 (POWERPC_MMU_BOOKE_FSL) #define POWERPC_MMU_e500v1 (POWERPC_MMU_BOOKE206)
#define POWERPC_EXCP_e500v1 (POWERPC_EXCP_BOOKE) #define POWERPC_EXCP_e500v1 (POWERPC_EXCP_BOOKE)
#define POWERPC_INPUT_e500v1 (PPC_FLAGS_INPUT_BookE) #define POWERPC_INPUT_e500v1 (PPC_FLAGS_INPUT_BookE)
#define POWERPC_BFDM_e500v1 (bfd_mach_ppc_860) #define POWERPC_BFDM_e500v1 (bfd_mach_ppc_860)
@ -4294,7 +4327,7 @@ static void init_proc_e300 (CPUPPCState *env)
POWERPC_FLAG_UBLE | POWERPC_FLAG_DE | \ POWERPC_FLAG_UBLE | POWERPC_FLAG_DE | \
POWERPC_FLAG_BUS_CLK) POWERPC_FLAG_BUS_CLK)
#define check_pow_e500v1 check_pow_hid0 #define check_pow_e500v1 check_pow_hid0
#define init_proc_e500v1 init_proc_e500 #define init_proc_e500v1 init_proc_e500v1
/* e500v2 core */ /* e500v2 core */
#define POWERPC_INSNS_e500v2 (PPC_INSNS_BASE | PPC_ISEL | \ #define POWERPC_INSNS_e500v2 (PPC_INSNS_BASE | PPC_ISEL | \
@ -4302,11 +4335,10 @@ static void init_proc_e300 (CPUPPCState *env)
PPC_WRTEE | PPC_RFDI | \ PPC_WRTEE | PPC_RFDI | \
PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \ PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \
PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \ PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \
PPC_MEM_TLBSYNC | PPC_TLBIVAX | \ PPC_MEM_TLBSYNC | PPC_TLBIVAX)
PPC_BOOKE) #define POWERPC_INSNS2_e500v2 (PPC2_BOOKE206)
#define POWERPC_INSNS2_e500v2 (PPC_NONE)
#define POWERPC_MSRM_e500v2 (0x000000000606FF30ULL) #define POWERPC_MSRM_e500v2 (0x000000000606FF30ULL)
#define POWERPC_MMU_e500v2 (POWERPC_MMU_BOOKE_FSL) #define POWERPC_MMU_e500v2 (POWERPC_MMU_BOOKE206)
#define POWERPC_EXCP_e500v2 (POWERPC_EXCP_BOOKE) #define POWERPC_EXCP_e500v2 (POWERPC_EXCP_BOOKE)
#define POWERPC_INPUT_e500v2 (PPC_FLAGS_INPUT_BookE) #define POWERPC_INPUT_e500v2 (PPC_FLAGS_INPUT_BookE)
#define POWERPC_BFDM_e500v2 (bfd_mach_ppc_860) #define POWERPC_BFDM_e500v2 (bfd_mach_ppc_860)
@ -4314,13 +4346,23 @@ static void init_proc_e300 (CPUPPCState *env)
POWERPC_FLAG_UBLE | POWERPC_FLAG_DE | \ POWERPC_FLAG_UBLE | POWERPC_FLAG_DE | \
POWERPC_FLAG_BUS_CLK) POWERPC_FLAG_BUS_CLK)
#define check_pow_e500v2 check_pow_hid0 #define check_pow_e500v2 check_pow_hid0
#define init_proc_e500v2 init_proc_e500 #define init_proc_e500v2 init_proc_e500v2
static void init_proc_e500 (CPUPPCState *env) static void init_proc_e500 (CPUPPCState *env, int version)
{ {
uint32_t tlbncfg[2];
#if !defined(CONFIG_USER_ONLY)
int i;
#endif
/* Time base */ /* Time base */
gen_tbl(env); gen_tbl(env);
gen_spr_BookE(env, 0x0000000F0000FD7FULL); /*
* XXX The e500 doesn't implement IVOR7 and IVOR9, but doesn't
* complain when accessing them.
* gen_spr_BookE(env, 0x0000000F0000FD7FULL);
*/
gen_spr_BookE(env, 0x0000000F0000FFFFULL);
/* Processor identification */ /* Processor identification */
spr_register(env, SPR_BOOKE_PIR, "PIR", spr_register(env, SPR_BOOKE_PIR, "PIR",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
@ -4334,8 +4376,24 @@ static void init_proc_e500 (CPUPPCState *env)
/* Memory management */ /* Memory management */
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
env->nb_pids = 3; env->nb_pids = 3;
env->nb_ways = 2;
env->id_tlbs = 0;
switch (version) {
case 1:
/* e500v1 */
tlbncfg[0] = gen_tlbncfg(2, 1, 1, 0, 256);
tlbncfg[1] = gen_tlbncfg(16, 1, 9, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16);
break;
case 2:
/* e500v2 */
tlbncfg[0] = gen_tlbncfg(4, 1, 1, 0, 512);
tlbncfg[1] = gen_tlbncfg(16, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16);
break;
default:
cpu_abort(env, "Unknown CPU: " TARGET_FMT_lx "\n", env->spr[SPR_PVR]);
}
#endif #endif
gen_spr_BookE_FSL(env, 0x0000005F); gen_spr_BookE206(env, 0x000000DF, tlbncfg);
/* XXX : not implemented */ /* XXX : not implemented */
spr_register(env, SPR_HID0, "HID0", spr_register(env, SPR_HID0, "HID0",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
@ -4384,23 +4442,13 @@ static void init_proc_e500 (CPUPPCState *env)
/* XXX : not implemented */ /* XXX : not implemented */
spr_register(env, SPR_Exxx_L1CSR0, "L1CSR0", spr_register(env, SPR_Exxx_L1CSR0, "L1CSR0",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_write_e500_l1csr0,
0x00000000); 0x00000000);
/* XXX : not implemented */ /* XXX : not implemented */
spr_register(env, SPR_Exxx_L1CSR1, "L1CSR1", spr_register(env, SPR_Exxx_L1CSR1, "L1CSR1",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_write_generic,
0x00000000); 0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_BOOKE_TLB0CFG, "TLB0CFG",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_BOOKE_TLB1CFG, "TLB1CFG",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0", spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_write_generic,
@ -4409,11 +4457,18 @@ static void init_proc_e500 (CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_write_generic,
0x00000000); 0x00000000);
spr_register(env, SPR_MMUCSR0, "MMUCSR0",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_booke206_mmucsr0,
0x00000000);
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
env->nb_tlb = 64; env->nb_tlb = 0;
env->nb_ways = 1; for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
env->id_tlbs = 0; env->nb_tlb += booke206_tlb_size(env, i);
}
#endif #endif
init_excp_e200(env); init_excp_e200(env);
env->dcache_line_size = 32; env->dcache_line_size = 32;
env->icache_line_size = 32; env->icache_line_size = 32;
@ -4421,6 +4476,16 @@ static void init_proc_e500 (CPUPPCState *env)
ppce500_irq_init(env); ppce500_irq_init(env);
} }
static void init_proc_e500v1(CPUPPCState *env)
{
init_proc_e500(env, 1);
}
static void init_proc_e500v2(CPUPPCState *env)
{
init_proc_e500(env, 2);
}
/* Non-embedded PowerPC */ /* Non-embedded PowerPC */
/* POWER : same as 601, without mfmsr, mfsr */ /* POWER : same as 601, without mfmsr, mfsr */
@ -9756,8 +9821,8 @@ int cpu_ppc_register_internal (CPUPPCState *env, const ppc_def_t *def)
case POWERPC_MMU_BOOKE: case POWERPC_MMU_BOOKE:
mmu_model = "PowerPC BookE"; mmu_model = "PowerPC BookE";
break; break;
case POWERPC_MMU_BOOKE_FSL: case POWERPC_MMU_BOOKE206:
mmu_model = "PowerPC BookE FSL"; mmu_model = "PowerPC BookE 2.06";
break; break;
case POWERPC_MMU_601: case POWERPC_MMU_601:
mmu_model = "PowerPC 601"; mmu_model = "PowerPC 601";