xref: /openbmc/qemu/target/ppc/mmu-radix64.c (revision 744c72a8)
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 "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 "internal.h"
29 #include "mmu-radix64.h"
30 #include "mmu-book3s-v3.h"
31 
32 static bool ppc_radix64_get_fully_qualified_addr(const CPUPPCState *env,
33                                                  vaddr eaddr,
34                                                  uint64_t *lpid, uint64_t *pid)
35 {
36     if (msr_hv) { /* MSR[HV] -> Hypervisor/bare metal */
37         switch (eaddr & R_EADDR_QUADRANT) {
38         case R_EADDR_QUADRANT0:
39             *lpid = 0;
40             *pid = env->spr[SPR_BOOKS_PID];
41             break;
42         case R_EADDR_QUADRANT1:
43             *lpid = env->spr[SPR_LPIDR];
44             *pid = env->spr[SPR_BOOKS_PID];
45             break;
46         case R_EADDR_QUADRANT2:
47             *lpid = env->spr[SPR_LPIDR];
48             *pid = 0;
49             break;
50         case R_EADDR_QUADRANT3:
51             *lpid = 0;
52             *pid = 0;
53             break;
54         default:
55             g_assert_not_reached();
56         }
57     } else {  /* !MSR[HV] -> Guest */
58         switch (eaddr & R_EADDR_QUADRANT) {
59         case R_EADDR_QUADRANT0: /* Guest application */
60             *lpid = env->spr[SPR_LPIDR];
61             *pid = env->spr[SPR_BOOKS_PID];
62             break;
63         case R_EADDR_QUADRANT1: /* Illegal */
64         case R_EADDR_QUADRANT2:
65             return false;
66         case R_EADDR_QUADRANT3: /* Guest OS */
67             *lpid = env->spr[SPR_LPIDR];
68             *pid = 0; /* pid set to 0 -> addresses guest operating system */
69             break;
70         default:
71             g_assert_not_reached();
72         }
73     }
74 
75     return true;
76 }
77 
78 static void ppc_radix64_raise_segi(PowerPCCPU *cpu, MMUAccessType access_type,
79                                    vaddr eaddr)
80 {
81     CPUState *cs = CPU(cpu);
82     CPUPPCState *env = &cpu->env;
83 
84     switch (access_type) {
85     case MMU_INST_FETCH:
86         /* Instruction Segment Interrupt */
87         cs->exception_index = POWERPC_EXCP_ISEG;
88         break;
89     case MMU_DATA_STORE:
90     case MMU_DATA_LOAD:
91         /* Data Segment Interrupt */
92         cs->exception_index = POWERPC_EXCP_DSEG;
93         env->spr[SPR_DAR] = eaddr;
94         break;
95     default:
96         g_assert_not_reached();
97     }
98     env->error_code = 0;
99 }
100 
101 static void ppc_radix64_raise_si(PowerPCCPU *cpu, MMUAccessType access_type,
102                                  vaddr eaddr, uint32_t cause)
103 {
104     CPUState *cs = CPU(cpu);
105     CPUPPCState *env = &cpu->env;
106 
107     switch (access_type) {
108     case MMU_INST_FETCH:
109         /* Instruction Storage Interrupt */
110         cs->exception_index = POWERPC_EXCP_ISI;
111         env->error_code = cause;
112         break;
113     case MMU_DATA_STORE:
114         cause |= DSISR_ISSTORE;
115         /* fall through */
116     case MMU_DATA_LOAD:
117         /* Data Storage Interrupt */
118         cs->exception_index = POWERPC_EXCP_DSI;
119         env->spr[SPR_DSISR] = cause;
120         env->spr[SPR_DAR] = eaddr;
121         env->error_code = 0;
122         break;
123     default:
124         g_assert_not_reached();
125     }
126 }
127 
128 static void ppc_radix64_raise_hsi(PowerPCCPU *cpu, MMUAccessType access_type,
129                                   vaddr eaddr, hwaddr g_raddr, uint32_t cause)
130 {
131     CPUState *cs = CPU(cpu);
132     CPUPPCState *env = &cpu->env;
133 
134     switch (access_type) {
135     case MMU_INST_FETCH:
136         /* H Instruction Storage Interrupt */
137         cs->exception_index = POWERPC_EXCP_HISI;
138         env->spr[SPR_ASDR] = g_raddr;
139         env->error_code = cause;
140         break;
141     case MMU_DATA_STORE:
142         cause |= DSISR_ISSTORE;
143         /* fall through */
144     case MMU_DATA_LOAD:
145         /* H Data Storage Interrupt */
146         cs->exception_index = POWERPC_EXCP_HDSI;
147         env->spr[SPR_HDSISR] = cause;
148         env->spr[SPR_HDAR] = eaddr;
149         env->spr[SPR_ASDR] = g_raddr;
150         env->error_code = 0;
151         break;
152     default:
153         g_assert_not_reached();
154     }
155 }
156 
157 static bool ppc_radix64_check_prot(PowerPCCPU *cpu, MMUAccessType access_type,
158                                    uint64_t pte, int *fault_cause, int *prot,
159                                    bool partition_scoped)
160 {
161     CPUPPCState *env = &cpu->env;
162     int need_prot;
163 
164     /* Check Page Attributes (pte58:59) */
165     if ((pte & R_PTE_ATT) == R_PTE_ATT_NI_IO && access_type == MMU_INST_FETCH) {
166         /*
167          * Radix PTE entries with the non-idempotent I/O attribute are treated
168          * as guarded storage
169          */
170         *fault_cause |= SRR1_NOEXEC_GUARD;
171         return true;
172     }
173 
174     /* Determine permissions allowed by Encoded Access Authority */
175     if (!partition_scoped && (pte & R_PTE_EAA_PRIV) && msr_pr) {
176         *prot = 0;
177     } else if (msr_pr || (pte & R_PTE_EAA_PRIV) || 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                                               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, &fault_cause, h_prot, true)) {
315         if (pde_addr) { /* address being translated was that of a guest pde */
316             fault_cause |= DSISR_PRTABLE_FAULT;
317         }
318         if (guest_visible) {
319             ppc_radix64_raise_hsi(cpu, access_type, eaddr, g_raddr, fault_cause);
320         }
321         return 1;
322     }
323 
324     if (guest_visible) {
325         ppc_radix64_set_rc(cpu, access_type, pte, pte_addr, h_prot);
326     }
327 
328     return 0;
329 }
330 
331 static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu,
332                                             MMUAccessType access_type,
333                                             vaddr eaddr, uint64_t pid,
334                                             ppc_v3_pate_t pate, hwaddr *g_raddr,
335                                             int *g_prot, int *g_page_size,
336                                             bool guest_visible)
337 {
338     CPUState *cs = CPU(cpu);
339     CPUPPCState *env = &cpu->env;
340     uint64_t offset, size, prtbe_addr, prtbe0, base_addr, nls, index, pte;
341     int fault_cause = 0, h_page_size, h_prot;
342     hwaddr h_raddr, pte_addr;
343     int ret;
344 
345     /* Index Process Table by PID to Find Corresponding Process Table Entry */
346     offset = pid * sizeof(struct prtb_entry);
347     size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12);
348     if (offset >= size) {
349         /* offset exceeds size of the process table */
350         if (guest_visible) {
351             ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_NOPTE);
352         }
353         return 1;
354     }
355     prtbe_addr = (pate.dw1 & PATE1_R_PRTB) + offset;
356 
357     if (cpu->vhyp) {
358         prtbe0 = ldq_phys(cs->as, prtbe_addr);
359     } else {
360         /*
361          * Process table addresses are subject to partition-scoped
362          * translation
363          *
364          * On a Radix host, the partition-scoped page table for LPID=0
365          * is only used to translate the effective addresses of the
366          * process table entries.
367          */
368         ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, prtbe_addr,
369                                                  pate, &h_raddr, &h_prot,
370                                                  &h_page_size, true,
371                                                  guest_visible);
372         if (ret) {
373             return ret;
374         }
375         prtbe0 = ldq_phys(cs->as, h_raddr);
376     }
377 
378     /* Walk Radix Tree from Process Table Entry to Convert EA to RA */
379     *g_page_size = PRTBE_R_GET_RTS(prtbe0);
380     base_addr = prtbe0 & PRTBE_R_RPDB;
381     nls = prtbe0 & PRTBE_R_RPDS;
382     if (msr_hv || cpu->vhyp) {
383         /*
384          * Can treat process table addresses as real addresses
385          */
386         ret = ppc_radix64_walk_tree(cs->as, eaddr & R_EADDR_MASK, base_addr,
387                                     nls, g_raddr, g_page_size, &pte,
388                                     &fault_cause, &pte_addr);
389         if (ret) {
390             /* No valid PTE */
391             if (guest_visible) {
392                 ppc_radix64_raise_si(cpu, access_type, eaddr, fault_cause);
393             }
394             return ret;
395         }
396     } else {
397         uint64_t rpn, mask;
398 
399         index = (eaddr & R_EADDR_MASK) >> (*g_page_size - nls); /* Shift */
400         index &= ((1UL << nls) - 1);                            /* Mask */
401         pte_addr = base_addr + (index * sizeof(pte));
402 
403         /*
404          * Each process table address is subject to a partition-scoped
405          * translation
406          */
407         do {
408             ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, pte_addr,
409                                                      pate, &h_raddr, &h_prot,
410                                                      &h_page_size, true,
411                                                      guest_visible);
412             if (ret) {
413                 return ret;
414             }
415 
416             ret = ppc_radix64_next_level(cs->as, eaddr & R_EADDR_MASK, &h_raddr,
417                                          &nls, g_page_size, &pte, &fault_cause);
418             if (ret) {
419                 /* No valid pte */
420                 if (guest_visible) {
421                     ppc_radix64_raise_si(cpu, access_type, eaddr, fault_cause);
422                 }
423                 return ret;
424             }
425             pte_addr = h_raddr;
426         } while (!(pte & R_PTE_LEAF));
427 
428         rpn = pte & R_PTE_RPN;
429         mask = (1UL << *g_page_size) - 1;
430 
431         /* Or high bits of rpn and low bits to ea to form whole real addr */
432         *g_raddr = (rpn & ~mask) | (eaddr & mask);
433     }
434 
435     if (ppc_radix64_check_prot(cpu, access_type, pte, &fault_cause, g_prot, false)) {
436         /* Access denied due to protection */
437         if (guest_visible) {
438             ppc_radix64_raise_si(cpu, access_type, eaddr, fault_cause);
439         }
440         return 1;
441     }
442 
443     if (guest_visible) {
444         ppc_radix64_set_rc(cpu, access_type, pte, pte_addr, g_prot);
445     }
446 
447     return 0;
448 }
449 
450 /*
451  * Radix tree translation is a 2 steps translation process:
452  *
453  * 1. Process-scoped translation:   Guest Eff Addr  -> Guest Real Addr
454  * 2. Partition-scoped translation: Guest Real Addr -> Host Real Addr
455  *
456  *                                  MSR[HV]
457  *              +-------------+----------------+---------------+
458  *              |             |     HV = 0     |     HV = 1    |
459  *              +-------------+----------------+---------------+
460  *              | Relocation  |    Partition   |      No       |
461  *              | = Off       |     Scoped     |  Translation  |
462  *  Relocation  +-------------+----------------+---------------+
463  *              | Relocation  |   Partition &  |    Process    |
464  *              | = On        | Process Scoped |    Scoped     |
465  *              +-------------+----------------+---------------+
466  */
467 static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr,
468                              MMUAccessType access_type,
469                              bool relocation,
470                              hwaddr *raddr, int *psizep, int *protp,
471                              bool guest_visible)
472 {
473     CPUPPCState *env = &cpu->env;
474     uint64_t lpid, pid;
475     ppc_v3_pate_t pate;
476     int psize, prot;
477     hwaddr g_raddr;
478 
479     /* Virtual Mode Access - get the fully qualified address */
480     if (!ppc_radix64_get_fully_qualified_addr(&cpu->env, eaddr, &lpid, &pid)) {
481         if (guest_visible) {
482             ppc_radix64_raise_segi(cpu, access_type, eaddr);
483         }
484         return 1;
485     }
486 
487     /* Get Process Table */
488     if (cpu->vhyp) {
489         PPCVirtualHypervisorClass *vhc;
490         vhc = PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
491         vhc->get_pate(cpu->vhyp, &pate);
492     } else {
493         if (!ppc64_v3_get_pate(cpu, lpid, &pate)) {
494             if (guest_visible) {
495                 ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_NOPTE);
496             }
497             return 1;
498         }
499         if (!validate_pate(cpu, lpid, &pate)) {
500             if (guest_visible) {
501                 ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_R_BADCONFIG);
502             }
503             return 1;
504         }
505     }
506 
507     *psizep = INT_MAX;
508     *protp = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
509 
510     /*
511      * Perform process-scoped translation if relocation enabled.
512      *
513      * - Translates an effective address to a host real address in
514      *   quadrants 0 and 3 when HV=1.
515      *
516      * - Translates an effective address to a guest real address.
517      */
518     if (relocation) {
519         int ret = ppc_radix64_process_scoped_xlate(cpu, access_type, eaddr, pid,
520                                                    pate, &g_raddr, &prot,
521                                                    &psize, guest_visible);
522         if (ret) {
523             return ret;
524         }
525         *psizep = MIN(*psizep, psize);
526         *protp &= prot;
527     } else {
528         g_raddr = eaddr & R_EADDR_MASK;
529     }
530 
531     if (cpu->vhyp) {
532         *raddr = g_raddr;
533     } else {
534         /*
535          * Perform partition-scoped translation if !HV or HV access to
536          * quadrants 1 or 2. Translates a guest real address to a host
537          * real address.
538          */
539         if (lpid || !msr_hv) {
540             int ret;
541 
542             ret = ppc_radix64_partition_scoped_xlate(cpu, access_type, eaddr,
543                                                      g_raddr, pate, raddr,
544                                                      &prot, &psize, false,
545                                                      guest_visible);
546             if (ret) {
547                 return ret;
548             }
549             *psizep = MIN(*psizep, psize);
550             *protp &= prot;
551         } else {
552             *raddr = g_raddr;
553         }
554     }
555 
556     return 0;
557 }
558 
559 int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
560                                  int mmu_idx)
561 {
562     CPUState *cs = CPU(cpu);
563     CPUPPCState *env = &cpu->env;
564     int page_size, prot;
565     bool relocation;
566     MMUAccessType access_type;
567     hwaddr raddr;
568 
569     assert(!(msr_hv && cpu->vhyp));
570     assert((rwx == 0) || (rwx == 1) || (rwx == 2));
571     access_type = rwx;
572 
573     relocation = (access_type == MMU_INST_FETCH ? msr_ir : msr_dr);
574     /* HV or virtual hypervisor Real Mode Access */
575     if (!relocation && (msr_hv || cpu->vhyp)) {
576         /* In real mode top 4 effective addr bits (mostly) ignored */
577         raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL;
578 
579         /* In HV mode, add HRMOR if top EA bit is clear */
580         if (msr_hv || !env->has_hv_mode) {
581             if (!(eaddr >> 63)) {
582                 raddr |= env->spr[SPR_HRMOR];
583            }
584         }
585         tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
586                      PAGE_READ | PAGE_WRITE | PAGE_EXEC, mmu_idx,
587                      TARGET_PAGE_SIZE);
588         return 0;
589     }
590 
591     /*
592      * Check UPRT (we avoid the check in real mode to deal with
593      * transitional states during kexec.
594      */
595     if (!ppc64_use_proc_tbl(cpu)) {
596         qemu_log_mask(LOG_GUEST_ERROR,
597                       "LPCR:UPRT not set in radix mode ! LPCR="
598                       TARGET_FMT_lx "\n", env->spr[SPR_LPCR]);
599     }
600 
601     /* Translate eaddr to raddr (where raddr is addr qemu needs for access) */
602     if (ppc_radix64_xlate(cpu, eaddr, access_type, relocation, &raddr,
603                           &page_size, &prot, true)) {
604         return 1;
605     }
606 
607     tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
608                  prot, mmu_idx, 1UL << page_size);
609     return 0;
610 }
611 
612 hwaddr ppc_radix64_get_phys_page_debug(PowerPCCPU *cpu, target_ulong eaddr)
613 {
614     CPUPPCState *env = &cpu->env;
615     int psize, prot;
616     hwaddr raddr;
617 
618     /* Handle Real Mode */
619     if ((msr_dr == 0) && (msr_hv || cpu->vhyp)) {
620         /* In real mode top 4 effective addr bits (mostly) ignored */
621         return eaddr & 0x0FFFFFFFFFFFFFFFULL;
622     }
623 
624     if (ppc_radix64_xlate(cpu, eaddr, 0, msr_dr, &raddr, &psize,
625                           &prot, false)) {
626         return -1;
627     }
628 
629     return raddr & TARGET_PAGE_MASK;
630 }
631