]> git.proxmox.com Git - mirror_qemu.git/blame - target-s390x/op_helper.c
target-s390x: split integer helpers
[mirror_qemu.git] / target-s390x / op_helper.c
CommitLineData
10ec5117
AG
1/*
2 * S/390 helper routines
3 *
defb0e31 4 * Copyright (c) 2009 Ulrich Hecht
10ec5117
AG
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
70539e18 18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
10ec5117
AG
19 */
20
3e457172 21#include "cpu.h"
9abf567d
CB
22#include "memory.h"
23#include "cputlb.h"
3e457172 24#include "dyngen-exec.h"
defb0e31 25#include "host-utils.h"
3208afbe 26#include "helper.h"
defb0e31
AG
27#include <string.h>
28#include "kvm.h"
29#include "qemu-timer.h"
af2be207
JK
30#ifdef CONFIG_KVM
31#include <linux/kvm.h>
32#endif
10ec5117 33
71e47088 34#if !defined(CONFIG_USER_ONLY)
1864b94a
AG
35#include "sysemu.h"
36#endif
37
10ec5117
AG
38/*****************************************************************************/
39/* Softmmu support */
71e47088 40#if !defined(CONFIG_USER_ONLY)
3e457172 41#include "softmmu_exec.h"
10ec5117
AG
42
43#define MMUSUFFIX _mmu
44
45#define SHIFT 0
46#include "softmmu_template.h"
47
48#define SHIFT 1
49#include "softmmu_template.h"
50
51#define SHIFT 2
52#include "softmmu_template.h"
53
54#define SHIFT 3
55#include "softmmu_template.h"
56
57/* try to fill the TLB and return an exception if error. If retaddr is
58 NULL, it means that the function was called in C code (i.e. not
59 from generated code or from helper.c) */
60/* XXX: fix it to restore all registers */
a4e3ad19 61void tlb_fill(CPUS390XState *env1, target_ulong addr, int is_write, int mmu_idx,
20503968 62 uintptr_t retaddr)
10ec5117
AG
63{
64 TranslationBlock *tb;
a4e3ad19 65 CPUS390XState *saved_env;
10ec5117
AG
66 int ret;
67
10ec5117 68 saved_env = env;
bccd9ec5 69 env = env1;
97b348e7 70 ret = cpu_s390x_handle_mmu_fault(env, addr, is_write, mmu_idx);
10ec5117
AG
71 if (unlikely(ret != 0)) {
72 if (likely(retaddr)) {
73 /* now we have a real cpu fault */
20503968 74 tb = tb_find_pc(retaddr);
10ec5117
AG
75 if (likely(tb)) {
76 /* the PC is inside the translated code. It means that we have
77 a virtual CPU fault */
20503968 78 cpu_restore_state(tb, env, retaddr);
10ec5117
AG
79 }
80 }
1162c041 81 cpu_loop_exit(env);
10ec5117
AG
82 }
83 env = saved_env;
84}
85
86#endif
d5a43964 87
defb0e31
AG
88/* #define DEBUG_HELPER */
89#ifdef DEBUG_HELPER
90#define HELPER_LOG(x...) qemu_log(x)
91#else
92#define HELPER_LOG(x...)
93#endif
94
95/* raise an exception */
96void HELPER(exception)(uint32_t excp)
97{
71e47088 98 HELPER_LOG("%s: exception %d\n", __func__, excp);
defb0e31 99 env->exception_index = excp;
1162c041 100 cpu_loop_exit(env);
defb0e31
AG
101}
102
103#ifndef CONFIG_USER_ONLY
a4e3ad19 104static void mvc_fast_memset(CPUS390XState *env, uint32_t l, uint64_t dest,
defb0e31
AG
105 uint8_t byte)
106{
107 target_phys_addr_t dest_phys;
108 target_phys_addr_t len = l;
109 void *dest_p;
110 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
111 int flags;
112
113 if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) {
114 stb(dest, byte);
115 cpu_abort(env, "should never reach here");
116 }
117 dest_phys |= dest & ~TARGET_PAGE_MASK;
118
119 dest_p = cpu_physical_memory_map(dest_phys, &len, 1);
120
121 memset(dest_p, byte, len);
122
123 cpu_physical_memory_unmap(dest_p, 1, len, len);
124}
125
a4e3ad19 126static void mvc_fast_memmove(CPUS390XState *env, uint32_t l, uint64_t dest,
defb0e31
AG
127 uint64_t src)
128{
129 target_phys_addr_t dest_phys;
130 target_phys_addr_t src_phys;
131 target_phys_addr_t len = l;
132 void *dest_p;
133 void *src_p;
134 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
135 int flags;
136
137 if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) {
138 stb(dest, 0);
139 cpu_abort(env, "should never reach here");
140 }
141 dest_phys |= dest & ~TARGET_PAGE_MASK;
142
143 if (mmu_translate(env, src, 0, asc, &src_phys, &flags)) {
144 ldub(src);
145 cpu_abort(env, "should never reach here");
146 }
147 src_phys |= src & ~TARGET_PAGE_MASK;
148
149 dest_p = cpu_physical_memory_map(dest_phys, &len, 1);
150 src_p = cpu_physical_memory_map(src_phys, &len, 0);
151
152 memmove(dest_p, src_p, len);
153
154 cpu_physical_memory_unmap(dest_p, 1, len, len);
155 cpu_physical_memory_unmap(src_p, 0, len, len);
156}
157#endif
158
159/* and on array */
160uint32_t HELPER(nc)(uint32_t l, uint64_t dest, uint64_t src)
161{
162 int i;
163 unsigned char x;
164 uint32_t cc = 0;
165
166 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
71e47088 167 __func__, l, dest, src);
defb0e31
AG
168 for (i = 0; i <= l; i++) {
169 x = ldub(dest + i) & ldub(src + i);
170 if (x) {
171 cc = 1;
172 }
173 stb(dest + i, x);
174 }
175 return cc;
176}
177
178/* xor on array */
179uint32_t HELPER(xc)(uint32_t l, uint64_t dest, uint64_t src)
180{
181 int i;
182 unsigned char x;
183 uint32_t cc = 0;
184
185 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
71e47088 186 __func__, l, dest, src);
defb0e31
AG
187
188#ifndef CONFIG_USER_ONLY
189 /* xor with itself is the same as memset(0) */
190 if ((l > 32) && (src == dest) &&
191 (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK)) {
192 mvc_fast_memset(env, l + 1, dest, 0);
193 return 0;
194 }
195#else
196 if (src == dest) {
197 memset(g2h(dest), 0, l + 1);
198 return 0;
199 }
200#endif
201
202 for (i = 0; i <= l; i++) {
203 x = ldub(dest + i) ^ ldub(src + i);
204 if (x) {
205 cc = 1;
206 }
207 stb(dest + i, x);
208 }
209 return cc;
210}
211
212/* or on array */
213uint32_t HELPER(oc)(uint32_t l, uint64_t dest, uint64_t src)
214{
215 int i;
216 unsigned char x;
217 uint32_t cc = 0;
218
219 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
71e47088 220 __func__, l, dest, src);
defb0e31
AG
221 for (i = 0; i <= l; i++) {
222 x = ldub(dest + i) | ldub(src + i);
223 if (x) {
224 cc = 1;
225 }
226 stb(dest + i, x);
227 }
228 return cc;
229}
230
231/* memmove */
232void HELPER(mvc)(uint32_t l, uint64_t dest, uint64_t src)
233{
234 int i = 0;
235 int x = 0;
236 uint32_t l_64 = (l + 1) / 8;
237
238 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
71e47088 239 __func__, l, dest, src);
defb0e31
AG
240
241#ifndef CONFIG_USER_ONLY
242 if ((l > 32) &&
243 (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK) &&
244 (dest & TARGET_PAGE_MASK) == ((dest + l) & TARGET_PAGE_MASK)) {
245 if (dest == (src + 1)) {
246 mvc_fast_memset(env, l + 1, dest, ldub(src));
247 return;
248 } else if ((src & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
249 mvc_fast_memmove(env, l + 1, dest, src);
250 return;
251 }
252 }
253#else
254 if (dest == (src + 1)) {
255 memset(g2h(dest), ldub(src), l + 1);
256 return;
257 } else {
258 memmove(g2h(dest), g2h(src), l + 1);
259 return;
260 }
261#endif
262
263 /* handle the parts that fit into 8-byte loads/stores */
264 if (dest != (src + 1)) {
265 for (i = 0; i < l_64; i++) {
266 stq(dest + x, ldq(src + x));
267 x += 8;
268 }
269 }
270
271 /* slow version crossing pages with byte accesses */
272 for (i = x; i <= l; i++) {
273 stb(dest + i, ldub(src + i));
274 }
275}
276
277/* compare unsigned byte arrays */
278uint32_t HELPER(clc)(uint32_t l, uint64_t s1, uint64_t s2)
279{
280 int i;
71e47088 281 unsigned char x, y;
defb0e31 282 uint32_t cc;
71e47088 283
defb0e31 284 HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n",
71e47088 285 __func__, l, s1, s2);
defb0e31
AG
286 for (i = 0; i <= l; i++) {
287 x = ldub(s1 + i);
288 y = ldub(s2 + i);
289 HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y);
290 if (x < y) {
291 cc = 1;
292 goto done;
293 } else if (x > y) {
294 cc = 2;
295 goto done;
296 }
297 }
298 cc = 0;
71e47088 299 done:
defb0e31
AG
300 HELPER_LOG("\n");
301 return cc;
302}
303
304/* compare logical under mask */
305uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr)
306{
71e47088 307 uint8_t r, d;
defb0e31 308 uint32_t cc;
71e47088
BS
309
310 HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1,
defb0e31
AG
311 mask, addr);
312 cc = 0;
313 while (mask) {
314 if (mask & 8) {
315 d = ldub(addr);
316 r = (r1 & 0xff000000UL) >> 24;
317 HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d,
71e47088 318 addr);
defb0e31
AG
319 if (r < d) {
320 cc = 1;
321 break;
322 } else if (r > d) {
323 cc = 2;
324 break;
325 }
326 addr++;
327 }
328 mask = (mask << 1) & 0xf;
329 r1 <<= 8;
330 }
331 HELPER_LOG("\n");
332 return cc;
333}
334
335/* store character under mask */
336void HELPER(stcm)(uint32_t r1, uint32_t mask, uint64_t addr)
337{
338 uint8_t r;
71e47088
BS
339
340 HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n", __func__, r1, mask,
defb0e31
AG
341 addr);
342 while (mask) {
343 if (mask & 8) {
344 r = (r1 & 0xff000000UL) >> 24;
345 stb(addr, r);
346 HELPER_LOG("mask 0x%x %02x (0x%lx) ", mask, r, addr);
347 addr++;
348 }
349 mask = (mask << 1) & 0xf;
350 r1 <<= 8;
351 }
352 HELPER_LOG("\n");
353}
354
defb0e31
AG
355static inline uint64_t get_address(int x2, int b2, int d2)
356{
357 uint64_t r = d2;
358
359 if (x2) {
360 r += env->regs[x2];
361 }
362
363 if (b2) {
364 r += env->regs[b2];
365 }
366
367 /* 31-Bit mode */
368 if (!(env->psw.mask & PSW_MASK_64)) {
369 r &= 0x7fffffff;
370 }
371
372 return r;
373}
374
375static inline uint64_t get_address_31fix(int reg)
376{
377 uint64_t r = env->regs[reg];
378
379 /* 31-Bit mode */
380 if (!(env->psw.mask & PSW_MASK_64)) {
381 r &= 0x7fffffff;
382 }
383
384 return r;
385}
386
387/* search string (c is byte to search, r2 is string, r1 end of string) */
388uint32_t HELPER(srst)(uint32_t c, uint32_t r1, uint32_t r2)
389{
390 uint64_t i;
391 uint32_t cc = 2;
392 uint64_t str = get_address_31fix(r2);
393 uint64_t end = get_address_31fix(r1);
394
71e47088 395 HELPER_LOG("%s: c %d *r1 0x%" PRIx64 " *r2 0x%" PRIx64 "\n", __func__,
defb0e31
AG
396 c, env->regs[r1], env->regs[r2]);
397
398 for (i = str; i != end; i++) {
399 if (ldub(i) == c) {
400 env->regs[r1] = i;
401 cc = 1;
402 break;
403 }
404 }
405
406 return cc;
407}
408
409/* unsigned string compare (c is string terminator) */
410uint32_t HELPER(clst)(uint32_t c, uint32_t r1, uint32_t r2)
411{
412 uint64_t s1 = get_address_31fix(r1);
413 uint64_t s2 = get_address_31fix(r2);
414 uint8_t v1, v2;
415 uint32_t cc;
71e47088 416
defb0e31
AG
417 c = c & 0xff;
418#ifdef CONFIG_USER_ONLY
419 if (!c) {
420 HELPER_LOG("%s: comparing '%s' and '%s'\n",
71e47088 421 __func__, (char *)g2h(s1), (char *)g2h(s2));
defb0e31
AG
422 }
423#endif
424 for (;;) {
425 v1 = ldub(s1);
426 v2 = ldub(s2);
427 if ((v1 == c || v2 == c) || (v1 != v2)) {
428 break;
429 }
430 s1++;
431 s2++;
432 }
433
434 if (v1 == v2) {
435 cc = 0;
436 } else {
437 cc = (v1 < v2) ? 1 : 2;
438 /* FIXME: 31-bit mode! */
439 env->regs[r1] = s1;
440 env->regs[r2] = s2;
441 }
442 return cc;
443}
444
445/* move page */
446void HELPER(mvpg)(uint64_t r0, uint64_t r1, uint64_t r2)
447{
448 /* XXX missing r0 handling */
449#ifdef CONFIG_USER_ONLY
450 int i;
451
452 for (i = 0; i < TARGET_PAGE_SIZE; i++) {
453 stb(r1 + i, ldub(r2 + i));
454 }
455#else
456 mvc_fast_memmove(env, TARGET_PAGE_SIZE, r1, r2);
457#endif
458}
459
460/* string copy (c is string terminator) */
461void HELPER(mvst)(uint32_t c, uint32_t r1, uint32_t r2)
462{
463 uint64_t dest = get_address_31fix(r1);
464 uint64_t src = get_address_31fix(r2);
465 uint8_t v;
71e47088 466
defb0e31
AG
467 c = c & 0xff;
468#ifdef CONFIG_USER_ONLY
469 if (!c) {
71e47088 470 HELPER_LOG("%s: copy '%s' to 0x%lx\n", __func__, (char *)g2h(src),
defb0e31
AG
471 dest);
472 }
473#endif
474 for (;;) {
475 v = ldub(src);
476 stb(dest, v);
477 if (v == c) {
478 break;
479 }
480 src++;
481 dest++;
482 }
483 env->regs[r1] = dest; /* FIXME: 31-bit mode! */
484}
485
486/* compare and swap 64-bit */
487uint32_t HELPER(csg)(uint32_t r1, uint64_t a2, uint32_t r3)
488{
489 /* FIXME: locking? */
490 uint32_t cc;
491 uint64_t v2 = ldq(a2);
71e47088 492
defb0e31
AG
493 if (env->regs[r1] == v2) {
494 cc = 0;
495 stq(a2, env->regs[r3]);
496 } else {
497 cc = 1;
498 env->regs[r1] = v2;
499 }
500 return cc;
501}
502
503/* compare double and swap 64-bit */
504uint32_t HELPER(cdsg)(uint32_t r1, uint64_t a2, uint32_t r3)
505{
506 /* FIXME: locking? */
507 uint32_t cc;
508 uint64_t v2_hi = ldq(a2);
509 uint64_t v2_lo = ldq(a2 + 8);
510 uint64_t v1_hi = env->regs[r1];
511 uint64_t v1_lo = env->regs[r1 + 1];
512
513 if ((v1_hi == v2_hi) && (v1_lo == v2_lo)) {
514 cc = 0;
515 stq(a2, env->regs[r3]);
516 stq(a2 + 8, env->regs[r3 + 1]);
517 } else {
518 cc = 1;
519 env->regs[r1] = v2_hi;
520 env->regs[r1 + 1] = v2_lo;
521 }
522
523 return cc;
524}
525
526/* compare and swap 32-bit */
527uint32_t HELPER(cs)(uint32_t r1, uint64_t a2, uint32_t r3)
528{
529 /* FIXME: locking? */
530 uint32_t cc;
defb0e31 531 uint32_t v2 = ldl(a2);
71e47088
BS
532
533 HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __func__, r1, a2, r3);
defb0e31
AG
534 if (((uint32_t)env->regs[r1]) == v2) {
535 cc = 0;
536 stl(a2, (uint32_t)env->regs[r3]);
537 } else {
538 cc = 1;
539 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | v2;
540 }
541 return cc;
542}
543
544static uint32_t helper_icm(uint32_t r1, uint64_t address, uint32_t mask)
545{
546 int pos = 24; /* top of the lower half of r1 */
547 uint64_t rmask = 0xff000000ULL;
548 uint8_t val = 0;
549 int ccd = 0;
550 uint32_t cc = 0;
551
552 while (mask) {
553 if (mask & 8) {
554 env->regs[r1] &= ~rmask;
555 val = ldub(address);
556 if ((val & 0x80) && !ccd) {
557 cc = 1;
558 }
559 ccd = 1;
560 if (val && cc == 0) {
561 cc = 2;
562 }
563 env->regs[r1] |= (uint64_t)val << pos;
564 address++;
565 }
566 mask = (mask << 1) & 0xf;
567 pos -= 8;
568 rmask >>= 8;
569 }
570
571 return cc;
572}
573
574/* execute instruction
575 this instruction executes an insn modified with the contents of r1
576 it does not change the executed instruction in memory
577 it does not change the program counter
578 in other words: tricky...
579 currently implemented by interpreting the cases it is most commonly used in
71e47088 580*/
defb0e31
AG
581uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret)
582{
583 uint16_t insn = lduw_code(addr);
71e47088
BS
584
585 HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __func__, v1, addr,
586 insn);
defb0e31
AG
587 if ((insn & 0xf0ff) == 0xd000) {
588 uint32_t l, insn2, b1, b2, d1, d2;
71e47088 589
defb0e31
AG
590 l = v1 & 0xff;
591 insn2 = ldl_code(addr + 2);
592 b1 = (insn2 >> 28) & 0xf;
593 b2 = (insn2 >> 12) & 0xf;
594 d1 = (insn2 >> 16) & 0xfff;
595 d2 = insn2 & 0xfff;
596 switch (insn & 0xf00) {
597 case 0x200:
598 helper_mvc(l, get_address(0, b1, d1), get_address(0, b2, d2));
599 break;
600 case 0x500:
601 cc = helper_clc(l, get_address(0, b1, d1), get_address(0, b2, d2));
602 break;
603 case 0x700:
604 cc = helper_xc(l, get_address(0, b1, d1), get_address(0, b2, d2));
605 break;
7d77793d
AG
606 case 0xc00:
607 helper_tr(l, get_address(0, b1, d1), get_address(0, b2, d2));
608 break;
defb0e31
AG
609 default:
610 goto abort;
611 break;
612 }
613 } else if ((insn & 0xff00) == 0x0a00) {
614 /* supervisor call */
71e47088 615 HELPER_LOG("%s: svc %ld via execute\n", __func__, (insn | v1) & 0xff);
defb0e31 616 env->psw.addr = ret - 4;
71e47088 617 env->int_svc_code = (insn | v1) & 0xff;
defb0e31
AG
618 env->int_svc_ilc = 4;
619 helper_exception(EXCP_SVC);
620 } else if ((insn & 0xff00) == 0xbf00) {
621 uint32_t insn2, r1, r3, b2, d2;
71e47088 622
defb0e31
AG
623 insn2 = ldl_code(addr + 2);
624 r1 = (insn2 >> 20) & 0xf;
625 r3 = (insn2 >> 16) & 0xf;
626 b2 = (insn2 >> 12) & 0xf;
627 d2 = insn2 & 0xfff;
628 cc = helper_icm(r1, get_address(0, b2, d2), r3);
629 } else {
71e47088 630 abort:
defb0e31
AG
631 cpu_abort(env, "EXECUTE on instruction prefix 0x%x not implemented\n",
632 insn);
633 }
634 return cc;
635}
636
defb0e31
AG
637/* store character under mask high operates on the upper half of r1 */
638void HELPER(stcmh)(uint32_t r1, uint64_t address, uint32_t mask)
639{
640 int pos = 56; /* top of the upper half of r1 */
641
642 while (mask) {
643 if (mask & 8) {
644 stb(address, (env->regs[r1] >> pos) & 0xff);
645 address++;
646 }
647 mask = (mask << 1) & 0xf;
648 pos -= 8;
649 }
650}
651
652/* insert character under mask high; same as icm, but operates on the
653 upper half of r1 */
654uint32_t HELPER(icmh)(uint32_t r1, uint64_t address, uint32_t mask)
655{
656 int pos = 56; /* top of the upper half of r1 */
657 uint64_t rmask = 0xff00000000000000ULL;
658 uint8_t val = 0;
659 int ccd = 0;
660 uint32_t cc = 0;
661
662 while (mask) {
663 if (mask & 8) {
664 env->regs[r1] &= ~rmask;
665 val = ldub(address);
666 if ((val & 0x80) && !ccd) {
667 cc = 1;
668 }
669 ccd = 1;
670 if (val && cc == 0) {
671 cc = 2;
672 }
673 env->regs[r1] |= (uint64_t)val << pos;
674 address++;
675 }
676 mask = (mask << 1) & 0xf;
677 pos -= 8;
678 rmask >>= 8;
679 }
680
681 return cc;
682}
683
defb0e31
AG
684/* load access registers r1 to r3 from memory at a2 */
685void HELPER(lam)(uint32_t r1, uint64_t a2, uint32_t r3)
686{
687 int i;
688
689 for (i = r1;; i = (i + 1) % 16) {
690 env->aregs[i] = ldl(a2);
691 a2 += 4;
692
693 if (i == r3) {
694 break;
695 }
696 }
697}
698
699/* store access registers r1 to r3 in memory at a2 */
700void HELPER(stam)(uint32_t r1, uint64_t a2, uint32_t r3)
701{
702 int i;
703
704 for (i = r1;; i = (i + 1) % 16) {
705 stl(a2, env->aregs[i]);
706 a2 += 4;
707
708 if (i == r3) {
709 break;
710 }
711 }
712}
713
714/* move long */
715uint32_t HELPER(mvcl)(uint32_t r1, uint32_t r2)
716{
717 uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
718 uint64_t dest = get_address_31fix(r1);
719 uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
720 uint64_t src = get_address_31fix(r2);
721 uint8_t pad = src >> 24;
722 uint8_t v;
723 uint32_t cc;
724
725 if (destlen == srclen) {
726 cc = 0;
727 } else if (destlen < srclen) {
728 cc = 1;
729 } else {
730 cc = 2;
731 }
732
733 if (srclen > destlen) {
734 srclen = destlen;
735 }
736
737 for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
738 v = ldub(src);
739 stb(dest, v);
740 }
741
742 for (; destlen; dest++, destlen--) {
743 stb(dest, pad);
744 }
745
746 env->regs[r1 + 1] = destlen;
747 /* can't use srclen here, we trunc'ed it */
748 env->regs[r2 + 1] -= src - env->regs[r2];
749 env->regs[r1] = dest;
750 env->regs[r2] = src;
751
752 return cc;
753}
754
755/* move long extended another memcopy insn with more bells and whistles */
756uint32_t HELPER(mvcle)(uint32_t r1, uint64_t a2, uint32_t r3)
757{
758 uint64_t destlen = env->regs[r1 + 1];
759 uint64_t dest = env->regs[r1];
760 uint64_t srclen = env->regs[r3 + 1];
761 uint64_t src = env->regs[r3];
762 uint8_t pad = a2 & 0xff;
763 uint8_t v;
764 uint32_t cc;
765
766 if (!(env->psw.mask & PSW_MASK_64)) {
767 destlen = (uint32_t)destlen;
768 srclen = (uint32_t)srclen;
769 dest &= 0x7fffffff;
770 src &= 0x7fffffff;
771 }
772
773 if (destlen == srclen) {
774 cc = 0;
775 } else if (destlen < srclen) {
776 cc = 1;
777 } else {
778 cc = 2;
779 }
780
781 if (srclen > destlen) {
782 srclen = destlen;
783 }
784
785 for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
786 v = ldub(src);
787 stb(dest, v);
788 }
789
790 for (; destlen; dest++, destlen--) {
791 stb(dest, pad);
792 }
793
794 env->regs[r1 + 1] = destlen;
795 /* can't use srclen here, we trunc'ed it */
796 /* FIXME: 31-bit mode! */
797 env->regs[r3 + 1] -= src - env->regs[r3];
798 env->regs[r1] = dest;
799 env->regs[r3] = src;
800
801 return cc;
802}
803
804/* compare logical long extended memcompare insn with padding */
805uint32_t HELPER(clcle)(uint32_t r1, uint64_t a2, uint32_t r3)
806{
807 uint64_t destlen = env->regs[r1 + 1];
808 uint64_t dest = get_address_31fix(r1);
809 uint64_t srclen = env->regs[r3 + 1];
810 uint64_t src = get_address_31fix(r3);
811 uint8_t pad = a2 & 0xff;
71e47088 812 uint8_t v1 = 0, v2 = 0;
defb0e31
AG
813 uint32_t cc = 0;
814
815 if (!(destlen || srclen)) {
816 return cc;
817 }
818
819 if (srclen > destlen) {
820 srclen = destlen;
821 }
822
823 for (; destlen || srclen; src++, dest++, destlen--, srclen--) {
824 v1 = srclen ? ldub(src) : pad;
825 v2 = destlen ? ldub(dest) : pad;
826 if (v1 != v2) {
827 cc = (v1 < v2) ? 1 : 2;
828 break;
829 }
830 }
831
832 env->regs[r1 + 1] = destlen;
833 /* can't use srclen here, we trunc'ed it */
834 env->regs[r3 + 1] -= src - env->regs[r3];
835 env->regs[r1] = dest;
836 env->regs[r3] = src;
837
838 return cc;
839}
840
defb0e31
AG
841/* checksum */
842void HELPER(cksm)(uint32_t r1, uint32_t r2)
843{
844 uint64_t src = get_address_31fix(r2);
845 uint64_t src_len = env->regs[(r2 + 1) & 15];
5b185639 846 uint64_t cksm = (uint32_t)env->regs[r1];
defb0e31
AG
847
848 while (src_len >= 4) {
849 cksm += ldl(src);
defb0e31
AG
850
851 /* move to next word */
852 src_len -= 4;
853 src += 4;
854 }
855
856 switch (src_len) {
857 case 0:
858 break;
859 case 1:
5b185639 860 cksm += ldub(src) << 24;
defb0e31
AG
861 break;
862 case 2:
5b185639 863 cksm += lduw(src) << 16;
defb0e31
AG
864 break;
865 case 3:
5b185639
AG
866 cksm += lduw(src) << 16;
867 cksm += ldub(src + 2) << 8;
defb0e31
AG
868 break;
869 }
870
871 /* indicate we've processed everything */
5b185639 872 env->regs[r2] = src + src_len;
defb0e31
AG
873 env->regs[(r2 + 1) & 15] = 0;
874
875 /* store result */
5b185639 876 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
71e47088 877 ((uint32_t)cksm + (cksm >> 32));
defb0e31
AG
878}
879
defb0e31
AG
880void HELPER(unpk)(uint32_t len, uint64_t dest, uint64_t src)
881{
882 int len_dest = len >> 4;
883 int len_src = len & 0xf;
884 uint8_t b;
885 int second_nibble = 0;
886
887 dest += len_dest;
888 src += len_src;
889
890 /* last byte is special, it only flips the nibbles */
891 b = ldub(src);
892 stb(dest, (b << 4) | (b >> 4));
893 src--;
894 len_src--;
895
896 /* now pad every nibble with 0xf0 */
897
898 while (len_dest > 0) {
899 uint8_t cur_byte = 0;
900
901 if (len_src > 0) {
902 cur_byte = ldub(src);
903 }
904
905 len_dest--;
906 dest--;
907
908 /* only advance one nibble at a time */
909 if (second_nibble) {
910 cur_byte >>= 4;
911 len_src--;
912 src--;
913 }
914 second_nibble = !second_nibble;
915
916 /* digit */
917 cur_byte = (cur_byte & 0xf);
918 /* zone bits */
919 cur_byte |= 0xf0;
920
921 stb(dest, cur_byte);
922 }
923}
924
925void HELPER(tr)(uint32_t len, uint64_t array, uint64_t trans)
926{
927 int i;
928
929 for (i = 0; i <= len; i++) {
930 uint8_t byte = ldub(array + i);
931 uint8_t new_byte = ldub(trans + byte);
71e47088 932
defb0e31
AG
933 stb(array + i, new_byte);
934 }
935}
936
937#ifndef CONFIG_USER_ONLY
a78b0504 938void program_interrupt(CPUS390XState *env, uint32_t code, int ilc)
defb0e31
AG
939{
940 qemu_log("program interrupt at %#" PRIx64 "\n", env->psw.addr);
941
942 if (kvm_enabled()) {
af2be207 943#ifdef CONFIG_KVM
defb0e31 944 kvm_s390_interrupt(env, KVM_S390_PROGRAM_INT, code);
af2be207 945#endif
defb0e31
AG
946 } else {
947 env->int_pgm_code = code;
948 env->int_pgm_ilc = ilc;
949 env->exception_index = EXCP_PGM;
1162c041 950 cpu_loop_exit(env);
defb0e31
AG
951 }
952}
953
9abf567d 954/*
71e47088 955 * ret < 0 indicates program check, ret = 0, 1, 2, 3 -> cc
9abf567d 956 */
a4e3ad19 957int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
defb0e31
AG
958{
959 int r = 0;
22486aa0 960 int shift = 0;
defb0e31
AG
961
962#ifdef DEBUG_HELPER
963 printf("sclp(0x%x, 0x%" PRIx64 ")\n", sccb, code);
964#endif
965
9abf567d
CB
966 /* basic checks */
967 if (!memory_region_is_ram(phys_page_find(sccb >> TARGET_PAGE_BITS)->mr)) {
968 return -PGM_ADDRESSING;
969 }
defb0e31 970 if (sccb & ~0x7ffffff8ul) {
9abf567d 971 return -PGM_SPECIFICATION;
defb0e31
AG
972 }
973
71e47088
BS
974 switch (code) {
975 case SCLP_CMDW_READ_SCP_INFO:
976 case SCLP_CMDW_READ_SCP_INFO_FORCED:
977 while ((ram_size >> (20 + shift)) > 65535) {
978 shift++;
979 }
980 stw_phys(sccb + SCP_MEM_CODE, ram_size >> (20 + shift));
981 stb_phys(sccb + SCP_INCREMENT, 1 << shift);
982 stw_phys(sccb + SCP_RESPONSE_CODE, 0x10);
defb0e31 983
71e47088
BS
984 s390_sclp_extint(sccb & ~3);
985 break;
986 default:
defb0e31 987#ifdef DEBUG_HELPER
71e47088 988 printf("KVM: invalid sclp call 0x%x / 0x%" PRIx64 "x\n", sccb, code);
defb0e31 989#endif
71e47088
BS
990 r = 3;
991 break;
defb0e31
AG
992 }
993
defb0e31
AG
994 return r;
995}
996
997/* SCLP service call */
998uint32_t HELPER(servc)(uint32_t r1, uint64_t r2)
999{
9abf567d 1000 int r;
defb0e31 1001
9abf567d
CB
1002 r = sclp_service_call(env, r1, r2);
1003 if (r < 0) {
1004 program_interrupt(env, -r, 4);
1005 return 0;
1006 }
1007 return r;
defb0e31
AG
1008}
1009
1010/* DIAG */
1011uint64_t HELPER(diag)(uint32_t num, uint64_t mem, uint64_t code)
1012{
1013 uint64_t r;
1014
1015 switch (num) {
1016 case 0x500:
1017 /* KVM hypercall */
1018 r = s390_virtio_hypercall(env, mem, code);
1019 break;
1020 case 0x44:
1021 /* yield */
1022 r = 0;
1023 break;
1024 case 0x308:
1025 /* ipl */
1026 r = 0;
1027 break;
1028 default:
1029 r = -1;
1030 break;
1031 }
1032
1033 if (r) {
1034 program_interrupt(env, PGM_OPERATION, ILC_LATER_INC);
1035 }
1036
1037 return r;
1038}
1039
1040/* Store CPU ID */
1041void HELPER(stidp)(uint64_t a1)
1042{
1043 stq(a1, env->cpu_num);
1044}
1045
1046/* Set Prefix */
1047void HELPER(spx)(uint64_t a1)
1048{
1049 uint32_t prefix;
1050
1051 prefix = ldl(a1);
1052 env->psa = prefix & 0xfffff000;
1053 qemu_log("prefix: %#x\n", prefix);
1054 tlb_flush_page(env, 0);
1055 tlb_flush_page(env, TARGET_PAGE_SIZE);
1056}
1057
1058/* Set Clock */
1059uint32_t HELPER(sck)(uint64_t a1)
1060{
1061 /* XXX not implemented - is it necessary? */
1062
1063 return 0;
1064}
1065
a4e3ad19 1066static inline uint64_t clock_value(CPUS390XState *env)
defb0e31
AG
1067{
1068 uint64_t time;
1069
1070 time = env->tod_offset +
71e47088 1071 time2tod(qemu_get_clock_ns(vm_clock) - env->tod_basetime);
defb0e31
AG
1072
1073 return time;
1074}
1075
1076/* Store Clock */
1077uint32_t HELPER(stck)(uint64_t a1)
1078{
1079 stq(a1, clock_value(env));
1080
1081 return 0;
1082}
1083
1084/* Store Clock Extended */
1085uint32_t HELPER(stcke)(uint64_t a1)
1086{
1087 stb(a1, 0);
1088 /* basically the same value as stck */
1089 stq(a1 + 1, clock_value(env) | env->cpu_num);
1090 /* more fine grained than stck */
1091 stq(a1 + 9, 0);
1092 /* XXX programmable fields */
1093 stw(a1 + 17, 0);
1094
defb0e31
AG
1095 return 0;
1096}
1097
1098/* Set Clock Comparator */
1099void HELPER(sckc)(uint64_t a1)
1100{
1101 uint64_t time = ldq(a1);
1102
1103 if (time == -1ULL) {
1104 return;
1105 }
1106
1107 /* difference between now and then */
1108 time -= clock_value(env);
1109 /* nanoseconds */
1110 time = (time * 125) >> 9;
1111
1112 qemu_mod_timer(env->tod_timer, qemu_get_clock_ns(vm_clock) + time);
1113}
1114
1115/* Store Clock Comparator */
1116void HELPER(stckc)(uint64_t a1)
1117{
1118 /* XXX implement */
1119 stq(a1, 0);
1120}
1121
1122/* Set CPU Timer */
1123void HELPER(spt)(uint64_t a1)
1124{
1125 uint64_t time = ldq(a1);
1126
1127 if (time == -1ULL) {
1128 return;
1129 }
1130
1131 /* nanoseconds */
1132 time = (time * 125) >> 9;
1133
1134 qemu_mod_timer(env->cpu_timer, qemu_get_clock_ns(vm_clock) + time);
1135}
1136
1137/* Store CPU Timer */
1138void HELPER(stpt)(uint64_t a1)
1139{
1140 /* XXX implement */
1141 stq(a1, 0);
1142}
1143
1144/* Store System Information */
1145uint32_t HELPER(stsi)(uint64_t a0, uint32_t r0, uint32_t r1)
1146{
1147 int cc = 0;
1148 int sel1, sel2;
1149
1150 if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 &&
1151 ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) {
1152 /* valid function code, invalid reserved bits */
1153 program_interrupt(env, PGM_SPECIFICATION, 2);
1154 }
1155
1156 sel1 = r0 & STSI_R0_SEL1_MASK;
1157 sel2 = r1 & STSI_R1_SEL2_MASK;
1158
1159 /* XXX: spec exception if sysib is not 4k-aligned */
1160
1161 switch (r0 & STSI_LEVEL_MASK) {
1162 case STSI_LEVEL_1:
1163 if ((sel1 == 1) && (sel2 == 1)) {
1164 /* Basic Machine Configuration */
1165 struct sysib_111 sysib;
1166
1167 memset(&sysib, 0, sizeof(sysib));
1168 ebcdic_put(sysib.manuf, "QEMU ", 16);
1169 /* same as machine type number in STORE CPU ID */
1170 ebcdic_put(sysib.type, "QEMU", 4);
1171 /* same as model number in STORE CPU ID */
1172 ebcdic_put(sysib.model, "QEMU ", 16);
1173 ebcdic_put(sysib.sequence, "QEMU ", 16);
1174 ebcdic_put(sysib.plant, "QEMU", 4);
71e47088 1175 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
defb0e31
AG
1176 } else if ((sel1 == 2) && (sel2 == 1)) {
1177 /* Basic Machine CPU */
1178 struct sysib_121 sysib;
1179
1180 memset(&sysib, 0, sizeof(sysib));
1181 /* XXX make different for different CPUs? */
1182 ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
1183 ebcdic_put(sysib.plant, "QEMU", 4);
1184 stw_p(&sysib.cpu_addr, env->cpu_num);
71e47088 1185 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
defb0e31
AG
1186 } else if ((sel1 == 2) && (sel2 == 2)) {
1187 /* Basic Machine CPUs */
1188 struct sysib_122 sysib;
1189
1190 memset(&sysib, 0, sizeof(sysib));
1191 stl_p(&sysib.capability, 0x443afc29);
1192 /* XXX change when SMP comes */
1193 stw_p(&sysib.total_cpus, 1);
1194 stw_p(&sysib.active_cpus, 1);
1195 stw_p(&sysib.standby_cpus, 0);
1196 stw_p(&sysib.reserved_cpus, 0);
71e47088 1197 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
defb0e31
AG
1198 } else {
1199 cc = 3;
1200 }
1201 break;
1202 case STSI_LEVEL_2:
71e47088
BS
1203 {
1204 if ((sel1 == 2) && (sel2 == 1)) {
1205 /* LPAR CPU */
1206 struct sysib_221 sysib;
1207
1208 memset(&sysib, 0, sizeof(sysib));
1209 /* XXX make different for different CPUs? */
1210 ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
1211 ebcdic_put(sysib.plant, "QEMU", 4);
1212 stw_p(&sysib.cpu_addr, env->cpu_num);
1213 stw_p(&sysib.cpu_id, 0);
1214 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
1215 } else if ((sel1 == 2) && (sel2 == 2)) {
1216 /* LPAR CPUs */
1217 struct sysib_222 sysib;
1218
1219 memset(&sysib, 0, sizeof(sysib));
1220 stw_p(&sysib.lpar_num, 0);
1221 sysib.lcpuc = 0;
1222 /* XXX change when SMP comes */
1223 stw_p(&sysib.total_cpus, 1);
1224 stw_p(&sysib.conf_cpus, 1);
1225 stw_p(&sysib.standby_cpus, 0);
1226 stw_p(&sysib.reserved_cpus, 0);
1227 ebcdic_put(sysib.name, "QEMU ", 8);
1228 stl_p(&sysib.caf, 1000);
1229 stw_p(&sysib.dedicated_cpus, 0);
1230 stw_p(&sysib.shared_cpus, 0);
1231 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
1232 } else {
1233 cc = 3;
1234 }
1235 break;
defb0e31 1236 }
defb0e31 1237 case STSI_LEVEL_3:
71e47088
BS
1238 {
1239 if ((sel1 == 2) && (sel2 == 2)) {
1240 /* VM CPUs */
1241 struct sysib_322 sysib;
1242
1243 memset(&sysib, 0, sizeof(sysib));
1244 sysib.count = 1;
1245 /* XXX change when SMP comes */
1246 stw_p(&sysib.vm[0].total_cpus, 1);
1247 stw_p(&sysib.vm[0].conf_cpus, 1);
1248 stw_p(&sysib.vm[0].standby_cpus, 0);
1249 stw_p(&sysib.vm[0].reserved_cpus, 0);
1250 ebcdic_put(sysib.vm[0].name, "KVMguest", 8);
1251 stl_p(&sysib.vm[0].caf, 1000);
1252 ebcdic_put(sysib.vm[0].cpi, "KVM/Linux ", 16);
1253 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
1254 } else {
1255 cc = 3;
1256 }
1257 break;
defb0e31 1258 }
defb0e31
AG
1259 case STSI_LEVEL_CURRENT:
1260 env->regs[0] = STSI_LEVEL_3;
1261 break;
1262 default:
1263 cc = 3;
1264 break;
1265 }
1266
1267 return cc;
1268}
1269
1270void HELPER(lctlg)(uint32_t r1, uint64_t a2, uint32_t r3)
1271{
1272 int i;
1273 uint64_t src = a2;
1274
1275 for (i = r1;; i = (i + 1) % 16) {
1276 env->cregs[i] = ldq(src);
1277 HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
1278 i, src, env->cregs[i]);
1279 src += sizeof(uint64_t);
1280
1281 if (i == r3) {
1282 break;
1283 }
1284 }
1285
1286 tlb_flush(env, 1);
1287}
1288
1289void HELPER(lctl)(uint32_t r1, uint64_t a2, uint32_t r3)
1290{
1291 int i;
1292 uint64_t src = a2;
1293
1294 for (i = r1;; i = (i + 1) % 16) {
1295 env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) | ldl(src);
1296 src += sizeof(uint32_t);
1297
1298 if (i == r3) {
1299 break;
1300 }
1301 }
1302
1303 tlb_flush(env, 1);
1304}
1305
1306void HELPER(stctg)(uint32_t r1, uint64_t a2, uint32_t r3)
1307{
1308 int i;
1309 uint64_t dest = a2;
1310
1311 for (i = r1;; i = (i + 1) % 16) {
1312 stq(dest, env->cregs[i]);
1313 dest += sizeof(uint64_t);
1314
1315 if (i == r3) {
1316 break;
1317 }
1318 }
1319}
1320
1321void HELPER(stctl)(uint32_t r1, uint64_t a2, uint32_t r3)
1322{
1323 int i;
1324 uint64_t dest = a2;
1325
1326 for (i = r1;; i = (i + 1) % 16) {
1327 stl(dest, env->cregs[i]);
1328 dest += sizeof(uint32_t);
1329
1330 if (i == r3) {
1331 break;
1332 }
1333 }
1334}
1335
1336uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2)
1337{
1338 /* XXX implement */
1339
1340 return 0;
1341}
1342
1343/* insert storage key extended */
1344uint64_t HELPER(iske)(uint64_t r2)
1345{
1346 uint64_t addr = get_address(0, 0, r2);
1347
1348 if (addr > ram_size) {
1349 return 0;
1350 }
1351
defb0e31
AG
1352 return env->storage_keys[addr / TARGET_PAGE_SIZE];
1353}
1354
1355/* set storage key extended */
1356void HELPER(sske)(uint32_t r1, uint64_t r2)
1357{
1358 uint64_t addr = get_address(0, 0, r2);
1359
1360 if (addr > ram_size) {
1361 return;
1362 }
1363
1364 env->storage_keys[addr / TARGET_PAGE_SIZE] = r1;
1365}
1366
1367/* reset reference bit extended */
1368uint32_t HELPER(rrbe)(uint32_t r1, uint64_t r2)
1369{
17bb18ce
AG
1370 uint8_t re;
1371 uint8_t key;
71e47088 1372
defb0e31
AG
1373 if (r2 > ram_size) {
1374 return 0;
1375 }
1376
17bb18ce
AG
1377 key = env->storage_keys[r2 / TARGET_PAGE_SIZE];
1378 re = key & (SK_R | SK_C);
1379 env->storage_keys[r2 / TARGET_PAGE_SIZE] = (key & ~SK_R);
defb0e31
AG
1380
1381 /*
1382 * cc
1383 *
1384 * 0 Reference bit zero; change bit zero
1385 * 1 Reference bit zero; change bit one
1386 * 2 Reference bit one; change bit zero
1387 * 3 Reference bit one; change bit one
1388 */
17bb18ce
AG
1389
1390 return re >> 1;
d5a43964 1391}
defb0e31
AG
1392
1393/* compare and swap and purge */
1394uint32_t HELPER(csp)(uint32_t r1, uint32_t r2)
1395{
1396 uint32_t cc;
1397 uint32_t o1 = env->regs[r1];
1398 uint64_t a2 = get_address_31fix(r2) & ~3ULL;
1399 uint32_t o2 = ldl(a2);
1400
1401 if (o1 == o2) {
1402 stl(a2, env->regs[(r1 + 1) & 15]);
1403 if (env->regs[r2] & 0x3) {
1404 /* flush TLB / ALB */
1405 tlb_flush(env, 1);
1406 }
1407 cc = 0;
1408 } else {
1409 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | o2;
1410 cc = 1;
1411 }
1412
1413 return cc;
1414}
1415
1416static uint32_t mvc_asc(int64_t l, uint64_t a1, uint64_t mode1, uint64_t a2,
1417 uint64_t mode2)
1418{
1419 target_ulong src, dest;
1420 int flags, cc = 0, i;
1421
1422 if (!l) {
1423 return 0;
1424 } else if (l > 256) {
1425 /* max 256 */
1426 l = 256;
1427 cc = 3;
1428 }
1429
1430 if (mmu_translate(env, a1 & TARGET_PAGE_MASK, 1, mode1, &dest, &flags)) {
1162c041 1431 cpu_loop_exit(env);
defb0e31
AG
1432 }
1433 dest |= a1 & ~TARGET_PAGE_MASK;
1434
1435 if (mmu_translate(env, a2 & TARGET_PAGE_MASK, 0, mode2, &src, &flags)) {
1162c041 1436 cpu_loop_exit(env);
defb0e31
AG
1437 }
1438 src |= a2 & ~TARGET_PAGE_MASK;
1439
1440 /* XXX replace w/ memcpy */
1441 for (i = 0; i < l; i++) {
1442 /* XXX be more clever */
1443 if ((((dest + i) & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) ||
1444 (((src + i) & TARGET_PAGE_MASK) != (src & TARGET_PAGE_MASK))) {
1445 mvc_asc(l - i, a1 + i, mode1, a2 + i, mode2);
1446 break;
1447 }
1448 stb_phys(dest + i, ldub_phys(src + i));
1449 }
1450
1451 return cc;
1452}
1453
1454uint32_t HELPER(mvcs)(uint64_t l, uint64_t a1, uint64_t a2)
1455{
1456 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
71e47088 1457 __func__, l, a1, a2);
defb0e31
AG
1458
1459 return mvc_asc(l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY);
1460}
1461
1462uint32_t HELPER(mvcp)(uint64_t l, uint64_t a1, uint64_t a2)
1463{
1464 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
71e47088 1465 __func__, l, a1, a2);
defb0e31
AG
1466
1467 return mvc_asc(l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY);
1468}
1469
1470uint32_t HELPER(sigp)(uint64_t order_code, uint32_t r1, uint64_t cpu_addr)
1471{
1472 int cc = 0;
1473
1474 HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n",
71e47088 1475 __func__, order_code, r1, cpu_addr);
defb0e31 1476
71e47088 1477 /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register"
defb0e31
AG
1478 as parameter (input). Status (output) is always R1. */
1479
1480 switch (order_code) {
1481 case SIGP_SET_ARCH:
1482 /* switch arch */
1483 break;
1484 case SIGP_SENSE:
1485 /* enumerate CPU status */
1486 if (cpu_addr) {
1487 /* XXX implement when SMP comes */
1488 return 3;
1489 }
1490 env->regs[r1] &= 0xffffffff00000000ULL;
1491 cc = 1;
1492 break;
71e47088 1493#if !defined(CONFIG_USER_ONLY)
1864b94a
AG
1494 case SIGP_RESTART:
1495 qemu_system_reset_request();
1496 cpu_loop_exit(env);
1497 break;
1498 case SIGP_STOP:
1499 qemu_system_shutdown_request();
1500 cpu_loop_exit(env);
1501 break;
1502#endif
defb0e31
AG
1503 default:
1504 /* unknown sigp */
1505 fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);
1506 cc = 3;
1507 }
1508
1509 return cc;
1510}
1511
defb0e31
AG
1512/* invalidate pte */
1513void HELPER(ipte)(uint64_t pte_addr, uint64_t vaddr)
1514{
1515 uint64_t page = vaddr & TARGET_PAGE_MASK;
1516 uint64_t pte = 0;
1517
1518 /* XXX broadcast to other CPUs */
1519
1520 /* XXX Linux is nice enough to give us the exact pte address.
71e47088 1521 According to spec we'd have to find it out ourselves */
defb0e31 1522 /* XXX Linux is fine with overwriting the pte, the spec requires
71e47088 1523 us to only set the invalid bit */
defb0e31
AG
1524 stq_phys(pte_addr, pte | _PAGE_INVALID);
1525
1526 /* XXX we exploit the fact that Linux passes the exact virtual
71e47088 1527 address here - it's not obliged to! */
defb0e31 1528 tlb_flush_page(env, page);
09ed75f7
AG
1529
1530 /* XXX 31-bit hack */
1531 if (page & 0x80000000) {
1532 tlb_flush_page(env, page & ~0x80000000);
1533 } else {
1534 tlb_flush_page(env, page | 0x80000000);
1535 }
defb0e31
AG
1536}
1537
1538/* flush local tlb */
1539void HELPER(ptlb)(void)
1540{
1541 tlb_flush(env, 1);
1542}
1543
1544/* store using real address */
1545void HELPER(stura)(uint64_t addr, uint32_t v1)
1546{
1547 stw_phys(get_address(0, 0, addr), v1);
1548}
1549
1550/* load real address */
1551uint32_t HELPER(lra)(uint64_t addr, uint32_t r1)
1552{
1553 uint32_t cc = 0;
1554 int old_exc = env->exception_index;
1555 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
1556 uint64_t ret;
1557 int flags;
1558
1559 /* XXX incomplete - has more corner cases */
1560 if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
1561 program_interrupt(env, PGM_SPECIAL_OP, 2);
1562 }
1563
1564 env->exception_index = old_exc;
1565 if (mmu_translate(env, addr, 0, asc, &ret, &flags)) {
1566 cc = 3;
1567 }
1568 if (env->exception_index == EXCP_PGM) {
1569 ret = env->int_pgm_code | 0x80000000;
1570 } else {
1571 ret |= addr & ~TARGET_PAGE_MASK;
1572 }
1573 env->exception_index = old_exc;
1574
1575 if (!(env->psw.mask & PSW_MASK_64)) {
71e47088
BS
1576 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
1577 (ret & 0xffffffffULL);
defb0e31
AG
1578 } else {
1579 env->regs[r1] = ret;
1580 }
1581
1582 return cc;
1583}
1584
1585#endif