]> Git Repo - qemu.git/blob - target/s390x/mem_helper.c
target/s390x: Fix some helper_ex problems
[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     uintptr_t ra = GETPC();
599     uint64_t destlen = env->regs[r1 + 1];
600     uint64_t dest = get_address_31fix(env, r1);
601     uint64_t srclen = env->regs[r3 + 1];
602     uint64_t src = get_address_31fix(env, r3);
603     uint8_t pad = a2 & 0xff;
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         uint8_t v1 = srclen ? cpu_ldub_data_ra(env, src, ra) : pad;
616         uint8_t v2 = destlen ? cpu_ldub_data_ra(env, dest, ra) : 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     uintptr_t ra = GETPC();
637     uint64_t max_len, len;
638     uint64_t cksm = (uint32_t)r1;
639
640     /* Lest we fail to service interrupts in a timely manner, limit the
641        amount of work we're willing to do.  For now, let's cap at 8k.  */
642     max_len = (src_len > 0x2000 ? 0x2000 : src_len);
643
644     /* Process full words as available.  */
645     for (len = 0; len + 4 <= max_len; len += 4, src += 4) {
646         cksm += (uint32_t)cpu_ldl_data_ra(env, src, ra);
647     }
648
649     switch (max_len - len) {
650     case 1:
651         cksm += cpu_ldub_data_ra(env, src, ra) << 24;
652         len += 1;
653         break;
654     case 2:
655         cksm += cpu_lduw_data_ra(env, src, ra) << 16;
656         len += 2;
657         break;
658     case 3:
659         cksm += cpu_lduw_data_ra(env, src, ra) << 16;
660         cksm += cpu_ldub_data_ra(env, src + 2, ra) << 8;
661         len += 3;
662         break;
663     }
664
665     /* Fold the carry from the checksum.  Note that we can see carry-out
666        during folding more than once (but probably not more than twice).  */
667     while (cksm > 0xffffffffull) {
668         cksm = (uint32_t)cksm + (cksm >> 32);
669     }
670
671     /* Indicate whether or not we've processed everything.  */
672     env->cc_op = (len == src_len ? 0 : 3);
673
674     /* Return both cksm and processed length.  */
675     env->retxl = cksm;
676     return len;
677 }
678
679 void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest,
680                   uint64_t src)
681 {
682     uintptr_t ra = GETPC();
683     int len_dest = len >> 4;
684     int len_src = len & 0xf;
685     uint8_t b;
686     int second_nibble = 0;
687
688     dest += len_dest;
689     src += len_src;
690
691     /* last byte is special, it only flips the nibbles */
692     b = cpu_ldub_data_ra(env, src, ra);
693     cpu_stb_data_ra(env, dest, (b << 4) | (b >> 4), ra);
694     src--;
695     len_src--;
696
697     /* now pad every nibble with 0xf0 */
698
699     while (len_dest > 0) {
700         uint8_t cur_byte = 0;
701
702         if (len_src > 0) {
703             cur_byte = cpu_ldub_data_ra(env, src, ra);
704         }
705
706         len_dest--;
707         dest--;
708
709         /* only advance one nibble at a time */
710         if (second_nibble) {
711             cur_byte >>= 4;
712             len_src--;
713             src--;
714         }
715         second_nibble = !second_nibble;
716
717         /* digit */
718         cur_byte = (cur_byte & 0xf);
719         /* zone bits */
720         cur_byte |= 0xf0;
721
722         cpu_stb_data_ra(env, dest, cur_byte, ra);
723     }
724 }
725
726 static void do_helper_tr(CPUS390XState *env, uint32_t len, uint64_t array,
727                          uint64_t trans, uintptr_t ra)
728 {
729     uint32_t i;
730
731     for (i = 0; i <= len; i++) {
732         uint8_t byte = cpu_ldub_data_ra(env, array + i, ra);
733         uint8_t new_byte = cpu_ldub_data_ra(env, trans + byte, ra);
734         cpu_stb_data_ra(env, array + i, new_byte, ra);
735     }
736 }
737
738 void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array,
739                 uint64_t trans)
740 {
741     return do_helper_tr(env, len, array, trans, GETPC());
742 }
743
744 uint64_t HELPER(tre)(CPUS390XState *env, uint64_t array,
745                      uint64_t len, uint64_t trans)
746 {
747     uintptr_t ra = GETPC();
748     uint8_t end = env->regs[0] & 0xff;
749     uint64_t l = len;
750     uint64_t i;
751     uint32_t cc = 0;
752
753     if (!(env->psw.mask & PSW_MASK_64)) {
754         array &= 0x7fffffff;
755         l = (uint32_t)l;
756     }
757
758     /* Lest we fail to service interrupts in a timely manner, limit the
759        amount of work we're willing to do.  For now, let's cap at 8k.  */
760     if (l > 0x2000) {
761         l = 0x2000;
762         cc = 3;
763     }
764
765     for (i = 0; i < l; i++) {
766         uint8_t byte, new_byte;
767
768         byte = cpu_ldub_data_ra(env, array + i, ra);
769
770         if (byte == end) {
771             cc = 1;
772             break;
773         }
774
775         new_byte = cpu_ldub_data_ra(env, trans + byte, ra);
776         cpu_stb_data_ra(env, array + i, new_byte, ra);
777     }
778
779     env->cc_op = cc;
780     env->retxl = len - i;
781     return array + i;
782 }
783
784 static uint32_t do_helper_trt(CPUS390XState *env, uint32_t len, uint64_t array,
785                               uint64_t trans, uintptr_t ra)
786 {
787     uint32_t i;
788
789     for (i = 0; i <= len; i++) {
790         uint8_t byte = cpu_ldub_data_ra(env, array + i, ra);
791         uint8_t sbyte = cpu_ldub_data_ra(env, trans + byte, ra);
792
793         if (sbyte != 0) {
794             env->regs[1] = array + i;
795             env->regs[2] = deposit64(env->regs[2], 0, 8, sbyte);
796             return (i == len) ? 2 : 1;
797         }
798     }
799
800     return 0;
801 }
802
803 uint32_t HELPER(trt)(CPUS390XState *env, uint32_t len, uint64_t array,
804                      uint64_t trans)
805 {
806     return do_helper_trt(env, len, array, trans, GETPC());
807 }
808
809 void HELPER(cdsg)(CPUS390XState *env, uint64_t addr,
810                   uint32_t r1, uint32_t r3)
811 {
812     uintptr_t ra = GETPC();
813     Int128 cmpv = int128_make128(env->regs[r1 + 1], env->regs[r1]);
814     Int128 newv = int128_make128(env->regs[r3 + 1], env->regs[r3]);
815     Int128 oldv;
816     bool fail;
817
818     if (parallel_cpus) {
819 #ifndef CONFIG_ATOMIC128
820         cpu_loop_exit_atomic(ENV_GET_CPU(env), ra);
821 #else
822         int mem_idx = cpu_mmu_index(env, false);
823         TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx);
824         oldv = helper_atomic_cmpxchgo_be_mmu(env, addr, cmpv, newv, oi, ra);
825         fail = !int128_eq(oldv, cmpv);
826 #endif
827     } else {
828         uint64_t oldh, oldl;
829
830         oldh = cpu_ldq_data_ra(env, addr + 0, ra);
831         oldl = cpu_ldq_data_ra(env, addr + 8, ra);
832
833         oldv = int128_make128(oldl, oldh);
834         fail = !int128_eq(oldv, cmpv);
835         if (fail) {
836             newv = oldv;
837         }
838
839         cpu_stq_data_ra(env, addr + 0, int128_gethi(newv), ra);
840         cpu_stq_data_ra(env, addr + 8, int128_getlo(newv), ra);
841     }
842
843     env->cc_op = fail;
844     env->regs[r1] = int128_gethi(oldv);
845     env->regs[r1 + 1] = int128_getlo(oldv);
846 }
847
848 #if !defined(CONFIG_USER_ONLY)
849 void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
850 {
851     uintptr_t ra = GETPC();
852     S390CPU *cpu = s390_env_get_cpu(env);
853     bool PERchanged = false;
854     uint64_t src = a2;
855     uint32_t i;
856
857     for (i = r1;; i = (i + 1) % 16) {
858         uint64_t val = cpu_ldq_data_ra(env, src, ra);
859         if (env->cregs[i] != val && i >= 9 && i <= 11) {
860             PERchanged = true;
861         }
862         env->cregs[i] = val;
863         HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
864                    i, src, val);
865         src += sizeof(uint64_t);
866
867         if (i == r3) {
868             break;
869         }
870     }
871
872     if (PERchanged && env->psw.mask & PSW_MASK_PER) {
873         s390_cpu_recompute_watchpoints(CPU(cpu));
874     }
875
876     tlb_flush(CPU(cpu));
877 }
878
879 void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
880 {
881     uintptr_t ra = GETPC();
882     S390CPU *cpu = s390_env_get_cpu(env);
883     bool PERchanged = false;
884     uint64_t src = a2;
885     uint32_t i;
886
887     for (i = r1;; i = (i + 1) % 16) {
888         uint32_t val = cpu_ldl_data_ra(env, src, ra);
889         if ((uint32_t)env->cregs[i] != val && i >= 9 && i <= 11) {
890             PERchanged = true;
891         }
892         env->cregs[i] = deposit64(env->cregs[i], 0, 32, val);
893         HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%x\n", i, src, val);
894         src += sizeof(uint32_t);
895
896         if (i == r3) {
897             break;
898         }
899     }
900
901     if (PERchanged && env->psw.mask & PSW_MASK_PER) {
902         s390_cpu_recompute_watchpoints(CPU(cpu));
903     }
904
905     tlb_flush(CPU(cpu));
906 }
907
908 void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
909 {
910     uintptr_t ra = GETPC();
911     uint64_t dest = a2;
912     uint32_t i;
913
914     for (i = r1;; i = (i + 1) % 16) {
915         cpu_stq_data_ra(env, dest, env->cregs[i], ra);
916         dest += sizeof(uint64_t);
917
918         if (i == r3) {
919             break;
920         }
921     }
922 }
923
924 void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
925 {
926     uintptr_t ra = GETPC();
927     uint64_t dest = a2;
928     uint32_t i;
929
930     for (i = r1;; i = (i + 1) % 16) {
931         cpu_stl_data_ra(env, dest, env->cregs[i], ra);
932         dest += sizeof(uint32_t);
933
934         if (i == r3) {
935             break;
936         }
937     }
938 }
939
940 uint32_t HELPER(testblock)(CPUS390XState *env, uint64_t real_addr)
941 {
942     uintptr_t ra = GETPC();
943     CPUState *cs = CPU(s390_env_get_cpu(env));
944     uint64_t abs_addr;
945     int i;
946
947     real_addr = fix_address(env, real_addr);
948     abs_addr = mmu_real2abs(env, real_addr) & TARGET_PAGE_MASK;
949     if (!address_space_access_valid(&address_space_memory, abs_addr,
950                                     TARGET_PAGE_SIZE, true)) {
951         cpu_restore_state(cs, ra);
952         program_interrupt(env, PGM_ADDRESSING, 4);
953         return 1;
954     }
955
956     /* Check low-address protection */
957     if ((env->cregs[0] & CR0_LOWPROT) && real_addr < 0x2000) {
958         cpu_restore_state(cs, ra);
959         program_interrupt(env, PGM_PROTECTION, 4);
960         return 1;
961     }
962
963     for (i = 0; i < TARGET_PAGE_SIZE; i += 8) {
964         stq_phys(cs->as, abs_addr + i, 0);
965     }
966
967     return 0;
968 }
969
970 uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2)
971 {
972     /* XXX implement */
973     return 0;
974 }
975
976 /* insert storage key extended */
977 uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2)
978 {
979     static S390SKeysState *ss;
980     static S390SKeysClass *skeyclass;
981     uint64_t addr = get_address(env, 0, 0, r2);
982     uint8_t key;
983
984     if (addr > ram_size) {
985         return 0;
986     }
987
988     if (unlikely(!ss)) {
989         ss = s390_get_skeys_device();
990         skeyclass = S390_SKEYS_GET_CLASS(ss);
991     }
992
993     if (skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key)) {
994         return 0;
995     }
996     return key;
997 }
998
999 /* set storage key extended */
1000 void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2)
1001 {
1002     static S390SKeysState *ss;
1003     static S390SKeysClass *skeyclass;
1004     uint64_t addr = get_address(env, 0, 0, r2);
1005     uint8_t key;
1006
1007     if (addr > ram_size) {
1008         return;
1009     }
1010
1011     if (unlikely(!ss)) {
1012         ss = s390_get_skeys_device();
1013         skeyclass = S390_SKEYS_GET_CLASS(ss);
1014     }
1015
1016     key = (uint8_t) r1;
1017     skeyclass->set_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
1018 }
1019
1020 /* reset reference bit extended */
1021 uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2)
1022 {
1023     static S390SKeysState *ss;
1024     static S390SKeysClass *skeyclass;
1025     uint8_t re, key;
1026
1027     if (r2 > ram_size) {
1028         return 0;
1029     }
1030
1031     if (unlikely(!ss)) {
1032         ss = s390_get_skeys_device();
1033         skeyclass = S390_SKEYS_GET_CLASS(ss);
1034     }
1035
1036     if (skeyclass->get_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
1037         return 0;
1038     }
1039
1040     re = key & (SK_R | SK_C);
1041     key &= ~SK_R;
1042
1043     if (skeyclass->set_skeys(ss, r2 / TARGET_PAGE_SIZE, 1, &key)) {
1044         return 0;
1045     }
1046
1047     /*
1048      * cc
1049      *
1050      * 0  Reference bit zero; change bit zero
1051      * 1  Reference bit zero; change bit one
1052      * 2  Reference bit one; change bit zero
1053      * 3  Reference bit one; change bit one
1054      */
1055
1056     return re >> 1;
1057 }
1058
1059 /* compare and swap and purge */
1060 uint32_t HELPER(csp)(CPUS390XState *env, uint32_t r1, uint64_t r2)
1061 {
1062     S390CPU *cpu = s390_env_get_cpu(env);
1063     uint32_t cc;
1064     uint32_t o1 = env->regs[r1];
1065     uint64_t a2 = r2 & ~3ULL;
1066     uint32_t o2 = cpu_ldl_data(env, a2);
1067
1068     if (o1 == o2) {
1069         cpu_stl_data(env, a2, env->regs[(r1 + 1) & 15]);
1070         if (r2 & 0x3) {
1071             /* flush TLB / ALB */
1072             tlb_flush(CPU(cpu));
1073         }
1074         cc = 0;
1075     } else {
1076         env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | o2;
1077         cc = 1;
1078     }
1079
1080     return cc;
1081 }
1082
1083 uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
1084 {
1085     uintptr_t ra = GETPC();
1086     int cc = 0, i;
1087
1088     HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1089                __func__, l, a1, a2);
1090
1091     if (l > 256) {
1092         /* max 256 */
1093         l = 256;
1094         cc = 3;
1095     }
1096
1097     /* XXX replace w/ memcpy */
1098     for (i = 0; i < l; i++) {
1099         uint8_t x = cpu_ldub_primary_ra(env, a2 + i, ra);
1100         cpu_stb_secondary_ra(env, a1 + i, x, ra);
1101     }
1102
1103     return cc;
1104 }
1105
1106 uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
1107 {
1108     uintptr_t ra = GETPC();
1109     int cc = 0, i;
1110
1111     HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1112                __func__, l, a1, a2);
1113
1114     if (l > 256) {
1115         /* max 256 */
1116         l = 256;
1117         cc = 3;
1118     }
1119
1120     /* XXX replace w/ memcpy */
1121     for (i = 0; i < l; i++) {
1122         uint8_t x = cpu_ldub_secondary_ra(env, a2 + i, ra);
1123         cpu_stb_primary_ra(env, a1 + i, x, ra);
1124     }
1125
1126     return cc;
1127 }
1128
1129 /* invalidate pte */
1130 void HELPER(ipte)(CPUS390XState *env, uint64_t pte_addr, uint64_t vaddr)
1131 {
1132     CPUState *cs = CPU(s390_env_get_cpu(env));
1133     uint64_t page = vaddr & TARGET_PAGE_MASK;
1134     uint64_t pte = 0;
1135
1136     /* XXX broadcast to other CPUs */
1137
1138     /* XXX Linux is nice enough to give us the exact pte address.
1139        According to spec we'd have to find it out ourselves */
1140     /* XXX Linux is fine with overwriting the pte, the spec requires
1141        us to only set the invalid bit */
1142     stq_phys(cs->as, pte_addr, pte | _PAGE_INVALID);
1143
1144     /* XXX we exploit the fact that Linux passes the exact virtual
1145        address here - it's not obliged to! */
1146     tlb_flush_page(cs, page);
1147
1148     /* XXX 31-bit hack */
1149     if (page & 0x80000000) {
1150         tlb_flush_page(cs, page & ~0x80000000);
1151     } else {
1152         tlb_flush_page(cs, page | 0x80000000);
1153     }
1154 }
1155
1156 /* flush local tlb */
1157 void HELPER(ptlb)(CPUS390XState *env)
1158 {
1159     S390CPU *cpu = s390_env_get_cpu(env);
1160
1161     tlb_flush(CPU(cpu));
1162 }
1163
1164 /* load using real address */
1165 uint64_t HELPER(lura)(CPUS390XState *env, uint64_t addr)
1166 {
1167     CPUState *cs = CPU(s390_env_get_cpu(env));
1168
1169     return (uint32_t)ldl_phys(cs->as, get_address(env, 0, 0, addr));
1170 }
1171
1172 uint64_t HELPER(lurag)(CPUS390XState *env, uint64_t addr)
1173 {
1174     CPUState *cs = CPU(s390_env_get_cpu(env));
1175
1176     return ldq_phys(cs->as, get_address(env, 0, 0, addr));
1177 }
1178
1179 /* store using real address */
1180 void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint64_t v1)
1181 {
1182     CPUState *cs = CPU(s390_env_get_cpu(env));
1183
1184     stl_phys(cs->as, get_address(env, 0, 0, addr), (uint32_t)v1);
1185
1186     if ((env->psw.mask & PSW_MASK_PER) &&
1187         (env->cregs[9] & PER_CR9_EVENT_STORE) &&
1188         (env->cregs[9] & PER_CR9_EVENT_STORE_REAL)) {
1189         /* PSW is saved just before calling the helper.  */
1190         env->per_address = env->psw.addr;
1191         env->per_perc_atmid = PER_CODE_EVENT_STORE_REAL | get_per_atmid(env);
1192     }
1193 }
1194
1195 void HELPER(sturg)(CPUS390XState *env, uint64_t addr, uint64_t v1)
1196 {
1197     CPUState *cs = CPU(s390_env_get_cpu(env));
1198
1199     stq_phys(cs->as, get_address(env, 0, 0, addr), v1);
1200
1201     if ((env->psw.mask & PSW_MASK_PER) &&
1202         (env->cregs[9] & PER_CR9_EVENT_STORE) &&
1203         (env->cregs[9] & PER_CR9_EVENT_STORE_REAL)) {
1204         /* PSW is saved just before calling the helper.  */
1205         env->per_address = env->psw.addr;
1206         env->per_perc_atmid = PER_CODE_EVENT_STORE_REAL | get_per_atmid(env);
1207     }
1208 }
1209
1210 /* load real address */
1211 uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr)
1212 {
1213     CPUState *cs = CPU(s390_env_get_cpu(env));
1214     uint32_t cc = 0;
1215     uint64_t asc = env->psw.mask & PSW_MASK_ASC;
1216     uint64_t ret;
1217     int old_exc, flags;
1218
1219     /* XXX incomplete - has more corner cases */
1220     if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
1221         cpu_restore_state(cs, GETPC());
1222         program_interrupt(env, PGM_SPECIAL_OP, 2);
1223     }
1224
1225     old_exc = cs->exception_index;
1226     if (mmu_translate(env, addr, 0, asc, &ret, &flags, true)) {
1227         cc = 3;
1228     }
1229     if (cs->exception_index == EXCP_PGM) {
1230         ret = env->int_pgm_code | 0x80000000;
1231     } else {
1232         ret |= addr & ~TARGET_PAGE_MASK;
1233     }
1234     cs->exception_index = old_exc;
1235
1236     env->cc_op = cc;
1237     return ret;
1238 }
1239 #endif
1240
1241 /* execute instruction
1242    this instruction executes an insn modified with the contents of r1
1243    it does not change the executed instruction in memory
1244    it does not change the program counter
1245    in other words: tricky...
1246    currently implemented by interpreting the cases it is most commonly used.
1247 */
1248 void HELPER(ex)(CPUS390XState *env, uint32_t ilen, uint64_t r1, uint64_t addr)
1249 {
1250     S390CPU *cpu = s390_env_get_cpu(env);
1251     uint64_t insn = cpu_lduw_code(env, addr);
1252     uint8_t opc = insn >> 8;
1253
1254     /* Or in the contents of R1[56:63].  */
1255     insn |= r1 & 0xff;
1256
1257     /* Load the rest of the instruction.  */
1258     insn <<= 48;
1259     switch (get_ilen(opc)) {
1260     case 2:
1261         break;
1262     case 4:
1263         insn |= (uint64_t)cpu_lduw_code(env, addr + 2) << 32;
1264         break;
1265     case 6:
1266         insn |= (uint64_t)(uint32_t)cpu_ldl_code(env, addr + 2) << 16;
1267         break;
1268     default:
1269         g_assert_not_reached();
1270     }
1271
1272     HELPER_LOG("%s: addr 0x%lx insn 0x%" PRIx64 "\n", __func__, addr, insn);
1273
1274     if ((opc & 0xf0) == 0xd0) {
1275         uint32_t l, b1, b2, d1, d2;
1276
1277         l = extract64(insn, 48, 8);
1278         b1 = extract64(insn, 44, 4);
1279         b2 = extract64(insn, 28, 4);
1280         d1 = extract64(insn, 32, 12);
1281         d2 = extract64(insn, 16, 12);
1282         switch (opc & 0xf) {
1283         case 0x2:
1284             do_helper_mvc(env, l, get_address(env, 0, b1, d1),
1285                           get_address(env, 0, b2, d2), 0);
1286             return;
1287         case 0x4:
1288             env->cc_op = do_helper_nc(env, l, get_address(env, 0, b1, d1),
1289                                       get_address(env, 0, b2, d2), 0);
1290             return;
1291         case 0x5:
1292             env->cc_op = do_helper_clc(env, l, get_address(env, 0, b1, d1),
1293                                        get_address(env, 0, b2, d2), 0);
1294             return;
1295         case 0x6:
1296             env->cc_op = do_helper_oc(env, l, get_address(env, 0, b1, d1),
1297                                       get_address(env, 0, b2, d2), 0);
1298             return;
1299         case 0x7:
1300             env->cc_op = do_helper_xc(env, l, get_address(env, 0, b1, d1),
1301                                       get_address(env, 0, b2, d2), 0);
1302             return;
1303         case 0xc:
1304             do_helper_tr(env, l, get_address(env, 0, b1, d1),
1305                          get_address(env, 0, b2, d2), 0);
1306             return;
1307         case 0xd:
1308             env->cc_op = do_helper_trt(env, l, get_address(env, 0, b1, d1),
1309                                        get_address(env, 0, b2, d2), 0);
1310             return;
1311         }
1312     } else if (opc == 0x0a) {
1313         /* supervisor call */
1314         env->int_svc_code = extract64(insn, 48, 8);
1315         env->int_svc_ilen = ilen;
1316         helper_exception(env, EXCP_SVC);
1317         return;
1318     } else if (opc == 0xbf) {
1319         uint32_t r1, r3, b2, d2;
1320
1321         r1 = extract64(insn, 52, 4);
1322         r3 = extract64(insn, 48, 4);
1323         b2 = extract64(insn, 44, 4);
1324         d2 = extract64(insn, 32, 12);
1325         env->cc_op = helper_icm(env, r1, get_address(env, 0, b2, d2), r3);
1326         return;
1327     }
1328
1329     cpu_abort(CPU(cpu), "EXECUTE on instruction prefix 0x%x not implemented\n",
1330               opc);
1331 }
This page took 0.095839 seconds and 4 git commands to generate.