xref: /openbmc/qemu/hw/ppc/spapr_hcall.c (revision c71c3e99)
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_read(PowerPCCPU *cpu, sPAPREnvironment *spapr,
327                            target_ulong opcode, target_ulong *args)
328 {
329     CPUPPCState *env = &cpu->env;
330     target_ulong flags = args[0];
331     target_ulong pte_index = args[1];
332     uint8_t *hpte;
333     int i, ridx, n_entries = 1;
334 
335     if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
336         return H_PARAMETER;
337     }
338 
339     if (flags & H_READ_4) {
340         /* Clear the two low order bits */
341         pte_index &= ~(3ULL);
342         n_entries = 4;
343     }
344 
345     hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
346 
347     for (i = 0, ridx = 0; i < n_entries; i++) {
348         args[ridx++] = ldq_p(hpte);
349         args[ridx++] = ldq_p(hpte + (HASH_PTE_SIZE_64/2));
350         hpte += HASH_PTE_SIZE_64;
351     }
352 
353     return H_SUCCESS;
354 }
355 
356 static target_ulong h_set_dabr(PowerPCCPU *cpu, sPAPREnvironment *spapr,
357                                target_ulong opcode, target_ulong *args)
358 {
359     /* FIXME: actually implement this */
360     return H_HARDWARE;
361 }
362 
363 #define FLAGS_REGISTER_VPA         0x0000200000000000ULL
364 #define FLAGS_REGISTER_DTL         0x0000400000000000ULL
365 #define FLAGS_REGISTER_SLBSHADOW   0x0000600000000000ULL
366 #define FLAGS_DEREGISTER_VPA       0x0000a00000000000ULL
367 #define FLAGS_DEREGISTER_DTL       0x0000c00000000000ULL
368 #define FLAGS_DEREGISTER_SLBSHADOW 0x0000e00000000000ULL
369 
370 #define VPA_MIN_SIZE           640
371 #define VPA_SIZE_OFFSET        0x4
372 #define VPA_SHARED_PROC_OFFSET 0x9
373 #define VPA_SHARED_PROC_VAL    0x2
374 
375 static target_ulong register_vpa(CPUPPCState *env, target_ulong vpa)
376 {
377     uint16_t size;
378     uint8_t tmp;
379 
380     if (vpa == 0) {
381         hcall_dprintf("Can't cope with registering a VPA at logical 0\n");
382         return H_HARDWARE;
383     }
384 
385     if (vpa % env->dcache_line_size) {
386         return H_PARAMETER;
387     }
388     /* FIXME: bounds check the address */
389 
390     size = lduw_be_phys(vpa + 0x4);
391 
392     if (size < VPA_MIN_SIZE) {
393         return H_PARAMETER;
394     }
395 
396     /* VPA is not allowed to cross a page boundary */
397     if ((vpa / 4096) != ((vpa + size - 1) / 4096)) {
398         return H_PARAMETER;
399     }
400 
401     env->vpa_addr = vpa;
402 
403     tmp = ldub_phys(env->vpa_addr + VPA_SHARED_PROC_OFFSET);
404     tmp |= VPA_SHARED_PROC_VAL;
405     stb_phys(env->vpa_addr + VPA_SHARED_PROC_OFFSET, tmp);
406 
407     return H_SUCCESS;
408 }
409 
410 static target_ulong deregister_vpa(CPUPPCState *env, target_ulong vpa)
411 {
412     if (env->slb_shadow_addr) {
413         return H_RESOURCE;
414     }
415 
416     if (env->dtl_addr) {
417         return H_RESOURCE;
418     }
419 
420     env->vpa_addr = 0;
421     return H_SUCCESS;
422 }
423 
424 static target_ulong register_slb_shadow(CPUPPCState *env, target_ulong addr)
425 {
426     uint32_t size;
427 
428     if (addr == 0) {
429         hcall_dprintf("Can't cope with SLB shadow at logical 0\n");
430         return H_HARDWARE;
431     }
432 
433     size = ldl_be_phys(addr + 0x4);
434     if (size < 0x8) {
435         return H_PARAMETER;
436     }
437 
438     if ((addr / 4096) != ((addr + size - 1) / 4096)) {
439         return H_PARAMETER;
440     }
441 
442     if (!env->vpa_addr) {
443         return H_RESOURCE;
444     }
445 
446     env->slb_shadow_addr = addr;
447     env->slb_shadow_size = size;
448 
449     return H_SUCCESS;
450 }
451 
452 static target_ulong deregister_slb_shadow(CPUPPCState *env, target_ulong addr)
453 {
454     env->slb_shadow_addr = 0;
455     env->slb_shadow_size = 0;
456     return H_SUCCESS;
457 }
458 
459 static target_ulong register_dtl(CPUPPCState *env, target_ulong addr)
460 {
461     uint32_t size;
462 
463     if (addr == 0) {
464         hcall_dprintf("Can't cope with DTL at logical 0\n");
465         return H_HARDWARE;
466     }
467 
468     size = ldl_be_phys(addr + 0x4);
469 
470     if (size < 48) {
471         return H_PARAMETER;
472     }
473 
474     if (!env->vpa_addr) {
475         return H_RESOURCE;
476     }
477 
478     env->dtl_addr = addr;
479     env->dtl_size = size;
480 
481     return H_SUCCESS;
482 }
483 
484 static target_ulong deregister_dtl(CPUPPCState *env, target_ulong addr)
485 {
486     env->dtl_addr = 0;
487     env->dtl_size = 0;
488 
489     return H_SUCCESS;
490 }
491 
492 static target_ulong h_register_vpa(PowerPCCPU *cpu, sPAPREnvironment *spapr,
493                                    target_ulong opcode, target_ulong *args)
494 {
495     target_ulong flags = args[0];
496     target_ulong procno = args[1];
497     target_ulong vpa = args[2];
498     target_ulong ret = H_PARAMETER;
499     CPUPPCState *tenv;
500     CPUState *tcpu;
501 
502     tcpu = qemu_get_cpu(procno);
503     if (!tcpu) {
504         return H_PARAMETER;
505     }
506     tenv = tcpu->env_ptr;
507 
508     switch (flags) {
509     case FLAGS_REGISTER_VPA:
510         ret = register_vpa(tenv, vpa);
511         break;
512 
513     case FLAGS_DEREGISTER_VPA:
514         ret = deregister_vpa(tenv, vpa);
515         break;
516 
517     case FLAGS_REGISTER_SLBSHADOW:
518         ret = register_slb_shadow(tenv, vpa);
519         break;
520 
521     case FLAGS_DEREGISTER_SLBSHADOW:
522         ret = deregister_slb_shadow(tenv, vpa);
523         break;
524 
525     case FLAGS_REGISTER_DTL:
526         ret = register_dtl(tenv, vpa);
527         break;
528 
529     case FLAGS_DEREGISTER_DTL:
530         ret = deregister_dtl(tenv, vpa);
531         break;
532     }
533 
534     return ret;
535 }
536 
537 static target_ulong h_cede(PowerPCCPU *cpu, sPAPREnvironment *spapr,
538                            target_ulong opcode, target_ulong *args)
539 {
540     CPUPPCState *env = &cpu->env;
541     CPUState *cs = CPU(cpu);
542 
543     env->msr |= (1ULL << MSR_EE);
544     hreg_compute_hflags(env);
545     if (!cpu_has_work(cs)) {
546         env->halted = 1;
547         env->exception_index = EXCP_HLT;
548         cs->exit_request = 1;
549     }
550     return H_SUCCESS;
551 }
552 
553 static target_ulong h_rtas(PowerPCCPU *cpu, sPAPREnvironment *spapr,
554                            target_ulong opcode, target_ulong *args)
555 {
556     target_ulong rtas_r3 = args[0];
557     uint32_t token = ldl_be_phys(rtas_r3);
558     uint32_t nargs = ldl_be_phys(rtas_r3 + 4);
559     uint32_t nret = ldl_be_phys(rtas_r3 + 8);
560 
561     return spapr_rtas_call(spapr, token, nargs, rtas_r3 + 12,
562                            nret, rtas_r3 + 12 + 4*nargs);
563 }
564 
565 static target_ulong h_logical_load(PowerPCCPU *cpu, sPAPREnvironment *spapr,
566                                    target_ulong opcode, target_ulong *args)
567 {
568     target_ulong size = args[0];
569     target_ulong addr = args[1];
570 
571     switch (size) {
572     case 1:
573         args[0] = ldub_phys(addr);
574         return H_SUCCESS;
575     case 2:
576         args[0] = lduw_phys(addr);
577         return H_SUCCESS;
578     case 4:
579         args[0] = ldl_phys(addr);
580         return H_SUCCESS;
581     case 8:
582         args[0] = ldq_phys(addr);
583         return H_SUCCESS;
584     }
585     return H_PARAMETER;
586 }
587 
588 static target_ulong h_logical_store(PowerPCCPU *cpu, sPAPREnvironment *spapr,
589                                     target_ulong opcode, target_ulong *args)
590 {
591     target_ulong size = args[0];
592     target_ulong addr = args[1];
593     target_ulong val  = args[2];
594 
595     switch (size) {
596     case 1:
597         stb_phys(addr, val);
598         return H_SUCCESS;
599     case 2:
600         stw_phys(addr, val);
601         return H_SUCCESS;
602     case 4:
603         stl_phys(addr, val);
604         return H_SUCCESS;
605     case 8:
606         stq_phys(addr, val);
607         return H_SUCCESS;
608     }
609     return H_PARAMETER;
610 }
611 
612 static target_ulong h_logical_memop(PowerPCCPU *cpu, sPAPREnvironment *spapr,
613                                     target_ulong opcode, target_ulong *args)
614 {
615     target_ulong dst   = args[0]; /* Destination address */
616     target_ulong src   = args[1]; /* Source address */
617     target_ulong esize = args[2]; /* Element size (0=1,1=2,2=4,3=8) */
618     target_ulong count = args[3]; /* Element count */
619     target_ulong op    = args[4]; /* 0 = copy, 1 = invert */
620     uint64_t tmp;
621     unsigned int mask = (1 << esize) - 1;
622     int step = 1 << esize;
623 
624     if (count > 0x80000000) {
625         return H_PARAMETER;
626     }
627 
628     if ((dst & mask) || (src & mask) || (op > 1)) {
629         return H_PARAMETER;
630     }
631 
632     if (dst >= src && dst < (src + (count << esize))) {
633             dst = dst + ((count - 1) << esize);
634             src = src + ((count - 1) << esize);
635             step = -step;
636     }
637 
638     while (count--) {
639         switch (esize) {
640         case 0:
641             tmp = ldub_phys(src);
642             break;
643         case 1:
644             tmp = lduw_phys(src);
645             break;
646         case 2:
647             tmp = ldl_phys(src);
648             break;
649         case 3:
650             tmp = ldq_phys(src);
651             break;
652         default:
653             return H_PARAMETER;
654         }
655         if (op == 1) {
656             tmp = ~tmp;
657         }
658         switch (esize) {
659         case 0:
660             stb_phys(dst, tmp);
661             break;
662         case 1:
663             stw_phys(dst, tmp);
664             break;
665         case 2:
666             stl_phys(dst, tmp);
667             break;
668         case 3:
669             stq_phys(dst, tmp);
670             break;
671         }
672         dst = dst + step;
673         src = src + step;
674     }
675 
676     return H_SUCCESS;
677 }
678 
679 static target_ulong h_logical_icbi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
680                                    target_ulong opcode, target_ulong *args)
681 {
682     /* Nothing to do on emulation, KVM will trap this in the kernel */
683     return H_SUCCESS;
684 }
685 
686 static target_ulong h_logical_dcbf(PowerPCCPU *cpu, sPAPREnvironment *spapr,
687                                    target_ulong opcode, target_ulong *args)
688 {
689     /* Nothing to do on emulation, KVM will trap this in the kernel */
690     return H_SUCCESS;
691 }
692 
693 static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
694 static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1];
695 
696 void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn)
697 {
698     spapr_hcall_fn *slot;
699 
700     if (opcode <= MAX_HCALL_OPCODE) {
701         assert((opcode & 0x3) == 0);
702 
703         slot = &papr_hypercall_table[opcode / 4];
704     } else {
705         assert((opcode >= KVMPPC_HCALL_BASE) && (opcode <= KVMPPC_HCALL_MAX));
706 
707         slot = &kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
708     }
709 
710     assert(!(*slot));
711     *slot = fn;
712 }
713 
714 target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
715                              target_ulong *args)
716 {
717     if ((opcode <= MAX_HCALL_OPCODE)
718         && ((opcode & 0x3) == 0)) {
719         spapr_hcall_fn fn = papr_hypercall_table[opcode / 4];
720 
721         if (fn) {
722             return fn(cpu, spapr, opcode, args);
723         }
724     } else if ((opcode >= KVMPPC_HCALL_BASE) &&
725                (opcode <= KVMPPC_HCALL_MAX)) {
726         spapr_hcall_fn fn = kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
727 
728         if (fn) {
729             return fn(cpu, spapr, opcode, args);
730         }
731     }
732 
733     hcall_dprintf("Unimplemented hcall 0x" TARGET_FMT_lx "\n", opcode);
734     return H_FUNCTION;
735 }
736 
737 static void hypercall_register_types(void)
738 {
739     /* hcall-pft */
740     spapr_register_hypercall(H_ENTER, h_enter);
741     spapr_register_hypercall(H_REMOVE, h_remove);
742     spapr_register_hypercall(H_PROTECT, h_protect);
743     spapr_register_hypercall(H_READ, h_read);
744 
745     /* hcall-bulk */
746     spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove);
747 
748     /* hcall-dabr */
749     spapr_register_hypercall(H_SET_DABR, h_set_dabr);
750 
751     /* hcall-splpar */
752     spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa);
753     spapr_register_hypercall(H_CEDE, h_cede);
754 
755     /* "debugger" hcalls (also used by SLOF). Note: We do -not- differenciate
756      * here between the "CI" and the "CACHE" variants, they will use whatever
757      * mapping attributes qemu is using. When using KVM, the kernel will
758      * enforce the attributes more strongly
759      */
760     spapr_register_hypercall(H_LOGICAL_CI_LOAD, h_logical_load);
761     spapr_register_hypercall(H_LOGICAL_CI_STORE, h_logical_store);
762     spapr_register_hypercall(H_LOGICAL_CACHE_LOAD, h_logical_load);
763     spapr_register_hypercall(H_LOGICAL_CACHE_STORE, h_logical_store);
764     spapr_register_hypercall(H_LOGICAL_ICBI, h_logical_icbi);
765     spapr_register_hypercall(H_LOGICAL_DCBF, h_logical_dcbf);
766     spapr_register_hypercall(KVMPPC_H_LOGICAL_MEMOP, h_logical_memop);
767 
768     /* qemu/KVM-PPC specific hcalls */
769     spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);
770 }
771 
772 type_init(hypercall_register_types)
773