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