]> git.proxmox.com Git - mirror_qemu.git/blob - target/ppc/mmu-radix64.c
target/ppc: Fix VXCVI return value
[mirror_qemu.git] / target / ppc / mmu-radix64.c
1 /*
2 * PowerPC Radix MMU mulation helpers for QEMU.
3 *
4 * Copyright (c) 2016 Suraj Jitindar Singh, IBM Corporation
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 "cpu.h"
22 #include "exec/exec-all.h"
23 #include "qemu/error-report.h"
24 #include "sysemu/kvm.h"
25 #include "kvm_ppc.h"
26 #include "exec/log.h"
27 #include "internal.h"
28 #include "mmu-radix64.h"
29 #include "mmu-book3s-v3.h"
30
31 static bool ppc_radix64_get_fully_qualified_addr(const CPUPPCState *env,
32 vaddr eaddr,
33 uint64_t *lpid, uint64_t *pid)
34 {
35 if (msr_hv) { /* MSR[HV] -> Hypervisor/bare metal */
36 switch (eaddr & R_EADDR_QUADRANT) {
37 case R_EADDR_QUADRANT0:
38 *lpid = 0;
39 *pid = env->spr[SPR_BOOKS_PID];
40 break;
41 case R_EADDR_QUADRANT1:
42 *lpid = env->spr[SPR_LPIDR];
43 *pid = env->spr[SPR_BOOKS_PID];
44 break;
45 case R_EADDR_QUADRANT2:
46 *lpid = env->spr[SPR_LPIDR];
47 *pid = 0;
48 break;
49 case R_EADDR_QUADRANT3:
50 *lpid = 0;
51 *pid = 0;
52 break;
53 default:
54 g_assert_not_reached();
55 }
56 } else { /* !MSR[HV] -> Guest */
57 switch (eaddr & R_EADDR_QUADRANT) {
58 case R_EADDR_QUADRANT0: /* Guest application */
59 *lpid = env->spr[SPR_LPIDR];
60 *pid = env->spr[SPR_BOOKS_PID];
61 break;
62 case R_EADDR_QUADRANT1: /* Illegal */
63 case R_EADDR_QUADRANT2:
64 return false;
65 case R_EADDR_QUADRANT3: /* Guest OS */
66 *lpid = env->spr[SPR_LPIDR];
67 *pid = 0; /* pid set to 0 -> addresses guest operating system */
68 break;
69 default:
70 g_assert_not_reached();
71 }
72 }
73
74 return true;
75 }
76
77 static void ppc_radix64_raise_segi(PowerPCCPU *cpu, MMUAccessType access_type,
78 vaddr eaddr)
79 {
80 CPUState *cs = CPU(cpu);
81 CPUPPCState *env = &cpu->env;
82
83 switch (access_type) {
84 case MMU_INST_FETCH:
85 /* Instruction Segment Interrupt */
86 cs->exception_index = POWERPC_EXCP_ISEG;
87 break;
88 case MMU_DATA_STORE:
89 case MMU_DATA_LOAD:
90 /* Data Segment Interrupt */
91 cs->exception_index = POWERPC_EXCP_DSEG;
92 env->spr[SPR_DAR] = eaddr;
93 break;
94 default:
95 g_assert_not_reached();
96 }
97 env->error_code = 0;
98 }
99
100 static void ppc_radix64_raise_si(PowerPCCPU *cpu, MMUAccessType access_type,
101 vaddr eaddr, uint32_t cause)
102 {
103 CPUState *cs = CPU(cpu);
104 CPUPPCState *env = &cpu->env;
105
106 switch (access_type) {
107 case MMU_INST_FETCH:
108 /* Instruction Storage Interrupt */
109 cs->exception_index = POWERPC_EXCP_ISI;
110 env->error_code = cause;
111 break;
112 case MMU_DATA_STORE:
113 cause |= DSISR_ISSTORE;
114 /* fall through */
115 case MMU_DATA_LOAD:
116 /* Data Storage Interrupt */
117 cs->exception_index = POWERPC_EXCP_DSI;
118 env->spr[SPR_DSISR] = cause;
119 env->spr[SPR_DAR] = eaddr;
120 env->error_code = 0;
121 break;
122 default:
123 g_assert_not_reached();
124 }
125 }
126
127 static void ppc_radix64_raise_hsi(PowerPCCPU *cpu, MMUAccessType access_type,
128 vaddr eaddr, hwaddr g_raddr, uint32_t cause)
129 {
130 CPUState *cs = CPU(cpu);
131 CPUPPCState *env = &cpu->env;
132
133 switch (access_type) {
134 case MMU_INST_FETCH:
135 /* H Instruction Storage Interrupt */
136 cs->exception_index = POWERPC_EXCP_HISI;
137 env->spr[SPR_ASDR] = g_raddr;
138 env->error_code = cause;
139 break;
140 case MMU_DATA_STORE:
141 cause |= DSISR_ISSTORE;
142 /* fall through */
143 case MMU_DATA_LOAD:
144 /* H Data Storage Interrupt */
145 cs->exception_index = POWERPC_EXCP_HDSI;
146 env->spr[SPR_HDSISR] = cause;
147 env->spr[SPR_HDAR] = eaddr;
148 env->spr[SPR_ASDR] = g_raddr;
149 env->error_code = 0;
150 break;
151 default:
152 g_assert_not_reached();
153 }
154 }
155
156 static bool ppc_radix64_check_prot(PowerPCCPU *cpu, MMUAccessType access_type,
157 uint64_t pte, int *fault_cause, int *prot,
158 int mmu_idx, bool partition_scoped)
159 {
160 CPUPPCState *env = &cpu->env;
161 int need_prot;
162
163 /* Check Page Attributes (pte58:59) */
164 if ((pte & R_PTE_ATT) == R_PTE_ATT_NI_IO && access_type == MMU_INST_FETCH) {
165 /*
166 * Radix PTE entries with the non-idempotent I/O attribute are treated
167 * as guarded storage
168 */
169 *fault_cause |= SRR1_NOEXEC_GUARD;
170 return true;
171 }
172
173 /* Determine permissions allowed by Encoded Access Authority */
174 if (!partition_scoped && (pte & R_PTE_EAA_PRIV) && msr_pr) {
175 *prot = 0;
176 } else if (mmuidx_pr(mmu_idx) || (pte & R_PTE_EAA_PRIV) ||
177 partition_scoped) {
178 *prot = ppc_radix64_get_prot_eaa(pte);
179 } else { /* !msr_pr && !(pte & R_PTE_EAA_PRIV) && !partition_scoped */
180 *prot = ppc_radix64_get_prot_eaa(pte);
181 *prot &= ppc_radix64_get_prot_amr(cpu); /* Least combined permissions */
182 }
183
184 /* Check if requested access type is allowed */
185 need_prot = prot_for_access_type(access_type);
186 if (need_prot & ~*prot) { /* Page Protected for that Access */
187 *fault_cause |= DSISR_PROTFAULT;
188 return true;
189 }
190
191 return false;
192 }
193
194 static void ppc_radix64_set_rc(PowerPCCPU *cpu, MMUAccessType access_type,
195 uint64_t pte, hwaddr pte_addr, int *prot)
196 {
197 CPUState *cs = CPU(cpu);
198 uint64_t npte;
199
200 npte = pte | R_PTE_R; /* Always set reference bit */
201
202 if (access_type == MMU_DATA_STORE) { /* Store/Write */
203 npte |= R_PTE_C; /* Set change bit */
204 } else {
205 /*
206 * Treat the page as read-only for now, so that a later write
207 * will pass through this function again to set the C bit.
208 */
209 *prot &= ~PAGE_WRITE;
210 }
211
212 if (pte ^ npte) { /* If pte has changed then write it back */
213 stq_phys(cs->as, pte_addr, npte);
214 }
215 }
216
217 static int ppc_radix64_next_level(AddressSpace *as, vaddr eaddr,
218 uint64_t *pte_addr, uint64_t *nls,
219 int *psize, uint64_t *pte, int *fault_cause)
220 {
221 uint64_t index, pde;
222
223 if (*nls < 5) { /* Directory maps less than 2**5 entries */
224 *fault_cause |= DSISR_R_BADCONFIG;
225 return 1;
226 }
227
228 /* Read page <directory/table> entry from guest address space */
229 pde = ldq_phys(as, *pte_addr);
230 if (!(pde & R_PTE_VALID)) { /* Invalid Entry */
231 *fault_cause |= DSISR_NOPTE;
232 return 1;
233 }
234
235 *pte = pde;
236 *psize -= *nls;
237 if (!(pde & R_PTE_LEAF)) { /* Prepare for next iteration */
238 *nls = pde & R_PDE_NLS;
239 index = eaddr >> (*psize - *nls); /* Shift */
240 index &= ((1UL << *nls) - 1); /* Mask */
241 *pte_addr = (pde & R_PDE_NLB) + (index * sizeof(pde));
242 }
243 return 0;
244 }
245
246 static int ppc_radix64_walk_tree(AddressSpace *as, vaddr eaddr,
247 uint64_t base_addr, uint64_t nls,
248 hwaddr *raddr, int *psize, uint64_t *pte,
249 int *fault_cause, hwaddr *pte_addr)
250 {
251 uint64_t index, pde, rpn , mask;
252
253 if (nls < 5) { /* Directory maps less than 2**5 entries */
254 *fault_cause |= DSISR_R_BADCONFIG;
255 return 1;
256 }
257
258 index = eaddr >> (*psize - nls); /* Shift */
259 index &= ((1UL << nls) - 1); /* Mask */
260 *pte_addr = base_addr + (index * sizeof(pde));
261 do {
262 int ret;
263
264 ret = ppc_radix64_next_level(as, eaddr, pte_addr, &nls, psize, &pde,
265 fault_cause);
266 if (ret) {
267 return ret;
268 }
269 } while (!(pde & R_PTE_LEAF));
270
271 *pte = pde;
272 rpn = pde & R_PTE_RPN;
273 mask = (1UL << *psize) - 1;
274
275 /* Or high bits of rpn and low bits to ea to form whole real addr */
276 *raddr = (rpn & ~mask) | (eaddr & mask);
277 return 0;
278 }
279
280 static bool validate_pate(PowerPCCPU *cpu, uint64_t lpid, ppc_v3_pate_t *pate)
281 {
282 CPUPPCState *env = &cpu->env;
283
284 if (!(pate->dw0 & PATE0_HR)) {
285 return false;
286 }
287 if (lpid == 0 && !msr_hv) {
288 return false;
289 }
290 if ((pate->dw0 & PATE1_R_PRTS) < 5) {
291 return false;
292 }
293 /* More checks ... */
294 return true;
295 }
296
297 static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu,
298 MMUAccessType access_type,
299 vaddr eaddr, hwaddr g_raddr,
300 ppc_v3_pate_t pate,
301 hwaddr *h_raddr, int *h_prot,
302 int *h_page_size, bool pde_addr,
303 int mmu_idx, bool guest_visible)
304 {
305 int fault_cause = 0;
306 hwaddr pte_addr;
307 uint64_t pte;
308
309 *h_page_size = PRTBE_R_GET_RTS(pate.dw0);
310 /* No valid pte or access denied due to protection */
311 if (ppc_radix64_walk_tree(CPU(cpu)->as, g_raddr, pate.dw0 & PRTBE_R_RPDB,
312 pate.dw0 & PRTBE_R_RPDS, h_raddr, h_page_size,
313 &pte, &fault_cause, &pte_addr) ||
314 ppc_radix64_check_prot(cpu, access_type, pte,
315 &fault_cause, h_prot, mmu_idx, true)) {
316 if (pde_addr) { /* address being translated was that of a guest pde */
317 fault_cause |= DSISR_PRTABLE_FAULT;
318 }
319 if (guest_visible) {
320 ppc_radix64_raise_hsi(cpu, access_type, eaddr, g_raddr, fault_cause);
321 }
322 return 1;
323 }
324
325 if (guest_visible) {
326 ppc_radix64_set_rc(cpu, access_type, pte, pte_addr, h_prot);
327 }
328
329 return 0;
330 }
331
332 static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu,
333 MMUAccessType access_type,
334 vaddr eaddr, uint64_t pid,
335 ppc_v3_pate_t pate, hwaddr *g_raddr,
336 int *g_prot, int *g_page_size,
337 int mmu_idx, bool guest_visible)
338 {
339 CPUState *cs = CPU(cpu);
340 CPUPPCState *env = &cpu->env;
341 uint64_t offset, size, prtbe_addr, prtbe0, base_addr, nls, index, pte;
342 int fault_cause = 0, h_page_size, h_prot;
343 hwaddr h_raddr, pte_addr;
344 int ret;
345
346 /* Index Process Table by PID to Find Corresponding Process Table Entry */
347 offset = pid * sizeof(struct prtb_entry);
348 size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12);
349 if (offset >= size) {
350 /* offset exceeds size of the process table */
351 if (guest_visible) {
352 ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_NOPTE);
353 }
354 return 1;
355 }
356 prtbe_addr = (pate.dw1 & PATE1_R_PRTB) + offset;
357
358 if (cpu->vhyp) {
359 prtbe0 = ldq_phys(cs->as, prtbe_addr);
360 } else {
361 /*
362 * Process table addresses are subject to partition-scoped
363 * translation
364 *
365 * On a Radix host, the partition-scoped page table for LPID=0
366 * is only used to translate the effective addresses of the
367 * process table entries.
368 */
369 ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, prtbe_addr,
370 pate, &h_raddr, &h_prot,
371 &h_page_size, true,
372 /* mmu_idx is 5 because we're translating from hypervisor scope */
373 5, guest_visible);
374 if (ret) {
375 return ret;
376 }
377 prtbe0 = ldq_phys(cs->as, h_raddr);
378 }
379
380 /* Walk Radix Tree from Process Table Entry to Convert EA to RA */
381 *g_page_size = PRTBE_R_GET_RTS(prtbe0);
382 base_addr = prtbe0 & PRTBE_R_RPDB;
383 nls = prtbe0 & PRTBE_R_RPDS;
384 if (msr_hv || cpu->vhyp) {
385 /*
386 * Can treat process table addresses as real addresses
387 */
388 ret = ppc_radix64_walk_tree(cs->as, eaddr & R_EADDR_MASK, base_addr,
389 nls, g_raddr, g_page_size, &pte,
390 &fault_cause, &pte_addr);
391 if (ret) {
392 /* No valid PTE */
393 if (guest_visible) {
394 ppc_radix64_raise_si(cpu, access_type, eaddr, fault_cause);
395 }
396 return ret;
397 }
398 } else {
399 uint64_t rpn, mask;
400
401 index = (eaddr & R_EADDR_MASK) >> (*g_page_size - nls); /* Shift */
402 index &= ((1UL << nls) - 1); /* Mask */
403 pte_addr = base_addr + (index * sizeof(pte));
404
405 /*
406 * Each process table address is subject to a partition-scoped
407 * translation
408 */
409 do {
410 ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, pte_addr,
411 pate, &h_raddr, &h_prot,
412 &h_page_size, true,
413 /* mmu_idx is 5 because we're translating from hypervisor scope */
414 5, guest_visible);
415 if (ret) {
416 return ret;
417 }
418
419 ret = ppc_radix64_next_level(cs->as, eaddr & R_EADDR_MASK, &h_raddr,
420 &nls, g_page_size, &pte, &fault_cause);
421 if (ret) {
422 /* No valid pte */
423 if (guest_visible) {
424 ppc_radix64_raise_si(cpu, access_type, eaddr, fault_cause);
425 }
426 return ret;
427 }
428 pte_addr = h_raddr;
429 } while (!(pte & R_PTE_LEAF));
430
431 rpn = pte & R_PTE_RPN;
432 mask = (1UL << *g_page_size) - 1;
433
434 /* Or high bits of rpn and low bits to ea to form whole real addr */
435 *g_raddr = (rpn & ~mask) | (eaddr & mask);
436 }
437
438 if (ppc_radix64_check_prot(cpu, access_type, pte, &fault_cause,
439 g_prot, mmu_idx, false)) {
440 /* Access denied due to protection */
441 if (guest_visible) {
442 ppc_radix64_raise_si(cpu, access_type, eaddr, fault_cause);
443 }
444 return 1;
445 }
446
447 if (guest_visible) {
448 ppc_radix64_set_rc(cpu, access_type, pte, pte_addr, g_prot);
449 }
450
451 return 0;
452 }
453
454 /*
455 * Radix tree translation is a 2 steps translation process:
456 *
457 * 1. Process-scoped translation: Guest Eff Addr -> Guest Real Addr
458 * 2. Partition-scoped translation: Guest Real Addr -> Host Real Addr
459 *
460 * MSR[HV]
461 * +-------------+----------------+---------------+
462 * | | HV = 0 | HV = 1 |
463 * +-------------+----------------+---------------+
464 * | Relocation | Partition | No |
465 * | = Off | Scoped | Translation |
466 * Relocation +-------------+----------------+---------------+
467 * | Relocation | Partition & | Process |
468 * | = On | Process Scoped | Scoped |
469 * +-------------+----------------+---------------+
470 */
471 bool ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
472 hwaddr *raddr, int *psizep, int *protp, int mmu_idx,
473 bool guest_visible)
474 {
475 CPUPPCState *env = &cpu->env;
476 uint64_t lpid, pid;
477 ppc_v3_pate_t pate;
478 int psize, prot;
479 hwaddr g_raddr;
480 bool relocation;
481
482 assert(!(mmuidx_hv(mmu_idx) && cpu->vhyp));
483
484 relocation = !mmuidx_real(mmu_idx);
485
486 /* HV or virtual hypervisor Real Mode Access */
487 if (!relocation && (mmuidx_hv(mmu_idx) || cpu->vhyp)) {
488 /* In real mode top 4 effective addr bits (mostly) ignored */
489 *raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL;
490
491 /* In HV mode, add HRMOR if top EA bit is clear */
492 if (mmuidx_hv(mmu_idx) || !env->has_hv_mode) {
493 if (!(eaddr >> 63)) {
494 *raddr |= env->spr[SPR_HRMOR];
495 }
496 }
497 *protp = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
498 *psizep = TARGET_PAGE_BITS;
499 return true;
500 }
501
502 /*
503 * Check UPRT (we avoid the check in real mode to deal with
504 * transitional states during kexec.
505 */
506 if (guest_visible && !ppc64_use_proc_tbl(cpu)) {
507 qemu_log_mask(LOG_GUEST_ERROR,
508 "LPCR:UPRT not set in radix mode ! LPCR="
509 TARGET_FMT_lx "\n", env->spr[SPR_LPCR]);
510 }
511
512 /* Virtual Mode Access - get the fully qualified address */
513 if (!ppc_radix64_get_fully_qualified_addr(&cpu->env, eaddr, &lpid, &pid)) {
514 if (guest_visible) {
515 ppc_radix64_raise_segi(cpu, access_type, eaddr);
516 }
517 return false;
518 }
519
520 /* Get Process Table */
521 if (cpu->vhyp) {
522 PPCVirtualHypervisorClass *vhc;
523 vhc = PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
524 vhc->get_pate(cpu->vhyp, &pate);
525 } else {
526 if (!ppc64_v3_get_pate(cpu, lpid, &pate)) {
527 if (guest_visible) {
528 ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_NOPTE);
529 }
530 return false;
531 }
532 if (!validate_pate(cpu, lpid, &pate)) {
533 if (guest_visible) {
534 ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_R_BADCONFIG);
535 }
536 return false;
537 }
538 }
539
540 *psizep = INT_MAX;
541 *protp = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
542
543 /*
544 * Perform process-scoped translation if relocation enabled.
545 *
546 * - Translates an effective address to a host real address in
547 * quadrants 0 and 3 when HV=1.
548 *
549 * - Translates an effective address to a guest real address.
550 */
551 if (relocation) {
552 int ret = ppc_radix64_process_scoped_xlate(cpu, access_type, eaddr, pid,
553 pate, &g_raddr, &prot,
554 &psize, mmu_idx, guest_visible);
555 if (ret) {
556 return false;
557 }
558 *psizep = MIN(*psizep, psize);
559 *protp &= prot;
560 } else {
561 g_raddr = eaddr & R_EADDR_MASK;
562 }
563
564 if (cpu->vhyp) {
565 *raddr = g_raddr;
566 } else {
567 /*
568 * Perform partition-scoped translation if !HV or HV access to
569 * quadrants 1 or 2. Translates a guest real address to a host
570 * real address.
571 */
572 if (lpid || !mmuidx_hv(mmu_idx)) {
573 int ret;
574
575 ret = ppc_radix64_partition_scoped_xlate(cpu, access_type, eaddr,
576 g_raddr, pate, raddr,
577 &prot, &psize, false,
578 mmu_idx, guest_visible);
579 if (ret) {
580 return false;
581 }
582 *psizep = MIN(*psizep, psize);
583 *protp &= prot;
584 } else {
585 *raddr = g_raddr;
586 }
587 }
588
589 return true;
590 }