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