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