target-s390x: avoid AREG0 for FPU helpers
[sdk/emulator/qemu.git] / target-s390x / mem_helper.c
1 /*
2  *  S/390 memory access helper routines
3  *
4  *  Copyright (c) 2009 Ulrich Hecht
5  *  Copyright (c) 2009 Alexander Graf
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "cpu.h"
22 #include "dyngen-exec.h"
23 #include "helper.h"
24
25 /*****************************************************************************/
26 /* Softmmu support */
27 #if !defined(CONFIG_USER_ONLY)
28 #include "softmmu_exec.h"
29
30 #define MMUSUFFIX _mmu
31
32 #define SHIFT 0
33 #include "softmmu_template.h"
34
35 #define SHIFT 1
36 #include "softmmu_template.h"
37
38 #define SHIFT 2
39 #include "softmmu_template.h"
40
41 #define SHIFT 3
42 #include "softmmu_template.h"
43
44 /* try to fill the TLB and return an exception if error. If retaddr is
45    NULL, it means that the function was called in C code (i.e. not
46    from generated code or from helper.c) */
47 /* XXX: fix it to restore all registers */
48 void tlb_fill(CPUS390XState *env1, target_ulong addr, int is_write, int mmu_idx,
49               uintptr_t retaddr)
50 {
51     TranslationBlock *tb;
52     CPUS390XState *saved_env;
53     int ret;
54
55     saved_env = env;
56     env = env1;
57     ret = cpu_s390x_handle_mmu_fault(env, addr, is_write, mmu_idx);
58     if (unlikely(ret != 0)) {
59         if (likely(retaddr)) {
60             /* now we have a real cpu fault */
61             tb = tb_find_pc(retaddr);
62             if (likely(tb)) {
63                 /* the PC is inside the translated code. It means that we have
64                    a virtual CPU fault */
65                 cpu_restore_state(tb, env, retaddr);
66             }
67         }
68         cpu_loop_exit(env);
69     }
70     env = saved_env;
71 }
72
73 #endif
74
75 /* #define DEBUG_HELPER */
76 #ifdef DEBUG_HELPER
77 #define HELPER_LOG(x...) qemu_log(x)
78 #else
79 #define HELPER_LOG(x...)
80 #endif
81
82 #ifndef CONFIG_USER_ONLY
83 static void mvc_fast_memset(CPUS390XState *env, uint32_t l, uint64_t dest,
84                             uint8_t byte)
85 {
86     target_phys_addr_t dest_phys;
87     target_phys_addr_t len = l;
88     void *dest_p;
89     uint64_t asc = env->psw.mask & PSW_MASK_ASC;
90     int flags;
91
92     if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) {
93         stb(dest, byte);
94         cpu_abort(env, "should never reach here");
95     }
96     dest_phys |= dest & ~TARGET_PAGE_MASK;
97
98     dest_p = cpu_physical_memory_map(dest_phys, &len, 1);
99
100     memset(dest_p, byte, len);
101
102     cpu_physical_memory_unmap(dest_p, 1, len, len);
103 }
104
105 static void mvc_fast_memmove(CPUS390XState *env, uint32_t l, uint64_t dest,
106                              uint64_t src)
107 {
108     target_phys_addr_t dest_phys;
109     target_phys_addr_t src_phys;
110     target_phys_addr_t len = l;
111     void *dest_p;
112     void *src_p;
113     uint64_t asc = env->psw.mask & PSW_MASK_ASC;
114     int flags;
115
116     if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) {
117         stb(dest, 0);
118         cpu_abort(env, "should never reach here");
119     }
120     dest_phys |= dest & ~TARGET_PAGE_MASK;
121
122     if (mmu_translate(env, src, 0, asc, &src_phys, &flags)) {
123         ldub(src);
124         cpu_abort(env, "should never reach here");
125     }
126     src_phys |= src & ~TARGET_PAGE_MASK;
127
128     dest_p = cpu_physical_memory_map(dest_phys, &len, 1);
129     src_p = cpu_physical_memory_map(src_phys, &len, 0);
130
131     memmove(dest_p, src_p, len);
132
133     cpu_physical_memory_unmap(dest_p, 1, len, len);
134     cpu_physical_memory_unmap(src_p, 0, len, len);
135 }
136 #endif
137
138 /* and on array */
139 uint32_t HELPER(nc)(uint32_t l, uint64_t dest, uint64_t src)
140 {
141     int i;
142     unsigned char x;
143     uint32_t cc = 0;
144
145     HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
146                __func__, l, dest, src);
147     for (i = 0; i <= l; i++) {
148         x = ldub(dest + i) & ldub(src + i);
149         if (x) {
150             cc = 1;
151         }
152         stb(dest + i, x);
153     }
154     return cc;
155 }
156
157 /* xor on array */
158 uint32_t HELPER(xc)(uint32_t l, uint64_t dest, uint64_t src)
159 {
160     int i;
161     unsigned char x;
162     uint32_t cc = 0;
163
164     HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
165                __func__, l, dest, src);
166
167 #ifndef CONFIG_USER_ONLY
168     /* xor with itself is the same as memset(0) */
169     if ((l > 32) && (src == dest) &&
170         (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK)) {
171         mvc_fast_memset(env, l + 1, dest, 0);
172         return 0;
173     }
174 #else
175     if (src == dest) {
176         memset(g2h(dest), 0, l + 1);
177         return 0;
178     }
179 #endif
180
181     for (i = 0; i <= l; i++) {
182         x = ldub(dest + i) ^ ldub(src + i);
183         if (x) {
184             cc = 1;
185         }
186         stb(dest + i, x);
187     }
188     return cc;
189 }
190
191 /* or on array */
192 uint32_t HELPER(oc)(uint32_t l, uint64_t dest, uint64_t src)
193 {
194     int i;
195     unsigned char x;
196     uint32_t cc = 0;
197
198     HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
199                __func__, l, dest, src);
200     for (i = 0; i <= l; i++) {
201         x = ldub(dest + i) | ldub(src + i);
202         if (x) {
203             cc = 1;
204         }
205         stb(dest + i, x);
206     }
207     return cc;
208 }
209
210 /* memmove */
211 void HELPER(mvc)(uint32_t l, uint64_t dest, uint64_t src)
212 {
213     int i = 0;
214     int x = 0;
215     uint32_t l_64 = (l + 1) / 8;
216
217     HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
218                __func__, l, dest, src);
219
220 #ifndef CONFIG_USER_ONLY
221     if ((l > 32) &&
222         (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK) &&
223         (dest & TARGET_PAGE_MASK) == ((dest + l) & TARGET_PAGE_MASK)) {
224         if (dest == (src + 1)) {
225             mvc_fast_memset(env, l + 1, dest, ldub(src));
226             return;
227         } else if ((src & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
228             mvc_fast_memmove(env, l + 1, dest, src);
229             return;
230         }
231     }
232 #else
233     if (dest == (src + 1)) {
234         memset(g2h(dest), ldub(src), l + 1);
235         return;
236     } else {
237         memmove(g2h(dest), g2h(src), l + 1);
238         return;
239     }
240 #endif
241
242     /* handle the parts that fit into 8-byte loads/stores */
243     if (dest != (src + 1)) {
244         for (i = 0; i < l_64; i++) {
245             stq(dest + x, ldq(src + x));
246             x += 8;
247         }
248     }
249
250     /* slow version crossing pages with byte accesses */
251     for (i = x; i <= l; i++) {
252         stb(dest + i, ldub(src + i));
253     }
254 }
255
256 /* compare unsigned byte arrays */
257 uint32_t HELPER(clc)(uint32_t l, uint64_t s1, uint64_t s2)
258 {
259     int i;
260     unsigned char x, y;
261     uint32_t cc;
262
263     HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n",
264                __func__, l, s1, s2);
265     for (i = 0; i <= l; i++) {
266         x = ldub(s1 + i);
267         y = ldub(s2 + i);
268         HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y);
269         if (x < y) {
270             cc = 1;
271             goto done;
272         } else if (x > y) {
273             cc = 2;
274             goto done;
275         }
276     }
277     cc = 0;
278  done:
279     HELPER_LOG("\n");
280     return cc;
281 }
282
283 /* compare logical under mask */
284 uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr)
285 {
286     uint8_t r, d;
287     uint32_t cc;
288
289     HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1,
290                mask, addr);
291     cc = 0;
292     while (mask) {
293         if (mask & 8) {
294             d = ldub(addr);
295             r = (r1 & 0xff000000UL) >> 24;
296             HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d,
297                        addr);
298             if (r < d) {
299                 cc = 1;
300                 break;
301             } else if (r > d) {
302                 cc = 2;
303                 break;
304             }
305             addr++;
306         }
307         mask = (mask << 1) & 0xf;
308         r1 <<= 8;
309     }
310     HELPER_LOG("\n");
311     return cc;
312 }
313
314 /* store character under mask */
315 void HELPER(stcm)(uint32_t r1, uint32_t mask, 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             stb(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
334 static inline uint64_t get_address(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     /* 31-Bit mode */
347     if (!(env->psw.mask & PSW_MASK_64)) {
348         r &= 0x7fffffff;
349     }
350
351     return r;
352 }
353
354 static inline uint64_t get_address_31fix(int reg)
355 {
356     uint64_t r = env->regs[reg];
357
358     /* 31-Bit mode */
359     if (!(env->psw.mask & PSW_MASK_64)) {
360         r &= 0x7fffffff;
361     }
362
363     return r;
364 }
365
366 /* search string (c is byte to search, r2 is string, r1 end of string) */
367 uint32_t HELPER(srst)(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(r2);
372     uint64_t end = get_address_31fix(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 (ldub(i) == c) {
379             env->regs[r1] = i;
380             cc = 1;
381             break;
382         }
383     }
384
385     return cc;
386 }
387
388 /* unsigned string compare (c is string terminator) */
389 uint32_t HELPER(clst)(uint32_t c, uint32_t r1, uint32_t r2)
390 {
391     uint64_t s1 = get_address_31fix(r1);
392     uint64_t s2 = get_address_31fix(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 = ldub(s1);
405         v2 = ldub(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         /* FIXME: 31-bit mode! */
418         env->regs[r1] = s1;
419         env->regs[r2] = s2;
420     }
421     return cc;
422 }
423
424 /* move page */
425 void HELPER(mvpg)(uint64_t r0, uint64_t r1, uint64_t r2)
426 {
427     /* XXX missing r0 handling */
428 #ifdef CONFIG_USER_ONLY
429     int i;
430
431     for (i = 0; i < TARGET_PAGE_SIZE; i++) {
432         stb(r1 + i, ldub(r2 + i));
433     }
434 #else
435     mvc_fast_memmove(env, TARGET_PAGE_SIZE, r1, r2);
436 #endif
437 }
438
439 /* string copy (c is string terminator) */
440 void HELPER(mvst)(uint32_t c, uint32_t r1, uint32_t r2)
441 {
442     uint64_t dest = get_address_31fix(r1);
443     uint64_t src = get_address_31fix(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 = ldub(src);
455         stb(dest, v);
456         if (v == c) {
457             break;
458         }
459         src++;
460         dest++;
461     }
462     env->regs[r1] = dest; /* FIXME: 31-bit mode! */
463 }
464
465 /* compare and swap 64-bit */
466 uint32_t HELPER(csg)(uint32_t r1, uint64_t a2, uint32_t r3)
467 {
468     /* FIXME: locking? */
469     uint32_t cc;
470     uint64_t v2 = ldq(a2);
471
472     if (env->regs[r1] == v2) {
473         cc = 0;
474         stq(a2, env->regs[r3]);
475     } else {
476         cc = 1;
477         env->regs[r1] = v2;
478     }
479     return cc;
480 }
481
482 /* compare double and swap 64-bit */
483 uint32_t HELPER(cdsg)(uint32_t r1, uint64_t a2, uint32_t r3)
484 {
485     /* FIXME: locking? */
486     uint32_t cc;
487     uint64_t v2_hi = ldq(a2);
488     uint64_t v2_lo = ldq(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         stq(a2, env->regs[r3]);
495         stq(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 /* compare and swap 32-bit */
506 uint32_t HELPER(cs)(uint32_t r1, uint64_t a2, uint32_t r3)
507 {
508     /* FIXME: locking? */
509     uint32_t cc;
510     uint32_t v2 = ldl(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         stl(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
523 static uint32_t helper_icm(uint32_t r1, uint64_t address, uint32_t mask)
524 {
525     int pos = 24; /* top of the lower half of r1 */
526     uint64_t rmask = 0xff000000ULL;
527     uint8_t val = 0;
528     int ccd = 0;
529     uint32_t cc = 0;
530
531     while (mask) {
532         if (mask & 8) {
533             env->regs[r1] &= ~rmask;
534             val = ldub(address);
535             if ((val & 0x80) && !ccd) {
536                 cc = 1;
537             }
538             ccd = 1;
539             if (val && cc == 0) {
540                 cc = 2;
541             }
542             env->regs[r1] |= (uint64_t)val << pos;
543             address++;
544         }
545         mask = (mask << 1) & 0xf;
546         pos -= 8;
547         rmask >>= 8;
548     }
549
550     return cc;
551 }
552
553 /* execute instruction
554    this instruction executes an insn modified with the contents of r1
555    it does not change the executed instruction in memory
556    it does not change the program counter
557    in other words: tricky...
558    currently implemented by interpreting the cases it is most commonly used in
559 */
560 uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret)
561 {
562     uint16_t insn = lduw_code(addr);
563
564     HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __func__, v1, addr,
565                insn);
566     if ((insn & 0xf0ff) == 0xd000) {
567         uint32_t l, insn2, b1, b2, d1, d2;
568
569         l = v1 & 0xff;
570         insn2 = ldl_code(addr + 2);
571         b1 = (insn2 >> 28) & 0xf;
572         b2 = (insn2 >> 12) & 0xf;
573         d1 = (insn2 >> 16) & 0xfff;
574         d2 = insn2 & 0xfff;
575         switch (insn & 0xf00) {
576         case 0x200:
577             helper_mvc(l, get_address(0, b1, d1), get_address(0, b2, d2));
578             break;
579         case 0x500:
580             cc = helper_clc(l, get_address(0, b1, d1), get_address(0, b2, d2));
581             break;
582         case 0x700:
583             cc = helper_xc(l, get_address(0, b1, d1), get_address(0, b2, d2));
584             break;
585         case 0xc00:
586             helper_tr(l, get_address(0, b1, d1), get_address(0, b2, d2));
587             break;
588         default:
589             goto abort;
590             break;
591         }
592     } else if ((insn & 0xff00) == 0x0a00) {
593         /* supervisor call */
594         HELPER_LOG("%s: svc %ld via execute\n", __func__, (insn | v1) & 0xff);
595         env->psw.addr = ret - 4;
596         env->int_svc_code = (insn | v1) & 0xff;
597         env->int_svc_ilc = 4;
598         helper_exception(EXCP_SVC);
599     } else if ((insn & 0xff00) == 0xbf00) {
600         uint32_t insn2, r1, r3, b2, d2;
601
602         insn2 = ldl_code(addr + 2);
603         r1 = (insn2 >> 20) & 0xf;
604         r3 = (insn2 >> 16) & 0xf;
605         b2 = (insn2 >> 12) & 0xf;
606         d2 = insn2 & 0xfff;
607         cc = helper_icm(r1, get_address(0, b2, d2), r3);
608     } else {
609     abort:
610         cpu_abort(env, "EXECUTE on instruction prefix 0x%x not implemented\n",
611                   insn);
612     }
613     return cc;
614 }
615
616 /* store character under mask high operates on the upper half of r1 */
617 void HELPER(stcmh)(uint32_t r1, uint64_t address, uint32_t mask)
618 {
619     int pos = 56; /* top of the upper half of r1 */
620
621     while (mask) {
622         if (mask & 8) {
623             stb(address, (env->regs[r1] >> pos) & 0xff);
624             address++;
625         }
626         mask = (mask << 1) & 0xf;
627         pos -= 8;
628     }
629 }
630
631 /* insert character under mask high; same as icm, but operates on the
632    upper half of r1 */
633 uint32_t HELPER(icmh)(uint32_t r1, uint64_t address, uint32_t mask)
634 {
635     int pos = 56; /* top of the upper half of r1 */
636     uint64_t rmask = 0xff00000000000000ULL;
637     uint8_t val = 0;
638     int ccd = 0;
639     uint32_t cc = 0;
640
641     while (mask) {
642         if (mask & 8) {
643             env->regs[r1] &= ~rmask;
644             val = ldub(address);
645             if ((val & 0x80) && !ccd) {
646                 cc = 1;
647             }
648             ccd = 1;
649             if (val && cc == 0) {
650                 cc = 2;
651             }
652             env->regs[r1] |= (uint64_t)val << pos;
653             address++;
654         }
655         mask = (mask << 1) & 0xf;
656         pos -= 8;
657         rmask >>= 8;
658     }
659
660     return cc;
661 }
662
663 /* load access registers r1 to r3 from memory at a2 */
664 void HELPER(lam)(uint32_t r1, uint64_t a2, uint32_t r3)
665 {
666     int i;
667
668     for (i = r1;; i = (i + 1) % 16) {
669         env->aregs[i] = ldl(a2);
670         a2 += 4;
671
672         if (i == r3) {
673             break;
674         }
675     }
676 }
677
678 /* store access registers r1 to r3 in memory at a2 */
679 void HELPER(stam)(uint32_t r1, uint64_t a2, uint32_t r3)
680 {
681     int i;
682
683     for (i = r1;; i = (i + 1) % 16) {
684         stl(a2, env->aregs[i]);
685         a2 += 4;
686
687         if (i == r3) {
688             break;
689         }
690     }
691 }
692
693 /* move long */
694 uint32_t HELPER(mvcl)(uint32_t r1, uint32_t r2)
695 {
696     uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
697     uint64_t dest = get_address_31fix(r1);
698     uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
699     uint64_t src = get_address_31fix(r2);
700     uint8_t pad = src >> 24;
701     uint8_t v;
702     uint32_t cc;
703
704     if (destlen == srclen) {
705         cc = 0;
706     } else if (destlen < srclen) {
707         cc = 1;
708     } else {
709         cc = 2;
710     }
711
712     if (srclen > destlen) {
713         srclen = destlen;
714     }
715
716     for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
717         v = ldub(src);
718         stb(dest, v);
719     }
720
721     for (; destlen; dest++, destlen--) {
722         stb(dest, pad);
723     }
724
725     env->regs[r1 + 1] = destlen;
726     /* can't use srclen here, we trunc'ed it */
727     env->regs[r2 + 1] -= src - env->regs[r2];
728     env->regs[r1] = dest;
729     env->regs[r2] = src;
730
731     return cc;
732 }
733
734 /* move long extended another memcopy insn with more bells and whistles */
735 uint32_t HELPER(mvcle)(uint32_t r1, uint64_t a2, uint32_t r3)
736 {
737     uint64_t destlen = env->regs[r1 + 1];
738     uint64_t dest = env->regs[r1];
739     uint64_t srclen = env->regs[r3 + 1];
740     uint64_t src = env->regs[r3];
741     uint8_t pad = a2 & 0xff;
742     uint8_t v;
743     uint32_t cc;
744
745     if (!(env->psw.mask & PSW_MASK_64)) {
746         destlen = (uint32_t)destlen;
747         srclen = (uint32_t)srclen;
748         dest &= 0x7fffffff;
749         src &= 0x7fffffff;
750     }
751
752     if (destlen == srclen) {
753         cc = 0;
754     } else if (destlen < srclen) {
755         cc = 1;
756     } else {
757         cc = 2;
758     }
759
760     if (srclen > destlen) {
761         srclen = destlen;
762     }
763
764     for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
765         v = ldub(src);
766         stb(dest, v);
767     }
768
769     for (; destlen; dest++, destlen--) {
770         stb(dest, pad);
771     }
772
773     env->regs[r1 + 1] = destlen;
774     /* can't use srclen here, we trunc'ed it */
775     /* FIXME: 31-bit mode! */
776     env->regs[r3 + 1] -= src - env->regs[r3];
777     env->regs[r1] = dest;
778     env->regs[r3] = src;
779
780     return cc;
781 }
782
783 /* compare logical long extended memcompare insn with padding */
784 uint32_t HELPER(clcle)(uint32_t r1, uint64_t a2, uint32_t r3)
785 {
786     uint64_t destlen = env->regs[r1 + 1];
787     uint64_t dest = get_address_31fix(r1);
788     uint64_t srclen = env->regs[r3 + 1];
789     uint64_t src = get_address_31fix(r3);
790     uint8_t pad = a2 & 0xff;
791     uint8_t v1 = 0, v2 = 0;
792     uint32_t cc = 0;
793
794     if (!(destlen || srclen)) {
795         return cc;
796     }
797
798     if (srclen > destlen) {
799         srclen = destlen;
800     }
801
802     for (; destlen || srclen; src++, dest++, destlen--, srclen--) {
803         v1 = srclen ? ldub(src) : pad;
804         v2 = destlen ? ldub(dest) : pad;
805         if (v1 != v2) {
806             cc = (v1 < v2) ? 1 : 2;
807             break;
808         }
809     }
810
811     env->regs[r1 + 1] = destlen;
812     /* can't use srclen here, we trunc'ed it */
813     env->regs[r3 + 1] -= src - env->regs[r3];
814     env->regs[r1] = dest;
815     env->regs[r3] = src;
816
817     return cc;
818 }
819
820 /* checksum */
821 void HELPER(cksm)(uint32_t r1, uint32_t r2)
822 {
823     uint64_t src = get_address_31fix(r2);
824     uint64_t src_len = env->regs[(r2 + 1) & 15];
825     uint64_t cksm = (uint32_t)env->regs[r1];
826
827     while (src_len >= 4) {
828         cksm += ldl(src);
829
830         /* move to next word */
831         src_len -= 4;
832         src += 4;
833     }
834
835     switch (src_len) {
836     case 0:
837         break;
838     case 1:
839         cksm += ldub(src) << 24;
840         break;
841     case 2:
842         cksm += lduw(src) << 16;
843         break;
844     case 3:
845         cksm += lduw(src) << 16;
846         cksm += ldub(src + 2) << 8;
847         break;
848     }
849
850     /* indicate we've processed everything */
851     env->regs[r2] = src + src_len;
852     env->regs[(r2 + 1) & 15] = 0;
853
854     /* store result */
855     env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
856         ((uint32_t)cksm + (cksm >> 32));
857 }
858
859 void HELPER(unpk)(uint32_t len, uint64_t dest, uint64_t src)
860 {
861     int len_dest = len >> 4;
862     int len_src = len & 0xf;
863     uint8_t b;
864     int second_nibble = 0;
865
866     dest += len_dest;
867     src += len_src;
868
869     /* last byte is special, it only flips the nibbles */
870     b = ldub(src);
871     stb(dest, (b << 4) | (b >> 4));
872     src--;
873     len_src--;
874
875     /* now pad every nibble with 0xf0 */
876
877     while (len_dest > 0) {
878         uint8_t cur_byte = 0;
879
880         if (len_src > 0) {
881             cur_byte = ldub(src);
882         }
883
884         len_dest--;
885         dest--;
886
887         /* only advance one nibble at a time */
888         if (second_nibble) {
889             cur_byte >>= 4;
890             len_src--;
891             src--;
892         }
893         second_nibble = !second_nibble;
894
895         /* digit */
896         cur_byte = (cur_byte & 0xf);
897         /* zone bits */
898         cur_byte |= 0xf0;
899
900         stb(dest, cur_byte);
901     }
902 }
903
904 void HELPER(tr)(uint32_t len, uint64_t array, uint64_t trans)
905 {
906     int i;
907
908     for (i = 0; i <= len; i++) {
909         uint8_t byte = ldub(array + i);
910         uint8_t new_byte = ldub(trans + byte);
911
912         stb(array + i, new_byte);
913     }
914 }
915
916 #if !defined(CONFIG_USER_ONLY)
917 void HELPER(lctlg)(uint32_t r1, uint64_t a2, uint32_t r3)
918 {
919     int i;
920     uint64_t src = a2;
921
922     for (i = r1;; i = (i + 1) % 16) {
923         env->cregs[i] = ldq(src);
924         HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
925                    i, src, env->cregs[i]);
926         src += sizeof(uint64_t);
927
928         if (i == r3) {
929             break;
930         }
931     }
932
933     tlb_flush(env, 1);
934 }
935
936 void HELPER(lctl)(uint32_t r1, uint64_t a2, uint32_t r3)
937 {
938     int i;
939     uint64_t src = a2;
940
941     for (i = r1;; i = (i + 1) % 16) {
942         env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) | ldl(src);
943         src += sizeof(uint32_t);
944
945         if (i == r3) {
946             break;
947         }
948     }
949
950     tlb_flush(env, 1);
951 }
952
953 void HELPER(stctg)(uint32_t r1, uint64_t a2, uint32_t r3)
954 {
955     int i;
956     uint64_t dest = a2;
957
958     for (i = r1;; i = (i + 1) % 16) {
959         stq(dest, env->cregs[i]);
960         dest += sizeof(uint64_t);
961
962         if (i == r3) {
963             break;
964         }
965     }
966 }
967
968 void HELPER(stctl)(uint32_t r1, uint64_t a2, uint32_t r3)
969 {
970     int i;
971     uint64_t dest = a2;
972
973     for (i = r1;; i = (i + 1) % 16) {
974         stl(dest, env->cregs[i]);
975         dest += sizeof(uint32_t);
976
977         if (i == r3) {
978             break;
979         }
980     }
981 }
982
983 uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2)
984 {
985     /* XXX implement */
986
987     return 0;
988 }
989
990 /* insert storage key extended */
991 uint64_t HELPER(iske)(uint64_t r2)
992 {
993     uint64_t addr = get_address(0, 0, r2);
994
995     if (addr > ram_size) {
996         return 0;
997     }
998
999     return env->storage_keys[addr / TARGET_PAGE_SIZE];
1000 }
1001
1002 /* set storage key extended */
1003 void HELPER(sske)(uint32_t r1, uint64_t r2)
1004 {
1005     uint64_t addr = get_address(0, 0, r2);
1006
1007     if (addr > ram_size) {
1008         return;
1009     }
1010
1011     env->storage_keys[addr / TARGET_PAGE_SIZE] = r1;
1012 }
1013
1014 /* reset reference bit extended */
1015 uint32_t HELPER(rrbe)(uint32_t r1, uint64_t r2)
1016 {
1017     uint8_t re;
1018     uint8_t key;
1019
1020     if (r2 > ram_size) {
1021         return 0;
1022     }
1023
1024     key = env->storage_keys[r2 / TARGET_PAGE_SIZE];
1025     re = key & (SK_R | SK_C);
1026     env->storage_keys[r2 / TARGET_PAGE_SIZE] = (key & ~SK_R);
1027
1028     /*
1029      * cc
1030      *
1031      * 0  Reference bit zero; change bit zero
1032      * 1  Reference bit zero; change bit one
1033      * 2  Reference bit one; change bit zero
1034      * 3  Reference bit one; change bit one
1035      */
1036
1037     return re >> 1;
1038 }
1039
1040 /* compare and swap and purge */
1041 uint32_t HELPER(csp)(uint32_t r1, uint32_t r2)
1042 {
1043     uint32_t cc;
1044     uint32_t o1 = env->regs[r1];
1045     uint64_t a2 = get_address_31fix(r2) & ~3ULL;
1046     uint32_t o2 = ldl(a2);
1047
1048     if (o1 == o2) {
1049         stl(a2, env->regs[(r1 + 1) & 15]);
1050         if (env->regs[r2] & 0x3) {
1051             /* flush TLB / ALB */
1052             tlb_flush(env, 1);
1053         }
1054         cc = 0;
1055     } else {
1056         env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | o2;
1057         cc = 1;
1058     }
1059
1060     return cc;
1061 }
1062
1063 static uint32_t mvc_asc(int64_t l, uint64_t a1, uint64_t mode1, uint64_t a2,
1064                         uint64_t mode2)
1065 {
1066     target_ulong src, dest;
1067     int flags, cc = 0, i;
1068
1069     if (!l) {
1070         return 0;
1071     } else if (l > 256) {
1072         /* max 256 */
1073         l = 256;
1074         cc = 3;
1075     }
1076
1077     if (mmu_translate(env, a1 & TARGET_PAGE_MASK, 1, mode1, &dest, &flags)) {
1078         cpu_loop_exit(env);
1079     }
1080     dest |= a1 & ~TARGET_PAGE_MASK;
1081
1082     if (mmu_translate(env, a2 & TARGET_PAGE_MASK, 0, mode2, &src, &flags)) {
1083         cpu_loop_exit(env);
1084     }
1085     src |= a2 & ~TARGET_PAGE_MASK;
1086
1087     /* XXX replace w/ memcpy */
1088     for (i = 0; i < l; i++) {
1089         /* XXX be more clever */
1090         if ((((dest + i) & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) ||
1091             (((src + i) & TARGET_PAGE_MASK) != (src & TARGET_PAGE_MASK))) {
1092             mvc_asc(l - i, a1 + i, mode1, a2 + i, mode2);
1093             break;
1094         }
1095         stb_phys(dest + i, ldub_phys(src + i));
1096     }
1097
1098     return cc;
1099 }
1100
1101 uint32_t HELPER(mvcs)(uint64_t l, uint64_t a1, uint64_t a2)
1102 {
1103     HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1104                __func__, l, a1, a2);
1105
1106     return mvc_asc(l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY);
1107 }
1108
1109 uint32_t HELPER(mvcp)(uint64_t l, uint64_t a1, uint64_t a2)
1110 {
1111     HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1112                __func__, l, a1, a2);
1113
1114     return mvc_asc(l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY);
1115 }
1116
1117 /* invalidate pte */
1118 void HELPER(ipte)(uint64_t pte_addr, uint64_t vaddr)
1119 {
1120     uint64_t page = vaddr & TARGET_PAGE_MASK;
1121     uint64_t pte = 0;
1122
1123     /* XXX broadcast to other CPUs */
1124
1125     /* XXX Linux is nice enough to give us the exact pte address.
1126        According to spec we'd have to find it out ourselves */
1127     /* XXX Linux is fine with overwriting the pte, the spec requires
1128        us to only set the invalid bit */
1129     stq_phys(pte_addr, pte | _PAGE_INVALID);
1130
1131     /* XXX we exploit the fact that Linux passes the exact virtual
1132        address here - it's not obliged to! */
1133     tlb_flush_page(env, page);
1134
1135     /* XXX 31-bit hack */
1136     if (page & 0x80000000) {
1137         tlb_flush_page(env, page & ~0x80000000);
1138     } else {
1139         tlb_flush_page(env, page | 0x80000000);
1140     }
1141 }
1142
1143 /* flush local tlb */
1144 void HELPER(ptlb)(void)
1145 {
1146     tlb_flush(env, 1);
1147 }
1148
1149 /* store using real address */
1150 void HELPER(stura)(uint64_t addr, uint32_t v1)
1151 {
1152     stw_phys(get_address(0, 0, addr), v1);
1153 }
1154
1155 /* load real address */
1156 uint32_t HELPER(lra)(uint64_t addr, uint32_t r1)
1157 {
1158     uint32_t cc = 0;
1159     int old_exc = env->exception_index;
1160     uint64_t asc = env->psw.mask & PSW_MASK_ASC;
1161     uint64_t ret;
1162     int flags;
1163
1164     /* XXX incomplete - has more corner cases */
1165     if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
1166         program_interrupt(env, PGM_SPECIAL_OP, 2);
1167     }
1168
1169     env->exception_index = old_exc;
1170     if (mmu_translate(env, addr, 0, asc, &ret, &flags)) {
1171         cc = 3;
1172     }
1173     if (env->exception_index == EXCP_PGM) {
1174         ret = env->int_pgm_code | 0x80000000;
1175     } else {
1176         ret |= addr & ~TARGET_PAGE_MASK;
1177     }
1178     env->exception_index = old_exc;
1179
1180     if (!(env->psw.mask & PSW_MASK_64)) {
1181         env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
1182             (ret & 0xffffffffULL);
1183     } else {
1184         env->regs[r1] = ret;
1185     }
1186
1187     return cc;
1188 }
1189
1190 #endif
1191
1192 /* temporary wrappers */
1193 #if defined(CONFIG_USER_ONLY)
1194 #define ldub_data(addr) ldub_raw(addr)
1195 #define lduw_data(addr) lduw_raw(addr)
1196 #define ldl_data(addr) ldl_raw(addr)
1197 #define ldq_data(addr) ldq_raw(addr)
1198
1199 #define stb_data(addr, data) stb_raw(addr, data)
1200 #define stw_data(addr, data) stw_raw(addr, data)
1201 #define stl_data(addr, data) stl_raw(addr, data)
1202 #define stq_data(addr, data) stq_raw(addr, data)
1203 #endif
1204
1205 #define WRAP_LD(rettype, fn)                                    \
1206     rettype cpu_ ## fn(CPUS390XState *env1, target_ulong addr)  \
1207     {                                                           \
1208         CPUS390XState *saved_env;                               \
1209         rettype ret;                                            \
1210                                                                 \
1211         saved_env = env;                                        \
1212         env = env1;                                             \
1213         ret = fn(addr);                                         \
1214         env = saved_env;                                        \
1215         return ret;                                             \
1216     }
1217
1218 WRAP_LD(uint32_t, ldub_data)
1219 WRAP_LD(uint32_t, lduw_data)
1220 WRAP_LD(uint32_t, ldl_data)
1221 WRAP_LD(uint64_t, ldq_data)
1222 #undef WRAP_LD
1223
1224 #define WRAP_ST(datatype, fn)                                           \
1225     void cpu_ ## fn(CPUS390XState *env1, target_ulong addr, datatype val) \
1226     {                                                                   \
1227         CPUS390XState *saved_env;                                       \
1228                                                                         \
1229         saved_env = env;                                                \
1230         env = env1;                                                     \
1231         fn(addr, val);                                                  \
1232         env = saved_env;                                                \
1233     }
1234
1235 WRAP_ST(uint32_t, stb_data)
1236 WRAP_ST(uint32_t, stw_data)
1237 WRAP_ST(uint32_t, stl_data)
1238 WRAP_ST(uint64_t, stq_data)
1239 #undef WRAP_ST