1*6c568998SPhilippe Mathieu-Daudé /* 2*6c568998SPhilippe Mathieu-Daudé * MMU hypercalls for the sPAPR (pseries) vHyp hypervisor that is used by TCG 3*6c568998SPhilippe Mathieu-Daudé * 4*6c568998SPhilippe Mathieu-Daudé * Copyright (c) 2004-2007 Fabrice Bellard 5*6c568998SPhilippe Mathieu-Daudé * Copyright (c) 2007 Jocelyn Mayer 6*6c568998SPhilippe Mathieu-Daudé * Copyright (c) 2010 David Gibson, IBM Corporation. 7*6c568998SPhilippe Mathieu-Daudé * 8*6c568998SPhilippe Mathieu-Daudé * SPDX-License-Identifier: MIT 9*6c568998SPhilippe Mathieu-Daudé */ 10*6c568998SPhilippe Mathieu-Daudé #include "qemu/osdep.h" 11*6c568998SPhilippe Mathieu-Daudé #include "qemu/cutils.h" 12*6c568998SPhilippe Mathieu-Daudé #include "qemu/memalign.h" 13*6c568998SPhilippe Mathieu-Daudé #include "qemu/error-report.h" 14*6c568998SPhilippe Mathieu-Daudé #include "cpu.h" 15*6c568998SPhilippe Mathieu-Daudé #include "helper_regs.h" 16*6c568998SPhilippe Mathieu-Daudé #include "hw/ppc/spapr.h" 17*6c568998SPhilippe Mathieu-Daudé #include "mmu-hash64.h" 18*6c568998SPhilippe Mathieu-Daudé #include "mmu-book3s-v3.h" 19*6c568998SPhilippe Mathieu-Daudé 20*6c568998SPhilippe Mathieu-Daudé 21*6c568998SPhilippe Mathieu-Daudé static inline bool valid_ptex(PowerPCCPU *cpu, target_ulong ptex) 22*6c568998SPhilippe Mathieu-Daudé { 23*6c568998SPhilippe Mathieu-Daudé /* 24*6c568998SPhilippe Mathieu-Daudé * hash value/pteg group index is normalized by HPT mask 25*6c568998SPhilippe Mathieu-Daudé */ 26*6c568998SPhilippe Mathieu-Daudé if (((ptex & ~7ULL) / HPTES_PER_GROUP) & ~ppc_hash64_hpt_mask(cpu)) { 27*6c568998SPhilippe Mathieu-Daudé return false; 28*6c568998SPhilippe Mathieu-Daudé } 29*6c568998SPhilippe Mathieu-Daudé return true; 30*6c568998SPhilippe Mathieu-Daudé } 31*6c568998SPhilippe Mathieu-Daudé 32*6c568998SPhilippe Mathieu-Daudé static target_ulong h_enter(PowerPCCPU *cpu, SpaprMachineState *spapr, 33*6c568998SPhilippe Mathieu-Daudé target_ulong opcode, target_ulong *args) 34*6c568998SPhilippe Mathieu-Daudé { 35*6c568998SPhilippe Mathieu-Daudé target_ulong flags = args[0]; 36*6c568998SPhilippe Mathieu-Daudé target_ulong ptex = args[1]; 37*6c568998SPhilippe Mathieu-Daudé target_ulong pteh = args[2]; 38*6c568998SPhilippe Mathieu-Daudé target_ulong ptel = args[3]; 39*6c568998SPhilippe Mathieu-Daudé unsigned apshift; 40*6c568998SPhilippe Mathieu-Daudé target_ulong raddr; 41*6c568998SPhilippe Mathieu-Daudé target_ulong slot; 42*6c568998SPhilippe Mathieu-Daudé const ppc_hash_pte64_t *hptes; 43*6c568998SPhilippe Mathieu-Daudé 44*6c568998SPhilippe Mathieu-Daudé apshift = ppc_hash64_hpte_page_shift_noslb(cpu, pteh, ptel); 45*6c568998SPhilippe Mathieu-Daudé if (!apshift) { 46*6c568998SPhilippe Mathieu-Daudé /* Bad page size encoding */ 47*6c568998SPhilippe Mathieu-Daudé return H_PARAMETER; 48*6c568998SPhilippe Mathieu-Daudé } 49*6c568998SPhilippe Mathieu-Daudé 50*6c568998SPhilippe Mathieu-Daudé raddr = (ptel & HPTE64_R_RPN) & ~((1ULL << apshift) - 1); 51*6c568998SPhilippe Mathieu-Daudé 52*6c568998SPhilippe Mathieu-Daudé if (is_ram_address(spapr, raddr)) { 53*6c568998SPhilippe Mathieu-Daudé /* Regular RAM - should have WIMG=0010 */ 54*6c568998SPhilippe Mathieu-Daudé if ((ptel & HPTE64_R_WIMG) != HPTE64_R_M) { 55*6c568998SPhilippe Mathieu-Daudé return H_PARAMETER; 56*6c568998SPhilippe Mathieu-Daudé } 57*6c568998SPhilippe Mathieu-Daudé } else { 58*6c568998SPhilippe Mathieu-Daudé target_ulong wimg_flags; 59*6c568998SPhilippe Mathieu-Daudé /* Looks like an IO address */ 60*6c568998SPhilippe Mathieu-Daudé /* FIXME: What WIMG combinations could be sensible for IO? 61*6c568998SPhilippe Mathieu-Daudé * For now we allow WIMG=010x, but are there others? */ 62*6c568998SPhilippe Mathieu-Daudé /* FIXME: Should we check against registered IO addresses? */ 63*6c568998SPhilippe Mathieu-Daudé wimg_flags = (ptel & (HPTE64_R_W | HPTE64_R_I | HPTE64_R_M)); 64*6c568998SPhilippe Mathieu-Daudé 65*6c568998SPhilippe Mathieu-Daudé if (wimg_flags != HPTE64_R_I && 66*6c568998SPhilippe Mathieu-Daudé wimg_flags != (HPTE64_R_I | HPTE64_R_M)) { 67*6c568998SPhilippe Mathieu-Daudé return H_PARAMETER; 68*6c568998SPhilippe Mathieu-Daudé } 69*6c568998SPhilippe Mathieu-Daudé } 70*6c568998SPhilippe Mathieu-Daudé 71*6c568998SPhilippe Mathieu-Daudé pteh &= ~0x60ULL; 72*6c568998SPhilippe Mathieu-Daudé 73*6c568998SPhilippe Mathieu-Daudé if (!valid_ptex(cpu, ptex)) { 74*6c568998SPhilippe Mathieu-Daudé return H_PARAMETER; 75*6c568998SPhilippe Mathieu-Daudé } 76*6c568998SPhilippe Mathieu-Daudé 77*6c568998SPhilippe Mathieu-Daudé slot = ptex & 7ULL; 78*6c568998SPhilippe Mathieu-Daudé ptex = ptex & ~7ULL; 79*6c568998SPhilippe Mathieu-Daudé 80*6c568998SPhilippe Mathieu-Daudé if (likely((flags & H_EXACT) == 0)) { 81*6c568998SPhilippe Mathieu-Daudé hptes = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP); 82*6c568998SPhilippe Mathieu-Daudé for (slot = 0; slot < 8; slot++) { 83*6c568998SPhilippe Mathieu-Daudé if (!(ppc_hash64_hpte0(cpu, hptes, slot) & HPTE64_V_VALID)) { 84*6c568998SPhilippe Mathieu-Daudé break; 85*6c568998SPhilippe Mathieu-Daudé } 86*6c568998SPhilippe Mathieu-Daudé } 87*6c568998SPhilippe Mathieu-Daudé ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP); 88*6c568998SPhilippe Mathieu-Daudé if (slot == 8) { 89*6c568998SPhilippe Mathieu-Daudé return H_PTEG_FULL; 90*6c568998SPhilippe Mathieu-Daudé } 91*6c568998SPhilippe Mathieu-Daudé } else { 92*6c568998SPhilippe Mathieu-Daudé hptes = ppc_hash64_map_hptes(cpu, ptex + slot, 1); 93*6c568998SPhilippe Mathieu-Daudé if (ppc_hash64_hpte0(cpu, hptes, 0) & HPTE64_V_VALID) { 94*6c568998SPhilippe Mathieu-Daudé ppc_hash64_unmap_hptes(cpu, hptes, ptex + slot, 1); 95*6c568998SPhilippe Mathieu-Daudé return H_PTEG_FULL; 96*6c568998SPhilippe Mathieu-Daudé } 97*6c568998SPhilippe Mathieu-Daudé ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1); 98*6c568998SPhilippe Mathieu-Daudé } 99*6c568998SPhilippe Mathieu-Daudé 100*6c568998SPhilippe Mathieu-Daudé spapr_store_hpte(cpu, ptex + slot, pteh | HPTE64_V_HPTE_DIRTY, ptel); 101*6c568998SPhilippe Mathieu-Daudé 102*6c568998SPhilippe Mathieu-Daudé args[0] = ptex + slot; 103*6c568998SPhilippe Mathieu-Daudé return H_SUCCESS; 104*6c568998SPhilippe Mathieu-Daudé } 105*6c568998SPhilippe Mathieu-Daudé 106*6c568998SPhilippe Mathieu-Daudé typedef enum { 107*6c568998SPhilippe Mathieu-Daudé REMOVE_SUCCESS = 0, 108*6c568998SPhilippe Mathieu-Daudé REMOVE_NOT_FOUND = 1, 109*6c568998SPhilippe Mathieu-Daudé REMOVE_PARM = 2, 110*6c568998SPhilippe Mathieu-Daudé REMOVE_HW = 3, 111*6c568998SPhilippe Mathieu-Daudé } RemoveResult; 112*6c568998SPhilippe Mathieu-Daudé 113*6c568998SPhilippe Mathieu-Daudé static RemoveResult remove_hpte(PowerPCCPU *cpu 114*6c568998SPhilippe Mathieu-Daudé , target_ulong ptex, 115*6c568998SPhilippe Mathieu-Daudé target_ulong avpn, 116*6c568998SPhilippe Mathieu-Daudé target_ulong flags, 117*6c568998SPhilippe Mathieu-Daudé target_ulong *vp, target_ulong *rp) 118*6c568998SPhilippe Mathieu-Daudé { 119*6c568998SPhilippe Mathieu-Daudé const ppc_hash_pte64_t *hptes; 120*6c568998SPhilippe Mathieu-Daudé target_ulong v, r; 121*6c568998SPhilippe Mathieu-Daudé 122*6c568998SPhilippe Mathieu-Daudé if (!valid_ptex(cpu, ptex)) { 123*6c568998SPhilippe Mathieu-Daudé return REMOVE_PARM; 124*6c568998SPhilippe Mathieu-Daudé } 125*6c568998SPhilippe Mathieu-Daudé 126*6c568998SPhilippe Mathieu-Daudé hptes = ppc_hash64_map_hptes(cpu, ptex, 1); 127*6c568998SPhilippe Mathieu-Daudé v = ppc_hash64_hpte0(cpu, hptes, 0); 128*6c568998SPhilippe Mathieu-Daudé r = ppc_hash64_hpte1(cpu, hptes, 0); 129*6c568998SPhilippe Mathieu-Daudé ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1); 130*6c568998SPhilippe Mathieu-Daudé 131*6c568998SPhilippe Mathieu-Daudé if ((v & HPTE64_V_VALID) == 0 || 132*6c568998SPhilippe Mathieu-Daudé ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) || 133*6c568998SPhilippe Mathieu-Daudé ((flags & H_ANDCOND) && (v & avpn) != 0)) { 134*6c568998SPhilippe Mathieu-Daudé return REMOVE_NOT_FOUND; 135*6c568998SPhilippe Mathieu-Daudé } 136*6c568998SPhilippe Mathieu-Daudé *vp = v; 137*6c568998SPhilippe Mathieu-Daudé *rp = r; 138*6c568998SPhilippe Mathieu-Daudé spapr_store_hpte(cpu, ptex, HPTE64_V_HPTE_DIRTY, 0); 139*6c568998SPhilippe Mathieu-Daudé ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r); 140*6c568998SPhilippe Mathieu-Daudé return REMOVE_SUCCESS; 141*6c568998SPhilippe Mathieu-Daudé } 142*6c568998SPhilippe Mathieu-Daudé 143*6c568998SPhilippe Mathieu-Daudé static target_ulong h_remove(PowerPCCPU *cpu, SpaprMachineState *spapr, 144*6c568998SPhilippe Mathieu-Daudé target_ulong opcode, target_ulong *args) 145*6c568998SPhilippe Mathieu-Daudé { 146*6c568998SPhilippe Mathieu-Daudé CPUPPCState *env = &cpu->env; 147*6c568998SPhilippe Mathieu-Daudé target_ulong flags = args[0]; 148*6c568998SPhilippe Mathieu-Daudé target_ulong ptex = args[1]; 149*6c568998SPhilippe Mathieu-Daudé target_ulong avpn = args[2]; 150*6c568998SPhilippe Mathieu-Daudé RemoveResult ret; 151*6c568998SPhilippe Mathieu-Daudé 152*6c568998SPhilippe Mathieu-Daudé ret = remove_hpte(cpu, ptex, avpn, flags, 153*6c568998SPhilippe Mathieu-Daudé &args[0], &args[1]); 154*6c568998SPhilippe Mathieu-Daudé 155*6c568998SPhilippe Mathieu-Daudé switch (ret) { 156*6c568998SPhilippe Mathieu-Daudé case REMOVE_SUCCESS: 157*6c568998SPhilippe Mathieu-Daudé check_tlb_flush(env, true); 158*6c568998SPhilippe Mathieu-Daudé return H_SUCCESS; 159*6c568998SPhilippe Mathieu-Daudé 160*6c568998SPhilippe Mathieu-Daudé case REMOVE_NOT_FOUND: 161*6c568998SPhilippe Mathieu-Daudé return H_NOT_FOUND; 162*6c568998SPhilippe Mathieu-Daudé 163*6c568998SPhilippe Mathieu-Daudé case REMOVE_PARM: 164*6c568998SPhilippe Mathieu-Daudé return H_PARAMETER; 165*6c568998SPhilippe Mathieu-Daudé 166*6c568998SPhilippe Mathieu-Daudé case REMOVE_HW: 167*6c568998SPhilippe Mathieu-Daudé return H_HARDWARE; 168*6c568998SPhilippe Mathieu-Daudé } 169*6c568998SPhilippe Mathieu-Daudé 170*6c568998SPhilippe Mathieu-Daudé g_assert_not_reached(); 171*6c568998SPhilippe Mathieu-Daudé } 172*6c568998SPhilippe Mathieu-Daudé 173*6c568998SPhilippe Mathieu-Daudé #define H_BULK_REMOVE_TYPE 0xc000000000000000ULL 174*6c568998SPhilippe Mathieu-Daudé #define H_BULK_REMOVE_REQUEST 0x4000000000000000ULL 175*6c568998SPhilippe Mathieu-Daudé #define H_BULK_REMOVE_RESPONSE 0x8000000000000000ULL 176*6c568998SPhilippe Mathieu-Daudé #define H_BULK_REMOVE_END 0xc000000000000000ULL 177*6c568998SPhilippe Mathieu-Daudé #define H_BULK_REMOVE_CODE 0x3000000000000000ULL 178*6c568998SPhilippe Mathieu-Daudé #define H_BULK_REMOVE_SUCCESS 0x0000000000000000ULL 179*6c568998SPhilippe Mathieu-Daudé #define H_BULK_REMOVE_NOT_FOUND 0x1000000000000000ULL 180*6c568998SPhilippe Mathieu-Daudé #define H_BULK_REMOVE_PARM 0x2000000000000000ULL 181*6c568998SPhilippe Mathieu-Daudé #define H_BULK_REMOVE_HW 0x3000000000000000ULL 182*6c568998SPhilippe Mathieu-Daudé #define H_BULK_REMOVE_RC 0x0c00000000000000ULL 183*6c568998SPhilippe Mathieu-Daudé #define H_BULK_REMOVE_FLAGS 0x0300000000000000ULL 184*6c568998SPhilippe Mathieu-Daudé #define H_BULK_REMOVE_ABSOLUTE 0x0000000000000000ULL 185*6c568998SPhilippe Mathieu-Daudé #define H_BULK_REMOVE_ANDCOND 0x0100000000000000ULL 186*6c568998SPhilippe Mathieu-Daudé #define H_BULK_REMOVE_AVPN 0x0200000000000000ULL 187*6c568998SPhilippe Mathieu-Daudé #define H_BULK_REMOVE_PTEX 0x00ffffffffffffffULL 188*6c568998SPhilippe Mathieu-Daudé 189*6c568998SPhilippe Mathieu-Daudé #define H_BULK_REMOVE_MAX_BATCH 4 190*6c568998SPhilippe Mathieu-Daudé 191*6c568998SPhilippe Mathieu-Daudé static target_ulong h_bulk_remove(PowerPCCPU *cpu, SpaprMachineState *spapr, 192*6c568998SPhilippe Mathieu-Daudé target_ulong opcode, target_ulong *args) 193*6c568998SPhilippe Mathieu-Daudé { 194*6c568998SPhilippe Mathieu-Daudé CPUPPCState *env = &cpu->env; 195*6c568998SPhilippe Mathieu-Daudé int i; 196*6c568998SPhilippe Mathieu-Daudé target_ulong rc = H_SUCCESS; 197*6c568998SPhilippe Mathieu-Daudé 198*6c568998SPhilippe Mathieu-Daudé for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) { 199*6c568998SPhilippe Mathieu-Daudé target_ulong *tsh = &args[i*2]; 200*6c568998SPhilippe Mathieu-Daudé target_ulong tsl = args[i*2 + 1]; 201*6c568998SPhilippe Mathieu-Daudé target_ulong v, r, ret; 202*6c568998SPhilippe Mathieu-Daudé 203*6c568998SPhilippe Mathieu-Daudé if ((*tsh & H_BULK_REMOVE_TYPE) == H_BULK_REMOVE_END) { 204*6c568998SPhilippe Mathieu-Daudé break; 205*6c568998SPhilippe Mathieu-Daudé } else if ((*tsh & H_BULK_REMOVE_TYPE) != H_BULK_REMOVE_REQUEST) { 206*6c568998SPhilippe Mathieu-Daudé return H_PARAMETER; 207*6c568998SPhilippe Mathieu-Daudé } 208*6c568998SPhilippe Mathieu-Daudé 209*6c568998SPhilippe Mathieu-Daudé *tsh &= H_BULK_REMOVE_PTEX | H_BULK_REMOVE_FLAGS; 210*6c568998SPhilippe Mathieu-Daudé *tsh |= H_BULK_REMOVE_RESPONSE; 211*6c568998SPhilippe Mathieu-Daudé 212*6c568998SPhilippe Mathieu-Daudé if ((*tsh & H_BULK_REMOVE_ANDCOND) && (*tsh & H_BULK_REMOVE_AVPN)) { 213*6c568998SPhilippe Mathieu-Daudé *tsh |= H_BULK_REMOVE_PARM; 214*6c568998SPhilippe Mathieu-Daudé return H_PARAMETER; 215*6c568998SPhilippe Mathieu-Daudé } 216*6c568998SPhilippe Mathieu-Daudé 217*6c568998SPhilippe Mathieu-Daudé ret = remove_hpte(cpu, *tsh & H_BULK_REMOVE_PTEX, tsl, 218*6c568998SPhilippe Mathieu-Daudé (*tsh & H_BULK_REMOVE_FLAGS) >> 26, 219*6c568998SPhilippe Mathieu-Daudé &v, &r); 220*6c568998SPhilippe Mathieu-Daudé 221*6c568998SPhilippe Mathieu-Daudé *tsh |= ret << 60; 222*6c568998SPhilippe Mathieu-Daudé 223*6c568998SPhilippe Mathieu-Daudé switch (ret) { 224*6c568998SPhilippe Mathieu-Daudé case REMOVE_SUCCESS: 225*6c568998SPhilippe Mathieu-Daudé *tsh |= (r & (HPTE64_R_C | HPTE64_R_R)) << 43; 226*6c568998SPhilippe Mathieu-Daudé break; 227*6c568998SPhilippe Mathieu-Daudé 228*6c568998SPhilippe Mathieu-Daudé case REMOVE_PARM: 229*6c568998SPhilippe Mathieu-Daudé rc = H_PARAMETER; 230*6c568998SPhilippe Mathieu-Daudé goto exit; 231*6c568998SPhilippe Mathieu-Daudé 232*6c568998SPhilippe Mathieu-Daudé case REMOVE_HW: 233*6c568998SPhilippe Mathieu-Daudé rc = H_HARDWARE; 234*6c568998SPhilippe Mathieu-Daudé goto exit; 235*6c568998SPhilippe Mathieu-Daudé } 236*6c568998SPhilippe Mathieu-Daudé } 237*6c568998SPhilippe Mathieu-Daudé exit: 238*6c568998SPhilippe Mathieu-Daudé check_tlb_flush(env, true); 239*6c568998SPhilippe Mathieu-Daudé 240*6c568998SPhilippe Mathieu-Daudé return rc; 241*6c568998SPhilippe Mathieu-Daudé } 242*6c568998SPhilippe Mathieu-Daudé 243*6c568998SPhilippe Mathieu-Daudé static target_ulong h_protect(PowerPCCPU *cpu, SpaprMachineState *spapr, 244*6c568998SPhilippe Mathieu-Daudé target_ulong opcode, target_ulong *args) 245*6c568998SPhilippe Mathieu-Daudé { 246*6c568998SPhilippe Mathieu-Daudé CPUPPCState *env = &cpu->env; 247*6c568998SPhilippe Mathieu-Daudé target_ulong flags = args[0]; 248*6c568998SPhilippe Mathieu-Daudé target_ulong ptex = args[1]; 249*6c568998SPhilippe Mathieu-Daudé target_ulong avpn = args[2]; 250*6c568998SPhilippe Mathieu-Daudé const ppc_hash_pte64_t *hptes; 251*6c568998SPhilippe Mathieu-Daudé target_ulong v, r; 252*6c568998SPhilippe Mathieu-Daudé 253*6c568998SPhilippe Mathieu-Daudé if (!valid_ptex(cpu, ptex)) { 254*6c568998SPhilippe Mathieu-Daudé return H_PARAMETER; 255*6c568998SPhilippe Mathieu-Daudé } 256*6c568998SPhilippe Mathieu-Daudé 257*6c568998SPhilippe Mathieu-Daudé hptes = ppc_hash64_map_hptes(cpu, ptex, 1); 258*6c568998SPhilippe Mathieu-Daudé v = ppc_hash64_hpte0(cpu, hptes, 0); 259*6c568998SPhilippe Mathieu-Daudé r = ppc_hash64_hpte1(cpu, hptes, 0); 260*6c568998SPhilippe Mathieu-Daudé ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1); 261*6c568998SPhilippe Mathieu-Daudé 262*6c568998SPhilippe Mathieu-Daudé if ((v & HPTE64_V_VALID) == 0 || 263*6c568998SPhilippe Mathieu-Daudé ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) { 264*6c568998SPhilippe Mathieu-Daudé return H_NOT_FOUND; 265*6c568998SPhilippe Mathieu-Daudé } 266*6c568998SPhilippe Mathieu-Daudé 267*6c568998SPhilippe Mathieu-Daudé r &= ~(HPTE64_R_PP0 | HPTE64_R_PP | HPTE64_R_N | 268*6c568998SPhilippe Mathieu-Daudé HPTE64_R_KEY_HI | HPTE64_R_KEY_LO); 269*6c568998SPhilippe Mathieu-Daudé r |= (flags << 55) & HPTE64_R_PP0; 270*6c568998SPhilippe Mathieu-Daudé r |= (flags << 48) & HPTE64_R_KEY_HI; 271*6c568998SPhilippe Mathieu-Daudé r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO); 272*6c568998SPhilippe Mathieu-Daudé spapr_store_hpte(cpu, ptex, 273*6c568998SPhilippe Mathieu-Daudé (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY, 0); 274*6c568998SPhilippe Mathieu-Daudé ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r); 275*6c568998SPhilippe Mathieu-Daudé /* Flush the tlb */ 276*6c568998SPhilippe Mathieu-Daudé check_tlb_flush(env, true); 277*6c568998SPhilippe Mathieu-Daudé /* Don't need a memory barrier, due to qemu's global lock */ 278*6c568998SPhilippe Mathieu-Daudé spapr_store_hpte(cpu, ptex, v | HPTE64_V_HPTE_DIRTY, r); 279*6c568998SPhilippe Mathieu-Daudé return H_SUCCESS; 280*6c568998SPhilippe Mathieu-Daudé } 281*6c568998SPhilippe Mathieu-Daudé 282*6c568998SPhilippe Mathieu-Daudé static target_ulong h_read(PowerPCCPU *cpu, SpaprMachineState *spapr, 283*6c568998SPhilippe Mathieu-Daudé target_ulong opcode, target_ulong *args) 284*6c568998SPhilippe Mathieu-Daudé { 285*6c568998SPhilippe Mathieu-Daudé target_ulong flags = args[0]; 286*6c568998SPhilippe Mathieu-Daudé target_ulong ptex = args[1]; 287*6c568998SPhilippe Mathieu-Daudé int i, ridx, n_entries = 1; 288*6c568998SPhilippe Mathieu-Daudé const ppc_hash_pte64_t *hptes; 289*6c568998SPhilippe Mathieu-Daudé 290*6c568998SPhilippe Mathieu-Daudé if (!valid_ptex(cpu, ptex)) { 291*6c568998SPhilippe Mathieu-Daudé return H_PARAMETER; 292*6c568998SPhilippe Mathieu-Daudé } 293*6c568998SPhilippe Mathieu-Daudé 294*6c568998SPhilippe Mathieu-Daudé if (flags & H_READ_4) { 295*6c568998SPhilippe Mathieu-Daudé /* Clear the two low order bits */ 296*6c568998SPhilippe Mathieu-Daudé ptex &= ~(3ULL); 297*6c568998SPhilippe Mathieu-Daudé n_entries = 4; 298*6c568998SPhilippe Mathieu-Daudé } 299*6c568998SPhilippe Mathieu-Daudé 300*6c568998SPhilippe Mathieu-Daudé hptes = ppc_hash64_map_hptes(cpu, ptex, n_entries); 301*6c568998SPhilippe Mathieu-Daudé for (i = 0, ridx = 0; i < n_entries; i++) { 302*6c568998SPhilippe Mathieu-Daudé args[ridx++] = ppc_hash64_hpte0(cpu, hptes, i); 303*6c568998SPhilippe Mathieu-Daudé args[ridx++] = ppc_hash64_hpte1(cpu, hptes, i); 304*6c568998SPhilippe Mathieu-Daudé } 305*6c568998SPhilippe Mathieu-Daudé ppc_hash64_unmap_hptes(cpu, hptes, ptex, n_entries); 306*6c568998SPhilippe Mathieu-Daudé 307*6c568998SPhilippe Mathieu-Daudé return H_SUCCESS; 308*6c568998SPhilippe Mathieu-Daudé } 309*6c568998SPhilippe Mathieu-Daudé 310*6c568998SPhilippe Mathieu-Daudé struct SpaprPendingHpt { 311*6c568998SPhilippe Mathieu-Daudé /* These fields are read-only after initialization */ 312*6c568998SPhilippe Mathieu-Daudé int shift; 313*6c568998SPhilippe Mathieu-Daudé QemuThread thread; 314*6c568998SPhilippe Mathieu-Daudé 315*6c568998SPhilippe Mathieu-Daudé /* These fields are protected by the BQL */ 316*6c568998SPhilippe Mathieu-Daudé bool complete; 317*6c568998SPhilippe Mathieu-Daudé 318*6c568998SPhilippe Mathieu-Daudé /* These fields are private to the preparation thread if 319*6c568998SPhilippe Mathieu-Daudé * !complete, otherwise protected by the BQL */ 320*6c568998SPhilippe Mathieu-Daudé int ret; 321*6c568998SPhilippe Mathieu-Daudé void *hpt; 322*6c568998SPhilippe Mathieu-Daudé }; 323*6c568998SPhilippe Mathieu-Daudé 324*6c568998SPhilippe Mathieu-Daudé static void free_pending_hpt(SpaprPendingHpt *pending) 325*6c568998SPhilippe Mathieu-Daudé { 326*6c568998SPhilippe Mathieu-Daudé if (pending->hpt) { 327*6c568998SPhilippe Mathieu-Daudé qemu_vfree(pending->hpt); 328*6c568998SPhilippe Mathieu-Daudé } 329*6c568998SPhilippe Mathieu-Daudé 330*6c568998SPhilippe Mathieu-Daudé g_free(pending); 331*6c568998SPhilippe Mathieu-Daudé } 332*6c568998SPhilippe Mathieu-Daudé 333*6c568998SPhilippe Mathieu-Daudé static void *hpt_prepare_thread(void *opaque) 334*6c568998SPhilippe Mathieu-Daudé { 335*6c568998SPhilippe Mathieu-Daudé SpaprPendingHpt *pending = opaque; 336*6c568998SPhilippe Mathieu-Daudé size_t size = 1ULL << pending->shift; 337*6c568998SPhilippe Mathieu-Daudé 338*6c568998SPhilippe Mathieu-Daudé pending->hpt = qemu_try_memalign(size, size); 339*6c568998SPhilippe Mathieu-Daudé if (pending->hpt) { 340*6c568998SPhilippe Mathieu-Daudé memset(pending->hpt, 0, size); 341*6c568998SPhilippe Mathieu-Daudé pending->ret = H_SUCCESS; 342*6c568998SPhilippe Mathieu-Daudé } else { 343*6c568998SPhilippe Mathieu-Daudé pending->ret = H_NO_MEM; 344*6c568998SPhilippe Mathieu-Daudé } 345*6c568998SPhilippe Mathieu-Daudé 346*6c568998SPhilippe Mathieu-Daudé bql_lock(); 347*6c568998SPhilippe Mathieu-Daudé 348*6c568998SPhilippe Mathieu-Daudé if (SPAPR_MACHINE(qdev_get_machine())->pending_hpt == pending) { 349*6c568998SPhilippe Mathieu-Daudé /* Ready to go */ 350*6c568998SPhilippe Mathieu-Daudé pending->complete = true; 351*6c568998SPhilippe Mathieu-Daudé } else { 352*6c568998SPhilippe Mathieu-Daudé /* We've been cancelled, clean ourselves up */ 353*6c568998SPhilippe Mathieu-Daudé free_pending_hpt(pending); 354*6c568998SPhilippe Mathieu-Daudé } 355*6c568998SPhilippe Mathieu-Daudé 356*6c568998SPhilippe Mathieu-Daudé bql_unlock(); 357*6c568998SPhilippe Mathieu-Daudé return NULL; 358*6c568998SPhilippe Mathieu-Daudé } 359*6c568998SPhilippe Mathieu-Daudé 360*6c568998SPhilippe Mathieu-Daudé /* Must be called with BQL held */ 361*6c568998SPhilippe Mathieu-Daudé static void cancel_hpt_prepare(SpaprMachineState *spapr) 362*6c568998SPhilippe Mathieu-Daudé { 363*6c568998SPhilippe Mathieu-Daudé SpaprPendingHpt *pending = spapr->pending_hpt; 364*6c568998SPhilippe Mathieu-Daudé 365*6c568998SPhilippe Mathieu-Daudé /* Let the thread know it's cancelled */ 366*6c568998SPhilippe Mathieu-Daudé spapr->pending_hpt = NULL; 367*6c568998SPhilippe Mathieu-Daudé 368*6c568998SPhilippe Mathieu-Daudé if (!pending) { 369*6c568998SPhilippe Mathieu-Daudé /* Nothing to do */ 370*6c568998SPhilippe Mathieu-Daudé return; 371*6c568998SPhilippe Mathieu-Daudé } 372*6c568998SPhilippe Mathieu-Daudé 373*6c568998SPhilippe Mathieu-Daudé if (!pending->complete) { 374*6c568998SPhilippe Mathieu-Daudé /* thread will clean itself up */ 375*6c568998SPhilippe Mathieu-Daudé return; 376*6c568998SPhilippe Mathieu-Daudé } 377*6c568998SPhilippe Mathieu-Daudé 378*6c568998SPhilippe Mathieu-Daudé free_pending_hpt(pending); 379*6c568998SPhilippe Mathieu-Daudé } 380*6c568998SPhilippe Mathieu-Daudé 381*6c568998SPhilippe Mathieu-Daudé target_ulong vhyp_mmu_resize_hpt_prepare(PowerPCCPU *cpu, 382*6c568998SPhilippe Mathieu-Daudé SpaprMachineState *spapr, 383*6c568998SPhilippe Mathieu-Daudé target_ulong shift) 384*6c568998SPhilippe Mathieu-Daudé { 385*6c568998SPhilippe Mathieu-Daudé SpaprPendingHpt *pending = spapr->pending_hpt; 386*6c568998SPhilippe Mathieu-Daudé 387*6c568998SPhilippe Mathieu-Daudé if (pending) { 388*6c568998SPhilippe Mathieu-Daudé /* something already in progress */ 389*6c568998SPhilippe Mathieu-Daudé if (pending->shift == shift) { 390*6c568998SPhilippe Mathieu-Daudé /* and it's suitable */ 391*6c568998SPhilippe Mathieu-Daudé if (pending->complete) { 392*6c568998SPhilippe Mathieu-Daudé return pending->ret; 393*6c568998SPhilippe Mathieu-Daudé } else { 394*6c568998SPhilippe Mathieu-Daudé return H_LONG_BUSY_ORDER_100_MSEC; 395*6c568998SPhilippe Mathieu-Daudé } 396*6c568998SPhilippe Mathieu-Daudé } 397*6c568998SPhilippe Mathieu-Daudé 398*6c568998SPhilippe Mathieu-Daudé /* not suitable, cancel and replace */ 399*6c568998SPhilippe Mathieu-Daudé cancel_hpt_prepare(spapr); 400*6c568998SPhilippe Mathieu-Daudé } 401*6c568998SPhilippe Mathieu-Daudé 402*6c568998SPhilippe Mathieu-Daudé if (!shift) { 403*6c568998SPhilippe Mathieu-Daudé /* nothing to do */ 404*6c568998SPhilippe Mathieu-Daudé return H_SUCCESS; 405*6c568998SPhilippe Mathieu-Daudé } 406*6c568998SPhilippe Mathieu-Daudé 407*6c568998SPhilippe Mathieu-Daudé /* start new prepare */ 408*6c568998SPhilippe Mathieu-Daudé 409*6c568998SPhilippe Mathieu-Daudé pending = g_new0(SpaprPendingHpt, 1); 410*6c568998SPhilippe Mathieu-Daudé pending->shift = shift; 411*6c568998SPhilippe Mathieu-Daudé pending->ret = H_HARDWARE; 412*6c568998SPhilippe Mathieu-Daudé 413*6c568998SPhilippe Mathieu-Daudé qemu_thread_create(&pending->thread, "sPAPR HPT prepare", 414*6c568998SPhilippe Mathieu-Daudé hpt_prepare_thread, pending, QEMU_THREAD_DETACHED); 415*6c568998SPhilippe Mathieu-Daudé 416*6c568998SPhilippe Mathieu-Daudé spapr->pending_hpt = pending; 417*6c568998SPhilippe Mathieu-Daudé 418*6c568998SPhilippe Mathieu-Daudé /* In theory we could estimate the time more accurately based on 419*6c568998SPhilippe Mathieu-Daudé * the new size, but there's not much point */ 420*6c568998SPhilippe Mathieu-Daudé return H_LONG_BUSY_ORDER_100_MSEC; 421*6c568998SPhilippe Mathieu-Daudé } 422*6c568998SPhilippe Mathieu-Daudé 423*6c568998SPhilippe Mathieu-Daudé static uint64_t new_hpte_load0(void *htab, uint64_t pteg, int slot) 424*6c568998SPhilippe Mathieu-Daudé { 425*6c568998SPhilippe Mathieu-Daudé uint8_t *addr = htab; 426*6c568998SPhilippe Mathieu-Daudé 427*6c568998SPhilippe Mathieu-Daudé addr += pteg * HASH_PTEG_SIZE_64; 428*6c568998SPhilippe Mathieu-Daudé addr += slot * HASH_PTE_SIZE_64; 429*6c568998SPhilippe Mathieu-Daudé return ldq_p(addr); 430*6c568998SPhilippe Mathieu-Daudé } 431*6c568998SPhilippe Mathieu-Daudé 432*6c568998SPhilippe Mathieu-Daudé static void new_hpte_store(void *htab, uint64_t pteg, int slot, 433*6c568998SPhilippe Mathieu-Daudé uint64_t pte0, uint64_t pte1) 434*6c568998SPhilippe Mathieu-Daudé { 435*6c568998SPhilippe Mathieu-Daudé uint8_t *addr = htab; 436*6c568998SPhilippe Mathieu-Daudé 437*6c568998SPhilippe Mathieu-Daudé addr += pteg * HASH_PTEG_SIZE_64; 438*6c568998SPhilippe Mathieu-Daudé addr += slot * HASH_PTE_SIZE_64; 439*6c568998SPhilippe Mathieu-Daudé 440*6c568998SPhilippe Mathieu-Daudé stq_p(addr, pte0); 441*6c568998SPhilippe Mathieu-Daudé stq_p(addr + HPTE64_DW1, pte1); 442*6c568998SPhilippe Mathieu-Daudé } 443*6c568998SPhilippe Mathieu-Daudé 444*6c568998SPhilippe Mathieu-Daudé static int rehash_hpte(PowerPCCPU *cpu, 445*6c568998SPhilippe Mathieu-Daudé const ppc_hash_pte64_t *hptes, 446*6c568998SPhilippe Mathieu-Daudé void *old_hpt, uint64_t oldsize, 447*6c568998SPhilippe Mathieu-Daudé void *new_hpt, uint64_t newsize, 448*6c568998SPhilippe Mathieu-Daudé uint64_t pteg, int slot) 449*6c568998SPhilippe Mathieu-Daudé { 450*6c568998SPhilippe Mathieu-Daudé uint64_t old_hash_mask = (oldsize >> 7) - 1; 451*6c568998SPhilippe Mathieu-Daudé uint64_t new_hash_mask = (newsize >> 7) - 1; 452*6c568998SPhilippe Mathieu-Daudé target_ulong pte0 = ppc_hash64_hpte0(cpu, hptes, slot); 453*6c568998SPhilippe Mathieu-Daudé target_ulong pte1; 454*6c568998SPhilippe Mathieu-Daudé uint64_t avpn; 455*6c568998SPhilippe Mathieu-Daudé unsigned base_pg_shift; 456*6c568998SPhilippe Mathieu-Daudé uint64_t hash, new_pteg, replace_pte0; 457*6c568998SPhilippe Mathieu-Daudé 458*6c568998SPhilippe Mathieu-Daudé if (!(pte0 & HPTE64_V_VALID) || !(pte0 & HPTE64_V_BOLTED)) { 459*6c568998SPhilippe Mathieu-Daudé return H_SUCCESS; 460*6c568998SPhilippe Mathieu-Daudé } 461*6c568998SPhilippe Mathieu-Daudé 462*6c568998SPhilippe Mathieu-Daudé pte1 = ppc_hash64_hpte1(cpu, hptes, slot); 463*6c568998SPhilippe Mathieu-Daudé 464*6c568998SPhilippe Mathieu-Daudé base_pg_shift = ppc_hash64_hpte_page_shift_noslb(cpu, pte0, pte1); 465*6c568998SPhilippe Mathieu-Daudé assert(base_pg_shift); /* H_ENTER shouldn't allow a bad encoding */ 466*6c568998SPhilippe Mathieu-Daudé avpn = HPTE64_V_AVPN_VAL(pte0) & ~(((1ULL << base_pg_shift) - 1) >> 23); 467*6c568998SPhilippe Mathieu-Daudé 468*6c568998SPhilippe Mathieu-Daudé if (pte0 & HPTE64_V_SECONDARY) { 469*6c568998SPhilippe Mathieu-Daudé pteg = ~pteg; 470*6c568998SPhilippe Mathieu-Daudé } 471*6c568998SPhilippe Mathieu-Daudé 472*6c568998SPhilippe Mathieu-Daudé if ((pte0 & HPTE64_V_SSIZE) == HPTE64_V_SSIZE_256M) { 473*6c568998SPhilippe Mathieu-Daudé uint64_t offset, vsid; 474*6c568998SPhilippe Mathieu-Daudé 475*6c568998SPhilippe Mathieu-Daudé /* We only have 28 - 23 bits of offset in avpn */ 476*6c568998SPhilippe Mathieu-Daudé offset = (avpn & 0x1f) << 23; 477*6c568998SPhilippe Mathieu-Daudé vsid = avpn >> 5; 478*6c568998SPhilippe Mathieu-Daudé /* We can find more bits from the pteg value */ 479*6c568998SPhilippe Mathieu-Daudé if (base_pg_shift < 23) { 480*6c568998SPhilippe Mathieu-Daudé offset |= ((vsid ^ pteg) & old_hash_mask) << base_pg_shift; 481*6c568998SPhilippe Mathieu-Daudé } 482*6c568998SPhilippe Mathieu-Daudé 483*6c568998SPhilippe Mathieu-Daudé hash = vsid ^ (offset >> base_pg_shift); 484*6c568998SPhilippe Mathieu-Daudé } else if ((pte0 & HPTE64_V_SSIZE) == HPTE64_V_SSIZE_1T) { 485*6c568998SPhilippe Mathieu-Daudé uint64_t offset, vsid; 486*6c568998SPhilippe Mathieu-Daudé 487*6c568998SPhilippe Mathieu-Daudé /* We only have 40 - 23 bits of seg_off in avpn */ 488*6c568998SPhilippe Mathieu-Daudé offset = (avpn & 0x1ffff) << 23; 489*6c568998SPhilippe Mathieu-Daudé vsid = avpn >> 17; 490*6c568998SPhilippe Mathieu-Daudé if (base_pg_shift < 23) { 491*6c568998SPhilippe Mathieu-Daudé offset |= ((vsid ^ (vsid << 25) ^ pteg) & old_hash_mask) 492*6c568998SPhilippe Mathieu-Daudé << base_pg_shift; 493*6c568998SPhilippe Mathieu-Daudé } 494*6c568998SPhilippe Mathieu-Daudé 495*6c568998SPhilippe Mathieu-Daudé hash = vsid ^ (vsid << 25) ^ (offset >> base_pg_shift); 496*6c568998SPhilippe Mathieu-Daudé } else { 497*6c568998SPhilippe Mathieu-Daudé error_report("rehash_pte: Bad segment size in HPTE"); 498*6c568998SPhilippe Mathieu-Daudé return H_HARDWARE; 499*6c568998SPhilippe Mathieu-Daudé } 500*6c568998SPhilippe Mathieu-Daudé 501*6c568998SPhilippe Mathieu-Daudé new_pteg = hash & new_hash_mask; 502*6c568998SPhilippe Mathieu-Daudé if (pte0 & HPTE64_V_SECONDARY) { 503*6c568998SPhilippe Mathieu-Daudé assert(~pteg == (hash & old_hash_mask)); 504*6c568998SPhilippe Mathieu-Daudé new_pteg = ~new_pteg; 505*6c568998SPhilippe Mathieu-Daudé } else { 506*6c568998SPhilippe Mathieu-Daudé assert(pteg == (hash & old_hash_mask)); 507*6c568998SPhilippe Mathieu-Daudé } 508*6c568998SPhilippe Mathieu-Daudé assert((oldsize != newsize) || (pteg == new_pteg)); 509*6c568998SPhilippe Mathieu-Daudé replace_pte0 = new_hpte_load0(new_hpt, new_pteg, slot); 510*6c568998SPhilippe Mathieu-Daudé /* 511*6c568998SPhilippe Mathieu-Daudé * Strictly speaking, we don't need all these tests, since we only 512*6c568998SPhilippe Mathieu-Daudé * ever rehash bolted HPTEs. We might in future handle non-bolted 513*6c568998SPhilippe Mathieu-Daudé * HPTEs, though so make the logic correct for those cases as 514*6c568998SPhilippe Mathieu-Daudé * well. 515*6c568998SPhilippe Mathieu-Daudé */ 516*6c568998SPhilippe Mathieu-Daudé if (replace_pte0 & HPTE64_V_VALID) { 517*6c568998SPhilippe Mathieu-Daudé assert(newsize < oldsize); 518*6c568998SPhilippe Mathieu-Daudé if (replace_pte0 & HPTE64_V_BOLTED) { 519*6c568998SPhilippe Mathieu-Daudé if (pte0 & HPTE64_V_BOLTED) { 520*6c568998SPhilippe Mathieu-Daudé /* Bolted collision, nothing we can do */ 521*6c568998SPhilippe Mathieu-Daudé return H_PTEG_FULL; 522*6c568998SPhilippe Mathieu-Daudé } else { 523*6c568998SPhilippe Mathieu-Daudé /* Discard this hpte */ 524*6c568998SPhilippe Mathieu-Daudé return H_SUCCESS; 525*6c568998SPhilippe Mathieu-Daudé } 526*6c568998SPhilippe Mathieu-Daudé } 527*6c568998SPhilippe Mathieu-Daudé } 528*6c568998SPhilippe Mathieu-Daudé 529*6c568998SPhilippe Mathieu-Daudé new_hpte_store(new_hpt, new_pteg, slot, pte0, pte1); 530*6c568998SPhilippe Mathieu-Daudé return H_SUCCESS; 531*6c568998SPhilippe Mathieu-Daudé } 532*6c568998SPhilippe Mathieu-Daudé 533*6c568998SPhilippe Mathieu-Daudé static int rehash_hpt(PowerPCCPU *cpu, 534*6c568998SPhilippe Mathieu-Daudé void *old_hpt, uint64_t oldsize, 535*6c568998SPhilippe Mathieu-Daudé void *new_hpt, uint64_t newsize) 536*6c568998SPhilippe Mathieu-Daudé { 537*6c568998SPhilippe Mathieu-Daudé uint64_t n_ptegs = oldsize >> 7; 538*6c568998SPhilippe Mathieu-Daudé uint64_t pteg; 539*6c568998SPhilippe Mathieu-Daudé int slot; 540*6c568998SPhilippe Mathieu-Daudé int rc; 541*6c568998SPhilippe Mathieu-Daudé 542*6c568998SPhilippe Mathieu-Daudé for (pteg = 0; pteg < n_ptegs; pteg++) { 543*6c568998SPhilippe Mathieu-Daudé hwaddr ptex = pteg * HPTES_PER_GROUP; 544*6c568998SPhilippe Mathieu-Daudé const ppc_hash_pte64_t *hptes 545*6c568998SPhilippe Mathieu-Daudé = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP); 546*6c568998SPhilippe Mathieu-Daudé 547*6c568998SPhilippe Mathieu-Daudé if (!hptes) { 548*6c568998SPhilippe Mathieu-Daudé return H_HARDWARE; 549*6c568998SPhilippe Mathieu-Daudé } 550*6c568998SPhilippe Mathieu-Daudé 551*6c568998SPhilippe Mathieu-Daudé for (slot = 0; slot < HPTES_PER_GROUP; slot++) { 552*6c568998SPhilippe Mathieu-Daudé rc = rehash_hpte(cpu, hptes, old_hpt, oldsize, new_hpt, newsize, 553*6c568998SPhilippe Mathieu-Daudé pteg, slot); 554*6c568998SPhilippe Mathieu-Daudé if (rc != H_SUCCESS) { 555*6c568998SPhilippe Mathieu-Daudé ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP); 556*6c568998SPhilippe Mathieu-Daudé return rc; 557*6c568998SPhilippe Mathieu-Daudé } 558*6c568998SPhilippe Mathieu-Daudé } 559*6c568998SPhilippe Mathieu-Daudé ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP); 560*6c568998SPhilippe Mathieu-Daudé } 561*6c568998SPhilippe Mathieu-Daudé 562*6c568998SPhilippe Mathieu-Daudé return H_SUCCESS; 563*6c568998SPhilippe Mathieu-Daudé } 564*6c568998SPhilippe Mathieu-Daudé 565*6c568998SPhilippe Mathieu-Daudé target_ulong vhyp_mmu_resize_hpt_commit(PowerPCCPU *cpu, 566*6c568998SPhilippe Mathieu-Daudé SpaprMachineState *spapr, 567*6c568998SPhilippe Mathieu-Daudé target_ulong flags, 568*6c568998SPhilippe Mathieu-Daudé target_ulong shift) 569*6c568998SPhilippe Mathieu-Daudé { 570*6c568998SPhilippe Mathieu-Daudé SpaprPendingHpt *pending = spapr->pending_hpt; 571*6c568998SPhilippe Mathieu-Daudé int rc; 572*6c568998SPhilippe Mathieu-Daudé size_t newsize; 573*6c568998SPhilippe Mathieu-Daudé 574*6c568998SPhilippe Mathieu-Daudé if (flags != 0) { 575*6c568998SPhilippe Mathieu-Daudé return H_PARAMETER; 576*6c568998SPhilippe Mathieu-Daudé } 577*6c568998SPhilippe Mathieu-Daudé 578*6c568998SPhilippe Mathieu-Daudé if (!pending || (pending->shift != shift)) { 579*6c568998SPhilippe Mathieu-Daudé /* no matching prepare */ 580*6c568998SPhilippe Mathieu-Daudé return H_CLOSED; 581*6c568998SPhilippe Mathieu-Daudé } 582*6c568998SPhilippe Mathieu-Daudé 583*6c568998SPhilippe Mathieu-Daudé if (!pending->complete) { 584*6c568998SPhilippe Mathieu-Daudé /* prepare has not completed */ 585*6c568998SPhilippe Mathieu-Daudé return H_BUSY; 586*6c568998SPhilippe Mathieu-Daudé } 587*6c568998SPhilippe Mathieu-Daudé 588*6c568998SPhilippe Mathieu-Daudé /* Shouldn't have got past PREPARE without an HPT */ 589*6c568998SPhilippe Mathieu-Daudé g_assert(spapr->htab_shift); 590*6c568998SPhilippe Mathieu-Daudé 591*6c568998SPhilippe Mathieu-Daudé newsize = 1ULL << pending->shift; 592*6c568998SPhilippe Mathieu-Daudé rc = rehash_hpt(cpu, spapr->htab, HTAB_SIZE(spapr), 593*6c568998SPhilippe Mathieu-Daudé pending->hpt, newsize); 594*6c568998SPhilippe Mathieu-Daudé if (rc == H_SUCCESS) { 595*6c568998SPhilippe Mathieu-Daudé qemu_vfree(spapr->htab); 596*6c568998SPhilippe Mathieu-Daudé spapr->htab = pending->hpt; 597*6c568998SPhilippe Mathieu-Daudé spapr->htab_shift = pending->shift; 598*6c568998SPhilippe Mathieu-Daudé 599*6c568998SPhilippe Mathieu-Daudé push_sregs_to_kvm_pr(spapr); 600*6c568998SPhilippe Mathieu-Daudé 601*6c568998SPhilippe Mathieu-Daudé pending->hpt = NULL; /* so it's not free()d */ 602*6c568998SPhilippe Mathieu-Daudé } 603*6c568998SPhilippe Mathieu-Daudé 604*6c568998SPhilippe Mathieu-Daudé /* Clean up */ 605*6c568998SPhilippe Mathieu-Daudé spapr->pending_hpt = NULL; 606*6c568998SPhilippe Mathieu-Daudé free_pending_hpt(pending); 607*6c568998SPhilippe Mathieu-Daudé 608*6c568998SPhilippe Mathieu-Daudé return rc; 609*6c568998SPhilippe Mathieu-Daudé } 610*6c568998SPhilippe Mathieu-Daudé 611*6c568998SPhilippe Mathieu-Daudé static void hypercall_register_types(void) 612*6c568998SPhilippe Mathieu-Daudé { 613*6c568998SPhilippe Mathieu-Daudé /* hcall-pft */ 614*6c568998SPhilippe Mathieu-Daudé spapr_register_hypercall(H_ENTER, h_enter); 615*6c568998SPhilippe Mathieu-Daudé spapr_register_hypercall(H_REMOVE, h_remove); 616*6c568998SPhilippe Mathieu-Daudé spapr_register_hypercall(H_PROTECT, h_protect); 617*6c568998SPhilippe Mathieu-Daudé spapr_register_hypercall(H_READ, h_read); 618*6c568998SPhilippe Mathieu-Daudé 619*6c568998SPhilippe Mathieu-Daudé /* hcall-bulk */ 620*6c568998SPhilippe Mathieu-Daudé spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove); 621*6c568998SPhilippe Mathieu-Daudé 622*6c568998SPhilippe Mathieu-Daudé } 623*6c568998SPhilippe Mathieu-Daudé 624*6c568998SPhilippe Mathieu-Daudé type_init(hypercall_register_types) 625