1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#include "qemu/osdep.h"
22#include "cpu.h"
23#include "exec/helper-proto.h"
24#include "exec/cpu_ldst.h"
25#include "hw/s390x/storage-keys.h"
26
27
28
29#if !defined(CONFIG_USER_ONLY)
30
31
32
33
34
35void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
36 uintptr_t retaddr)
37{
38 int ret;
39
40 ret = s390_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx);
41 if (unlikely(ret != 0)) {
42 if (likely(retaddr)) {
43
44 cpu_restore_state(cs, retaddr);
45 }
46 cpu_loop_exit(cs);
47 }
48}
49
50#endif
51
52
53#ifdef DEBUG_HELPER
54#define HELPER_LOG(x...) qemu_log(x)
55#else
56#define HELPER_LOG(x...)
57#endif
58
59
60static inline uint64_t adj_len_to_page(uint64_t len, uint64_t addr)
61{
62#ifndef CONFIG_USER_ONLY
63 if ((addr & ~TARGET_PAGE_MASK) + len - 1 >= TARGET_PAGE_SIZE) {
64 return -addr & ~TARGET_PAGE_MASK;
65 }
66#endif
67 return len;
68}
69
70static void fast_memset(CPUS390XState *env, uint64_t dest, uint8_t byte,
71 uint32_t l)
72{
73 int mmu_idx = cpu_mmu_index(env, false);
74
75 while (l > 0) {
76 void *p = tlb_vaddr_to_host(env, dest, MMU_DATA_STORE, mmu_idx);
77 if (p) {
78
79 int l_adj = adj_len_to_page(l, dest);
80 memset(p, byte, l_adj);
81 dest += l_adj;
82 l -= l_adj;
83 } else {
84
85
86 cpu_stb_data(env, dest, byte);
87 dest++;
88 l--;
89 }
90 }
91}
92
93static void fast_memmove(CPUS390XState *env, uint64_t dest, uint64_t src,
94 uint32_t l)
95{
96 int mmu_idx = cpu_mmu_index(env, false);
97
98 while (l > 0) {
99 void *src_p = tlb_vaddr_to_host(env, src, MMU_DATA_LOAD, mmu_idx);
100 void *dest_p = tlb_vaddr_to_host(env, dest, MMU_DATA_STORE, mmu_idx);
101 if (src_p && dest_p) {
102
103 int l_adj = adj_len_to_page(l, src);
104 l_adj = adj_len_to_page(l_adj, dest);
105 memmove(dest_p, src_p, l_adj);
106 src += l_adj;
107 dest += l_adj;
108 l -= l_adj;
109 } else {
110
111
112
113 cpu_stb_data(env, dest, cpu_ldub_data(env, src));
114 src++;
115 dest++;
116 l--;
117 }
118 }
119}
120
121
122uint32_t HELPER(nc)(CPUS390XState *env, uint32_t l, uint64_t dest,
123 uint64_t src)
124{
125 int i;
126 unsigned char x;
127 uint32_t cc = 0;
128
129 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
130 __func__, l, dest, src);
131 for (i = 0; i <= l; i++) {
132 x = cpu_ldub_data(env, dest + i) & cpu_ldub_data(env, src + i);
133 if (x) {
134 cc = 1;
135 }
136 cpu_stb_data(env, dest + i, x);
137 }
138 return cc;
139}
140
141
142uint32_t HELPER(xc)(CPUS390XState *env, uint32_t l, uint64_t dest,
143 uint64_t src)
144{
145 int i;
146 unsigned char x;
147 uint32_t cc = 0;
148
149 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
150 __func__, l, dest, src);
151
152
153 if (src == dest) {
154 fast_memset(env, dest, 0, l + 1);
155 return 0;
156 }
157
158 for (i = 0; i <= l; i++) {
159 x = cpu_ldub_data(env, dest + i) ^ cpu_ldub_data(env, src + i);
160 if (x) {
161 cc = 1;
162 }
163 cpu_stb_data(env, dest + i, x);
164 }
165 return cc;
166}
167
168
169uint32_t HELPER(oc)(CPUS390XState *env, uint32_t l, uint64_t dest,
170 uint64_t src)
171{
172 int i;
173 unsigned char x;
174 uint32_t cc = 0;
175
176 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
177 __func__, l, dest, src);
178 for (i = 0; i <= l; i++) {
179 x = cpu_ldub_data(env, dest + i) | cpu_ldub_data(env, src + i);
180 if (x) {
181 cc = 1;
182 }
183 cpu_stb_data(env, dest + i, x);
184 }
185 return cc;
186}
187
188
189void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
190{
191 int i = 0;
192
193 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
194 __func__, l, dest, src);
195
196
197
198 if (dest == (src + 1)) {
199 fast_memset(env, dest, cpu_ldub_data(env, src), l + 1);
200 return;
201 }
202
203
204 if ((dest < src) || (src + l < dest)) {
205 fast_memmove(env, dest, src, l + 1);
206 return;
207 }
208
209
210 for (i = 0; i <= l; i++) {
211 cpu_stb_data(env, dest + i, cpu_ldub_data(env, src + i));
212 }
213}
214
215
216uint32_t HELPER(clc)(CPUS390XState *env, uint32_t l, uint64_t s1, uint64_t s2)
217{
218 int i;
219 unsigned char x, y;
220 uint32_t cc;
221
222 HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n",
223 __func__, l, s1, s2);
224 for (i = 0; i <= l; i++) {
225 x = cpu_ldub_data(env, s1 + i);
226 y = cpu_ldub_data(env, s2 + i);
227 HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y);
228 if (x < y) {
229 cc = 1;
230 goto done;
231 } else if (x > y) {
232 cc = 2;
233 goto done;
234 }
235 }
236 cc = 0;
237 done:
238 HELPER_LOG("\n");
239 return cc;
240}
241
242
243uint32_t HELPER(clm)(CPUS390XState *env, uint32_t r1, uint32_t mask,
244 uint64_t addr)
245{
246 uint8_t r, d;
247 uint32_t cc;
248
249 HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1,
250 mask, addr);
251 cc = 0;
252 while (mask) {
253 if (mask & 8) {
254 d = cpu_ldub_data(env, addr);
255 r = (r1 & 0xff000000UL) >> 24;
256 HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d,
257 addr);
258 if (r < d) {
259 cc = 1;
260 break;
261 } else if (r > d) {
262 cc = 2;
263 break;
264 }
265 addr++;
266 }
267 mask = (mask << 1) & 0xf;
268 r1 <<= 8;
269 }
270 HELPER_LOG("\n");
271 return cc;
272}
273
274static inline uint64_t fix_address(CPUS390XState *env, uint64_t a)
275{
276
277 if (!(env->psw.mask & PSW_MASK_64)) {
278 a &= 0x7fffffff;
279 }
280 return a;
281}
282
283static inline uint64_t get_address(CPUS390XState *env, int x2, int b2, int d2)
284{
285 uint64_t r = d2;
286 if (x2) {
287 r += env->regs[x2];
288 }
289 if (b2) {
290 r += env->regs[b2];
291 }
292 return fix_address(env, r);
293}
294
295static inline uint64_t get_address_31fix(CPUS390XState *env, int reg)
296{
297 return fix_address(env, env->regs[reg]);
298}
299
300
301uint64_t HELPER(srst)(CPUS390XState *env, uint64_t r0, uint64_t end,
302 uint64_t str)
303{
304 uint32_t len;
305 uint8_t v, c = r0;
306
307 str = fix_address(env, str);
308 end = fix_address(env, end);
309
310
311 env->retxl = str;
312
313
314
315 for (len = 0; len < 0x2000; ++len) {
316 if (str + len == end) {
317
318 env->cc_op = 2;
319 return end;
320 }
321 v = cpu_ldub_data(env, str + len);
322 if (v == c) {
323
324 env->cc_op = 1;
325 return str + len;
326 }
327 }
328
329
330 env->retxl = str + len;
331 env->cc_op = 3;
332 return end;
333}
334
335
336uint64_t HELPER(clst)(CPUS390XState *env, uint64_t c, uint64_t s1, uint64_t s2)
337{
338 uint32_t len;
339
340 c = c & 0xff;
341 s1 = fix_address(env, s1);
342 s2 = fix_address(env, s2);
343
344
345
346 for (len = 0; len < 0x2000; ++len) {
347 uint8_t v1 = cpu_ldub_data(env, s1 + len);
348 uint8_t v2 = cpu_ldub_data(env, s2 + len);
349 if (v1 == v2) {
350 if (v1 == c) {
351
352 env->cc_op = 0;
353 env->retxl = s2;
354 return s1;
355 }
356 } else {
357
358
359
360 env->cc_op = (v1 == c ? 1 : v2 == c ? 2 : v1 < v2 ? 1 : 2);
361 env->retxl = s2 + len;
362 return s1 + len;
363 }
364 }
365
366
367 env->cc_op = 3;
368 env->retxl = s2 + len;
369 return s1 + len;
370}
371
372
373void HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2)
374{
375
376 env->cc_op = 0;
377 fast_memmove(env, r1, r2, TARGET_PAGE_SIZE);
378}
379
380
381uint64_t HELPER(mvst)(CPUS390XState *env, uint64_t c, uint64_t d, uint64_t s)
382{
383 uint32_t len;
384
385 c = c & 0xff;
386 d = fix_address(env, d);
387 s = fix_address(env, s);
388
389
390
391 for (len = 0; len < 0x2000; ++len) {
392 uint8_t v = cpu_ldub_data(env, s + len);
393 cpu_stb_data(env, d + len, v);
394 if (v == c) {
395
396 env->cc_op = 1;
397 env->retxl = s;
398 return d + len;
399 }
400 }
401
402
403 env->cc_op = 3;
404 env->retxl = s + len;
405 return d + len;
406}
407
408static uint32_t helper_icm(CPUS390XState *env, uint32_t r1, uint64_t address,
409 uint32_t mask)
410{
411 int pos = 24;
412 uint64_t rmask = 0xff000000ULL;
413 uint8_t val = 0;
414 int ccd = 0;
415 uint32_t cc = 0;
416
417 while (mask) {
418 if (mask & 8) {
419 env->regs[r1] &= ~rmask;
420 val = cpu_ldub_data(env, address);
421 if ((val & 0x80) && !ccd) {
422 cc = 1;
423 }
424 ccd = 1;
425 if (val && cc == 0) {
426 cc = 2;
427 }
428 env->regs[r1] |= (uint64_t)val << pos;
429 address++;
430 }
431 mask = (mask << 1) & 0xf;
432 pos -= 8;
433 rmask >>= 8;
434 }
435
436 return cc;
437}
438
439
440
441
442
443
444
445
446uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1,
447 uint64_t addr, uint64_t ret)
448{
449 S390CPU *cpu = s390_env_get_cpu(env);
450 uint16_t insn = cpu_lduw_code(env, addr);
451
452 HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __func__, v1, addr,
453 insn);
454 if ((insn & 0xf0ff) == 0xd000) {
455 uint32_t l, insn2, b1, b2, d1, d2;
456
457 l = v1 & 0xff;
458 insn2 = cpu_ldl_code(env, addr + 2);
459 b1 = (insn2 >> 28) & 0xf;
460 b2 = (insn2 >> 12) & 0xf;
461 d1 = (insn2 >> 16) & 0xfff;
462 d2 = insn2 & 0xfff;
463 switch (insn & 0xf00) {
464 case 0x200:
465 helper_mvc(env, l, get_address(env, 0, b1, d1),
466 get_address(env, 0, b2, d2));
467 break;
468 case 0x400:
469 cc = helper_nc(env, l, get_address(env, 0, b1, d1),
470 get_address(env, 0, b2, d2));
471 break;
472 case 0x500:
473 cc = helper_clc(env, l, get_address(env, 0, b1, d1),
474 get_address(env, 0, b2, d2));
475 break;
476 case 0x600:
477 cc = helper_oc(env, l, get_address(env, 0, b1, d1),
478 get_address(env, 0, b2, d2));
479 break;
480 case 0x700:
481 cc = helper_xc(env, l, get_address(env, 0, b1, d1),
482 get_address(env, 0, b2, d2));
483 break;
484 case 0xc00:
485 helper_tr(env, l, get_address(env, 0, b1, d1),
486 get_address(env, 0, b2, d2));
487 break;
488 case 0xd00:
489 cc = helper_trt(env, l, get_address(env, 0, b1, d1),
490 get_address(env, 0, b2, d2));
491 break;
492 default:
493 goto abort;
494 }
495 } else if ((insn & 0xff00) == 0x0a00) {
496
497 HELPER_LOG("%s: svc %ld via execute\n", __func__, (insn | v1) & 0xff);
498 env->psw.addr = ret - 4;
499 env->int_svc_code = (insn | v1) & 0xff;
500 env->int_svc_ilen = 4;
501 helper_exception(env, EXCP_SVC);
502 } else if ((insn & 0xff00) == 0xbf00) {
503 uint32_t insn2, r1, r3, b2, d2;
504
505 insn2 = cpu_ldl_code(env, addr + 2);
506 r1 = (insn2 >> 20) & 0xf;
507 r3 = (insn2 >> 16) & 0xf;
508 b2 = (insn2 >> 12) & 0xf;
509 d2 = insn2 & 0xfff;
510 cc = helper_icm(env, r1, get_address(env, 0, b2, d2), r3);
511 } else {
512 abort:
513 cpu_abort(CPU(cpu), "EXECUTE on instruction prefix 0x%x not implemented\n",
514 insn);
515 }
516 return cc;
517}
518
519
520void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
521{
522 int i;
523
524 for (i = r1;; i = (i + 1) % 16) {
525 env->aregs[i] = cpu_ldl_data(env, a2);
526 a2 += 4;
527
528 if (i == r3) {
529 break;
530 }
531 }
532}
533
534
535void HELPER(stam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
536{
537 int i;
538
539 for (i = r1;; i = (i + 1) % 16) {
540 cpu_stl_data(env, a2, env->aregs[i]);
541 a2 += 4;
542
543 if (i == r3) {
544 break;
545 }
546 }
547}
548
549
550uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
551{
552 uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
553 uint64_t dest = get_address_31fix(env, r1);
554 uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
555 uint64_t src = get_address_31fix(env, r2);
556 uint8_t pad = env->regs[r2 + 1] >> 24;
557 uint8_t v;
558 uint32_t cc;
559
560 if (destlen == srclen) {
561 cc = 0;
562 } else if (destlen < srclen) {
563 cc = 1;
564 } else {
565 cc = 2;
566 }
567
568 if (srclen > destlen) {
569 srclen = destlen;
570 }
571
572 for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
573 v = cpu_ldub_data(env, src);
574 cpu_stb_data(env, dest, v);
575 }
576
577 for (; destlen; dest++, destlen--) {
578 cpu_stb_data(env, dest, pad);
579 }
580
581 env->regs[r1 + 1] = destlen;
582
583 env->regs[r2 + 1] -= src - env->regs[r2];
584 env->regs[r1] = dest;
585 env->regs[r2] = src;
586
587 return cc;
588}
589
590
591uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
592 uint32_t r3)
593{
594 uint64_t destlen = env->regs[r1 + 1];
595 uint64_t dest = env->regs[r1];
596 uint64_t srclen = env->regs[r3 + 1];
597 uint64_t src = env->regs[r3];
598 uint8_t pad = a2 & 0xff;
599 uint8_t v;
600 uint32_t cc;
601
602 if (!(env->psw.mask & PSW_MASK_64)) {
603 destlen = (uint32_t)destlen;
604 srclen = (uint32_t)srclen;
605 dest &= 0x7fffffff;
606 src &= 0x7fffffff;
607 }
608
609 if (destlen == srclen) {
610 cc = 0;
611 } else if (destlen < srclen) {
612 cc = 1;
613 } else {
614 cc = 2;
615 }
616
617 if (srclen > destlen) {
618 srclen = destlen;
619 }
620
621 for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
622 v = cpu_ldub_data(env, src);
623 cpu_stb_data(env, dest, v);
624 }
625
626 for (; destlen; dest++, destlen--) {
627 cpu_stb_data(env, dest, pad);
628 }
629
630 env->regs[r1 + 1] = destlen;
631
632
633 env->regs[r3 + 1] -= src - env->regs[r3];
634 env->regs[r1] = dest;
635 env->regs[r3] = src;
636
637 return cc;
638}
639
640
641uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
642 uint32_t r3)
643{
644 uint64_t destlen = env->regs[r1 + 1];
645 uint64_t dest = get_address_31fix(env, r1);
646 uint64_t srclen = env->regs[r3 + 1];
647 uint64_t src = get_address_31fix(env, r3);
648 uint8_t pad = a2 & 0xff;
649 uint8_t v1 = 0, v2 = 0;
650 uint32_t cc = 0;
651
652 if (!(destlen || srclen)) {
653 return cc;
654 }
655
656 if (srclen > destlen) {
657 srclen = destlen;
658 }
659
660 for (; destlen || srclen; src++, dest++, destlen--, srclen--) {
661 v1 = srclen ? cpu_ldub_data(env, src) : pad;
662 v2 = destlen ? cpu_ldub_data(env, dest) : pad;
663 if (v1 != v2) {
664 cc = (v1 < v2) ? 1 : 2;
665 break;
666 }
667 }
668
669 env->regs[r1 + 1] = destlen;
670
671 env->regs[r3 + 1] -= src - env->regs[r3];
672 env->regs[r1] = dest;
673 env->regs[r3] = src;
674
675 return cc;
676}
677
678
679uint64_t HELPER(cksm)(CPUS390XState *env, uint64_t r1,
680 uint64_t src, uint64_t src_len)
681{
682 uint64_t max_len, len;
683 uint64_t cksm = (uint32_t)r1;
684
685
686
687 max_len = (src_len > 0x2000 ? 0x2000 : src_len);
688
689
690 for (len = 0; len + 4 <= max_len; len += 4, src += 4) {
691 cksm += (uint32_t)cpu_ldl_data(env, src);
692 }
693
694 switch (max_len - len) {
695 case 1:
696 cksm += cpu_ldub_data(env, src) << 24;
697 len += 1;
698 break;
699 case 2:
700 cksm += cpu_lduw_data(env, src) << 16;
701 len += 2;
702 break;
703 case 3:
704 cksm += cpu_lduw_data(env, src) << 16;
705 cksm += cpu_ldub_data(env, src + 2) << 8;
706 len += 3;
707 break;
708 }
709
710
711
712 while (cksm > 0xffffffffull) {
713 cksm = (uint32_t)cksm + (cksm >> 32);
714 }
715
716
717 env->cc_op = (len == src_len ? 0 : 3);
718
719
720 env->retxl = cksm;
721 return len;
722}
723
724void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest,
725 uint64_t src)
726{
727 int len_dest = len >> 4;
728 int len_src = len & 0xf;
729 uint8_t b;
730 int second_nibble = 0;
731
732 dest += len_dest;
733 src += len_src;
734
735
736 b = cpu_ldub_data(env, src);
737 cpu_stb_data(env, dest, (b << 4) | (b >> 4));
738 src--;
739 len_src--;
740
741
742
743 while (len_dest > 0) {
744 uint8_t cur_byte = 0;
745
746 if (len_src > 0) {
747 cur_byte = cpu_ldub_data(env, src);
748 }
749
750 len_dest--;
751 dest--;
752
753
754 if (second_nibble) {
755 cur_byte >>= 4;
756 len_src--;
757 src--;
758 }
759 second_nibble = !second_nibble;
760
761
762 cur_byte = (cur_byte & 0xf);
763
764 cur_byte |= 0xf0;
765
766 cpu_stb_data(env, dest, cur_byte);
767 }
768}
769
770void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array,
771 uint64_t trans)
772{
773 int i;
774
775 for (i = 0; i <= len; i++) {
776 uint8_t byte = cpu_ldub_data(env, array + i);
777 uint8_t new_byte = cpu_ldub_data(env, trans + byte);
778
779 cpu_stb_data(env, array + i, new_byte);
780 }
781}
782
783uint64_t HELPER(tre)(CPUS390XState *env, uint64_t array,
784 uint64_t len, uint64_t trans)
785{
786 uint8_t end = env->regs[0] & 0xff;
787 uint64_t l = len;
788 uint64_t i;
789
790 if (!(env->psw.mask & PSW_MASK_64)) {
791 array &= 0x7fffffff;
792 l = (uint32_t)l;
793 }
794
795
796
797 if (l > 0x2000) {
798 l = 0x2000;
799 env->cc_op = 3;
800 } else {
801 env->cc_op = 0;
802 }
803
804 for (i = 0; i < l; i++) {
805 uint8_t byte, new_byte;
806
807 byte = cpu_ldub_data(env, array + i);
808
809 if (byte == end) {
810 env->cc_op = 1;
811 break;
812 }
813
814 new_byte = cpu_ldub_data(env, trans + byte);
815 cpu_stb_data(env, array + i, new_byte);
816 }
817
818 env->retxl = len - i;
819 return array + i;
820}
821
822uint32_t HELPER(trt)(CPUS390XState *env, uint32_t len, uint64_t array,
823 uint64_t trans)
824{
825 uint32_t cc = 0;
826 int i;
827
828 for (i = 0; i <= len; i++) {
829 uint8_t byte = cpu_ldub_data(env, array + i);
830 uint8_t sbyte = cpu_ldub_data(env, trans + byte);
831
832 if (sbyte != 0) {
833 env->regs[1] = array + i;
834 env->regs[2] = (env->regs[2] & ~0xff) | sbyte;
835 cc = (i == len) ? 2 : 1;
836 break;
837 }
838 }
839
840 return cc;
841}
842
843#if !defined(CONFIG_USER_ONLY)
844void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
845{
846 S390CPU *cpu = s390_env_get_cpu(env);
847 bool PERchanged = false;
848 int i;
849 uint64_t src = a2;
850 uint64_t val;
851
852 for (i = r1;; i = (i + 1) % 16) {
853 val = cpu_ldq_data(env, src);
854 if (env->cregs[i] != val && i >= 9 && i <= 11) {
855 PERchanged = true;
856 }
857 env->cregs[i] = val;
858 HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
859 i, src, env->cregs[i]);
860 src += sizeof(uint64_t);
861
862 if (i == r3) {
863 break;
864 }
865 }
866
867 if (PERchanged && env->psw.mask & PSW_MASK_PER) {
868 s390_cpu_recompute_watchpoints(CPU(cpu));
869 }
870
871 tlb_flush(CPU(cpu), 1);
872}
873
874void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
875{
876 S390CPU *cpu = s390_env_get_cpu(env);
877 bool PERchanged = false;
878 int i;
879 uint64_t src = a2;
880 uint32_t val;
881
882 for (i = r1;; i = (i + 1) % 16) {
883 val = cpu_ldl_data(env, src);
884 if ((uint32_t)env->cregs[i] != val && i >= 9 && i <= 11) {
885 PERchanged = true;
886 }
887 env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) | val;
888 src += sizeof(uint32_t);
889
890 if (i == r3) {
891 break;
892 }
893 }
894
895 if (PERchanged && env->psw.mask & PSW_MASK_PER) {
896 s390_cpu_recompute_watchpoints(CPU(cpu));
897 }
898
899 tlb_flush(CPU(cpu), 1);
900}
901
902void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
903{
904 int i;
905 uint64_t dest = a2;
906
907 for (i = r1;; i = (i + 1) % 16) {
908 cpu_stq_data(env, dest, env->cregs[i]);
909 dest += sizeof(uint64_t);
910
911 if (i == r3) {
912 break;
913 }
914 }
915}
916
917void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
918{
919 int i;
920 uint64_t dest = a2;
921
922 for (i = r1;; i = (i + 1) % 16) {
923 cpu_stl_data(env, dest, env->cregs[i]);
924 dest += sizeof(uint32_t);
925
926 if (i == r3) {
927 break;
928 }
929 }
930}
931
932uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2)
933{
934
935
936 return 0;
937}
938
939
940uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2)
941{
942 static S390SKeysState *ss;
943 static S390SKeysClass *skeyclass;
944 uint64_t addr = get_address(env, 0, 0, r2);
945 uint8_t key;
946
947 if (addr > ram_size) {
948 return 0;
949 }
950
951 if (unlikely(!ss)) {
952 ss = s390_get_skeys_device();
953 skeyclass = S390_SKEYS_GET_CLASS(ss);
954 }
955
956 if (skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key)) {
957 return 0;
958 }
959 return key;
960}
961
962
963void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2)
964{
965 static S390SKeysState *ss;
966 static S390SKeysClass *skeyclass;
967 uint64_t addr = get_address(env, 0, 0, r2);
968 uint8_t key;
969
970 if (addr > ram_size) {
971 return;
972 }
973
974 if (unlikely(!ss)) {
975 ss = s390_get_skeys_device();
976 skeyclass = S390_SKEYS_GET_CLASS(ss);
977 }
978
979 key = (uint8_t) r1;
980 skeyclass->set_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
981}
982
983
984uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2)
985{
986 static S390SKeysState *ss;
987 static S390SKeysClass *skeyclass;
988 uint8_t re, key;
989
990 if (r2 > ram_size) {
991 return 0;
992 }
993
994 if (unlikely(!ss)) {
995 ss = s390_get_skeys_device();
996 skeyclass = S390_SKEYS_GET_CLASS(ss);
997 }
998
999 if (skeyclass->get_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
1000 return 0;
1001 }
1002
1003 re = key & (SK_R | SK_C);
1004 key &= ~SK_R;
1005
1006 if (skeyclass->set_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
1007 return 0;
1008 }
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019 return re >> 1;
1020}
1021
1022
1023uint32_t HELPER(csp)(CPUS390XState *env, uint32_t r1, uint64_t r2)
1024{
1025 S390CPU *cpu = s390_env_get_cpu(env);
1026 uint32_t cc;
1027 uint32_t o1 = env->regs[r1];
1028 uint64_t a2 = r2 & ~3ULL;
1029 uint32_t o2 = cpu_ldl_data(env, a2);
1030
1031 if (o1 == o2) {
1032 cpu_stl_data(env, a2, env->regs[(r1 + 1) & 15]);
1033 if (r2 & 0x3) {
1034
1035 tlb_flush(CPU(cpu), 1);
1036 }
1037 cc = 0;
1038 } else {
1039 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | o2;
1040 cc = 1;
1041 }
1042
1043 return cc;
1044}
1045
1046uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
1047{
1048 int cc = 0, i;
1049
1050 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1051 __func__, l, a1, a2);
1052
1053 if (l > 256) {
1054
1055 l = 256;
1056 cc = 3;
1057 }
1058
1059
1060 for (i = 0; i < l; i++) {
1061 cpu_stb_secondary(env, a1 + i, cpu_ldub_primary(env, a2 + i));
1062 }
1063
1064 return cc;
1065}
1066
1067uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
1068{
1069 int cc = 0, i;
1070
1071 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1072 __func__, l, a1, a2);
1073
1074 if (l > 256) {
1075
1076 l = 256;
1077 cc = 3;
1078 }
1079
1080
1081 for (i = 0; i < l; i++) {
1082 cpu_stb_primary(env, a1 + i, cpu_ldub_secondary(env, a2 + i));
1083 }
1084
1085 return cc;
1086}
1087
1088
1089void HELPER(ipte)(CPUS390XState *env, uint64_t pte_addr, uint64_t vaddr)
1090{
1091 CPUState *cs = CPU(s390_env_get_cpu(env));
1092 uint64_t page = vaddr & TARGET_PAGE_MASK;
1093 uint64_t pte = 0;
1094
1095
1096
1097
1098
1099
1100
1101 stq_phys(cs->as, pte_addr, pte | _PAGE_INVALID);
1102
1103
1104
1105 tlb_flush_page(cs, page);
1106
1107
1108 if (page & 0x80000000) {
1109 tlb_flush_page(cs, page & ~0x80000000);
1110 } else {
1111 tlb_flush_page(cs, page | 0x80000000);
1112 }
1113}
1114
1115
1116void HELPER(ptlb)(CPUS390XState *env)
1117{
1118 S390CPU *cpu = s390_env_get_cpu(env);
1119
1120 tlb_flush(CPU(cpu), 1);
1121}
1122
1123
1124uint64_t HELPER(lura)(CPUS390XState *env, uint64_t addr)
1125{
1126 CPUState *cs = CPU(s390_env_get_cpu(env));
1127
1128 return (uint32_t)ldl_phys(cs->as, get_address(env, 0, 0, addr));
1129}
1130
1131uint64_t HELPER(lurag)(CPUS390XState *env, uint64_t addr)
1132{
1133 CPUState *cs = CPU(s390_env_get_cpu(env));
1134
1135 return ldq_phys(cs->as, get_address(env, 0, 0, addr));
1136}
1137
1138
1139void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint64_t v1)
1140{
1141 CPUState *cs = CPU(s390_env_get_cpu(env));
1142
1143 stl_phys(cs->as, get_address(env, 0, 0, addr), (uint32_t)v1);
1144
1145 if ((env->psw.mask & PSW_MASK_PER) &&
1146 (env->cregs[9] & PER_CR9_EVENT_STORE) &&
1147 (env->cregs[9] & PER_CR9_EVENT_STORE_REAL)) {
1148
1149 env->per_address = env->psw.addr;
1150 env->per_perc_atmid = PER_CODE_EVENT_STORE_REAL | get_per_atmid(env);
1151 }
1152}
1153
1154void HELPER(sturg)(CPUS390XState *env, uint64_t addr, uint64_t v1)
1155{
1156 CPUState *cs = CPU(s390_env_get_cpu(env));
1157
1158 stq_phys(cs->as, get_address(env, 0, 0, addr), v1);
1159
1160 if ((env->psw.mask & PSW_MASK_PER) &&
1161 (env->cregs[9] & PER_CR9_EVENT_STORE) &&
1162 (env->cregs[9] & PER_CR9_EVENT_STORE_REAL)) {
1163
1164 env->per_address = env->psw.addr;
1165 env->per_perc_atmid = PER_CODE_EVENT_STORE_REAL | get_per_atmid(env);
1166 }
1167}
1168
1169
1170uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr)
1171{
1172 CPUState *cs = CPU(s390_env_get_cpu(env));
1173 uint32_t cc = 0;
1174 int old_exc = cs->exception_index;
1175 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
1176 uint64_t ret;
1177 int flags;
1178
1179
1180 if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
1181 program_interrupt(env, PGM_SPECIAL_OP, 2);
1182 }
1183
1184 cs->exception_index = old_exc;
1185 if (mmu_translate(env, addr, 0, asc, &ret, &flags, true)) {
1186 cc = 3;
1187 }
1188 if (cs->exception_index == EXCP_PGM) {
1189 ret = env->int_pgm_code | 0x80000000;
1190 } else {
1191 ret |= addr & ~TARGET_PAGE_MASK;
1192 }
1193 cs->exception_index = old_exc;
1194
1195 env->cc_op = cc;
1196 return ret;
1197}
1198#endif
1199