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