blob: 1422ae97a889eb913fa48197579aaae7ce84b3c3 [file] [log] [blame]
Blue Swirl8ef7f782012-09-02 07:33:34 +00001/*
2 * S/390 memory access helper routines
3 *
4 * Copyright (c) 2009 Ulrich Hecht
5 * Copyright (c) 2009 Alexander Graf
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include "cpu.h"
Blue Swirl8ef7f782012-09-02 07:33:34 +000022#include "helper.h"
23
24/*****************************************************************************/
25/* Softmmu support */
26#if !defined(CONFIG_USER_ONLY)
Paolo Bonzini022c62c2012-12-17 18:19:49 +010027#include "exec/softmmu_exec.h"
Blue Swirl8ef7f782012-09-02 07:33:34 +000028
29#define MMUSUFFIX _mmu
30
31#define SHIFT 0
Paolo Bonzini022c62c2012-12-17 18:19:49 +010032#include "exec/softmmu_template.h"
Blue Swirl8ef7f782012-09-02 07:33:34 +000033
34#define SHIFT 1
Paolo Bonzini022c62c2012-12-17 18:19:49 +010035#include "exec/softmmu_template.h"
Blue Swirl8ef7f782012-09-02 07:33:34 +000036
37#define SHIFT 2
Paolo Bonzini022c62c2012-12-17 18:19:49 +010038#include "exec/softmmu_template.h"
Blue Swirl8ef7f782012-09-02 07:33:34 +000039
40#define SHIFT 3
Paolo Bonzini022c62c2012-12-17 18:19:49 +010041#include "exec/softmmu_template.h"
Blue Swirl8ef7f782012-09-02 07:33:34 +000042
43/* try to fill the TLB and return an exception if error. If retaddr is
44 NULL, it means that the function was called in C code (i.e. not
45 from generated code or from helper.c) */
46/* XXX: fix it to restore all registers */
Blue Swirl19b05162012-09-02 07:33:40 +000047void tlb_fill(CPUS390XState *env, target_ulong addr, int is_write, int mmu_idx,
Blue Swirl8ef7f782012-09-02 07:33:34 +000048 uintptr_t retaddr)
49{
Blue Swirl8ef7f782012-09-02 07:33:34 +000050 int ret;
51
Blue Swirl8ef7f782012-09-02 07:33:34 +000052 ret = cpu_s390x_handle_mmu_fault(env, addr, is_write, mmu_idx);
53 if (unlikely(ret != 0)) {
54 if (likely(retaddr)) {
55 /* now we have a real cpu fault */
Blue Swirla8a826a2012-12-04 20:16:07 +000056 cpu_restore_state(env, retaddr);
Blue Swirl8ef7f782012-09-02 07:33:34 +000057 }
58 cpu_loop_exit(env);
59 }
Blue Swirl8ef7f782012-09-02 07:33:34 +000060}
61
62#endif
63
64/* #define DEBUG_HELPER */
65#ifdef DEBUG_HELPER
66#define HELPER_LOG(x...) qemu_log(x)
67#else
68#define HELPER_LOG(x...)
69#endif
70
71#ifndef CONFIG_USER_ONLY
72static void mvc_fast_memset(CPUS390XState *env, uint32_t l, uint64_t dest,
73 uint8_t byte)
74{
Avi Kivitya8170e52012-10-23 12:30:10 +020075 hwaddr dest_phys;
76 hwaddr len = l;
Blue Swirl8ef7f782012-09-02 07:33:34 +000077 void *dest_p;
78 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
79 int flags;
80
81 if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) {
Blue Swirl19b05162012-09-02 07:33:40 +000082 cpu_stb_data(env, dest, byte);
Blue Swirl8ef7f782012-09-02 07:33:34 +000083 cpu_abort(env, "should never reach here");
84 }
85 dest_phys |= dest & ~TARGET_PAGE_MASK;
86
87 dest_p = cpu_physical_memory_map(dest_phys, &len, 1);
88
89 memset(dest_p, byte, len);
90
91 cpu_physical_memory_unmap(dest_p, 1, len, len);
92}
93
94static void mvc_fast_memmove(CPUS390XState *env, uint32_t l, uint64_t dest,
95 uint64_t src)
96{
Avi Kivitya8170e52012-10-23 12:30:10 +020097 hwaddr dest_phys;
98 hwaddr src_phys;
99 hwaddr len = l;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000100 void *dest_p;
101 void *src_p;
102 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
103 int flags;
104
105 if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) {
Blue Swirl19b05162012-09-02 07:33:40 +0000106 cpu_stb_data(env, dest, 0);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000107 cpu_abort(env, "should never reach here");
108 }
109 dest_phys |= dest & ~TARGET_PAGE_MASK;
110
111 if (mmu_translate(env, src, 0, asc, &src_phys, &flags)) {
Blue Swirl19b05162012-09-02 07:33:40 +0000112 cpu_ldub_data(env, src);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000113 cpu_abort(env, "should never reach here");
114 }
115 src_phys |= src & ~TARGET_PAGE_MASK;
116
117 dest_p = cpu_physical_memory_map(dest_phys, &len, 1);
118 src_p = cpu_physical_memory_map(src_phys, &len, 0);
119
120 memmove(dest_p, src_p, len);
121
122 cpu_physical_memory_unmap(dest_p, 1, len, len);
123 cpu_physical_memory_unmap(src_p, 0, len, len);
124}
125#endif
126
127/* and on array */
Blue Swirl19b05162012-09-02 07:33:40 +0000128uint32_t HELPER(nc)(CPUS390XState *env, uint32_t l, uint64_t dest,
129 uint64_t src)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000130{
131 int i;
132 unsigned char x;
133 uint32_t cc = 0;
134
135 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
136 __func__, l, dest, src);
137 for (i = 0; i <= l; i++) {
Blue Swirl19b05162012-09-02 07:33:40 +0000138 x = cpu_ldub_data(env, dest + i) & cpu_ldub_data(env, src + i);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000139 if (x) {
140 cc = 1;
141 }
Blue Swirl19b05162012-09-02 07:33:40 +0000142 cpu_stb_data(env, dest + i, x);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000143 }
144 return cc;
145}
146
147/* xor on array */
Blue Swirl19b05162012-09-02 07:33:40 +0000148uint32_t HELPER(xc)(CPUS390XState *env, uint32_t l, uint64_t dest,
149 uint64_t src)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000150{
151 int i;
152 unsigned char x;
153 uint32_t cc = 0;
154
155 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
156 __func__, l, dest, src);
157
158#ifndef CONFIG_USER_ONLY
159 /* xor with itself is the same as memset(0) */
160 if ((l > 32) && (src == dest) &&
161 (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK)) {
162 mvc_fast_memset(env, l + 1, dest, 0);
163 return 0;
164 }
165#else
166 if (src == dest) {
167 memset(g2h(dest), 0, l + 1);
168 return 0;
169 }
170#endif
171
172 for (i = 0; i <= l; i++) {
Blue Swirl19b05162012-09-02 07:33:40 +0000173 x = cpu_ldub_data(env, dest + i) ^ cpu_ldub_data(env, src + i);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000174 if (x) {
175 cc = 1;
176 }
Blue Swirl19b05162012-09-02 07:33:40 +0000177 cpu_stb_data(env, dest + i, x);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000178 }
179 return cc;
180}
181
182/* or on array */
Blue Swirl19b05162012-09-02 07:33:40 +0000183uint32_t HELPER(oc)(CPUS390XState *env, uint32_t l, uint64_t dest,
184 uint64_t src)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000185{
186 int i;
187 unsigned char x;
188 uint32_t cc = 0;
189
190 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
191 __func__, l, dest, src);
192 for (i = 0; i <= l; i++) {
Blue Swirl19b05162012-09-02 07:33:40 +0000193 x = cpu_ldub_data(env, dest + i) | cpu_ldub_data(env, src + i);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000194 if (x) {
195 cc = 1;
196 }
Blue Swirl19b05162012-09-02 07:33:40 +0000197 cpu_stb_data(env, dest + i, x);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000198 }
199 return cc;
200}
201
202/* memmove */
Blue Swirl19b05162012-09-02 07:33:40 +0000203void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000204{
205 int i = 0;
206 int x = 0;
207 uint32_t l_64 = (l + 1) / 8;
208
209 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
210 __func__, l, dest, src);
211
212#ifndef CONFIG_USER_ONLY
213 if ((l > 32) &&
214 (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK) &&
215 (dest & TARGET_PAGE_MASK) == ((dest + l) & TARGET_PAGE_MASK)) {
216 if (dest == (src + 1)) {
Blue Swirl19b05162012-09-02 07:33:40 +0000217 mvc_fast_memset(env, l + 1, dest, cpu_ldub_data(env, src));
Blue Swirl8ef7f782012-09-02 07:33:34 +0000218 return;
219 } else if ((src & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
220 mvc_fast_memmove(env, l + 1, dest, src);
221 return;
222 }
223 }
224#else
225 if (dest == (src + 1)) {
Blue Swirl19b05162012-09-02 07:33:40 +0000226 memset(g2h(dest), cpu_ldub_data(env, src), l + 1);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000227 return;
228 } else {
229 memmove(g2h(dest), g2h(src), l + 1);
230 return;
231 }
232#endif
233
234 /* handle the parts that fit into 8-byte loads/stores */
235 if (dest != (src + 1)) {
236 for (i = 0; i < l_64; i++) {
Blue Swirl19b05162012-09-02 07:33:40 +0000237 cpu_stq_data(env, dest + x, cpu_ldq_data(env, src + x));
Blue Swirl8ef7f782012-09-02 07:33:34 +0000238 x += 8;
239 }
240 }
241
242 /* slow version crossing pages with byte accesses */
243 for (i = x; i <= l; i++) {
Blue Swirl19b05162012-09-02 07:33:40 +0000244 cpu_stb_data(env, dest + i, cpu_ldub_data(env, src + i));
Blue Swirl8ef7f782012-09-02 07:33:34 +0000245 }
246}
247
248/* compare unsigned byte arrays */
Blue Swirl19b05162012-09-02 07:33:40 +0000249uint32_t HELPER(clc)(CPUS390XState *env, uint32_t l, uint64_t s1, uint64_t s2)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000250{
251 int i;
252 unsigned char x, y;
253 uint32_t cc;
254
255 HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n",
256 __func__, l, s1, s2);
257 for (i = 0; i <= l; i++) {
Blue Swirl19b05162012-09-02 07:33:40 +0000258 x = cpu_ldub_data(env, s1 + i);
259 y = cpu_ldub_data(env, s2 + i);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000260 HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y);
261 if (x < y) {
262 cc = 1;
263 goto done;
264 } else if (x > y) {
265 cc = 2;
266 goto done;
267 }
268 }
269 cc = 0;
270 done:
271 HELPER_LOG("\n");
272 return cc;
273}
274
275/* compare logical under mask */
Blue Swirl19b05162012-09-02 07:33:40 +0000276uint32_t HELPER(clm)(CPUS390XState *env, uint32_t r1, uint32_t mask,
277 uint64_t addr)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000278{
279 uint8_t r, d;
280 uint32_t cc;
281
282 HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1,
283 mask, addr);
284 cc = 0;
285 while (mask) {
286 if (mask & 8) {
Blue Swirl19b05162012-09-02 07:33:40 +0000287 d = cpu_ldub_data(env, addr);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000288 r = (r1 & 0xff000000UL) >> 24;
289 HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d,
290 addr);
291 if (r < d) {
292 cc = 1;
293 break;
294 } else if (r > d) {
295 cc = 2;
296 break;
297 }
298 addr++;
299 }
300 mask = (mask << 1) & 0xf;
301 r1 <<= 8;
302 }
303 HELPER_LOG("\n");
304 return cc;
305}
306
Richard Hendersonaa31bf62012-09-05 10:20:53 -0700307static inline uint64_t fix_address(CPUS390XState *env, uint64_t a)
308{
309 /* 31-Bit mode */
310 if (!(env->psw.mask & PSW_MASK_64)) {
311 a &= 0x7fffffff;
312 }
313 return a;
314}
315
Blue Swirl19b05162012-09-02 07:33:40 +0000316static inline uint64_t get_address(CPUS390XState *env, int x2, int b2, int d2)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000317{
318 uint64_t r = d2;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000319 if (x2) {
320 r += env->regs[x2];
321 }
Blue Swirl8ef7f782012-09-02 07:33:34 +0000322 if (b2) {
323 r += env->regs[b2];
324 }
Richard Hendersonaa31bf62012-09-05 10:20:53 -0700325 return fix_address(env, r);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000326}
327
Blue Swirl19b05162012-09-02 07:33:40 +0000328static inline uint64_t get_address_31fix(CPUS390XState *env, int reg)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000329{
Richard Hendersonaa31bf62012-09-05 10:20:53 -0700330 return fix_address(env, env->regs[reg]);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000331}
332
333/* search string (c is byte to search, r2 is string, r1 end of string) */
Richard Henderson4600c992012-08-24 14:27:42 -0700334uint64_t HELPER(srst)(CPUS390XState *env, uint64_t r0, uint64_t end,
335 uint64_t str)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000336{
Richard Henderson4600c992012-08-24 14:27:42 -0700337 uint32_t len;
338 uint8_t v, c = r0;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000339
Richard Henderson4600c992012-08-24 14:27:42 -0700340 str = fix_address(env, str);
341 end = fix_address(env, end);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000342
Richard Henderson4600c992012-08-24 14:27:42 -0700343 /* Assume for now that R2 is unmodified. */
344 env->retxl = str;
345
346 /* Lest we fail to service interrupts in a timely manner, limit the
Peter Maydelle03ba132013-04-09 12:48:19 +0100347 amount of work we're willing to do. For now, let's cap at 8k. */
Richard Henderson4600c992012-08-24 14:27:42 -0700348 for (len = 0; len < 0x2000; ++len) {
349 if (str + len == end) {
350 /* Character not found. R1 & R2 are unmodified. */
351 env->cc_op = 2;
352 return end;
353 }
354 v = cpu_ldub_data(env, str + len);
355 if (v == c) {
356 /* Character found. Set R1 to the location; R2 is unmodified. */
357 env->cc_op = 1;
358 return str + len;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000359 }
360 }
361
Richard Henderson4600c992012-08-24 14:27:42 -0700362 /* CPU-determined bytes processed. Advance R2 to next byte to process. */
363 env->retxl = str + len;
364 env->cc_op = 3;
365 return end;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000366}
367
368/* unsigned string compare (c is string terminator) */
Richard Hendersonaa31bf62012-09-05 10:20:53 -0700369uint64_t HELPER(clst)(CPUS390XState *env, uint64_t c, uint64_t s1, uint64_t s2)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000370{
Richard Hendersonaa31bf62012-09-05 10:20:53 -0700371 uint32_t len;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000372
373 c = c & 0xff;
Richard Hendersonaa31bf62012-09-05 10:20:53 -0700374 s1 = fix_address(env, s1);
375 s2 = fix_address(env, s2);
376
377 /* Lest we fail to service interrupts in a timely manner, limit the
Peter Maydelle03ba132013-04-09 12:48:19 +0100378 amount of work we're willing to do. For now, let's cap at 8k. */
Richard Hendersonaa31bf62012-09-05 10:20:53 -0700379 for (len = 0; len < 0x2000; ++len) {
380 uint8_t v1 = cpu_ldub_data(env, s1 + len);
381 uint8_t v2 = cpu_ldub_data(env, s2 + len);
382 if (v1 == v2) {
383 if (v1 == c) {
384 /* Equal. CC=0, and don't advance the registers. */
385 env->cc_op = 0;
386 env->retxl = s2;
387 return s1;
388 }
389 } else {
390 /* Unequal. CC={1,2}, and advance the registers. Note that
391 the terminator need not be zero, but the string that contains
392 the terminator is by definition "low". */
393 env->cc_op = (v1 == c ? 1 : v2 == c ? 2 : v1 < v2 ? 1 : 2);
394 env->retxl = s2 + len;
395 return s1 + len;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000396 }
Blue Swirl8ef7f782012-09-02 07:33:34 +0000397 }
398
Richard Hendersonaa31bf62012-09-05 10:20:53 -0700399 /* CPU-determined bytes equal; advance the registers. */
400 env->cc_op = 3;
401 env->retxl = s2 + len;
402 return s1 + len;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000403}
404
405/* move page */
Blue Swirl19b05162012-09-02 07:33:40 +0000406void HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000407{
408 /* XXX missing r0 handling */
Richard Hendersonee6c38d2012-09-05 10:19:44 -0700409 env->cc_op = 0;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000410#ifdef CONFIG_USER_ONLY
Richard Hendersonee6c38d2012-09-05 10:19:44 -0700411 memmove(g2h(r1), g2h(r2), TARGET_PAGE_SIZE);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000412#else
413 mvc_fast_memmove(env, TARGET_PAGE_SIZE, r1, r2);
414#endif
415}
416
417/* string copy (c is string terminator) */
Richard Hendersonaa31bf62012-09-05 10:20:53 -0700418uint64_t HELPER(mvst)(CPUS390XState *env, uint64_t c, uint64_t d, uint64_t s)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000419{
Richard Hendersonaa31bf62012-09-05 10:20:53 -0700420 uint32_t len;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000421
422 c = c & 0xff;
Richard Hendersonaa31bf62012-09-05 10:20:53 -0700423 d = fix_address(env, d);
424 s = fix_address(env, s);
425
426 /* Lest we fail to service interrupts in a timely manner, limit the
Peter Maydelle03ba132013-04-09 12:48:19 +0100427 amount of work we're willing to do. For now, let's cap at 8k. */
Richard Hendersonaa31bf62012-09-05 10:20:53 -0700428 for (len = 0; len < 0x2000; ++len) {
429 uint8_t v = cpu_ldub_data(env, s + len);
430 cpu_stb_data(env, d + len, v);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000431 if (v == c) {
Richard Hendersonaa31bf62012-09-05 10:20:53 -0700432 /* Complete. Set CC=1 and advance R1. */
433 env->cc_op = 1;
434 env->retxl = s;
435 return d + len;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000436 }
Blue Swirl8ef7f782012-09-02 07:33:34 +0000437 }
Richard Hendersonaa31bf62012-09-05 10:20:53 -0700438
439 /* Incomplete. Set CC=3 and signal to advance R1 and R2. */
440 env->cc_op = 3;
441 env->retxl = s + len;
442 return d + len;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000443}
444
Blue Swirl19b05162012-09-02 07:33:40 +0000445static uint32_t helper_icm(CPUS390XState *env, uint32_t r1, uint64_t address,
446 uint32_t mask)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000447{
448 int pos = 24; /* top of the lower half of r1 */
449 uint64_t rmask = 0xff000000ULL;
450 uint8_t val = 0;
451 int ccd = 0;
452 uint32_t cc = 0;
453
454 while (mask) {
455 if (mask & 8) {
456 env->regs[r1] &= ~rmask;
Blue Swirl19b05162012-09-02 07:33:40 +0000457 val = cpu_ldub_data(env, address);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000458 if ((val & 0x80) && !ccd) {
459 cc = 1;
460 }
461 ccd = 1;
462 if (val && cc == 0) {
463 cc = 2;
464 }
465 env->regs[r1] |= (uint64_t)val << pos;
466 address++;
467 }
468 mask = (mask << 1) & 0xf;
469 pos -= 8;
470 rmask >>= 8;
471 }
472
473 return cc;
474}
475
476/* execute instruction
477 this instruction executes an insn modified with the contents of r1
478 it does not change the executed instruction in memory
479 it does not change the program counter
480 in other words: tricky...
481 currently implemented by interpreting the cases it is most commonly used in
482*/
Blue Swirl19b05162012-09-02 07:33:40 +0000483uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1,
484 uint64_t addr, uint64_t ret)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000485{
Blue Swirl19b05162012-09-02 07:33:40 +0000486 uint16_t insn = cpu_lduw_code(env, addr);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000487
488 HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __func__, v1, addr,
489 insn);
490 if ((insn & 0xf0ff) == 0xd000) {
491 uint32_t l, insn2, b1, b2, d1, d2;
492
493 l = v1 & 0xff;
Blue Swirl19b05162012-09-02 07:33:40 +0000494 insn2 = cpu_ldl_code(env, addr + 2);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000495 b1 = (insn2 >> 28) & 0xf;
496 b2 = (insn2 >> 12) & 0xf;
497 d1 = (insn2 >> 16) & 0xfff;
498 d2 = insn2 & 0xfff;
499 switch (insn & 0xf00) {
500 case 0x200:
Blue Swirl19b05162012-09-02 07:33:40 +0000501 helper_mvc(env, l, get_address(env, 0, b1, d1),
502 get_address(env, 0, b2, d2));
Blue Swirl8ef7f782012-09-02 07:33:34 +0000503 break;
504 case 0x500:
Blue Swirl19b05162012-09-02 07:33:40 +0000505 cc = helper_clc(env, l, get_address(env, 0, b1, d1),
506 get_address(env, 0, b2, d2));
Blue Swirl8ef7f782012-09-02 07:33:34 +0000507 break;
508 case 0x700:
Blue Swirl19b05162012-09-02 07:33:40 +0000509 cc = helper_xc(env, l, get_address(env, 0, b1, d1),
510 get_address(env, 0, b2, d2));
Blue Swirl8ef7f782012-09-02 07:33:34 +0000511 break;
512 case 0xc00:
Blue Swirl19b05162012-09-02 07:33:40 +0000513 helper_tr(env, l, get_address(env, 0, b1, d1),
514 get_address(env, 0, b2, d2));
Blue Swirl8ef7f782012-09-02 07:33:34 +0000515 break;
516 default:
517 goto abort;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000518 }
519 } else if ((insn & 0xff00) == 0x0a00) {
520 /* supervisor call */
521 HELPER_LOG("%s: svc %ld via execute\n", __func__, (insn | v1) & 0xff);
522 env->psw.addr = ret - 4;
523 env->int_svc_code = (insn | v1) & 0xff;
Richard Hendersond5a103c2012-09-14 19:31:57 -0700524 env->int_svc_ilen = 4;
Blue Swirl089f5c02012-09-02 07:33:39 +0000525 helper_exception(env, EXCP_SVC);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000526 } else if ((insn & 0xff00) == 0xbf00) {
527 uint32_t insn2, r1, r3, b2, d2;
528
Blue Swirl19b05162012-09-02 07:33:40 +0000529 insn2 = cpu_ldl_code(env, addr + 2);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000530 r1 = (insn2 >> 20) & 0xf;
531 r3 = (insn2 >> 16) & 0xf;
532 b2 = (insn2 >> 12) & 0xf;
533 d2 = insn2 & 0xfff;
Blue Swirl19b05162012-09-02 07:33:40 +0000534 cc = helper_icm(env, r1, get_address(env, 0, b2, d2), r3);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000535 } else {
536 abort:
537 cpu_abort(env, "EXECUTE on instruction prefix 0x%x not implemented\n",
538 insn);
539 }
540 return cc;
541}
542
Blue Swirl8ef7f782012-09-02 07:33:34 +0000543/* load access registers r1 to r3 from memory at a2 */
Blue Swirl19b05162012-09-02 07:33:40 +0000544void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000545{
546 int i;
547
548 for (i = r1;; i = (i + 1) % 16) {
Blue Swirl19b05162012-09-02 07:33:40 +0000549 env->aregs[i] = cpu_ldl_data(env, a2);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000550 a2 += 4;
551
552 if (i == r3) {
553 break;
554 }
555 }
556}
557
558/* store access registers r1 to r3 in memory at a2 */
Blue Swirl19b05162012-09-02 07:33:40 +0000559void HELPER(stam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000560{
561 int i;
562
563 for (i = r1;; i = (i + 1) % 16) {
Blue Swirl19b05162012-09-02 07:33:40 +0000564 cpu_stl_data(env, a2, env->aregs[i]);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000565 a2 += 4;
566
567 if (i == r3) {
568 break;
569 }
570 }
571}
572
573/* move long */
Blue Swirl19b05162012-09-02 07:33:40 +0000574uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000575{
576 uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
Blue Swirl19b05162012-09-02 07:33:40 +0000577 uint64_t dest = get_address_31fix(env, r1);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000578 uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
Blue Swirl19b05162012-09-02 07:33:40 +0000579 uint64_t src = get_address_31fix(env, r2);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000580 uint8_t pad = src >> 24;
581 uint8_t v;
582 uint32_t cc;
583
584 if (destlen == srclen) {
585 cc = 0;
586 } else if (destlen < srclen) {
587 cc = 1;
588 } else {
589 cc = 2;
590 }
591
592 if (srclen > destlen) {
593 srclen = destlen;
594 }
595
596 for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
Blue Swirl19b05162012-09-02 07:33:40 +0000597 v = cpu_ldub_data(env, src);
598 cpu_stb_data(env, dest, v);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000599 }
600
601 for (; destlen; dest++, destlen--) {
Blue Swirl19b05162012-09-02 07:33:40 +0000602 cpu_stb_data(env, dest, pad);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000603 }
604
605 env->regs[r1 + 1] = destlen;
606 /* can't use srclen here, we trunc'ed it */
607 env->regs[r2 + 1] -= src - env->regs[r2];
608 env->regs[r1] = dest;
609 env->regs[r2] = src;
610
611 return cc;
612}
613
614/* move long extended another memcopy insn with more bells and whistles */
Blue Swirl19b05162012-09-02 07:33:40 +0000615uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
616 uint32_t r3)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000617{
618 uint64_t destlen = env->regs[r1 + 1];
619 uint64_t dest = env->regs[r1];
620 uint64_t srclen = env->regs[r3 + 1];
621 uint64_t src = env->regs[r3];
622 uint8_t pad = a2 & 0xff;
623 uint8_t v;
624 uint32_t cc;
625
626 if (!(env->psw.mask & PSW_MASK_64)) {
627 destlen = (uint32_t)destlen;
628 srclen = (uint32_t)srclen;
629 dest &= 0x7fffffff;
630 src &= 0x7fffffff;
631 }
632
633 if (destlen == srclen) {
634 cc = 0;
635 } else if (destlen < srclen) {
636 cc = 1;
637 } else {
638 cc = 2;
639 }
640
641 if (srclen > destlen) {
642 srclen = destlen;
643 }
644
645 for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
Blue Swirl19b05162012-09-02 07:33:40 +0000646 v = cpu_ldub_data(env, src);
647 cpu_stb_data(env, dest, v);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000648 }
649
650 for (; destlen; dest++, destlen--) {
Blue Swirl19b05162012-09-02 07:33:40 +0000651 cpu_stb_data(env, dest, pad);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000652 }
653
654 env->regs[r1 + 1] = destlen;
655 /* can't use srclen here, we trunc'ed it */
656 /* FIXME: 31-bit mode! */
657 env->regs[r3 + 1] -= src - env->regs[r3];
658 env->regs[r1] = dest;
659 env->regs[r3] = src;
660
661 return cc;
662}
663
664/* compare logical long extended memcompare insn with padding */
Blue Swirl19b05162012-09-02 07:33:40 +0000665uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
666 uint32_t r3)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000667{
668 uint64_t destlen = env->regs[r1 + 1];
Blue Swirl19b05162012-09-02 07:33:40 +0000669 uint64_t dest = get_address_31fix(env, r1);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000670 uint64_t srclen = env->regs[r3 + 1];
Blue Swirl19b05162012-09-02 07:33:40 +0000671 uint64_t src = get_address_31fix(env, r3);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000672 uint8_t pad = a2 & 0xff;
673 uint8_t v1 = 0, v2 = 0;
674 uint32_t cc = 0;
675
676 if (!(destlen || srclen)) {
677 return cc;
678 }
679
680 if (srclen > destlen) {
681 srclen = destlen;
682 }
683
684 for (; destlen || srclen; src++, dest++, destlen--, srclen--) {
Blue Swirl19b05162012-09-02 07:33:40 +0000685 v1 = srclen ? cpu_ldub_data(env, src) : pad;
686 v2 = destlen ? cpu_ldub_data(env, dest) : pad;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000687 if (v1 != v2) {
688 cc = (v1 < v2) ? 1 : 2;
689 break;
690 }
691 }
692
693 env->regs[r1 + 1] = destlen;
694 /* can't use srclen here, we trunc'ed it */
695 env->regs[r3 + 1] -= src - env->regs[r3];
696 env->regs[r1] = dest;
697 env->regs[r3] = src;
698
699 return cc;
700}
701
702/* checksum */
Richard Henderson374724f2012-08-24 11:38:12 -0700703uint64_t HELPER(cksm)(CPUS390XState *env, uint64_t r1,
704 uint64_t src, uint64_t src_len)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000705{
Richard Henderson374724f2012-08-24 11:38:12 -0700706 uint64_t max_len, len;
707 uint64_t cksm = (uint32_t)r1;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000708
Richard Henderson374724f2012-08-24 11:38:12 -0700709 /* Lest we fail to service interrupts in a timely manner, limit the
Peter Maydelle03ba132013-04-09 12:48:19 +0100710 amount of work we're willing to do. For now, let's cap at 8k. */
Richard Henderson374724f2012-08-24 11:38:12 -0700711 max_len = (src_len > 0x2000 ? 0x2000 : src_len);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000712
Richard Henderson374724f2012-08-24 11:38:12 -0700713 /* Process full words as available. */
714 for (len = 0; len + 4 <= max_len; len += 4, src += 4) {
715 cksm += (uint32_t)cpu_ldl_data(env, src);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000716 }
717
Richard Henderson374724f2012-08-24 11:38:12 -0700718 switch (max_len - len) {
Blue Swirl8ef7f782012-09-02 07:33:34 +0000719 case 1:
Blue Swirl19b05162012-09-02 07:33:40 +0000720 cksm += cpu_ldub_data(env, src) << 24;
Richard Henderson374724f2012-08-24 11:38:12 -0700721 len += 1;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000722 break;
723 case 2:
Blue Swirl19b05162012-09-02 07:33:40 +0000724 cksm += cpu_lduw_data(env, src) << 16;
Richard Henderson374724f2012-08-24 11:38:12 -0700725 len += 2;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000726 break;
727 case 3:
Blue Swirl19b05162012-09-02 07:33:40 +0000728 cksm += cpu_lduw_data(env, src) << 16;
729 cksm += cpu_ldub_data(env, src + 2) << 8;
Richard Henderson374724f2012-08-24 11:38:12 -0700730 len += 3;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000731 break;
732 }
733
Richard Henderson374724f2012-08-24 11:38:12 -0700734 /* Fold the carry from the checksum. Note that we can see carry-out
735 during folding more than once (but probably not more than twice). */
736 while (cksm > 0xffffffffull) {
737 cksm = (uint32_t)cksm + (cksm >> 32);
738 }
Blue Swirl8ef7f782012-09-02 07:33:34 +0000739
Richard Henderson374724f2012-08-24 11:38:12 -0700740 /* Indicate whether or not we've processed everything. */
741 env->cc_op = (len == src_len ? 0 : 3);
742
743 /* Return both cksm and processed length. */
744 env->retxl = cksm;
745 return len;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000746}
747
Blue Swirl19b05162012-09-02 07:33:40 +0000748void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest,
749 uint64_t src)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000750{
751 int len_dest = len >> 4;
752 int len_src = len & 0xf;
753 uint8_t b;
754 int second_nibble = 0;
755
756 dest += len_dest;
757 src += len_src;
758
759 /* last byte is special, it only flips the nibbles */
Blue Swirl19b05162012-09-02 07:33:40 +0000760 b = cpu_ldub_data(env, src);
761 cpu_stb_data(env, dest, (b << 4) | (b >> 4));
Blue Swirl8ef7f782012-09-02 07:33:34 +0000762 src--;
763 len_src--;
764
765 /* now pad every nibble with 0xf0 */
766
767 while (len_dest > 0) {
768 uint8_t cur_byte = 0;
769
770 if (len_src > 0) {
Blue Swirl19b05162012-09-02 07:33:40 +0000771 cur_byte = cpu_ldub_data(env, src);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000772 }
773
774 len_dest--;
775 dest--;
776
777 /* only advance one nibble at a time */
778 if (second_nibble) {
779 cur_byte >>= 4;
780 len_src--;
781 src--;
782 }
783 second_nibble = !second_nibble;
784
785 /* digit */
786 cur_byte = (cur_byte & 0xf);
787 /* zone bits */
788 cur_byte |= 0xf0;
789
Blue Swirl19b05162012-09-02 07:33:40 +0000790 cpu_stb_data(env, dest, cur_byte);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000791 }
792}
793
Blue Swirl19b05162012-09-02 07:33:40 +0000794void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array,
795 uint64_t trans)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000796{
797 int i;
798
799 for (i = 0; i <= len; i++) {
Blue Swirl19b05162012-09-02 07:33:40 +0000800 uint8_t byte = cpu_ldub_data(env, array + i);
801 uint8_t new_byte = cpu_ldub_data(env, trans + byte);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000802
Blue Swirl19b05162012-09-02 07:33:40 +0000803 cpu_stb_data(env, array + i, new_byte);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000804 }
805}
806
807#if !defined(CONFIG_USER_ONLY)
Blue Swirl19b05162012-09-02 07:33:40 +0000808void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000809{
810 int i;
811 uint64_t src = a2;
812
813 for (i = r1;; i = (i + 1) % 16) {
Blue Swirl19b05162012-09-02 07:33:40 +0000814 env->cregs[i] = cpu_ldq_data(env, src);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000815 HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
816 i, src, env->cregs[i]);
817 src += sizeof(uint64_t);
818
819 if (i == r3) {
820 break;
821 }
822 }
823
824 tlb_flush(env, 1);
825}
826
Blue Swirl19b05162012-09-02 07:33:40 +0000827void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000828{
829 int i;
830 uint64_t src = a2;
831
832 for (i = r1;; i = (i + 1) % 16) {
Blue Swirl19b05162012-09-02 07:33:40 +0000833 env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) |
834 cpu_ldl_data(env, src);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000835 src += sizeof(uint32_t);
836
837 if (i == r3) {
838 break;
839 }
840 }
841
842 tlb_flush(env, 1);
843}
844
Blue Swirl19b05162012-09-02 07:33:40 +0000845void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000846{
847 int i;
848 uint64_t dest = a2;
849
850 for (i = r1;; i = (i + 1) % 16) {
Blue Swirl19b05162012-09-02 07:33:40 +0000851 cpu_stq_data(env, dest, env->cregs[i]);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000852 dest += sizeof(uint64_t);
853
854 if (i == r3) {
855 break;
856 }
857 }
858}
859
Blue Swirl19b05162012-09-02 07:33:40 +0000860void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000861{
862 int i;
863 uint64_t dest = a2;
864
865 for (i = r1;; i = (i + 1) % 16) {
Blue Swirl19b05162012-09-02 07:33:40 +0000866 cpu_stl_data(env, dest, env->cregs[i]);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000867 dest += sizeof(uint32_t);
868
869 if (i == r3) {
870 break;
871 }
872 }
873}
874
875uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2)
876{
877 /* XXX implement */
878
879 return 0;
880}
881
882/* insert storage key extended */
Blue Swirl19b05162012-09-02 07:33:40 +0000883uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000884{
Blue Swirl19b05162012-09-02 07:33:40 +0000885 uint64_t addr = get_address(env, 0, 0, r2);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000886
887 if (addr > ram_size) {
888 return 0;
889 }
890
891 return env->storage_keys[addr / TARGET_PAGE_SIZE];
892}
893
894/* set storage key extended */
Richard Henderson2bbde272012-08-27 09:18:01 -0700895void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000896{
Blue Swirl19b05162012-09-02 07:33:40 +0000897 uint64_t addr = get_address(env, 0, 0, r2);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000898
899 if (addr > ram_size) {
900 return;
901 }
902
903 env->storage_keys[addr / TARGET_PAGE_SIZE] = r1;
904}
905
906/* reset reference bit extended */
Richard Henderson5cc69c52012-08-27 09:22:13 -0700907uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000908{
909 uint8_t re;
910 uint8_t key;
911
912 if (r2 > ram_size) {
913 return 0;
914 }
915
916 key = env->storage_keys[r2 / TARGET_PAGE_SIZE];
917 re = key & (SK_R | SK_C);
918 env->storage_keys[r2 / TARGET_PAGE_SIZE] = (key & ~SK_R);
919
920 /*
921 * cc
922 *
923 * 0 Reference bit zero; change bit zero
924 * 1 Reference bit zero; change bit one
925 * 2 Reference bit one; change bit zero
926 * 3 Reference bit one; change bit one
927 */
928
929 return re >> 1;
930}
931
932/* compare and swap and purge */
Richard Henderson3d596f42012-08-27 09:57:18 -0700933uint32_t HELPER(csp)(CPUS390XState *env, uint32_t r1, uint64_t r2)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000934{
935 uint32_t cc;
936 uint32_t o1 = env->regs[r1];
Richard Henderson3d596f42012-08-27 09:57:18 -0700937 uint64_t a2 = r2 & ~3ULL;
Blue Swirl19b05162012-09-02 07:33:40 +0000938 uint32_t o2 = cpu_ldl_data(env, a2);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000939
940 if (o1 == o2) {
Blue Swirl19b05162012-09-02 07:33:40 +0000941 cpu_stl_data(env, a2, env->regs[(r1 + 1) & 15]);
Richard Henderson3d596f42012-08-27 09:57:18 -0700942 if (r2 & 0x3) {
Blue Swirl8ef7f782012-09-02 07:33:34 +0000943 /* flush TLB / ALB */
944 tlb_flush(env, 1);
945 }
946 cc = 0;
947 } else {
948 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | o2;
949 cc = 1;
950 }
951
952 return cc;
953}
954
Blue Swirl19b05162012-09-02 07:33:40 +0000955static uint32_t mvc_asc(CPUS390XState *env, int64_t l, uint64_t a1,
956 uint64_t mode1, uint64_t a2, uint64_t mode2)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000957{
958 target_ulong src, dest;
959 int flags, cc = 0, i;
960
961 if (!l) {
962 return 0;
963 } else if (l > 256) {
964 /* max 256 */
965 l = 256;
966 cc = 3;
967 }
968
969 if (mmu_translate(env, a1 & TARGET_PAGE_MASK, 1, mode1, &dest, &flags)) {
970 cpu_loop_exit(env);
971 }
972 dest |= a1 & ~TARGET_PAGE_MASK;
973
974 if (mmu_translate(env, a2 & TARGET_PAGE_MASK, 0, mode2, &src, &flags)) {
975 cpu_loop_exit(env);
976 }
977 src |= a2 & ~TARGET_PAGE_MASK;
978
979 /* XXX replace w/ memcpy */
980 for (i = 0; i < l; i++) {
981 /* XXX be more clever */
982 if ((((dest + i) & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) ||
983 (((src + i) & TARGET_PAGE_MASK) != (src & TARGET_PAGE_MASK))) {
Blue Swirl19b05162012-09-02 07:33:40 +0000984 mvc_asc(env, l - i, a1 + i, mode1, a2 + i, mode2);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000985 break;
986 }
987 stb_phys(dest + i, ldub_phys(src + i));
988 }
989
990 return cc;
991}
992
Blue Swirl19b05162012-09-02 07:33:40 +0000993uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000994{
995 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
996 __func__, l, a1, a2);
997
Blue Swirl19b05162012-09-02 07:33:40 +0000998 return mvc_asc(env, l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000999}
1000
Blue Swirl19b05162012-09-02 07:33:40 +00001001uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
Blue Swirl8ef7f782012-09-02 07:33:34 +00001002{
1003 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1004 __func__, l, a1, a2);
1005
Blue Swirl19b05162012-09-02 07:33:40 +00001006 return mvc_asc(env, l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY);
Blue Swirl8ef7f782012-09-02 07:33:34 +00001007}
1008
1009/* invalidate pte */
Blue Swirl19b05162012-09-02 07:33:40 +00001010void HELPER(ipte)(CPUS390XState *env, uint64_t pte_addr, uint64_t vaddr)
Blue Swirl8ef7f782012-09-02 07:33:34 +00001011{
1012 uint64_t page = vaddr & TARGET_PAGE_MASK;
1013 uint64_t pte = 0;
1014
1015 /* XXX broadcast to other CPUs */
1016
1017 /* XXX Linux is nice enough to give us the exact pte address.
1018 According to spec we'd have to find it out ourselves */
1019 /* XXX Linux is fine with overwriting the pte, the spec requires
1020 us to only set the invalid bit */
1021 stq_phys(pte_addr, pte | _PAGE_INVALID);
1022
1023 /* XXX we exploit the fact that Linux passes the exact virtual
1024 address here - it's not obliged to! */
1025 tlb_flush_page(env, page);
1026
1027 /* XXX 31-bit hack */
1028 if (page & 0x80000000) {
1029 tlb_flush_page(env, page & ~0x80000000);
1030 } else {
1031 tlb_flush_page(env, page | 0x80000000);
1032 }
1033}
1034
1035/* flush local tlb */
Blue Swirl19b05162012-09-02 07:33:40 +00001036void HELPER(ptlb)(CPUS390XState *env)
Blue Swirl8ef7f782012-09-02 07:33:34 +00001037{
1038 tlb_flush(env, 1);
1039}
1040
1041/* store using real address */
Richard Henderson204504e2012-08-27 09:45:38 -07001042void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint64_t v1)
Blue Swirl8ef7f782012-09-02 07:33:34 +00001043{
Richard Henderson204504e2012-08-27 09:45:38 -07001044 stw_phys(get_address(env, 0, 0, addr), (uint32_t)v1);
Blue Swirl8ef7f782012-09-02 07:33:34 +00001045}
1046
1047/* load real address */
Richard Hendersond8fe4a92012-08-22 13:15:10 -07001048uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr)
Blue Swirl8ef7f782012-09-02 07:33:34 +00001049{
1050 uint32_t cc = 0;
1051 int old_exc = env->exception_index;
1052 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
1053 uint64_t ret;
1054 int flags;
1055
1056 /* XXX incomplete - has more corner cases */
1057 if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
1058 program_interrupt(env, PGM_SPECIAL_OP, 2);
1059 }
1060
1061 env->exception_index = old_exc;
1062 if (mmu_translate(env, addr, 0, asc, &ret, &flags)) {
1063 cc = 3;
1064 }
1065 if (env->exception_index == EXCP_PGM) {
1066 ret = env->int_pgm_code | 0x80000000;
1067 } else {
1068 ret |= addr & ~TARGET_PAGE_MASK;
1069 }
1070 env->exception_index = old_exc;
1071
Richard Hendersond8fe4a92012-08-22 13:15:10 -07001072 env->cc_op = cc;
1073 return ret;
Blue Swirl8ef7f782012-09-02 07:33:34 +00001074}
Blue Swirl8ef7f782012-09-02 07:33:34 +00001075#endif