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, |     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__) */ | ||||||
|  | |||||||
| @ -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.  */ | ||||||
|  | |||||||
| @ -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) | ||||||
|  | |||||||
| @ -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 */ | ||||||
|  | |||||||
| @ -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], | ||||||
|  | |||||||
| @ -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"; | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Alexander Graf
						Alexander Graf