]> git.proxmox.com Git - mirror_qemu.git/blame - target-s390x/op_helper.c
target-s390x: split FPU ops
[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
355/* 64/64 -> 128 unsigned multiplication */
356void HELPER(mlg)(uint32_t r1, uint64_t v2)
357{
358#if HOST_LONG_BITS == 64 && defined(__GNUC__)
359 /* assuming 64-bit hosts have __uint128_t */
360 __uint128_t res = (__uint128_t)env->regs[r1 + 1];
71e47088 361
defb0e31
AG
362 res *= (__uint128_t)v2;
363 env->regs[r1] = (uint64_t)(res >> 64);
364 env->regs[r1 + 1] = (uint64_t)res;
365#else
366 mulu64(&env->regs[r1 + 1], &env->regs[r1], env->regs[r1 + 1], v2);
367#endif
368}
369
370/* 128 -> 64/64 unsigned division */
371void HELPER(dlg)(uint32_t r1, uint64_t v2)
372{
373 uint64_t divisor = v2;
374
375 if (!env->regs[r1]) {
376 /* 64 -> 64/64 case */
71e47088
BS
377 env->regs[r1] = env->regs[r1 + 1] % divisor;
378 env->regs[r1 + 1] = env->regs[r1 + 1] / divisor;
defb0e31
AG
379 return;
380 } else {
defb0e31
AG
381#if HOST_LONG_BITS == 64 && defined(__GNUC__)
382 /* assuming 64-bit hosts have __uint128_t */
383 __uint128_t dividend = (((__uint128_t)env->regs[r1]) << 64) |
71e47088 384 (env->regs[r1 + 1]);
defb0e31 385 __uint128_t quotient = dividend / divisor;
defb0e31 386 __uint128_t remainder = dividend % divisor;
71e47088
BS
387
388 env->regs[r1 + 1] = quotient;
defb0e31
AG
389 env->regs[r1] = remainder;
390#else
391 /* 32-bit hosts would need special wrapper functionality - just abort if
392 we encounter such a case; it's very unlikely anyways. */
393 cpu_abort(env, "128 -> 64/64 division not implemented\n");
394#endif
395 }
396}
397
398static inline uint64_t get_address(int x2, int b2, int d2)
399{
400 uint64_t r = d2;
401
402 if (x2) {
403 r += env->regs[x2];
404 }
405
406 if (b2) {
407 r += env->regs[b2];
408 }
409
410 /* 31-Bit mode */
411 if (!(env->psw.mask & PSW_MASK_64)) {
412 r &= 0x7fffffff;
413 }
414
415 return r;
416}
417
418static inline uint64_t get_address_31fix(int reg)
419{
420 uint64_t r = env->regs[reg];
421
422 /* 31-Bit mode */
423 if (!(env->psw.mask & PSW_MASK_64)) {
424 r &= 0x7fffffff;
425 }
426
427 return r;
428}
429
430/* search string (c is byte to search, r2 is string, r1 end of string) */
431uint32_t HELPER(srst)(uint32_t c, uint32_t r1, uint32_t r2)
432{
433 uint64_t i;
434 uint32_t cc = 2;
435 uint64_t str = get_address_31fix(r2);
436 uint64_t end = get_address_31fix(r1);
437
71e47088 438 HELPER_LOG("%s: c %d *r1 0x%" PRIx64 " *r2 0x%" PRIx64 "\n", __func__,
defb0e31
AG
439 c, env->regs[r1], env->regs[r2]);
440
441 for (i = str; i != end; i++) {
442 if (ldub(i) == c) {
443 env->regs[r1] = i;
444 cc = 1;
445 break;
446 }
447 }
448
449 return cc;
450}
451
452/* unsigned string compare (c is string terminator) */
453uint32_t HELPER(clst)(uint32_t c, uint32_t r1, uint32_t r2)
454{
455 uint64_t s1 = get_address_31fix(r1);
456 uint64_t s2 = get_address_31fix(r2);
457 uint8_t v1, v2;
458 uint32_t cc;
71e47088 459
defb0e31
AG
460 c = c & 0xff;
461#ifdef CONFIG_USER_ONLY
462 if (!c) {
463 HELPER_LOG("%s: comparing '%s' and '%s'\n",
71e47088 464 __func__, (char *)g2h(s1), (char *)g2h(s2));
defb0e31
AG
465 }
466#endif
467 for (;;) {
468 v1 = ldub(s1);
469 v2 = ldub(s2);
470 if ((v1 == c || v2 == c) || (v1 != v2)) {
471 break;
472 }
473 s1++;
474 s2++;
475 }
476
477 if (v1 == v2) {
478 cc = 0;
479 } else {
480 cc = (v1 < v2) ? 1 : 2;
481 /* FIXME: 31-bit mode! */
482 env->regs[r1] = s1;
483 env->regs[r2] = s2;
484 }
485 return cc;
486}
487
488/* move page */
489void HELPER(mvpg)(uint64_t r0, uint64_t r1, uint64_t r2)
490{
491 /* XXX missing r0 handling */
492#ifdef CONFIG_USER_ONLY
493 int i;
494
495 for (i = 0; i < TARGET_PAGE_SIZE; i++) {
496 stb(r1 + i, ldub(r2 + i));
497 }
498#else
499 mvc_fast_memmove(env, TARGET_PAGE_SIZE, r1, r2);
500#endif
501}
502
503/* string copy (c is string terminator) */
504void HELPER(mvst)(uint32_t c, uint32_t r1, uint32_t r2)
505{
506 uint64_t dest = get_address_31fix(r1);
507 uint64_t src = get_address_31fix(r2);
508 uint8_t v;
71e47088 509
defb0e31
AG
510 c = c & 0xff;
511#ifdef CONFIG_USER_ONLY
512 if (!c) {
71e47088 513 HELPER_LOG("%s: copy '%s' to 0x%lx\n", __func__, (char *)g2h(src),
defb0e31
AG
514 dest);
515 }
516#endif
517 for (;;) {
518 v = ldub(src);
519 stb(dest, v);
520 if (v == c) {
521 break;
522 }
523 src++;
524 dest++;
525 }
526 env->regs[r1] = dest; /* FIXME: 31-bit mode! */
527}
528
529/* compare and swap 64-bit */
530uint32_t HELPER(csg)(uint32_t r1, uint64_t a2, uint32_t r3)
531{
532 /* FIXME: locking? */
533 uint32_t cc;
534 uint64_t v2 = ldq(a2);
71e47088 535
defb0e31
AG
536 if (env->regs[r1] == v2) {
537 cc = 0;
538 stq(a2, env->regs[r3]);
539 } else {
540 cc = 1;
541 env->regs[r1] = v2;
542 }
543 return cc;
544}
545
546/* compare double and swap 64-bit */
547uint32_t HELPER(cdsg)(uint32_t r1, uint64_t a2, uint32_t r3)
548{
549 /* FIXME: locking? */
550 uint32_t cc;
551 uint64_t v2_hi = ldq(a2);
552 uint64_t v2_lo = ldq(a2 + 8);
553 uint64_t v1_hi = env->regs[r1];
554 uint64_t v1_lo = env->regs[r1 + 1];
555
556 if ((v1_hi == v2_hi) && (v1_lo == v2_lo)) {
557 cc = 0;
558 stq(a2, env->regs[r3]);
559 stq(a2 + 8, env->regs[r3 + 1]);
560 } else {
561 cc = 1;
562 env->regs[r1] = v2_hi;
563 env->regs[r1 + 1] = v2_lo;
564 }
565
566 return cc;
567}
568
569/* compare and swap 32-bit */
570uint32_t HELPER(cs)(uint32_t r1, uint64_t a2, uint32_t r3)
571{
572 /* FIXME: locking? */
573 uint32_t cc;
defb0e31 574 uint32_t v2 = ldl(a2);
71e47088
BS
575
576 HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __func__, r1, a2, r3);
defb0e31
AG
577 if (((uint32_t)env->regs[r1]) == v2) {
578 cc = 0;
579 stl(a2, (uint32_t)env->regs[r3]);
580 } else {
581 cc = 1;
582 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | v2;
583 }
584 return cc;
585}
586
587static uint32_t helper_icm(uint32_t r1, uint64_t address, uint32_t mask)
588{
589 int pos = 24; /* top of the lower half of r1 */
590 uint64_t rmask = 0xff000000ULL;
591 uint8_t val = 0;
592 int ccd = 0;
593 uint32_t cc = 0;
594
595 while (mask) {
596 if (mask & 8) {
597 env->regs[r1] &= ~rmask;
598 val = ldub(address);
599 if ((val & 0x80) && !ccd) {
600 cc = 1;
601 }
602 ccd = 1;
603 if (val && cc == 0) {
604 cc = 2;
605 }
606 env->regs[r1] |= (uint64_t)val << pos;
607 address++;
608 }
609 mask = (mask << 1) & 0xf;
610 pos -= 8;
611 rmask >>= 8;
612 }
613
614 return cc;
615}
616
617/* execute instruction
618 this instruction executes an insn modified with the contents of r1
619 it does not change the executed instruction in memory
620 it does not change the program counter
621 in other words: tricky...
622 currently implemented by interpreting the cases it is most commonly used in
71e47088 623*/
defb0e31
AG
624uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret)
625{
626 uint16_t insn = lduw_code(addr);
71e47088
BS
627
628 HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __func__, v1, addr,
629 insn);
defb0e31
AG
630 if ((insn & 0xf0ff) == 0xd000) {
631 uint32_t l, insn2, b1, b2, d1, d2;
71e47088 632
defb0e31
AG
633 l = v1 & 0xff;
634 insn2 = ldl_code(addr + 2);
635 b1 = (insn2 >> 28) & 0xf;
636 b2 = (insn2 >> 12) & 0xf;
637 d1 = (insn2 >> 16) & 0xfff;
638 d2 = insn2 & 0xfff;
639 switch (insn & 0xf00) {
640 case 0x200:
641 helper_mvc(l, get_address(0, b1, d1), get_address(0, b2, d2));
642 break;
643 case 0x500:
644 cc = helper_clc(l, get_address(0, b1, d1), get_address(0, b2, d2));
645 break;
646 case 0x700:
647 cc = helper_xc(l, get_address(0, b1, d1), get_address(0, b2, d2));
648 break;
7d77793d
AG
649 case 0xc00:
650 helper_tr(l, get_address(0, b1, d1), get_address(0, b2, d2));
651 break;
defb0e31
AG
652 default:
653 goto abort;
654 break;
655 }
656 } else if ((insn & 0xff00) == 0x0a00) {
657 /* supervisor call */
71e47088 658 HELPER_LOG("%s: svc %ld via execute\n", __func__, (insn | v1) & 0xff);
defb0e31 659 env->psw.addr = ret - 4;
71e47088 660 env->int_svc_code = (insn | v1) & 0xff;
defb0e31
AG
661 env->int_svc_ilc = 4;
662 helper_exception(EXCP_SVC);
663 } else if ((insn & 0xff00) == 0xbf00) {
664 uint32_t insn2, r1, r3, b2, d2;
71e47088 665
defb0e31
AG
666 insn2 = ldl_code(addr + 2);
667 r1 = (insn2 >> 20) & 0xf;
668 r3 = (insn2 >> 16) & 0xf;
669 b2 = (insn2 >> 12) & 0xf;
670 d2 = insn2 & 0xfff;
671 cc = helper_icm(r1, get_address(0, b2, d2), r3);
672 } else {
71e47088 673 abort:
defb0e31
AG
674 cpu_abort(env, "EXECUTE on instruction prefix 0x%x not implemented\n",
675 insn);
676 }
677 return cc;
678}
679
680/* absolute value 32-bit */
681uint32_t HELPER(abs_i32)(int32_t val)
682{
683 if (val < 0) {
684 return -val;
685 } else {
686 return val;
687 }
688}
689
690/* negative absolute value 32-bit */
691int32_t HELPER(nabs_i32)(int32_t val)
692{
693 if (val < 0) {
694 return val;
695 } else {
696 return -val;
697 }
698}
699
700/* absolute value 64-bit */
701uint64_t HELPER(abs_i64)(int64_t val)
702{
71e47088 703 HELPER_LOG("%s: val 0x%" PRIx64 "\n", __func__, val);
defb0e31
AG
704
705 if (val < 0) {
706 return -val;
707 } else {
708 return val;
709 }
710}
711
712/* negative absolute value 64-bit */
713int64_t HELPER(nabs_i64)(int64_t val)
714{
715 if (val < 0) {
716 return val;
717 } else {
718 return -val;
719 }
720}
721
722/* add with carry 32-bit unsigned */
723uint32_t HELPER(addc_u32)(uint32_t cc, uint32_t v1, uint32_t v2)
724{
725 uint32_t res;
726
727 res = v1 + v2;
728 if (cc & 2) {
729 res++;
730 }
731
732 return res;
733}
734
735/* store character under mask high operates on the upper half of r1 */
736void HELPER(stcmh)(uint32_t r1, uint64_t address, uint32_t mask)
737{
738 int pos = 56; /* top of the upper half of r1 */
739
740 while (mask) {
741 if (mask & 8) {
742 stb(address, (env->regs[r1] >> pos) & 0xff);
743 address++;
744 }
745 mask = (mask << 1) & 0xf;
746 pos -= 8;
747 }
748}
749
750/* insert character under mask high; same as icm, but operates on the
751 upper half of r1 */
752uint32_t HELPER(icmh)(uint32_t r1, uint64_t address, uint32_t mask)
753{
754 int pos = 56; /* top of the upper half of r1 */
755 uint64_t rmask = 0xff00000000000000ULL;
756 uint8_t val = 0;
757 int ccd = 0;
758 uint32_t cc = 0;
759
760 while (mask) {
761 if (mask & 8) {
762 env->regs[r1] &= ~rmask;
763 val = ldub(address);
764 if ((val & 0x80) && !ccd) {
765 cc = 1;
766 }
767 ccd = 1;
768 if (val && cc == 0) {
769 cc = 2;
770 }
771 env->regs[r1] |= (uint64_t)val << pos;
772 address++;
773 }
774 mask = (mask << 1) & 0xf;
775 pos -= 8;
776 rmask >>= 8;
777 }
778
779 return cc;
780}
781
782/* insert psw mask and condition code into r1 */
783void HELPER(ipm)(uint32_t cc, uint32_t r1)
784{
785 uint64_t r = env->regs[r1];
786
787 r &= 0xffffffff00ffffffULL;
71e47088 788 r |= (cc << 28) | ((env->psw.mask >> 40) & 0xf);
defb0e31 789 env->regs[r1] = r;
71e47088 790 HELPER_LOG("%s: cc %d psw.mask 0x%lx r1 0x%lx\n", __func__,
defb0e31
AG
791 cc, env->psw.mask, r);
792}
793
794/* load access registers r1 to r3 from memory at a2 */
795void HELPER(lam)(uint32_t r1, uint64_t a2, uint32_t r3)
796{
797 int i;
798
799 for (i = r1;; i = (i + 1) % 16) {
800 env->aregs[i] = ldl(a2);
801 a2 += 4;
802
803 if (i == r3) {
804 break;
805 }
806 }
807}
808
809/* store access registers r1 to r3 in memory at a2 */
810void HELPER(stam)(uint32_t r1, uint64_t a2, uint32_t r3)
811{
812 int i;
813
814 for (i = r1;; i = (i + 1) % 16) {
815 stl(a2, env->aregs[i]);
816 a2 += 4;
817
818 if (i == r3) {
819 break;
820 }
821 }
822}
823
824/* move long */
825uint32_t HELPER(mvcl)(uint32_t r1, uint32_t r2)
826{
827 uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
828 uint64_t dest = get_address_31fix(r1);
829 uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
830 uint64_t src = get_address_31fix(r2);
831 uint8_t pad = src >> 24;
832 uint8_t v;
833 uint32_t cc;
834
835 if (destlen == srclen) {
836 cc = 0;
837 } else if (destlen < srclen) {
838 cc = 1;
839 } else {
840 cc = 2;
841 }
842
843 if (srclen > destlen) {
844 srclen = destlen;
845 }
846
847 for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
848 v = ldub(src);
849 stb(dest, v);
850 }
851
852 for (; destlen; dest++, destlen--) {
853 stb(dest, pad);
854 }
855
856 env->regs[r1 + 1] = destlen;
857 /* can't use srclen here, we trunc'ed it */
858 env->regs[r2 + 1] -= src - env->regs[r2];
859 env->regs[r1] = dest;
860 env->regs[r2] = src;
861
862 return cc;
863}
864
865/* move long extended another memcopy insn with more bells and whistles */
866uint32_t HELPER(mvcle)(uint32_t r1, uint64_t a2, uint32_t r3)
867{
868 uint64_t destlen = env->regs[r1 + 1];
869 uint64_t dest = env->regs[r1];
870 uint64_t srclen = env->regs[r3 + 1];
871 uint64_t src = env->regs[r3];
872 uint8_t pad = a2 & 0xff;
873 uint8_t v;
874 uint32_t cc;
875
876 if (!(env->psw.mask & PSW_MASK_64)) {
877 destlen = (uint32_t)destlen;
878 srclen = (uint32_t)srclen;
879 dest &= 0x7fffffff;
880 src &= 0x7fffffff;
881 }
882
883 if (destlen == srclen) {
884 cc = 0;
885 } else if (destlen < srclen) {
886 cc = 1;
887 } else {
888 cc = 2;
889 }
890
891 if (srclen > destlen) {
892 srclen = destlen;
893 }
894
895 for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
896 v = ldub(src);
897 stb(dest, v);
898 }
899
900 for (; destlen; dest++, destlen--) {
901 stb(dest, pad);
902 }
903
904 env->regs[r1 + 1] = destlen;
905 /* can't use srclen here, we trunc'ed it */
906 /* FIXME: 31-bit mode! */
907 env->regs[r3 + 1] -= src - env->regs[r3];
908 env->regs[r1] = dest;
909 env->regs[r3] = src;
910
911 return cc;
912}
913
914/* compare logical long extended memcompare insn with padding */
915uint32_t HELPER(clcle)(uint32_t r1, uint64_t a2, uint32_t r3)
916{
917 uint64_t destlen = env->regs[r1 + 1];
918 uint64_t dest = get_address_31fix(r1);
919 uint64_t srclen = env->regs[r3 + 1];
920 uint64_t src = get_address_31fix(r3);
921 uint8_t pad = a2 & 0xff;
71e47088 922 uint8_t v1 = 0, v2 = 0;
defb0e31
AG
923 uint32_t cc = 0;
924
925 if (!(destlen || srclen)) {
926 return cc;
927 }
928
929 if (srclen > destlen) {
930 srclen = destlen;
931 }
932
933 for (; destlen || srclen; src++, dest++, destlen--, srclen--) {
934 v1 = srclen ? ldub(src) : pad;
935 v2 = destlen ? ldub(dest) : pad;
936 if (v1 != v2) {
937 cc = (v1 < v2) ? 1 : 2;
938 break;
939 }
940 }
941
942 env->regs[r1 + 1] = destlen;
943 /* can't use srclen here, we trunc'ed it */
944 env->regs[r3 + 1] -= src - env->regs[r3];
945 env->regs[r1] = dest;
946 env->regs[r3] = src;
947
948 return cc;
949}
950
951/* subtract unsigned v2 from v1 with borrow */
952uint32_t HELPER(slb)(uint32_t cc, uint32_t r1, uint32_t v2)
953{
954 uint32_t v1 = env->regs[r1];
955 uint32_t res = v1 + (~v2) + (cc >> 1);
956
957 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | res;
958 if (cc & 2) {
959 /* borrow */
960 return v1 ? 1 : 0;
961 } else {
962 return v1 ? 3 : 2;
963 }
964}
965
966/* subtract unsigned v2 from v1 with borrow */
967uint32_t HELPER(slbg)(uint32_t cc, uint32_t r1, uint64_t v1, uint64_t v2)
968{
969 uint64_t res = v1 + (~v2) + (cc >> 1);
970
971 env->regs[r1] = res;
972 if (cc & 2) {
973 /* borrow */
974 return v1 ? 1 : 0;
975 } else {
976 return v1 ? 3 : 2;
977 }
978}
979
defb0e31
AG
980/* find leftmost one */
981uint32_t HELPER(flogr)(uint32_t r1, uint64_t v2)
982{
983 uint64_t res = 0;
984 uint64_t ov2 = v2;
985
986 while (!(v2 & 0x8000000000000000ULL) && v2) {
987 v2 <<= 1;
988 res++;
989 }
990
991 if (!v2) {
992 env->regs[r1] = 64;
993 env->regs[r1 + 1] = 0;
994 return 0;
995 } else {
996 env->regs[r1] = res;
997 env->regs[r1 + 1] = ov2 & ~(0x8000000000000000ULL >> res);
998 return 2;
999 }
1000}
1001
defb0e31
AG
1002/* checksum */
1003void HELPER(cksm)(uint32_t r1, uint32_t r2)
1004{
1005 uint64_t src = get_address_31fix(r2);
1006 uint64_t src_len = env->regs[(r2 + 1) & 15];
5b185639 1007 uint64_t cksm = (uint32_t)env->regs[r1];
defb0e31
AG
1008
1009 while (src_len >= 4) {
1010 cksm += ldl(src);
defb0e31
AG
1011
1012 /* move to next word */
1013 src_len -= 4;
1014 src += 4;
1015 }
1016
1017 switch (src_len) {
1018 case 0:
1019 break;
1020 case 1:
5b185639 1021 cksm += ldub(src) << 24;
defb0e31
AG
1022 break;
1023 case 2:
5b185639 1024 cksm += lduw(src) << 16;
defb0e31
AG
1025 break;
1026 case 3:
5b185639
AG
1027 cksm += lduw(src) << 16;
1028 cksm += ldub(src + 2) << 8;
defb0e31
AG
1029 break;
1030 }
1031
1032 /* indicate we've processed everything */
5b185639 1033 env->regs[r2] = src + src_len;
defb0e31
AG
1034 env->regs[(r2 + 1) & 15] = 0;
1035
1036 /* store result */
5b185639 1037 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
71e47088 1038 ((uint32_t)cksm + (cksm >> 32));
defb0e31
AG
1039}
1040
a4e3ad19 1041static inline uint32_t cc_calc_ltgt_32(CPUS390XState *env, int32_t src,
defb0e31
AG
1042 int32_t dst)
1043{
1044 if (src == dst) {
1045 return 0;
1046 } else if (src < dst) {
1047 return 1;
1048 } else {
1049 return 2;
1050 }
1051}
1052
a4e3ad19 1053static inline uint32_t cc_calc_ltgt0_32(CPUS390XState *env, int32_t dst)
defb0e31
AG
1054{
1055 return cc_calc_ltgt_32(env, dst, 0);
1056}
1057
a4e3ad19 1058static inline uint32_t cc_calc_ltgt_64(CPUS390XState *env, int64_t src,
defb0e31
AG
1059 int64_t dst)
1060{
1061 if (src == dst) {
1062 return 0;
1063 } else if (src < dst) {
1064 return 1;
1065 } else {
1066 return 2;
1067 }
1068}
1069
a4e3ad19 1070static inline uint32_t cc_calc_ltgt0_64(CPUS390XState *env, int64_t dst)
defb0e31
AG
1071{
1072 return cc_calc_ltgt_64(env, dst, 0);
1073}
1074
a4e3ad19 1075static inline uint32_t cc_calc_ltugtu_32(CPUS390XState *env, uint32_t src,
defb0e31
AG
1076 uint32_t dst)
1077{
1078 if (src == dst) {
1079 return 0;
1080 } else if (src < dst) {
1081 return 1;
1082 } else {
1083 return 2;
1084 }
1085}
1086
a4e3ad19 1087static inline uint32_t cc_calc_ltugtu_64(CPUS390XState *env, uint64_t src,
defb0e31
AG
1088 uint64_t dst)
1089{
1090 if (src == dst) {
1091 return 0;
1092 } else if (src < dst) {
1093 return 1;
1094 } else {
1095 return 2;
1096 }
1097}
1098
71e47088
BS
1099static inline uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val,
1100 uint32_t mask)
defb0e31 1101{
defb0e31 1102 uint16_t r = val & mask;
71e47088
BS
1103
1104 HELPER_LOG("%s: val 0x%x mask 0x%x\n", __func__, val, mask);
defb0e31
AG
1105 if (r == 0 || mask == 0) {
1106 return 0;
1107 } else if (r == mask) {
1108 return 3;
1109 } else {
1110 return 1;
1111 }
1112}
1113
1114/* set condition code for test under mask */
71e47088
BS
1115static inline uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val,
1116 uint32_t mask)
defb0e31
AG
1117{
1118 uint16_t r = val & mask;
71e47088
BS
1119
1120 HELPER_LOG("%s: val 0x%lx mask 0x%x r 0x%x\n", __func__, val, mask, r);
defb0e31
AG
1121 if (r == 0 || mask == 0) {
1122 return 0;
1123 } else if (r == mask) {
1124 return 3;
1125 } else {
1126 while (!(mask & 0x8000)) {
1127 mask <<= 1;
1128 val <<= 1;
1129 }
1130 if (val & 0x8000) {
1131 return 2;
1132 } else {
1133 return 1;
1134 }
1135 }
1136}
1137
a4e3ad19 1138static inline uint32_t cc_calc_nz(CPUS390XState *env, uint64_t dst)
defb0e31
AG
1139{
1140 return !!dst;
1141}
1142
71e47088
BS
1143static inline uint32_t cc_calc_add_64(CPUS390XState *env, int64_t a1,
1144 int64_t a2, int64_t ar)
defb0e31
AG
1145{
1146 if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
1147 return 3; /* overflow */
1148 } else {
1149 if (ar < 0) {
1150 return 1;
1151 } else if (ar > 0) {
1152 return 2;
1153 } else {
1154 return 0;
1155 }
1156 }
1157}
1158
71e47088
BS
1159static inline uint32_t cc_calc_addu_64(CPUS390XState *env, uint64_t a1,
1160 uint64_t a2, uint64_t ar)
defb0e31
AG
1161{
1162 if (ar == 0) {
1163 if (a1) {
1164 return 2;
1165 } else {
1166 return 0;
1167 }
1168 } else {
1169 if (ar < a1 || ar < a2) {
71e47088 1170 return 3;
defb0e31 1171 } else {
71e47088 1172 return 1;
defb0e31
AG
1173 }
1174 }
1175}
1176
71e47088
BS
1177static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1,
1178 int64_t a2, int64_t ar)
defb0e31
AG
1179{
1180 if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
1181 return 3; /* overflow */
1182 } else {
1183 if (ar < 0) {
1184 return 1;
1185 } else if (ar > 0) {
1186 return 2;
1187 } else {
1188 return 0;
1189 }
1190 }
1191}
1192
71e47088
BS
1193static inline uint32_t cc_calc_subu_64(CPUS390XState *env, uint64_t a1,
1194 uint64_t a2, uint64_t ar)
defb0e31
AG
1195{
1196 if (ar == 0) {
1197 return 2;
1198 } else {
1199 if (a2 > a1) {
1200 return 1;
1201 } else {
1202 return 3;
1203 }
1204 }
1205}
1206
a4e3ad19 1207static inline uint32_t cc_calc_abs_64(CPUS390XState *env, int64_t dst)
defb0e31
AG
1208{
1209 if ((uint64_t)dst == 0x8000000000000000ULL) {
1210 return 3;
1211 } else if (dst) {
1212 return 1;
1213 } else {
1214 return 0;
1215 }
1216}
1217
a4e3ad19 1218static inline uint32_t cc_calc_nabs_64(CPUS390XState *env, int64_t dst)
defb0e31
AG
1219{
1220 return !!dst;
1221}
1222
a4e3ad19 1223static inline uint32_t cc_calc_comp_64(CPUS390XState *env, int64_t dst)
defb0e31
AG
1224{
1225 if ((uint64_t)dst == 0x8000000000000000ULL) {
1226 return 3;
1227 } else if (dst < 0) {
1228 return 1;
1229 } else if (dst > 0) {
1230 return 2;
1231 } else {
1232 return 0;
1233 }
1234}
1235
1236
71e47088
BS
1237static inline uint32_t cc_calc_add_32(CPUS390XState *env, int32_t a1,
1238 int32_t a2, int32_t ar)
defb0e31
AG
1239{
1240 if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
1241 return 3; /* overflow */
1242 } else {
1243 if (ar < 0) {
1244 return 1;
1245 } else if (ar > 0) {
1246 return 2;
1247 } else {
1248 return 0;
1249 }
1250 }
1251}
1252
71e47088
BS
1253static inline uint32_t cc_calc_addu_32(CPUS390XState *env, uint32_t a1,
1254 uint32_t a2, uint32_t ar)
defb0e31
AG
1255{
1256 if (ar == 0) {
1257 if (a1) {
71e47088 1258 return 2;
defb0e31 1259 } else {
71e47088 1260 return 0;
defb0e31
AG
1261 }
1262 } else {
1263 if (ar < a1 || ar < a2) {
71e47088 1264 return 3;
defb0e31 1265 } else {
71e47088 1266 return 1;
defb0e31
AG
1267 }
1268 }
1269}
1270
71e47088
BS
1271static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1,
1272 int32_t a2, int32_t ar)
defb0e31
AG
1273{
1274 if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
1275 return 3; /* overflow */
1276 } else {
1277 if (ar < 0) {
1278 return 1;
1279 } else if (ar > 0) {
1280 return 2;
1281 } else {
1282 return 0;
1283 }
1284 }
1285}
1286
71e47088
BS
1287static inline uint32_t cc_calc_subu_32(CPUS390XState *env, uint32_t a1,
1288 uint32_t a2, uint32_t ar)
defb0e31
AG
1289{
1290 if (ar == 0) {
1291 return 2;
1292 } else {
1293 if (a2 > a1) {
1294 return 1;
1295 } else {
1296 return 3;
1297 }
1298 }
1299}
1300
a4e3ad19 1301static inline uint32_t cc_calc_abs_32(CPUS390XState *env, int32_t dst)
defb0e31
AG
1302{
1303 if ((uint32_t)dst == 0x80000000UL) {
1304 return 3;
1305 } else if (dst) {
1306 return 1;
1307 } else {
1308 return 0;
1309 }
1310}
1311
a4e3ad19 1312static inline uint32_t cc_calc_nabs_32(CPUS390XState *env, int32_t dst)
defb0e31
AG
1313{
1314 return !!dst;
1315}
1316
a4e3ad19 1317static inline uint32_t cc_calc_comp_32(CPUS390XState *env, int32_t dst)
defb0e31
AG
1318{
1319 if ((uint32_t)dst == 0x80000000UL) {
1320 return 3;
1321 } else if (dst < 0) {
1322 return 1;
1323 } else if (dst > 0) {
1324 return 2;
1325 } else {
1326 return 0;
1327 }
1328}
1329
1330/* calculate condition code for insert character under mask insn */
71e47088
BS
1331static inline uint32_t cc_calc_icm_32(CPUS390XState *env, uint32_t mask,
1332 uint32_t val)
defb0e31 1333{
defb0e31
AG
1334 uint32_t cc;
1335
71e47088 1336 HELPER_LOG("%s: mask 0x%x val %d\n", __func__, mask, val);
defb0e31
AG
1337 if (mask == 0xf) {
1338 if (!val) {
1339 return 0;
1340 } else if (val & 0x80000000) {
1341 return 1;
1342 } else {
1343 return 2;
1344 }
1345 }
1346
1347 if (!val || !mask) {
1348 cc = 0;
1349 } else {
1350 while (mask != 1) {
1351 mask >>= 1;
1352 val >>= 8;
1353 }
1354 if (val & 0x80) {
1355 cc = 1;
1356 } else {
1357 cc = 2;
1358 }
1359 }
1360 return cc;
1361}
1362
71e47088
BS
1363static inline uint32_t cc_calc_slag(CPUS390XState *env, uint64_t src,
1364 uint64_t shift)
defb0e31
AG
1365{
1366 uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift);
1367 uint64_t match, r;
1368
1369 /* check if the sign bit stays the same */
1370 if (src & (1ULL << 63)) {
1371 match = mask;
1372 } else {
1373 match = 0;
1374 }
1375
1376 if ((src & mask) != match) {
1377 /* overflow */
1378 return 3;
1379 }
1380
1381 r = ((src << shift) & ((1ULL << 63) - 1)) | (src & (1ULL << 63));
1382
1383 if ((int64_t)r == 0) {
1384 return 0;
1385 } else if ((int64_t)r < 0) {
1386 return 1;
1387 }
1388
1389 return 2;
1390}
1391
1392
71e47088
BS
1393static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op,
1394 uint64_t src, uint64_t dst, uint64_t vr)
defb0e31
AG
1395{
1396 uint32_t r = 0;
1397
1398 switch (cc_op) {
1399 case CC_OP_CONST0:
1400 case CC_OP_CONST1:
1401 case CC_OP_CONST2:
1402 case CC_OP_CONST3:
1403 /* cc_op value _is_ cc */
1404 r = cc_op;
1405 break;
1406 case CC_OP_LTGT0_32:
1407 r = cc_calc_ltgt0_32(env, dst);
1408 break;
1409 case CC_OP_LTGT0_64:
1410 r = cc_calc_ltgt0_64(env, dst);
1411 break;
1412 case CC_OP_LTGT_32:
1413 r = cc_calc_ltgt_32(env, src, dst);
1414 break;
1415 case CC_OP_LTGT_64:
1416 r = cc_calc_ltgt_64(env, src, dst);
1417 break;
1418 case CC_OP_LTUGTU_32:
1419 r = cc_calc_ltugtu_32(env, src, dst);
1420 break;
1421 case CC_OP_LTUGTU_64:
1422 r = cc_calc_ltugtu_64(env, src, dst);
1423 break;
1424 case CC_OP_TM_32:
1425 r = cc_calc_tm_32(env, src, dst);
1426 break;
1427 case CC_OP_TM_64:
1428 r = cc_calc_tm_64(env, src, dst);
1429 break;
1430 case CC_OP_NZ:
1431 r = cc_calc_nz(env, dst);
1432 break;
1433 case CC_OP_ADD_64:
1434 r = cc_calc_add_64(env, src, dst, vr);
1435 break;
1436 case CC_OP_ADDU_64:
1437 r = cc_calc_addu_64(env, src, dst, vr);
1438 break;
1439 case CC_OP_SUB_64:
1440 r = cc_calc_sub_64(env, src, dst, vr);
1441 break;
1442 case CC_OP_SUBU_64:
1443 r = cc_calc_subu_64(env, src, dst, vr);
1444 break;
1445 case CC_OP_ABS_64:
1446 r = cc_calc_abs_64(env, dst);
1447 break;
1448 case CC_OP_NABS_64:
1449 r = cc_calc_nabs_64(env, dst);
1450 break;
1451 case CC_OP_COMP_64:
1452 r = cc_calc_comp_64(env, dst);
1453 break;
1454
1455 case CC_OP_ADD_32:
1456 r = cc_calc_add_32(env, src, dst, vr);
1457 break;
1458 case CC_OP_ADDU_32:
1459 r = cc_calc_addu_32(env, src, dst, vr);
1460 break;
1461 case CC_OP_SUB_32:
1462 r = cc_calc_sub_32(env, src, dst, vr);
1463 break;
1464 case CC_OP_SUBU_32:
1465 r = cc_calc_subu_32(env, src, dst, vr);
1466 break;
1467 case CC_OP_ABS_32:
1468 r = cc_calc_abs_64(env, dst);
1469 break;
1470 case CC_OP_NABS_32:
1471 r = cc_calc_nabs_64(env, dst);
1472 break;
1473 case CC_OP_COMP_32:
1474 r = cc_calc_comp_32(env, dst);
1475 break;
1476
1477 case CC_OP_ICM:
1478 r = cc_calc_icm_32(env, src, dst);
1479 break;
1480 case CC_OP_SLAG:
1481 r = cc_calc_slag(env, src, dst);
1482 break;
1483
1484 case CC_OP_LTGT_F32:
1485 r = set_cc_f32(src, dst);
1486 break;
1487 case CC_OP_LTGT_F64:
1488 r = set_cc_f64(src, dst);
1489 break;
1490 case CC_OP_NZ_F32:
1491 r = set_cc_nz_f32(dst);
1492 break;
1493 case CC_OP_NZ_F64:
1494 r = set_cc_nz_f64(dst);
1495 break;
1496
1497 default:
1498 cpu_abort(env, "Unknown CC operation: %s\n", cc_name(cc_op));
1499 }
1500
71e47088 1501 HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __func__,
defb0e31
AG
1502 cc_name(cc_op), src, dst, vr, r);
1503 return r;
1504}
1505
a4e3ad19 1506uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
d5a43964
AG
1507 uint64_t vr)
1508{
defb0e31
AG
1509 return do_calc_cc(env, cc_op, src, dst, vr);
1510}
1511
1512uint32_t HELPER(calc_cc)(uint32_t cc_op, uint64_t src, uint64_t dst,
1513 uint64_t vr)
1514{
1515 return do_calc_cc(env, cc_op, src, dst, vr);
1516}
1517
1518uint64_t HELPER(cvd)(int32_t bin)
1519{
1520 /* positive 0 */
1521 uint64_t dec = 0x0c;
1522 int shift = 4;
1523
1524 if (bin < 0) {
1525 bin = -bin;
1526 dec = 0x0d;
1527 }
1528
1529 for (shift = 4; (shift < 64) && bin; shift += 4) {
1530 int current_number = bin % 10;
1531
1532 dec |= (current_number) << shift;
1533 bin /= 10;
1534 }
1535
1536 return dec;
1537}
1538
1539void HELPER(unpk)(uint32_t len, uint64_t dest, uint64_t src)
1540{
1541 int len_dest = len >> 4;
1542 int len_src = len & 0xf;
1543 uint8_t b;
1544 int second_nibble = 0;
1545
1546 dest += len_dest;
1547 src += len_src;
1548
1549 /* last byte is special, it only flips the nibbles */
1550 b = ldub(src);
1551 stb(dest, (b << 4) | (b >> 4));
1552 src--;
1553 len_src--;
1554
1555 /* now pad every nibble with 0xf0 */
1556
1557 while (len_dest > 0) {
1558 uint8_t cur_byte = 0;
1559
1560 if (len_src > 0) {
1561 cur_byte = ldub(src);
1562 }
1563
1564 len_dest--;
1565 dest--;
1566
1567 /* only advance one nibble at a time */
1568 if (second_nibble) {
1569 cur_byte >>= 4;
1570 len_src--;
1571 src--;
1572 }
1573 second_nibble = !second_nibble;
1574
1575 /* digit */
1576 cur_byte = (cur_byte & 0xf);
1577 /* zone bits */
1578 cur_byte |= 0xf0;
1579
1580 stb(dest, cur_byte);
1581 }
1582}
1583
1584void HELPER(tr)(uint32_t len, uint64_t array, uint64_t trans)
1585{
1586 int i;
1587
1588 for (i = 0; i <= len; i++) {
1589 uint8_t byte = ldub(array + i);
1590 uint8_t new_byte = ldub(trans + byte);
71e47088 1591
defb0e31
AG
1592 stb(array + i, new_byte);
1593 }
1594}
1595
1596#ifndef CONFIG_USER_ONLY
1597
1598void HELPER(load_psw)(uint64_t mask, uint64_t addr)
1599{
1600 load_psw(env, mask, addr);
1162c041 1601 cpu_loop_exit(env);
defb0e31
AG
1602}
1603
a4e3ad19 1604static void program_interrupt(CPUS390XState *env, uint32_t code, int ilc)
defb0e31
AG
1605{
1606 qemu_log("program interrupt at %#" PRIx64 "\n", env->psw.addr);
1607
1608 if (kvm_enabled()) {
af2be207 1609#ifdef CONFIG_KVM
defb0e31 1610 kvm_s390_interrupt(env, KVM_S390_PROGRAM_INT, code);
af2be207 1611#endif
defb0e31
AG
1612 } else {
1613 env->int_pgm_code = code;
1614 env->int_pgm_ilc = ilc;
1615 env->exception_index = EXCP_PGM;
1162c041 1616 cpu_loop_exit(env);
defb0e31
AG
1617 }
1618}
1619
9abf567d 1620/*
71e47088 1621 * ret < 0 indicates program check, ret = 0, 1, 2, 3 -> cc
9abf567d 1622 */
a4e3ad19 1623int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
defb0e31
AG
1624{
1625 int r = 0;
22486aa0 1626 int shift = 0;
defb0e31
AG
1627
1628#ifdef DEBUG_HELPER
1629 printf("sclp(0x%x, 0x%" PRIx64 ")\n", sccb, code);
1630#endif
1631
9abf567d
CB
1632 /* basic checks */
1633 if (!memory_region_is_ram(phys_page_find(sccb >> TARGET_PAGE_BITS)->mr)) {
1634 return -PGM_ADDRESSING;
1635 }
defb0e31 1636 if (sccb & ~0x7ffffff8ul) {
9abf567d 1637 return -PGM_SPECIFICATION;
defb0e31
AG
1638 }
1639
71e47088
BS
1640 switch (code) {
1641 case SCLP_CMDW_READ_SCP_INFO:
1642 case SCLP_CMDW_READ_SCP_INFO_FORCED:
1643 while ((ram_size >> (20 + shift)) > 65535) {
1644 shift++;
1645 }
1646 stw_phys(sccb + SCP_MEM_CODE, ram_size >> (20 + shift));
1647 stb_phys(sccb + SCP_INCREMENT, 1 << shift);
1648 stw_phys(sccb + SCP_RESPONSE_CODE, 0x10);
defb0e31 1649
71e47088
BS
1650 s390_sclp_extint(sccb & ~3);
1651 break;
1652 default:
defb0e31 1653#ifdef DEBUG_HELPER
71e47088 1654 printf("KVM: invalid sclp call 0x%x / 0x%" PRIx64 "x\n", sccb, code);
defb0e31 1655#endif
71e47088
BS
1656 r = 3;
1657 break;
defb0e31
AG
1658 }
1659
defb0e31
AG
1660 return r;
1661}
1662
1663/* SCLP service call */
1664uint32_t HELPER(servc)(uint32_t r1, uint64_t r2)
1665{
9abf567d 1666 int r;
defb0e31 1667
9abf567d
CB
1668 r = sclp_service_call(env, r1, r2);
1669 if (r < 0) {
1670 program_interrupt(env, -r, 4);
1671 return 0;
1672 }
1673 return r;
defb0e31
AG
1674}
1675
1676/* DIAG */
1677uint64_t HELPER(diag)(uint32_t num, uint64_t mem, uint64_t code)
1678{
1679 uint64_t r;
1680
1681 switch (num) {
1682 case 0x500:
1683 /* KVM hypercall */
1684 r = s390_virtio_hypercall(env, mem, code);
1685 break;
1686 case 0x44:
1687 /* yield */
1688 r = 0;
1689 break;
1690 case 0x308:
1691 /* ipl */
1692 r = 0;
1693 break;
1694 default:
1695 r = -1;
1696 break;
1697 }
1698
1699 if (r) {
1700 program_interrupt(env, PGM_OPERATION, ILC_LATER_INC);
1701 }
1702
1703 return r;
1704}
1705
1706/* Store CPU ID */
1707void HELPER(stidp)(uint64_t a1)
1708{
1709 stq(a1, env->cpu_num);
1710}
1711
1712/* Set Prefix */
1713void HELPER(spx)(uint64_t a1)
1714{
1715 uint32_t prefix;
1716
1717 prefix = ldl(a1);
1718 env->psa = prefix & 0xfffff000;
1719 qemu_log("prefix: %#x\n", prefix);
1720 tlb_flush_page(env, 0);
1721 tlb_flush_page(env, TARGET_PAGE_SIZE);
1722}
1723
1724/* Set Clock */
1725uint32_t HELPER(sck)(uint64_t a1)
1726{
1727 /* XXX not implemented - is it necessary? */
1728
1729 return 0;
1730}
1731
a4e3ad19 1732static inline uint64_t clock_value(CPUS390XState *env)
defb0e31
AG
1733{
1734 uint64_t time;
1735
1736 time = env->tod_offset +
71e47088 1737 time2tod(qemu_get_clock_ns(vm_clock) - env->tod_basetime);
defb0e31
AG
1738
1739 return time;
1740}
1741
1742/* Store Clock */
1743uint32_t HELPER(stck)(uint64_t a1)
1744{
1745 stq(a1, clock_value(env));
1746
1747 return 0;
1748}
1749
1750/* Store Clock Extended */
1751uint32_t HELPER(stcke)(uint64_t a1)
1752{
1753 stb(a1, 0);
1754 /* basically the same value as stck */
1755 stq(a1 + 1, clock_value(env) | env->cpu_num);
1756 /* more fine grained than stck */
1757 stq(a1 + 9, 0);
1758 /* XXX programmable fields */
1759 stw(a1 + 17, 0);
1760
defb0e31
AG
1761 return 0;
1762}
1763
1764/* Set Clock Comparator */
1765void HELPER(sckc)(uint64_t a1)
1766{
1767 uint64_t time = ldq(a1);
1768
1769 if (time == -1ULL) {
1770 return;
1771 }
1772
1773 /* difference between now and then */
1774 time -= clock_value(env);
1775 /* nanoseconds */
1776 time = (time * 125) >> 9;
1777
1778 qemu_mod_timer(env->tod_timer, qemu_get_clock_ns(vm_clock) + time);
1779}
1780
1781/* Store Clock Comparator */
1782void HELPER(stckc)(uint64_t a1)
1783{
1784 /* XXX implement */
1785 stq(a1, 0);
1786}
1787
1788/* Set CPU Timer */
1789void HELPER(spt)(uint64_t a1)
1790{
1791 uint64_t time = ldq(a1);
1792
1793 if (time == -1ULL) {
1794 return;
1795 }
1796
1797 /* nanoseconds */
1798 time = (time * 125) >> 9;
1799
1800 qemu_mod_timer(env->cpu_timer, qemu_get_clock_ns(vm_clock) + time);
1801}
1802
1803/* Store CPU Timer */
1804void HELPER(stpt)(uint64_t a1)
1805{
1806 /* XXX implement */
1807 stq(a1, 0);
1808}
1809
1810/* Store System Information */
1811uint32_t HELPER(stsi)(uint64_t a0, uint32_t r0, uint32_t r1)
1812{
1813 int cc = 0;
1814 int sel1, sel2;
1815
1816 if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 &&
1817 ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) {
1818 /* valid function code, invalid reserved bits */
1819 program_interrupt(env, PGM_SPECIFICATION, 2);
1820 }
1821
1822 sel1 = r0 & STSI_R0_SEL1_MASK;
1823 sel2 = r1 & STSI_R1_SEL2_MASK;
1824
1825 /* XXX: spec exception if sysib is not 4k-aligned */
1826
1827 switch (r0 & STSI_LEVEL_MASK) {
1828 case STSI_LEVEL_1:
1829 if ((sel1 == 1) && (sel2 == 1)) {
1830 /* Basic Machine Configuration */
1831 struct sysib_111 sysib;
1832
1833 memset(&sysib, 0, sizeof(sysib));
1834 ebcdic_put(sysib.manuf, "QEMU ", 16);
1835 /* same as machine type number in STORE CPU ID */
1836 ebcdic_put(sysib.type, "QEMU", 4);
1837 /* same as model number in STORE CPU ID */
1838 ebcdic_put(sysib.model, "QEMU ", 16);
1839 ebcdic_put(sysib.sequence, "QEMU ", 16);
1840 ebcdic_put(sysib.plant, "QEMU", 4);
71e47088 1841 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
defb0e31
AG
1842 } else if ((sel1 == 2) && (sel2 == 1)) {
1843 /* Basic Machine CPU */
1844 struct sysib_121 sysib;
1845
1846 memset(&sysib, 0, sizeof(sysib));
1847 /* XXX make different for different CPUs? */
1848 ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
1849 ebcdic_put(sysib.plant, "QEMU", 4);
1850 stw_p(&sysib.cpu_addr, env->cpu_num);
71e47088 1851 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
defb0e31
AG
1852 } else if ((sel1 == 2) && (sel2 == 2)) {
1853 /* Basic Machine CPUs */
1854 struct sysib_122 sysib;
1855
1856 memset(&sysib, 0, sizeof(sysib));
1857 stl_p(&sysib.capability, 0x443afc29);
1858 /* XXX change when SMP comes */
1859 stw_p(&sysib.total_cpus, 1);
1860 stw_p(&sysib.active_cpus, 1);
1861 stw_p(&sysib.standby_cpus, 0);
1862 stw_p(&sysib.reserved_cpus, 0);
71e47088 1863 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
defb0e31
AG
1864 } else {
1865 cc = 3;
1866 }
1867 break;
1868 case STSI_LEVEL_2:
71e47088
BS
1869 {
1870 if ((sel1 == 2) && (sel2 == 1)) {
1871 /* LPAR CPU */
1872 struct sysib_221 sysib;
1873
1874 memset(&sysib, 0, sizeof(sysib));
1875 /* XXX make different for different CPUs? */
1876 ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
1877 ebcdic_put(sysib.plant, "QEMU", 4);
1878 stw_p(&sysib.cpu_addr, env->cpu_num);
1879 stw_p(&sysib.cpu_id, 0);
1880 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
1881 } else if ((sel1 == 2) && (sel2 == 2)) {
1882 /* LPAR CPUs */
1883 struct sysib_222 sysib;
1884
1885 memset(&sysib, 0, sizeof(sysib));
1886 stw_p(&sysib.lpar_num, 0);
1887 sysib.lcpuc = 0;
1888 /* XXX change when SMP comes */
1889 stw_p(&sysib.total_cpus, 1);
1890 stw_p(&sysib.conf_cpus, 1);
1891 stw_p(&sysib.standby_cpus, 0);
1892 stw_p(&sysib.reserved_cpus, 0);
1893 ebcdic_put(sysib.name, "QEMU ", 8);
1894 stl_p(&sysib.caf, 1000);
1895 stw_p(&sysib.dedicated_cpus, 0);
1896 stw_p(&sysib.shared_cpus, 0);
1897 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
1898 } else {
1899 cc = 3;
1900 }
1901 break;
defb0e31 1902 }
defb0e31 1903 case STSI_LEVEL_3:
71e47088
BS
1904 {
1905 if ((sel1 == 2) && (sel2 == 2)) {
1906 /* VM CPUs */
1907 struct sysib_322 sysib;
1908
1909 memset(&sysib, 0, sizeof(sysib));
1910 sysib.count = 1;
1911 /* XXX change when SMP comes */
1912 stw_p(&sysib.vm[0].total_cpus, 1);
1913 stw_p(&sysib.vm[0].conf_cpus, 1);
1914 stw_p(&sysib.vm[0].standby_cpus, 0);
1915 stw_p(&sysib.vm[0].reserved_cpus, 0);
1916 ebcdic_put(sysib.vm[0].name, "KVMguest", 8);
1917 stl_p(&sysib.vm[0].caf, 1000);
1918 ebcdic_put(sysib.vm[0].cpi, "KVM/Linux ", 16);
1919 cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
1920 } else {
1921 cc = 3;
1922 }
1923 break;
defb0e31 1924 }
defb0e31
AG
1925 case STSI_LEVEL_CURRENT:
1926 env->regs[0] = STSI_LEVEL_3;
1927 break;
1928 default:
1929 cc = 3;
1930 break;
1931 }
1932
1933 return cc;
1934}
1935
1936void HELPER(lctlg)(uint32_t r1, uint64_t a2, uint32_t r3)
1937{
1938 int i;
1939 uint64_t src = a2;
1940
1941 for (i = r1;; i = (i + 1) % 16) {
1942 env->cregs[i] = ldq(src);
1943 HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
1944 i, src, env->cregs[i]);
1945 src += sizeof(uint64_t);
1946
1947 if (i == r3) {
1948 break;
1949 }
1950 }
1951
1952 tlb_flush(env, 1);
1953}
1954
1955void HELPER(lctl)(uint32_t r1, uint64_t a2, uint32_t r3)
1956{
1957 int i;
1958 uint64_t src = a2;
1959
1960 for (i = r1;; i = (i + 1) % 16) {
1961 env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) | ldl(src);
1962 src += sizeof(uint32_t);
1963
1964 if (i == r3) {
1965 break;
1966 }
1967 }
1968
1969 tlb_flush(env, 1);
1970}
1971
1972void HELPER(stctg)(uint32_t r1, uint64_t a2, uint32_t r3)
1973{
1974 int i;
1975 uint64_t dest = a2;
1976
1977 for (i = r1;; i = (i + 1) % 16) {
1978 stq(dest, env->cregs[i]);
1979 dest += sizeof(uint64_t);
1980
1981 if (i == r3) {
1982 break;
1983 }
1984 }
1985}
1986
1987void HELPER(stctl)(uint32_t r1, uint64_t a2, uint32_t r3)
1988{
1989 int i;
1990 uint64_t dest = a2;
1991
1992 for (i = r1;; i = (i + 1) % 16) {
1993 stl(dest, env->cregs[i]);
1994 dest += sizeof(uint32_t);
1995
1996 if (i == r3) {
1997 break;
1998 }
1999 }
2000}
2001
2002uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2)
2003{
2004 /* XXX implement */
2005
2006 return 0;
2007}
2008
2009/* insert storage key extended */
2010uint64_t HELPER(iske)(uint64_t r2)
2011{
2012 uint64_t addr = get_address(0, 0, r2);
2013
2014 if (addr > ram_size) {
2015 return 0;
2016 }
2017
defb0e31
AG
2018 return env->storage_keys[addr / TARGET_PAGE_SIZE];
2019}
2020
2021/* set storage key extended */
2022void HELPER(sske)(uint32_t r1, uint64_t r2)
2023{
2024 uint64_t addr = get_address(0, 0, r2);
2025
2026 if (addr > ram_size) {
2027 return;
2028 }
2029
2030 env->storage_keys[addr / TARGET_PAGE_SIZE] = r1;
2031}
2032
2033/* reset reference bit extended */
2034uint32_t HELPER(rrbe)(uint32_t r1, uint64_t r2)
2035{
17bb18ce
AG
2036 uint8_t re;
2037 uint8_t key;
71e47088 2038
defb0e31
AG
2039 if (r2 > ram_size) {
2040 return 0;
2041 }
2042
17bb18ce
AG
2043 key = env->storage_keys[r2 / TARGET_PAGE_SIZE];
2044 re = key & (SK_R | SK_C);
2045 env->storage_keys[r2 / TARGET_PAGE_SIZE] = (key & ~SK_R);
defb0e31
AG
2046
2047 /*
2048 * cc
2049 *
2050 * 0 Reference bit zero; change bit zero
2051 * 1 Reference bit zero; change bit one
2052 * 2 Reference bit one; change bit zero
2053 * 3 Reference bit one; change bit one
2054 */
17bb18ce
AG
2055
2056 return re >> 1;
d5a43964 2057}
defb0e31
AG
2058
2059/* compare and swap and purge */
2060uint32_t HELPER(csp)(uint32_t r1, uint32_t r2)
2061{
2062 uint32_t cc;
2063 uint32_t o1 = env->regs[r1];
2064 uint64_t a2 = get_address_31fix(r2) & ~3ULL;
2065 uint32_t o2 = ldl(a2);
2066
2067 if (o1 == o2) {
2068 stl(a2, env->regs[(r1 + 1) & 15]);
2069 if (env->regs[r2] & 0x3) {
2070 /* flush TLB / ALB */
2071 tlb_flush(env, 1);
2072 }
2073 cc = 0;
2074 } else {
2075 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | o2;
2076 cc = 1;
2077 }
2078
2079 return cc;
2080}
2081
2082static uint32_t mvc_asc(int64_t l, uint64_t a1, uint64_t mode1, uint64_t a2,
2083 uint64_t mode2)
2084{
2085 target_ulong src, dest;
2086 int flags, cc = 0, i;
2087
2088 if (!l) {
2089 return 0;
2090 } else if (l > 256) {
2091 /* max 256 */
2092 l = 256;
2093 cc = 3;
2094 }
2095
2096 if (mmu_translate(env, a1 & TARGET_PAGE_MASK, 1, mode1, &dest, &flags)) {
1162c041 2097 cpu_loop_exit(env);
defb0e31
AG
2098 }
2099 dest |= a1 & ~TARGET_PAGE_MASK;
2100
2101 if (mmu_translate(env, a2 & TARGET_PAGE_MASK, 0, mode2, &src, &flags)) {
1162c041 2102 cpu_loop_exit(env);
defb0e31
AG
2103 }
2104 src |= a2 & ~TARGET_PAGE_MASK;
2105
2106 /* XXX replace w/ memcpy */
2107 for (i = 0; i < l; i++) {
2108 /* XXX be more clever */
2109 if ((((dest + i) & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) ||
2110 (((src + i) & TARGET_PAGE_MASK) != (src & TARGET_PAGE_MASK))) {
2111 mvc_asc(l - i, a1 + i, mode1, a2 + i, mode2);
2112 break;
2113 }
2114 stb_phys(dest + i, ldub_phys(src + i));
2115 }
2116
2117 return cc;
2118}
2119
2120uint32_t HELPER(mvcs)(uint64_t l, uint64_t a1, uint64_t a2)
2121{
2122 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
71e47088 2123 __func__, l, a1, a2);
defb0e31
AG
2124
2125 return mvc_asc(l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY);
2126}
2127
2128uint32_t HELPER(mvcp)(uint64_t l, uint64_t a1, uint64_t a2)
2129{
2130 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
71e47088 2131 __func__, l, a1, a2);
defb0e31
AG
2132
2133 return mvc_asc(l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY);
2134}
2135
2136uint32_t HELPER(sigp)(uint64_t order_code, uint32_t r1, uint64_t cpu_addr)
2137{
2138 int cc = 0;
2139
2140 HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n",
71e47088 2141 __func__, order_code, r1, cpu_addr);
defb0e31 2142
71e47088 2143 /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register"
defb0e31
AG
2144 as parameter (input). Status (output) is always R1. */
2145
2146 switch (order_code) {
2147 case SIGP_SET_ARCH:
2148 /* switch arch */
2149 break;
2150 case SIGP_SENSE:
2151 /* enumerate CPU status */
2152 if (cpu_addr) {
2153 /* XXX implement when SMP comes */
2154 return 3;
2155 }
2156 env->regs[r1] &= 0xffffffff00000000ULL;
2157 cc = 1;
2158 break;
71e47088 2159#if !defined(CONFIG_USER_ONLY)
1864b94a
AG
2160 case SIGP_RESTART:
2161 qemu_system_reset_request();
2162 cpu_loop_exit(env);
2163 break;
2164 case SIGP_STOP:
2165 qemu_system_shutdown_request();
2166 cpu_loop_exit(env);
2167 break;
2168#endif
defb0e31
AG
2169 default:
2170 /* unknown sigp */
2171 fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);
2172 cc = 3;
2173 }
2174
2175 return cc;
2176}
2177
2178void HELPER(sacf)(uint64_t a1)
2179{
71e47088 2180 HELPER_LOG("%s: %16" PRIx64 "\n", __func__, a1);
defb0e31
AG
2181
2182 switch (a1 & 0xf00) {
2183 case 0x000:
2184 env->psw.mask &= ~PSW_MASK_ASC;
2185 env->psw.mask |= PSW_ASC_PRIMARY;
2186 break;
2187 case 0x100:
2188 env->psw.mask &= ~PSW_MASK_ASC;
2189 env->psw.mask |= PSW_ASC_SECONDARY;
2190 break;
2191 case 0x300:
2192 env->psw.mask &= ~PSW_MASK_ASC;
2193 env->psw.mask |= PSW_ASC_HOME;
2194 break;
2195 default:
2196 qemu_log("unknown sacf mode: %" PRIx64 "\n", a1);
2197 program_interrupt(env, PGM_SPECIFICATION, 2);
2198 break;
2199 }
2200}
2201
2202/* invalidate pte */
2203void HELPER(ipte)(uint64_t pte_addr, uint64_t vaddr)
2204{
2205 uint64_t page = vaddr & TARGET_PAGE_MASK;
2206 uint64_t pte = 0;
2207
2208 /* XXX broadcast to other CPUs */
2209
2210 /* XXX Linux is nice enough to give us the exact pte address.
71e47088 2211 According to spec we'd have to find it out ourselves */
defb0e31 2212 /* XXX Linux is fine with overwriting the pte, the spec requires
71e47088 2213 us to only set the invalid bit */
defb0e31
AG
2214 stq_phys(pte_addr, pte | _PAGE_INVALID);
2215
2216 /* XXX we exploit the fact that Linux passes the exact virtual
71e47088 2217 address here - it's not obliged to! */
defb0e31 2218 tlb_flush_page(env, page);
09ed75f7
AG
2219
2220 /* XXX 31-bit hack */
2221 if (page & 0x80000000) {
2222 tlb_flush_page(env, page & ~0x80000000);
2223 } else {
2224 tlb_flush_page(env, page | 0x80000000);
2225 }
defb0e31
AG
2226}
2227
2228/* flush local tlb */
2229void HELPER(ptlb)(void)
2230{
2231 tlb_flush(env, 1);
2232}
2233
2234/* store using real address */
2235void HELPER(stura)(uint64_t addr, uint32_t v1)
2236{
2237 stw_phys(get_address(0, 0, addr), v1);
2238}
2239
2240/* load real address */
2241uint32_t HELPER(lra)(uint64_t addr, uint32_t r1)
2242{
2243 uint32_t cc = 0;
2244 int old_exc = env->exception_index;
2245 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
2246 uint64_t ret;
2247 int flags;
2248
2249 /* XXX incomplete - has more corner cases */
2250 if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
2251 program_interrupt(env, PGM_SPECIAL_OP, 2);
2252 }
2253
2254 env->exception_index = old_exc;
2255 if (mmu_translate(env, addr, 0, asc, &ret, &flags)) {
2256 cc = 3;
2257 }
2258 if (env->exception_index == EXCP_PGM) {
2259 ret = env->int_pgm_code | 0x80000000;
2260 } else {
2261 ret |= addr & ~TARGET_PAGE_MASK;
2262 }
2263 env->exception_index = old_exc;
2264
2265 if (!(env->psw.mask & PSW_MASK_64)) {
71e47088
BS
2266 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
2267 (ret & 0xffffffffULL);
defb0e31
AG
2268 } else {
2269 env->regs[r1] = ret;
2270 }
2271
2272 return cc;
2273}
2274
2275#endif