xref: /qemu/target/ppc/mmu-radix64.c (revision b114a0b9)
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                                    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 (msr_pr || (pte & R_PTE_EAA_PRIV) || partition_scoped) {
177         *prot = ppc_radix64_get_prot_eaa(pte);
178     } else { /* !msr_pr && !(pte & R_PTE_EAA_PRIV) && !partition_scoped */
179         *prot = ppc_radix64_get_prot_eaa(pte);
180         *prot &= ppc_radix64_get_prot_amr(cpu); /* Least combined permissions */
181     }
182 
183     /* Check if requested access type is allowed */
184     need_prot = prot_for_access_type(access_type);
185     if (need_prot & ~*prot) { /* Page Protected for that Access */
186         *fault_cause |= DSISR_PROTFAULT;
187         return true;
188     }
189 
190     return false;
191 }
192 
193 static void ppc_radix64_set_rc(PowerPCCPU *cpu, MMUAccessType access_type,
194                                uint64_t pte, hwaddr pte_addr, int *prot)
195 {
196     CPUState *cs = CPU(cpu);
197     uint64_t npte;
198 
199     npte = pte | R_PTE_R; /* Always set reference bit */
200 
201     if (access_type == MMU_DATA_STORE) { /* Store/Write */
202         npte |= R_PTE_C; /* Set change bit */
203     } else {
204         /*
205          * Treat the page as read-only for now, so that a later write
206          * will pass through this function again to set the C bit.
207          */
208         *prot &= ~PAGE_WRITE;
209     }
210 
211     if (pte ^ npte) { /* If pte has changed then write it back */
212         stq_phys(cs->as, pte_addr, npte);
213     }
214 }
215 
216 static int ppc_radix64_next_level(AddressSpace *as, vaddr eaddr,
217                                   uint64_t *pte_addr, uint64_t *nls,
218                                   int *psize, uint64_t *pte, int *fault_cause)
219 {
220     uint64_t index, pde;
221 
222     if (*nls < 5) { /* Directory maps less than 2**5 entries */
223         *fault_cause |= DSISR_R_BADCONFIG;
224         return 1;
225     }
226 
227     /* Read page <directory/table> entry from guest address space */
228     pde = ldq_phys(as, *pte_addr);
229     if (!(pde & R_PTE_VALID)) {         /* Invalid Entry */
230         *fault_cause |= DSISR_NOPTE;
231         return 1;
232     }
233 
234     *pte = pde;
235     *psize -= *nls;
236     if (!(pde & R_PTE_LEAF)) { /* Prepare for next iteration */
237         *nls = pde & R_PDE_NLS;
238         index = eaddr >> (*psize - *nls);       /* Shift */
239         index &= ((1UL << *nls) - 1);           /* Mask */
240         *pte_addr = (pde & R_PDE_NLB) + (index * sizeof(pde));
241     }
242     return 0;
243 }
244 
245 static int ppc_radix64_walk_tree(AddressSpace *as, vaddr eaddr,
246                                  uint64_t base_addr, uint64_t nls,
247                                  hwaddr *raddr, int *psize, uint64_t *pte,
248                                  int *fault_cause, hwaddr *pte_addr)
249 {
250     uint64_t index, pde, rpn , mask;
251 
252     if (nls < 5) { /* Directory maps less than 2**5 entries */
253         *fault_cause |= DSISR_R_BADCONFIG;
254         return 1;
255     }
256 
257     index = eaddr >> (*psize - nls);    /* Shift */
258     index &= ((1UL << nls) - 1);       /* Mask */
259     *pte_addr = base_addr + (index * sizeof(pde));
260     do {
261         int ret;
262 
263         ret = ppc_radix64_next_level(as, eaddr, pte_addr, &nls, psize, &pde,
264                                      fault_cause);
265         if (ret) {
266             return ret;
267         }
268     } while (!(pde & R_PTE_LEAF));
269 
270     *pte = pde;
271     rpn = pde & R_PTE_RPN;
272     mask = (1UL << *psize) - 1;
273 
274     /* Or high bits of rpn and low bits to ea to form whole real addr */
275     *raddr = (rpn & ~mask) | (eaddr & mask);
276     return 0;
277 }
278 
279 static bool validate_pate(PowerPCCPU *cpu, uint64_t lpid, ppc_v3_pate_t *pate)
280 {
281     CPUPPCState *env = &cpu->env;
282 
283     if (!(pate->dw0 & PATE0_HR)) {
284         return false;
285     }
286     if (lpid == 0 && !msr_hv) {
287         return false;
288     }
289     if ((pate->dw0 & PATE1_R_PRTS) < 5) {
290         return false;
291     }
292     /* More checks ... */
293     return true;
294 }
295 
296 static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu,
297                                               MMUAccessType access_type,
298                                               vaddr eaddr, hwaddr g_raddr,
299                                               ppc_v3_pate_t pate,
300                                               hwaddr *h_raddr, int *h_prot,
301                                               int *h_page_size, bool pde_addr,
302                                               bool guest_visible)
303 {
304     int fault_cause = 0;
305     hwaddr pte_addr;
306     uint64_t pte;
307 
308     *h_page_size = PRTBE_R_GET_RTS(pate.dw0);
309     /* No valid pte or access denied due to protection */
310     if (ppc_radix64_walk_tree(CPU(cpu)->as, g_raddr, pate.dw0 & PRTBE_R_RPDB,
311                               pate.dw0 & PRTBE_R_RPDS, h_raddr, h_page_size,
312                               &pte, &fault_cause, &pte_addr) ||
313         ppc_radix64_check_prot(cpu, access_type, pte, &fault_cause, h_prot, true)) {
314         if (pde_addr) { /* address being translated was that of a guest pde */
315             fault_cause |= DSISR_PRTABLE_FAULT;
316         }
317         if (guest_visible) {
318             ppc_radix64_raise_hsi(cpu, access_type, eaddr, g_raddr, fault_cause);
319         }
320         return 1;
321     }
322 
323     if (guest_visible) {
324         ppc_radix64_set_rc(cpu, access_type, pte, pte_addr, h_prot);
325     }
326 
327     return 0;
328 }
329 
330 static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu,
331                                             MMUAccessType access_type,
332                                             vaddr eaddr, uint64_t pid,
333                                             ppc_v3_pate_t pate, hwaddr *g_raddr,
334                                             int *g_prot, int *g_page_size,
335                                             bool guest_visible)
336 {
337     CPUState *cs = CPU(cpu);
338     CPUPPCState *env = &cpu->env;
339     uint64_t offset, size, prtbe_addr, prtbe0, base_addr, nls, index, pte;
340     int fault_cause = 0, h_page_size, h_prot;
341     hwaddr h_raddr, pte_addr;
342     int ret;
343 
344     /* Index Process Table by PID to Find Corresponding Process Table Entry */
345     offset = pid * sizeof(struct prtb_entry);
346     size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12);
347     if (offset >= size) {
348         /* offset exceeds size of the process table */
349         if (guest_visible) {
350             ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_NOPTE);
351         }
352         return 1;
353     }
354     prtbe_addr = (pate.dw1 & PATE1_R_PRTB) + offset;
355 
356     if (cpu->vhyp) {
357         prtbe0 = ldq_phys(cs->as, prtbe_addr);
358     } else {
359         /*
360          * Process table addresses are subject to partition-scoped
361          * translation
362          *
363          * On a Radix host, the partition-scoped page table for LPID=0
364          * is only used to translate the effective addresses of the
365          * process table entries.
366          */
367         ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, prtbe_addr,
368                                                  pate, &h_raddr, &h_prot,
369                                                  &h_page_size, true,
370                                                  guest_visible);
371         if (ret) {
372             return ret;
373         }
374         prtbe0 = ldq_phys(cs->as, h_raddr);
375     }
376 
377     /* Walk Radix Tree from Process Table Entry to Convert EA to RA */
378     *g_page_size = PRTBE_R_GET_RTS(prtbe0);
379     base_addr = prtbe0 & PRTBE_R_RPDB;
380     nls = prtbe0 & PRTBE_R_RPDS;
381     if (msr_hv || cpu->vhyp) {
382         /*
383          * Can treat process table addresses as real addresses
384          */
385         ret = ppc_radix64_walk_tree(cs->as, eaddr & R_EADDR_MASK, base_addr,
386                                     nls, g_raddr, g_page_size, &pte,
387                                     &fault_cause, &pte_addr);
388         if (ret) {
389             /* No valid PTE */
390             if (guest_visible) {
391                 ppc_radix64_raise_si(cpu, access_type, eaddr, fault_cause);
392             }
393             return ret;
394         }
395     } else {
396         uint64_t rpn, mask;
397 
398         index = (eaddr & R_EADDR_MASK) >> (*g_page_size - nls); /* Shift */
399         index &= ((1UL << nls) - 1);                            /* Mask */
400         pte_addr = base_addr + (index * sizeof(pte));
401 
402         /*
403          * Each process table address is subject to a partition-scoped
404          * translation
405          */
406         do {
407             ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, pte_addr,
408                                                      pate, &h_raddr, &h_prot,
409                                                      &h_page_size, true,
410                                                      guest_visible);
411             if (ret) {
412                 return ret;
413             }
414 
415             ret = ppc_radix64_next_level(cs->as, eaddr & R_EADDR_MASK, &h_raddr,
416                                          &nls, g_page_size, &pte, &fault_cause);
417             if (ret) {
418                 /* No valid pte */
419                 if (guest_visible) {
420                     ppc_radix64_raise_si(cpu, access_type, eaddr, fault_cause);
421                 }
422                 return ret;
423             }
424             pte_addr = h_raddr;
425         } while (!(pte & R_PTE_LEAF));
426 
427         rpn = pte & R_PTE_RPN;
428         mask = (1UL << *g_page_size) - 1;
429 
430         /* Or high bits of rpn and low bits to ea to form whole real addr */
431         *g_raddr = (rpn & ~mask) | (eaddr & mask);
432     }
433 
434     if (ppc_radix64_check_prot(cpu, access_type, pte, &fault_cause, g_prot, false)) {
435         /* Access denied due to protection */
436         if (guest_visible) {
437             ppc_radix64_raise_si(cpu, access_type, eaddr, fault_cause);
438         }
439         return 1;
440     }
441 
442     if (guest_visible) {
443         ppc_radix64_set_rc(cpu, access_type, pte, pte_addr, g_prot);
444     }
445 
446     return 0;
447 }
448 
449 /*
450  * Radix tree translation is a 2 steps translation process:
451  *
452  * 1. Process-scoped translation:   Guest Eff Addr  -> Guest Real Addr
453  * 2. Partition-scoped translation: Guest Real Addr -> Host Real Addr
454  *
455  *                                  MSR[HV]
456  *              +-------------+----------------+---------------+
457  *              |             |     HV = 0     |     HV = 1    |
458  *              +-------------+----------------+---------------+
459  *              | Relocation  |    Partition   |      No       |
460  *              | = Off       |     Scoped     |  Translation  |
461  *  Relocation  +-------------+----------------+---------------+
462  *              | Relocation  |   Partition &  |    Process    |
463  *              | = On        | Process Scoped |    Scoped     |
464  *              +-------------+----------------+---------------+
465  */
466 static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr,
467                              MMUAccessType access_type,
468                              bool relocation,
469                              hwaddr *raddr, int *psizep, int *protp,
470                              bool guest_visible)
471 {
472     CPUPPCState *env = &cpu->env;
473     uint64_t lpid, pid;
474     ppc_v3_pate_t pate;
475     int psize, prot;
476     hwaddr g_raddr;
477 
478     /* Virtual Mode Access - get the fully qualified address */
479     if (!ppc_radix64_get_fully_qualified_addr(&cpu->env, eaddr, &lpid, &pid)) {
480         if (guest_visible) {
481             ppc_radix64_raise_segi(cpu, access_type, eaddr);
482         }
483         return 1;
484     }
485 
486     /* Get Process Table */
487     if (cpu->vhyp) {
488         PPCVirtualHypervisorClass *vhc;
489         vhc = PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
490         vhc->get_pate(cpu->vhyp, &pate);
491     } else {
492         if (!ppc64_v3_get_pate(cpu, lpid, &pate)) {
493             if (guest_visible) {
494                 ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_NOPTE);
495             }
496             return 1;
497         }
498         if (!validate_pate(cpu, lpid, &pate)) {
499             if (guest_visible) {
500                 ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_R_BADCONFIG);
501             }
502             return 1;
503         }
504     }
505 
506     *psizep = INT_MAX;
507     *protp = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
508 
509     /*
510      * Perform process-scoped translation if relocation enabled.
511      *
512      * - Translates an effective address to a host real address in
513      *   quadrants 0 and 3 when HV=1.
514      *
515      * - Translates an effective address to a guest real address.
516      */
517     if (relocation) {
518         int ret = ppc_radix64_process_scoped_xlate(cpu, access_type, eaddr, pid,
519                                                    pate, &g_raddr, &prot,
520                                                    &psize, guest_visible);
521         if (ret) {
522             return ret;
523         }
524         *psizep = MIN(*psizep, psize);
525         *protp &= prot;
526     } else {
527         g_raddr = eaddr & R_EADDR_MASK;
528     }
529 
530     if (cpu->vhyp) {
531         *raddr = g_raddr;
532     } else {
533         /*
534          * Perform partition-scoped translation if !HV or HV access to
535          * quadrants 1 or 2. Translates a guest real address to a host
536          * real address.
537          */
538         if (lpid || !msr_hv) {
539             int ret;
540 
541             ret = ppc_radix64_partition_scoped_xlate(cpu, access_type, eaddr,
542                                                      g_raddr, pate, raddr,
543                                                      &prot, &psize, false,
544                                                      guest_visible);
545             if (ret) {
546                 return ret;
547             }
548             *psizep = MIN(*psizep, psize);
549             *protp &= prot;
550         } else {
551             *raddr = g_raddr;
552         }
553     }
554 
555     return 0;
556 }
557 
558 int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
559                                  int mmu_idx)
560 {
561     CPUState *cs = CPU(cpu);
562     CPUPPCState *env = &cpu->env;
563     int page_size, prot;
564     bool relocation;
565     MMUAccessType access_type;
566     hwaddr raddr;
567 
568     assert(!(msr_hv && cpu->vhyp));
569     assert((rwx == 0) || (rwx == 1) || (rwx == 2));
570     access_type = rwx;
571 
572     relocation = (access_type == MMU_INST_FETCH ? msr_ir : msr_dr);
573     /* HV or virtual hypervisor Real Mode Access */
574     if (!relocation && (msr_hv || cpu->vhyp)) {
575         /* In real mode top 4 effective addr bits (mostly) ignored */
576         raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL;
577 
578         /* In HV mode, add HRMOR if top EA bit is clear */
579         if (msr_hv || !env->has_hv_mode) {
580             if (!(eaddr >> 63)) {
581                 raddr |= env->spr[SPR_HRMOR];
582            }
583         }
584         tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
585                      PAGE_READ | PAGE_WRITE | PAGE_EXEC, mmu_idx,
586                      TARGET_PAGE_SIZE);
587         return 0;
588     }
589 
590     /*
591      * Check UPRT (we avoid the check in real mode to deal with
592      * transitional states during kexec.
593      */
594     if (!ppc64_use_proc_tbl(cpu)) {
595         qemu_log_mask(LOG_GUEST_ERROR,
596                       "LPCR:UPRT not set in radix mode ! LPCR="
597                       TARGET_FMT_lx "\n", env->spr[SPR_LPCR]);
598     }
599 
600     /* Translate eaddr to raddr (where raddr is addr qemu needs for access) */
601     if (ppc_radix64_xlate(cpu, eaddr, access_type, relocation, &raddr,
602                           &page_size, &prot, true)) {
603         return 1;
604     }
605 
606     tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
607                  prot, mmu_idx, 1UL << page_size);
608     return 0;
609 }
610 
611 hwaddr ppc_radix64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong eaddr)
612 {
613     CPUPPCState *env = &cpu->env;
614     int psize, prot;
615     hwaddr raddr;
616 
617     /* Handle Real Mode */
618     if ((msr_dr == 0) && (msr_hv || cpu->vhyp)) {
619         /* In real mode top 4 effective addr bits (mostly) ignored */
620         return eaddr & 0x0FFFFFFFFFFFFFFFULL;
621     }
622 
623     if (ppc_radix64_xlate(cpu, eaddr, 0, msr_dr, &raddr, &psize,
624                           &prot, false)) {
625         return -1;
626     }
627 
628     return raddr & TARGET_PAGE_MASK;
629 }
630