2 * S/390 memory access helper routines
4 * Copyright (c) 2009 Ulrich Hecht
5 * Copyright (c) 2009 Alexander Graf
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.
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.
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/>.
24 /*****************************************************************************/
26 #if !defined(CONFIG_USER_ONLY)
27 #include "exec/softmmu_exec.h"
29 #define MMUSUFFIX _mmu
32 #include "exec/softmmu_template.h"
35 #include "exec/softmmu_template.h"
38 #include "exec/softmmu_template.h"
41 #include "exec/softmmu_template.h"
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 */
47 void tlb_fill(CPUState
*cs
, target_ulong addr
, int is_write
, int mmu_idx
,
52 ret
= s390_cpu_handle_mmu_fault(cs
, addr
, is_write
, mmu_idx
);
53 if (unlikely(ret
!= 0)) {
54 if (likely(retaddr
)) {
55 /* now we have a real cpu fault */
56 cpu_restore_state(cs
, retaddr
);
64 /* #define DEBUG_HELPER */
66 #define HELPER_LOG(x...) qemu_log(x)
68 #define HELPER_LOG(x...)
71 #ifndef CONFIG_USER_ONLY
72 static void mvc_fast_memset(CPUS390XState
*env
, uint32_t l
, uint64_t dest
,
75 S390CPU
*cpu
= s390_env_get_cpu(env
);
79 uint64_t asc
= env
->psw
.mask
& PSW_MASK_ASC
;
82 if (mmu_translate(env
, dest
, 1, asc
, &dest_phys
, &flags
)) {
83 cpu_stb_data(env
, dest
, byte
);
84 cpu_abort(CPU(cpu
), "should never reach here");
86 dest_phys
|= dest
& ~TARGET_PAGE_MASK
;
88 dest_p
= cpu_physical_memory_map(dest_phys
, &len
, 1);
90 memset(dest_p
, byte
, len
);
92 cpu_physical_memory_unmap(dest_p
, 1, len
, len
);
95 static void mvc_fast_memmove(CPUS390XState
*env
, uint32_t l
, uint64_t dest
,
98 S390CPU
*cpu
= s390_env_get_cpu(env
);
104 uint64_t asc
= env
->psw
.mask
& PSW_MASK_ASC
;
107 if (mmu_translate(env
, dest
, 1, asc
, &dest_phys
, &flags
)) {
108 cpu_stb_data(env
, dest
, 0);
109 cpu_abort(CPU(cpu
), "should never reach here");
111 dest_phys
|= dest
& ~TARGET_PAGE_MASK
;
113 if (mmu_translate(env
, src
, 0, asc
, &src_phys
, &flags
)) {
114 cpu_ldub_data(env
, src
);
115 cpu_abort(CPU(cpu
), "should never reach here");
117 src_phys
|= src
& ~TARGET_PAGE_MASK
;
119 dest_p
= cpu_physical_memory_map(dest_phys
, &len
, 1);
120 src_p
= cpu_physical_memory_map(src_phys
, &len
, 0);
122 memmove(dest_p
, src_p
, len
);
124 cpu_physical_memory_unmap(dest_p
, 1, len
, len
);
125 cpu_physical_memory_unmap(src_p
, 0, len
, len
);
130 uint32_t HELPER(nc
)(CPUS390XState
*env
, uint32_t l
, uint64_t dest
,
137 HELPER_LOG("%s l %d dest %" PRIx64
" src %" PRIx64
"\n",
138 __func__
, l
, dest
, src
);
139 for (i
= 0; i
<= l
; i
++) {
140 x
= cpu_ldub_data(env
, dest
+ i
) & cpu_ldub_data(env
, src
+ i
);
144 cpu_stb_data(env
, dest
+ i
, x
);
150 uint32_t HELPER(xc
)(CPUS390XState
*env
, uint32_t l
, uint64_t dest
,
157 HELPER_LOG("%s l %d dest %" PRIx64
" src %" PRIx64
"\n",
158 __func__
, l
, dest
, src
);
160 #ifndef CONFIG_USER_ONLY
161 /* xor with itself is the same as memset(0) */
162 if ((l
> 32) && (src
== dest
) &&
163 (src
& TARGET_PAGE_MASK
) == ((src
+ l
) & TARGET_PAGE_MASK
)) {
164 mvc_fast_memset(env
, l
+ 1, dest
, 0);
169 memset(g2h(dest
), 0, l
+ 1);
174 for (i
= 0; i
<= l
; i
++) {
175 x
= cpu_ldub_data(env
, dest
+ i
) ^ cpu_ldub_data(env
, src
+ i
);
179 cpu_stb_data(env
, dest
+ i
, x
);
185 uint32_t HELPER(oc
)(CPUS390XState
*env
, uint32_t l
, uint64_t dest
,
192 HELPER_LOG("%s l %d dest %" PRIx64
" src %" PRIx64
"\n",
193 __func__
, l
, dest
, src
);
194 for (i
= 0; i
<= l
; i
++) {
195 x
= cpu_ldub_data(env
, dest
+ i
) | cpu_ldub_data(env
, src
+ i
);
199 cpu_stb_data(env
, dest
+ i
, x
);
205 void HELPER(mvc
)(CPUS390XState
*env
, uint32_t l
, uint64_t dest
, uint64_t src
)
209 uint32_t l_64
= (l
+ 1) / 8;
211 HELPER_LOG("%s l %d dest %" PRIx64
" src %" PRIx64
"\n",
212 __func__
, l
, dest
, src
);
214 #ifndef CONFIG_USER_ONLY
216 (src
& TARGET_PAGE_MASK
) == ((src
+ l
) & TARGET_PAGE_MASK
) &&
217 (dest
& TARGET_PAGE_MASK
) == ((dest
+ l
) & TARGET_PAGE_MASK
)) {
218 if (dest
== (src
+ 1)) {
219 mvc_fast_memset(env
, l
+ 1, dest
, cpu_ldub_data(env
, src
));
221 } else if ((src
& TARGET_PAGE_MASK
) != (dest
& TARGET_PAGE_MASK
)) {
222 mvc_fast_memmove(env
, l
+ 1, dest
, src
);
227 if (dest
== (src
+ 1)) {
228 memset(g2h(dest
), cpu_ldub_data(env
, src
), l
+ 1);
231 memmove(g2h(dest
), g2h(src
), l
+ 1);
236 /* handle the parts that fit into 8-byte loads/stores */
237 if (dest
!= (src
+ 1)) {
238 for (i
= 0; i
< l_64
; i
++) {
239 cpu_stq_data(env
, dest
+ x
, cpu_ldq_data(env
, src
+ x
));
244 /* slow version crossing pages with byte accesses */
245 for (i
= x
; i
<= l
; i
++) {
246 cpu_stb_data(env
, dest
+ i
, cpu_ldub_data(env
, src
+ i
));
250 /* compare unsigned byte arrays */
251 uint32_t HELPER(clc
)(CPUS390XState
*env
, uint32_t l
, uint64_t s1
, uint64_t s2
)
257 HELPER_LOG("%s l %d s1 %" PRIx64
" s2 %" PRIx64
"\n",
258 __func__
, l
, s1
, s2
);
259 for (i
= 0; i
<= l
; i
++) {
260 x
= cpu_ldub_data(env
, s1
+ i
);
261 y
= cpu_ldub_data(env
, s2
+ i
);
262 HELPER_LOG("%02x (%c)/%02x (%c) ", x
, x
, y
, y
);
277 /* compare logical under mask */
278 uint32_t HELPER(clm
)(CPUS390XState
*env
, uint32_t r1
, uint32_t mask
,
284 HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64
"\n", __func__
, r1
,
289 d
= cpu_ldub_data(env
, addr
);
290 r
= (r1
& 0xff000000UL
) >> 24;
291 HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64
") ", mask
, r
, d
,
302 mask
= (mask
<< 1) & 0xf;
309 static inline uint64_t fix_address(CPUS390XState
*env
, uint64_t a
)
312 if (!(env
->psw
.mask
& PSW_MASK_64
)) {
318 static inline uint64_t get_address(CPUS390XState
*env
, int x2
, int b2
, int d2
)
327 return fix_address(env
, r
);
330 static inline uint64_t get_address_31fix(CPUS390XState
*env
, int reg
)
332 return fix_address(env
, env
->regs
[reg
]);
335 /* search string (c is byte to search, r2 is string, r1 end of string) */
336 uint64_t HELPER(srst
)(CPUS390XState
*env
, uint64_t r0
, uint64_t end
,
342 str
= fix_address(env
, str
);
343 end
= fix_address(env
, end
);
345 /* Assume for now that R2 is unmodified. */
348 /* Lest we fail to service interrupts in a timely manner, limit the
349 amount of work we're willing to do. For now, let's cap at 8k. */
350 for (len
= 0; len
< 0x2000; ++len
) {
351 if (str
+ len
== end
) {
352 /* Character not found. R1 & R2 are unmodified. */
356 v
= cpu_ldub_data(env
, str
+ len
);
358 /* Character found. Set R1 to the location; R2 is unmodified. */
364 /* CPU-determined bytes processed. Advance R2 to next byte to process. */
365 env
->retxl
= str
+ len
;
370 /* unsigned string compare (c is string terminator) */
371 uint64_t HELPER(clst
)(CPUS390XState
*env
, uint64_t c
, uint64_t s1
, uint64_t s2
)
376 s1
= fix_address(env
, s1
);
377 s2
= fix_address(env
, s2
);
379 /* Lest we fail to service interrupts in a timely manner, limit the
380 amount of work we're willing to do. For now, let's cap at 8k. */
381 for (len
= 0; len
< 0x2000; ++len
) {
382 uint8_t v1
= cpu_ldub_data(env
, s1
+ len
);
383 uint8_t v2
= cpu_ldub_data(env
, s2
+ len
);
386 /* Equal. CC=0, and don't advance the registers. */
392 /* Unequal. CC={1,2}, and advance the registers. Note that
393 the terminator need not be zero, but the string that contains
394 the terminator is by definition "low". */
395 env
->cc_op
= (v1
== c
? 1 : v2
== c
? 2 : v1
< v2
? 1 : 2);
396 env
->retxl
= s2
+ len
;
401 /* CPU-determined bytes equal; advance the registers. */
403 env
->retxl
= s2
+ len
;
408 void HELPER(mvpg
)(CPUS390XState
*env
, uint64_t r0
, uint64_t r1
, uint64_t r2
)
410 /* XXX missing r0 handling */
412 #ifdef CONFIG_USER_ONLY
413 memmove(g2h(r1
), g2h(r2
), TARGET_PAGE_SIZE
);
415 mvc_fast_memmove(env
, TARGET_PAGE_SIZE
, r1
, r2
);
419 /* string copy (c is string terminator) */
420 uint64_t HELPER(mvst
)(CPUS390XState
*env
, uint64_t c
, uint64_t d
, uint64_t s
)
425 d
= fix_address(env
, d
);
426 s
= fix_address(env
, s
);
428 /* Lest we fail to service interrupts in a timely manner, limit the
429 amount of work we're willing to do. For now, let's cap at 8k. */
430 for (len
= 0; len
< 0x2000; ++len
) {
431 uint8_t v
= cpu_ldub_data(env
, s
+ len
);
432 cpu_stb_data(env
, d
+ len
, v
);
434 /* Complete. Set CC=1 and advance R1. */
441 /* Incomplete. Set CC=3 and signal to advance R1 and R2. */
443 env
->retxl
= s
+ len
;
447 static uint32_t helper_icm(CPUS390XState
*env
, uint32_t r1
, uint64_t address
,
450 int pos
= 24; /* top of the lower half of r1 */
451 uint64_t rmask
= 0xff000000ULL
;
458 env
->regs
[r1
] &= ~rmask
;
459 val
= cpu_ldub_data(env
, address
);
460 if ((val
& 0x80) && !ccd
) {
464 if (val
&& cc
== 0) {
467 env
->regs
[r1
] |= (uint64_t)val
<< pos
;
470 mask
= (mask
<< 1) & 0xf;
478 /* execute instruction
479 this instruction executes an insn modified with the contents of r1
480 it does not change the executed instruction in memory
481 it does not change the program counter
482 in other words: tricky...
483 currently implemented by interpreting the cases it is most commonly used in
485 uint32_t HELPER(ex
)(CPUS390XState
*env
, uint32_t cc
, uint64_t v1
,
486 uint64_t addr
, uint64_t ret
)
488 S390CPU
*cpu
= s390_env_get_cpu(env
);
489 uint16_t insn
= cpu_lduw_code(env
, addr
);
491 HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __func__
, v1
, addr
,
493 if ((insn
& 0xf0ff) == 0xd000) {
494 uint32_t l
, insn2
, b1
, b2
, d1
, d2
;
497 insn2
= cpu_ldl_code(env
, addr
+ 2);
498 b1
= (insn2
>> 28) & 0xf;
499 b2
= (insn2
>> 12) & 0xf;
500 d1
= (insn2
>> 16) & 0xfff;
502 switch (insn
& 0xf00) {
504 helper_mvc(env
, l
, get_address(env
, 0, b1
, d1
),
505 get_address(env
, 0, b2
, d2
));
508 cc
= helper_clc(env
, l
, get_address(env
, 0, b1
, d1
),
509 get_address(env
, 0, b2
, d2
));
512 cc
= helper_xc(env
, l
, get_address(env
, 0, b1
, d1
),
513 get_address(env
, 0, b2
, d2
));
516 helper_tr(env
, l
, get_address(env
, 0, b1
, d1
),
517 get_address(env
, 0, b2
, d2
));
522 } else if ((insn
& 0xff00) == 0x0a00) {
523 /* supervisor call */
524 HELPER_LOG("%s: svc %ld via execute\n", __func__
, (insn
| v1
) & 0xff);
525 env
->psw
.addr
= ret
- 4;
526 env
->int_svc_code
= (insn
| v1
) & 0xff;
527 env
->int_svc_ilen
= 4;
528 helper_exception(env
, EXCP_SVC
);
529 } else if ((insn
& 0xff00) == 0xbf00) {
530 uint32_t insn2
, r1
, r3
, b2
, d2
;
532 insn2
= cpu_ldl_code(env
, addr
+ 2);
533 r1
= (insn2
>> 20) & 0xf;
534 r3
= (insn2
>> 16) & 0xf;
535 b2
= (insn2
>> 12) & 0xf;
537 cc
= helper_icm(env
, r1
, get_address(env
, 0, b2
, d2
), r3
);
540 cpu_abort(CPU(cpu
), "EXECUTE on instruction prefix 0x%x not implemented\n",
546 /* load access registers r1 to r3 from memory at a2 */
547 void HELPER(lam
)(CPUS390XState
*env
, uint32_t r1
, uint64_t a2
, uint32_t r3
)
551 for (i
= r1
;; i
= (i
+ 1) % 16) {
552 env
->aregs
[i
] = cpu_ldl_data(env
, a2
);
561 /* store access registers r1 to r3 in memory at a2 */
562 void HELPER(stam
)(CPUS390XState
*env
, uint32_t r1
, uint64_t a2
, uint32_t r3
)
566 for (i
= r1
;; i
= (i
+ 1) % 16) {
567 cpu_stl_data(env
, a2
, env
->aregs
[i
]);
577 uint32_t HELPER(mvcl
)(CPUS390XState
*env
, uint32_t r1
, uint32_t r2
)
579 uint64_t destlen
= env
->regs
[r1
+ 1] & 0xffffff;
580 uint64_t dest
= get_address_31fix(env
, r1
);
581 uint64_t srclen
= env
->regs
[r2
+ 1] & 0xffffff;
582 uint64_t src
= get_address_31fix(env
, r2
);
583 uint8_t pad
= src
>> 24;
587 if (destlen
== srclen
) {
589 } else if (destlen
< srclen
) {
595 if (srclen
> destlen
) {
599 for (; destlen
&& srclen
; src
++, dest
++, destlen
--, srclen
--) {
600 v
= cpu_ldub_data(env
, src
);
601 cpu_stb_data(env
, dest
, v
);
604 for (; destlen
; dest
++, destlen
--) {
605 cpu_stb_data(env
, dest
, pad
);
608 env
->regs
[r1
+ 1] = destlen
;
609 /* can't use srclen here, we trunc'ed it */
610 env
->regs
[r2
+ 1] -= src
- env
->regs
[r2
];
611 env
->regs
[r1
] = dest
;
617 /* move long extended another memcopy insn with more bells and whistles */
618 uint32_t HELPER(mvcle
)(CPUS390XState
*env
, uint32_t r1
, uint64_t a2
,
621 uint64_t destlen
= env
->regs
[r1
+ 1];
622 uint64_t dest
= env
->regs
[r1
];
623 uint64_t srclen
= env
->regs
[r3
+ 1];
624 uint64_t src
= env
->regs
[r3
];
625 uint8_t pad
= a2
& 0xff;
629 if (!(env
->psw
.mask
& PSW_MASK_64
)) {
630 destlen
= (uint32_t)destlen
;
631 srclen
= (uint32_t)srclen
;
636 if (destlen
== srclen
) {
638 } else if (destlen
< srclen
) {
644 if (srclen
> destlen
) {
648 for (; destlen
&& srclen
; src
++, dest
++, destlen
--, srclen
--) {
649 v
= cpu_ldub_data(env
, src
);
650 cpu_stb_data(env
, dest
, v
);
653 for (; destlen
; dest
++, destlen
--) {
654 cpu_stb_data(env
, dest
, pad
);
657 env
->regs
[r1
+ 1] = destlen
;
658 /* can't use srclen here, we trunc'ed it */
659 /* FIXME: 31-bit mode! */
660 env
->regs
[r3
+ 1] -= src
- env
->regs
[r3
];
661 env
->regs
[r1
] = dest
;
667 /* compare logical long extended memcompare insn with padding */
668 uint32_t HELPER(clcle
)(CPUS390XState
*env
, uint32_t r1
, uint64_t a2
,
671 uint64_t destlen
= env
->regs
[r1
+ 1];
672 uint64_t dest
= get_address_31fix(env
, r1
);
673 uint64_t srclen
= env
->regs
[r3
+ 1];
674 uint64_t src
= get_address_31fix(env
, r3
);
675 uint8_t pad
= a2
& 0xff;
676 uint8_t v1
= 0, v2
= 0;
679 if (!(destlen
|| srclen
)) {
683 if (srclen
> destlen
) {
687 for (; destlen
|| srclen
; src
++, dest
++, destlen
--, srclen
--) {
688 v1
= srclen
? cpu_ldub_data(env
, src
) : pad
;
689 v2
= destlen
? cpu_ldub_data(env
, dest
) : pad
;
691 cc
= (v1
< v2
) ? 1 : 2;
696 env
->regs
[r1
+ 1] = destlen
;
697 /* can't use srclen here, we trunc'ed it */
698 env
->regs
[r3
+ 1] -= src
- env
->regs
[r3
];
699 env
->regs
[r1
] = dest
;
706 uint64_t HELPER(cksm
)(CPUS390XState
*env
, uint64_t r1
,
707 uint64_t src
, uint64_t src_len
)
709 uint64_t max_len
, len
;
710 uint64_t cksm
= (uint32_t)r1
;
712 /* Lest we fail to service interrupts in a timely manner, limit the
713 amount of work we're willing to do. For now, let's cap at 8k. */
714 max_len
= (src_len
> 0x2000 ? 0x2000 : src_len
);
716 /* Process full words as available. */
717 for (len
= 0; len
+ 4 <= max_len
; len
+= 4, src
+= 4) {
718 cksm
+= (uint32_t)cpu_ldl_data(env
, src
);
721 switch (max_len
- len
) {
723 cksm
+= cpu_ldub_data(env
, src
) << 24;
727 cksm
+= cpu_lduw_data(env
, src
) << 16;
731 cksm
+= cpu_lduw_data(env
, src
) << 16;
732 cksm
+= cpu_ldub_data(env
, src
+ 2) << 8;
737 /* Fold the carry from the checksum. Note that we can see carry-out
738 during folding more than once (but probably not more than twice). */
739 while (cksm
> 0xffffffffull
) {
740 cksm
= (uint32_t)cksm
+ (cksm
>> 32);
743 /* Indicate whether or not we've processed everything. */
744 env
->cc_op
= (len
== src_len
? 0 : 3);
746 /* Return both cksm and processed length. */
751 void HELPER(unpk
)(CPUS390XState
*env
, uint32_t len
, uint64_t dest
,
754 int len_dest
= len
>> 4;
755 int len_src
= len
& 0xf;
757 int second_nibble
= 0;
762 /* last byte is special, it only flips the nibbles */
763 b
= cpu_ldub_data(env
, src
);
764 cpu_stb_data(env
, dest
, (b
<< 4) | (b
>> 4));
768 /* now pad every nibble with 0xf0 */
770 while (len_dest
> 0) {
771 uint8_t cur_byte
= 0;
774 cur_byte
= cpu_ldub_data(env
, src
);
780 /* only advance one nibble at a time */
786 second_nibble
= !second_nibble
;
789 cur_byte
= (cur_byte
& 0xf);
793 cpu_stb_data(env
, dest
, cur_byte
);
797 void HELPER(tr
)(CPUS390XState
*env
, uint32_t len
, uint64_t array
,
802 for (i
= 0; i
<= len
; i
++) {
803 uint8_t byte
= cpu_ldub_data(env
, array
+ i
);
804 uint8_t new_byte
= cpu_ldub_data(env
, trans
+ byte
);
806 cpu_stb_data(env
, array
+ i
, new_byte
);
810 #if !defined(CONFIG_USER_ONLY)
811 void HELPER(lctlg
)(CPUS390XState
*env
, uint32_t r1
, uint64_t a2
, uint32_t r3
)
813 S390CPU
*cpu
= s390_env_get_cpu(env
);
817 for (i
= r1
;; i
= (i
+ 1) % 16) {
818 env
->cregs
[i
] = cpu_ldq_data(env
, src
);
819 HELPER_LOG("load ctl %d from 0x%" PRIx64
" == 0x%" PRIx64
"\n",
820 i
, src
, env
->cregs
[i
]);
821 src
+= sizeof(uint64_t);
828 tlb_flush(CPU(cpu
), 1);
831 void HELPER(lctl
)(CPUS390XState
*env
, uint32_t r1
, uint64_t a2
, uint32_t r3
)
833 S390CPU
*cpu
= s390_env_get_cpu(env
);
837 for (i
= r1
;; i
= (i
+ 1) % 16) {
838 env
->cregs
[i
] = (env
->cregs
[i
] & 0xFFFFFFFF00000000ULL
) |
839 cpu_ldl_data(env
, src
);
840 src
+= sizeof(uint32_t);
847 tlb_flush(CPU(cpu
), 1);
850 void HELPER(stctg
)(CPUS390XState
*env
, uint32_t r1
, uint64_t a2
, uint32_t r3
)
855 for (i
= r1
;; i
= (i
+ 1) % 16) {
856 cpu_stq_data(env
, dest
, env
->cregs
[i
]);
857 dest
+= sizeof(uint64_t);
865 void HELPER(stctl
)(CPUS390XState
*env
, uint32_t r1
, uint64_t a2
, uint32_t r3
)
870 for (i
= r1
;; i
= (i
+ 1) % 16) {
871 cpu_stl_data(env
, dest
, env
->cregs
[i
]);
872 dest
+= sizeof(uint32_t);
880 uint32_t HELPER(tprot
)(uint64_t a1
, uint64_t a2
)
887 /* insert storage key extended */
888 uint64_t HELPER(iske
)(CPUS390XState
*env
, uint64_t r2
)
890 uint64_t addr
= get_address(env
, 0, 0, r2
);
892 if (addr
> ram_size
) {
896 return env
->storage_keys
[addr
/ TARGET_PAGE_SIZE
];
899 /* set storage key extended */
900 void HELPER(sske
)(CPUS390XState
*env
, uint64_t r1
, uint64_t r2
)
902 uint64_t addr
= get_address(env
, 0, 0, r2
);
904 if (addr
> ram_size
) {
908 env
->storage_keys
[addr
/ TARGET_PAGE_SIZE
] = r1
;
911 /* reset reference bit extended */
912 uint32_t HELPER(rrbe
)(CPUS390XState
*env
, uint64_t r2
)
921 key
= env
->storage_keys
[r2
/ TARGET_PAGE_SIZE
];
922 re
= key
& (SK_R
| SK_C
);
923 env
->storage_keys
[r2
/ TARGET_PAGE_SIZE
] = (key
& ~SK_R
);
928 * 0 Reference bit zero; change bit zero
929 * 1 Reference bit zero; change bit one
930 * 2 Reference bit one; change bit zero
931 * 3 Reference bit one; change bit one
937 /* compare and swap and purge */
938 uint32_t HELPER(csp
)(CPUS390XState
*env
, uint32_t r1
, uint64_t r2
)
940 S390CPU
*cpu
= s390_env_get_cpu(env
);
942 uint32_t o1
= env
->regs
[r1
];
943 uint64_t a2
= r2
& ~3ULL;
944 uint32_t o2
= cpu_ldl_data(env
, a2
);
947 cpu_stl_data(env
, a2
, env
->regs
[(r1
+ 1) & 15]);
949 /* flush TLB / ALB */
950 tlb_flush(CPU(cpu
), 1);
954 env
->regs
[r1
] = (env
->regs
[r1
] & 0xffffffff00000000ULL
) | o2
;
961 static uint32_t mvc_asc(CPUS390XState
*env
, int64_t l
, uint64_t a1
,
962 uint64_t mode1
, uint64_t a2
, uint64_t mode2
)
964 CPUState
*cs
= CPU(s390_env_get_cpu(env
));
965 target_ulong src
, dest
;
966 int flags
, cc
= 0, i
;
970 } else if (l
> 256) {
976 if (mmu_translate(env
, a1
& TARGET_PAGE_MASK
, 1, mode1
, &dest
, &flags
)) {
977 cpu_loop_exit(CPU(s390_env_get_cpu(env
)));
979 dest
|= a1
& ~TARGET_PAGE_MASK
;
981 if (mmu_translate(env
, a2
& TARGET_PAGE_MASK
, 0, mode2
, &src
, &flags
)) {
982 cpu_loop_exit(CPU(s390_env_get_cpu(env
)));
984 src
|= a2
& ~TARGET_PAGE_MASK
;
986 /* XXX replace w/ memcpy */
987 for (i
= 0; i
< l
; i
++) {
988 /* XXX be more clever */
989 if ((((dest
+ i
) & TARGET_PAGE_MASK
) != (dest
& TARGET_PAGE_MASK
)) ||
990 (((src
+ i
) & TARGET_PAGE_MASK
) != (src
& TARGET_PAGE_MASK
))) {
991 mvc_asc(env
, l
- i
, a1
+ i
, mode1
, a2
+ i
, mode2
);
994 stb_phys(cs
->as
, dest
+ i
, ldub_phys(cs
->as
, src
+ i
));
1000 uint32_t HELPER(mvcs
)(CPUS390XState
*env
, uint64_t l
, uint64_t a1
, uint64_t a2
)
1002 HELPER_LOG("%s: %16" PRIx64
" %16" PRIx64
" %16" PRIx64
"\n",
1003 __func__
, l
, a1
, a2
);
1005 return mvc_asc(env
, l
, a1
, PSW_ASC_SECONDARY
, a2
, PSW_ASC_PRIMARY
);
1008 uint32_t HELPER(mvcp
)(CPUS390XState
*env
, uint64_t l
, uint64_t a1
, uint64_t a2
)
1010 HELPER_LOG("%s: %16" PRIx64
" %16" PRIx64
" %16" PRIx64
"\n",
1011 __func__
, l
, a1
, a2
);
1013 return mvc_asc(env
, l
, a1
, PSW_ASC_PRIMARY
, a2
, PSW_ASC_SECONDARY
);
1016 /* invalidate pte */
1017 void HELPER(ipte
)(CPUS390XState
*env
, uint64_t pte_addr
, uint64_t vaddr
)
1019 CPUState
*cs
= CPU(s390_env_get_cpu(env
));
1020 uint64_t page
= vaddr
& TARGET_PAGE_MASK
;
1023 /* XXX broadcast to other CPUs */
1025 /* XXX Linux is nice enough to give us the exact pte address.
1026 According to spec we'd have to find it out ourselves */
1027 /* XXX Linux is fine with overwriting the pte, the spec requires
1028 us to only set the invalid bit */
1029 stq_phys(cs
->as
, pte_addr
, pte
| _PAGE_INVALID
);
1031 /* XXX we exploit the fact that Linux passes the exact virtual
1032 address here - it's not obliged to! */
1033 tlb_flush_page(cs
, page
);
1035 /* XXX 31-bit hack */
1036 if (page
& 0x80000000) {
1037 tlb_flush_page(cs
, page
& ~0x80000000);
1039 tlb_flush_page(cs
, page
| 0x80000000);
1043 /* flush local tlb */
1044 void HELPER(ptlb
)(CPUS390XState
*env
)
1046 S390CPU
*cpu
= s390_env_get_cpu(env
);
1048 tlb_flush(CPU(cpu
), 1);
1051 /* store using real address */
1052 void HELPER(stura
)(CPUS390XState
*env
, uint64_t addr
, uint64_t v1
)
1054 CPUState
*cs
= CPU(s390_env_get_cpu(env
));
1056 stw_phys(cs
->as
, get_address(env
, 0, 0, addr
), (uint32_t)v1
);
1059 /* load real address */
1060 uint64_t HELPER(lra
)(CPUS390XState
*env
, uint64_t addr
)
1062 CPUState
*cs
= CPU(s390_env_get_cpu(env
));
1064 int old_exc
= cs
->exception_index
;
1065 uint64_t asc
= env
->psw
.mask
& PSW_MASK_ASC
;
1069 /* XXX incomplete - has more corner cases */
1070 if (!(env
->psw
.mask
& PSW_MASK_64
) && (addr
>> 32)) {
1071 program_interrupt(env
, PGM_SPECIAL_OP
, 2);
1074 cs
->exception_index
= old_exc
;
1075 if (mmu_translate(env
, addr
, 0, asc
, &ret
, &flags
)) {
1078 if (cs
->exception_index
== EXCP_PGM
) {
1079 ret
= env
->int_pgm_code
| 0x80000000;
1081 ret
|= addr
& ~TARGET_PAGE_MASK
;
1083 cs
->exception_index
= old_exc
;