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