master
c 532 lines 16.6 KB
Raw
1 /*
2 * PowerPC BookE MMU, TLB 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
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "qemu/osdep.h"
21 #include "exec/page-protection.h"
22 #include "exec/target_page.h"
23 #include "exec/log.h"
24 #include "cpu.h"
25 #include "internal.h"
26 #include "mmu-booke.h"
27
28 /* Generic TLB check function for embedded PowerPC implementations */
29 static bool ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
30 hwaddr *raddrp,
31 target_ulong address, uint32_t pid, int i)
32 {
33 target_ulong mask;
34
35 /* Check valid flag */
36 if (!(tlb->prot & PAGE_VALID)) {
37 return false;
38 }
39 mask = ~(tlb->size - 1);
40 qemu_log_mask(CPU_LOG_MMU, "%s: TLB %d address " TARGET_FMT_lx
41 " PID %u <=> " TARGET_FMT_lx " " TARGET_FMT_lx " %u %x\n",
42 __func__, i, address, pid, tlb->EPN,
43 mask, (uint32_t)tlb->PID, tlb->prot);
44 /* Check PID */
45 if (tlb->PID != 0 && tlb->PID != pid) {
46 return false;
47 }
48 /* Check effective address */
49 if ((address & mask) != tlb->EPN) {
50 return false;
51 }
52 *raddrp = (tlb->RPN & mask) | (address & ~mask);
53 return true;
54 }
55
56 /* Generic TLB search function for PowerPC embedded implementations */
57 int ppcemb_tlb_search(CPUPPCState *env, target_ulong address, uint32_t pid)
58 {
59 ppcemb_tlb_t *tlb;
60 hwaddr raddr;
61 int i;
62
63 for (i = 0; i < env->nb_tlb; i++) {
64 tlb = &env->tlb.tlbe[i];
65 if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, i)) {
66 return i;
67 }
68 }
69 return -1;
70 }
71
72 int mmu40x_get_physical_address(CPUPPCState *env, hwaddr *raddr, int *prot,
73 target_ulong address,
74 MMUAccessType access_type)
75 {
76 ppcemb_tlb_t *tlb;
77 int i, ret, zsel, zpr, pr;
78
79 ret = -1;
80 pr = FIELD_EX64(env->msr, MSR, PR);
81 for (i = 0; i < env->nb_tlb; i++) {
82 tlb = &env->tlb.tlbe[i];
83 if (!ppcemb_tlb_check(env, tlb, raddr, address,
84 env->spr[SPR_40x_PID], i)) {
85 continue;
86 }
87 zsel = (tlb->attr >> 4) & 0xF;
88 zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
89 qemu_log_mask(CPU_LOG_MMU,
90 "%s: TLB %d zsel %d zpr %d ty %d attr %08x\n",
91 __func__, i, zsel, zpr, access_type, tlb->attr);
92 /* Check execute enable bit */
93 switch (zpr) {
94 case 0x2:
95 if (pr != 0) {
96 goto check_perms;
97 }
98 /* fall through */
99 case 0x3:
100 /* All accesses granted */
101 *prot = PAGE_RWX;
102 ret = 0;
103 break;
104
105 case 0x0:
106 if (pr != 0) {
107 /* Raise Zone protection fault. */
108 env->spr[SPR_40x_ESR] = 1 << 22;
109 *prot = 0;
110 ret = -2;
111 break;
112 }
113 /* fall through */
114 case 0x1:
115 check_perms:
116 /* Check from TLB entry */
117 *prot = tlb->prot;
118 if (check_prot_access_type(*prot, access_type)) {
119 ret = 0;
120 } else {
121 env->spr[SPR_40x_ESR] = 0;
122 ret = -2;
123 }
124 break;
125 }
126 }
127 qemu_log_mask(CPU_LOG_MMU, "%s: access %s " TARGET_FMT_lx " => "
128 HWADDR_FMT_plx " %d %d\n", __func__,
129 ret < 0 ? "refused" : "granted", address,
130 ret < 0 ? 0 : *raddr, *prot, ret);
131
132 return ret;
133 }
134
135 static bool mmubooke_check_pid(CPUPPCState *env, ppcemb_tlb_t *tlb,
136 hwaddr *raddr, target_ulong addr, int i)
137 {
138 if (ppcemb_tlb_check(env, tlb, raddr, addr, env->spr[SPR_BOOKE_PID], i)) {
139 if (!env->nb_pids) {
140 /* Extend the physical address to 36 bits */
141 *raddr |= (uint64_t)(tlb->RPN & 0xF) << 32;
142 }
143 return true;
144 } else if (!env->nb_pids) {
145 return false;
146 }
147 if (env->spr[SPR_BOOKE_PID1] &&
148 ppcemb_tlb_check(env, tlb, raddr, addr, env->spr[SPR_BOOKE_PID1], i)) {
149 return true;
150 }
151 if (env->spr[SPR_BOOKE_PID2] &&
152 ppcemb_tlb_check(env, tlb, raddr, addr, env->spr[SPR_BOOKE_PID2], i)) {
153 return true;
154 }
155 return false;
156 }
157
158 static int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb,
159 hwaddr *raddr, int *prot, target_ulong address,
160 MMUAccessType access_type, int i)
161 {
162 if (!mmubooke_check_pid(env, tlb, raddr, address, i)) {
163 qemu_log_mask(CPU_LOG_MMU, "%s: TLB entry not found\n", __func__);
164 return -1;
165 }
166
167 /* Check the address space */
168 if ((access_type == MMU_INST_FETCH ?
169 FIELD_EX64(env->msr, MSR, IR) :
170 FIELD_EX64(env->msr, MSR, DR)) != (tlb->attr & 1)) {
171 qemu_log_mask(CPU_LOG_MMU, "%s: AS doesn't match\n", __func__);
172 return -1;
173 }
174
175 if (FIELD_EX64(env->msr, MSR, PR)) {
176 *prot = tlb->prot & 0xF;
177 } else {
178 *prot = (tlb->prot >> 4) & 0xF;
179 }
180 if (check_prot_access_type(*prot, access_type)) {
181 qemu_log_mask(CPU_LOG_MMU, "%s: good TLB!\n", __func__);
182 return 0;
183 }
184
185 qemu_log_mask(CPU_LOG_MMU, "%s: no prot match: %x\n", __func__, *prot);
186 return access_type == MMU_INST_FETCH ? -3 : -2;
187 }
188
189 static int mmubooke_get_physical_address(CPUPPCState *env, hwaddr *raddr,
190 int *prot, target_ulong address,
191 MMUAccessType access_type)
192 {
193 ppcemb_tlb_t *tlb;
194 int i, ret = -1;
195
196 for (i = 0; i < env->nb_tlb; i++) {
197 tlb = &env->tlb.tlbe[i];
198 ret = mmubooke_check_tlb(env, tlb, raddr, prot, address,
199 access_type, i);
200 if (ret != -1) {
201 break;
202 }
203 }
204 qemu_log_mask(CPU_LOG_MMU,
205 "%s: access %s " TARGET_FMT_lx " => " HWADDR_FMT_plx
206 " %d %d\n", __func__, ret < 0 ? "refused" : "granted",
207 address, ret < 0 ? -1 : *raddr, ret == -1 ? 0 : *prot, ret);
208 return ret;
209 }
210
211 hwaddr booke206_tlb_to_page_size(CPUPPCState *env, ppcmas_tlb_t *tlb)
212 {
213 int tlbm_size;
214
215 tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
216
217 return 1024ULL << tlbm_size;
218 }
219
220 /* TLB check function for MAS based SoftTLBs */
221 int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb, hwaddr *raddrp,
222 target_ulong address, uint32_t pid)
223 {
224 hwaddr mask;
225 uint32_t tlb_pid;
226
227 if (!FIELD_EX64(env->msr, MSR, CM)) {
228 /* In 32bit mode we can only address 32bit EAs */
229 address = (uint32_t)address;
230 }
231
232 /* Check valid flag */
233 if (!(tlb->mas1 & MAS1_VALID)) {
234 return -1;
235 }
236
237 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
238 qemu_log_mask(CPU_LOG_MMU, "%s: TLB ADDR=0x" TARGET_FMT_lx
239 " PID=0x%x MAS1=0x%x MAS2=0x%" PRIx64 " mask=0x%"
240 HWADDR_PRIx " MAS7_3=0x%" PRIx64 " MAS8=0x%" PRIx32 "\n",
241 __func__, address, pid, tlb->mas1, tlb->mas2, mask,
242 tlb->mas7_3, tlb->mas8);
243
244 /* Check PID */
245 tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
246 if (tlb_pid != 0 && tlb_pid != pid) {
247 return -1;
248 }
249
250 /* Check effective address */
251 if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
252 return -1;
253 }
254
255 if (raddrp) {
256 *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
257 }
258
259 return 0;
260 }
261
262 static bool is_epid_mmu(int mmu_idx)
263 {
264 return mmu_idx == PPC_TLB_EPID_STORE || mmu_idx == PPC_TLB_EPID_LOAD;
265 }
266
267 static uint32_t mmubooke206_esr(int mmu_idx, MMUAccessType access_type)
268 {
269 uint32_t esr = 0;
270 if (access_type == MMU_DATA_STORE) {
271 esr |= ESR_ST;
272 }
273 if (is_epid_mmu(mmu_idx)) {
274 esr |= ESR_EPID;
275 }
276 return esr;
277 }
278
279 /*
280 * Get EPID register given the mmu_idx. If this is regular load,
281 * construct the EPID access bits from current processor state
282 *
283 * Get the effective AS and PR bits and the PID. The PID is returned
284 * only if EPID load is requested, otherwise the caller must detect
285 * the correct EPID. Return true if valid EPID is returned.
286 */
287 static bool mmubooke206_get_as(CPUPPCState *env,
288 int mmu_idx, uint32_t *epid_out,
289 bool *as_out, bool *pr_out)
290 {
291 if (is_epid_mmu(mmu_idx)) {
292 uint32_t epidr;
293 if (mmu_idx == PPC_TLB_EPID_STORE) {
294 epidr = env->spr[SPR_BOOKE_EPSC];
295 } else {
296 epidr = env->spr[SPR_BOOKE_EPLC];
297 }
298 *epid_out = (epidr & EPID_EPID) >> EPID_EPID_SHIFT;
299 *as_out = !!(epidr & EPID_EAS);
300 *pr_out = !!(epidr & EPID_EPR);
301 return true;
302 } else {
303 *as_out = FIELD_EX64(env->msr, MSR, DS);
304 *pr_out = FIELD_EX64(env->msr, MSR, PR);
305 return false;
306 }
307 }
308
309 /* Check if the tlb found by hashing really matches */
310 static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb,
311 hwaddr *raddr, int *prot,
312 target_ulong address,
313 MMUAccessType access_type, int mmu_idx)
314 {
315 uint32_t epid;
316 bool as, pr;
317 bool use_epid = mmubooke206_get_as(env, mmu_idx, &epid, &as, &pr);
318
319 if (!use_epid) {
320 if (ppcmas_tlb_check(env, tlb, raddr, address,
321 env->spr[SPR_BOOKE_PID]) >= 0) {
322 goto found_tlb;
323 }
324
325 if (env->spr[SPR_BOOKE_PID1] &&
326 ppcmas_tlb_check(env, tlb, raddr, address,
327 env->spr[SPR_BOOKE_PID1]) >= 0) {
328 goto found_tlb;
329 }
330
331 if (env->spr[SPR_BOOKE_PID2] &&
332 ppcmas_tlb_check(env, tlb, raddr, address,
333 env->spr[SPR_BOOKE_PID2]) >= 0) {
334 goto found_tlb;
335 }
336 } else {
337 if (ppcmas_tlb_check(env, tlb, raddr, address, epid) >= 0) {
338 goto found_tlb;
339 }
340 }
341
342 qemu_log_mask(CPU_LOG_MMU, "%s: No TLB entry found for effective address "
343 "0x" TARGET_FMT_lx "\n", __func__, address);
344 return -1;
345
346 found_tlb:
347
348 /* Check the address space and permissions */
349 if (access_type == MMU_INST_FETCH) {
350 /* There is no way to fetch code using epid load */
351 assert(!use_epid);
352 as = FIELD_EX64(env->msr, MSR, IR);
353 }
354
355 if (as != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
356 qemu_log_mask(CPU_LOG_MMU, "%s: AS doesn't match\n", __func__);
357 return -1;
358 }
359
360 *prot = 0;
361 if (pr) {
362 if (tlb->mas7_3 & MAS3_UR) {
363 *prot |= PAGE_READ;
364 }
365 if (tlb->mas7_3 & MAS3_UW) {
366 *prot |= PAGE_WRITE;
367 }
368 if (tlb->mas7_3 & MAS3_UX) {
369 *prot |= PAGE_EXEC;
370 }
371 } else {
372 if (tlb->mas7_3 & MAS3_SR) {
373 *prot |= PAGE_READ;
374 }
375 if (tlb->mas7_3 & MAS3_SW) {
376 *prot |= PAGE_WRITE;
377 }
378 if (tlb->mas7_3 & MAS3_SX) {
379 *prot |= PAGE_EXEC;
380 }
381 }
382 if (check_prot_access_type(*prot, access_type)) {
383 qemu_log_mask(CPU_LOG_MMU, "%s: good TLB!\n", __func__);
384 return 0;
385 }
386
387 qemu_log_mask(CPU_LOG_MMU, "%s: no prot match: %x\n", __func__, *prot);
388 return access_type == MMU_INST_FETCH ? -3 : -2;
389 }
390
391 static int mmubooke206_get_physical_address(CPUPPCState *env, hwaddr *raddr,
392 int *prot, target_ulong address,
393 MMUAccessType access_type,
394 int mmu_idx)
395 {
396 ppcmas_tlb_t *tlb;
397 int i, j, ret = -1;
398
399 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
400 int ways = booke206_tlb_ways(env, i);
401 for (j = 0; j < ways; j++) {
402 tlb = booke206_get_tlbm(env, i, address, j);
403 if (!tlb) {
404 continue;
405 }
406 ret = mmubooke206_check_tlb(env, tlb, raddr, prot, address,
407 access_type, mmu_idx);
408 if (ret != -1) {
409 goto found_tlb;
410 }
411 }
412 }
413
414 found_tlb:
415
416 qemu_log_mask(CPU_LOG_MMU, "%s: access %s " TARGET_FMT_lx " => "
417 HWADDR_FMT_plx " %d %d\n", __func__,
418 ret < 0 ? "refused" : "granted", address,
419 ret < 0 ? -1 : *raddr, ret == -1 ? 0 : *prot, ret);
420 return ret;
421 }
422
423 static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address,
424 MMUAccessType access_type, int mmu_idx)
425 {
426 uint32_t epid;
427 bool as, pr;
428 uint32_t missed_tid = 0;
429 bool use_epid = mmubooke206_get_as(env, mmu_idx, &epid, &as, &pr);
430
431 if (access_type == MMU_INST_FETCH) {
432 as = FIELD_EX64(env->msr, MSR, IR);
433 }
434 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
435 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
436 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
437 env->spr[SPR_BOOKE_MAS3] = 0;
438 env->spr[SPR_BOOKE_MAS6] = 0;
439 env->spr[SPR_BOOKE_MAS7] = 0;
440
441 /* AS */
442 if (as) {
443 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
444 env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
445 }
446
447 env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
448 env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
449
450 if (!use_epid) {
451 switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
452 case MAS4_TIDSELD_PID0:
453 missed_tid = env->spr[SPR_BOOKE_PID];
454 break;
455 case MAS4_TIDSELD_PID1:
456 missed_tid = env->spr[SPR_BOOKE_PID1];
457 break;
458 case MAS4_TIDSELD_PID2:
459 missed_tid = env->spr[SPR_BOOKE_PID2];
460 break;
461 }
462 env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
463 } else {
464 missed_tid = epid;
465 env->spr[SPR_BOOKE_MAS6] |= missed_tid << 16;
466 }
467 env->spr[SPR_BOOKE_MAS1] |= (missed_tid << MAS1_TID_SHIFT);
468
469
470 /* next victim logic */
471 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
472 env->last_way++;
473 env->last_way &= booke206_tlb_ways(env, 0) - 1;
474 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
475 }
476
477 bool ppc_booke_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
478 hwaddr *raddrp, int *psizep, int *protp, int mmu_idx,
479 bool guest_visible)
480 {
481 CPUState *cs = CPU(cpu);
482 CPUPPCState *env = &cpu->env;
483 hwaddr raddr;
484 int prot, ret;
485
486 if (env->mmu_model == POWERPC_MMU_BOOKE206) {
487 ret = mmubooke206_get_physical_address(env, &raddr, &prot, eaddr,
488 access_type, mmu_idx);
489 } else {
490 ret = mmubooke_get_physical_address(env, &raddr, &prot, eaddr,
491 access_type);
492 }
493 if (ret == 0) {
494 *raddrp = raddr;
495 *protp = prot;
496 *psizep = qemu_target_page_bits();
497 return true;
498 } else if (!guest_visible) {
499 return false;
500 }
501
502 log_cpu_state_mask(CPU_LOG_MMU, cs, 0);
503 env->error_code = 0;
504 switch (ret) {
505 case -1:
506 /* No matches in page tables or TLB */
507 if (env->mmu_model == POWERPC_MMU_BOOKE206) {
508 booke206_update_mas_tlb_miss(env, eaddr, access_type, mmu_idx);
509 }
510 cs->exception_index = (access_type == MMU_INST_FETCH) ?
511 POWERPC_EXCP_ITLB : POWERPC_EXCP_DTLB;
512 env->spr[SPR_BOOKE_DEAR] = eaddr;
513 env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, access_type);
514 break;
515 case -2:
516 /* Access rights violation */
517 cs->exception_index = (access_type == MMU_INST_FETCH) ?
518 POWERPC_EXCP_ISI : POWERPC_EXCP_DSI;
519 if (access_type != MMU_INST_FETCH) {
520 env->spr[SPR_BOOKE_DEAR] = eaddr;
521 env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, access_type);
522 }
523 break;
524 case -3:
525 /* No execute protection violation */
526 cs->exception_index = POWERPC_EXCP_ISI;
527 env->spr[SPR_BOOKE_ESR] = 0;
528 break;
529 }
530
531 return false;
532 }