xref: /openbmc/qemu/hw/ppc/spapr_vhyp_mmu.c (revision 14a43ab3)
16c568998SPhilippe Mathieu-Daudé /*
26c568998SPhilippe Mathieu-Daudé  * MMU hypercalls for the sPAPR (pseries) vHyp hypervisor that is used by TCG
36c568998SPhilippe Mathieu-Daudé  *
46c568998SPhilippe Mathieu-Daudé  * Copyright (c) 2004-2007 Fabrice Bellard
56c568998SPhilippe Mathieu-Daudé  * Copyright (c) 2007 Jocelyn Mayer
66c568998SPhilippe Mathieu-Daudé  * Copyright (c) 2010 David Gibson, IBM Corporation.
76c568998SPhilippe Mathieu-Daudé  *
86c568998SPhilippe Mathieu-Daudé  * SPDX-License-Identifier: MIT
96c568998SPhilippe Mathieu-Daudé  */
106c568998SPhilippe Mathieu-Daudé #include "qemu/osdep.h"
116c568998SPhilippe Mathieu-Daudé #include "qemu/cutils.h"
126c568998SPhilippe Mathieu-Daudé #include "qemu/memalign.h"
136c568998SPhilippe Mathieu-Daudé #include "qemu/error-report.h"
146c568998SPhilippe Mathieu-Daudé #include "cpu.h"
156c568998SPhilippe Mathieu-Daudé #include "helper_regs.h"
166c568998SPhilippe Mathieu-Daudé #include "hw/ppc/spapr.h"
176c568998SPhilippe Mathieu-Daudé #include "mmu-hash64.h"
186c568998SPhilippe Mathieu-Daudé 
h_enter(PowerPCCPU * cpu,SpaprMachineState * spapr,target_ulong opcode,target_ulong * args)196c568998SPhilippe Mathieu-Daudé static target_ulong h_enter(PowerPCCPU *cpu, SpaprMachineState *spapr,
206c568998SPhilippe Mathieu-Daudé                             target_ulong opcode, target_ulong *args)
216c568998SPhilippe Mathieu-Daudé {
226c568998SPhilippe Mathieu-Daudé     target_ulong flags = args[0];
236c568998SPhilippe Mathieu-Daudé     target_ulong ptex = args[1];
246c568998SPhilippe Mathieu-Daudé     target_ulong pteh = args[2];
256c568998SPhilippe Mathieu-Daudé     target_ulong ptel = args[3];
266c568998SPhilippe Mathieu-Daudé     unsigned apshift;
276c568998SPhilippe Mathieu-Daudé     target_ulong raddr;
286c568998SPhilippe Mathieu-Daudé     target_ulong slot;
296c568998SPhilippe Mathieu-Daudé     const ppc_hash_pte64_t *hptes;
306c568998SPhilippe Mathieu-Daudé 
316c568998SPhilippe Mathieu-Daudé     apshift = ppc_hash64_hpte_page_shift_noslb(cpu, pteh, ptel);
326c568998SPhilippe Mathieu-Daudé     if (!apshift) {
336c568998SPhilippe Mathieu-Daudé         /* Bad page size encoding */
346c568998SPhilippe Mathieu-Daudé         return H_PARAMETER;
356c568998SPhilippe Mathieu-Daudé     }
366c568998SPhilippe Mathieu-Daudé 
376c568998SPhilippe Mathieu-Daudé     raddr = (ptel & HPTE64_R_RPN) & ~((1ULL << apshift) - 1);
386c568998SPhilippe Mathieu-Daudé 
396c568998SPhilippe Mathieu-Daudé     if (is_ram_address(spapr, raddr)) {
406c568998SPhilippe Mathieu-Daudé         /* Regular RAM - should have WIMG=0010 */
416c568998SPhilippe Mathieu-Daudé         if ((ptel & HPTE64_R_WIMG) != HPTE64_R_M) {
426c568998SPhilippe Mathieu-Daudé             return H_PARAMETER;
436c568998SPhilippe Mathieu-Daudé         }
446c568998SPhilippe Mathieu-Daudé     } else {
456c568998SPhilippe Mathieu-Daudé         target_ulong wimg_flags;
466c568998SPhilippe Mathieu-Daudé         /* Looks like an IO address */
476c568998SPhilippe Mathieu-Daudé         /* FIXME: What WIMG combinations could be sensible for IO?
486c568998SPhilippe Mathieu-Daudé          * For now we allow WIMG=010x, but are there others? */
496c568998SPhilippe Mathieu-Daudé         /* FIXME: Should we check against registered IO addresses? */
506c568998SPhilippe Mathieu-Daudé         wimg_flags = (ptel & (HPTE64_R_W | HPTE64_R_I | HPTE64_R_M));
516c568998SPhilippe Mathieu-Daudé 
526c568998SPhilippe Mathieu-Daudé         if (wimg_flags != HPTE64_R_I &&
536c568998SPhilippe Mathieu-Daudé             wimg_flags != (HPTE64_R_I | HPTE64_R_M)) {
546c568998SPhilippe Mathieu-Daudé             return H_PARAMETER;
556c568998SPhilippe Mathieu-Daudé         }
566c568998SPhilippe Mathieu-Daudé     }
576c568998SPhilippe Mathieu-Daudé 
586c568998SPhilippe Mathieu-Daudé     pteh &= ~0x60ULL;
596c568998SPhilippe Mathieu-Daudé 
60*14a43ab3SBALATON Zoltan     if (!ppc_hash64_valid_ptex(cpu, ptex)) {
616c568998SPhilippe Mathieu-Daudé         return H_PARAMETER;
626c568998SPhilippe Mathieu-Daudé     }
636c568998SPhilippe Mathieu-Daudé 
646c568998SPhilippe Mathieu-Daudé     slot = ptex & 7ULL;
656c568998SPhilippe Mathieu-Daudé     ptex = ptex & ~7ULL;
666c568998SPhilippe Mathieu-Daudé 
676c568998SPhilippe Mathieu-Daudé     if (likely((flags & H_EXACT) == 0)) {
686c568998SPhilippe Mathieu-Daudé         hptes = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP);
696c568998SPhilippe Mathieu-Daudé         for (slot = 0; slot < 8; slot++) {
706c568998SPhilippe Mathieu-Daudé             if (!(ppc_hash64_hpte0(cpu, hptes, slot) & HPTE64_V_VALID)) {
716c568998SPhilippe Mathieu-Daudé                 break;
726c568998SPhilippe Mathieu-Daudé             }
736c568998SPhilippe Mathieu-Daudé         }
746c568998SPhilippe Mathieu-Daudé         ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP);
756c568998SPhilippe Mathieu-Daudé         if (slot == 8) {
766c568998SPhilippe Mathieu-Daudé             return H_PTEG_FULL;
776c568998SPhilippe Mathieu-Daudé         }
786c568998SPhilippe Mathieu-Daudé     } else {
796c568998SPhilippe Mathieu-Daudé         hptes = ppc_hash64_map_hptes(cpu, ptex + slot, 1);
806c568998SPhilippe Mathieu-Daudé         if (ppc_hash64_hpte0(cpu, hptes, 0) & HPTE64_V_VALID) {
816c568998SPhilippe Mathieu-Daudé             ppc_hash64_unmap_hptes(cpu, hptes, ptex + slot, 1);
826c568998SPhilippe Mathieu-Daudé             return H_PTEG_FULL;
836c568998SPhilippe Mathieu-Daudé         }
846c568998SPhilippe Mathieu-Daudé         ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
856c568998SPhilippe Mathieu-Daudé     }
866c568998SPhilippe Mathieu-Daudé 
876c568998SPhilippe Mathieu-Daudé     spapr_store_hpte(cpu, ptex + slot, pteh | HPTE64_V_HPTE_DIRTY, ptel);
886c568998SPhilippe Mathieu-Daudé 
896c568998SPhilippe Mathieu-Daudé     args[0] = ptex + slot;
906c568998SPhilippe Mathieu-Daudé     return H_SUCCESS;
916c568998SPhilippe Mathieu-Daudé }
926c568998SPhilippe Mathieu-Daudé 
936c568998SPhilippe Mathieu-Daudé typedef enum {
946c568998SPhilippe Mathieu-Daudé     REMOVE_SUCCESS = 0,
956c568998SPhilippe Mathieu-Daudé     REMOVE_NOT_FOUND = 1,
966c568998SPhilippe Mathieu-Daudé     REMOVE_PARM = 2,
976c568998SPhilippe Mathieu-Daudé     REMOVE_HW = 3,
986c568998SPhilippe Mathieu-Daudé } RemoveResult;
996c568998SPhilippe Mathieu-Daudé 
remove_hpte(PowerPCCPU * cpu,target_ulong ptex,target_ulong avpn,target_ulong flags,target_ulong * vp,target_ulong * rp)1006c568998SPhilippe Mathieu-Daudé static RemoveResult remove_hpte(PowerPCCPU *cpu
1016c568998SPhilippe Mathieu-Daudé                                 , target_ulong ptex,
1026c568998SPhilippe Mathieu-Daudé                                 target_ulong avpn,
1036c568998SPhilippe Mathieu-Daudé                                 target_ulong flags,
1046c568998SPhilippe Mathieu-Daudé                                 target_ulong *vp, target_ulong *rp)
1056c568998SPhilippe Mathieu-Daudé {
1066c568998SPhilippe Mathieu-Daudé     const ppc_hash_pte64_t *hptes;
1076c568998SPhilippe Mathieu-Daudé     target_ulong v, r;
1086c568998SPhilippe Mathieu-Daudé 
109*14a43ab3SBALATON Zoltan     if (!ppc_hash64_valid_ptex(cpu, ptex)) {
1106c568998SPhilippe Mathieu-Daudé         return REMOVE_PARM;
1116c568998SPhilippe Mathieu-Daudé     }
1126c568998SPhilippe Mathieu-Daudé 
1136c568998SPhilippe Mathieu-Daudé     hptes = ppc_hash64_map_hptes(cpu, ptex, 1);
1146c568998SPhilippe Mathieu-Daudé     v = ppc_hash64_hpte0(cpu, hptes, 0);
1156c568998SPhilippe Mathieu-Daudé     r = ppc_hash64_hpte1(cpu, hptes, 0);
1166c568998SPhilippe Mathieu-Daudé     ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
1176c568998SPhilippe Mathieu-Daudé 
1186c568998SPhilippe Mathieu-Daudé     if ((v & HPTE64_V_VALID) == 0 ||
1196c568998SPhilippe Mathieu-Daudé         ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
1206c568998SPhilippe Mathieu-Daudé         ((flags & H_ANDCOND) && (v & avpn) != 0)) {
1216c568998SPhilippe Mathieu-Daudé         return REMOVE_NOT_FOUND;
1226c568998SPhilippe Mathieu-Daudé     }
1236c568998SPhilippe Mathieu-Daudé     *vp = v;
1246c568998SPhilippe Mathieu-Daudé     *rp = r;
1256c568998SPhilippe Mathieu-Daudé     spapr_store_hpte(cpu, ptex, HPTE64_V_HPTE_DIRTY, 0);
1266c568998SPhilippe Mathieu-Daudé     ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r);
1276c568998SPhilippe Mathieu-Daudé     return REMOVE_SUCCESS;
1286c568998SPhilippe Mathieu-Daudé }
1296c568998SPhilippe Mathieu-Daudé 
h_remove(PowerPCCPU * cpu,SpaprMachineState * spapr,target_ulong opcode,target_ulong * args)1306c568998SPhilippe Mathieu-Daudé static target_ulong h_remove(PowerPCCPU *cpu, SpaprMachineState *spapr,
1316c568998SPhilippe Mathieu-Daudé                              target_ulong opcode, target_ulong *args)
1326c568998SPhilippe Mathieu-Daudé {
1336c568998SPhilippe Mathieu-Daudé     CPUPPCState *env = &cpu->env;
1346c568998SPhilippe Mathieu-Daudé     target_ulong flags = args[0];
1356c568998SPhilippe Mathieu-Daudé     target_ulong ptex = args[1];
1366c568998SPhilippe Mathieu-Daudé     target_ulong avpn = args[2];
1376c568998SPhilippe Mathieu-Daudé     RemoveResult ret;
1386c568998SPhilippe Mathieu-Daudé 
1396c568998SPhilippe Mathieu-Daudé     ret = remove_hpte(cpu, ptex, avpn, flags,
1406c568998SPhilippe Mathieu-Daudé                       &args[0], &args[1]);
1416c568998SPhilippe Mathieu-Daudé 
1426c568998SPhilippe Mathieu-Daudé     switch (ret) {
1436c568998SPhilippe Mathieu-Daudé     case REMOVE_SUCCESS:
1446c568998SPhilippe Mathieu-Daudé         check_tlb_flush(env, true);
1456c568998SPhilippe Mathieu-Daudé         return H_SUCCESS;
1466c568998SPhilippe Mathieu-Daudé 
1476c568998SPhilippe Mathieu-Daudé     case REMOVE_NOT_FOUND:
1486c568998SPhilippe Mathieu-Daudé         return H_NOT_FOUND;
1496c568998SPhilippe Mathieu-Daudé 
1506c568998SPhilippe Mathieu-Daudé     case REMOVE_PARM:
1516c568998SPhilippe Mathieu-Daudé         return H_PARAMETER;
1526c568998SPhilippe Mathieu-Daudé 
1536c568998SPhilippe Mathieu-Daudé     case REMOVE_HW:
1546c568998SPhilippe Mathieu-Daudé         return H_HARDWARE;
1556c568998SPhilippe Mathieu-Daudé     }
1566c568998SPhilippe Mathieu-Daudé 
1576c568998SPhilippe Mathieu-Daudé     g_assert_not_reached();
1586c568998SPhilippe Mathieu-Daudé }
1596c568998SPhilippe Mathieu-Daudé 
1606c568998SPhilippe Mathieu-Daudé #define H_BULK_REMOVE_TYPE             0xc000000000000000ULL
1616c568998SPhilippe Mathieu-Daudé #define   H_BULK_REMOVE_REQUEST        0x4000000000000000ULL
1626c568998SPhilippe Mathieu-Daudé #define   H_BULK_REMOVE_RESPONSE       0x8000000000000000ULL
1636c568998SPhilippe Mathieu-Daudé #define   H_BULK_REMOVE_END            0xc000000000000000ULL
1646c568998SPhilippe Mathieu-Daudé #define H_BULK_REMOVE_CODE             0x3000000000000000ULL
1656c568998SPhilippe Mathieu-Daudé #define   H_BULK_REMOVE_SUCCESS        0x0000000000000000ULL
1666c568998SPhilippe Mathieu-Daudé #define   H_BULK_REMOVE_NOT_FOUND      0x1000000000000000ULL
1676c568998SPhilippe Mathieu-Daudé #define   H_BULK_REMOVE_PARM           0x2000000000000000ULL
1686c568998SPhilippe Mathieu-Daudé #define   H_BULK_REMOVE_HW             0x3000000000000000ULL
1696c568998SPhilippe Mathieu-Daudé #define H_BULK_REMOVE_RC               0x0c00000000000000ULL
1706c568998SPhilippe Mathieu-Daudé #define H_BULK_REMOVE_FLAGS            0x0300000000000000ULL
1716c568998SPhilippe Mathieu-Daudé #define   H_BULK_REMOVE_ABSOLUTE       0x0000000000000000ULL
1726c568998SPhilippe Mathieu-Daudé #define   H_BULK_REMOVE_ANDCOND        0x0100000000000000ULL
1736c568998SPhilippe Mathieu-Daudé #define   H_BULK_REMOVE_AVPN           0x0200000000000000ULL
1746c568998SPhilippe Mathieu-Daudé #define H_BULK_REMOVE_PTEX             0x00ffffffffffffffULL
1756c568998SPhilippe Mathieu-Daudé 
1766c568998SPhilippe Mathieu-Daudé #define H_BULK_REMOVE_MAX_BATCH        4
1776c568998SPhilippe Mathieu-Daudé 
h_bulk_remove(PowerPCCPU * cpu,SpaprMachineState * spapr,target_ulong opcode,target_ulong * args)1786c568998SPhilippe Mathieu-Daudé static target_ulong h_bulk_remove(PowerPCCPU *cpu, SpaprMachineState *spapr,
1796c568998SPhilippe Mathieu-Daudé                                   target_ulong opcode, target_ulong *args)
1806c568998SPhilippe Mathieu-Daudé {
1816c568998SPhilippe Mathieu-Daudé     CPUPPCState *env = &cpu->env;
1826c568998SPhilippe Mathieu-Daudé     int i;
1836c568998SPhilippe Mathieu-Daudé     target_ulong rc = H_SUCCESS;
1846c568998SPhilippe Mathieu-Daudé 
1856c568998SPhilippe Mathieu-Daudé     for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) {
1866c568998SPhilippe Mathieu-Daudé         target_ulong *tsh = &args[i*2];
1876c568998SPhilippe Mathieu-Daudé         target_ulong tsl = args[i*2 + 1];
1886c568998SPhilippe Mathieu-Daudé         target_ulong v, r, ret;
1896c568998SPhilippe Mathieu-Daudé 
1906c568998SPhilippe Mathieu-Daudé         if ((*tsh & H_BULK_REMOVE_TYPE) == H_BULK_REMOVE_END) {
1916c568998SPhilippe Mathieu-Daudé             break;
1926c568998SPhilippe Mathieu-Daudé         } else if ((*tsh & H_BULK_REMOVE_TYPE) != H_BULK_REMOVE_REQUEST) {
1936c568998SPhilippe Mathieu-Daudé             return H_PARAMETER;
1946c568998SPhilippe Mathieu-Daudé         }
1956c568998SPhilippe Mathieu-Daudé 
1966c568998SPhilippe Mathieu-Daudé         *tsh &= H_BULK_REMOVE_PTEX | H_BULK_REMOVE_FLAGS;
1976c568998SPhilippe Mathieu-Daudé         *tsh |= H_BULK_REMOVE_RESPONSE;
1986c568998SPhilippe Mathieu-Daudé 
1996c568998SPhilippe Mathieu-Daudé         if ((*tsh & H_BULK_REMOVE_ANDCOND) && (*tsh & H_BULK_REMOVE_AVPN)) {
2006c568998SPhilippe Mathieu-Daudé             *tsh |= H_BULK_REMOVE_PARM;
2016c568998SPhilippe Mathieu-Daudé             return H_PARAMETER;
2026c568998SPhilippe Mathieu-Daudé         }
2036c568998SPhilippe Mathieu-Daudé 
2046c568998SPhilippe Mathieu-Daudé         ret = remove_hpte(cpu, *tsh & H_BULK_REMOVE_PTEX, tsl,
2056c568998SPhilippe Mathieu-Daudé                           (*tsh & H_BULK_REMOVE_FLAGS) >> 26,
2066c568998SPhilippe Mathieu-Daudé                           &v, &r);
2076c568998SPhilippe Mathieu-Daudé 
2086c568998SPhilippe Mathieu-Daudé         *tsh |= ret << 60;
2096c568998SPhilippe Mathieu-Daudé 
2106c568998SPhilippe Mathieu-Daudé         switch (ret) {
2116c568998SPhilippe Mathieu-Daudé         case REMOVE_SUCCESS:
2126c568998SPhilippe Mathieu-Daudé             *tsh |= (r & (HPTE64_R_C | HPTE64_R_R)) << 43;
2136c568998SPhilippe Mathieu-Daudé             break;
2146c568998SPhilippe Mathieu-Daudé 
2156c568998SPhilippe Mathieu-Daudé         case REMOVE_PARM:
2166c568998SPhilippe Mathieu-Daudé             rc = H_PARAMETER;
2176c568998SPhilippe Mathieu-Daudé             goto exit;
2186c568998SPhilippe Mathieu-Daudé 
2196c568998SPhilippe Mathieu-Daudé         case REMOVE_HW:
2206c568998SPhilippe Mathieu-Daudé             rc = H_HARDWARE;
2216c568998SPhilippe Mathieu-Daudé             goto exit;
2226c568998SPhilippe Mathieu-Daudé         }
2236c568998SPhilippe Mathieu-Daudé     }
2246c568998SPhilippe Mathieu-Daudé  exit:
2256c568998SPhilippe Mathieu-Daudé     check_tlb_flush(env, true);
2266c568998SPhilippe Mathieu-Daudé 
2276c568998SPhilippe Mathieu-Daudé     return rc;
2286c568998SPhilippe Mathieu-Daudé }
2296c568998SPhilippe Mathieu-Daudé 
h_protect(PowerPCCPU * cpu,SpaprMachineState * spapr,target_ulong opcode,target_ulong * args)2306c568998SPhilippe Mathieu-Daudé static target_ulong h_protect(PowerPCCPU *cpu, SpaprMachineState *spapr,
2316c568998SPhilippe Mathieu-Daudé                               target_ulong opcode, target_ulong *args)
2326c568998SPhilippe Mathieu-Daudé {
2336c568998SPhilippe Mathieu-Daudé     CPUPPCState *env = &cpu->env;
2346c568998SPhilippe Mathieu-Daudé     target_ulong flags = args[0];
2356c568998SPhilippe Mathieu-Daudé     target_ulong ptex = args[1];
2366c568998SPhilippe Mathieu-Daudé     target_ulong avpn = args[2];
2376c568998SPhilippe Mathieu-Daudé     const ppc_hash_pte64_t *hptes;
2386c568998SPhilippe Mathieu-Daudé     target_ulong v, r;
2396c568998SPhilippe Mathieu-Daudé 
240*14a43ab3SBALATON Zoltan     if (!ppc_hash64_valid_ptex(cpu, ptex)) {
2416c568998SPhilippe Mathieu-Daudé         return H_PARAMETER;
2426c568998SPhilippe Mathieu-Daudé     }
2436c568998SPhilippe Mathieu-Daudé 
2446c568998SPhilippe Mathieu-Daudé     hptes = ppc_hash64_map_hptes(cpu, ptex, 1);
2456c568998SPhilippe Mathieu-Daudé     v = ppc_hash64_hpte0(cpu, hptes, 0);
2466c568998SPhilippe Mathieu-Daudé     r = ppc_hash64_hpte1(cpu, hptes, 0);
2476c568998SPhilippe Mathieu-Daudé     ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1);
2486c568998SPhilippe Mathieu-Daudé 
2496c568998SPhilippe Mathieu-Daudé     if ((v & HPTE64_V_VALID) == 0 ||
2506c568998SPhilippe Mathieu-Daudé         ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
2516c568998SPhilippe Mathieu-Daudé         return H_NOT_FOUND;
2526c568998SPhilippe Mathieu-Daudé     }
2536c568998SPhilippe Mathieu-Daudé 
2546c568998SPhilippe Mathieu-Daudé     r &= ~(HPTE64_R_PP0 | HPTE64_R_PP | HPTE64_R_N |
2556c568998SPhilippe Mathieu-Daudé            HPTE64_R_KEY_HI | HPTE64_R_KEY_LO);
2566c568998SPhilippe Mathieu-Daudé     r |= (flags << 55) & HPTE64_R_PP0;
2576c568998SPhilippe Mathieu-Daudé     r |= (flags << 48) & HPTE64_R_KEY_HI;
2586c568998SPhilippe Mathieu-Daudé     r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO);
2596c568998SPhilippe Mathieu-Daudé     spapr_store_hpte(cpu, ptex,
2606c568998SPhilippe Mathieu-Daudé                      (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY, 0);
2616c568998SPhilippe Mathieu-Daudé     ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r);
2626c568998SPhilippe Mathieu-Daudé     /* Flush the tlb */
2636c568998SPhilippe Mathieu-Daudé     check_tlb_flush(env, true);
2646c568998SPhilippe Mathieu-Daudé     /* Don't need a memory barrier, due to qemu's global lock */
2656c568998SPhilippe Mathieu-Daudé     spapr_store_hpte(cpu, ptex, v | HPTE64_V_HPTE_DIRTY, r);
2666c568998SPhilippe Mathieu-Daudé     return H_SUCCESS;
2676c568998SPhilippe Mathieu-Daudé }
2686c568998SPhilippe Mathieu-Daudé 
h_read(PowerPCCPU * cpu,SpaprMachineState * spapr,target_ulong opcode,target_ulong * args)2696c568998SPhilippe Mathieu-Daudé static target_ulong h_read(PowerPCCPU *cpu, SpaprMachineState *spapr,
2706c568998SPhilippe Mathieu-Daudé                            target_ulong opcode, target_ulong *args)
2716c568998SPhilippe Mathieu-Daudé {
2726c568998SPhilippe Mathieu-Daudé     target_ulong flags = args[0];
2736c568998SPhilippe Mathieu-Daudé     target_ulong ptex = args[1];
2746c568998SPhilippe Mathieu-Daudé     int i, ridx, n_entries = 1;
2756c568998SPhilippe Mathieu-Daudé     const ppc_hash_pte64_t *hptes;
2766c568998SPhilippe Mathieu-Daudé 
277*14a43ab3SBALATON Zoltan     if (!ppc_hash64_valid_ptex(cpu, ptex)) {
2786c568998SPhilippe Mathieu-Daudé         return H_PARAMETER;
2796c568998SPhilippe Mathieu-Daudé     }
2806c568998SPhilippe Mathieu-Daudé 
2816c568998SPhilippe Mathieu-Daudé     if (flags & H_READ_4) {
2826c568998SPhilippe Mathieu-Daudé         /* Clear the two low order bits */
2836c568998SPhilippe Mathieu-Daudé         ptex &= ~(3ULL);
2846c568998SPhilippe Mathieu-Daudé         n_entries = 4;
2856c568998SPhilippe Mathieu-Daudé     }
2866c568998SPhilippe Mathieu-Daudé 
2876c568998SPhilippe Mathieu-Daudé     hptes = ppc_hash64_map_hptes(cpu, ptex, n_entries);
2886c568998SPhilippe Mathieu-Daudé     for (i = 0, ridx = 0; i < n_entries; i++) {
2896c568998SPhilippe Mathieu-Daudé         args[ridx++] = ppc_hash64_hpte0(cpu, hptes, i);
2906c568998SPhilippe Mathieu-Daudé         args[ridx++] = ppc_hash64_hpte1(cpu, hptes, i);
2916c568998SPhilippe Mathieu-Daudé     }
2926c568998SPhilippe Mathieu-Daudé     ppc_hash64_unmap_hptes(cpu, hptes, ptex, n_entries);
2936c568998SPhilippe Mathieu-Daudé 
2946c568998SPhilippe Mathieu-Daudé     return H_SUCCESS;
2956c568998SPhilippe Mathieu-Daudé }
2966c568998SPhilippe Mathieu-Daudé 
2976c568998SPhilippe Mathieu-Daudé struct SpaprPendingHpt {
2986c568998SPhilippe Mathieu-Daudé     /* These fields are read-only after initialization */
2996c568998SPhilippe Mathieu-Daudé     int shift;
3006c568998SPhilippe Mathieu-Daudé     QemuThread thread;
3016c568998SPhilippe Mathieu-Daudé 
3026c568998SPhilippe Mathieu-Daudé     /* These fields are protected by the BQL */
3036c568998SPhilippe Mathieu-Daudé     bool complete;
3046c568998SPhilippe Mathieu-Daudé 
3056c568998SPhilippe Mathieu-Daudé     /* These fields are private to the preparation thread if
3066c568998SPhilippe Mathieu-Daudé      * !complete, otherwise protected by the BQL */
3076c568998SPhilippe Mathieu-Daudé     int ret;
3086c568998SPhilippe Mathieu-Daudé     void *hpt;
3096c568998SPhilippe Mathieu-Daudé };
3106c568998SPhilippe Mathieu-Daudé 
free_pending_hpt(SpaprPendingHpt * pending)3116c568998SPhilippe Mathieu-Daudé static void free_pending_hpt(SpaprPendingHpt *pending)
3126c568998SPhilippe Mathieu-Daudé {
3136c568998SPhilippe Mathieu-Daudé     if (pending->hpt) {
3146c568998SPhilippe Mathieu-Daudé         qemu_vfree(pending->hpt);
3156c568998SPhilippe Mathieu-Daudé     }
3166c568998SPhilippe Mathieu-Daudé 
3176c568998SPhilippe Mathieu-Daudé     g_free(pending);
3186c568998SPhilippe Mathieu-Daudé }
3196c568998SPhilippe Mathieu-Daudé 
hpt_prepare_thread(void * opaque)3206c568998SPhilippe Mathieu-Daudé static void *hpt_prepare_thread(void *opaque)
3216c568998SPhilippe Mathieu-Daudé {
3226c568998SPhilippe Mathieu-Daudé     SpaprPendingHpt *pending = opaque;
3236c568998SPhilippe Mathieu-Daudé     size_t size = 1ULL << pending->shift;
3246c568998SPhilippe Mathieu-Daudé 
3256c568998SPhilippe Mathieu-Daudé     pending->hpt = qemu_try_memalign(size, size);
3266c568998SPhilippe Mathieu-Daudé     if (pending->hpt) {
3276c568998SPhilippe Mathieu-Daudé         memset(pending->hpt, 0, size);
3286c568998SPhilippe Mathieu-Daudé         pending->ret = H_SUCCESS;
3296c568998SPhilippe Mathieu-Daudé     } else {
3306c568998SPhilippe Mathieu-Daudé         pending->ret = H_NO_MEM;
3316c568998SPhilippe Mathieu-Daudé     }
3326c568998SPhilippe Mathieu-Daudé 
3336c568998SPhilippe Mathieu-Daudé     bql_lock();
3346c568998SPhilippe Mathieu-Daudé 
3356c568998SPhilippe Mathieu-Daudé     if (SPAPR_MACHINE(qdev_get_machine())->pending_hpt == pending) {
3366c568998SPhilippe Mathieu-Daudé         /* Ready to go */
3376c568998SPhilippe Mathieu-Daudé         pending->complete = true;
3386c568998SPhilippe Mathieu-Daudé     } else {
3396c568998SPhilippe Mathieu-Daudé         /* We've been cancelled, clean ourselves up */
3406c568998SPhilippe Mathieu-Daudé         free_pending_hpt(pending);
3416c568998SPhilippe Mathieu-Daudé     }
3426c568998SPhilippe Mathieu-Daudé 
3436c568998SPhilippe Mathieu-Daudé     bql_unlock();
3446c568998SPhilippe Mathieu-Daudé     return NULL;
3456c568998SPhilippe Mathieu-Daudé }
3466c568998SPhilippe Mathieu-Daudé 
3476c568998SPhilippe Mathieu-Daudé /* Must be called with BQL held */
cancel_hpt_prepare(SpaprMachineState * spapr)3486c568998SPhilippe Mathieu-Daudé static void cancel_hpt_prepare(SpaprMachineState *spapr)
3496c568998SPhilippe Mathieu-Daudé {
3506c568998SPhilippe Mathieu-Daudé     SpaprPendingHpt *pending = spapr->pending_hpt;
3516c568998SPhilippe Mathieu-Daudé 
3526c568998SPhilippe Mathieu-Daudé     /* Let the thread know it's cancelled */
3536c568998SPhilippe Mathieu-Daudé     spapr->pending_hpt = NULL;
3546c568998SPhilippe Mathieu-Daudé 
3556c568998SPhilippe Mathieu-Daudé     if (!pending) {
3566c568998SPhilippe Mathieu-Daudé         /* Nothing to do */
3576c568998SPhilippe Mathieu-Daudé         return;
3586c568998SPhilippe Mathieu-Daudé     }
3596c568998SPhilippe Mathieu-Daudé 
3606c568998SPhilippe Mathieu-Daudé     if (!pending->complete) {
3616c568998SPhilippe Mathieu-Daudé         /* thread will clean itself up */
3626c568998SPhilippe Mathieu-Daudé         return;
3636c568998SPhilippe Mathieu-Daudé     }
3646c568998SPhilippe Mathieu-Daudé 
3656c568998SPhilippe Mathieu-Daudé     free_pending_hpt(pending);
3666c568998SPhilippe Mathieu-Daudé }
3676c568998SPhilippe Mathieu-Daudé 
vhyp_mmu_resize_hpt_prepare(PowerPCCPU * cpu,SpaprMachineState * spapr,target_ulong shift)3686c568998SPhilippe Mathieu-Daudé target_ulong vhyp_mmu_resize_hpt_prepare(PowerPCCPU *cpu,
3696c568998SPhilippe Mathieu-Daudé                                          SpaprMachineState *spapr,
3706c568998SPhilippe Mathieu-Daudé                                          target_ulong shift)
3716c568998SPhilippe Mathieu-Daudé {
3726c568998SPhilippe Mathieu-Daudé     SpaprPendingHpt *pending = spapr->pending_hpt;
3736c568998SPhilippe Mathieu-Daudé 
3746c568998SPhilippe Mathieu-Daudé     if (pending) {
3756c568998SPhilippe Mathieu-Daudé         /* something already in progress */
3766c568998SPhilippe Mathieu-Daudé         if (pending->shift == shift) {
3776c568998SPhilippe Mathieu-Daudé             /* and it's suitable */
3786c568998SPhilippe Mathieu-Daudé             if (pending->complete) {
3796c568998SPhilippe Mathieu-Daudé                 return pending->ret;
3806c568998SPhilippe Mathieu-Daudé             } else {
3816c568998SPhilippe Mathieu-Daudé                 return H_LONG_BUSY_ORDER_100_MSEC;
3826c568998SPhilippe Mathieu-Daudé             }
3836c568998SPhilippe Mathieu-Daudé         }
3846c568998SPhilippe Mathieu-Daudé 
3856c568998SPhilippe Mathieu-Daudé         /* not suitable, cancel and replace */
3866c568998SPhilippe Mathieu-Daudé         cancel_hpt_prepare(spapr);
3876c568998SPhilippe Mathieu-Daudé     }
3886c568998SPhilippe Mathieu-Daudé 
3896c568998SPhilippe Mathieu-Daudé     if (!shift) {
3906c568998SPhilippe Mathieu-Daudé         /* nothing to do */
3916c568998SPhilippe Mathieu-Daudé         return H_SUCCESS;
3926c568998SPhilippe Mathieu-Daudé     }
3936c568998SPhilippe Mathieu-Daudé 
3946c568998SPhilippe Mathieu-Daudé     /* start new prepare */
3956c568998SPhilippe Mathieu-Daudé 
3966c568998SPhilippe Mathieu-Daudé     pending = g_new0(SpaprPendingHpt, 1);
3976c568998SPhilippe Mathieu-Daudé     pending->shift = shift;
3986c568998SPhilippe Mathieu-Daudé     pending->ret = H_HARDWARE;
3996c568998SPhilippe Mathieu-Daudé 
4006c568998SPhilippe Mathieu-Daudé     qemu_thread_create(&pending->thread, "sPAPR HPT prepare",
4016c568998SPhilippe Mathieu-Daudé                        hpt_prepare_thread, pending, QEMU_THREAD_DETACHED);
4026c568998SPhilippe Mathieu-Daudé 
4036c568998SPhilippe Mathieu-Daudé     spapr->pending_hpt = pending;
4046c568998SPhilippe Mathieu-Daudé 
4056c568998SPhilippe Mathieu-Daudé     /* In theory we could estimate the time more accurately based on
4066c568998SPhilippe Mathieu-Daudé      * the new size, but there's not much point */
4076c568998SPhilippe Mathieu-Daudé     return H_LONG_BUSY_ORDER_100_MSEC;
4086c568998SPhilippe Mathieu-Daudé }
4096c568998SPhilippe Mathieu-Daudé 
new_hpte_load0(void * htab,uint64_t pteg,int slot)4106c568998SPhilippe Mathieu-Daudé static uint64_t new_hpte_load0(void *htab, uint64_t pteg, int slot)
4116c568998SPhilippe Mathieu-Daudé {
4126c568998SPhilippe Mathieu-Daudé     uint8_t *addr = htab;
4136c568998SPhilippe Mathieu-Daudé 
4146c568998SPhilippe Mathieu-Daudé     addr += pteg * HASH_PTEG_SIZE_64;
4156c568998SPhilippe Mathieu-Daudé     addr += slot * HASH_PTE_SIZE_64;
4166c568998SPhilippe Mathieu-Daudé     return  ldq_p(addr);
4176c568998SPhilippe Mathieu-Daudé }
4186c568998SPhilippe Mathieu-Daudé 
new_hpte_store(void * htab,uint64_t pteg,int slot,uint64_t pte0,uint64_t pte1)4196c568998SPhilippe Mathieu-Daudé static void new_hpte_store(void *htab, uint64_t pteg, int slot,
4206c568998SPhilippe Mathieu-Daudé                            uint64_t pte0, uint64_t pte1)
4216c568998SPhilippe Mathieu-Daudé {
4226c568998SPhilippe Mathieu-Daudé     uint8_t *addr = htab;
4236c568998SPhilippe Mathieu-Daudé 
4246c568998SPhilippe Mathieu-Daudé     addr += pteg * HASH_PTEG_SIZE_64;
4256c568998SPhilippe Mathieu-Daudé     addr += slot * HASH_PTE_SIZE_64;
4266c568998SPhilippe Mathieu-Daudé 
4276c568998SPhilippe Mathieu-Daudé     stq_p(addr, pte0);
4286c568998SPhilippe Mathieu-Daudé     stq_p(addr + HPTE64_DW1, pte1);
4296c568998SPhilippe Mathieu-Daudé }
4306c568998SPhilippe Mathieu-Daudé 
rehash_hpte(PowerPCCPU * cpu,const ppc_hash_pte64_t * hptes,void * old_hpt,uint64_t oldsize,void * new_hpt,uint64_t newsize,uint64_t pteg,int slot)4316c568998SPhilippe Mathieu-Daudé static int rehash_hpte(PowerPCCPU *cpu,
4326c568998SPhilippe Mathieu-Daudé                        const ppc_hash_pte64_t *hptes,
4336c568998SPhilippe Mathieu-Daudé                        void *old_hpt, uint64_t oldsize,
4346c568998SPhilippe Mathieu-Daudé                        void *new_hpt, uint64_t newsize,
4356c568998SPhilippe Mathieu-Daudé                        uint64_t pteg, int slot)
4366c568998SPhilippe Mathieu-Daudé {
4376c568998SPhilippe Mathieu-Daudé     uint64_t old_hash_mask = (oldsize >> 7) - 1;
4386c568998SPhilippe Mathieu-Daudé     uint64_t new_hash_mask = (newsize >> 7) - 1;
4396c568998SPhilippe Mathieu-Daudé     target_ulong pte0 = ppc_hash64_hpte0(cpu, hptes, slot);
4406c568998SPhilippe Mathieu-Daudé     target_ulong pte1;
4416c568998SPhilippe Mathieu-Daudé     uint64_t avpn;
4426c568998SPhilippe Mathieu-Daudé     unsigned base_pg_shift;
4436c568998SPhilippe Mathieu-Daudé     uint64_t hash, new_pteg, replace_pte0;
4446c568998SPhilippe Mathieu-Daudé 
4456c568998SPhilippe Mathieu-Daudé     if (!(pte0 & HPTE64_V_VALID) || !(pte0 & HPTE64_V_BOLTED)) {
4466c568998SPhilippe Mathieu-Daudé         return H_SUCCESS;
4476c568998SPhilippe Mathieu-Daudé     }
4486c568998SPhilippe Mathieu-Daudé 
4496c568998SPhilippe Mathieu-Daudé     pte1 = ppc_hash64_hpte1(cpu, hptes, slot);
4506c568998SPhilippe Mathieu-Daudé 
4516c568998SPhilippe Mathieu-Daudé     base_pg_shift = ppc_hash64_hpte_page_shift_noslb(cpu, pte0, pte1);
4526c568998SPhilippe Mathieu-Daudé     assert(base_pg_shift); /* H_ENTER shouldn't allow a bad encoding */
4536c568998SPhilippe Mathieu-Daudé     avpn = HPTE64_V_AVPN_VAL(pte0) & ~(((1ULL << base_pg_shift) - 1) >> 23);
4546c568998SPhilippe Mathieu-Daudé 
4556c568998SPhilippe Mathieu-Daudé     if (pte0 & HPTE64_V_SECONDARY) {
4566c568998SPhilippe Mathieu-Daudé         pteg = ~pteg;
4576c568998SPhilippe Mathieu-Daudé     }
4586c568998SPhilippe Mathieu-Daudé 
4596c568998SPhilippe Mathieu-Daudé     if ((pte0 & HPTE64_V_SSIZE) == HPTE64_V_SSIZE_256M) {
4606c568998SPhilippe Mathieu-Daudé         uint64_t offset, vsid;
4616c568998SPhilippe Mathieu-Daudé 
4626c568998SPhilippe Mathieu-Daudé         /* We only have 28 - 23 bits of offset in avpn */
4636c568998SPhilippe Mathieu-Daudé         offset = (avpn & 0x1f) << 23;
4646c568998SPhilippe Mathieu-Daudé         vsid = avpn >> 5;
4656c568998SPhilippe Mathieu-Daudé         /* We can find more bits from the pteg value */
4666c568998SPhilippe Mathieu-Daudé         if (base_pg_shift < 23) {
4676c568998SPhilippe Mathieu-Daudé             offset |= ((vsid ^ pteg) & old_hash_mask) << base_pg_shift;
4686c568998SPhilippe Mathieu-Daudé         }
4696c568998SPhilippe Mathieu-Daudé 
4706c568998SPhilippe Mathieu-Daudé         hash = vsid ^ (offset >> base_pg_shift);
4716c568998SPhilippe Mathieu-Daudé     } else if ((pte0 & HPTE64_V_SSIZE) == HPTE64_V_SSIZE_1T) {
4726c568998SPhilippe Mathieu-Daudé         uint64_t offset, vsid;
4736c568998SPhilippe Mathieu-Daudé 
4746c568998SPhilippe Mathieu-Daudé         /* We only have 40 - 23 bits of seg_off in avpn */
4756c568998SPhilippe Mathieu-Daudé         offset = (avpn & 0x1ffff) << 23;
4766c568998SPhilippe Mathieu-Daudé         vsid = avpn >> 17;
4776c568998SPhilippe Mathieu-Daudé         if (base_pg_shift < 23) {
4786c568998SPhilippe Mathieu-Daudé             offset |= ((vsid ^ (vsid << 25) ^ pteg) & old_hash_mask)
4796c568998SPhilippe Mathieu-Daudé                 << base_pg_shift;
4806c568998SPhilippe Mathieu-Daudé         }
4816c568998SPhilippe Mathieu-Daudé 
4826c568998SPhilippe Mathieu-Daudé         hash = vsid ^ (vsid << 25) ^ (offset >> base_pg_shift);
4836c568998SPhilippe Mathieu-Daudé     } else {
4846c568998SPhilippe Mathieu-Daudé         error_report("rehash_pte: Bad segment size in HPTE");
4856c568998SPhilippe Mathieu-Daudé         return H_HARDWARE;
4866c568998SPhilippe Mathieu-Daudé     }
4876c568998SPhilippe Mathieu-Daudé 
4886c568998SPhilippe Mathieu-Daudé     new_pteg = hash & new_hash_mask;
4896c568998SPhilippe Mathieu-Daudé     if (pte0 & HPTE64_V_SECONDARY) {
4906c568998SPhilippe Mathieu-Daudé         assert(~pteg == (hash & old_hash_mask));
4916c568998SPhilippe Mathieu-Daudé         new_pteg = ~new_pteg;
4926c568998SPhilippe Mathieu-Daudé     } else {
4936c568998SPhilippe Mathieu-Daudé         assert(pteg == (hash & old_hash_mask));
4946c568998SPhilippe Mathieu-Daudé     }
4956c568998SPhilippe Mathieu-Daudé     assert((oldsize != newsize) || (pteg == new_pteg));
4966c568998SPhilippe Mathieu-Daudé     replace_pte0 = new_hpte_load0(new_hpt, new_pteg, slot);
4976c568998SPhilippe Mathieu-Daudé     /*
4986c568998SPhilippe Mathieu-Daudé      * Strictly speaking, we don't need all these tests, since we only
4996c568998SPhilippe Mathieu-Daudé      * ever rehash bolted HPTEs.  We might in future handle non-bolted
5006c568998SPhilippe Mathieu-Daudé      * HPTEs, though so make the logic correct for those cases as
5016c568998SPhilippe Mathieu-Daudé      * well.
5026c568998SPhilippe Mathieu-Daudé      */
5036c568998SPhilippe Mathieu-Daudé     if (replace_pte0 & HPTE64_V_VALID) {
5046c568998SPhilippe Mathieu-Daudé         assert(newsize < oldsize);
5056c568998SPhilippe Mathieu-Daudé         if (replace_pte0 & HPTE64_V_BOLTED) {
5066c568998SPhilippe Mathieu-Daudé             if (pte0 & HPTE64_V_BOLTED) {
5076c568998SPhilippe Mathieu-Daudé                 /* Bolted collision, nothing we can do */
5086c568998SPhilippe Mathieu-Daudé                 return H_PTEG_FULL;
5096c568998SPhilippe Mathieu-Daudé             } else {
5106c568998SPhilippe Mathieu-Daudé                 /* Discard this hpte */
5116c568998SPhilippe Mathieu-Daudé                 return H_SUCCESS;
5126c568998SPhilippe Mathieu-Daudé             }
5136c568998SPhilippe Mathieu-Daudé         }
5146c568998SPhilippe Mathieu-Daudé     }
5156c568998SPhilippe Mathieu-Daudé 
5166c568998SPhilippe Mathieu-Daudé     new_hpte_store(new_hpt, new_pteg, slot, pte0, pte1);
5176c568998SPhilippe Mathieu-Daudé     return H_SUCCESS;
5186c568998SPhilippe Mathieu-Daudé }
5196c568998SPhilippe Mathieu-Daudé 
rehash_hpt(PowerPCCPU * cpu,void * old_hpt,uint64_t oldsize,void * new_hpt,uint64_t newsize)5206c568998SPhilippe Mathieu-Daudé static int rehash_hpt(PowerPCCPU *cpu,
5216c568998SPhilippe Mathieu-Daudé                       void *old_hpt, uint64_t oldsize,
5226c568998SPhilippe Mathieu-Daudé                       void *new_hpt, uint64_t newsize)
5236c568998SPhilippe Mathieu-Daudé {
5246c568998SPhilippe Mathieu-Daudé     uint64_t n_ptegs = oldsize >> 7;
5256c568998SPhilippe Mathieu-Daudé     uint64_t pteg;
5266c568998SPhilippe Mathieu-Daudé     int slot;
5276c568998SPhilippe Mathieu-Daudé     int rc;
5286c568998SPhilippe Mathieu-Daudé 
5296c568998SPhilippe Mathieu-Daudé     for (pteg = 0; pteg < n_ptegs; pteg++) {
5306c568998SPhilippe Mathieu-Daudé         hwaddr ptex = pteg * HPTES_PER_GROUP;
5316c568998SPhilippe Mathieu-Daudé         const ppc_hash_pte64_t *hptes
5326c568998SPhilippe Mathieu-Daudé             = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP);
5336c568998SPhilippe Mathieu-Daudé 
5346c568998SPhilippe Mathieu-Daudé         if (!hptes) {
5356c568998SPhilippe Mathieu-Daudé             return H_HARDWARE;
5366c568998SPhilippe Mathieu-Daudé         }
5376c568998SPhilippe Mathieu-Daudé 
5386c568998SPhilippe Mathieu-Daudé         for (slot = 0; slot < HPTES_PER_GROUP; slot++) {
5396c568998SPhilippe Mathieu-Daudé             rc = rehash_hpte(cpu, hptes, old_hpt, oldsize, new_hpt, newsize,
5406c568998SPhilippe Mathieu-Daudé                              pteg, slot);
5416c568998SPhilippe Mathieu-Daudé             if (rc != H_SUCCESS) {
5426c568998SPhilippe Mathieu-Daudé                 ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP);
5436c568998SPhilippe Mathieu-Daudé                 return rc;
5446c568998SPhilippe Mathieu-Daudé             }
5456c568998SPhilippe Mathieu-Daudé         }
5466c568998SPhilippe Mathieu-Daudé         ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP);
5476c568998SPhilippe Mathieu-Daudé     }
5486c568998SPhilippe Mathieu-Daudé 
5496c568998SPhilippe Mathieu-Daudé     return H_SUCCESS;
5506c568998SPhilippe Mathieu-Daudé }
5516c568998SPhilippe Mathieu-Daudé 
vhyp_mmu_resize_hpt_commit(PowerPCCPU * cpu,SpaprMachineState * spapr,target_ulong flags,target_ulong shift)5526c568998SPhilippe Mathieu-Daudé target_ulong vhyp_mmu_resize_hpt_commit(PowerPCCPU *cpu,
5536c568998SPhilippe Mathieu-Daudé                                         SpaprMachineState *spapr,
5546c568998SPhilippe Mathieu-Daudé                                         target_ulong flags,
5556c568998SPhilippe Mathieu-Daudé                                         target_ulong shift)
5566c568998SPhilippe Mathieu-Daudé {
5576c568998SPhilippe Mathieu-Daudé     SpaprPendingHpt *pending = spapr->pending_hpt;
5586c568998SPhilippe Mathieu-Daudé     int rc;
5596c568998SPhilippe Mathieu-Daudé     size_t newsize;
5606c568998SPhilippe Mathieu-Daudé 
5616c568998SPhilippe Mathieu-Daudé     if (flags != 0) {
5626c568998SPhilippe Mathieu-Daudé         return H_PARAMETER;
5636c568998SPhilippe Mathieu-Daudé     }
5646c568998SPhilippe Mathieu-Daudé 
5656c568998SPhilippe Mathieu-Daudé     if (!pending || (pending->shift != shift)) {
5666c568998SPhilippe Mathieu-Daudé         /* no matching prepare */
5676c568998SPhilippe Mathieu-Daudé         return H_CLOSED;
5686c568998SPhilippe Mathieu-Daudé     }
5696c568998SPhilippe Mathieu-Daudé 
5706c568998SPhilippe Mathieu-Daudé     if (!pending->complete) {
5716c568998SPhilippe Mathieu-Daudé         /* prepare has not completed */
5726c568998SPhilippe Mathieu-Daudé         return H_BUSY;
5736c568998SPhilippe Mathieu-Daudé     }
5746c568998SPhilippe Mathieu-Daudé 
5756c568998SPhilippe Mathieu-Daudé     /* Shouldn't have got past PREPARE without an HPT */
5766c568998SPhilippe Mathieu-Daudé     g_assert(spapr->htab_shift);
5776c568998SPhilippe Mathieu-Daudé 
5786c568998SPhilippe Mathieu-Daudé     newsize = 1ULL << pending->shift;
5796c568998SPhilippe Mathieu-Daudé     rc = rehash_hpt(cpu, spapr->htab, HTAB_SIZE(spapr),
5806c568998SPhilippe Mathieu-Daudé                     pending->hpt, newsize);
5816c568998SPhilippe Mathieu-Daudé     if (rc == H_SUCCESS) {
5826c568998SPhilippe Mathieu-Daudé         qemu_vfree(spapr->htab);
5836c568998SPhilippe Mathieu-Daudé         spapr->htab = pending->hpt;
5846c568998SPhilippe Mathieu-Daudé         spapr->htab_shift = pending->shift;
5856c568998SPhilippe Mathieu-Daudé 
5866c568998SPhilippe Mathieu-Daudé         push_sregs_to_kvm_pr(spapr);
5876c568998SPhilippe Mathieu-Daudé 
5886c568998SPhilippe Mathieu-Daudé         pending->hpt = NULL; /* so it's not free()d */
5896c568998SPhilippe Mathieu-Daudé     }
5906c568998SPhilippe Mathieu-Daudé 
5916c568998SPhilippe Mathieu-Daudé     /* Clean up */
5926c568998SPhilippe Mathieu-Daudé     spapr->pending_hpt = NULL;
5936c568998SPhilippe Mathieu-Daudé     free_pending_hpt(pending);
5946c568998SPhilippe Mathieu-Daudé 
5956c568998SPhilippe Mathieu-Daudé     return rc;
5966c568998SPhilippe Mathieu-Daudé }
5976c568998SPhilippe Mathieu-Daudé 
hypercall_register_types(void)5986c568998SPhilippe Mathieu-Daudé static void hypercall_register_types(void)
5996c568998SPhilippe Mathieu-Daudé {
6006c568998SPhilippe Mathieu-Daudé     /* hcall-pft */
6016c568998SPhilippe Mathieu-Daudé     spapr_register_hypercall(H_ENTER, h_enter);
6026c568998SPhilippe Mathieu-Daudé     spapr_register_hypercall(H_REMOVE, h_remove);
6036c568998SPhilippe Mathieu-Daudé     spapr_register_hypercall(H_PROTECT, h_protect);
6046c568998SPhilippe Mathieu-Daudé     spapr_register_hypercall(H_READ, h_read);
6056c568998SPhilippe Mathieu-Daudé 
6066c568998SPhilippe Mathieu-Daudé     /* hcall-bulk */
6076c568998SPhilippe Mathieu-Daudé     spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove);
6086c568998SPhilippe Mathieu-Daudé 
6096c568998SPhilippe Mathieu-Daudé }
6106c568998SPhilippe Mathieu-Daudé 
6116c568998SPhilippe Mathieu-Daudé type_init(hypercall_register_types)
612