]> Git Repo - qemu.git/blob - target/s390x/mem_helper.c
target/s390x: Use unwind data for helper_mvcle
[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     uintptr_t ra = GETPC();
473     int i;
474
475     for (i = r1;; i = (i + 1) % 16) {
476         env->aregs[i] = cpu_ldl_data_ra(env, a2, ra);
477         a2 += 4;
478
479         if (i == r3) {
480             break;
481         }
482     }
483 }
484
485 /* store access registers r1 to r3 in memory at a2 */
486 void HELPER(stam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
487 {
488     uintptr_t ra = GETPC();
489     int i;
490
491     for (i = r1;; i = (i + 1) % 16) {
492         cpu_stl_data_ra(env, a2, env->aregs[i], ra);
493         a2 += 4;
494
495         if (i == r3) {
496             break;
497         }
498     }
499 }
500
501 /* move long */
502 uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
503 {
504     uintptr_t ra = GETPC();
505     uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
506     uint64_t dest = get_address_31fix(env, r1);
507     uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
508     uint64_t src = get_address_31fix(env, r2);
509     uint8_t pad = env->regs[r2 + 1] >> 24;
510     uint8_t v;
511     uint32_t cc;
512
513     if (destlen == srclen) {
514         cc = 0;
515     } else if (destlen < srclen) {
516         cc = 1;
517     } else {
518         cc = 2;
519     }
520
521     if (srclen > destlen) {
522         srclen = destlen;
523     }
524
525     for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
526         v = cpu_ldub_data_ra(env, src, ra);
527         cpu_stb_data_ra(env, dest, v, ra);
528     }
529
530     for (; destlen; dest++, destlen--) {
531         cpu_stb_data_ra(env, dest, pad, ra);
532     }
533
534     env->regs[r1 + 1] = destlen;
535     /* can't use srclen here, we trunc'ed it */
536     env->regs[r2 + 1] -= src - env->regs[r2];
537     env->regs[r1] = dest;
538     env->regs[r2] = src;
539
540     return cc;
541 }
542
543 /* move long extended another memcopy insn with more bells and whistles */
544 uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
545                        uint32_t r3)
546 {
547     uintptr_t ra = GETPC();
548     uint64_t destlen = env->regs[r1 + 1];
549     uint64_t dest = env->regs[r1];
550     uint64_t srclen = env->regs[r3 + 1];
551     uint64_t src = env->regs[r3];
552     uint8_t pad = a2 & 0xff;
553     uint8_t v;
554     uint32_t cc;
555
556     if (!(env->psw.mask & PSW_MASK_64)) {
557         destlen = (uint32_t)destlen;
558         srclen = (uint32_t)srclen;
559         dest &= 0x7fffffff;
560         src &= 0x7fffffff;
561     }
562
563     if (destlen == srclen) {
564         cc = 0;
565     } else if (destlen < srclen) {
566         cc = 1;
567     } else {
568         cc = 2;
569     }
570
571     if (srclen > destlen) {
572         srclen = destlen;
573     }
574
575     for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
576         v = cpu_ldub_data_ra(env, src, ra);
577         cpu_stb_data_ra(env, dest, v, ra);
578     }
579
580     for (; destlen; dest++, destlen--) {
581         cpu_stb_data_ra(env, dest, pad, ra);
582     }
583
584     env->regs[r1 + 1] = destlen;
585     /* can't use srclen here, we trunc'ed it */
586     /* FIXME: 31-bit mode! */
587     env->regs[r3 + 1] -= src - env->regs[r3];
588     env->regs[r1] = dest;
589     env->regs[r3] = src;
590
591     return cc;
592 }
593
594 /* compare logical long extended memcompare insn with padding */
595 uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
596                        uint32_t r3)
597 {
598     uint64_t destlen = env->regs[r1 + 1];
599     uint64_t dest = get_address_31fix(env, r1);
600     uint64_t srclen = env->regs[r3 + 1];
601     uint64_t src = get_address_31fix(env, r3);
602     uint8_t pad = a2 & 0xff;
603     uint8_t v1 = 0, v2 = 0;
604     uint32_t cc = 0;
605
606     if (!(destlen || srclen)) {
607         return cc;
608     }
609
610     if (srclen > destlen) {
611         srclen = destlen;
612     }
613
614     for (; destlen || srclen; src++, dest++, destlen--, srclen--) {
615         v1 = srclen ? cpu_ldub_data(env, src) : pad;
616         v2 = destlen ? cpu_ldub_data(env, dest) : pad;
617         if (v1 != v2) {
618             cc = (v1 < v2) ? 1 : 2;
619             break;
620         }
621     }
622
623     env->regs[r1 + 1] = destlen;
624     /* can't use srclen here, we trunc'ed it */
625     env->regs[r3 + 1] -= src - env->regs[r3];
626     env->regs[r1] = dest;
627     env->regs[r3] = src;
628
629     return cc;
630 }
631
632 /* checksum */
633 uint64_t HELPER(cksm)(CPUS390XState *env, uint64_t r1,
634                       uint64_t src, uint64_t src_len)
635 {
636     uint64_t max_len, len;
637     uint64_t cksm = (uint32_t)r1;
638
639     /* Lest we fail to service interrupts in a timely manner, limit the
640        amount of work we're willing to do.  For now, let's cap at 8k.  */
641     max_len = (src_len > 0x2000 ? 0x2000 : src_len);
642
643     /* Process full words as available.  */
644     for (len = 0; len + 4 <= max_len; len += 4, src += 4) {
645         cksm += (uint32_t)cpu_ldl_data(env, src);
646     }
647
648     switch (max_len - len) {
649     case 1:
650         cksm += cpu_ldub_data(env, src) << 24;
651         len += 1;
652         break;
653     case 2:
654         cksm += cpu_lduw_data(env, src) << 16;
655         len += 2;
656         break;
657     case 3:
658         cksm += cpu_lduw_data(env, src) << 16;
659         cksm += cpu_ldub_data(env, src + 2) << 8;
660         len += 3;
661         break;
662     }
663
664     /* Fold the carry from the checksum.  Note that we can see carry-out
665        during folding more than once (but probably not more than twice).  */
666     while (cksm > 0xffffffffull) {
667         cksm = (uint32_t)cksm + (cksm >> 32);
668     }
669
670     /* Indicate whether or not we've processed everything.  */
671     env->cc_op = (len == src_len ? 0 : 3);
672
673     /* Return both cksm and processed length.  */
674     env->retxl = cksm;
675     return len;
676 }
677
678 void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest,
679                   uint64_t src)
680 {
681     int len_dest = len >> 4;
682     int len_src = len & 0xf;
683     uint8_t b;
684     int second_nibble = 0;
685
686     dest += len_dest;
687     src += len_src;
688
689     /* last byte is special, it only flips the nibbles */
690     b = cpu_ldub_data(env, src);
691     cpu_stb_data(env, dest, (b << 4) | (b >> 4));
692     src--;
693     len_src--;
694
695     /* now pad every nibble with 0xf0 */
696
697     while (len_dest > 0) {
698         uint8_t cur_byte = 0;
699
700         if (len_src > 0) {
701             cur_byte = cpu_ldub_data(env, src);
702         }
703
704         len_dest--;
705         dest--;
706
707         /* only advance one nibble at a time */
708         if (second_nibble) {
709             cur_byte >>= 4;
710             len_src--;
711             src--;
712         }
713         second_nibble = !second_nibble;
714
715         /* digit */
716         cur_byte = (cur_byte & 0xf);
717         /* zone bits */
718         cur_byte |= 0xf0;
719
720         cpu_stb_data(env, dest, cur_byte);
721     }
722 }
723
724 void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array,
725                 uint64_t trans)
726 {
727     int i;
728
729     for (i = 0; i <= len; i++) {
730         uint8_t byte = cpu_ldub_data(env, array + i);
731         uint8_t new_byte = cpu_ldub_data(env, trans + byte);
732
733         cpu_stb_data(env, array + i, new_byte);
734     }
735 }
736
737 uint64_t HELPER(tre)(CPUS390XState *env, uint64_t array,
738                      uint64_t len, uint64_t trans)
739 {
740     uint8_t end = env->regs[0] & 0xff;
741     uint64_t l = len;
742     uint64_t i;
743
744     if (!(env->psw.mask & PSW_MASK_64)) {
745         array &= 0x7fffffff;
746         l = (uint32_t)l;
747     }
748
749     /* Lest we fail to service interrupts in a timely manner, limit the
750        amount of work we're willing to do.  For now, let's cap at 8k.  */
751     if (l > 0x2000) {
752         l = 0x2000;
753         env->cc_op = 3;
754     } else {
755         env->cc_op = 0;
756     }
757
758     for (i = 0; i < l; i++) {
759         uint8_t byte, new_byte;
760
761         byte = cpu_ldub_data(env, array + i);
762
763         if (byte == end) {
764             env->cc_op = 1;
765             break;
766         }
767
768         new_byte = cpu_ldub_data(env, trans + byte);
769         cpu_stb_data(env, array + i, new_byte);
770     }
771
772     env->retxl = len - i;
773     return array + i;
774 }
775
776 uint32_t HELPER(trt)(CPUS390XState *env, uint32_t len, uint64_t array,
777                      uint64_t trans)
778 {
779     uint32_t cc = 0;
780     int i;
781
782     for (i = 0; i <= len; i++) {
783         uint8_t byte = cpu_ldub_data(env, array + i);
784         uint8_t sbyte = cpu_ldub_data(env, trans + byte);
785
786         if (sbyte != 0) {
787             env->regs[1] = array + i;
788             env->regs[2] = (env->regs[2] & ~0xff) | sbyte;
789             cc = (i == len) ? 2 : 1;
790             break;
791         }
792     }
793
794     return cc;
795 }
796
797 void HELPER(cdsg)(CPUS390XState *env, uint64_t addr,
798                   uint32_t r1, uint32_t r3)
799 {
800     uintptr_t ra = GETPC();
801     Int128 cmpv = int128_make128(env->regs[r1 + 1], env->regs[r1]);
802     Int128 newv = int128_make128(env->regs[r3 + 1], env->regs[r3]);
803     Int128 oldv;
804     bool fail;
805
806     if (parallel_cpus) {
807 #ifndef CONFIG_ATOMIC128
808         cpu_loop_exit_atomic(ENV_GET_CPU(env), ra);
809 #else
810         int mem_idx = cpu_mmu_index(env, false);
811         TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
812         oldv = helper_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, oi, ra);
813         fail = !int128_eq(oldv, cmpv);
814 #endif
815     } else {
816         uint64_t oldh, oldl;
817
818         oldh = cpu_ldq_data_ra(env, addr + 0, ra);
819         oldl = cpu_ldq_data_ra(env, addr + 8, ra);
820
821         oldv = int128_make128(oldl, oldh);
822         fail = !int128_eq(oldv, cmpv);
823         if (fail) {
824             newv = oldv;
825         }
826
827         cpu_stq_data_ra(env, addr + 0, int128_gethi(newv), ra);
828         cpu_stq_data_ra(env, addr + 8, int128_getlo(newv), ra);
829     }
830
831     env->cc_op = fail;
832     env->regs[r1] = int128_gethi(oldv);
833     env->regs[r1 + 1] = int128_getlo(oldv);
834 }
835
836 #if !defined(CONFIG_USER_ONLY)
837 void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
838 {
839     S390CPU *cpu = s390_env_get_cpu(env);
840     bool PERchanged = false;
841     int i;
842     uint64_t src = a2;
843     uint64_t val;
844
845     for (i = r1;; i = (i + 1) % 16) {
846         val = cpu_ldq_data(env, src);
847         if (env->cregs[i] != val && i >= 9 && i <= 11) {
848             PERchanged = true;
849         }
850         env->cregs[i] = val;
851         HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
852                    i, src, env->cregs[i]);
853         src += sizeof(uint64_t);
854
855         if (i == r3) {
856             break;
857         }
858     }
859
860     if (PERchanged && env->psw.mask & PSW_MASK_PER) {
861         s390_cpu_recompute_watchpoints(CPU(cpu));
862     }
863
864     tlb_flush(CPU(cpu));
865 }
866
867 void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
868 {
869     S390CPU *cpu = s390_env_get_cpu(env);
870     bool PERchanged = false;
871     int i;
872     uint64_t src = a2;
873     uint32_t val;
874
875     for (i = r1;; i = (i + 1) % 16) {
876         val = cpu_ldl_data(env, src);
877         if ((uint32_t)env->cregs[i] != val && i >= 9 && i <= 11) {
878             PERchanged = true;
879         }
880         env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) | val;
881         src += sizeof(uint32_t);
882
883         if (i == r3) {
884             break;
885         }
886     }
887
888     if (PERchanged && env->psw.mask & PSW_MASK_PER) {
889         s390_cpu_recompute_watchpoints(CPU(cpu));
890     }
891
892     tlb_flush(CPU(cpu));
893 }
894
895 void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
896 {
897     int i;
898     uint64_t dest = a2;
899
900     for (i = r1;; i = (i + 1) % 16) {
901         cpu_stq_data(env, dest, env->cregs[i]);
902         dest += sizeof(uint64_t);
903
904         if (i == r3) {
905             break;
906         }
907     }
908 }
909
910 void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
911 {
912     int i;
913     uint64_t dest = a2;
914
915     for (i = r1;; i = (i + 1) % 16) {
916         cpu_stl_data(env, dest, env->cregs[i]);
917         dest += sizeof(uint32_t);
918
919         if (i == r3) {
920             break;
921         }
922     }
923 }
924
925 uint32_t HELPER(testblock)(CPUS390XState *env, uint64_t real_addr)
926 {
927     CPUState *cs = CPU(s390_env_get_cpu(env));
928     uint64_t abs_addr;
929     int i;
930
931     real_addr = fix_address(env, real_addr);
932     abs_addr = mmu_real2abs(env, real_addr) & TARGET_PAGE_MASK;
933     if (!address_space_access_valid(&address_space_memory, abs_addr,
934                                     TARGET_PAGE_SIZE, true)) {
935         program_interrupt(env, PGM_ADDRESSING, 4);
936         return 1;
937     }
938
939     /* Check low-address protection */
940     if ((env->cregs[0] & CR0_LOWPROT) && real_addr < 0x2000) {
941         program_interrupt(env, PGM_PROTECTION, 4);
942         return 1;
943     }
944
945     for (i = 0; i < TARGET_PAGE_SIZE; i += 8) {
946         stq_phys(cs->as, abs_addr + i, 0);
947     }
948
949     return 0;
950 }
951
952 uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2)
953 {
954     /* XXX implement */
955
956     return 0;
957 }
958
959 /* insert storage key extended */
960 uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2)
961 {
962     static S390SKeysState *ss;
963     static S390SKeysClass *skeyclass;
964     uint64_t addr = get_address(env, 0, 0, r2);
965     uint8_t key;
966
967     if (addr > ram_size) {
968         return 0;
969     }
970
971     if (unlikely(!ss)) {
972         ss = s390_get_skeys_device();
973         skeyclass = S390_SKEYS_GET_CLASS(ss);
974     }
975
976     if (skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key)) {
977         return 0;
978     }
979     return key;
980 }
981
982 /* set storage key extended */
983 void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2)
984 {
985     static S390SKeysState *ss;
986     static S390SKeysClass *skeyclass;
987     uint64_t addr = get_address(env, 0, 0, r2);
988     uint8_t key;
989
990     if (addr > ram_size) {
991         return;
992     }
993
994     if (unlikely(!ss)) {
995         ss = s390_get_skeys_device();
996         skeyclass = S390_SKEYS_GET_CLASS(ss);
997     }
998
999     key = (uint8_t) r1;
1000     skeyclass->set_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
1001 }
1002
1003 /* reset reference bit extended */
1004 uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2)
1005 {
1006     static S390SKeysState *ss;
1007     static S390SKeysClass *skeyclass;
1008     uint8_t re, key;
1009
1010     if (r2 > ram_size) {
1011         return 0;
1012     }
1013
1014     if (unlikely(!ss)) {
1015         ss = s390_get_skeys_device();
1016         skeyclass = S390_SKEYS_GET_CLASS(ss);
1017     }
1018
1019     if (skeyclass->get_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
1020         return 0;
1021     }
1022
1023     re = key & (SK_R | SK_C);
1024     key &= ~SK_R;
1025
1026     if (skeyclass->set_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
1027         return 0;
1028     }
1029
1030     /*
1031      * cc
1032      *
1033      * 0  Reference bit zero; change bit zero
1034      * 1  Reference bit zero; change bit one
1035      * 2  Reference bit one; change bit zero
1036      * 3  Reference bit one; change bit one
1037      */
1038
1039     return re >> 1;
1040 }
1041
1042 /* compare and swap and purge */
1043 uint32_t HELPER(csp)(CPUS390XState *env, uint32_t r1, uint64_t r2)
1044 {
1045     S390CPU *cpu = s390_env_get_cpu(env);
1046     uint32_t cc;
1047     uint32_t o1 = env->regs[r1];
1048     uint64_t a2 = r2 & ~3ULL;
1049     uint32_t o2 = cpu_ldl_data(env, a2);
1050
1051     if (o1 == o2) {
1052         cpu_stl_data(env, a2, env->regs[(r1 + 1) & 15]);
1053         if (r2 & 0x3) {
1054             /* flush TLB / ALB */
1055             tlb_flush(CPU(cpu));
1056         }
1057         cc = 0;
1058     } else {
1059         env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | o2;
1060         cc = 1;
1061     }
1062
1063     return cc;
1064 }
1065
1066 uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
1067 {
1068     int cc = 0, i;
1069
1070     HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1071                __func__, l, a1, a2);
1072
1073     if (l > 256) {
1074         /* max 256 */
1075         l = 256;
1076         cc = 3;
1077     }
1078
1079     /* XXX replace w/ memcpy */
1080     for (i = 0; i < l; i++) {
1081         cpu_stb_secondary(env, a1 + i, cpu_ldub_primary(env, a2 + i));
1082     }
1083
1084     return cc;
1085 }
1086
1087 uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
1088 {
1089     int cc = 0, i;
1090
1091     HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1092                __func__, l, a1, a2);
1093
1094     if (l > 256) {
1095         /* max 256 */
1096         l = 256;
1097         cc = 3;
1098     }
1099
1100     /* XXX replace w/ memcpy */
1101     for (i = 0; i < l; i++) {
1102         cpu_stb_primary(env, a1 + i, cpu_ldub_secondary(env, a2 + i));
1103     }
1104
1105     return cc;
1106 }
1107
1108 /* invalidate pte */
1109 void HELPER(ipte)(CPUS390XState *env, uint64_t pte_addr, uint64_t vaddr)
1110 {
1111     CPUState *cs = CPU(s390_env_get_cpu(env));
1112     uint64_t page = vaddr & TARGET_PAGE_MASK;
1113     uint64_t pte = 0;
1114
1115     /* XXX broadcast to other CPUs */
1116
1117     /* XXX Linux is nice enough to give us the exact pte address.
1118        According to spec we'd have to find it out ourselves */
1119     /* XXX Linux is fine with overwriting the pte, the spec requires
1120        us to only set the invalid bit */
1121     stq_phys(cs->as, pte_addr, pte | _PAGE_INVALID);
1122
1123     /* XXX we exploit the fact that Linux passes the exact virtual
1124        address here - it's not obliged to! */
1125     tlb_flush_page(cs, page);
1126
1127     /* XXX 31-bit hack */
1128     if (page & 0x80000000) {
1129         tlb_flush_page(cs, page & ~0x80000000);
1130     } else {
1131         tlb_flush_page(cs, page | 0x80000000);
1132     }
1133 }
1134
1135 /* flush local tlb */
1136 void HELPER(ptlb)(CPUS390XState *env)
1137 {
1138     S390CPU *cpu = s390_env_get_cpu(env);
1139
1140     tlb_flush(CPU(cpu));
1141 }
1142
1143 /* load using real address */
1144 uint64_t HELPER(lura)(CPUS390XState *env, uint64_t addr)
1145 {
1146     CPUState *cs = CPU(s390_env_get_cpu(env));
1147
1148     return (uint32_t)ldl_phys(cs->as, get_address(env, 0, 0, addr));
1149 }
1150
1151 uint64_t HELPER(lurag)(CPUS390XState *env, uint64_t addr)
1152 {
1153     CPUState *cs = CPU(s390_env_get_cpu(env));
1154
1155     return ldq_phys(cs->as, get_address(env, 0, 0, addr));
1156 }
1157
1158 /* store using real address */
1159 void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint64_t v1)
1160 {
1161     CPUState *cs = CPU(s390_env_get_cpu(env));
1162
1163     stl_phys(cs->as, get_address(env, 0, 0, addr), (uint32_t)v1);
1164
1165     if ((env->psw.mask & PSW_MASK_PER) &&
1166         (env->cregs[9] & PER_CR9_EVENT_STORE) &&
1167         (env->cregs[9] & PER_CR9_EVENT_STORE_REAL)) {
1168         /* PSW is saved just before calling the helper.  */
1169         env->per_address = env->psw.addr;
1170         env->per_perc_atmid = PER_CODE_EVENT_STORE_REAL | get_per_atmid(env);
1171     }
1172 }
1173
1174 void HELPER(sturg)(CPUS390XState *env, uint64_t addr, uint64_t v1)
1175 {
1176     CPUState *cs = CPU(s390_env_get_cpu(env));
1177
1178     stq_phys(cs->as, get_address(env, 0, 0, addr), v1);
1179
1180     if ((env->psw.mask & PSW_MASK_PER) &&
1181         (env->cregs[9] & PER_CR9_EVENT_STORE) &&
1182         (env->cregs[9] & PER_CR9_EVENT_STORE_REAL)) {
1183         /* PSW is saved just before calling the helper.  */
1184         env->per_address = env->psw.addr;
1185         env->per_perc_atmid = PER_CODE_EVENT_STORE_REAL | get_per_atmid(env);
1186     }
1187 }
1188
1189 /* load real address */
1190 uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr)
1191 {
1192     CPUState *cs = CPU(s390_env_get_cpu(env));
1193     uint32_t cc = 0;
1194     int old_exc = cs->exception_index;
1195     uint64_t asc = env->psw.mask & PSW_MASK_ASC;
1196     uint64_t ret;
1197     int flags;
1198
1199     /* XXX incomplete - has more corner cases */
1200     if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
1201         program_interrupt(env, PGM_SPECIAL_OP, 2);
1202     }
1203
1204     cs->exception_index = old_exc;
1205     if (mmu_translate(env, addr, 0, asc, &ret, &flags, true)) {
1206         cc = 3;
1207     }
1208     if (cs->exception_index == EXCP_PGM) {
1209         ret = env->int_pgm_code | 0x80000000;
1210     } else {
1211         ret |= addr & ~TARGET_PAGE_MASK;
1212     }
1213     cs->exception_index = old_exc;
1214
1215     env->cc_op = cc;
1216     return ret;
1217 }
1218 #endif
1219
1220 /* execute instruction
1221    this instruction executes an insn modified with the contents of r1
1222    it does not change the executed instruction in memory
1223    it does not change the program counter
1224    in other words: tricky...
1225    currently implemented by interpreting the cases it is most commonly used.
1226 */
1227 uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1,
1228                     uint64_t addr, uint64_t ret)
1229 {
1230     S390CPU *cpu = s390_env_get_cpu(env);
1231     uint16_t insn = cpu_lduw_code(env, addr);
1232
1233     HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __func__, v1, addr,
1234                insn);
1235     if ((insn & 0xf0ff) == 0xd000) {
1236         uint32_t l, insn2, b1, b2, d1, d2;
1237
1238         l = v1 & 0xff;
1239         insn2 = cpu_ldl_code(env, addr + 2);
1240         b1 = (insn2 >> 28) & 0xf;
1241         b2 = (insn2 >> 12) & 0xf;
1242         d1 = (insn2 >> 16) & 0xfff;
1243         d2 = insn2 & 0xfff;
1244         switch (insn & 0xf00) {
1245         case 0x200:
1246             do_helper_mvc(env, l, get_address(env, 0, b1, d1),
1247                           get_address(env, 0, b2, d2), 0);
1248             break;
1249         case 0x400:
1250             cc = do_helper_nc(env, l, get_address(env, 0, b1, d1),
1251                               get_address(env, 0, b2, d2), 0);
1252             break;
1253         case 0x500:
1254             cc = do_helper_clc(env, l, get_address(env, 0, b1, d1),
1255                                get_address(env, 0, b2, d2), 0);
1256             break;
1257         case 0x600:
1258             cc = do_helper_oc(env, l, get_address(env, 0, b1, d1),
1259                               get_address(env, 0, b2, d2), 0);
1260             break;
1261         case 0x700:
1262             cc = do_helper_xc(env, l, get_address(env, 0, b1, d1),
1263                               get_address(env, 0, b2, d2), 0);
1264             break;
1265         case 0xc00:
1266             helper_tr(env, l, get_address(env, 0, b1, d1),
1267                       get_address(env, 0, b2, d2));
1268             break;
1269         case 0xd00:
1270             cc = helper_trt(env, l, get_address(env, 0, b1, d1),
1271                             get_address(env, 0, b2, d2));
1272             break;
1273         default:
1274             goto abort;
1275         }
1276     } else if ((insn & 0xff00) == 0x0a00) {
1277         /* supervisor call */
1278         HELPER_LOG("%s: svc %ld via execute\n", __func__, (insn | v1) & 0xff);
1279         env->psw.addr = ret - 4;
1280         env->int_svc_code = (insn | v1) & 0xff;
1281         env->int_svc_ilen = 4;
1282         helper_exception(env, EXCP_SVC);
1283     } else if ((insn & 0xff00) == 0xbf00) {
1284         uint32_t insn2, r1, r3, b2, d2;
1285
1286         insn2 = cpu_ldl_code(env, addr + 2);
1287         r1 = (insn2 >> 20) & 0xf;
1288         r3 = (insn2 >> 16) & 0xf;
1289         b2 = (insn2 >> 12) & 0xf;
1290         d2 = insn2 & 0xfff;
1291         cc = helper_icm(env, r1, get_address(env, 0, b2, d2), r3);
1292     } else {
1293     abort:
1294         cpu_abort(CPU(cpu),
1295                   "EXECUTE on instruction prefix 0x%x not implemented\n",
1296                   insn);
1297     }
1298     return cc;
1299 }
This page took 0.097678 seconds and 4 git commands to generate.