16cd1da55SPhilippe Mathieu-Daudé /* 26cd1da55SPhilippe Mathieu-Daudé * MMU hypercalls for the sPAPR (pseries) vHyp hypervisor that is used by TCG 36cd1da55SPhilippe Mathieu-Daudé * 46cd1da55SPhilippe Mathieu-Daudé * Copyright (c) 2004-2007 Fabrice Bellard 56cd1da55SPhilippe Mathieu-Daudé * Copyright (c) 2007 Jocelyn Mayer 66cd1da55SPhilippe Mathieu-Daudé * Copyright (c) 2010 David Gibson, IBM Corporation. 76cd1da55SPhilippe Mathieu-Daudé * 86cd1da55SPhilippe Mathieu-Daudé * SPDX-License-Identifier: MIT 96cd1da55SPhilippe Mathieu-Daudé */ 10962104f0SLucas Mateus Castro (alqotel) #include "qemu/osdep.h" 11962104f0SLucas Mateus Castro (alqotel) #include "qemu/cutils.h" 125df022cfSPeter Maydell #include "qemu/memalign.h" 13cc37d98bSRichard Henderson #include "qemu/error-report.h" 14962104f0SLucas Mateus Castro (alqotel) #include "cpu.h" 15962104f0SLucas Mateus Castro (alqotel) #include "helper_regs.h" 16962104f0SLucas Mateus Castro (alqotel) #include "hw/ppc/spapr.h" 17962104f0SLucas Mateus Castro (alqotel) #include "mmu-hash64.h" 18962104f0SLucas Mateus Castro (alqotel) #include "mmu-book3s-v3.h" 19962104f0SLucas Mateus Castro (alqotel) 20cc37d98bSRichard Henderson 21962104f0SLucas Mateus Castro (alqotel) static inline bool valid_ptex(PowerPCCPU *cpu, target_ulong ptex) 22962104f0SLucas Mateus Castro (alqotel) { 23962104f0SLucas Mateus Castro (alqotel) /* 24962104f0SLucas Mateus Castro (alqotel) * hash value/pteg group index is normalized by HPT mask 25962104f0SLucas Mateus Castro (alqotel) */ 26962104f0SLucas Mateus Castro (alqotel) if (((ptex & ~7ULL) / HPTES_PER_GROUP) & ~ppc_hash64_hpt_mask(cpu)) { 27962104f0SLucas Mateus Castro (alqotel) return false; 28962104f0SLucas Mateus Castro (alqotel) } 29962104f0SLucas Mateus Castro (alqotel) return true; 30962104f0SLucas Mateus Castro (alqotel) } 31962104f0SLucas Mateus Castro (alqotel) 32962104f0SLucas Mateus Castro (alqotel) static target_ulong h_enter(PowerPCCPU *cpu, SpaprMachineState *spapr, 33962104f0SLucas Mateus Castro (alqotel) target_ulong opcode, target_ulong *args) 34962104f0SLucas Mateus Castro (alqotel) { 35962104f0SLucas Mateus Castro (alqotel) target_ulong flags = args[0]; 36962104f0SLucas Mateus Castro (alqotel) target_ulong ptex = args[1]; 37962104f0SLucas Mateus Castro (alqotel) target_ulong pteh = args[2]; 38962104f0SLucas Mateus Castro (alqotel) target_ulong ptel = args[3]; 39962104f0SLucas Mateus Castro (alqotel) unsigned apshift; 40962104f0SLucas Mateus Castro (alqotel) target_ulong raddr; 41962104f0SLucas Mateus Castro (alqotel) target_ulong slot; 42962104f0SLucas Mateus Castro (alqotel) const ppc_hash_pte64_t *hptes; 43962104f0SLucas Mateus Castro (alqotel) 44962104f0SLucas Mateus Castro (alqotel) apshift = ppc_hash64_hpte_page_shift_noslb(cpu, pteh, ptel); 45962104f0SLucas Mateus Castro (alqotel) if (!apshift) { 46962104f0SLucas Mateus Castro (alqotel) /* Bad page size encoding */ 47962104f0SLucas Mateus Castro (alqotel) return H_PARAMETER; 48962104f0SLucas Mateus Castro (alqotel) } 49962104f0SLucas Mateus Castro (alqotel) 50962104f0SLucas Mateus Castro (alqotel) raddr = (ptel & HPTE64_R_RPN) & ~((1ULL << apshift) - 1); 51962104f0SLucas Mateus Castro (alqotel) 52962104f0SLucas Mateus Castro (alqotel) if (is_ram_address(spapr, raddr)) { 53962104f0SLucas Mateus Castro (alqotel) /* Regular RAM - should have WIMG=0010 */ 54962104f0SLucas Mateus Castro (alqotel) if ((ptel & HPTE64_R_WIMG) != HPTE64_R_M) { 55962104f0SLucas Mateus Castro (alqotel) return H_PARAMETER; 56962104f0SLucas Mateus Castro (alqotel) } 57962104f0SLucas Mateus Castro (alqotel) } else { 58962104f0SLucas Mateus Castro (alqotel) target_ulong wimg_flags; 59962104f0SLucas Mateus Castro (alqotel) /* Looks like an IO address */ 60962104f0SLucas Mateus Castro (alqotel) /* FIXME: What WIMG combinations could be sensible for IO? 61962104f0SLucas Mateus Castro (alqotel) * For now we allow WIMG=010x, but are there others? */ 62962104f0SLucas Mateus Castro (alqotel) /* FIXME: Should we check against registered IO addresses? */ 63962104f0SLucas Mateus Castro (alqotel) wimg_flags = (ptel & (HPTE64_R_W | HPTE64_R_I | HPTE64_R_M)); 64962104f0SLucas Mateus Castro (alqotel) 65962104f0SLucas Mateus Castro (alqotel) if (wimg_flags != HPTE64_R_I && 66962104f0SLucas Mateus Castro (alqotel) wimg_flags != (HPTE64_R_I | HPTE64_R_M)) { 67962104f0SLucas Mateus Castro (alqotel) return H_PARAMETER; 68962104f0SLucas Mateus Castro (alqotel) } 69962104f0SLucas Mateus Castro (alqotel) } 70962104f0SLucas Mateus Castro (alqotel) 71962104f0SLucas Mateus Castro (alqotel) pteh &= ~0x60ULL; 72962104f0SLucas Mateus Castro (alqotel) 73962104f0SLucas Mateus Castro (alqotel) if (!valid_ptex(cpu, ptex)) { 74962104f0SLucas Mateus Castro (alqotel) return H_PARAMETER; 75962104f0SLucas Mateus Castro (alqotel) } 76962104f0SLucas Mateus Castro (alqotel) 77962104f0SLucas Mateus Castro (alqotel) slot = ptex & 7ULL; 78962104f0SLucas Mateus Castro (alqotel) ptex = ptex & ~7ULL; 79962104f0SLucas Mateus Castro (alqotel) 80962104f0SLucas Mateus Castro (alqotel) if (likely((flags & H_EXACT) == 0)) { 81962104f0SLucas Mateus Castro (alqotel) hptes = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP); 82962104f0SLucas Mateus Castro (alqotel) for (slot = 0; slot < 8; slot++) { 83962104f0SLucas Mateus Castro (alqotel) if (!(ppc_hash64_hpte0(cpu, hptes, slot) & HPTE64_V_VALID)) { 84962104f0SLucas Mateus Castro (alqotel) break; 85962104f0SLucas Mateus Castro (alqotel) } 86962104f0SLucas Mateus Castro (alqotel) } 87962104f0SLucas Mateus Castro (alqotel) ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP); 88962104f0SLucas Mateus Castro (alqotel) if (slot == 8) { 89962104f0SLucas Mateus Castro (alqotel) return H_PTEG_FULL; 90962104f0SLucas Mateus Castro (alqotel) } 91962104f0SLucas Mateus Castro (alqotel) } else { 92962104f0SLucas Mateus Castro (alqotel) hptes = ppc_hash64_map_hptes(cpu, ptex + slot, 1); 93962104f0SLucas Mateus Castro (alqotel) if (ppc_hash64_hpte0(cpu, hptes, 0) & HPTE64_V_VALID) { 94962104f0SLucas Mateus Castro (alqotel) ppc_hash64_unmap_hptes(cpu, hptes, ptex + slot, 1); 95962104f0SLucas Mateus Castro (alqotel) return H_PTEG_FULL; 96962104f0SLucas Mateus Castro (alqotel) } 97962104f0SLucas Mateus Castro (alqotel) ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1); 98962104f0SLucas Mateus Castro (alqotel) } 99962104f0SLucas Mateus Castro (alqotel) 100962104f0SLucas Mateus Castro (alqotel) spapr_store_hpte(cpu, ptex + slot, pteh | HPTE64_V_HPTE_DIRTY, ptel); 101962104f0SLucas Mateus Castro (alqotel) 102962104f0SLucas Mateus Castro (alqotel) args[0] = ptex + slot; 103962104f0SLucas Mateus Castro (alqotel) return H_SUCCESS; 104962104f0SLucas Mateus Castro (alqotel) } 105962104f0SLucas Mateus Castro (alqotel) 106962104f0SLucas Mateus Castro (alqotel) typedef enum { 107962104f0SLucas Mateus Castro (alqotel) REMOVE_SUCCESS = 0, 108962104f0SLucas Mateus Castro (alqotel) REMOVE_NOT_FOUND = 1, 109962104f0SLucas Mateus Castro (alqotel) REMOVE_PARM = 2, 110962104f0SLucas Mateus Castro (alqotel) REMOVE_HW = 3, 111962104f0SLucas Mateus Castro (alqotel) } RemoveResult; 112962104f0SLucas Mateus Castro (alqotel) 113962104f0SLucas Mateus Castro (alqotel) static RemoveResult remove_hpte(PowerPCCPU *cpu 114962104f0SLucas Mateus Castro (alqotel) , target_ulong ptex, 115962104f0SLucas Mateus Castro (alqotel) target_ulong avpn, 116962104f0SLucas Mateus Castro (alqotel) target_ulong flags, 117962104f0SLucas Mateus Castro (alqotel) target_ulong *vp, target_ulong *rp) 118962104f0SLucas Mateus Castro (alqotel) { 119962104f0SLucas Mateus Castro (alqotel) const ppc_hash_pte64_t *hptes; 120962104f0SLucas Mateus Castro (alqotel) target_ulong v, r; 121962104f0SLucas Mateus Castro (alqotel) 122962104f0SLucas Mateus Castro (alqotel) if (!valid_ptex(cpu, ptex)) { 123962104f0SLucas Mateus Castro (alqotel) return REMOVE_PARM; 124962104f0SLucas Mateus Castro (alqotel) } 125962104f0SLucas Mateus Castro (alqotel) 126962104f0SLucas Mateus Castro (alqotel) hptes = ppc_hash64_map_hptes(cpu, ptex, 1); 127962104f0SLucas Mateus Castro (alqotel) v = ppc_hash64_hpte0(cpu, hptes, 0); 128962104f0SLucas Mateus Castro (alqotel) r = ppc_hash64_hpte1(cpu, hptes, 0); 129962104f0SLucas Mateus Castro (alqotel) ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1); 130962104f0SLucas Mateus Castro (alqotel) 131962104f0SLucas Mateus Castro (alqotel) if ((v & HPTE64_V_VALID) == 0 || 132962104f0SLucas Mateus Castro (alqotel) ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) || 133962104f0SLucas Mateus Castro (alqotel) ((flags & H_ANDCOND) && (v & avpn) != 0)) { 134962104f0SLucas Mateus Castro (alqotel) return REMOVE_NOT_FOUND; 135962104f0SLucas Mateus Castro (alqotel) } 136962104f0SLucas Mateus Castro (alqotel) *vp = v; 137962104f0SLucas Mateus Castro (alqotel) *rp = r; 138962104f0SLucas Mateus Castro (alqotel) spapr_store_hpte(cpu, ptex, HPTE64_V_HPTE_DIRTY, 0); 139962104f0SLucas Mateus Castro (alqotel) ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r); 140962104f0SLucas Mateus Castro (alqotel) return REMOVE_SUCCESS; 141962104f0SLucas Mateus Castro (alqotel) } 142962104f0SLucas Mateus Castro (alqotel) 143962104f0SLucas Mateus Castro (alqotel) static target_ulong h_remove(PowerPCCPU *cpu, SpaprMachineState *spapr, 144962104f0SLucas Mateus Castro (alqotel) target_ulong opcode, target_ulong *args) 145962104f0SLucas Mateus Castro (alqotel) { 146962104f0SLucas Mateus Castro (alqotel) CPUPPCState *env = &cpu->env; 147962104f0SLucas Mateus Castro (alqotel) target_ulong flags = args[0]; 148962104f0SLucas Mateus Castro (alqotel) target_ulong ptex = args[1]; 149962104f0SLucas Mateus Castro (alqotel) target_ulong avpn = args[2]; 150962104f0SLucas Mateus Castro (alqotel) RemoveResult ret; 151962104f0SLucas Mateus Castro (alqotel) 152962104f0SLucas Mateus Castro (alqotel) ret = remove_hpte(cpu, ptex, avpn, flags, 153962104f0SLucas Mateus Castro (alqotel) &args[0], &args[1]); 154962104f0SLucas Mateus Castro (alqotel) 155962104f0SLucas Mateus Castro (alqotel) switch (ret) { 156962104f0SLucas Mateus Castro (alqotel) case REMOVE_SUCCESS: 157962104f0SLucas Mateus Castro (alqotel) check_tlb_flush(env, true); 158962104f0SLucas Mateus Castro (alqotel) return H_SUCCESS; 159962104f0SLucas Mateus Castro (alqotel) 160962104f0SLucas Mateus Castro (alqotel) case REMOVE_NOT_FOUND: 161962104f0SLucas Mateus Castro (alqotel) return H_NOT_FOUND; 162962104f0SLucas Mateus Castro (alqotel) 163962104f0SLucas Mateus Castro (alqotel) case REMOVE_PARM: 164962104f0SLucas Mateus Castro (alqotel) return H_PARAMETER; 165962104f0SLucas Mateus Castro (alqotel) 166962104f0SLucas Mateus Castro (alqotel) case REMOVE_HW: 167962104f0SLucas Mateus Castro (alqotel) return H_HARDWARE; 168962104f0SLucas Mateus Castro (alqotel) } 169962104f0SLucas Mateus Castro (alqotel) 170962104f0SLucas Mateus Castro (alqotel) g_assert_not_reached(); 171962104f0SLucas Mateus Castro (alqotel) } 172962104f0SLucas Mateus Castro (alqotel) 173962104f0SLucas Mateus Castro (alqotel) #define H_BULK_REMOVE_TYPE 0xc000000000000000ULL 174962104f0SLucas Mateus Castro (alqotel) #define H_BULK_REMOVE_REQUEST 0x4000000000000000ULL 175962104f0SLucas Mateus Castro (alqotel) #define H_BULK_REMOVE_RESPONSE 0x8000000000000000ULL 176962104f0SLucas Mateus Castro (alqotel) #define H_BULK_REMOVE_END 0xc000000000000000ULL 177962104f0SLucas Mateus Castro (alqotel) #define H_BULK_REMOVE_CODE 0x3000000000000000ULL 178962104f0SLucas Mateus Castro (alqotel) #define H_BULK_REMOVE_SUCCESS 0x0000000000000000ULL 179962104f0SLucas Mateus Castro (alqotel) #define H_BULK_REMOVE_NOT_FOUND 0x1000000000000000ULL 180962104f0SLucas Mateus Castro (alqotel) #define H_BULK_REMOVE_PARM 0x2000000000000000ULL 181962104f0SLucas Mateus Castro (alqotel) #define H_BULK_REMOVE_HW 0x3000000000000000ULL 182962104f0SLucas Mateus Castro (alqotel) #define H_BULK_REMOVE_RC 0x0c00000000000000ULL 183962104f0SLucas Mateus Castro (alqotel) #define H_BULK_REMOVE_FLAGS 0x0300000000000000ULL 184962104f0SLucas Mateus Castro (alqotel) #define H_BULK_REMOVE_ABSOLUTE 0x0000000000000000ULL 185962104f0SLucas Mateus Castro (alqotel) #define H_BULK_REMOVE_ANDCOND 0x0100000000000000ULL 186962104f0SLucas Mateus Castro (alqotel) #define H_BULK_REMOVE_AVPN 0x0200000000000000ULL 187962104f0SLucas Mateus Castro (alqotel) #define H_BULK_REMOVE_PTEX 0x00ffffffffffffffULL 188962104f0SLucas Mateus Castro (alqotel) 189962104f0SLucas Mateus Castro (alqotel) #define H_BULK_REMOVE_MAX_BATCH 4 190962104f0SLucas Mateus Castro (alqotel) 191962104f0SLucas Mateus Castro (alqotel) static target_ulong h_bulk_remove(PowerPCCPU *cpu, SpaprMachineState *spapr, 192962104f0SLucas Mateus Castro (alqotel) target_ulong opcode, target_ulong *args) 193962104f0SLucas Mateus Castro (alqotel) { 194962104f0SLucas Mateus Castro (alqotel) CPUPPCState *env = &cpu->env; 195962104f0SLucas Mateus Castro (alqotel) int i; 196962104f0SLucas Mateus Castro (alqotel) target_ulong rc = H_SUCCESS; 197962104f0SLucas Mateus Castro (alqotel) 198962104f0SLucas Mateus Castro (alqotel) for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) { 199962104f0SLucas Mateus Castro (alqotel) target_ulong *tsh = &args[i*2]; 200962104f0SLucas Mateus Castro (alqotel) target_ulong tsl = args[i*2 + 1]; 201962104f0SLucas Mateus Castro (alqotel) target_ulong v, r, ret; 202962104f0SLucas Mateus Castro (alqotel) 203962104f0SLucas Mateus Castro (alqotel) if ((*tsh & H_BULK_REMOVE_TYPE) == H_BULK_REMOVE_END) { 204962104f0SLucas Mateus Castro (alqotel) break; 205962104f0SLucas Mateus Castro (alqotel) } else if ((*tsh & H_BULK_REMOVE_TYPE) != H_BULK_REMOVE_REQUEST) { 206962104f0SLucas Mateus Castro (alqotel) return H_PARAMETER; 207962104f0SLucas Mateus Castro (alqotel) } 208962104f0SLucas Mateus Castro (alqotel) 209962104f0SLucas Mateus Castro (alqotel) *tsh &= H_BULK_REMOVE_PTEX | H_BULK_REMOVE_FLAGS; 210962104f0SLucas Mateus Castro (alqotel) *tsh |= H_BULK_REMOVE_RESPONSE; 211962104f0SLucas Mateus Castro (alqotel) 212962104f0SLucas Mateus Castro (alqotel) if ((*tsh & H_BULK_REMOVE_ANDCOND) && (*tsh & H_BULK_REMOVE_AVPN)) { 213962104f0SLucas Mateus Castro (alqotel) *tsh |= H_BULK_REMOVE_PARM; 214962104f0SLucas Mateus Castro (alqotel) return H_PARAMETER; 215962104f0SLucas Mateus Castro (alqotel) } 216962104f0SLucas Mateus Castro (alqotel) 217962104f0SLucas Mateus Castro (alqotel) ret = remove_hpte(cpu, *tsh & H_BULK_REMOVE_PTEX, tsl, 218962104f0SLucas Mateus Castro (alqotel) (*tsh & H_BULK_REMOVE_FLAGS) >> 26, 219962104f0SLucas Mateus Castro (alqotel) &v, &r); 220962104f0SLucas Mateus Castro (alqotel) 221962104f0SLucas Mateus Castro (alqotel) *tsh |= ret << 60; 222962104f0SLucas Mateus Castro (alqotel) 223962104f0SLucas Mateus Castro (alqotel) switch (ret) { 224962104f0SLucas Mateus Castro (alqotel) case REMOVE_SUCCESS: 225962104f0SLucas Mateus Castro (alqotel) *tsh |= (r & (HPTE64_R_C | HPTE64_R_R)) << 43; 226962104f0SLucas Mateus Castro (alqotel) break; 227962104f0SLucas Mateus Castro (alqotel) 228962104f0SLucas Mateus Castro (alqotel) case REMOVE_PARM: 229962104f0SLucas Mateus Castro (alqotel) rc = H_PARAMETER; 230962104f0SLucas Mateus Castro (alqotel) goto exit; 231962104f0SLucas Mateus Castro (alqotel) 232962104f0SLucas Mateus Castro (alqotel) case REMOVE_HW: 233962104f0SLucas Mateus Castro (alqotel) rc = H_HARDWARE; 234962104f0SLucas Mateus Castro (alqotel) goto exit; 235962104f0SLucas Mateus Castro (alqotel) } 236962104f0SLucas Mateus Castro (alqotel) } 237962104f0SLucas Mateus Castro (alqotel) exit: 238962104f0SLucas Mateus Castro (alqotel) check_tlb_flush(env, true); 239962104f0SLucas Mateus Castro (alqotel) 240962104f0SLucas Mateus Castro (alqotel) return rc; 241962104f0SLucas Mateus Castro (alqotel) } 242962104f0SLucas Mateus Castro (alqotel) 243962104f0SLucas Mateus Castro (alqotel) static target_ulong h_protect(PowerPCCPU *cpu, SpaprMachineState *spapr, 244962104f0SLucas Mateus Castro (alqotel) target_ulong opcode, target_ulong *args) 245962104f0SLucas Mateus Castro (alqotel) { 246962104f0SLucas Mateus Castro (alqotel) CPUPPCState *env = &cpu->env; 247962104f0SLucas Mateus Castro (alqotel) target_ulong flags = args[0]; 248962104f0SLucas Mateus Castro (alqotel) target_ulong ptex = args[1]; 249962104f0SLucas Mateus Castro (alqotel) target_ulong avpn = args[2]; 250962104f0SLucas Mateus Castro (alqotel) const ppc_hash_pte64_t *hptes; 251962104f0SLucas Mateus Castro (alqotel) target_ulong v, r; 252962104f0SLucas Mateus Castro (alqotel) 253962104f0SLucas Mateus Castro (alqotel) if (!valid_ptex(cpu, ptex)) { 254962104f0SLucas Mateus Castro (alqotel) return H_PARAMETER; 255962104f0SLucas Mateus Castro (alqotel) } 256962104f0SLucas Mateus Castro (alqotel) 257962104f0SLucas Mateus Castro (alqotel) hptes = ppc_hash64_map_hptes(cpu, ptex, 1); 258962104f0SLucas Mateus Castro (alqotel) v = ppc_hash64_hpte0(cpu, hptes, 0); 259962104f0SLucas Mateus Castro (alqotel) r = ppc_hash64_hpte1(cpu, hptes, 0); 260962104f0SLucas Mateus Castro (alqotel) ppc_hash64_unmap_hptes(cpu, hptes, ptex, 1); 261962104f0SLucas Mateus Castro (alqotel) 262962104f0SLucas Mateus Castro (alqotel) if ((v & HPTE64_V_VALID) == 0 || 263962104f0SLucas Mateus Castro (alqotel) ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) { 264962104f0SLucas Mateus Castro (alqotel) return H_NOT_FOUND; 265962104f0SLucas Mateus Castro (alqotel) } 266962104f0SLucas Mateus Castro (alqotel) 267962104f0SLucas Mateus Castro (alqotel) r &= ~(HPTE64_R_PP0 | HPTE64_R_PP | HPTE64_R_N | 268962104f0SLucas Mateus Castro (alqotel) HPTE64_R_KEY_HI | HPTE64_R_KEY_LO); 269962104f0SLucas Mateus Castro (alqotel) r |= (flags << 55) & HPTE64_R_PP0; 270962104f0SLucas Mateus Castro (alqotel) r |= (flags << 48) & HPTE64_R_KEY_HI; 271962104f0SLucas Mateus Castro (alqotel) r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO); 272962104f0SLucas Mateus Castro (alqotel) spapr_store_hpte(cpu, ptex, 273962104f0SLucas Mateus Castro (alqotel) (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY, 0); 274962104f0SLucas Mateus Castro (alqotel) ppc_hash64_tlb_flush_hpte(cpu, ptex, v, r); 275962104f0SLucas Mateus Castro (alqotel) /* Flush the tlb */ 276962104f0SLucas Mateus Castro (alqotel) check_tlb_flush(env, true); 277962104f0SLucas Mateus Castro (alqotel) /* Don't need a memory barrier, due to qemu's global lock */ 278962104f0SLucas Mateus Castro (alqotel) spapr_store_hpte(cpu, ptex, v | HPTE64_V_HPTE_DIRTY, r); 279962104f0SLucas Mateus Castro (alqotel) return H_SUCCESS; 280962104f0SLucas Mateus Castro (alqotel) } 281962104f0SLucas Mateus Castro (alqotel) 282962104f0SLucas Mateus Castro (alqotel) static target_ulong h_read(PowerPCCPU *cpu, SpaprMachineState *spapr, 283962104f0SLucas Mateus Castro (alqotel) target_ulong opcode, target_ulong *args) 284962104f0SLucas Mateus Castro (alqotel) { 285962104f0SLucas Mateus Castro (alqotel) target_ulong flags = args[0]; 286962104f0SLucas Mateus Castro (alqotel) target_ulong ptex = args[1]; 287962104f0SLucas Mateus Castro (alqotel) int i, ridx, n_entries = 1; 288962104f0SLucas Mateus Castro (alqotel) const ppc_hash_pte64_t *hptes; 289962104f0SLucas Mateus Castro (alqotel) 290962104f0SLucas Mateus Castro (alqotel) if (!valid_ptex(cpu, ptex)) { 291962104f0SLucas Mateus Castro (alqotel) return H_PARAMETER; 292962104f0SLucas Mateus Castro (alqotel) } 293962104f0SLucas Mateus Castro (alqotel) 294962104f0SLucas Mateus Castro (alqotel) if (flags & H_READ_4) { 295962104f0SLucas Mateus Castro (alqotel) /* Clear the two low order bits */ 296962104f0SLucas Mateus Castro (alqotel) ptex &= ~(3ULL); 297962104f0SLucas Mateus Castro (alqotel) n_entries = 4; 298962104f0SLucas Mateus Castro (alqotel) } 299962104f0SLucas Mateus Castro (alqotel) 300962104f0SLucas Mateus Castro (alqotel) hptes = ppc_hash64_map_hptes(cpu, ptex, n_entries); 301962104f0SLucas Mateus Castro (alqotel) for (i = 0, ridx = 0; i < n_entries; i++) { 302962104f0SLucas Mateus Castro (alqotel) args[ridx++] = ppc_hash64_hpte0(cpu, hptes, i); 303962104f0SLucas Mateus Castro (alqotel) args[ridx++] = ppc_hash64_hpte1(cpu, hptes, i); 304962104f0SLucas Mateus Castro (alqotel) } 305962104f0SLucas Mateus Castro (alqotel) ppc_hash64_unmap_hptes(cpu, hptes, ptex, n_entries); 306962104f0SLucas Mateus Castro (alqotel) 307962104f0SLucas Mateus Castro (alqotel) return H_SUCCESS; 308962104f0SLucas Mateus Castro (alqotel) } 309962104f0SLucas Mateus Castro (alqotel) 310962104f0SLucas Mateus Castro (alqotel) struct SpaprPendingHpt { 311962104f0SLucas Mateus Castro (alqotel) /* These fields are read-only after initialization */ 312962104f0SLucas Mateus Castro (alqotel) int shift; 313962104f0SLucas Mateus Castro (alqotel) QemuThread thread; 314962104f0SLucas Mateus Castro (alqotel) 315962104f0SLucas Mateus Castro (alqotel) /* These fields are protected by the BQL */ 316962104f0SLucas Mateus Castro (alqotel) bool complete; 317962104f0SLucas Mateus Castro (alqotel) 318962104f0SLucas Mateus Castro (alqotel) /* These fields are private to the preparation thread if 319962104f0SLucas Mateus Castro (alqotel) * !complete, otherwise protected by the BQL */ 320962104f0SLucas Mateus Castro (alqotel) int ret; 321962104f0SLucas Mateus Castro (alqotel) void *hpt; 322962104f0SLucas Mateus Castro (alqotel) }; 323962104f0SLucas Mateus Castro (alqotel) 324962104f0SLucas Mateus Castro (alqotel) static void free_pending_hpt(SpaprPendingHpt *pending) 325962104f0SLucas Mateus Castro (alqotel) { 326962104f0SLucas Mateus Castro (alqotel) if (pending->hpt) { 327962104f0SLucas Mateus Castro (alqotel) qemu_vfree(pending->hpt); 328962104f0SLucas Mateus Castro (alqotel) } 329962104f0SLucas Mateus Castro (alqotel) 330962104f0SLucas Mateus Castro (alqotel) g_free(pending); 331962104f0SLucas Mateus Castro (alqotel) } 332962104f0SLucas Mateus Castro (alqotel) 333962104f0SLucas Mateus Castro (alqotel) static void *hpt_prepare_thread(void *opaque) 334962104f0SLucas Mateus Castro (alqotel) { 335962104f0SLucas Mateus Castro (alqotel) SpaprPendingHpt *pending = opaque; 336962104f0SLucas Mateus Castro (alqotel) size_t size = 1ULL << pending->shift; 337962104f0SLucas Mateus Castro (alqotel) 338962104f0SLucas Mateus Castro (alqotel) pending->hpt = qemu_try_memalign(size, size); 339962104f0SLucas Mateus Castro (alqotel) if (pending->hpt) { 340962104f0SLucas Mateus Castro (alqotel) memset(pending->hpt, 0, size); 341962104f0SLucas Mateus Castro (alqotel) pending->ret = H_SUCCESS; 342962104f0SLucas Mateus Castro (alqotel) } else { 343962104f0SLucas Mateus Castro (alqotel) pending->ret = H_NO_MEM; 344962104f0SLucas Mateus Castro (alqotel) } 345962104f0SLucas Mateus Castro (alqotel) 346195801d7SStefan Hajnoczi bql_lock(); 347962104f0SLucas Mateus Castro (alqotel) 348962104f0SLucas Mateus Castro (alqotel) if (SPAPR_MACHINE(qdev_get_machine())->pending_hpt == pending) { 349962104f0SLucas Mateus Castro (alqotel) /* Ready to go */ 350962104f0SLucas Mateus Castro (alqotel) pending->complete = true; 351962104f0SLucas Mateus Castro (alqotel) } else { 352962104f0SLucas Mateus Castro (alqotel) /* We've been cancelled, clean ourselves up */ 353962104f0SLucas Mateus Castro (alqotel) free_pending_hpt(pending); 354962104f0SLucas Mateus Castro (alqotel) } 355962104f0SLucas Mateus Castro (alqotel) 356195801d7SStefan Hajnoczi bql_unlock(); 357962104f0SLucas Mateus Castro (alqotel) return NULL; 358962104f0SLucas Mateus Castro (alqotel) } 359962104f0SLucas Mateus Castro (alqotel) 360962104f0SLucas Mateus Castro (alqotel) /* Must be called with BQL held */ 361962104f0SLucas Mateus Castro (alqotel) static void cancel_hpt_prepare(SpaprMachineState *spapr) 362962104f0SLucas Mateus Castro (alqotel) { 363962104f0SLucas Mateus Castro (alqotel) SpaprPendingHpt *pending = spapr->pending_hpt; 364962104f0SLucas Mateus Castro (alqotel) 365962104f0SLucas Mateus Castro (alqotel) /* Let the thread know it's cancelled */ 366962104f0SLucas Mateus Castro (alqotel) spapr->pending_hpt = NULL; 367962104f0SLucas Mateus Castro (alqotel) 368962104f0SLucas Mateus Castro (alqotel) if (!pending) { 369962104f0SLucas Mateus Castro (alqotel) /* Nothing to do */ 370962104f0SLucas Mateus Castro (alqotel) return; 371962104f0SLucas Mateus Castro (alqotel) } 372962104f0SLucas Mateus Castro (alqotel) 373962104f0SLucas Mateus Castro (alqotel) if (!pending->complete) { 374962104f0SLucas Mateus Castro (alqotel) /* thread will clean itself up */ 375962104f0SLucas Mateus Castro (alqotel) return; 376962104f0SLucas Mateus Castro (alqotel) } 377962104f0SLucas Mateus Castro (alqotel) 378962104f0SLucas Mateus Castro (alqotel) free_pending_hpt(pending); 379962104f0SLucas Mateus Castro (alqotel) } 380962104f0SLucas Mateus Castro (alqotel) 381*a3d0cf82SPhilippe Mathieu-Daudé target_ulong vhyp_mmu_resize_hpt_prepare(PowerPCCPU *cpu, 382962104f0SLucas Mateus Castro (alqotel) SpaprMachineState *spapr, 383962104f0SLucas Mateus Castro (alqotel) target_ulong shift) 384962104f0SLucas Mateus Castro (alqotel) { 385962104f0SLucas Mateus Castro (alqotel) SpaprPendingHpt *pending = spapr->pending_hpt; 386962104f0SLucas Mateus Castro (alqotel) 387962104f0SLucas Mateus Castro (alqotel) if (pending) { 388962104f0SLucas Mateus Castro (alqotel) /* something already in progress */ 389962104f0SLucas Mateus Castro (alqotel) if (pending->shift == shift) { 390962104f0SLucas Mateus Castro (alqotel) /* and it's suitable */ 391962104f0SLucas Mateus Castro (alqotel) if (pending->complete) { 392962104f0SLucas Mateus Castro (alqotel) return pending->ret; 393962104f0SLucas Mateus Castro (alqotel) } else { 394962104f0SLucas Mateus Castro (alqotel) return H_LONG_BUSY_ORDER_100_MSEC; 395962104f0SLucas Mateus Castro (alqotel) } 396962104f0SLucas Mateus Castro (alqotel) } 397962104f0SLucas Mateus Castro (alqotel) 398962104f0SLucas Mateus Castro (alqotel) /* not suitable, cancel and replace */ 399962104f0SLucas Mateus Castro (alqotel) cancel_hpt_prepare(spapr); 400962104f0SLucas Mateus Castro (alqotel) } 401962104f0SLucas Mateus Castro (alqotel) 402962104f0SLucas Mateus Castro (alqotel) if (!shift) { 403962104f0SLucas Mateus Castro (alqotel) /* nothing to do */ 404962104f0SLucas Mateus Castro (alqotel) return H_SUCCESS; 405962104f0SLucas Mateus Castro (alqotel) } 406962104f0SLucas Mateus Castro (alqotel) 407962104f0SLucas Mateus Castro (alqotel) /* start new prepare */ 408962104f0SLucas Mateus Castro (alqotel) 409962104f0SLucas Mateus Castro (alqotel) pending = g_new0(SpaprPendingHpt, 1); 410962104f0SLucas Mateus Castro (alqotel) pending->shift = shift; 411962104f0SLucas Mateus Castro (alqotel) pending->ret = H_HARDWARE; 412962104f0SLucas Mateus Castro (alqotel) 413962104f0SLucas Mateus Castro (alqotel) qemu_thread_create(&pending->thread, "sPAPR HPT prepare", 414962104f0SLucas Mateus Castro (alqotel) hpt_prepare_thread, pending, QEMU_THREAD_DETACHED); 415962104f0SLucas Mateus Castro (alqotel) 416962104f0SLucas Mateus Castro (alqotel) spapr->pending_hpt = pending; 417962104f0SLucas Mateus Castro (alqotel) 418962104f0SLucas Mateus Castro (alqotel) /* In theory we could estimate the time more accurately based on 419962104f0SLucas Mateus Castro (alqotel) * the new size, but there's not much point */ 420962104f0SLucas Mateus Castro (alqotel) return H_LONG_BUSY_ORDER_100_MSEC; 421962104f0SLucas Mateus Castro (alqotel) } 422962104f0SLucas Mateus Castro (alqotel) 423962104f0SLucas Mateus Castro (alqotel) static uint64_t new_hpte_load0(void *htab, uint64_t pteg, int slot) 424962104f0SLucas Mateus Castro (alqotel) { 425962104f0SLucas Mateus Castro (alqotel) uint8_t *addr = htab; 426962104f0SLucas Mateus Castro (alqotel) 427962104f0SLucas Mateus Castro (alqotel) addr += pteg * HASH_PTEG_SIZE_64; 428962104f0SLucas Mateus Castro (alqotel) addr += slot * HASH_PTE_SIZE_64; 429962104f0SLucas Mateus Castro (alqotel) return ldq_p(addr); 430962104f0SLucas Mateus Castro (alqotel) } 431962104f0SLucas Mateus Castro (alqotel) 432962104f0SLucas Mateus Castro (alqotel) static void new_hpte_store(void *htab, uint64_t pteg, int slot, 433962104f0SLucas Mateus Castro (alqotel) uint64_t pte0, uint64_t pte1) 434962104f0SLucas Mateus Castro (alqotel) { 435962104f0SLucas Mateus Castro (alqotel) uint8_t *addr = htab; 436962104f0SLucas Mateus Castro (alqotel) 437962104f0SLucas Mateus Castro (alqotel) addr += pteg * HASH_PTEG_SIZE_64; 438962104f0SLucas Mateus Castro (alqotel) addr += slot * HASH_PTE_SIZE_64; 439962104f0SLucas Mateus Castro (alqotel) 440962104f0SLucas Mateus Castro (alqotel) stq_p(addr, pte0); 4417bf00dfbSLeandro Lupori stq_p(addr + HPTE64_DW1, pte1); 442962104f0SLucas Mateus Castro (alqotel) } 443962104f0SLucas Mateus Castro (alqotel) 444962104f0SLucas Mateus Castro (alqotel) static int rehash_hpte(PowerPCCPU *cpu, 445962104f0SLucas Mateus Castro (alqotel) const ppc_hash_pte64_t *hptes, 446962104f0SLucas Mateus Castro (alqotel) void *old_hpt, uint64_t oldsize, 447962104f0SLucas Mateus Castro (alqotel) void *new_hpt, uint64_t newsize, 448962104f0SLucas Mateus Castro (alqotel) uint64_t pteg, int slot) 449962104f0SLucas Mateus Castro (alqotel) { 450962104f0SLucas Mateus Castro (alqotel) uint64_t old_hash_mask = (oldsize >> 7) - 1; 451962104f0SLucas Mateus Castro (alqotel) uint64_t new_hash_mask = (newsize >> 7) - 1; 452962104f0SLucas Mateus Castro (alqotel) target_ulong pte0 = ppc_hash64_hpte0(cpu, hptes, slot); 453962104f0SLucas Mateus Castro (alqotel) target_ulong pte1; 454962104f0SLucas Mateus Castro (alqotel) uint64_t avpn; 455962104f0SLucas Mateus Castro (alqotel) unsigned base_pg_shift; 456962104f0SLucas Mateus Castro (alqotel) uint64_t hash, new_pteg, replace_pte0; 457962104f0SLucas Mateus Castro (alqotel) 458962104f0SLucas Mateus Castro (alqotel) if (!(pte0 & HPTE64_V_VALID) || !(pte0 & HPTE64_V_BOLTED)) { 459962104f0SLucas Mateus Castro (alqotel) return H_SUCCESS; 460962104f0SLucas Mateus Castro (alqotel) } 461962104f0SLucas Mateus Castro (alqotel) 462962104f0SLucas Mateus Castro (alqotel) pte1 = ppc_hash64_hpte1(cpu, hptes, slot); 463962104f0SLucas Mateus Castro (alqotel) 464962104f0SLucas Mateus Castro (alqotel) base_pg_shift = ppc_hash64_hpte_page_shift_noslb(cpu, pte0, pte1); 465962104f0SLucas Mateus Castro (alqotel) assert(base_pg_shift); /* H_ENTER shouldn't allow a bad encoding */ 466962104f0SLucas Mateus Castro (alqotel) avpn = HPTE64_V_AVPN_VAL(pte0) & ~(((1ULL << base_pg_shift) - 1) >> 23); 467962104f0SLucas Mateus Castro (alqotel) 468962104f0SLucas Mateus Castro (alqotel) if (pte0 & HPTE64_V_SECONDARY) { 469962104f0SLucas Mateus Castro (alqotel) pteg = ~pteg; 470962104f0SLucas Mateus Castro (alqotel) } 471962104f0SLucas Mateus Castro (alqotel) 472962104f0SLucas Mateus Castro (alqotel) if ((pte0 & HPTE64_V_SSIZE) == HPTE64_V_SSIZE_256M) { 473962104f0SLucas Mateus Castro (alqotel) uint64_t offset, vsid; 474962104f0SLucas Mateus Castro (alqotel) 475962104f0SLucas Mateus Castro (alqotel) /* We only have 28 - 23 bits of offset in avpn */ 476962104f0SLucas Mateus Castro (alqotel) offset = (avpn & 0x1f) << 23; 477962104f0SLucas Mateus Castro (alqotel) vsid = avpn >> 5; 478962104f0SLucas Mateus Castro (alqotel) /* We can find more bits from the pteg value */ 479962104f0SLucas Mateus Castro (alqotel) if (base_pg_shift < 23) { 480962104f0SLucas Mateus Castro (alqotel) offset |= ((vsid ^ pteg) & old_hash_mask) << base_pg_shift; 481962104f0SLucas Mateus Castro (alqotel) } 482962104f0SLucas Mateus Castro (alqotel) 483962104f0SLucas Mateus Castro (alqotel) hash = vsid ^ (offset >> base_pg_shift); 484962104f0SLucas Mateus Castro (alqotel) } else if ((pte0 & HPTE64_V_SSIZE) == HPTE64_V_SSIZE_1T) { 485962104f0SLucas Mateus Castro (alqotel) uint64_t offset, vsid; 486962104f0SLucas Mateus Castro (alqotel) 487962104f0SLucas Mateus Castro (alqotel) /* We only have 40 - 23 bits of seg_off in avpn */ 488962104f0SLucas Mateus Castro (alqotel) offset = (avpn & 0x1ffff) << 23; 489962104f0SLucas Mateus Castro (alqotel) vsid = avpn >> 17; 490962104f0SLucas Mateus Castro (alqotel) if (base_pg_shift < 23) { 491962104f0SLucas Mateus Castro (alqotel) offset |= ((vsid ^ (vsid << 25) ^ pteg) & old_hash_mask) 492962104f0SLucas Mateus Castro (alqotel) << base_pg_shift; 493962104f0SLucas Mateus Castro (alqotel) } 494962104f0SLucas Mateus Castro (alqotel) 495962104f0SLucas Mateus Castro (alqotel) hash = vsid ^ (vsid << 25) ^ (offset >> base_pg_shift); 496962104f0SLucas Mateus Castro (alqotel) } else { 497962104f0SLucas Mateus Castro (alqotel) error_report("rehash_pte: Bad segment size in HPTE"); 498962104f0SLucas Mateus Castro (alqotel) return H_HARDWARE; 499962104f0SLucas Mateus Castro (alqotel) } 500962104f0SLucas Mateus Castro (alqotel) 501962104f0SLucas Mateus Castro (alqotel) new_pteg = hash & new_hash_mask; 502962104f0SLucas Mateus Castro (alqotel) if (pte0 & HPTE64_V_SECONDARY) { 503962104f0SLucas Mateus Castro (alqotel) assert(~pteg == (hash & old_hash_mask)); 504962104f0SLucas Mateus Castro (alqotel) new_pteg = ~new_pteg; 505962104f0SLucas Mateus Castro (alqotel) } else { 506962104f0SLucas Mateus Castro (alqotel) assert(pteg == (hash & old_hash_mask)); 507962104f0SLucas Mateus Castro (alqotel) } 508962104f0SLucas Mateus Castro (alqotel) assert((oldsize != newsize) || (pteg == new_pteg)); 509962104f0SLucas Mateus Castro (alqotel) replace_pte0 = new_hpte_load0(new_hpt, new_pteg, slot); 510962104f0SLucas Mateus Castro (alqotel) /* 511962104f0SLucas Mateus Castro (alqotel) * Strictly speaking, we don't need all these tests, since we only 512962104f0SLucas Mateus Castro (alqotel) * ever rehash bolted HPTEs. We might in future handle non-bolted 513962104f0SLucas Mateus Castro (alqotel) * HPTEs, though so make the logic correct for those cases as 514962104f0SLucas Mateus Castro (alqotel) * well. 515962104f0SLucas Mateus Castro (alqotel) */ 516962104f0SLucas Mateus Castro (alqotel) if (replace_pte0 & HPTE64_V_VALID) { 517962104f0SLucas Mateus Castro (alqotel) assert(newsize < oldsize); 518962104f0SLucas Mateus Castro (alqotel) if (replace_pte0 & HPTE64_V_BOLTED) { 519962104f0SLucas Mateus Castro (alqotel) if (pte0 & HPTE64_V_BOLTED) { 520962104f0SLucas Mateus Castro (alqotel) /* Bolted collision, nothing we can do */ 521962104f0SLucas Mateus Castro (alqotel) return H_PTEG_FULL; 522962104f0SLucas Mateus Castro (alqotel) } else { 523962104f0SLucas Mateus Castro (alqotel) /* Discard this hpte */ 524962104f0SLucas Mateus Castro (alqotel) return H_SUCCESS; 525962104f0SLucas Mateus Castro (alqotel) } 526962104f0SLucas Mateus Castro (alqotel) } 527962104f0SLucas Mateus Castro (alqotel) } 528962104f0SLucas Mateus Castro (alqotel) 529962104f0SLucas Mateus Castro (alqotel) new_hpte_store(new_hpt, new_pteg, slot, pte0, pte1); 530962104f0SLucas Mateus Castro (alqotel) return H_SUCCESS; 531962104f0SLucas Mateus Castro (alqotel) } 532962104f0SLucas Mateus Castro (alqotel) 533962104f0SLucas Mateus Castro (alqotel) static int rehash_hpt(PowerPCCPU *cpu, 534962104f0SLucas Mateus Castro (alqotel) void *old_hpt, uint64_t oldsize, 535962104f0SLucas Mateus Castro (alqotel) void *new_hpt, uint64_t newsize) 536962104f0SLucas Mateus Castro (alqotel) { 537962104f0SLucas Mateus Castro (alqotel) uint64_t n_ptegs = oldsize >> 7; 538962104f0SLucas Mateus Castro (alqotel) uint64_t pteg; 539962104f0SLucas Mateus Castro (alqotel) int slot; 540962104f0SLucas Mateus Castro (alqotel) int rc; 541962104f0SLucas Mateus Castro (alqotel) 542962104f0SLucas Mateus Castro (alqotel) for (pteg = 0; pteg < n_ptegs; pteg++) { 543962104f0SLucas Mateus Castro (alqotel) hwaddr ptex = pteg * HPTES_PER_GROUP; 544962104f0SLucas Mateus Castro (alqotel) const ppc_hash_pte64_t *hptes 545962104f0SLucas Mateus Castro (alqotel) = ppc_hash64_map_hptes(cpu, ptex, HPTES_PER_GROUP); 546962104f0SLucas Mateus Castro (alqotel) 547962104f0SLucas Mateus Castro (alqotel) if (!hptes) { 548962104f0SLucas Mateus Castro (alqotel) return H_HARDWARE; 549962104f0SLucas Mateus Castro (alqotel) } 550962104f0SLucas Mateus Castro (alqotel) 551962104f0SLucas Mateus Castro (alqotel) for (slot = 0; slot < HPTES_PER_GROUP; slot++) { 552962104f0SLucas Mateus Castro (alqotel) rc = rehash_hpte(cpu, hptes, old_hpt, oldsize, new_hpt, newsize, 553962104f0SLucas Mateus Castro (alqotel) pteg, slot); 554962104f0SLucas Mateus Castro (alqotel) if (rc != H_SUCCESS) { 555962104f0SLucas Mateus Castro (alqotel) ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP); 556962104f0SLucas Mateus Castro (alqotel) return rc; 557962104f0SLucas Mateus Castro (alqotel) } 558962104f0SLucas Mateus Castro (alqotel) } 559962104f0SLucas Mateus Castro (alqotel) ppc_hash64_unmap_hptes(cpu, hptes, ptex, HPTES_PER_GROUP); 560962104f0SLucas Mateus Castro (alqotel) } 561962104f0SLucas Mateus Castro (alqotel) 562962104f0SLucas Mateus Castro (alqotel) return H_SUCCESS; 563962104f0SLucas Mateus Castro (alqotel) } 564962104f0SLucas Mateus Castro (alqotel) 565*a3d0cf82SPhilippe Mathieu-Daudé target_ulong vhyp_mmu_resize_hpt_commit(PowerPCCPU *cpu, 566962104f0SLucas Mateus Castro (alqotel) SpaprMachineState *spapr, 567962104f0SLucas Mateus Castro (alqotel) target_ulong flags, 568962104f0SLucas Mateus Castro (alqotel) target_ulong shift) 569962104f0SLucas Mateus Castro (alqotel) { 570962104f0SLucas Mateus Castro (alqotel) SpaprPendingHpt *pending = spapr->pending_hpt; 571962104f0SLucas Mateus Castro (alqotel) int rc; 572962104f0SLucas Mateus Castro (alqotel) size_t newsize; 573962104f0SLucas Mateus Castro (alqotel) 574962104f0SLucas Mateus Castro (alqotel) if (flags != 0) { 575962104f0SLucas Mateus Castro (alqotel) return H_PARAMETER; 576962104f0SLucas Mateus Castro (alqotel) } 577962104f0SLucas Mateus Castro (alqotel) 578962104f0SLucas Mateus Castro (alqotel) if (!pending || (pending->shift != shift)) { 579962104f0SLucas Mateus Castro (alqotel) /* no matching prepare */ 580962104f0SLucas Mateus Castro (alqotel) return H_CLOSED; 581962104f0SLucas Mateus Castro (alqotel) } 582962104f0SLucas Mateus Castro (alqotel) 583962104f0SLucas Mateus Castro (alqotel) if (!pending->complete) { 584962104f0SLucas Mateus Castro (alqotel) /* prepare has not completed */ 585962104f0SLucas Mateus Castro (alqotel) return H_BUSY; 586962104f0SLucas Mateus Castro (alqotel) } 587962104f0SLucas Mateus Castro (alqotel) 588962104f0SLucas Mateus Castro (alqotel) /* Shouldn't have got past PREPARE without an HPT */ 589962104f0SLucas Mateus Castro (alqotel) g_assert(spapr->htab_shift); 590962104f0SLucas Mateus Castro (alqotel) 591962104f0SLucas Mateus Castro (alqotel) newsize = 1ULL << pending->shift; 592962104f0SLucas Mateus Castro (alqotel) rc = rehash_hpt(cpu, spapr->htab, HTAB_SIZE(spapr), 593962104f0SLucas Mateus Castro (alqotel) pending->hpt, newsize); 594962104f0SLucas Mateus Castro (alqotel) if (rc == H_SUCCESS) { 595962104f0SLucas Mateus Castro (alqotel) qemu_vfree(spapr->htab); 596962104f0SLucas Mateus Castro (alqotel) spapr->htab = pending->hpt; 597962104f0SLucas Mateus Castro (alqotel) spapr->htab_shift = pending->shift; 598962104f0SLucas Mateus Castro (alqotel) 599962104f0SLucas Mateus Castro (alqotel) push_sregs_to_kvm_pr(spapr); 600962104f0SLucas Mateus Castro (alqotel) 601962104f0SLucas Mateus Castro (alqotel) pending->hpt = NULL; /* so it's not free()d */ 602962104f0SLucas Mateus Castro (alqotel) } 603962104f0SLucas Mateus Castro (alqotel) 604962104f0SLucas Mateus Castro (alqotel) /* Clean up */ 605962104f0SLucas Mateus Castro (alqotel) spapr->pending_hpt = NULL; 606962104f0SLucas Mateus Castro (alqotel) free_pending_hpt(pending); 607962104f0SLucas Mateus Castro (alqotel) 608962104f0SLucas Mateus Castro (alqotel) return rc; 609962104f0SLucas Mateus Castro (alqotel) } 610962104f0SLucas Mateus Castro (alqotel) 611962104f0SLucas Mateus Castro (alqotel) static void hypercall_register_types(void) 612962104f0SLucas Mateus Castro (alqotel) { 613962104f0SLucas Mateus Castro (alqotel) /* hcall-pft */ 614962104f0SLucas Mateus Castro (alqotel) spapr_register_hypercall(H_ENTER, h_enter); 615962104f0SLucas Mateus Castro (alqotel) spapr_register_hypercall(H_REMOVE, h_remove); 616962104f0SLucas Mateus Castro (alqotel) spapr_register_hypercall(H_PROTECT, h_protect); 617962104f0SLucas Mateus Castro (alqotel) spapr_register_hypercall(H_READ, h_read); 618962104f0SLucas Mateus Castro (alqotel) 619962104f0SLucas Mateus Castro (alqotel) /* hcall-bulk */ 620962104f0SLucas Mateus Castro (alqotel) spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove); 621962104f0SLucas Mateus Castro (alqotel) 622962104f0SLucas Mateus Castro (alqotel) } 623962104f0SLucas Mateus Castro (alqotel) 624962104f0SLucas Mateus Castro (alqotel) type_init(hypercall_register_types) 625