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