1#include "sysemu/sysemu.h"
2#include "cpu.h"
3#include "helper_regs.h"
4#include "hw/ppc/spapr.h"
5#include "mmu-hash64.h"
6
7struct SPRSyncState {
8 CPUState *cs;
9 int spr;
10 target_ulong value;
11 target_ulong mask;
12};
13
14static void do_spr_sync(void *arg)
15{
16 struct SPRSyncState *s = arg;
17 PowerPCCPU *cpu = POWERPC_CPU(s->cs);
18 CPUPPCState *env = &cpu->env;
19
20 cpu_synchronize_state(s->cs);
21 env->spr[s->spr] &= ~s->mask;
22 env->spr[s->spr] |= s->value;
23}
24
25static void set_spr(CPUState *cs, int spr, target_ulong value,
26 target_ulong mask)
27{
28 struct SPRSyncState s = {
29 .cs = cs,
30 .spr = spr,
31 .value = value,
32 .mask = mask
33 };
34 run_on_cpu(cs, do_spr_sync, &s);
35}
36
37static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,
38 target_ulong pte_index)
39{
40 target_ulong rb, va_low;
41
42 rb = (v & ~0x7fULL) << 16;
43 va_low = pte_index >> 3;
44 if (v & HPTE64_V_SECONDARY) {
45 va_low = ~va_low;
46 }
47
48 if (!(v & HPTE64_V_1TB_SEG)) {
49 va_low ^= v >> 12;
50 } else {
51 va_low ^= v >> 24;
52 }
53 va_low &= 0x7ff;
54 if (v & HPTE64_V_LARGE) {
55 rb |= 1;
56#if 0
57 if (r & 0xff000) {
58
59
60 rb |= 0x1000;
61 rb |= (va_low & 0x7f) << 16;
62 rb |= (va_low & 0xfe);
63 }
64#endif
65 } else {
66
67 rb |= (va_low & 0x7ff) << 12;
68 }
69 rb |= (v >> 54) & 0x300;
70 return rb;
71}
72
73static inline bool valid_pte_index(CPUPPCState *env, target_ulong pte_index)
74{
75
76
77
78 if (((pte_index & ~7ULL) / HPTES_PER_GROUP) & ~env->htab_mask) {
79 return false;
80 }
81 return true;
82}
83
84static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
85 target_ulong opcode, target_ulong *args)
86{
87 CPUPPCState *env = &cpu->env;
88 target_ulong flags = args[0];
89 target_ulong pte_index = args[1];
90 target_ulong pteh = args[2];
91 target_ulong ptel = args[3];
92 target_ulong page_shift = 12;
93 target_ulong raddr;
94 target_ulong index;
95 uint64_t token;
96
97
98 if (pteh & HPTE64_V_LARGE) {
99#if 0
100 if ((ptel & 0xf000) == 0x1000) {
101
102 } else
103#endif
104 if ((ptel & 0xff000) == 0) {
105
106 page_shift = 24;
107
108 if (pteh & 0x80) {
109 return H_PARAMETER;
110 }
111 } else {
112 return H_PARAMETER;
113 }
114 }
115
116 raddr = (ptel & HPTE64_R_RPN) & ~((1ULL << page_shift) - 1);
117
118 if (raddr < spapr->ram_limit) {
119
120 if ((ptel & HPTE64_R_WIMG) != HPTE64_R_M) {
121 return H_PARAMETER;
122 }
123 } else {
124
125
126
127
128 if ((ptel & (HPTE64_R_W | HPTE64_R_I | HPTE64_R_M)) != HPTE64_R_I) {
129 return H_PARAMETER;
130 }
131 }
132
133 pteh &= ~0x60ULL;
134
135 if (!valid_pte_index(env, pte_index)) {
136 return H_PARAMETER;
137 }
138
139 index = 0;
140 if (likely((flags & H_EXACT) == 0)) {
141 pte_index &= ~7ULL;
142 token = ppc_hash64_start_access(cpu, pte_index);
143 for (; index < 8; index++) {
144 if ((ppc_hash64_load_hpte0(env, token, index) & HPTE64_V_VALID) == 0) {
145 break;
146 }
147 }
148 ppc_hash64_stop_access(token);
149 if (index == 8) {
150 return H_PTEG_FULL;
151 }
152 } else {
153 token = ppc_hash64_start_access(cpu, pte_index);
154 if (ppc_hash64_load_hpte0(env, token, 0) & HPTE64_V_VALID) {
155 ppc_hash64_stop_access(token);
156 return H_PTEG_FULL;
157 }
158 ppc_hash64_stop_access(token);
159 }
160
161 ppc_hash64_store_hpte(env, pte_index + index,
162 pteh | HPTE64_V_HPTE_DIRTY, ptel);
163
164 args[0] = pte_index + index;
165 return H_SUCCESS;
166}
167
168typedef enum {
169 REMOVE_SUCCESS = 0,
170 REMOVE_NOT_FOUND = 1,
171 REMOVE_PARM = 2,
172 REMOVE_HW = 3,
173} RemoveResult;
174
175static RemoveResult remove_hpte(CPUPPCState *env, target_ulong ptex,
176 target_ulong avpn,
177 target_ulong flags,
178 target_ulong *vp, target_ulong *rp)
179{
180 uint64_t token;
181 target_ulong v, r, rb;
182
183 if (!valid_pte_index(env, ptex)) {
184 return REMOVE_PARM;
185 }
186
187 token = ppc_hash64_start_access(ppc_env_get_cpu(env), ptex);
188 v = ppc_hash64_load_hpte0(env, token, 0);
189 r = ppc_hash64_load_hpte1(env, token, 0);
190 ppc_hash64_stop_access(token);
191
192 if ((v & HPTE64_V_VALID) == 0 ||
193 ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
194 ((flags & H_ANDCOND) && (v & avpn) != 0)) {
195 return REMOVE_NOT_FOUND;
196 }
197 *vp = v;
198 *rp = r;
199 ppc_hash64_store_hpte(env, ptex, HPTE64_V_HPTE_DIRTY, 0);
200 rb = compute_tlbie_rb(v, r, ptex);
201 ppc_tlb_invalidate_one(env, rb);
202 return REMOVE_SUCCESS;
203}
204
205static target_ulong h_remove(PowerPCCPU *cpu, sPAPREnvironment *spapr,
206 target_ulong opcode, target_ulong *args)
207{
208 CPUPPCState *env = &cpu->env;
209 target_ulong flags = args[0];
210 target_ulong pte_index = args[1];
211 target_ulong avpn = args[2];
212 RemoveResult ret;
213
214 ret = remove_hpte(env, pte_index, avpn, flags,
215 &args[0], &args[1]);
216
217 switch (ret) {
218 case REMOVE_SUCCESS:
219 return H_SUCCESS;
220
221 case REMOVE_NOT_FOUND:
222 return H_NOT_FOUND;
223
224 case REMOVE_PARM:
225 return H_PARAMETER;
226
227 case REMOVE_HW:
228 return H_HARDWARE;
229 }
230
231 g_assert_not_reached();
232}
233
234#define H_BULK_REMOVE_TYPE 0xc000000000000000ULL
235#define H_BULK_REMOVE_REQUEST 0x4000000000000000ULL
236#define H_BULK_REMOVE_RESPONSE 0x8000000000000000ULL
237#define H_BULK_REMOVE_END 0xc000000000000000ULL
238#define H_BULK_REMOVE_CODE 0x3000000000000000ULL
239#define H_BULK_REMOVE_SUCCESS 0x0000000000000000ULL
240#define H_BULK_REMOVE_NOT_FOUND 0x1000000000000000ULL
241#define H_BULK_REMOVE_PARM 0x2000000000000000ULL
242#define H_BULK_REMOVE_HW 0x3000000000000000ULL
243#define H_BULK_REMOVE_RC 0x0c00000000000000ULL
244#define H_BULK_REMOVE_FLAGS 0x0300000000000000ULL
245#define H_BULK_REMOVE_ABSOLUTE 0x0000000000000000ULL
246#define H_BULK_REMOVE_ANDCOND 0x0100000000000000ULL
247#define H_BULK_REMOVE_AVPN 0x0200000000000000ULL
248#define H_BULK_REMOVE_PTEX 0x00ffffffffffffffULL
249
250#define H_BULK_REMOVE_MAX_BATCH 4
251
252static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPREnvironment *spapr,
253 target_ulong opcode, target_ulong *args)
254{
255 CPUPPCState *env = &cpu->env;
256 int i;
257
258 for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) {
259 target_ulong *tsh = &args[i*2];
260 target_ulong tsl = args[i*2 + 1];
261 target_ulong v, r, ret;
262
263 if ((*tsh & H_BULK_REMOVE_TYPE) == H_BULK_REMOVE_END) {
264 break;
265 } else if ((*tsh & H_BULK_REMOVE_TYPE) != H_BULK_REMOVE_REQUEST) {
266 return H_PARAMETER;
267 }
268
269 *tsh &= H_BULK_REMOVE_PTEX | H_BULK_REMOVE_FLAGS;
270 *tsh |= H_BULK_REMOVE_RESPONSE;
271
272 if ((*tsh & H_BULK_REMOVE_ANDCOND) && (*tsh & H_BULK_REMOVE_AVPN)) {
273 *tsh |= H_BULK_REMOVE_PARM;
274 return H_PARAMETER;
275 }
276
277 ret = remove_hpte(env, *tsh & H_BULK_REMOVE_PTEX, tsl,
278 (*tsh & H_BULK_REMOVE_FLAGS) >> 26,
279 &v, &r);
280
281 *tsh |= ret << 60;
282
283 switch (ret) {
284 case REMOVE_SUCCESS:
285 *tsh |= (r & (HPTE64_R_C | HPTE64_R_R)) << 43;
286 break;
287
288 case REMOVE_PARM:
289 return H_PARAMETER;
290
291 case REMOVE_HW:
292 return H_HARDWARE;
293 }
294 }
295
296 return H_SUCCESS;
297}
298
299static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr,
300 target_ulong opcode, target_ulong *args)
301{
302 CPUPPCState *env = &cpu->env;
303 target_ulong flags = args[0];
304 target_ulong pte_index = args[1];
305 target_ulong avpn = args[2];
306 uint64_t token;
307 target_ulong v, r, rb;
308
309 if (!valid_pte_index(env, pte_index)) {
310 return H_PARAMETER;
311 }
312
313 token = ppc_hash64_start_access(cpu, pte_index);
314 v = ppc_hash64_load_hpte0(env, token, 0);
315 r = ppc_hash64_load_hpte1(env, token, 0);
316 ppc_hash64_stop_access(token);
317
318 if ((v & HPTE64_V_VALID) == 0 ||
319 ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
320 return H_NOT_FOUND;
321 }
322
323 r &= ~(HPTE64_R_PP0 | HPTE64_R_PP | HPTE64_R_N |
324 HPTE64_R_KEY_HI | HPTE64_R_KEY_LO);
325 r |= (flags << 55) & HPTE64_R_PP0;
326 r |= (flags << 48) & HPTE64_R_KEY_HI;
327 r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO);
328 rb = compute_tlbie_rb(v, r, pte_index);
329 ppc_hash64_store_hpte(env, pte_index,
330 (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY, 0);
331 ppc_tlb_invalidate_one(env, rb);
332
333 ppc_hash64_store_hpte(env, pte_index, v | HPTE64_V_HPTE_DIRTY, r);
334 return H_SUCCESS;
335}
336
337static target_ulong h_read(PowerPCCPU *cpu, sPAPREnvironment *spapr,
338 target_ulong opcode, target_ulong *args)
339{
340 CPUPPCState *env = &cpu->env;
341 target_ulong flags = args[0];
342 target_ulong pte_index = args[1];
343 uint8_t *hpte;
344 int i, ridx, n_entries = 1;
345
346 if (!valid_pte_index(env, pte_index)) {
347 return H_PARAMETER;
348 }
349
350 if (flags & H_READ_4) {
351
352 pte_index &= ~(3ULL);
353 n_entries = 4;
354 }
355
356 hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
357
358 for (i = 0, ridx = 0; i < n_entries; i++) {
359 args[ridx++] = ldq_p(hpte);
360 args[ridx++] = ldq_p(hpte + (HASH_PTE_SIZE_64/2));
361 hpte += HASH_PTE_SIZE_64;
362 }
363
364 return H_SUCCESS;
365}
366
367static target_ulong h_set_dabr(PowerPCCPU *cpu, sPAPREnvironment *spapr,
368 target_ulong opcode, target_ulong *args)
369{
370
371 return H_HARDWARE;
372}
373
374#define FLAGS_REGISTER_VPA 0x0000200000000000ULL
375#define FLAGS_REGISTER_DTL 0x0000400000000000ULL
376#define FLAGS_REGISTER_SLBSHADOW 0x0000600000000000ULL
377#define FLAGS_DEREGISTER_VPA 0x0000a00000000000ULL
378#define FLAGS_DEREGISTER_DTL 0x0000c00000000000ULL
379#define FLAGS_DEREGISTER_SLBSHADOW 0x0000e00000000000ULL
380
381#define VPA_MIN_SIZE 640
382#define VPA_SIZE_OFFSET 0x4
383#define VPA_SHARED_PROC_OFFSET 0x9
384#define VPA_SHARED_PROC_VAL 0x2
385
386static target_ulong register_vpa(CPUPPCState *env, target_ulong vpa)
387{
388 CPUState *cs = CPU(ppc_env_get_cpu(env));
389 uint16_t size;
390 uint8_t tmp;
391
392 if (vpa == 0) {
393 hcall_dprintf("Can't cope with registering a VPA at logical 0\n");
394 return H_HARDWARE;
395 }
396
397 if (vpa % env->dcache_line_size) {
398 return H_PARAMETER;
399 }
400
401
402 size = lduw_be_phys(cs->as, vpa + 0x4);
403
404 if (size < VPA_MIN_SIZE) {
405 return H_PARAMETER;
406 }
407
408
409 if ((vpa / 4096) != ((vpa + size - 1) / 4096)) {
410 return H_PARAMETER;
411 }
412
413 env->vpa_addr = vpa;
414
415 tmp = ldub_phys(cs->as, env->vpa_addr + VPA_SHARED_PROC_OFFSET);
416 tmp |= VPA_SHARED_PROC_VAL;
417 stb_phys(cs->as, env->vpa_addr + VPA_SHARED_PROC_OFFSET, tmp);
418
419 return H_SUCCESS;
420}
421
422static target_ulong deregister_vpa(CPUPPCState *env, target_ulong vpa)
423{
424 if (env->slb_shadow_addr) {
425 return H_RESOURCE;
426 }
427
428 if (env->dtl_addr) {
429 return H_RESOURCE;
430 }
431
432 env->vpa_addr = 0;
433 return H_SUCCESS;
434}
435
436static target_ulong register_slb_shadow(CPUPPCState *env, target_ulong addr)
437{
438 CPUState *cs = CPU(ppc_env_get_cpu(env));
439 uint32_t size;
440
441 if (addr == 0) {
442 hcall_dprintf("Can't cope with SLB shadow at logical 0\n");
443 return H_HARDWARE;
444 }
445
446 size = ldl_be_phys(cs->as, addr + 0x4);
447 if (size < 0x8) {
448 return H_PARAMETER;
449 }
450
451 if ((addr / 4096) != ((addr + size - 1) / 4096)) {
452 return H_PARAMETER;
453 }
454
455 if (!env->vpa_addr) {
456 return H_RESOURCE;
457 }
458
459 env->slb_shadow_addr = addr;
460 env->slb_shadow_size = size;
461
462 return H_SUCCESS;
463}
464
465static target_ulong deregister_slb_shadow(CPUPPCState *env, target_ulong addr)
466{
467 env->slb_shadow_addr = 0;
468 env->slb_shadow_size = 0;
469 return H_SUCCESS;
470}
471
472static target_ulong register_dtl(CPUPPCState *env, target_ulong addr)
473{
474 CPUState *cs = CPU(ppc_env_get_cpu(env));
475 uint32_t size;
476
477 if (addr == 0) {
478 hcall_dprintf("Can't cope with DTL at logical 0\n");
479 return H_HARDWARE;
480 }
481
482 size = ldl_be_phys(cs->as, addr + 0x4);
483
484 if (size < 48) {
485 return H_PARAMETER;
486 }
487
488 if (!env->vpa_addr) {
489 return H_RESOURCE;
490 }
491
492 env->dtl_addr = addr;
493 env->dtl_size = size;
494
495 return H_SUCCESS;
496}
497
498static target_ulong deregister_dtl(CPUPPCState *env, target_ulong addr)
499{
500 env->dtl_addr = 0;
501 env->dtl_size = 0;
502
503 return H_SUCCESS;
504}
505
506static target_ulong h_register_vpa(PowerPCCPU *cpu, sPAPREnvironment *spapr,
507 target_ulong opcode, target_ulong *args)
508{
509 target_ulong flags = args[0];
510 target_ulong procno = args[1];
511 target_ulong vpa = args[2];
512 target_ulong ret = H_PARAMETER;
513 CPUPPCState *tenv;
514 PowerPCCPU *tcpu;
515
516 tcpu = ppc_get_vcpu_by_dt_id(procno);
517 if (!tcpu) {
518 return H_PARAMETER;
519 }
520 tenv = &tcpu->env;
521
522 switch (flags) {
523 case FLAGS_REGISTER_VPA:
524 ret = register_vpa(tenv, vpa);
525 break;
526
527 case FLAGS_DEREGISTER_VPA:
528 ret = deregister_vpa(tenv, vpa);
529 break;
530
531 case FLAGS_REGISTER_SLBSHADOW:
532 ret = register_slb_shadow(tenv, vpa);
533 break;
534
535 case FLAGS_DEREGISTER_SLBSHADOW:
536 ret = deregister_slb_shadow(tenv, vpa);
537 break;
538
539 case FLAGS_REGISTER_DTL:
540 ret = register_dtl(tenv, vpa);
541 break;
542
543 case FLAGS_DEREGISTER_DTL:
544 ret = deregister_dtl(tenv, vpa);
545 break;
546 }
547
548 return ret;
549}
550
551static target_ulong h_cede(PowerPCCPU *cpu, sPAPREnvironment *spapr,
552 target_ulong opcode, target_ulong *args)
553{
554 CPUPPCState *env = &cpu->env;
555 CPUState *cs = CPU(cpu);
556
557 env->msr |= (1ULL << MSR_EE);
558 hreg_compute_hflags(env);
559 if (!cpu_has_work(cs)) {
560 cs->halted = 1;
561 cs->exception_index = EXCP_HLT;
562 cs->exit_request = 1;
563 }
564 return H_SUCCESS;
565}
566
567static target_ulong h_rtas(PowerPCCPU *cpu, sPAPREnvironment *spapr,
568 target_ulong opcode, target_ulong *args)
569{
570 target_ulong rtas_r3 = args[0];
571 uint32_t token = rtas_ld(rtas_r3, 0);
572 uint32_t nargs = rtas_ld(rtas_r3, 1);
573 uint32_t nret = rtas_ld(rtas_r3, 2);
574
575 return spapr_rtas_call(cpu, spapr, token, nargs, rtas_r3 + 12,
576 nret, rtas_r3 + 12 + 4*nargs);
577}
578
579static target_ulong h_logical_load(PowerPCCPU *cpu, sPAPREnvironment *spapr,
580 target_ulong opcode, target_ulong *args)
581{
582 CPUState *cs = CPU(cpu);
583 target_ulong size = args[0];
584 target_ulong addr = args[1];
585
586 switch (size) {
587 case 1:
588 args[0] = ldub_phys(cs->as, addr);
589 return H_SUCCESS;
590 case 2:
591 args[0] = lduw_phys(cs->as, addr);
592 return H_SUCCESS;
593 case 4:
594 args[0] = ldl_phys(cs->as, addr);
595 return H_SUCCESS;
596 case 8:
597 args[0] = ldq_phys(cs->as, addr);
598 return H_SUCCESS;
599 }
600 return H_PARAMETER;
601}
602
603static target_ulong h_logical_store(PowerPCCPU *cpu, sPAPREnvironment *spapr,
604 target_ulong opcode, target_ulong *args)
605{
606 CPUState *cs = CPU(cpu);
607
608 target_ulong size = args[0];
609 target_ulong addr = args[1];
610 target_ulong val = args[2];
611
612 switch (size) {
613 case 1:
614 stb_phys(cs->as, addr, val);
615 return H_SUCCESS;
616 case 2:
617 stw_phys(cs->as, addr, val);
618 return H_SUCCESS;
619 case 4:
620 stl_phys(cs->as, addr, val);
621 return H_SUCCESS;
622 case 8:
623 stq_phys(cs->as, addr, val);
624 return H_SUCCESS;
625 }
626 return H_PARAMETER;
627}
628
629static target_ulong h_logical_memop(PowerPCCPU *cpu, sPAPREnvironment *spapr,
630 target_ulong opcode, target_ulong *args)
631{
632 CPUState *cs = CPU(cpu);
633
634 target_ulong dst = args[0];
635 target_ulong src = args[1];
636 target_ulong esize = args[2];
637 target_ulong count = args[3];
638 target_ulong op = args[4];
639 uint64_t tmp;
640 unsigned int mask = (1 << esize) - 1;
641 int step = 1 << esize;
642
643 if (count > 0x80000000) {
644 return H_PARAMETER;
645 }
646
647 if ((dst & mask) || (src & mask) || (op > 1)) {
648 return H_PARAMETER;
649 }
650
651 if (dst >= src && dst < (src + (count << esize))) {
652 dst = dst + ((count - 1) << esize);
653 src = src + ((count - 1) << esize);
654 step = -step;
655 }
656
657 while (count--) {
658 switch (esize) {
659 case 0:
660 tmp = ldub_phys(cs->as, src);
661 break;
662 case 1:
663 tmp = lduw_phys(cs->as, src);
664 break;
665 case 2:
666 tmp = ldl_phys(cs->as, src);
667 break;
668 case 3:
669 tmp = ldq_phys(cs->as, src);
670 break;
671 default:
672 return H_PARAMETER;
673 }
674 if (op == 1) {
675 tmp = ~tmp;
676 }
677 switch (esize) {
678 case 0:
679 stb_phys(cs->as, dst, tmp);
680 break;
681 case 1:
682 stw_phys(cs->as, dst, tmp);
683 break;
684 case 2:
685 stl_phys(cs->as, dst, tmp);
686 break;
687 case 3:
688 stq_phys(cs->as, dst, tmp);
689 break;
690 }
691 dst = dst + step;
692 src = src + step;
693 }
694
695 return H_SUCCESS;
696}
697
698static target_ulong h_logical_icbi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
699 target_ulong opcode, target_ulong *args)
700{
701
702 return H_SUCCESS;
703}
704
705static target_ulong h_logical_dcbf(PowerPCCPU *cpu, sPAPREnvironment *spapr,
706 target_ulong opcode, target_ulong *args)
707{
708
709 return H_SUCCESS;
710}
711
712static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPREnvironment *spapr,
713 target_ulong opcode, target_ulong *args)
714{
715 CPUState *cs;
716 target_ulong mflags = args[0];
717 target_ulong resource = args[1];
718 target_ulong value1 = args[2];
719 target_ulong value2 = args[3];
720 target_ulong ret = H_P2;
721
722 if (resource == H_SET_MODE_RESOURCE_LE) {
723 if (value1) {
724 ret = H_P3;
725 goto out;
726 }
727 if (value2) {
728 ret = H_P4;
729 goto out;
730 }
731 switch (mflags) {
732 case H_SET_MODE_ENDIAN_BIG:
733 CPU_FOREACH(cs) {
734 set_spr(cs, SPR_LPCR, 0, LPCR_ILE);
735 }
736 ret = H_SUCCESS;
737 break;
738
739 case H_SET_MODE_ENDIAN_LITTLE:
740 CPU_FOREACH(cs) {
741 set_spr(cs, SPR_LPCR, LPCR_ILE, LPCR_ILE);
742 }
743 ret = H_SUCCESS;
744 break;
745
746 default:
747 ret = H_UNSUPPORTED_FLAG;
748 }
749 }
750
751out:
752 return ret;
753}
754
755static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
756static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1];
757
758void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn)
759{
760 spapr_hcall_fn *slot;
761
762 if (opcode <= MAX_HCALL_OPCODE) {
763 assert((opcode & 0x3) == 0);
764
765 slot = &papr_hypercall_table[opcode / 4];
766 } else {
767 assert((opcode >= KVMPPC_HCALL_BASE) && (opcode <= KVMPPC_HCALL_MAX));
768
769 slot = &kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
770 }
771
772 assert(!(*slot));
773 *slot = fn;
774}
775
776target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
777 target_ulong *args)
778{
779 if ((opcode <= MAX_HCALL_OPCODE)
780 && ((opcode & 0x3) == 0)) {
781 spapr_hcall_fn fn = papr_hypercall_table[opcode / 4];
782
783 if (fn) {
784 return fn(cpu, spapr, opcode, args);
785 }
786 } else if ((opcode >= KVMPPC_HCALL_BASE) &&
787 (opcode <= KVMPPC_HCALL_MAX)) {
788 spapr_hcall_fn fn = kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
789
790 if (fn) {
791 return fn(cpu, spapr, opcode, args);
792 }
793 }
794
795 hcall_dprintf("Unimplemented hcall 0x" TARGET_FMT_lx "\n", opcode);
796 return H_FUNCTION;
797}
798
799static void hypercall_register_types(void)
800{
801
802 spapr_register_hypercall(H_ENTER, h_enter);
803 spapr_register_hypercall(H_REMOVE, h_remove);
804 spapr_register_hypercall(H_PROTECT, h_protect);
805 spapr_register_hypercall(H_READ, h_read);
806
807
808 spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove);
809
810
811 spapr_register_hypercall(H_SET_DABR, h_set_dabr);
812
813
814 spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa);
815 spapr_register_hypercall(H_CEDE, h_cede);
816
817
818
819
820
821
822 spapr_register_hypercall(H_LOGICAL_CI_LOAD, h_logical_load);
823 spapr_register_hypercall(H_LOGICAL_CI_STORE, h_logical_store);
824 spapr_register_hypercall(H_LOGICAL_CACHE_LOAD, h_logical_load);
825 spapr_register_hypercall(H_LOGICAL_CACHE_STORE, h_logical_store);
826 spapr_register_hypercall(H_LOGICAL_ICBI, h_logical_icbi);
827 spapr_register_hypercall(H_LOGICAL_DCBF, h_logical_dcbf);
828 spapr_register_hypercall(KVMPPC_H_LOGICAL_MEMOP, h_logical_memop);
829
830
831 spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);
832
833 spapr_register_hypercall(H_SET_MODE, h_set_mode);
834}
835
836type_init(hypercall_register_types)
837