]> git.proxmox.com Git - mirror_qemu.git/blame - target-ppc/mmu-hash32.c
ppc: Clean up includes
[mirror_qemu.git] / target-ppc / mmu-hash32.c
CommitLineData
9d7c3f4a
DG
1/*
2 * PowerPC MMU, TLB and BAT emulation helpers for QEMU.
3 *
4 * Copyright (c) 2003-2007 Jocelyn Mayer
5 * Copyright (c) 2013 David Gibson, IBM Corporation
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 */
20
0d75590d 21#include "qemu/osdep.h"
9d7c3f4a 22#include "cpu.h"
2ef6175a 23#include "exec/helper-proto.h"
9d7c3f4a
DG
24#include "sysemu/kvm.h"
25#include "kvm_ppc.h"
26#include "mmu-hash32.h"
27
98132796 28//#define DEBUG_BAT
9d7c3f4a 29
98132796 30#ifdef DEBUG_BATS
48880da6 31# define LOG_BATS(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
98132796
DG
32#else
33# define LOG_BATS(...) do { } while (0)
34#endif
35
5dc68eb0
DG
36struct mmu_ctx_hash32 {
37 hwaddr raddr; /* Real address */
5dc68eb0 38 int prot; /* Protection bits */
5dc68eb0 39 int key; /* Access key */
5dc68eb0
DG
40};
41
e01b4445 42static int ppc_hash32_pp_prot(int key, int pp, int nx)
496272a7 43{
e01b4445 44 int prot;
496272a7 45
496272a7
DG
46 if (key == 0) {
47 switch (pp) {
48 case 0x0:
49 case 0x1:
50 case 0x2:
e01b4445
DG
51 prot = PAGE_READ | PAGE_WRITE;
52 break;
53
496272a7 54 case 0x3:
e01b4445 55 prot = PAGE_READ;
496272a7 56 break;
e01b4445
DG
57
58 default:
59 abort();
496272a7
DG
60 }
61 } else {
62 switch (pp) {
63 case 0x0:
e01b4445 64 prot = 0;
496272a7 65 break;
e01b4445 66
496272a7
DG
67 case 0x1:
68 case 0x3:
e01b4445 69 prot = PAGE_READ;
496272a7 70 break;
e01b4445 71
496272a7 72 case 0x2:
e01b4445 73 prot = PAGE_READ | PAGE_WRITE;
496272a7 74 break;
e01b4445
DG
75
76 default:
77 abort();
496272a7
DG
78 }
79 }
80 if (nx == 0) {
e01b4445 81 prot |= PAGE_EXEC;
496272a7
DG
82 }
83
e01b4445 84 return prot;
496272a7
DG
85}
86
e01b4445
DG
87static int ppc_hash32_pte_prot(CPUPPCState *env,
88 target_ulong sr, ppc_hash_pte32_t pte)
496272a7 89{
e01b4445 90 unsigned pp, key;
496272a7 91
e01b4445
DG
92 key = !!(msr_pr ? (sr & SR32_KP) : (sr & SR32_KS));
93 pp = pte.pte1 & HPTE32_R_PP;
496272a7 94
e01b4445 95 return ppc_hash32_pp_prot(key, pp, !!(sr & SR32_NX));
496272a7
DG
96}
97
6fc76aa9
DG
98static target_ulong hash32_bat_size(CPUPPCState *env,
99 target_ulong batu, target_ulong batl)
98132796 100{
6fc76aa9
DG
101 if ((msr_pr && !(batu & BATU32_VP))
102 || (!msr_pr && !(batu & BATU32_VS))) {
103 return 0;
98132796 104 }
6fc76aa9
DG
105
106 return BATU32_BEPI & ~((batu & BATU32_BL) << 15);
98132796
DG
107}
108
e1d49515
DG
109static int hash32_bat_prot(CPUPPCState *env,
110 target_ulong batu, target_ulong batl)
111{
112 int pp, prot;
113
114 prot = 0;
115 pp = batl & BATL32_PP;
116 if (pp != 0) {
117 prot = PAGE_READ | PAGE_EXEC;
118 if (pp == 0x2) {
119 prot |= PAGE_WRITE;
120 }
121 }
122 return prot;
123}
124
6fc76aa9 125static target_ulong hash32_bat_601_size(CPUPPCState *env,
e1d49515 126 target_ulong batu, target_ulong batl)
98132796 127{
6fc76aa9
DG
128 if (!(batl & BATL32_601_V)) {
129 return 0;
130 }
131
132 return BATU32_BEPI & ~((batl & BATL32_601_BL) << 17);
e1d49515
DG
133}
134
135static int hash32_bat_601_prot(CPUPPCState *env,
136 target_ulong batu, target_ulong batl)
137{
138 int key, pp;
139
140 pp = batu & BATU32_601_PP;
141 if (msr_pr == 0) {
142 key = !!(batu & BATU32_601_KS);
143 } else {
144 key = !!(batu & BATU32_601_KP);
145 }
e01b4445 146 return ppc_hash32_pp_prot(key, pp, 0);
98132796
DG
147}
148
145e52f3
DG
149static hwaddr ppc_hash32_bat_lookup(CPUPPCState *env, target_ulong ea, int rwx,
150 int *prot)
98132796 151{
9986ed1e 152 target_ulong *BATlt, *BATut;
145e52f3 153 int i;
98132796
DG
154
155 LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
145e52f3 156 rwx == 2 ? 'I' : 'D', ea);
91cda45b 157 if (rwx == 2) {
98132796
DG
158 BATlt = env->IBAT[1];
159 BATut = env->IBAT[0];
91cda45b 160 } else {
98132796
DG
161 BATlt = env->DBAT[1];
162 BATut = env->DBAT[0];
98132796
DG
163 }
164 for (i = 0; i < env->nb_BATs; i++) {
9986ed1e
DG
165 target_ulong batu = BATut[i];
166 target_ulong batl = BATlt[i];
6fc76aa9 167 target_ulong mask;
9986ed1e 168
98132796 169 if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
6fc76aa9 170 mask = hash32_bat_601_size(env, batu, batl);
98132796 171 } else {
6fc76aa9 172 mask = hash32_bat_size(env, batu, batl);
98132796
DG
173 }
174 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
175 " BATl " TARGET_FMT_lx "\n", __func__,
145e52f3
DG
176 type == ACCESS_CODE ? 'I' : 'D', i, ea, batu, batl);
177
178 if (mask && ((ea & mask) == (batu & BATU32_BEPI))) {
179 hwaddr raddr = (batl & mask) | (ea & ~mask);
180
181 if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
182 *prot = hash32_bat_601_prot(env, batu, batl);
183 } else {
184 *prot = hash32_bat_prot(env, batu, batl);
98132796 185 }
145e52f3
DG
186
187 return raddr & TARGET_PAGE_MASK;
98132796
DG
188 }
189 }
145e52f3
DG
190
191 /* No hit */
98132796 192#if defined(DEBUG_BATS)
145e52f3
DG
193 if (qemu_log_enabled()) {
194 LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", ea);
195 for (i = 0; i < 4; i++) {
196 BATu = &BATut[i];
197 BATl = &BATlt[i];
198 BEPIu = *BATu & BATU32_BEPIU;
199 BEPIl = *BATu & BATU32_BEPIL;
200 bl = (*BATu & 0x00001FFC) << 15;
201 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
202 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
203 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
204 __func__, type == ACCESS_CODE ? 'I' : 'D', i, ea,
205 *BATu, *BATl, BEPIu, BEPIl, bl);
98132796 206 }
98132796 207 }
145e52f3
DG
208#endif
209
210 return -1;
98132796
DG
211}
212
723ed73a
DG
213static int ppc_hash32_direct_store(CPUPPCState *env, target_ulong sr,
214 target_ulong eaddr, int rwx,
215 hwaddr *raddr, int *prot)
216{
27103424 217 CPUState *cs = CPU(ppc_env_get_cpu(env));
723ed73a
DG
218 int key = !!(msr_pr ? (sr & SR32_KP) : (sr & SR32_KS));
219
339aaf5b 220 qemu_log_mask(CPU_LOG_MMU, "direct store...\n");
723ed73a
DG
221
222 if ((sr & 0x1FF00000) >> 20 == 0x07f) {
223 /* Memory-forced I/O controller interface access */
224 /* If T=1 and BUID=x'07F', the 601 performs a memory access
225 * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
226 */
227 *raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
228 *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
229 return 0;
230 }
231
232 if (rwx == 2) {
233 /* No code fetch is allowed in direct-store areas */
27103424 234 cs->exception_index = POWERPC_EXCP_ISI;
caa597bd
DG
235 env->error_code = 0x10000000;
236 return 1;
723ed73a
DG
237 }
238
239 switch (env->access_type) {
240 case ACCESS_INT:
241 /* Integer load/store : only access allowed */
242 break;
243 case ACCESS_FLOAT:
244 /* Floating point load/store */
27103424 245 cs->exception_index = POWERPC_EXCP_ALIGN;
caa597bd
DG
246 env->error_code = POWERPC_EXCP_ALIGN_FP;
247 env->spr[SPR_DAR] = eaddr;
248 return 1;
723ed73a
DG
249 case ACCESS_RES:
250 /* lwarx, ldarx or srwcx. */
caa597bd
DG
251 env->error_code = 0;
252 env->spr[SPR_DAR] = eaddr;
253 if (rwx == 1) {
254 env->spr[SPR_DSISR] = 0x06000000;
255 } else {
256 env->spr[SPR_DSISR] = 0x04000000;
257 }
258 return 1;
723ed73a
DG
259 case ACCESS_CACHE:
260 /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
261 /* Should make the instruction do no-op.
262 * As it already do no-op, it's quite easy :-)
263 */
264 *raddr = eaddr;
265 return 0;
266 case ACCESS_EXT:
267 /* eciwx or ecowx */
27103424 268 cs->exception_index = POWERPC_EXCP_DSI;
caa597bd
DG
269 env->error_code = 0;
270 env->spr[SPR_DAR] = eaddr;
271 if (rwx == 1) {
272 env->spr[SPR_DSISR] = 0x06100000;
273 } else {
274 env->spr[SPR_DSISR] = 0x04100000;
275 }
276 return 1;
723ed73a 277 default:
48880da6 278 cpu_abort(cs, "ERROR: instruction should not need "
723ed73a 279 "address translation\n");
723ed73a
DG
280 }
281 if ((rwx == 1 || key != 1) && (rwx == 0 || key != 0)) {
282 *raddr = eaddr;
caa597bd 283 return 0;
723ed73a 284 } else {
27103424 285 cs->exception_index = POWERPC_EXCP_DSI;
caa597bd
DG
286 env->error_code = 0;
287 env->spr[SPR_DAR] = eaddr;
288 if (rwx == 1) {
289 env->spr[SPR_DSISR] = 0x0a000000;
290 } else {
291 env->spr[SPR_DSISR] = 0x08000000;
292 }
293 return 1;
723ed73a
DG
294 }
295}
296
59191721
DG
297hwaddr get_pteg_offset32(CPUPPCState *env, hwaddr hash)
298{
d5aea6f3 299 return (hash * HASH_PTEG_SIZE_32) & env->htab_mask;
59191721
DG
300}
301
aea390e4
DG
302static hwaddr ppc_hash32_pteg_search(CPUPPCState *env, hwaddr pteg_off,
303 bool secondary, target_ulong ptem,
304 ppc_hash_pte32_t *pte)
305{
306 hwaddr pte_offset = pteg_off;
307 target_ulong pte0, pte1;
308 int i;
309
310 for (i = 0; i < HPTES_PER_GROUP; i++) {
311 pte0 = ppc_hash32_load_hpte0(env, pte_offset);
312 pte1 = ppc_hash32_load_hpte1(env, pte_offset);
313
314 if ((pte0 & HPTE32_V_VALID)
315 && (secondary == !!(pte0 & HPTE32_V_SECONDARY))
316 && HPTE32_V_COMPARE(pte0, ptem)) {
317 pte->pte0 = pte0;
318 pte->pte1 = pte1;
319 return pte_offset;
320 }
321
322 pte_offset += HASH_PTE_SIZE_32;
323 }
324
325 return -1;
326}
327
7f3bdc2d
DG
328static hwaddr ppc_hash32_htab_lookup(CPUPPCState *env,
329 target_ulong sr, target_ulong eaddr,
330 ppc_hash_pte32_t *pte)
c69b6151 331{
aea390e4 332 hwaddr pteg_off, pte_offset;
a1ff751a
DG
333 hwaddr hash;
334 uint32_t vsid, pgidx, ptem;
c69b6151 335
a1ff751a 336 vsid = sr & SR32_VSID;
a1ff751a
DG
337 pgidx = (eaddr & ~SEGMENT_MASK_256M) >> TARGET_PAGE_BITS;
338 hash = vsid ^ pgidx;
339 ptem = (vsid << 7) | (pgidx >> 10);
340
341 /* Page address translation */
339aaf5b
AP
342 qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx
343 " htab_mask " TARGET_FMT_plx
a1ff751a
DG
344 " hash " TARGET_FMT_plx "\n",
345 env->htab_base, env->htab_mask, hash);
346
347 /* Primary PTEG lookup */
339aaf5b 348 qemu_log_mask(CPU_LOG_MMU, "0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
a1ff751a
DG
349 " vsid=%" PRIx32 " ptem=%" PRIx32
350 " hash=" TARGET_FMT_plx "\n",
351 env->htab_base, env->htab_mask, vsid, ptem, hash);
352 pteg_off = get_pteg_offset32(env, hash);
7f3bdc2d 353 pte_offset = ppc_hash32_pteg_search(env, pteg_off, 0, ptem, pte);
a1ff751a
DG
354 if (pte_offset == -1) {
355 /* Secondary PTEG lookup */
339aaf5b 356 qemu_log_mask(CPU_LOG_MMU, "1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
a1ff751a
DG
357 " vsid=%" PRIx32 " api=%" PRIx32
358 " hash=" TARGET_FMT_plx "\n", env->htab_base,
359 env->htab_mask, vsid, ptem, ~hash);
360 pteg_off = get_pteg_offset32(env, ~hash);
7f3bdc2d 361 pte_offset = ppc_hash32_pteg_search(env, pteg_off, 1, ptem, pte);
a1ff751a
DG
362 }
363
7f3bdc2d 364 return pte_offset;
c69b6151 365}
0480884f 366
6d11d998
DG
367static hwaddr ppc_hash32_pte_raddr(target_ulong sr, ppc_hash_pte32_t pte,
368 target_ulong eaddr)
369{
75d5ec89 370 hwaddr rpn = pte.pte1 & HPTE32_R_RPN;
6d11d998
DG
371 hwaddr mask = ~TARGET_PAGE_MASK;
372
373 return (rpn & ~mask) | (eaddr & mask);
374}
375
d0e39c5d 376int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, target_ulong eaddr, int rwx,
caa597bd 377 int mmu_idx)
0480884f 378{
d0e39c5d
AF
379 CPUState *cs = CPU(cpu);
380 CPUPPCState *env = &cpu->env;
a1ff751a 381 target_ulong sr;
7f3bdc2d
DG
382 hwaddr pte_offset;
383 ppc_hash_pte32_t pte;
caa597bd 384 int prot;
b3440746 385 uint32_t new_pte1;
e01b4445 386 const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC};
caa597bd 387 hwaddr raddr;
0480884f 388
6a980110
DG
389 assert((rwx == 0) || (rwx == 1) || (rwx == 2));
390
65d61643
DG
391 /* 1. Handle real mode accesses */
392 if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) {
393 /* Translation is off */
caa597bd 394 raddr = eaddr;
0c591eb0 395 tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
caa597bd
DG
396 PAGE_READ | PAGE_WRITE | PAGE_EXEC, mmu_idx,
397 TARGET_PAGE_SIZE);
65d61643
DG
398 return 0;
399 }
400
401 /* 2. Check Block Address Translation entries (BATs) */
402 if (env->nb_BATs != 0) {
caa597bd
DG
403 raddr = ppc_hash32_bat_lookup(env, eaddr, rwx, &prot);
404 if (raddr != -1) {
405 if (need_prot[rwx] & ~prot) {
406 if (rwx == 2) {
27103424 407 cs->exception_index = POWERPC_EXCP_ISI;
caa597bd
DG
408 env->error_code = 0x08000000;
409 } else {
27103424 410 cs->exception_index = POWERPC_EXCP_DSI;
caa597bd
DG
411 env->error_code = 0;
412 env->spr[SPR_DAR] = eaddr;
413 if (rwx == 1) {
414 env->spr[SPR_DSISR] = 0x0a000000;
415 } else {
416 env->spr[SPR_DSISR] = 0x08000000;
417 }
418 }
419 return 1;
e01b4445 420 }
caa597bd 421
0c591eb0 422 tlb_set_page(cs, eaddr & TARGET_PAGE_MASK,
caa597bd
DG
423 raddr & TARGET_PAGE_MASK, prot, mmu_idx,
424 TARGET_PAGE_SIZE);
e01b4445 425 return 0;
65d61643
DG
426 }
427 }
428
4b9605a5 429 /* 3. Look up the Segment Register */
0480884f 430 sr = env->sr[eaddr >> 28];
4b9605a5 431
4b9605a5
DG
432 /* 4. Handle direct store segments */
433 if (sr & SR32_T) {
caa597bd
DG
434 if (ppc_hash32_direct_store(env, sr, eaddr, rwx,
435 &raddr, &prot) == 0) {
0c591eb0 436 tlb_set_page(cs, eaddr & TARGET_PAGE_MASK,
caa597bd
DG
437 raddr & TARGET_PAGE_MASK, prot, mmu_idx,
438 TARGET_PAGE_SIZE);
439 return 0;
440 } else {
441 return 1;
442 }
4b9605a5
DG
443 }
444
bb218042 445 /* 5. Check for segment level no-execute violation */
e01b4445 446 if ((rwx == 2) && (sr & SR32_NX)) {
27103424 447 cs->exception_index = POWERPC_EXCP_ISI;
caa597bd
DG
448 env->error_code = 0x10000000;
449 return 1;
bb218042 450 }
7f3bdc2d
DG
451
452 /* 6. Locate the PTE in the hash table */
453 pte_offset = ppc_hash32_htab_lookup(env, sr, eaddr, &pte);
454 if (pte_offset == -1) {
caa597bd 455 if (rwx == 2) {
27103424 456 cs->exception_index = POWERPC_EXCP_ISI;
caa597bd
DG
457 env->error_code = 0x40000000;
458 } else {
27103424 459 cs->exception_index = POWERPC_EXCP_DSI;
caa597bd
DG
460 env->error_code = 0;
461 env->spr[SPR_DAR] = eaddr;
462 if (rwx == 1) {
463 env->spr[SPR_DSISR] = 0x42000000;
464 } else {
465 env->spr[SPR_DSISR] = 0x40000000;
466 }
467 }
468
469 return 1;
7f3bdc2d 470 }
339aaf5b
AP
471 qemu_log_mask(CPU_LOG_MMU,
472 "found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
7f3bdc2d
DG
473
474 /* 7. Check access permissions */
6a980110 475
caa597bd 476 prot = ppc_hash32_pte_prot(env, sr, pte);
6a980110 477
caa597bd 478 if (need_prot[rwx] & ~prot) {
6a980110 479 /* Access right violation */
339aaf5b 480 qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
caa597bd 481 if (rwx == 2) {
27103424 482 cs->exception_index = POWERPC_EXCP_ISI;
caa597bd
DG
483 env->error_code = 0x08000000;
484 } else {
27103424 485 cs->exception_index = POWERPC_EXCP_DSI;
caa597bd
DG
486 env->error_code = 0;
487 env->spr[SPR_DAR] = eaddr;
488 if (rwx == 1) {
489 env->spr[SPR_DSISR] = 0x0a000000;
490 } else {
491 env->spr[SPR_DSISR] = 0x08000000;
492 }
493 }
494 return 1;
6a980110
DG
495 }
496
339aaf5b 497 qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
87dc3fd1
DG
498
499 /* 8. Update PTE referenced and changed bits if necessary */
500
b3440746
DG
501 new_pte1 = pte.pte1 | HPTE32_R_R; /* set referenced bit */
502 if (rwx == 1) {
503 new_pte1 |= HPTE32_R_C; /* set changed (dirty) bit */
504 } else {
505 /* Treat the page as read-only for now, so that a later write
506 * will pass through this function again to set the C bit */
caa597bd 507 prot &= ~PAGE_WRITE;
b3440746
DG
508 }
509
510 if (new_pte1 != pte.pte1) {
511 ppc_hash32_store_hpte1(env, pte_offset, new_pte1);
7f3bdc2d 512 }
0480884f 513
6d11d998
DG
514 /* 9. Determine the real address from the PTE */
515
caa597bd
DG
516 raddr = ppc_hash32_pte_raddr(sr, pte, eaddr);
517
0c591eb0 518 tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
caa597bd 519 prot, mmu_idx, TARGET_PAGE_SIZE);
e01b4445
DG
520
521 return 0;
0480884f 522}
629bd516 523
5883d8b2 524hwaddr ppc_hash32_get_phys_page_debug(CPUPPCState *env, target_ulong eaddr)
f2ad6be8 525{
5883d8b2
DG
526 target_ulong sr;
527 hwaddr pte_offset;
528 ppc_hash_pte32_t pte;
529 int prot;
530
531 if (msr_dr == 0) {
532 /* Translation is off */
533 return eaddr;
534 }
f2ad6be8 535
5883d8b2
DG
536 if (env->nb_BATs != 0) {
537 hwaddr raddr = ppc_hash32_bat_lookup(env, eaddr, 0, &prot);
538 if (raddr != -1) {
539 return raddr;
540 }
541 }
542
543 sr = env->sr[eaddr >> 28];
544
545 if (sr & SR32_T) {
546 /* FIXME: Add suitable debug support for Direct Store segments */
547 return -1;
548 }
549
550 pte_offset = ppc_hash32_htab_lookup(env, sr, eaddr, &pte);
551 if (pte_offset == -1) {
f2ad6be8
DG
552 return -1;
553 }
554
5883d8b2 555 return ppc_hash32_pte_raddr(sr, pte, eaddr) & TARGET_PAGE_MASK;
f2ad6be8 556}