xref: /openbmc/qemu/hw/ppc/spapr_vhyp_mmu.c (revision 6c568998)
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