spapr_hcall: Fix little-endian resource handling in H_SET_MODE
[qemu.git] / hw / ppc / spapr_hcall.c
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
7 struct SPRSyncState {
8 CPUState *cs;
9 int spr;
10 target_ulong value;
11 target_ulong mask;
12 };
13
14 static 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
25 static 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
37 static 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; /* AVA field */
43 va_low = pte_index >> 3;
44 if (v & HPTE64_V_SECONDARY) {
45 va_low = ~va_low;
46 }
47 /* xor vsid from AVA */
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; /* L field */
56 #if 0 /* Disable that P7 specific bit for now */
57 if (r & 0xff000) {
58 /* non-16MB large page, must be 64k */
59 /* (masks depend on page size) */
60 rb |= 0x1000; /* page encoding in LP field */
61 rb |= (va_low & 0x7f) << 16; /* 7b of VA in AVA/LP field */
62 rb |= (va_low & 0xfe); /* AVAL field */
63 }
64 #endif
65 } else {
66 /* 4kB page */
67 rb |= (va_low & 0x7ff) << 12; /* remaining 11b of AVA */
68 }
69 rb |= (v >> 54) & 0x300; /* B field */
70 return rb;
71 }
72
73 static inline bool valid_pte_index(CPUPPCState *env, target_ulong pte_index)
74 {
75 /*
76 * hash value/pteg group index is normalized by htab_mask
77 */
78 if (((pte_index & ~7ULL) / HPTES_PER_GROUP) & ~env->htab_mask) {
79 return false;
80 }
81 return true;
82 }
83
84 static 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 /* only handle 4k and 16M pages for now */
98 if (pteh & HPTE64_V_LARGE) {
99 #if 0 /* We don't support 64k pages yet */
100 if ((ptel & 0xf000) == 0x1000) {
101 /* 64k page */
102 } else
103 #endif
104 if ((ptel & 0xff000) == 0) {
105 /* 16M page */
106 page_shift = 24;
107 /* lowest AVA bit must be 0 for 16M pages */
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 /* Regular RAM - should have WIMG=0010 */
120 if ((ptel & HPTE64_R_WIMG) != HPTE64_R_M) {
121 return H_PARAMETER;
122 }
123 } else {
124 /* Looks like an IO address */
125 /* FIXME: What WIMG combinations could be sensible for IO?
126 * For now we allow WIMG=010x, but are there others? */
127 /* FIXME: Should we check against registered IO addresses? */
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
168 typedef enum {
169 REMOVE_SUCCESS = 0,
170 REMOVE_NOT_FOUND = 1,
171 REMOVE_PARM = 2,
172 REMOVE_HW = 3,
173 } RemoveResult;
174
175 static 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
205 static 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
252 static 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
299 static 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 /* Don't need a memory barrier, due to qemu's global lock */
333 ppc_hash64_store_hpte(env, pte_index, v | HPTE64_V_HPTE_DIRTY, r);
334 return H_SUCCESS;
335 }
336
337 static 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 /* Clear the two low order bits */
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
367 static target_ulong h_set_dabr(PowerPCCPU *cpu, sPAPREnvironment *spapr,
368 target_ulong opcode, target_ulong *args)
369 {
370 /* FIXME: actually implement this */
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
386 static 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 /* FIXME: bounds check the address */
401
402 size = lduw_be_phys(cs->as, vpa + 0x4);
403
404 if (size < VPA_MIN_SIZE) {
405 return H_PARAMETER;
406 }
407
408 /* VPA is not allowed to cross a page boundary */
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
422 static 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
436 static 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
465 static 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
472 static 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
498 static 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
506 static 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
551 static 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
567 static 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
579 static 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
603 static 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
629 static 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]; /* Destination address */
635 target_ulong src = args[1]; /* Source address */
636 target_ulong esize = args[2]; /* Element size (0=1,1=2,2=4,3=8) */
637 target_ulong count = args[3]; /* Element count */
638 target_ulong op = args[4]; /* 0 = copy, 1 = invert */
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
698 static target_ulong h_logical_icbi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
699 target_ulong opcode, target_ulong *args)
700 {
701 /* Nothing to do on emulation, KVM will trap this in the kernel */
702 return H_SUCCESS;
703 }
704
705 static target_ulong h_logical_dcbf(PowerPCCPU *cpu, sPAPREnvironment *spapr,
706 target_ulong opcode, target_ulong *args)
707 {
708 /* Nothing to do on emulation, KVM will trap this in the kernel */
709 return H_SUCCESS;
710 }
711
712 static 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
751 out:
752 return ret;
753 }
754
755 static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
756 static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1];
757
758 void 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
776 target_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
799 static void hypercall_register_types(void)
800 {
801 /* hcall-pft */
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 /* hcall-bulk */
808 spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove);
809
810 /* hcall-dabr */
811 spapr_register_hypercall(H_SET_DABR, h_set_dabr);
812
813 /* hcall-splpar */
814 spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa);
815 spapr_register_hypercall(H_CEDE, h_cede);
816
817 /* "debugger" hcalls (also used by SLOF). Note: We do -not- differenciate
818 * here between the "CI" and the "CACHE" variants, they will use whatever
819 * mapping attributes qemu is using. When using KVM, the kernel will
820 * enforce the attributes more strongly
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 /* qemu/KVM-PPC specific hcalls */
831 spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);
832
833 spapr_register_hypercall(H_SET_MODE, h_set_mode);
834 }
835
836 type_init(hypercall_register_types)