mmu_common.c (da5c1d20e9d63575cb358158895a0efa55682c35) | mmu_common.c (aa781c102a445e1007a307a972fed24c66b9c24c) |
---|---|
1/* 2 * PowerPC MMU, TLB, SLB and BAT emulation helpers for QEMU. 3 * 4 * Copyright (c) 2003-2007 Jocelyn Mayer 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either --- 77 unchanged lines hidden (view full) --- 86 nr += env->nb_tlb; 87 } 88 89 return nr; 90} 91 92/* Software driven TLB helpers */ 93 | 1/* 2 * PowerPC MMU, TLB, SLB and BAT emulation helpers for QEMU. 3 * 4 * Copyright (c) 2003-2007 Jocelyn Mayer 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either --- 77 unchanged lines hidden (view full) --- 86 nr += env->nb_tlb; 87 } 88 89 return nr; 90} 91 92/* Software driven TLB helpers */ 93 |
94static int ppc6xx_tlb_check(CPUPPCState *env, 95 mmu_ctx_t *ctx, target_ulong eaddr, 96 MMUAccessType access_type, target_ulong ptem, 97 bool key, bool nx) | 94static int ppc6xx_tlb_check(CPUPPCState *env, hwaddr *raddr, int *prot, 95 target_ulong eaddr, MMUAccessType access_type, 96 target_ulong ptem, bool key, bool nx) |
98{ 99 ppc6xx_tlb_t *tlb; 100 target_ulong *pte1p; 101 int nr, best, way, ret; 102 bool is_code = (access_type == MMU_INST_FETCH); 103 104 /* Initialize real address with an invalid value */ | 97{ 98 ppc6xx_tlb_t *tlb; 99 target_ulong *pte1p; 100 int nr, best, way, ret; 101 bool is_code = (access_type == MMU_INST_FETCH); 102 103 /* Initialize real address with an invalid value */ |
105 ctx->raddr = (hwaddr)-1ULL; | 104 *raddr = (hwaddr)-1ULL; |
106 best = -1; 107 ret = -1; /* No TLB found */ 108 for (way = 0; way < env->nb_ways; way++) { 109 nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code); 110 tlb = &env->tlb.tlb6[nr]; 111 /* This test "emulates" the PTE index match for hardware TLBs */ 112 if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) { 113 qemu_log_mask(CPU_LOG_MMU, "TLB %d/%d %s [" TARGET_FMT_lx --- 11 unchanged lines hidden (view full) --- 125 access_type == MMU_DATA_STORE ? 'S' : 'L', 126 access_type == MMU_INST_FETCH ? 'I' : 'D'); 127 /* Check validity and table match */ 128 if (!pte_is_valid(tlb->pte0) || ((tlb->pte0 >> 6) & 1) != 0 || 129 (tlb->pte0 & PTE_PTEM_MASK) != ptem) { 130 continue; 131 } 132 /* all matches should have equal RPN, WIMG & PP */ | 105 best = -1; 106 ret = -1; /* No TLB found */ 107 for (way = 0; way < env->nb_ways; way++) { 108 nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code); 109 tlb = &env->tlb.tlb6[nr]; 110 /* This test "emulates" the PTE index match for hardware TLBs */ 111 if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) { 112 qemu_log_mask(CPU_LOG_MMU, "TLB %d/%d %s [" TARGET_FMT_lx --- 11 unchanged lines hidden (view full) --- 124 access_type == MMU_DATA_STORE ? 'S' : 'L', 125 access_type == MMU_INST_FETCH ? 'I' : 'D'); 126 /* Check validity and table match */ 127 if (!pte_is_valid(tlb->pte0) || ((tlb->pte0 >> 6) & 1) != 0 || 128 (tlb->pte0 & PTE_PTEM_MASK) != ptem) { 129 continue; 130 } 131 /* all matches should have equal RPN, WIMG & PP */ |
133 if (ctx->raddr != (hwaddr)-1ULL && 134 (ctx->raddr & PTE_CHECK_MASK) != (tlb->pte1 & PTE_CHECK_MASK)) { | 132 if (*raddr != (hwaddr)-1ULL && 133 (*raddr & PTE_CHECK_MASK) != (tlb->pte1 & PTE_CHECK_MASK)) { |
135 qemu_log_mask(CPU_LOG_MMU, "Bad RPN/WIMG/PP\n"); 136 /* TLB inconsistency */ 137 continue; 138 } 139 /* Keep the matching PTE information */ 140 best = nr; | 134 qemu_log_mask(CPU_LOG_MMU, "Bad RPN/WIMG/PP\n"); 135 /* TLB inconsistency */ 136 continue; 137 } 138 /* Keep the matching PTE information */ 139 best = nr; |
141 ctx->raddr = tlb->pte1; 142 ctx->prot = ppc_hash32_prot(key, tlb->pte1 & HPTE32_R_PP, nx); 143 if (check_prot_access_type(ctx->prot, access_type)) { | 140 *raddr = tlb->pte1; 141 *prot = ppc_hash32_prot(key, tlb->pte1 & HPTE32_R_PP, nx); 142 if (check_prot_access_type(*prot, access_type)) { |
144 qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n"); 145 ret = 0; 146 break; 147 } else { 148 qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n"); 149 ret = -2; 150 } 151 } 152 if (best != -1) { 153 qemu_log_mask(CPU_LOG_MMU, "found TLB at addr " HWADDR_FMT_plx 154 " prot=%01x ret=%d\n", | 143 qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n"); 144 ret = 0; 145 break; 146 } else { 147 qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n"); 148 ret = -2; 149 } 150 } 151 if (best != -1) { 152 qemu_log_mask(CPU_LOG_MMU, "found TLB at addr " HWADDR_FMT_plx 153 " prot=%01x ret=%d\n", |
155 ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret); | 154 *raddr & TARGET_PAGE_MASK, *prot, ret); |
156 /* Update page flags */ 157 pte1p = &env->tlb.tlb6[best].pte1; 158 *pte1p |= 0x00000100; /* Update accessed flag */ 159 if (!(*pte1p & 0x00000080)) { 160 if (access_type == MMU_DATA_STORE && ret == 0) { 161 /* Update changed flag */ 162 *pte1p |= 0x00000080; 163 } else { 164 /* Force page fault for first write access */ | 155 /* Update page flags */ 156 pte1p = &env->tlb.tlb6[best].pte1; 157 *pte1p |= 0x00000100; /* Update accessed flag */ 158 if (!(*pte1p & 0x00000080)) { 159 if (access_type == MMU_DATA_STORE && ret == 0) { 160 /* Update changed flag */ 161 *pte1p |= 0x00000080; 162 } else { 163 /* Force page fault for first write access */ |
165 ctx->prot &= ~PAGE_WRITE; | 164 *prot &= ~PAGE_WRITE; |
166 } 167 } 168 } 169 if (ret == -1) { 170 int r = is_code ? SPR_ICMP : SPR_DCMP; 171 env->spr[r] = ptem; 172 } 173#if defined(DUMP_PAGE_TABLES) --- 165 unchanged lines hidden (view full) --- 339 } 340 /* Page address translation */ 341 qemu_log_mask(CPU_LOG_MMU, "htab_base " HWADDR_FMT_plx " htab_mask " 342 HWADDR_FMT_plx " hash " HWADDR_FMT_plx "\n", 343 ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash); 344 *hashp = hash; 345 346 /* Software TLB search */ | 165 } 166 } 167 } 168 if (ret == -1) { 169 int r = is_code ? SPR_ICMP : SPR_DCMP; 170 env->spr[r] = ptem; 171 } 172#if defined(DUMP_PAGE_TABLES) --- 165 unchanged lines hidden (view full) --- 338 } 339 /* Page address translation */ 340 qemu_log_mask(CPU_LOG_MMU, "htab_base " HWADDR_FMT_plx " htab_mask " 341 HWADDR_FMT_plx " hash " HWADDR_FMT_plx "\n", 342 ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash); 343 *hashp = hash; 344 345 /* Software TLB search */ |
347 return ppc6xx_tlb_check(env, ctx, eaddr, access_type, ptem, key, nx); | 346 return ppc6xx_tlb_check(env, &ctx->raddr, &ctx->prot, eaddr, 347 access_type, ptem, key, nx); |
348 } 349 350 /* Direct-store segment : absolutely *BUGGY* for now */ 351 qemu_log_mask(CPU_LOG_MMU, "direct store...\n"); 352 switch (type) { 353 case ACCESS_INT: 354 /* Integer load/store : only access allowed */ 355 break; --- 552 unchanged lines hidden --- | 348 } 349 350 /* Direct-store segment : absolutely *BUGGY* for now */ 351 qemu_log_mask(CPU_LOG_MMU, "direct store...\n"); 352 switch (type) { 353 case ACCESS_INT: 354 /* Integer load/store : only access allowed */ 355 break; --- 552 unchanged lines hidden --- |