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