blob: 7d87c746f68dbcbb0d100e3f75afe59013beeb15 [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) */
Blue Swirl19b05162012-09-02 07:33:40 +0000334uint32_t HELPER(srst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000335{
336 uint64_t i;
337 uint32_t cc = 2;
Blue Swirl19b05162012-09-02 07:33:40 +0000338 uint64_t str = get_address_31fix(env, r2);
339 uint64_t end = get_address_31fix(env, r1);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000340
341 HELPER_LOG("%s: c %d *r1 0x%" PRIx64 " *r2 0x%" PRIx64 "\n", __func__,
342 c, env->regs[r1], env->regs[r2]);
343
344 for (i = str; i != end; i++) {
Blue Swirl19b05162012-09-02 07:33:40 +0000345 if (cpu_ldub_data(env, i) == c) {
Blue Swirl8ef7f782012-09-02 07:33:34 +0000346 env->regs[r1] = i;
347 cc = 1;
348 break;
349 }
350 }
351
352 return cc;
353}
354
355/* unsigned string compare (c is string terminator) */
Richard Hendersonaa31bf62012-09-05 10:20:53 -0700356uint64_t HELPER(clst)(CPUS390XState *env, uint64_t c, uint64_t s1, uint64_t s2)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000357{
Richard Hendersonaa31bf62012-09-05 10:20:53 -0700358 uint32_t len;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000359
360 c = c & 0xff;
Richard Hendersonaa31bf62012-09-05 10:20:53 -0700361 s1 = fix_address(env, s1);
362 s2 = fix_address(env, s2);
363
364 /* Lest we fail to service interrupts in a timely manner, limit the
365 amount of work we're willing to do. For now, lets cap at 8k. */
366 for (len = 0; len < 0x2000; ++len) {
367 uint8_t v1 = cpu_ldub_data(env, s1 + len);
368 uint8_t v2 = cpu_ldub_data(env, s2 + len);
369 if (v1 == v2) {
370 if (v1 == c) {
371 /* Equal. CC=0, and don't advance the registers. */
372 env->cc_op = 0;
373 env->retxl = s2;
374 return s1;
375 }
376 } else {
377 /* Unequal. CC={1,2}, and advance the registers. Note that
378 the terminator need not be zero, but the string that contains
379 the terminator is by definition "low". */
380 env->cc_op = (v1 == c ? 1 : v2 == c ? 2 : v1 < v2 ? 1 : 2);
381 env->retxl = s2 + len;
382 return s1 + len;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000383 }
Blue Swirl8ef7f782012-09-02 07:33:34 +0000384 }
385
Richard Hendersonaa31bf62012-09-05 10:20:53 -0700386 /* CPU-determined bytes equal; advance the registers. */
387 env->cc_op = 3;
388 env->retxl = s2 + len;
389 return s1 + len;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000390}
391
392/* move page */
Blue Swirl19b05162012-09-02 07:33:40 +0000393void HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000394{
395 /* XXX missing r0 handling */
Richard Hendersonee6c38d2012-09-05 10:19:44 -0700396 env->cc_op = 0;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000397#ifdef CONFIG_USER_ONLY
Richard Hendersonee6c38d2012-09-05 10:19:44 -0700398 memmove(g2h(r1), g2h(r2), TARGET_PAGE_SIZE);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000399#else
400 mvc_fast_memmove(env, TARGET_PAGE_SIZE, r1, r2);
401#endif
402}
403
404/* string copy (c is string terminator) */
Richard Hendersonaa31bf62012-09-05 10:20:53 -0700405uint64_t HELPER(mvst)(CPUS390XState *env, uint64_t c, uint64_t d, uint64_t s)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000406{
Richard Hendersonaa31bf62012-09-05 10:20:53 -0700407 uint32_t len;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000408
409 c = c & 0xff;
Richard Hendersonaa31bf62012-09-05 10:20:53 -0700410 d = fix_address(env, d);
411 s = fix_address(env, s);
412
413 /* Lest we fail to service interrupts in a timely manner, limit the
414 amount of work we're willing to do. For now, lets cap at 8k. */
415 for (len = 0; len < 0x2000; ++len) {
416 uint8_t v = cpu_ldub_data(env, s + len);
417 cpu_stb_data(env, d + len, v);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000418 if (v == c) {
Richard Hendersonaa31bf62012-09-05 10:20:53 -0700419 /* Complete. Set CC=1 and advance R1. */
420 env->cc_op = 1;
421 env->retxl = s;
422 return d + len;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000423 }
Blue Swirl8ef7f782012-09-02 07:33:34 +0000424 }
Richard Hendersonaa31bf62012-09-05 10:20:53 -0700425
426 /* Incomplete. Set CC=3 and signal to advance R1 and R2. */
427 env->cc_op = 3;
428 env->retxl = s + len;
429 return d + len;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000430}
431
432/* compare and swap 64-bit */
Richard Hendersonf3de39c2012-08-22 14:46:55 -0700433uint64_t HELPER(csg)(CPUS390XState *env, uint64_t r1, uint64_t a2, uint64_t r3)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000434{
435 /* FIXME: locking? */
Blue Swirl19b05162012-09-02 07:33:40 +0000436 uint64_t v2 = cpu_ldq_data(env, a2);
Richard Hendersonf3de39c2012-08-22 14:46:55 -0700437 if (r1 == v2) {
438 cpu_stq_data(env, a2, r3);
439 env->cc_op = 0;
440 return r1;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000441 } else {
Richard Hendersonf3de39c2012-08-22 14:46:55 -0700442 env->cc_op = 1;
443 return v2;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000444 }
Blue Swirl8ef7f782012-09-02 07:33:34 +0000445}
446
447/* compare double and swap 64-bit */
Blue Swirl19b05162012-09-02 07:33:40 +0000448uint32_t HELPER(cdsg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000449{
450 /* FIXME: locking? */
451 uint32_t cc;
Blue Swirl19b05162012-09-02 07:33:40 +0000452 uint64_t v2_hi = cpu_ldq_data(env, a2);
453 uint64_t v2_lo = cpu_ldq_data(env, a2 + 8);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000454 uint64_t v1_hi = env->regs[r1];
455 uint64_t v1_lo = env->regs[r1 + 1];
456
457 if ((v1_hi == v2_hi) && (v1_lo == v2_lo)) {
458 cc = 0;
Blue Swirl19b05162012-09-02 07:33:40 +0000459 cpu_stq_data(env, a2, env->regs[r3]);
460 cpu_stq_data(env, a2 + 8, env->regs[r3 + 1]);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000461 } else {
462 cc = 1;
463 env->regs[r1] = v2_hi;
464 env->regs[r1 + 1] = v2_lo;
465 }
466
467 return cc;
468}
469
470/* compare and swap 32-bit */
Richard Hendersonf3de39c2012-08-22 14:46:55 -0700471uint64_t HELPER(cs)(CPUS390XState *env, uint64_t r1, uint64_t a2, uint64_t r3)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000472{
473 /* FIXME: locking? */
Blue Swirl19b05162012-09-02 07:33:40 +0000474 uint32_t v2 = cpu_ldl_data(env, a2);
Richard Hendersonf3de39c2012-08-22 14:46:55 -0700475 if ((uint32_t)r1 == v2) {
476 cpu_stl_data(env, a2, (uint32_t)r3);
477 env->cc_op = 0;
478 return r1;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000479 } else {
Richard Hendersonf3de39c2012-08-22 14:46:55 -0700480 env->cc_op = 1;
481 return v2;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000482 }
Blue Swirl8ef7f782012-09-02 07:33:34 +0000483}
484
Blue Swirl19b05162012-09-02 07:33:40 +0000485static uint32_t helper_icm(CPUS390XState *env, uint32_t r1, uint64_t address,
486 uint32_t mask)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000487{
488 int pos = 24; /* top of the lower half of r1 */
489 uint64_t rmask = 0xff000000ULL;
490 uint8_t val = 0;
491 int ccd = 0;
492 uint32_t cc = 0;
493
494 while (mask) {
495 if (mask & 8) {
496 env->regs[r1] &= ~rmask;
Blue Swirl19b05162012-09-02 07:33:40 +0000497 val = cpu_ldub_data(env, address);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000498 if ((val & 0x80) && !ccd) {
499 cc = 1;
500 }
501 ccd = 1;
502 if (val && cc == 0) {
503 cc = 2;
504 }
505 env->regs[r1] |= (uint64_t)val << pos;
506 address++;
507 }
508 mask = (mask << 1) & 0xf;
509 pos -= 8;
510 rmask >>= 8;
511 }
512
513 return cc;
514}
515
516/* execute instruction
517 this instruction executes an insn modified with the contents of r1
518 it does not change the executed instruction in memory
519 it does not change the program counter
520 in other words: tricky...
521 currently implemented by interpreting the cases it is most commonly used in
522*/
Blue Swirl19b05162012-09-02 07:33:40 +0000523uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1,
524 uint64_t addr, uint64_t ret)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000525{
Blue Swirl19b05162012-09-02 07:33:40 +0000526 uint16_t insn = cpu_lduw_code(env, addr);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000527
528 HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __func__, v1, addr,
529 insn);
530 if ((insn & 0xf0ff) == 0xd000) {
531 uint32_t l, insn2, b1, b2, d1, d2;
532
533 l = v1 & 0xff;
Blue Swirl19b05162012-09-02 07:33:40 +0000534 insn2 = cpu_ldl_code(env, addr + 2);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000535 b1 = (insn2 >> 28) & 0xf;
536 b2 = (insn2 >> 12) & 0xf;
537 d1 = (insn2 >> 16) & 0xfff;
538 d2 = insn2 & 0xfff;
539 switch (insn & 0xf00) {
540 case 0x200:
Blue Swirl19b05162012-09-02 07:33:40 +0000541 helper_mvc(env, l, get_address(env, 0, b1, d1),
542 get_address(env, 0, b2, d2));
Blue Swirl8ef7f782012-09-02 07:33:34 +0000543 break;
544 case 0x500:
Blue Swirl19b05162012-09-02 07:33:40 +0000545 cc = helper_clc(env, l, get_address(env, 0, b1, d1),
546 get_address(env, 0, b2, d2));
Blue Swirl8ef7f782012-09-02 07:33:34 +0000547 break;
548 case 0x700:
Blue Swirl19b05162012-09-02 07:33:40 +0000549 cc = helper_xc(env, l, get_address(env, 0, b1, d1),
550 get_address(env, 0, b2, d2));
Blue Swirl8ef7f782012-09-02 07:33:34 +0000551 break;
552 case 0xc00:
Blue Swirl19b05162012-09-02 07:33:40 +0000553 helper_tr(env, l, get_address(env, 0, b1, d1),
554 get_address(env, 0, b2, d2));
Blue Swirl8ef7f782012-09-02 07:33:34 +0000555 break;
556 default:
557 goto abort;
558 break;
559 }
560 } else if ((insn & 0xff00) == 0x0a00) {
561 /* supervisor call */
562 HELPER_LOG("%s: svc %ld via execute\n", __func__, (insn | v1) & 0xff);
563 env->psw.addr = ret - 4;
564 env->int_svc_code = (insn | v1) & 0xff;
Richard Hendersond5a103c2012-09-14 19:31:57 -0700565 env->int_svc_ilen = 4;
Blue Swirl089f5c02012-09-02 07:33:39 +0000566 helper_exception(env, EXCP_SVC);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000567 } else if ((insn & 0xff00) == 0xbf00) {
568 uint32_t insn2, r1, r3, b2, d2;
569
Blue Swirl19b05162012-09-02 07:33:40 +0000570 insn2 = cpu_ldl_code(env, addr + 2);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000571 r1 = (insn2 >> 20) & 0xf;
572 r3 = (insn2 >> 16) & 0xf;
573 b2 = (insn2 >> 12) & 0xf;
574 d2 = insn2 & 0xfff;
Blue Swirl19b05162012-09-02 07:33:40 +0000575 cc = helper_icm(env, r1, get_address(env, 0, b2, d2), r3);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000576 } else {
577 abort:
578 cpu_abort(env, "EXECUTE on instruction prefix 0x%x not implemented\n",
579 insn);
580 }
581 return cc;
582}
583
Blue Swirl8ef7f782012-09-02 07:33:34 +0000584/* load access registers r1 to r3 from memory at a2 */
Blue Swirl19b05162012-09-02 07:33:40 +0000585void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000586{
587 int i;
588
589 for (i = r1;; i = (i + 1) % 16) {
Blue Swirl19b05162012-09-02 07:33:40 +0000590 env->aregs[i] = cpu_ldl_data(env, a2);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000591 a2 += 4;
592
593 if (i == r3) {
594 break;
595 }
596 }
597}
598
599/* store access registers r1 to r3 in memory at a2 */
Blue Swirl19b05162012-09-02 07:33:40 +0000600void HELPER(stam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000601{
602 int i;
603
604 for (i = r1;; i = (i + 1) % 16) {
Blue Swirl19b05162012-09-02 07:33:40 +0000605 cpu_stl_data(env, a2, env->aregs[i]);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000606 a2 += 4;
607
608 if (i == r3) {
609 break;
610 }
611 }
612}
613
614/* move long */
Blue Swirl19b05162012-09-02 07:33:40 +0000615uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000616{
617 uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
Blue Swirl19b05162012-09-02 07:33:40 +0000618 uint64_t dest = get_address_31fix(env, r1);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000619 uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
Blue Swirl19b05162012-09-02 07:33:40 +0000620 uint64_t src = get_address_31fix(env, r2);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000621 uint8_t pad = src >> 24;
622 uint8_t v;
623 uint32_t cc;
624
625 if (destlen == srclen) {
626 cc = 0;
627 } else if (destlen < srclen) {
628 cc = 1;
629 } else {
630 cc = 2;
631 }
632
633 if (srclen > destlen) {
634 srclen = destlen;
635 }
636
637 for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
Blue Swirl19b05162012-09-02 07:33:40 +0000638 v = cpu_ldub_data(env, src);
639 cpu_stb_data(env, dest, v);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000640 }
641
642 for (; destlen; dest++, destlen--) {
Blue Swirl19b05162012-09-02 07:33:40 +0000643 cpu_stb_data(env, dest, pad);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000644 }
645
646 env->regs[r1 + 1] = destlen;
647 /* can't use srclen here, we trunc'ed it */
648 env->regs[r2 + 1] -= src - env->regs[r2];
649 env->regs[r1] = dest;
650 env->regs[r2] = src;
651
652 return cc;
653}
654
655/* move long extended another memcopy insn with more bells and whistles */
Blue Swirl19b05162012-09-02 07:33:40 +0000656uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
657 uint32_t r3)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000658{
659 uint64_t destlen = env->regs[r1 + 1];
660 uint64_t dest = env->regs[r1];
661 uint64_t srclen = env->regs[r3 + 1];
662 uint64_t src = env->regs[r3];
663 uint8_t pad = a2 & 0xff;
664 uint8_t v;
665 uint32_t cc;
666
667 if (!(env->psw.mask & PSW_MASK_64)) {
668 destlen = (uint32_t)destlen;
669 srclen = (uint32_t)srclen;
670 dest &= 0x7fffffff;
671 src &= 0x7fffffff;
672 }
673
674 if (destlen == srclen) {
675 cc = 0;
676 } else if (destlen < srclen) {
677 cc = 1;
678 } else {
679 cc = 2;
680 }
681
682 if (srclen > destlen) {
683 srclen = destlen;
684 }
685
686 for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
Blue Swirl19b05162012-09-02 07:33:40 +0000687 v = cpu_ldub_data(env, src);
688 cpu_stb_data(env, dest, v);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000689 }
690
691 for (; destlen; dest++, destlen--) {
Blue Swirl19b05162012-09-02 07:33:40 +0000692 cpu_stb_data(env, dest, pad);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000693 }
694
695 env->regs[r1 + 1] = destlen;
696 /* can't use srclen here, we trunc'ed it */
697 /* FIXME: 31-bit mode! */
698 env->regs[r3 + 1] -= src - env->regs[r3];
699 env->regs[r1] = dest;
700 env->regs[r3] = src;
701
702 return cc;
703}
704
705/* compare logical long extended memcompare insn with padding */
Blue Swirl19b05162012-09-02 07:33:40 +0000706uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
707 uint32_t r3)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000708{
709 uint64_t destlen = env->regs[r1 + 1];
Blue Swirl19b05162012-09-02 07:33:40 +0000710 uint64_t dest = get_address_31fix(env, r1);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000711 uint64_t srclen = env->regs[r3 + 1];
Blue Swirl19b05162012-09-02 07:33:40 +0000712 uint64_t src = get_address_31fix(env, r3);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000713 uint8_t pad = a2 & 0xff;
714 uint8_t v1 = 0, v2 = 0;
715 uint32_t cc = 0;
716
717 if (!(destlen || srclen)) {
718 return cc;
719 }
720
721 if (srclen > destlen) {
722 srclen = destlen;
723 }
724
725 for (; destlen || srclen; src++, dest++, destlen--, srclen--) {
Blue Swirl19b05162012-09-02 07:33:40 +0000726 v1 = srclen ? cpu_ldub_data(env, src) : pad;
727 v2 = destlen ? cpu_ldub_data(env, dest) : pad;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000728 if (v1 != v2) {
729 cc = (v1 < v2) ? 1 : 2;
730 break;
731 }
732 }
733
734 env->regs[r1 + 1] = destlen;
735 /* can't use srclen here, we trunc'ed it */
736 env->regs[r3 + 1] -= src - env->regs[r3];
737 env->regs[r1] = dest;
738 env->regs[r3] = src;
739
740 return cc;
741}
742
743/* checksum */
Richard Henderson374724f2012-08-24 11:38:12 -0700744uint64_t HELPER(cksm)(CPUS390XState *env, uint64_t r1,
745 uint64_t src, uint64_t src_len)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000746{
Richard Henderson374724f2012-08-24 11:38:12 -0700747 uint64_t max_len, len;
748 uint64_t cksm = (uint32_t)r1;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000749
Richard Henderson374724f2012-08-24 11:38:12 -0700750 /* Lest we fail to service interrupts in a timely manner, limit the
751 amount of work we're willing to do. For now, lets cap at 8k. */
752 max_len = (src_len > 0x2000 ? 0x2000 : src_len);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000753
Richard Henderson374724f2012-08-24 11:38:12 -0700754 /* Process full words as available. */
755 for (len = 0; len + 4 <= max_len; len += 4, src += 4) {
756 cksm += (uint32_t)cpu_ldl_data(env, src);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000757 }
758
Richard Henderson374724f2012-08-24 11:38:12 -0700759 switch (max_len - len) {
Blue Swirl8ef7f782012-09-02 07:33:34 +0000760 case 1:
Blue Swirl19b05162012-09-02 07:33:40 +0000761 cksm += cpu_ldub_data(env, src) << 24;
Richard Henderson374724f2012-08-24 11:38:12 -0700762 len += 1;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000763 break;
764 case 2:
Blue Swirl19b05162012-09-02 07:33:40 +0000765 cksm += cpu_lduw_data(env, src) << 16;
Richard Henderson374724f2012-08-24 11:38:12 -0700766 len += 2;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000767 break;
768 case 3:
Blue Swirl19b05162012-09-02 07:33:40 +0000769 cksm += cpu_lduw_data(env, src) << 16;
770 cksm += cpu_ldub_data(env, src + 2) << 8;
Richard Henderson374724f2012-08-24 11:38:12 -0700771 len += 3;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000772 break;
773 }
774
Richard Henderson374724f2012-08-24 11:38:12 -0700775 /* Fold the carry from the checksum. Note that we can see carry-out
776 during folding more than once (but probably not more than twice). */
777 while (cksm > 0xffffffffull) {
778 cksm = (uint32_t)cksm + (cksm >> 32);
779 }
Blue Swirl8ef7f782012-09-02 07:33:34 +0000780
Richard Henderson374724f2012-08-24 11:38:12 -0700781 /* Indicate whether or not we've processed everything. */
782 env->cc_op = (len == src_len ? 0 : 3);
783
784 /* Return both cksm and processed length. */
785 env->retxl = cksm;
786 return len;
Blue Swirl8ef7f782012-09-02 07:33:34 +0000787}
788
Blue Swirl19b05162012-09-02 07:33:40 +0000789void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest,
790 uint64_t src)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000791{
792 int len_dest = len >> 4;
793 int len_src = len & 0xf;
794 uint8_t b;
795 int second_nibble = 0;
796
797 dest += len_dest;
798 src += len_src;
799
800 /* last byte is special, it only flips the nibbles */
Blue Swirl19b05162012-09-02 07:33:40 +0000801 b = cpu_ldub_data(env, src);
802 cpu_stb_data(env, dest, (b << 4) | (b >> 4));
Blue Swirl8ef7f782012-09-02 07:33:34 +0000803 src--;
804 len_src--;
805
806 /* now pad every nibble with 0xf0 */
807
808 while (len_dest > 0) {
809 uint8_t cur_byte = 0;
810
811 if (len_src > 0) {
Blue Swirl19b05162012-09-02 07:33:40 +0000812 cur_byte = cpu_ldub_data(env, src);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000813 }
814
815 len_dest--;
816 dest--;
817
818 /* only advance one nibble at a time */
819 if (second_nibble) {
820 cur_byte >>= 4;
821 len_src--;
822 src--;
823 }
824 second_nibble = !second_nibble;
825
826 /* digit */
827 cur_byte = (cur_byte & 0xf);
828 /* zone bits */
829 cur_byte |= 0xf0;
830
Blue Swirl19b05162012-09-02 07:33:40 +0000831 cpu_stb_data(env, dest, cur_byte);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000832 }
833}
834
Blue Swirl19b05162012-09-02 07:33:40 +0000835void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array,
836 uint64_t trans)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000837{
838 int i;
839
840 for (i = 0; i <= len; i++) {
Blue Swirl19b05162012-09-02 07:33:40 +0000841 uint8_t byte = cpu_ldub_data(env, array + i);
842 uint8_t new_byte = cpu_ldub_data(env, trans + byte);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000843
Blue Swirl19b05162012-09-02 07:33:40 +0000844 cpu_stb_data(env, array + i, new_byte);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000845 }
846}
847
848#if !defined(CONFIG_USER_ONLY)
Blue Swirl19b05162012-09-02 07:33:40 +0000849void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000850{
851 int i;
852 uint64_t src = a2;
853
854 for (i = r1;; i = (i + 1) % 16) {
Blue Swirl19b05162012-09-02 07:33:40 +0000855 env->cregs[i] = cpu_ldq_data(env, src);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000856 HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
857 i, src, env->cregs[i]);
858 src += sizeof(uint64_t);
859
860 if (i == r3) {
861 break;
862 }
863 }
864
865 tlb_flush(env, 1);
866}
867
Blue Swirl19b05162012-09-02 07:33:40 +0000868void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000869{
870 int i;
871 uint64_t src = a2;
872
873 for (i = r1;; i = (i + 1) % 16) {
Blue Swirl19b05162012-09-02 07:33:40 +0000874 env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) |
875 cpu_ldl_data(env, src);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000876 src += sizeof(uint32_t);
877
878 if (i == r3) {
879 break;
880 }
881 }
882
883 tlb_flush(env, 1);
884}
885
Blue Swirl19b05162012-09-02 07:33:40 +0000886void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000887{
888 int i;
889 uint64_t dest = a2;
890
891 for (i = r1;; i = (i + 1) % 16) {
Blue Swirl19b05162012-09-02 07:33:40 +0000892 cpu_stq_data(env, dest, env->cregs[i]);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000893 dest += sizeof(uint64_t);
894
895 if (i == r3) {
896 break;
897 }
898 }
899}
900
Blue Swirl19b05162012-09-02 07:33:40 +0000901void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000902{
903 int i;
904 uint64_t dest = a2;
905
906 for (i = r1;; i = (i + 1) % 16) {
Blue Swirl19b05162012-09-02 07:33:40 +0000907 cpu_stl_data(env, dest, env->cregs[i]);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000908 dest += sizeof(uint32_t);
909
910 if (i == r3) {
911 break;
912 }
913 }
914}
915
916uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2)
917{
918 /* XXX implement */
919
920 return 0;
921}
922
923/* insert storage key extended */
Blue Swirl19b05162012-09-02 07:33:40 +0000924uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000925{
Blue Swirl19b05162012-09-02 07:33:40 +0000926 uint64_t addr = get_address(env, 0, 0, r2);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000927
928 if (addr > ram_size) {
929 return 0;
930 }
931
932 return env->storage_keys[addr / TARGET_PAGE_SIZE];
933}
934
935/* set storage key extended */
Blue Swirl19b05162012-09-02 07:33:40 +0000936void HELPER(sske)(CPUS390XState *env, uint32_t r1, uint64_t r2)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000937{
Blue Swirl19b05162012-09-02 07:33:40 +0000938 uint64_t addr = get_address(env, 0, 0, r2);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000939
940 if (addr > ram_size) {
941 return;
942 }
943
944 env->storage_keys[addr / TARGET_PAGE_SIZE] = r1;
945}
946
947/* reset reference bit extended */
Blue Swirl19b05162012-09-02 07:33:40 +0000948uint32_t HELPER(rrbe)(CPUS390XState *env, uint32_t r1, uint64_t r2)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000949{
950 uint8_t re;
951 uint8_t key;
952
953 if (r2 > ram_size) {
954 return 0;
955 }
956
957 key = env->storage_keys[r2 / TARGET_PAGE_SIZE];
958 re = key & (SK_R | SK_C);
959 env->storage_keys[r2 / TARGET_PAGE_SIZE] = (key & ~SK_R);
960
961 /*
962 * cc
963 *
964 * 0 Reference bit zero; change bit zero
965 * 1 Reference bit zero; change bit one
966 * 2 Reference bit one; change bit zero
967 * 3 Reference bit one; change bit one
968 */
969
970 return re >> 1;
971}
972
973/* compare and swap and purge */
Blue Swirl19b05162012-09-02 07:33:40 +0000974uint32_t HELPER(csp)(CPUS390XState *env, uint32_t r1, uint32_t r2)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000975{
976 uint32_t cc;
977 uint32_t o1 = env->regs[r1];
Blue Swirl19b05162012-09-02 07:33:40 +0000978 uint64_t a2 = get_address_31fix(env, r2) & ~3ULL;
979 uint32_t o2 = cpu_ldl_data(env, a2);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000980
981 if (o1 == o2) {
Blue Swirl19b05162012-09-02 07:33:40 +0000982 cpu_stl_data(env, a2, env->regs[(r1 + 1) & 15]);
Blue Swirl8ef7f782012-09-02 07:33:34 +0000983 if (env->regs[r2] & 0x3) {
984 /* flush TLB / ALB */
985 tlb_flush(env, 1);
986 }
987 cc = 0;
988 } else {
989 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | o2;
990 cc = 1;
991 }
992
993 return cc;
994}
995
Blue Swirl19b05162012-09-02 07:33:40 +0000996static uint32_t mvc_asc(CPUS390XState *env, int64_t l, uint64_t a1,
997 uint64_t mode1, uint64_t a2, uint64_t mode2)
Blue Swirl8ef7f782012-09-02 07:33:34 +0000998{
999 target_ulong src, dest;
1000 int flags, cc = 0, i;
1001
1002 if (!l) {
1003 return 0;
1004 } else if (l > 256) {
1005 /* max 256 */
1006 l = 256;
1007 cc = 3;
1008 }
1009
1010 if (mmu_translate(env, a1 & TARGET_PAGE_MASK, 1, mode1, &dest, &flags)) {
1011 cpu_loop_exit(env);
1012 }
1013 dest |= a1 & ~TARGET_PAGE_MASK;
1014
1015 if (mmu_translate(env, a2 & TARGET_PAGE_MASK, 0, mode2, &src, &flags)) {
1016 cpu_loop_exit(env);
1017 }
1018 src |= a2 & ~TARGET_PAGE_MASK;
1019
1020 /* XXX replace w/ memcpy */
1021 for (i = 0; i < l; i++) {
1022 /* XXX be more clever */
1023 if ((((dest + i) & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) ||
1024 (((src + i) & TARGET_PAGE_MASK) != (src & TARGET_PAGE_MASK))) {
Blue Swirl19b05162012-09-02 07:33:40 +00001025 mvc_asc(env, l - i, a1 + i, mode1, a2 + i, mode2);
Blue Swirl8ef7f782012-09-02 07:33:34 +00001026 break;
1027 }
1028 stb_phys(dest + i, ldub_phys(src + i));
1029 }
1030
1031 return cc;
1032}
1033
Blue Swirl19b05162012-09-02 07:33:40 +00001034uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
Blue Swirl8ef7f782012-09-02 07:33:34 +00001035{
1036 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1037 __func__, l, a1, a2);
1038
Blue Swirl19b05162012-09-02 07:33:40 +00001039 return mvc_asc(env, l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY);
Blue Swirl8ef7f782012-09-02 07:33:34 +00001040}
1041
Blue Swirl19b05162012-09-02 07:33:40 +00001042uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
Blue Swirl8ef7f782012-09-02 07:33:34 +00001043{
1044 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
1045 __func__, l, a1, a2);
1046
Blue Swirl19b05162012-09-02 07:33:40 +00001047 return mvc_asc(env, l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY);
Blue Swirl8ef7f782012-09-02 07:33:34 +00001048}
1049
1050/* invalidate pte */
Blue Swirl19b05162012-09-02 07:33:40 +00001051void HELPER(ipte)(CPUS390XState *env, uint64_t pte_addr, uint64_t vaddr)
Blue Swirl8ef7f782012-09-02 07:33:34 +00001052{
1053 uint64_t page = vaddr & TARGET_PAGE_MASK;
1054 uint64_t pte = 0;
1055
1056 /* XXX broadcast to other CPUs */
1057
1058 /* XXX Linux is nice enough to give us the exact pte address.
1059 According to spec we'd have to find it out ourselves */
1060 /* XXX Linux is fine with overwriting the pte, the spec requires
1061 us to only set the invalid bit */
1062 stq_phys(pte_addr, pte | _PAGE_INVALID);
1063
1064 /* XXX we exploit the fact that Linux passes the exact virtual
1065 address here - it's not obliged to! */
1066 tlb_flush_page(env, page);
1067
1068 /* XXX 31-bit hack */
1069 if (page & 0x80000000) {
1070 tlb_flush_page(env, page & ~0x80000000);
1071 } else {
1072 tlb_flush_page(env, page | 0x80000000);
1073 }
1074}
1075
1076/* flush local tlb */
Blue Swirl19b05162012-09-02 07:33:40 +00001077void HELPER(ptlb)(CPUS390XState *env)
Blue Swirl8ef7f782012-09-02 07:33:34 +00001078{
1079 tlb_flush(env, 1);
1080}
1081
1082/* store using real address */
Blue Swirl19b05162012-09-02 07:33:40 +00001083void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint32_t v1)
Blue Swirl8ef7f782012-09-02 07:33:34 +00001084{
Blue Swirl19b05162012-09-02 07:33:40 +00001085 stw_phys(get_address(env, 0, 0, addr), v1);
Blue Swirl8ef7f782012-09-02 07:33:34 +00001086}
1087
1088/* load real address */
Richard Hendersond8fe4a92012-08-22 13:15:10 -07001089uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr)
Blue Swirl8ef7f782012-09-02 07:33:34 +00001090{
1091 uint32_t cc = 0;
1092 int old_exc = env->exception_index;
1093 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
1094 uint64_t ret;
1095 int flags;
1096
1097 /* XXX incomplete - has more corner cases */
1098 if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
1099 program_interrupt(env, PGM_SPECIAL_OP, 2);
1100 }
1101
1102 env->exception_index = old_exc;
1103 if (mmu_translate(env, addr, 0, asc, &ret, &flags)) {
1104 cc = 3;
1105 }
1106 if (env->exception_index == EXCP_PGM) {
1107 ret = env->int_pgm_code | 0x80000000;
1108 } else {
1109 ret |= addr & ~TARGET_PAGE_MASK;
1110 }
1111 env->exception_index = old_exc;
1112
Richard Hendersond8fe4a92012-08-22 13:15:10 -07001113 env->cc_op = cc;
1114 return ret;
Blue Swirl8ef7f782012-09-02 07:33:34 +00001115}
Blue Swirl8ef7f782012-09-02 07:33:34 +00001116#endif