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