mirror of
				https://github.com/qemu/qemu.git
				synced 2025-10-27 22:03:47 +00:00 
			
		
		
		
	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:
		
							parent
							
								
									a5858d7af0
								
							
						
					
					
						commit
						01662f3e51
					
				
							
								
								
									
										304
									
								
								target-ppc/cpu.h
									
									
									
									
									
								
							
							
						
						
									
										304
									
								
								target-ppc/cpu.h
									
									
									
									
									
								
							| @ -108,8 +108,8 @@ enum powerpc_mmu_t { | ||||
|     POWERPC_MMU_MPC8xx     = 0x00000007, | ||||
|     /* BookE MMU model                                         */ | ||||
|     POWERPC_MMU_BOOKE      = 0x00000008, | ||||
|     /* BookE FSL MMU model                                     */ | ||||
|     POWERPC_MMU_BOOKE_FSL  = 0x00000009, | ||||
|     /* BookE 2.06 MMU model                                    */ | ||||
|     POWERPC_MMU_BOOKE206   = 0x00000009, | ||||
|     /* PowerPC 601 MMU model (specific BATs format)            */ | ||||
|     POWERPC_MMU_601        = 0x0000000A, | ||||
| #if defined(TARGET_PPC64) | ||||
| @ -607,6 +607,224 @@ enum { | ||||
| #define vscr_nj		(((env->vscr) >> VSCR_NJ)	& 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 */ | ||||
| #define NB_MMU_MODES 3 | ||||
| @ -678,7 +896,7 @@ struct CPUPPCState { | ||||
|     int nb_BATs; | ||||
|     target_ulong DBAT[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 tlb_per_way; /* Speed-up helper: used to avoid divisions at run time */ | ||||
|     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_booke_tcr (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_one (CPUPPCState *env, target_ulong addr); | ||||
| #if defined(TARGET_PPC64) | ||||
| @ -1547,6 +1769,11 @@ enum { | ||||
|     PPC_DCRUX          = 0x4000000000000000ULL, | ||||
|     /* popcntw and popcntd instructions                                      */ | ||||
|     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 | ||||
| } | ||||
| 
 | ||||
| #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 *); | ||||
| 
 | ||||
| #endif /* !defined (__CPU_PPC_H__) */ | ||||
|  | ||||
| @ -993,7 +993,7 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx, | ||||
| } | ||||
| 
 | ||||
| /* 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_ulong address, uint32_t pid, int ext, | ||||
|                      int i) | ||||
| @ -1006,8 +1006,8 @@ static inline int ppcemb_tlb_check(CPUState *env, ppcemb_tlb_t *tlb, | ||||
|     } | ||||
|     mask = ~(tlb->size - 1); | ||||
|     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, | ||||
|               mask, (uint32_t)tlb->PID); | ||||
|               " " TARGET_FMT_lx " %u %x\n", __func__, i, address, pid, tlb->EPN, | ||||
|               mask, (uint32_t)tlb->PID, tlb->prot); | ||||
|     /* Check PID */ | ||||
|     if (tlb->PID != 0 && tlb->PID != pid) | ||||
|         return -1; | ||||
| @ -1153,48 +1153,164 @@ void store_40x_sler (CPUPPCState *env, uint32_t 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, | ||||
|                                           target_ulong address, int rw, | ||||
|                                           int access_type) | ||||
| { | ||||
|     ppcemb_tlb_t *tlb; | ||||
|     target_phys_addr_t raddr; | ||||
|     int i, prot, ret; | ||||
|     int i, ret; | ||||
| 
 | ||||
|     ret = -1; | ||||
|     raddr = (target_phys_addr_t)-1ULL; | ||||
|     for (i = 0; i < env->nb_tlb; i++) { | ||||
|         tlb = &env->tlb[i].tlbe; | ||||
|         if (ppcemb_tlb_check(env, tlb, &raddr, address, | ||||
|                              env->spr[SPR_BOOKE_PID], 1, i) < 0) | ||||
|             continue; | ||||
|         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)) | ||||
|                 continue; | ||||
|             ctx->prot = prot; | ||||
|             if (prot & PAGE_EXEC) { | ||||
|                 ret = 0; | ||||
|         ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw, | ||||
|                                  access_type, i); | ||||
|         if (!ret) { | ||||
|             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; | ||||
|         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; | ||||
| } | ||||
| @ -1254,9 +1370,8 @@ static inline int check_physical(CPUState *env, mmu_ctx_t *ctx, | ||||
|         /* XXX: TODO */ | ||||
|         cpu_abort(env, "MPC8xx MMU model is not implemented\n"); | ||||
|         break; | ||||
|     case POWERPC_MMU_BOOKE_FSL: | ||||
|         /* XXX: TODO */ | ||||
|         cpu_abort(env, "BookE FSL MMU model not implemented\n"); | ||||
|     case POWERPC_MMU_BOOKE206: | ||||
|         cpu_abort(env, "BookE 2.06 MMU doesn't have physical real mode\n"); | ||||
|         break; | ||||
|     default: | ||||
|         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.  */ | ||||
|             ret = mmubooke_get_physical_address(env, ctx, eaddr, | ||||
|                                                 rw, access_type); | ||||
|         } else if (env->mmu_model == POWERPC_MMU_BOOKE206) { | ||||
|             ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw, | ||||
|                                                access_type); | ||||
|         } else { | ||||
|             /* No address translation.  */ | ||||
|             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, | ||||
|                                                 rw, access_type); | ||||
|             break; | ||||
|         case POWERPC_MMU_BOOKE206: | ||||
|             ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw, | ||||
|                                                access_type); | ||||
|             break; | ||||
|         case POWERPC_MMU_MPC8xx: | ||||
|             /* XXX: TODO */ | ||||
|             cpu_abort(env, "MPC8xx MMU model is not implemented\n"); | ||||
|             break; | ||||
|         case POWERPC_MMU_BOOKE_FSL: | ||||
|             /* XXX: TODO */ | ||||
|             cpu_abort(env, "BookE FSL MMU model not implemented\n"); | ||||
|             return -1; | ||||
|         case POWERPC_MMU_REAL: | ||||
|             cpu_abort(env, "PowerPC in real mode do not do any translation\n"); | ||||
|             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; | ||||
| } | ||||
| 
 | ||||
| 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 */ | ||||
| int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, | ||||
|                               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->error_code = 0x40000000; | ||||
|                     break; | ||||
|                 case POWERPC_MMU_BOOKE206: | ||||
|                     booke206_update_mas_tlb_miss(env, address, rw); | ||||
|                     /* fall through */ | ||||
|                 case POWERPC_MMU_BOOKE: | ||||
|                     env->exception_index = POWERPC_EXCP_ITLB; | ||||
|                     env->error_code = 0; | ||||
|                     env->spr[SPR_BOOKE_DEAR] = address; | ||||
|                     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: | ||||
|                     /* XXX: TODO */ | ||||
|                     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; | ||||
|             case -3: | ||||
|                 /* 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->exception_index = POWERPC_EXCP_ISI; | ||||
| @ -1522,16 +1680,15 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, | ||||
|                     /* XXX: TODO */ | ||||
|                     cpu_abort(env, "MPC8xx MMU model is not implemented\n"); | ||||
|                     break; | ||||
|                 case POWERPC_MMU_BOOKE206: | ||||
|                     booke206_update_mas_tlb_miss(env, address, rw); | ||||
|                     /* fall through */ | ||||
|                 case POWERPC_MMU_BOOKE: | ||||
|                     env->exception_index = POWERPC_EXCP_DTLB; | ||||
|                     env->error_code = 0; | ||||
|                     env->spr[SPR_BOOKE_DEAR] = address; | ||||
|                     env->spr[SPR_BOOKE_ESR] = rw ? 1 << ESR_ST : 0; | ||||
|                     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: | ||||
|                     cpu_abort(env, "PowerPC in real mode should never raise " | ||||
|                               "any MMU exceptions\n"); | ||||
| @ -1551,7 +1708,8 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw, | ||||
|                     if (rw) { | ||||
|                         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_ESR] = rw ? 1 << ESR_ST : 0; | ||||
|                 } else { | ||||
| @ -1822,10 +1980,8 @@ void ppc_tlb_invalidate_all (CPUPPCState *env) | ||||
|     case POWERPC_MMU_BOOKE: | ||||
|         tlb_flush(env, 1); | ||||
|         break; | ||||
|     case POWERPC_MMU_BOOKE_FSL: | ||||
|         /* XXX: TODO */ | ||||
|         if (!kvm_enabled()) | ||||
|             cpu_abort(env, "BookE MMU model is not implemented\n"); | ||||
|     case POWERPC_MMU_BOOKE206: | ||||
|         booke206_flush_tlb(env, -1, 0); | ||||
|         break; | ||||
|     case POWERPC_MMU_32B: | ||||
|     case POWERPC_MMU_601: | ||||
| @ -1869,9 +2025,9 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr) | ||||
|         /* XXX: TODO */ | ||||
|         cpu_abort(env, "BookE MMU model is not implemented\n"); | ||||
|         break; | ||||
|     case POWERPC_MMU_BOOKE_FSL: | ||||
|     case POWERPC_MMU_BOOKE206: | ||||
|         /* 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; | ||||
|     case POWERPC_MMU_32B: | ||||
|     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->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,
 | ||||
|                 we should probably implement that as different MMU indexes, | ||||
|                 but for the moment we do it the slow way and flush all.  */ | ||||
|  | ||||
| @ -334,6 +334,12 @@ DEF_HELPER_1(4xx_tlbsx, tl, tl) | ||||
| DEF_HELPER_2(440_tlbre, tl, i32, tl) | ||||
| DEF_HELPER_3(440_tlbwe, void, i32, 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_tlbi, void, tl) | ||||
| DEF_HELPER_1(74xx_tlbd, void, tl) | ||||
|  | ||||
| @ -4206,4 +4206,300 @@ target_ulong helper_440_tlbsx (target_ulong address) | ||||
|     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 */ | ||||
|  | ||||
| @ -5988,6 +5988,80 @@ static void gen_tlbwe_440(DisasContext *ctx) | ||||
| #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 */ | ||||
| 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(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON), | ||||
| 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(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_RFMCI), | ||||
| 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(tlbsx_440, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000, 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(wrteei, 0x1F, 0x03, 0x05, 0x000E7C01, PPC_WRTEE), | ||||
| GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC), | ||||
| GEN_HANDLER(mbar, 0x1F, 0x16, 0x1a, 0x001FF801, PPC_BOOKE), | ||||
| GEN_HANDLER(msync, 0x1F, 0x16, 0x12, 0x03FFF801, PPC_BOOKE), | ||||
| GEN_HANDLER2(icbt_440, "icbt", 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE), | ||||
| GEN_HANDLER_E(mbar, 0x1F, 0x16, 0x1a, 0x001FF801, | ||||
|               PPC_BOOKE, PPC2_BOOKE206), | ||||
| 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(lvsr, 0x1f, 0x06, 0x01, 0x00000001, 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 | ||||
|         cpu_fprintf(f, " SDR1 " TARGET_FMT_lx "\n", env->spr[SPR_SDR1]); | ||||
|         break; | ||||
|     case POWERPC_MMU_BOOKE_FSL: | ||||
|     case POWERPC_MMU_BOOKE206: | ||||
|         cpu_fprintf(f, " MAS0 " TARGET_FMT_lx "  MAS1 " TARGET_FMT_lx | ||||
|                        "   MAS2 " TARGET_FMT_lx "   MAS3 " TARGET_FMT_lx "\n", | ||||
|                     env->spr[SPR_BOOKE_MAS0], env->spr[SPR_BOOKE_MAS1], | ||||
|  | ||||
| @ -1355,6 +1355,31 @@ static void gen_74xx_soft_tlb (CPUPPCState *env, int nb_tlbs, int nb_ways) | ||||
| #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) | ||||
| { | ||||
|     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_NOACCESS, SPR_NOACCESS, | ||||
|                  &spr_read_generic, &spr_write_generic, | ||||
|                  &spr_read_generic, &spr_write_booke_pid, | ||||
|                  0x00000000); | ||||
|     spr_register(env, SPR_BOOKE_TCR, "TCR", | ||||
|                  SPR_NOACCESS, SPR_NOACCESS, | ||||
| @ -1536,8 +1561,19 @@ static void gen_spr_BookE (CPUPPCState *env, uint64_t ivor_mask) | ||||
|                  0x00000000); | ||||
| } | ||||
| 
 | ||||
| /* FSL storage control registers */ | ||||
| static void gen_spr_BookE_FSL (CPUPPCState *env, uint32_t mas_mask) | ||||
| static inline uint32_t gen_tlbncfg(uint32_t assoc, uint32_t minsize, | ||||
|                                    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) | ||||
|     const char *mas_names[8] = { | ||||
| @ -1563,14 +1599,14 @@ static void gen_spr_BookE_FSL (CPUPPCState *env, uint32_t mas_mask) | ||||
|         /* XXX : not implemented */ | ||||
|         spr_register(env, SPR_BOOKE_PID1, "PID1", | ||||
|                      SPR_NOACCESS, SPR_NOACCESS, | ||||
|                      &spr_read_generic, &spr_write_generic, | ||||
|                      &spr_read_generic, &spr_write_booke_pid, | ||||
|                      0x00000000); | ||||
|     } | ||||
|     if (env->nb_pids > 2) { | ||||
|         /* XXX : not implemented */ | ||||
|         spr_register(env, SPR_BOOKE_PID2, "PID2", | ||||
|                      SPR_NOACCESS, SPR_NOACCESS, | ||||
|                      &spr_read_generic, &spr_write_generic, | ||||
|                      &spr_read_generic, &spr_write_booke_pid, | ||||
|                      0x00000000); | ||||
|     } | ||||
|     /* XXX : not implemented */ | ||||
| @ -1578,45 +1614,38 @@ static void gen_spr_BookE_FSL (CPUPPCState *env, uint32_t mas_mask) | ||||
|                  SPR_NOACCESS, SPR_NOACCESS, | ||||
|                  &spr_read_generic, SPR_NOACCESS, | ||||
|                  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) { | ||||
|     case 4: | ||||
|         /* XXX : not implemented */ | ||||
|         spr_register(env, SPR_BOOKE_TLB3CFG, "TLB3CFG", | ||||
|                      SPR_NOACCESS, SPR_NOACCESS, | ||||
|                      &spr_read_generic, SPR_NOACCESS, | ||||
|                      0x00000000); /* TOFIX */ | ||||
|                      tlbncfg[3]); | ||||
|         /* Fallthru */ | ||||
|     case 3: | ||||
|         /* XXX : not implemented */ | ||||
|         spr_register(env, SPR_BOOKE_TLB2CFG, "TLB2CFG", | ||||
|                      SPR_NOACCESS, SPR_NOACCESS, | ||||
|                      &spr_read_generic, SPR_NOACCESS, | ||||
|                      0x00000000); /* TOFIX */ | ||||
|                      tlbncfg[2]); | ||||
|         /* Fallthru */ | ||||
|     case 2: | ||||
|         /* XXX : not implemented */ | ||||
|         spr_register(env, SPR_BOOKE_TLB1CFG, "TLB1CFG", | ||||
|                      SPR_NOACCESS, SPR_NOACCESS, | ||||
|                      &spr_read_generic, SPR_NOACCESS, | ||||
|                      0x00000000); /* TOFIX */ | ||||
|                      tlbncfg[1]); | ||||
|         /* Fallthru */ | ||||
|     case 1: | ||||
|         /* XXX : not implemented */ | ||||
|         spr_register(env, SPR_BOOKE_TLB0CFG, "TLB0CFG", | ||||
|                      SPR_NOACCESS, SPR_NOACCESS, | ||||
|                      &spr_read_generic, SPR_NOACCESS, | ||||
|                      0x00000000); /* TOFIX */ | ||||
|                      tlbncfg[0]); | ||||
|         /* Fallthru */ | ||||
|     case 0: | ||||
|     default: | ||||
|         break; | ||||
|     } | ||||
| #endif | ||||
| 
 | ||||
|     gen_spr_usprgh(env); | ||||
| } | ||||
| 
 | ||||
| /* SPR specific to PowerPC 440 implementation */ | ||||
| @ -4113,7 +4142,7 @@ static void init_proc_G2LE (CPUPPCState *env) | ||||
|                               PPC_BOOKE) | ||||
| #define POWERPC_INSNS2_e200  (PPC_NONE) | ||||
| #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_INPUT_e200   (PPC_FLAGS_INPUT_BookE) | ||||
| #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, | ||||
|                  0x00000000); | ||||
|     /* Memory management */ | ||||
|     gen_spr_BookE_FSL(env, 0x0000005D); | ||||
|     gen_spr_BookE206(env, 0x0000005D, NULL); | ||||
|     /* XXX : not implemented */ | ||||
|     spr_register(env, SPR_HID0, "HID0", | ||||
|                  SPR_NOACCESS, SPR_NOACCESS, | ||||
| @ -4205,6 +4234,11 @@ static void init_proc_e200 (CPUPPCState *env) | ||||
|                  SPR_NOACCESS, SPR_NOACCESS, | ||||
|                  &spr_read_generic, &spr_write_generic, | ||||
|                  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_NOACCESS, SPR_NOACCESS, | ||||
|                  &spr_read_generic, &spr_write_generic, | ||||
| @ -4282,11 +4316,10 @@ static void init_proc_e300 (CPUPPCState *env) | ||||
|                                 PPC_WRTEE | PPC_RFDI |                  \ | ||||
|                                 PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \ | ||||
|                                 PPC_CACHE_DCBZ | PPC_CACHE_DCBA |       \ | ||||
|                                 PPC_MEM_TLBSYNC | PPC_TLBIVAX |         \ | ||||
|                                 PPC_BOOKE) | ||||
| #define POWERPC_INSNS2_e500v1  (PPC_NONE) | ||||
|                                 PPC_MEM_TLBSYNC | PPC_TLBIVAX) | ||||
| #define POWERPC_INSNS2_e500v1  (PPC2_BOOKE206) | ||||
| #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_INPUT_e500v1   (PPC_FLAGS_INPUT_BookE) | ||||
| #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_BUS_CLK) | ||||
| #define check_pow_e500v1       check_pow_hid0 | ||||
| #define init_proc_e500v1       init_proc_e500 | ||||
| #define init_proc_e500v1       init_proc_e500v1 | ||||
| 
 | ||||
| /* e500v2 core                                                               */ | ||||
| #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_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \ | ||||
|                                 PPC_CACHE_DCBZ | PPC_CACHE_DCBA |       \ | ||||
|                                 PPC_MEM_TLBSYNC | PPC_TLBIVAX |         \ | ||||
|                                 PPC_BOOKE) | ||||
| #define POWERPC_INSNS2_e500v2  (PPC_NONE) | ||||
|                                 PPC_MEM_TLBSYNC | PPC_TLBIVAX) | ||||
| #define POWERPC_INSNS2_e500v2  (PPC2_BOOKE206) | ||||
| #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_INPUT_e500v2   (PPC_FLAGS_INPUT_BookE) | ||||
| #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_BUS_CLK) | ||||
| #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 */ | ||||
|     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 */ | ||||
|     spr_register(env, SPR_BOOKE_PIR, "PIR", | ||||
|                  SPR_NOACCESS, SPR_NOACCESS, | ||||
| @ -4334,8 +4376,24 @@ static void init_proc_e500 (CPUPPCState *env) | ||||
|     /* Memory management */ | ||||
| #if !defined(CONFIG_USER_ONLY) | ||||
|     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 | ||||
|     gen_spr_BookE_FSL(env, 0x0000005F); | ||||
|     gen_spr_BookE206(env, 0x000000DF, tlbncfg); | ||||
|     /* XXX : not implemented */ | ||||
|     spr_register(env, SPR_HID0, "HID0", | ||||
|                  SPR_NOACCESS, SPR_NOACCESS, | ||||
| @ -4384,23 +4442,13 @@ static void init_proc_e500 (CPUPPCState *env) | ||||
|     /* XXX : not implemented */ | ||||
|     spr_register(env, SPR_Exxx_L1CSR0, "L1CSR0", | ||||
|                  SPR_NOACCESS, SPR_NOACCESS, | ||||
|                  &spr_read_generic, &spr_write_generic, | ||||
|                  &spr_read_generic, &spr_write_e500_l1csr0, | ||||
|                  0x00000000); | ||||
|     /* XXX : not implemented */ | ||||
|     spr_register(env, SPR_Exxx_L1CSR1, "L1CSR1", | ||||
|                  SPR_NOACCESS, SPR_NOACCESS, | ||||
|                  &spr_read_generic, &spr_write_generic, | ||||
|                  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_NOACCESS, SPR_NOACCESS, | ||||
|                  &spr_read_generic, &spr_write_generic, | ||||
| @ -4409,11 +4457,18 @@ static void init_proc_e500 (CPUPPCState *env) | ||||
|                  SPR_NOACCESS, SPR_NOACCESS, | ||||
|                  &spr_read_generic, &spr_write_generic, | ||||
|                  0x00000000); | ||||
|     spr_register(env, SPR_MMUCSR0, "MMUCSR0", | ||||
|                  SPR_NOACCESS, SPR_NOACCESS, | ||||
|                  &spr_read_generic, &spr_write_booke206_mmucsr0, | ||||
|                  0x00000000); | ||||
| 
 | ||||
| #if !defined(CONFIG_USER_ONLY) | ||||
|     env->nb_tlb = 64; | ||||
|     env->nb_ways = 1; | ||||
|     env->id_tlbs = 0; | ||||
|     env->nb_tlb = 0; | ||||
|     for (i = 0; i < BOOKE206_MAX_TLBN; i++) { | ||||
|         env->nb_tlb += booke206_tlb_size(env, i); | ||||
|     } | ||||
| #endif | ||||
| 
 | ||||
|     init_excp_e200(env); | ||||
|     env->dcache_line_size = 32; | ||||
|     env->icache_line_size = 32; | ||||
| @ -4421,6 +4476,16 @@ static void init_proc_e500 (CPUPPCState *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                                                      */ | ||||
| 
 | ||||
| /* 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: | ||||
|             mmu_model = "PowerPC BookE"; | ||||
|             break; | ||||
|         case POWERPC_MMU_BOOKE_FSL: | ||||
|             mmu_model = "PowerPC BookE FSL"; | ||||
|         case POWERPC_MMU_BOOKE206: | ||||
|             mmu_model = "PowerPC BookE 2.06"; | ||||
|             break; | ||||
|         case POWERPC_MMU_601: | ||||
|             mmu_model = "PowerPC 601"; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Alexander Graf
						Alexander Graf