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