xref: /openbmc/qemu/target/ppc/mmu-radix64.c (revision 769244f9)
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/page-protection.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     /* When EA(2:11) are nonzero, raise a segment interrupt */
37     if (eaddr & ~R_EADDR_VALID_MASK) {
38         return false;
39     }
40 
41     if (FIELD_EX64(env->msr, MSR, HV)) { /* MSR[HV] -> Hypervisor/bare metal */
42         switch (eaddr & R_EADDR_QUADRANT) {
43         case R_EADDR_QUADRANT0:
44             *lpid = 0;
45             *pid = env->spr[SPR_BOOKS_PID];
46             break;
47         case R_EADDR_QUADRANT1:
48             *lpid = env->spr[SPR_LPIDR];
49             *pid = env->spr[SPR_BOOKS_PID];
50             break;
51         case R_EADDR_QUADRANT2:
52             *lpid = env->spr[SPR_LPIDR];
53             *pid = 0;
54             break;
55         case R_EADDR_QUADRANT3:
56             *lpid = 0;
57             *pid = 0;
58             break;
59         default:
60             g_assert_not_reached();
61         }
62     } else {  /* !MSR[HV] -> Guest */
63         switch (eaddr & R_EADDR_QUADRANT) {
64         case R_EADDR_QUADRANT0: /* Guest application */
65             *lpid = env->spr[SPR_LPIDR];
66             *pid = env->spr[SPR_BOOKS_PID];
67             break;
68         case R_EADDR_QUADRANT1: /* Illegal */
69         case R_EADDR_QUADRANT2:
70             return false;
71         case R_EADDR_QUADRANT3: /* Guest OS */
72             *lpid = env->spr[SPR_LPIDR];
73             *pid = 0; /* pid set to 0 -> addresses guest operating system */
74             break;
75         default:
76             g_assert_not_reached();
77         }
78     }
79 
80     return true;
81 }
82 
83 static void ppc_radix64_raise_segi(PowerPCCPU *cpu, MMUAccessType access_type,
84                                    vaddr eaddr)
85 {
86     CPUState *cs = CPU(cpu);
87     CPUPPCState *env = &cpu->env;
88 
89     switch (access_type) {
90     case MMU_INST_FETCH:
91         /* Instruction Segment Interrupt */
92         cs->exception_index = POWERPC_EXCP_ISEG;
93         break;
94     case MMU_DATA_STORE:
95     case MMU_DATA_LOAD:
96         /* Data Segment Interrupt */
97         cs->exception_index = POWERPC_EXCP_DSEG;
98         env->spr[SPR_DAR] = eaddr;
99         break;
100     default:
101         g_assert_not_reached();
102     }
103     env->error_code = 0;
104 }
105 
106 static inline const char *access_str(MMUAccessType access_type)
107 {
108     return access_type == MMU_DATA_LOAD ? "reading" :
109         (access_type == MMU_DATA_STORE ? "writing" : "execute");
110 }
111 
112 static void ppc_radix64_raise_si(PowerPCCPU *cpu, MMUAccessType access_type,
113                                  vaddr eaddr, uint32_t cause)
114 {
115     CPUState *cs = CPU(cpu);
116     CPUPPCState *env = &cpu->env;
117 
118     qemu_log_mask(CPU_LOG_MMU, "%s for %s @0x%"VADDR_PRIx" cause %08x\n",
119                   __func__, access_str(access_type),
120                   eaddr, cause);
121 
122     switch (access_type) {
123     case MMU_INST_FETCH:
124         /* Instruction Storage Interrupt */
125         cs->exception_index = POWERPC_EXCP_ISI;
126         env->error_code = cause;
127         break;
128     case MMU_DATA_STORE:
129         cause |= DSISR_ISSTORE;
130         /* fall through */
131     case MMU_DATA_LOAD:
132         /* Data Storage Interrupt */
133         cs->exception_index = POWERPC_EXCP_DSI;
134         env->spr[SPR_DSISR] = cause;
135         env->spr[SPR_DAR] = eaddr;
136         env->error_code = 0;
137         break;
138     default:
139         g_assert_not_reached();
140     }
141 }
142 
143 static void ppc_radix64_raise_hsi(PowerPCCPU *cpu, MMUAccessType access_type,
144                                   vaddr eaddr, hwaddr g_raddr, uint32_t cause)
145 {
146     CPUState *cs = CPU(cpu);
147     CPUPPCState *env = &cpu->env;
148 
149     env->error_code = 0;
150     if (cause & DSISR_PRTABLE_FAULT) {
151         /* HDSI PRTABLE_FAULT gets the originating access type in error_code */
152         env->error_code = access_type;
153         access_type = MMU_DATA_LOAD;
154     }
155 
156     qemu_log_mask(CPU_LOG_MMU, "%s for %s @0x%"VADDR_PRIx" 0x%"
157                   HWADDR_PRIx" cause %08x\n",
158                   __func__, access_str(access_type),
159                   eaddr, g_raddr, cause);
160 
161     switch (access_type) {
162     case MMU_INST_FETCH:
163         /* H Instruction Storage Interrupt */
164         cs->exception_index = POWERPC_EXCP_HISI;
165         env->spr[SPR_ASDR] = g_raddr;
166         env->error_code = cause;
167         break;
168     case MMU_DATA_STORE:
169         cause |= DSISR_ISSTORE;
170         /* fall through */
171     case MMU_DATA_LOAD:
172         /* H Data Storage Interrupt */
173         cs->exception_index = POWERPC_EXCP_HDSI;
174         env->spr[SPR_HDSISR] = cause;
175         env->spr[SPR_HDAR] = eaddr;
176         env->spr[SPR_ASDR] = g_raddr;
177         break;
178     default:
179         g_assert_not_reached();
180     }
181 }
182 
183 static bool ppc_radix64_check_prot(PowerPCCPU *cpu, MMUAccessType access_type,
184                                    uint64_t pte, int *fault_cause, int *prot,
185                                    int mmu_idx, bool partition_scoped)
186 {
187     CPUPPCState *env = &cpu->env;
188 
189     /* Check Page Attributes (pte58:59) */
190     if ((pte & R_PTE_ATT) == R_PTE_ATT_NI_IO && access_type == MMU_INST_FETCH) {
191         /*
192          * Radix PTE entries with the non-idempotent I/O attribute are treated
193          * as guarded storage
194          */
195         *fault_cause |= SRR1_NOEXEC_GUARD;
196         return true;
197     }
198 
199     /* Determine permissions allowed by Encoded Access Authority */
200     if (!partition_scoped && (pte & R_PTE_EAA_PRIV) &&
201         FIELD_EX64(env->msr, MSR, PR)) {
202         *prot = 0;
203     } else if (mmuidx_pr(mmu_idx) || (pte & R_PTE_EAA_PRIV) ||
204                partition_scoped) {
205         *prot = ppc_radix64_get_prot_eaa(pte);
206     } else { /* !MSR_PR && !(pte & R_PTE_EAA_PRIV) && !partition_scoped */
207         *prot = ppc_radix64_get_prot_eaa(pte);
208         *prot &= ppc_radix64_get_prot_amr(cpu); /* Least combined permissions */
209     }
210 
211     /* Check if requested access type is allowed */
212     if (!check_prot_access_type(*prot, access_type)) {
213         /* Page Protected for that Access */
214         *fault_cause |= access_type == MMU_INST_FETCH ? SRR1_NOEXEC_GUARD :
215                                                         DSISR_PROTFAULT;
216         return true;
217     }
218 
219     return false;
220 }
221 
222 static int ppc_radix64_check_rc(MMUAccessType access_type, uint64_t pte)
223 {
224     switch (access_type) {
225     case MMU_DATA_STORE:
226         if (!(pte & R_PTE_C)) {
227             break;
228         }
229         /* fall through */
230     case MMU_INST_FETCH:
231     case MMU_DATA_LOAD:
232         if (!(pte & R_PTE_R)) {
233             break;
234         }
235 
236         /* R/C bits are already set appropriately for this access */
237         return 0;
238     }
239 
240     return 1;
241 }
242 
243 static bool ppc_radix64_is_valid_level(int level, int psize, uint64_t nls)
244 {
245     bool ret;
246 
247     /*
248      * Check if this is a valid level, according to POWER9 and POWER10
249      * Processor User's Manuals, sections 4.10.4.1 and 5.10.6.1, respectively:
250      * Supported Radix Tree Configurations and Resulting Page Sizes.
251      *
252      * Note: these checks are specific to POWER9 and POWER10 CPUs. Any future
253      * CPUs that supports a different Radix MMU configuration will need their
254      * own implementation.
255      */
256     switch (level) {
257     case 0:     /* Root Page Dir */
258         ret = psize == 52 && nls == 13;
259         break;
260     case 1:
261     case 2:
262         ret = nls == 9;
263         break;
264     case 3:
265         ret = nls == 9 || nls == 5;
266         break;
267     default:
268         ret = false;
269     }
270 
271     if (unlikely(!ret)) {
272         qemu_log_mask(LOG_GUEST_ERROR, "invalid radix configuration: "
273                       "level %d size %d nls %"PRIu64"\n",
274                       level, psize, nls);
275     }
276     return ret;
277 }
278 
279 static int ppc_radix64_next_level(AddressSpace *as, vaddr eaddr,
280                                   uint64_t *pte_addr, uint64_t *nls,
281                                   int *psize, uint64_t *pte, int *fault_cause)
282 {
283     uint64_t index, mask, nlb, pde;
284 
285     /* Read page <directory/table> entry from guest address space */
286     pde = ldq_phys(as, *pte_addr);
287     if (!(pde & R_PTE_VALID)) {         /* Invalid Entry */
288         *fault_cause |= DSISR_NOPTE;
289         return 1;
290     }
291 
292     *pte = pde;
293     *psize -= *nls;
294     if (!(pde & R_PTE_LEAF)) { /* Prepare for next iteration */
295         *nls = pde & R_PDE_NLS;
296         index = eaddr >> (*psize - *nls);       /* Shift */
297         index &= ((1UL << *nls) - 1);           /* Mask */
298         nlb = pde & R_PDE_NLB;
299         mask = MAKE_64BIT_MASK(0, *nls + 3);
300 
301         if (nlb & mask) {
302             qemu_log_mask(LOG_GUEST_ERROR,
303                 "%s: misaligned page dir/table base: 0x%" PRIx64
304                 " page dir size: 0x%" PRIx64 "\n",
305                 __func__, nlb, mask + 1);
306             nlb &= ~mask;
307         }
308         *pte_addr = nlb + index * sizeof(pde);
309     }
310     return 0;
311 }
312 
313 static int ppc_radix64_walk_tree(AddressSpace *as, vaddr eaddr,
314                                  uint64_t base_addr, uint64_t nls,
315                                  hwaddr *raddr, int *psize, uint64_t *pte,
316                                  int *fault_cause, hwaddr *pte_addr)
317 {
318     uint64_t index, pde, rpn, mask;
319     int level = 0;
320 
321     index = eaddr >> (*psize - nls);    /* Shift */
322     index &= ((1UL << nls) - 1);        /* Mask */
323     mask = MAKE_64BIT_MASK(0, nls + 3);
324 
325     if (base_addr & mask) {
326         qemu_log_mask(LOG_GUEST_ERROR,
327             "%s: misaligned page dir base: 0x%" PRIx64
328             " page dir size: 0x%" PRIx64 "\n",
329             __func__, base_addr, mask + 1);
330         base_addr &= ~mask;
331     }
332     *pte_addr = base_addr + index * sizeof(pde);
333 
334     do {
335         int ret;
336 
337         if (!ppc_radix64_is_valid_level(level++, *psize, nls)) {
338             *fault_cause |= DSISR_R_BADCONFIG;
339             return 1;
340         }
341 
342         ret = ppc_radix64_next_level(as, eaddr, pte_addr, &nls, psize, &pde,
343                                      fault_cause);
344         if (ret) {
345             return ret;
346         }
347     } while (!(pde & R_PTE_LEAF));
348 
349     *pte = pde;
350     rpn = pde & R_PTE_RPN;
351     mask = (1UL << *psize) - 1;
352 
353     /* Or high bits of rpn and low bits to ea to form whole real addr */
354     *raddr = (rpn & ~mask) | (eaddr & mask);
355     return 0;
356 }
357 
358 static bool validate_pate(PowerPCCPU *cpu, uint64_t lpid, ppc_v3_pate_t *pate)
359 {
360     CPUPPCState *env = &cpu->env;
361 
362     if (!(pate->dw0 & PATE0_HR)) {
363         return false;
364     }
365     if (lpid == 0 && !FIELD_EX64(env->msr, MSR, HV)) {
366         return false;
367     }
368     if ((pate->dw0 & PATE1_R_PRTS) < 5) {
369         return false;
370     }
371     /* More checks ... */
372     return true;
373 }
374 
375 static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu,
376                                               MMUAccessType orig_access_type,
377                                               vaddr eaddr, hwaddr g_raddr,
378                                               ppc_v3_pate_t pate,
379                                               hwaddr *h_raddr, int *h_prot,
380                                               int *h_page_size, bool pde_addr,
381                                               int mmu_idx, uint64_t lpid,
382                                               bool guest_visible)
383 {
384     MMUAccessType access_type = orig_access_type;
385     int fault_cause = 0;
386     hwaddr pte_addr;
387     uint64_t pte;
388 
389     if (pde_addr) {
390         /*
391          * Translation of process-scoped tables/directories is performed as
392          * a read-access.
393          */
394         access_type = MMU_DATA_LOAD;
395     }
396 
397     qemu_log_mask(CPU_LOG_MMU, "%s for %s @0x%"VADDR_PRIx
398                   " mmu_idx %u 0x%"HWADDR_PRIx"\n",
399                   __func__, access_str(access_type),
400                   eaddr, mmu_idx, g_raddr);
401 
402     *h_page_size = PRTBE_R_GET_RTS(pate.dw0);
403     /* No valid pte or access denied due to protection */
404     if (ppc_radix64_walk_tree(CPU(cpu)->as, g_raddr, pate.dw0 & PRTBE_R_RPDB,
405                               pate.dw0 & PRTBE_R_RPDS, h_raddr, h_page_size,
406                               &pte, &fault_cause, &pte_addr) ||
407         ppc_radix64_check_prot(cpu, access_type, pte,
408                                &fault_cause, h_prot, mmu_idx, true)) {
409         if (pde_addr) { /* address being translated was that of a guest pde */
410             fault_cause |= DSISR_PRTABLE_FAULT;
411         }
412         if (guest_visible) {
413             ppc_radix64_raise_hsi(cpu, orig_access_type,
414                                   eaddr, g_raddr, fault_cause);
415         }
416         return 1;
417     }
418 
419     if (guest_visible) {
420         if (ppc_radix64_check_rc(access_type, pte)) {
421             /*
422              * Per ISA 3.1 Book III, 7.5.3 and 7.5.5, failure to set R/C during
423              * partition-scoped translation when effLPID = 0 results in normal
424              * (non-Hypervisor) Data and Instruction Storage Interrupts
425              * respectively.
426              *
427              * ISA 3.0 is ambiguous about this, but tests on POWER9 hardware
428              * seem to exhibit the same behavior.
429              */
430             if (lpid > 0) {
431                 ppc_radix64_raise_hsi(cpu, access_type, eaddr, g_raddr,
432                                       DSISR_ATOMIC_RC);
433             } else {
434                 ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_ATOMIC_RC);
435             }
436             return 1;
437         }
438     }
439 
440     return 0;
441 }
442 
443 /*
444  * The spapr vhc has a flat partition scope provided by qemu memory when
445  * not nested.
446  *
447  * When running a nested guest, the addressing is 2-level radix on top of the
448  * vhc memory, so it works practically identically to the bare metal 2-level
449  * radix. So that code is selected directly. A cleaner and more flexible nested
450  * hypervisor implementation would allow the vhc to provide a ->nested_xlate()
451  * function but that is not required for the moment.
452  */
453 static bool vhyp_flat_addressing(PowerPCCPU *cpu)
454 {
455     if (cpu->vhyp) {
456         return !vhyp_cpu_in_nested(cpu);
457     }
458     return false;
459 }
460 
461 static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu,
462                                             MMUAccessType access_type,
463                                             vaddr eaddr, uint64_t pid,
464                                             ppc_v3_pate_t pate, hwaddr *g_raddr,
465                                             int *g_prot, int *g_page_size,
466                                             int mmu_idx, uint64_t lpid,
467                                             bool guest_visible)
468 {
469     CPUState *cs = CPU(cpu);
470     CPUPPCState *env = &cpu->env;
471     uint64_t offset, size, prtb, prtbe_addr, prtbe0, base_addr, nls, index, pte;
472     int fault_cause = 0, h_page_size, h_prot;
473     hwaddr h_raddr, pte_addr;
474     int ret;
475 
476     qemu_log_mask(CPU_LOG_MMU, "%s for %s @0x%"VADDR_PRIx
477                   " mmu_idx %u pid %"PRIu64"\n",
478                   __func__, access_str(access_type),
479                   eaddr, mmu_idx, pid);
480 
481     prtb = (pate.dw1 & PATE1_R_PRTB);
482     size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12);
483     if (prtb & (size - 1)) {
484         /* Process Table not properly aligned */
485         if (guest_visible) {
486             ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_R_BADCONFIG);
487         }
488         return 1;
489     }
490 
491     /* Index Process Table by PID to Find Corresponding Process Table Entry */
492     offset = pid * sizeof(struct prtb_entry);
493     if (offset >= size) {
494         /* offset exceeds size of the process table */
495         if (guest_visible) {
496             ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_NOPTE);
497         }
498         return 1;
499     }
500     prtbe_addr = prtb + offset;
501 
502     if (vhyp_flat_addressing(cpu)) {
503         prtbe0 = ldq_phys(cs->as, prtbe_addr);
504     } else {
505         /*
506          * Process table addresses are subject to partition-scoped
507          * translation
508          *
509          * On a Radix host, the partition-scoped page table for LPID=0
510          * is only used to translate the effective addresses of the
511          * process table entries.
512          */
513         /* mmu_idx is 5 because we're translating from hypervisor scope */
514         ret = ppc_radix64_partition_scoped_xlate(cpu, access_type, eaddr,
515                                                  prtbe_addr, pate, &h_raddr,
516                                                  &h_prot, &h_page_size, true,
517                                                  5, lpid, guest_visible);
518         if (ret) {
519             return ret;
520         }
521         prtbe0 = ldq_phys(cs->as, h_raddr);
522     }
523 
524     /* Walk Radix Tree from Process Table Entry to Convert EA to RA */
525     *g_page_size = PRTBE_R_GET_RTS(prtbe0);
526     base_addr = prtbe0 & PRTBE_R_RPDB;
527     nls = prtbe0 & PRTBE_R_RPDS;
528     if (FIELD_EX64(env->msr, MSR, HV) || vhyp_flat_addressing(cpu)) {
529         /*
530          * Can treat process table addresses as real addresses
531          */
532         ret = ppc_radix64_walk_tree(cs->as, eaddr & R_EADDR_MASK, base_addr,
533                                     nls, g_raddr, g_page_size, &pte,
534                                     &fault_cause, &pte_addr);
535         if (ret) {
536             /* No valid PTE */
537             if (guest_visible) {
538                 ppc_radix64_raise_si(cpu, access_type, eaddr, fault_cause);
539             }
540             return ret;
541         }
542     } else {
543         uint64_t rpn, mask;
544         int level = 0;
545 
546         index = (eaddr & R_EADDR_MASK) >> (*g_page_size - nls); /* Shift */
547         index &= ((1UL << nls) - 1);                            /* Mask */
548         pte_addr = base_addr + (index * sizeof(pte));
549 
550         /*
551          * Each process table address is subject to a partition-scoped
552          * translation
553          */
554         do {
555             /* mmu_idx is 5 because we're translating from hypervisor scope */
556             ret = ppc_radix64_partition_scoped_xlate(cpu, access_type, eaddr,
557                                                      pte_addr, pate, &h_raddr,
558                                                      &h_prot, &h_page_size,
559                                                      true, 5, lpid,
560                                                      guest_visible);
561             if (ret) {
562                 return ret;
563             }
564 
565             if (!ppc_radix64_is_valid_level(level++, *g_page_size, nls)) {
566                 fault_cause |= DSISR_R_BADCONFIG;
567                 ret = 1;
568             } else {
569                 ret = ppc_radix64_next_level(cs->as, eaddr & R_EADDR_MASK,
570                                              &h_raddr, &nls, g_page_size,
571                                              &pte, &fault_cause);
572             }
573 
574             if (ret) {
575                 /* No valid pte */
576                 if (guest_visible) {
577                     ppc_radix64_raise_si(cpu, access_type, eaddr, fault_cause);
578                 }
579                 return ret;
580             }
581             pte_addr = h_raddr;
582         } while (!(pte & R_PTE_LEAF));
583 
584         rpn = pte & R_PTE_RPN;
585         mask = (1UL << *g_page_size) - 1;
586 
587         /* Or high bits of rpn and low bits to ea to form whole real addr */
588         *g_raddr = (rpn & ~mask) | (eaddr & mask);
589     }
590 
591     if (ppc_radix64_check_prot(cpu, access_type, pte, &fault_cause,
592                                g_prot, mmu_idx, false)) {
593         /* Access denied due to protection */
594         if (guest_visible) {
595             ppc_radix64_raise_si(cpu, access_type, eaddr, fault_cause);
596         }
597         return 1;
598     }
599 
600     if (guest_visible) {
601         /* R/C bits not appropriately set for access */
602         if (ppc_radix64_check_rc(access_type, pte)) {
603             ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_ATOMIC_RC);
604             return 1;
605         }
606     }
607 
608     return 0;
609 }
610 
611 /*
612  * Radix tree translation is a 2 steps translation process:
613  *
614  * 1. Process-scoped translation:   Guest Eff Addr  -> Guest Real Addr
615  * 2. Partition-scoped translation: Guest Real Addr -> Host Real Addr
616  *
617  *                                  MSR[HV]
618  *              +-------------+----------------+---------------+
619  *              |             |     HV = 0     |     HV = 1    |
620  *              +-------------+----------------+---------------+
621  *              | Relocation  |    Partition   |      No       |
622  *              | = Off       |     Scoped     |  Translation  |
623  *  Relocation  +-------------+----------------+---------------+
624  *              | Relocation  |   Partition &  |    Process    |
625  *              | = On        | Process Scoped |    Scoped     |
626  *              +-------------+----------------+---------------+
627  */
628 static bool ppc_radix64_xlate_impl(PowerPCCPU *cpu, vaddr eaddr,
629                                    MMUAccessType access_type, hwaddr *raddr,
630                                    int *psizep, int *protp, int mmu_idx,
631                                    bool guest_visible)
632 {
633     CPUPPCState *env = &cpu->env;
634     uint64_t lpid, pid;
635     ppc_v3_pate_t pate;
636     int psize, prot;
637     hwaddr g_raddr;
638     bool relocation;
639 
640     assert(!(mmuidx_hv(mmu_idx) && cpu->vhyp));
641 
642     relocation = !mmuidx_real(mmu_idx);
643 
644     /* HV or virtual hypervisor Real Mode Access */
645     if (!relocation && (mmuidx_hv(mmu_idx) || vhyp_flat_addressing(cpu))) {
646         /* In real mode top 4 effective addr bits (mostly) ignored */
647         *raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL;
648 
649         /* In HV mode, add HRMOR if top EA bit is clear */
650         if (mmuidx_hv(mmu_idx) || !env->has_hv_mode) {
651             if (!(eaddr >> 63)) {
652                 *raddr |= env->spr[SPR_HRMOR];
653            }
654         }
655         *protp = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
656         *psizep = TARGET_PAGE_BITS;
657         return true;
658     }
659 
660     /*
661      * Check UPRT (we avoid the check in real mode to deal with
662      * transitional states during kexec.
663      */
664     if (guest_visible && !ppc64_use_proc_tbl(cpu)) {
665         qemu_log_mask(LOG_GUEST_ERROR,
666                       "LPCR:UPRT not set in radix mode ! LPCR="
667                       TARGET_FMT_lx "\n", env->spr[SPR_LPCR]);
668     }
669 
670     /* Virtual Mode Access - get the fully qualified address */
671     if (!ppc_radix64_get_fully_qualified_addr(&cpu->env, eaddr, &lpid, &pid)) {
672         if (guest_visible) {
673             ppc_radix64_raise_segi(cpu, access_type, eaddr);
674         }
675         return false;
676     }
677 
678     /* Get Partition Table */
679     if (cpu->vhyp) {
680         if (!cpu->vhyp_class->get_pate(cpu->vhyp, cpu, lpid, &pate)) {
681             if (guest_visible) {
682                 ppc_radix64_raise_hsi(cpu, access_type, eaddr, eaddr,
683                                       DSISR_R_BADCONFIG);
684             }
685             return false;
686         }
687     } else {
688         if (!ppc64_v3_get_pate(cpu, lpid, &pate)) {
689             if (guest_visible) {
690                 ppc_radix64_raise_hsi(cpu, access_type, eaddr, eaddr,
691                                       DSISR_R_BADCONFIG);
692             }
693             return false;
694         }
695         if (!validate_pate(cpu, lpid, &pate)) {
696             if (guest_visible) {
697                 ppc_radix64_raise_hsi(cpu, access_type, eaddr, eaddr,
698                                       DSISR_R_BADCONFIG);
699             }
700             return false;
701         }
702     }
703 
704     *psizep = INT_MAX;
705     *protp = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
706 
707     /*
708      * Perform process-scoped translation if relocation enabled.
709      *
710      * - Translates an effective address to a host real address in
711      *   quadrants 0 and 3 when HV=1.
712      *
713      * - Translates an effective address to a guest real address.
714      */
715     if (relocation) {
716         int ret = ppc_radix64_process_scoped_xlate(cpu, access_type, eaddr, pid,
717                                                    pate, &g_raddr, &prot,
718                                                    &psize, mmu_idx, lpid,
719                                                    guest_visible);
720         if (ret) {
721             return false;
722         }
723         *psizep = MIN(*psizep, psize);
724         *protp &= prot;
725     } else {
726         g_raddr = eaddr & R_EADDR_MASK;
727     }
728 
729     if (vhyp_flat_addressing(cpu)) {
730         *raddr = g_raddr;
731     } else {
732         /*
733          * Perform partition-scoped translation if !HV or HV access to
734          * quadrants 1 or 2. Translates a guest real address to a host
735          * real address.
736          */
737         if (lpid || !mmuidx_hv(mmu_idx)) {
738             int ret;
739 
740             ret = ppc_radix64_partition_scoped_xlate(cpu, access_type, eaddr,
741                                                      g_raddr, pate, raddr,
742                                                      &prot, &psize, false,
743                                                      mmu_idx, lpid,
744                                                      guest_visible);
745             if (ret) {
746                 return false;
747             }
748             *psizep = MIN(*psizep, psize);
749             *protp &= prot;
750         } else {
751             *raddr = g_raddr;
752         }
753     }
754 
755     return true;
756 }
757 
758 bool ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
759                        hwaddr *raddrp, int *psizep, int *protp, int mmu_idx,
760                        bool guest_visible)
761 {
762     bool ret = ppc_radix64_xlate_impl(cpu, eaddr, access_type, raddrp,
763                                       psizep, protp, mmu_idx, guest_visible);
764 
765     qemu_log_mask(CPU_LOG_MMU, "%s for %s @0x%"VADDR_PRIx
766                   " mmu_idx %u (prot %c%c%c) -> 0x%"HWADDR_PRIx"\n",
767                   __func__, access_str(access_type),
768                   eaddr, mmu_idx,
769                   *protp & PAGE_READ ? 'r' : '-',
770                   *protp & PAGE_WRITE ? 'w' : '-',
771                   *protp & PAGE_EXEC ? 'x' : '-',
772                   *raddrp);
773 
774     return ret;
775 }
776