xref: /qemu/hw/ppc/spapr_hcall.c (revision 9f64bd8a)
1 #include "sysemu/sysemu.h"
2 #include "cpu.h"
3 #include "sysemu/sysemu.h"
4 #include "helper_regs.h"
5 #include "hw/spapr.h"
6 
7 #define HPTES_PER_GROUP 8
8 
9 #define HPTE_V_SSIZE_SHIFT      62
10 #define HPTE_V_AVPN_SHIFT       7
11 #define HPTE_V_AVPN             0x3fffffffffffff80ULL
12 #define HPTE_V_AVPN_VAL(x)      (((x) & HPTE_V_AVPN) >> HPTE_V_AVPN_SHIFT)
13 #define HPTE_V_COMPARE(x, y)    (!(((x) ^ (y)) & 0xffffffffffffff80UL))
14 #define HPTE_V_BOLTED           0x0000000000000010ULL
15 #define HPTE_V_LOCK             0x0000000000000008ULL
16 #define HPTE_V_LARGE            0x0000000000000004ULL
17 #define HPTE_V_SECONDARY        0x0000000000000002ULL
18 #define HPTE_V_VALID            0x0000000000000001ULL
19 
20 #define HPTE_R_PP0              0x8000000000000000ULL
21 #define HPTE_R_TS               0x4000000000000000ULL
22 #define HPTE_R_KEY_HI           0x3000000000000000ULL
23 #define HPTE_R_RPN_SHIFT        12
24 #define HPTE_R_RPN              0x3ffffffffffff000ULL
25 #define HPTE_R_FLAGS            0x00000000000003ffULL
26 #define HPTE_R_PP               0x0000000000000003ULL
27 #define HPTE_R_N                0x0000000000000004ULL
28 #define HPTE_R_G                0x0000000000000008ULL
29 #define HPTE_R_M                0x0000000000000010ULL
30 #define HPTE_R_I                0x0000000000000020ULL
31 #define HPTE_R_W                0x0000000000000040ULL
32 #define HPTE_R_WIMG             0x0000000000000078ULL
33 #define HPTE_R_C                0x0000000000000080ULL
34 #define HPTE_R_R                0x0000000000000100ULL
35 #define HPTE_R_KEY_LO           0x0000000000000e00ULL
36 
37 #define HPTE_V_1TB_SEG          0x4000000000000000ULL
38 #define HPTE_V_VRMA_MASK        0x4001ffffff000000ULL
39 
40 static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,
41                                      target_ulong pte_index)
42 {
43     target_ulong rb, va_low;
44 
45     rb = (v & ~0x7fULL) << 16; /* AVA field */
46     va_low = pte_index >> 3;
47     if (v & HPTE_V_SECONDARY) {
48         va_low = ~va_low;
49     }
50     /* xor vsid from AVA */
51     if (!(v & HPTE_V_1TB_SEG)) {
52         va_low ^= v >> 12;
53     } else {
54         va_low ^= v >> 24;
55     }
56     va_low &= 0x7ff;
57     if (v & HPTE_V_LARGE) {
58         rb |= 1;                         /* L field */
59 #if 0 /* Disable that P7 specific bit for now */
60         if (r & 0xff000) {
61             /* non-16MB large page, must be 64k */
62             /* (masks depend on page size) */
63             rb |= 0x1000;                /* page encoding in LP field */
64             rb |= (va_low & 0x7f) << 16; /* 7b of VA in AVA/LP field */
65             rb |= (va_low & 0xfe);       /* AVAL field */
66         }
67 #endif
68     } else {
69         /* 4kB page */
70         rb |= (va_low & 0x7ff) << 12;   /* remaining 11b of AVA */
71     }
72     rb |= (v >> 54) & 0x300;            /* B field */
73     return rb;
74 }
75 
76 static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
77                             target_ulong opcode, target_ulong *args)
78 {
79     CPUPPCState *env = &cpu->env;
80     target_ulong flags = args[0];
81     target_ulong pte_index = args[1];
82     target_ulong pteh = args[2];
83     target_ulong ptel = args[3];
84     target_ulong page_shift = 12;
85     target_ulong raddr;
86     target_ulong i;
87     uint8_t *hpte;
88 
89     /* only handle 4k and 16M pages for now */
90     if (pteh & HPTE_V_LARGE) {
91 #if 0 /* We don't support 64k pages yet */
92         if ((ptel & 0xf000) == 0x1000) {
93             /* 64k page */
94         } else
95 #endif
96         if ((ptel & 0xff000) == 0) {
97             /* 16M page */
98             page_shift = 24;
99             /* lowest AVA bit must be 0 for 16M pages */
100             if (pteh & 0x80) {
101                 return H_PARAMETER;
102             }
103         } else {
104             return H_PARAMETER;
105         }
106     }
107 
108     raddr = (ptel & HPTE_R_RPN) & ~((1ULL << page_shift) - 1);
109 
110     if (raddr < spapr->ram_limit) {
111         /* Regular RAM - should have WIMG=0010 */
112         if ((ptel & HPTE_R_WIMG) != HPTE_R_M) {
113             return H_PARAMETER;
114         }
115     } else {
116         /* Looks like an IO address */
117         /* FIXME: What WIMG combinations could be sensible for IO?
118          * For now we allow WIMG=010x, but are there others? */
119         /* FIXME: Should we check against registered IO addresses? */
120         if ((ptel & (HPTE_R_W | HPTE_R_I | HPTE_R_M)) != HPTE_R_I) {
121             return H_PARAMETER;
122         }
123     }
124 
125     pteh &= ~0x60ULL;
126 
127     if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
128         return H_PARAMETER;
129     }
130     if (likely((flags & H_EXACT) == 0)) {
131         pte_index &= ~7ULL;
132         hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
133         for (i = 0; ; ++i) {
134             if (i == 8) {
135                 return H_PTEG_FULL;
136             }
137             if ((ldq_p(hpte) & HPTE_V_VALID) == 0) {
138                 break;
139             }
140             hpte += HASH_PTE_SIZE_64;
141         }
142     } else {
143         i = 0;
144         hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
145         if (ldq_p(hpte) & HPTE_V_VALID) {
146             return H_PTEG_FULL;
147         }
148     }
149     stq_p(hpte + (HASH_PTE_SIZE_64/2), ptel);
150     /* eieio();  FIXME: need some sort of barrier for smp? */
151     stq_p(hpte, pteh);
152 
153     args[0] = pte_index + i;
154     return H_SUCCESS;
155 }
156 
157 enum {
158     REMOVE_SUCCESS = 0,
159     REMOVE_NOT_FOUND = 1,
160     REMOVE_PARM = 2,
161     REMOVE_HW = 3,
162 };
163 
164 static target_ulong remove_hpte(CPUPPCState *env, target_ulong ptex,
165                                 target_ulong avpn,
166                                 target_ulong flags,
167                                 target_ulong *vp, target_ulong *rp)
168 {
169     uint8_t *hpte;
170     target_ulong v, r, rb;
171 
172     if ((ptex * HASH_PTE_SIZE_64) & ~env->htab_mask) {
173         return REMOVE_PARM;
174     }
175 
176     hpte = env->external_htab + (ptex * HASH_PTE_SIZE_64);
177 
178     v = ldq_p(hpte);
179     r = ldq_p(hpte + (HASH_PTE_SIZE_64/2));
180 
181     if ((v & HPTE_V_VALID) == 0 ||
182         ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
183         ((flags & H_ANDCOND) && (v & avpn) != 0)) {
184         return REMOVE_NOT_FOUND;
185     }
186     *vp = v;
187     *rp = r;
188     stq_p(hpte, 0);
189     rb = compute_tlbie_rb(v, r, ptex);
190     ppc_tlb_invalidate_one(env, rb);
191     return REMOVE_SUCCESS;
192 }
193 
194 static target_ulong h_remove(PowerPCCPU *cpu, sPAPREnvironment *spapr,
195                              target_ulong opcode, target_ulong *args)
196 {
197     CPUPPCState *env = &cpu->env;
198     target_ulong flags = args[0];
199     target_ulong pte_index = args[1];
200     target_ulong avpn = args[2];
201     int ret;
202 
203     ret = remove_hpte(env, pte_index, avpn, flags,
204                       &args[0], &args[1]);
205 
206     switch (ret) {
207     case REMOVE_SUCCESS:
208         return H_SUCCESS;
209 
210     case REMOVE_NOT_FOUND:
211         return H_NOT_FOUND;
212 
213     case REMOVE_PARM:
214         return H_PARAMETER;
215 
216     case REMOVE_HW:
217         return H_HARDWARE;
218     }
219 
220     assert(0);
221 }
222 
223 #define H_BULK_REMOVE_TYPE             0xc000000000000000ULL
224 #define   H_BULK_REMOVE_REQUEST        0x4000000000000000ULL
225 #define   H_BULK_REMOVE_RESPONSE       0x8000000000000000ULL
226 #define   H_BULK_REMOVE_END            0xc000000000000000ULL
227 #define H_BULK_REMOVE_CODE             0x3000000000000000ULL
228 #define   H_BULK_REMOVE_SUCCESS        0x0000000000000000ULL
229 #define   H_BULK_REMOVE_NOT_FOUND      0x1000000000000000ULL
230 #define   H_BULK_REMOVE_PARM           0x2000000000000000ULL
231 #define   H_BULK_REMOVE_HW             0x3000000000000000ULL
232 #define H_BULK_REMOVE_RC               0x0c00000000000000ULL
233 #define H_BULK_REMOVE_FLAGS            0x0300000000000000ULL
234 #define   H_BULK_REMOVE_ABSOLUTE       0x0000000000000000ULL
235 #define   H_BULK_REMOVE_ANDCOND        0x0100000000000000ULL
236 #define   H_BULK_REMOVE_AVPN           0x0200000000000000ULL
237 #define H_BULK_REMOVE_PTEX             0x00ffffffffffffffULL
238 
239 #define H_BULK_REMOVE_MAX_BATCH        4
240 
241 static target_ulong h_bulk_remove(PowerPCCPU *cpu, sPAPREnvironment *spapr,
242                                   target_ulong opcode, target_ulong *args)
243 {
244     CPUPPCState *env = &cpu->env;
245     int i;
246 
247     for (i = 0; i < H_BULK_REMOVE_MAX_BATCH; i++) {
248         target_ulong *tsh = &args[i*2];
249         target_ulong tsl = args[i*2 + 1];
250         target_ulong v, r, ret;
251 
252         if ((*tsh & H_BULK_REMOVE_TYPE) == H_BULK_REMOVE_END) {
253             break;
254         } else if ((*tsh & H_BULK_REMOVE_TYPE) != H_BULK_REMOVE_REQUEST) {
255             return H_PARAMETER;
256         }
257 
258         *tsh &= H_BULK_REMOVE_PTEX | H_BULK_REMOVE_FLAGS;
259         *tsh |= H_BULK_REMOVE_RESPONSE;
260 
261         if ((*tsh & H_BULK_REMOVE_ANDCOND) && (*tsh & H_BULK_REMOVE_AVPN)) {
262             *tsh |= H_BULK_REMOVE_PARM;
263             return H_PARAMETER;
264         }
265 
266         ret = remove_hpte(env, *tsh & H_BULK_REMOVE_PTEX, tsl,
267                           (*tsh & H_BULK_REMOVE_FLAGS) >> 26,
268                           &v, &r);
269 
270         *tsh |= ret << 60;
271 
272         switch (ret) {
273         case REMOVE_SUCCESS:
274             *tsh |= (r & (HPTE_R_C | HPTE_R_R)) << 43;
275             break;
276 
277         case REMOVE_PARM:
278             return H_PARAMETER;
279 
280         case REMOVE_HW:
281             return H_HARDWARE;
282         }
283     }
284 
285     return H_SUCCESS;
286 }
287 
288 static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr,
289                               target_ulong opcode, target_ulong *args)
290 {
291     CPUPPCState *env = &cpu->env;
292     target_ulong flags = args[0];
293     target_ulong pte_index = args[1];
294     target_ulong avpn = args[2];
295     uint8_t *hpte;
296     target_ulong v, r, rb;
297 
298     if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
299         return H_PARAMETER;
300     }
301 
302     hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
303 
304     v = ldq_p(hpte);
305     r = ldq_p(hpte + (HASH_PTE_SIZE_64/2));
306 
307     if ((v & HPTE_V_VALID) == 0 ||
308         ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
309         return H_NOT_FOUND;
310     }
311 
312     r &= ~(HPTE_R_PP0 | HPTE_R_PP | HPTE_R_N |
313            HPTE_R_KEY_HI | HPTE_R_KEY_LO);
314     r |= (flags << 55) & HPTE_R_PP0;
315     r |= (flags << 48) & HPTE_R_KEY_HI;
316     r |= flags & (HPTE_R_PP | HPTE_R_N | HPTE_R_KEY_LO);
317     rb = compute_tlbie_rb(v, r, pte_index);
318     stq_p(hpte, v & ~HPTE_V_VALID);
319     ppc_tlb_invalidate_one(env, rb);
320     stq_p(hpte + (HASH_PTE_SIZE_64/2), r);
321     /* Don't need a memory barrier, due to qemu's global lock */
322     stq_p(hpte, v);
323     return H_SUCCESS;
324 }
325 
326 static target_ulong h_set_dabr(PowerPCCPU *cpu, sPAPREnvironment *spapr,
327                                target_ulong opcode, target_ulong *args)
328 {
329     /* FIXME: actually implement this */
330     return H_HARDWARE;
331 }
332 
333 #define FLAGS_REGISTER_VPA         0x0000200000000000ULL
334 #define FLAGS_REGISTER_DTL         0x0000400000000000ULL
335 #define FLAGS_REGISTER_SLBSHADOW   0x0000600000000000ULL
336 #define FLAGS_DEREGISTER_VPA       0x0000a00000000000ULL
337 #define FLAGS_DEREGISTER_DTL       0x0000c00000000000ULL
338 #define FLAGS_DEREGISTER_SLBSHADOW 0x0000e00000000000ULL
339 
340 #define VPA_MIN_SIZE           640
341 #define VPA_SIZE_OFFSET        0x4
342 #define VPA_SHARED_PROC_OFFSET 0x9
343 #define VPA_SHARED_PROC_VAL    0x2
344 
345 static target_ulong register_vpa(CPUPPCState *env, target_ulong vpa)
346 {
347     uint16_t size;
348     uint8_t tmp;
349 
350     if (vpa == 0) {
351         hcall_dprintf("Can't cope with registering a VPA at logical 0\n");
352         return H_HARDWARE;
353     }
354 
355     if (vpa % env->dcache_line_size) {
356         return H_PARAMETER;
357     }
358     /* FIXME: bounds check the address */
359 
360     size = lduw_be_phys(vpa + 0x4);
361 
362     if (size < VPA_MIN_SIZE) {
363         return H_PARAMETER;
364     }
365 
366     /* VPA is not allowed to cross a page boundary */
367     if ((vpa / 4096) != ((vpa + size - 1) / 4096)) {
368         return H_PARAMETER;
369     }
370 
371     env->vpa_addr = vpa;
372 
373     tmp = ldub_phys(env->vpa_addr + VPA_SHARED_PROC_OFFSET);
374     tmp |= VPA_SHARED_PROC_VAL;
375     stb_phys(env->vpa_addr + VPA_SHARED_PROC_OFFSET, tmp);
376 
377     return H_SUCCESS;
378 }
379 
380 static target_ulong deregister_vpa(CPUPPCState *env, target_ulong vpa)
381 {
382     if (env->slb_shadow_addr) {
383         return H_RESOURCE;
384     }
385 
386     if (env->dtl_addr) {
387         return H_RESOURCE;
388     }
389 
390     env->vpa_addr = 0;
391     return H_SUCCESS;
392 }
393 
394 static target_ulong register_slb_shadow(CPUPPCState *env, target_ulong addr)
395 {
396     uint32_t size;
397 
398     if (addr == 0) {
399         hcall_dprintf("Can't cope with SLB shadow at logical 0\n");
400         return H_HARDWARE;
401     }
402 
403     size = ldl_be_phys(addr + 0x4);
404     if (size < 0x8) {
405         return H_PARAMETER;
406     }
407 
408     if ((addr / 4096) != ((addr + size - 1) / 4096)) {
409         return H_PARAMETER;
410     }
411 
412     if (!env->vpa_addr) {
413         return H_RESOURCE;
414     }
415 
416     env->slb_shadow_addr = addr;
417     env->slb_shadow_size = size;
418 
419     return H_SUCCESS;
420 }
421 
422 static target_ulong deregister_slb_shadow(CPUPPCState *env, target_ulong addr)
423 {
424     env->slb_shadow_addr = 0;
425     env->slb_shadow_size = 0;
426     return H_SUCCESS;
427 }
428 
429 static target_ulong register_dtl(CPUPPCState *env, target_ulong addr)
430 {
431     uint32_t size;
432 
433     if (addr == 0) {
434         hcall_dprintf("Can't cope with DTL at logical 0\n");
435         return H_HARDWARE;
436     }
437 
438     size = ldl_be_phys(addr + 0x4);
439 
440     if (size < 48) {
441         return H_PARAMETER;
442     }
443 
444     if (!env->vpa_addr) {
445         return H_RESOURCE;
446     }
447 
448     env->dtl_addr = addr;
449     env->dtl_size = size;
450 
451     return H_SUCCESS;
452 }
453 
454 static target_ulong deregister_dtl(CPUPPCState *env, target_ulong addr)
455 {
456     env->dtl_addr = 0;
457     env->dtl_size = 0;
458 
459     return H_SUCCESS;
460 }
461 
462 static target_ulong h_register_vpa(PowerPCCPU *cpu, sPAPREnvironment *spapr,
463                                    target_ulong opcode, target_ulong *args)
464 {
465     target_ulong flags = args[0];
466     target_ulong procno = args[1];
467     target_ulong vpa = args[2];
468     target_ulong ret = H_PARAMETER;
469     CPUPPCState *tenv;
470     CPUState *tcpu;
471 
472     tcpu = qemu_get_cpu(procno);
473     if (!tcpu) {
474         return H_PARAMETER;
475     }
476     tenv = tcpu->env_ptr;
477 
478     switch (flags) {
479     case FLAGS_REGISTER_VPA:
480         ret = register_vpa(tenv, vpa);
481         break;
482 
483     case FLAGS_DEREGISTER_VPA:
484         ret = deregister_vpa(tenv, vpa);
485         break;
486 
487     case FLAGS_REGISTER_SLBSHADOW:
488         ret = register_slb_shadow(tenv, vpa);
489         break;
490 
491     case FLAGS_DEREGISTER_SLBSHADOW:
492         ret = deregister_slb_shadow(tenv, vpa);
493         break;
494 
495     case FLAGS_REGISTER_DTL:
496         ret = register_dtl(tenv, vpa);
497         break;
498 
499     case FLAGS_DEREGISTER_DTL:
500         ret = deregister_dtl(tenv, vpa);
501         break;
502     }
503 
504     return ret;
505 }
506 
507 static target_ulong h_cede(PowerPCCPU *cpu, sPAPREnvironment *spapr,
508                            target_ulong opcode, target_ulong *args)
509 {
510     CPUPPCState *env = &cpu->env;
511     CPUState *cs = CPU(cpu);
512 
513     env->msr |= (1ULL << MSR_EE);
514     hreg_compute_hflags(env);
515     if (!cpu_has_work(cs)) {
516         env->halted = 1;
517         env->exception_index = EXCP_HLT;
518         cs->exit_request = 1;
519     }
520     return H_SUCCESS;
521 }
522 
523 static target_ulong h_rtas(PowerPCCPU *cpu, sPAPREnvironment *spapr,
524                            target_ulong opcode, target_ulong *args)
525 {
526     target_ulong rtas_r3 = args[0];
527     uint32_t token = ldl_be_phys(rtas_r3);
528     uint32_t nargs = ldl_be_phys(rtas_r3 + 4);
529     uint32_t nret = ldl_be_phys(rtas_r3 + 8);
530 
531     return spapr_rtas_call(spapr, token, nargs, rtas_r3 + 12,
532                            nret, rtas_r3 + 12 + 4*nargs);
533 }
534 
535 static target_ulong h_logical_load(PowerPCCPU *cpu, sPAPREnvironment *spapr,
536                                    target_ulong opcode, target_ulong *args)
537 {
538     target_ulong size = args[0];
539     target_ulong addr = args[1];
540 
541     switch (size) {
542     case 1:
543         args[0] = ldub_phys(addr);
544         return H_SUCCESS;
545     case 2:
546         args[0] = lduw_phys(addr);
547         return H_SUCCESS;
548     case 4:
549         args[0] = ldl_phys(addr);
550         return H_SUCCESS;
551     case 8:
552         args[0] = ldq_phys(addr);
553         return H_SUCCESS;
554     }
555     return H_PARAMETER;
556 }
557 
558 static target_ulong h_logical_store(PowerPCCPU *cpu, sPAPREnvironment *spapr,
559                                     target_ulong opcode, target_ulong *args)
560 {
561     target_ulong size = args[0];
562     target_ulong addr = args[1];
563     target_ulong val  = args[2];
564 
565     switch (size) {
566     case 1:
567         stb_phys(addr, val);
568         return H_SUCCESS;
569     case 2:
570         stw_phys(addr, val);
571         return H_SUCCESS;
572     case 4:
573         stl_phys(addr, val);
574         return H_SUCCESS;
575     case 8:
576         stq_phys(addr, val);
577         return H_SUCCESS;
578     }
579     return H_PARAMETER;
580 }
581 
582 static target_ulong h_logical_memop(PowerPCCPU *cpu, sPAPREnvironment *spapr,
583                                     target_ulong opcode, target_ulong *args)
584 {
585     target_ulong dst   = args[0]; /* Destination address */
586     target_ulong src   = args[1]; /* Source address */
587     target_ulong esize = args[2]; /* Element size (0=1,1=2,2=4,3=8) */
588     target_ulong count = args[3]; /* Element count */
589     target_ulong op    = args[4]; /* 0 = copy, 1 = invert */
590     uint64_t tmp;
591     unsigned int mask = (1 << esize) - 1;
592     int step = 1 << esize;
593 
594     if (count > 0x80000000) {
595         return H_PARAMETER;
596     }
597 
598     if ((dst & mask) || (src & mask) || (op > 1)) {
599         return H_PARAMETER;
600     }
601 
602     if (dst >= src && dst < (src + (count << esize))) {
603             dst = dst + ((count - 1) << esize);
604             src = src + ((count - 1) << esize);
605             step = -step;
606     }
607 
608     while (count--) {
609         switch (esize) {
610         case 0:
611             tmp = ldub_phys(src);
612             break;
613         case 1:
614             tmp = lduw_phys(src);
615             break;
616         case 2:
617             tmp = ldl_phys(src);
618             break;
619         case 3:
620             tmp = ldq_phys(src);
621             break;
622         default:
623             return H_PARAMETER;
624         }
625         if (op == 1) {
626             tmp = ~tmp;
627         }
628         switch (esize) {
629         case 0:
630             stb_phys(dst, tmp);
631             break;
632         case 1:
633             stw_phys(dst, tmp);
634             break;
635         case 2:
636             stl_phys(dst, tmp);
637             break;
638         case 3:
639             stq_phys(dst, tmp);
640             break;
641         }
642         dst = dst + step;
643         src = src + step;
644     }
645 
646     return H_SUCCESS;
647 }
648 
649 static target_ulong h_logical_icbi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
650                                    target_ulong opcode, target_ulong *args)
651 {
652     /* Nothing to do on emulation, KVM will trap this in the kernel */
653     return H_SUCCESS;
654 }
655 
656 static target_ulong h_logical_dcbf(PowerPCCPU *cpu, sPAPREnvironment *spapr,
657                                    target_ulong opcode, target_ulong *args)
658 {
659     /* Nothing to do on emulation, KVM will trap this in the kernel */
660     return H_SUCCESS;
661 }
662 
663 static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
664 static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1];
665 
666 void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn)
667 {
668     spapr_hcall_fn *slot;
669 
670     if (opcode <= MAX_HCALL_OPCODE) {
671         assert((opcode & 0x3) == 0);
672 
673         slot = &papr_hypercall_table[opcode / 4];
674     } else {
675         assert((opcode >= KVMPPC_HCALL_BASE) && (opcode <= KVMPPC_HCALL_MAX));
676 
677         slot = &kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
678     }
679 
680     assert(!(*slot));
681     *slot = fn;
682 }
683 
684 target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
685                              target_ulong *args)
686 {
687     if ((opcode <= MAX_HCALL_OPCODE)
688         && ((opcode & 0x3) == 0)) {
689         spapr_hcall_fn fn = papr_hypercall_table[opcode / 4];
690 
691         if (fn) {
692             return fn(cpu, spapr, opcode, args);
693         }
694     } else if ((opcode >= KVMPPC_HCALL_BASE) &&
695                (opcode <= KVMPPC_HCALL_MAX)) {
696         spapr_hcall_fn fn = kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
697 
698         if (fn) {
699             return fn(cpu, spapr, opcode, args);
700         }
701     }
702 
703     hcall_dprintf("Unimplemented hcall 0x" TARGET_FMT_lx "\n", opcode);
704     return H_FUNCTION;
705 }
706 
707 static void hypercall_register_types(void)
708 {
709     /* hcall-pft */
710     spapr_register_hypercall(H_ENTER, h_enter);
711     spapr_register_hypercall(H_REMOVE, h_remove);
712     spapr_register_hypercall(H_PROTECT, h_protect);
713 
714     /* hcall-bulk */
715     spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove);
716 
717     /* hcall-dabr */
718     spapr_register_hypercall(H_SET_DABR, h_set_dabr);
719 
720     /* hcall-splpar */
721     spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa);
722     spapr_register_hypercall(H_CEDE, h_cede);
723 
724     /* "debugger" hcalls (also used by SLOF). Note: We do -not- differenciate
725      * here between the "CI" and the "CACHE" variants, they will use whatever
726      * mapping attributes qemu is using. When using KVM, the kernel will
727      * enforce the attributes more strongly
728      */
729     spapr_register_hypercall(H_LOGICAL_CI_LOAD, h_logical_load);
730     spapr_register_hypercall(H_LOGICAL_CI_STORE, h_logical_store);
731     spapr_register_hypercall(H_LOGICAL_CACHE_LOAD, h_logical_load);
732     spapr_register_hypercall(H_LOGICAL_CACHE_STORE, h_logical_store);
733     spapr_register_hypercall(H_LOGICAL_ICBI, h_logical_icbi);
734     spapr_register_hypercall(H_LOGICAL_DCBF, h_logical_dcbf);
735     spapr_register_hypercall(KVMPPC_H_LOGICAL_MEMOP, h_logical_memop);
736 
737     /* qemu/KVM-PPC specific hcalls */
738     spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);
739 }
740 
741 type_init(hypercall_register_types)
742