1c9274b6bSCho, Yu-Chen /*
2c9274b6bSCho, Yu-Chen * S/390 memory access helper routines
3c9274b6bSCho, Yu-Chen *
4c9274b6bSCho, Yu-Chen * Copyright (c) 2009 Ulrich Hecht
5c9274b6bSCho, Yu-Chen * Copyright (c) 2009 Alexander Graf
6c9274b6bSCho, Yu-Chen *
7c9274b6bSCho, Yu-Chen * This library is free software; you can redistribute it and/or
8c9274b6bSCho, Yu-Chen * modify it under the terms of the GNU Lesser General Public
9c9274b6bSCho, Yu-Chen * License as published by the Free Software Foundation; either
10c9274b6bSCho, Yu-Chen * version 2.1 of the License, or (at your option) any later version.
11c9274b6bSCho, Yu-Chen *
12c9274b6bSCho, Yu-Chen * This library is distributed in the hope that it will be useful,
13c9274b6bSCho, Yu-Chen * but WITHOUT ANY WARRANTY; without even the implied warranty of
14c9274b6bSCho, Yu-Chen * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15c9274b6bSCho, Yu-Chen * Lesser General Public License for more details.
16c9274b6bSCho, Yu-Chen *
17c9274b6bSCho, Yu-Chen * You should have received a copy of the GNU Lesser General Public
18c9274b6bSCho, Yu-Chen * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19c9274b6bSCho, Yu-Chen */
20c9274b6bSCho, Yu-Chen
21c9274b6bSCho, Yu-Chen #include "qemu/osdep.h"
22cd617484SPhilippe Mathieu-Daudé #include "qemu/log.h"
23c9274b6bSCho, Yu-Chen #include "cpu.h"
24c9274b6bSCho, Yu-Chen #include "s390x-internal.h"
25c9274b6bSCho, Yu-Chen #include "tcg_s390x.h"
26c9274b6bSCho, Yu-Chen #include "exec/helper-proto.h"
27c9274b6bSCho, Yu-Chen #include "exec/exec-all.h"
2874781c08SPhilippe Mathieu-Daudé #include "exec/page-protection.h"
29c9274b6bSCho, Yu-Chen #include "exec/cpu_ldst.h"
306eece7f5SPhilippe Mathieu-Daudé #include "hw/core/tcg-cpu-ops.h"
31c9274b6bSCho, Yu-Chen #include "qemu/int128.h"
32c9274b6bSCho, Yu-Chen #include "qemu/atomic128.h"
33c9274b6bSCho, Yu-Chen
34c9274b6bSCho, Yu-Chen #if !defined(CONFIG_USER_ONLY)
35c9274b6bSCho, Yu-Chen #include "hw/s390x/storage-keys.h"
36c9274b6bSCho, Yu-Chen #include "hw/boards.h"
37c9274b6bSCho, Yu-Chen #endif
38c9274b6bSCho, Yu-Chen
3961dee10fSRichard Henderson #ifdef CONFIG_USER_ONLY
4061dee10fSRichard Henderson # define user_or_likely(X) true
4161dee10fSRichard Henderson #else
4261dee10fSRichard Henderson # define user_or_likely(X) likely(X)
4361dee10fSRichard Henderson #endif
4461dee10fSRichard Henderson
45c9274b6bSCho, Yu-Chen /*****************************************************************************/
46c9274b6bSCho, Yu-Chen /* Softmmu support */
47c9274b6bSCho, Yu-Chen
48c9274b6bSCho, Yu-Chen /* #define DEBUG_HELPER */
49c9274b6bSCho, Yu-Chen #ifdef DEBUG_HELPER
50c9274b6bSCho, Yu-Chen #define HELPER_LOG(x...) qemu_log(x)
51c9274b6bSCho, Yu-Chen #else
52c9274b6bSCho, Yu-Chen #define HELPER_LOG(x...)
53c9274b6bSCho, Yu-Chen #endif
54c9274b6bSCho, Yu-Chen
psw_key_valid(CPUS390XState * env,uint8_t psw_key)55c9274b6bSCho, Yu-Chen static inline bool psw_key_valid(CPUS390XState *env, uint8_t psw_key)
56c9274b6bSCho, Yu-Chen {
57c9274b6bSCho, Yu-Chen uint16_t pkm = env->cregs[3] >> 16;
58c9274b6bSCho, Yu-Chen
59c9274b6bSCho, Yu-Chen if (env->psw.mask & PSW_MASK_PSTATE) {
60c9274b6bSCho, Yu-Chen /* PSW key has range 0..15, it is valid if the bit is 1 in the PKM */
615e275ca6SThomas Huth return pkm & (0x8000 >> psw_key);
62c9274b6bSCho, Yu-Chen }
63c9274b6bSCho, Yu-Chen return true;
64c9274b6bSCho, Yu-Chen }
65c9274b6bSCho, Yu-Chen
is_destructive_overlap(CPUS390XState * env,uint64_t dest,uint64_t src,uint32_t len)66c9274b6bSCho, Yu-Chen static bool is_destructive_overlap(CPUS390XState *env, uint64_t dest,
67c9274b6bSCho, Yu-Chen uint64_t src, uint32_t len)
68c9274b6bSCho, Yu-Chen {
69c9274b6bSCho, Yu-Chen if (!len || src == dest) {
70c9274b6bSCho, Yu-Chen return false;
71c9274b6bSCho, Yu-Chen }
72c9274b6bSCho, Yu-Chen /* Take care of wrapping at the end of address space. */
73c9274b6bSCho, Yu-Chen if (unlikely(wrap_address(env, src + len - 1) < src)) {
74c9274b6bSCho, Yu-Chen return dest > src || dest <= wrap_address(env, src + len - 1);
75c9274b6bSCho, Yu-Chen }
76c9274b6bSCho, Yu-Chen return dest > src && dest <= src + len - 1;
77c9274b6bSCho, Yu-Chen }
78c9274b6bSCho, Yu-Chen
79c9274b6bSCho, Yu-Chen /* Trigger a SPECIFICATION exception if an address or a length is not
80c9274b6bSCho, Yu-Chen naturally aligned. */
check_alignment(CPUS390XState * env,uint64_t v,int wordsize,uintptr_t ra)81c9274b6bSCho, Yu-Chen static inline void check_alignment(CPUS390XState *env, uint64_t v,
82c9274b6bSCho, Yu-Chen int wordsize, uintptr_t ra)
83c9274b6bSCho, Yu-Chen {
84c9274b6bSCho, Yu-Chen if (v % wordsize) {
85c9274b6bSCho, Yu-Chen tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
86c9274b6bSCho, Yu-Chen }
87c9274b6bSCho, Yu-Chen }
88c9274b6bSCho, Yu-Chen
89c9274b6bSCho, Yu-Chen /* Load a value from memory according to its size. */
cpu_ldusize_data_ra(CPUS390XState * env,uint64_t addr,int wordsize,uintptr_t ra)90c9274b6bSCho, Yu-Chen static inline uint64_t cpu_ldusize_data_ra(CPUS390XState *env, uint64_t addr,
91c9274b6bSCho, Yu-Chen int wordsize, uintptr_t ra)
92c9274b6bSCho, Yu-Chen {
93c9274b6bSCho, Yu-Chen switch (wordsize) {
94c9274b6bSCho, Yu-Chen case 1:
95c9274b6bSCho, Yu-Chen return cpu_ldub_data_ra(env, addr, ra);
96c9274b6bSCho, Yu-Chen case 2:
97c9274b6bSCho, Yu-Chen return cpu_lduw_data_ra(env, addr, ra);
98c9274b6bSCho, Yu-Chen default:
99c9274b6bSCho, Yu-Chen abort();
100c9274b6bSCho, Yu-Chen }
101c9274b6bSCho, Yu-Chen }
102c9274b6bSCho, Yu-Chen
103c9274b6bSCho, Yu-Chen /* Store a to memory according to its size. */
cpu_stsize_data_ra(CPUS390XState * env,uint64_t addr,uint64_t value,int wordsize,uintptr_t ra)104c9274b6bSCho, Yu-Chen static inline void cpu_stsize_data_ra(CPUS390XState *env, uint64_t addr,
105c9274b6bSCho, Yu-Chen uint64_t value, int wordsize,
106c9274b6bSCho, Yu-Chen uintptr_t ra)
107c9274b6bSCho, Yu-Chen {
108c9274b6bSCho, Yu-Chen switch (wordsize) {
109c9274b6bSCho, Yu-Chen case 1:
110c9274b6bSCho, Yu-Chen cpu_stb_data_ra(env, addr, value, ra);
111c9274b6bSCho, Yu-Chen break;
112c9274b6bSCho, Yu-Chen case 2:
113c9274b6bSCho, Yu-Chen cpu_stw_data_ra(env, addr, value, ra);
114c9274b6bSCho, Yu-Chen break;
115c9274b6bSCho, Yu-Chen default:
116c9274b6bSCho, Yu-Chen abort();
117c9274b6bSCho, Yu-Chen }
118c9274b6bSCho, Yu-Chen }
119c9274b6bSCho, Yu-Chen
120c9274b6bSCho, Yu-Chen /* An access covers at most 4096 bytes and therefore at most two pages. */
121c9274b6bSCho, Yu-Chen typedef struct S390Access {
122c9274b6bSCho, Yu-Chen target_ulong vaddr1;
123c9274b6bSCho, Yu-Chen target_ulong vaddr2;
124bebc8adeSRichard Henderson void *haddr1;
125bebc8adeSRichard Henderson void *haddr2;
126c9274b6bSCho, Yu-Chen uint16_t size1;
127c9274b6bSCho, Yu-Chen uint16_t size2;
128c9274b6bSCho, Yu-Chen /*
129c9274b6bSCho, Yu-Chen * If we can't access the host page directly, we'll have to do I/O access
130c9274b6bSCho, Yu-Chen * via ld/st helpers. These are internal details, so we store the
131c9274b6bSCho, Yu-Chen * mmu idx to do the access here instead of passing it around in the
13296b1416fSRichard Henderson * helpers.
133c9274b6bSCho, Yu-Chen */
134c9274b6bSCho, Yu-Chen int mmu_idx;
135c9274b6bSCho, Yu-Chen } S390Access;
136c9274b6bSCho, Yu-Chen
137c9274b6bSCho, Yu-Chen /*
138c9274b6bSCho, Yu-Chen * With nonfault=1, return the PGM_ exception that would have been injected
139c9274b6bSCho, Yu-Chen * into the guest; return 0 if no exception was detected.
140c9274b6bSCho, Yu-Chen *
141c9274b6bSCho, Yu-Chen * For !CONFIG_USER_ONLY, the TEC is stored stored to env->tlb_fill_tec.
142c9274b6bSCho, Yu-Chen * For CONFIG_USER_ONLY, the faulting address is stored to env->__excp_addr.
143c9274b6bSCho, Yu-Chen */
s390_probe_access(CPUArchState * env,target_ulong addr,int size,MMUAccessType access_type,int mmu_idx,bool nonfault,void ** phost,uintptr_t ra)14440494314SRichard Henderson static inline int s390_probe_access(CPUArchState *env, target_ulong addr,
14540494314SRichard Henderson int size, MMUAccessType access_type,
14640494314SRichard Henderson int mmu_idx, bool nonfault,
14740494314SRichard Henderson void **phost, uintptr_t ra)
148c9274b6bSCho, Yu-Chen {
149*066b9de4SIlya Leoshkevich int flags = probe_access_flags(env, addr, size, access_type, mmu_idx,
150db9aab57SRichard Henderson nonfault, phost, ra);
151c9274b6bSCho, Yu-Chen
15240494314SRichard Henderson if (unlikely(flags & TLB_INVALID_MASK)) {
15340494314SRichard Henderson #ifdef CONFIG_USER_ONLY
15440494314SRichard Henderson /* Address is in TEC in system mode; see s390_cpu_record_sigsegv. */
15540494314SRichard Henderson env->__excp_addr = addr & TARGET_PAGE_MASK;
15640494314SRichard Henderson return (page_get_flags(addr) & PAGE_VALID
15740494314SRichard Henderson ? PGM_PROTECTION : PGM_ADDRESSING);
15840494314SRichard Henderson #else
159c9274b6bSCho, Yu-Chen return env->tlb_fill_exc;
16040494314SRichard Henderson #endif
161c9274b6bSCho, Yu-Chen }
162c9274b6bSCho, Yu-Chen
16340494314SRichard Henderson #ifndef CONFIG_USER_ONLY
164c9274b6bSCho, Yu-Chen if (unlikely(flags & TLB_WATCHPOINT)) {
165c9274b6bSCho, Yu-Chen /* S390 does not presently use transaction attributes. */
166c9274b6bSCho, Yu-Chen cpu_check_watchpoint(env_cpu(env), addr, size,
167c9274b6bSCho, Yu-Chen MEMTXATTRS_UNSPECIFIED,
168c9274b6bSCho, Yu-Chen (access_type == MMU_DATA_STORE
169c9274b6bSCho, Yu-Chen ? BP_MEM_WRITE : BP_MEM_READ), ra);
170c9274b6bSCho, Yu-Chen }
171db9aab57SRichard Henderson #endif
17240494314SRichard Henderson
17340494314SRichard Henderson return 0;
174c9274b6bSCho, Yu-Chen }
175c9274b6bSCho, Yu-Chen
access_prepare_nf(S390Access * access,CPUS390XState * env,bool nonfault,vaddr vaddr1,int size,MMUAccessType access_type,int mmu_idx,uintptr_t ra)176c9274b6bSCho, Yu-Chen static int access_prepare_nf(S390Access *access, CPUS390XState *env,
177c9274b6bSCho, Yu-Chen bool nonfault, vaddr vaddr1, int size,
178c9274b6bSCho, Yu-Chen MMUAccessType access_type,
179c9274b6bSCho, Yu-Chen int mmu_idx, uintptr_t ra)
180c9274b6bSCho, Yu-Chen {
181c9274b6bSCho, Yu-Chen int size1, size2, exc;
182c9274b6bSCho, Yu-Chen
183c9274b6bSCho, Yu-Chen assert(size > 0 && size <= 4096);
184c9274b6bSCho, Yu-Chen
185c9274b6bSCho, Yu-Chen size1 = MIN(size, -(vaddr1 | TARGET_PAGE_MASK)),
186c9274b6bSCho, Yu-Chen size2 = size - size1;
187c9274b6bSCho, Yu-Chen
188fb391b0bSRichard Henderson memset(access, 0, sizeof(*access));
189fb391b0bSRichard Henderson access->vaddr1 = vaddr1;
190fb391b0bSRichard Henderson access->size1 = size1;
191fb391b0bSRichard Henderson access->size2 = size2;
192fb391b0bSRichard Henderson access->mmu_idx = mmu_idx;
193fb391b0bSRichard Henderson
194c9274b6bSCho, Yu-Chen exc = s390_probe_access(env, vaddr1, size1, access_type, mmu_idx, nonfault,
195fb391b0bSRichard Henderson &access->haddr1, ra);
196fb391b0bSRichard Henderson if (unlikely(exc)) {
197c9274b6bSCho, Yu-Chen return exc;
198c9274b6bSCho, Yu-Chen }
199c9274b6bSCho, Yu-Chen if (unlikely(size2)) {
200c9274b6bSCho, Yu-Chen /* The access crosses page boundaries. */
201fb391b0bSRichard Henderson vaddr vaddr2 = wrap_address(env, vaddr1 + size1);
202fb391b0bSRichard Henderson
203fb391b0bSRichard Henderson access->vaddr2 = vaddr2;
204c9274b6bSCho, Yu-Chen exc = s390_probe_access(env, vaddr2, size2, access_type, mmu_idx,
205fb391b0bSRichard Henderson nonfault, &access->haddr2, ra);
206fb391b0bSRichard Henderson if (unlikely(exc)) {
207c9274b6bSCho, Yu-Chen return exc;
208c9274b6bSCho, Yu-Chen }
209c9274b6bSCho, Yu-Chen }
210c9274b6bSCho, Yu-Chen return 0;
211c9274b6bSCho, Yu-Chen }
212c9274b6bSCho, Yu-Chen
access_prepare(S390Access * ret,CPUS390XState * env,vaddr vaddr,int size,MMUAccessType access_type,int mmu_idx,uintptr_t ra)2137ba5da81SRichard Henderson static inline void access_prepare(S390Access *ret, CPUS390XState *env,
2147ba5da81SRichard Henderson vaddr vaddr, int size,
215c9274b6bSCho, Yu-Chen MMUAccessType access_type, int mmu_idx,
216c9274b6bSCho, Yu-Chen uintptr_t ra)
217c9274b6bSCho, Yu-Chen {
2187ba5da81SRichard Henderson int exc = access_prepare_nf(ret, env, false, vaddr, size,
219c9274b6bSCho, Yu-Chen access_type, mmu_idx, ra);
220c9274b6bSCho, Yu-Chen assert(!exc);
221c9274b6bSCho, Yu-Chen }
222c9274b6bSCho, Yu-Chen
223c9274b6bSCho, Yu-Chen /* Helper to handle memset on a single page. */
do_access_memset(CPUS390XState * env,vaddr vaddr,char * haddr,uint8_t byte,uint16_t size,int mmu_idx,uintptr_t ra)224c9274b6bSCho, Yu-Chen static void do_access_memset(CPUS390XState *env, vaddr vaddr, char *haddr,
225c9274b6bSCho, Yu-Chen uint8_t byte, uint16_t size, int mmu_idx,
226c9274b6bSCho, Yu-Chen uintptr_t ra)
227c9274b6bSCho, Yu-Chen {
228814e4659SRichard Henderson if (user_or_likely(haddr)) {
229c9274b6bSCho, Yu-Chen memset(haddr, byte, size);
230c9274b6bSCho, Yu-Chen } else {
23196b1416fSRichard Henderson MemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
23296b1416fSRichard Henderson for (int i = 0; i < size; i++) {
233bfe5b847SRichard Henderson cpu_stb_mmu(env, vaddr + i, byte, oi, ra);
234c9274b6bSCho, Yu-Chen }
235c9274b6bSCho, Yu-Chen }
236c9274b6bSCho, Yu-Chen }
237c9274b6bSCho, Yu-Chen
access_memset(CPUS390XState * env,S390Access * desta,uint8_t byte,uintptr_t ra)238c9274b6bSCho, Yu-Chen static void access_memset(CPUS390XState *env, S390Access *desta,
239c9274b6bSCho, Yu-Chen uint8_t byte, uintptr_t ra)
240c9274b6bSCho, Yu-Chen {
2412730df91SRichard Henderson set_helper_retaddr(ra);
242c9274b6bSCho, Yu-Chen do_access_memset(env, desta->vaddr1, desta->haddr1, byte, desta->size1,
243c9274b6bSCho, Yu-Chen desta->mmu_idx, ra);
2442730df91SRichard Henderson if (unlikely(desta->size2)) {
2452730df91SRichard Henderson do_access_memset(env, desta->vaddr2, desta->haddr2, byte,
2462730df91SRichard Henderson desta->size2, desta->mmu_idx, ra);
247c9274b6bSCho, Yu-Chen }
2482730df91SRichard Henderson clear_helper_retaddr();
249c9274b6bSCho, Yu-Chen }
250c9274b6bSCho, Yu-Chen
access_get_byte(CPUS390XState * env,S390Access * access,int offset,uintptr_t ra)251c9274b6bSCho, Yu-Chen static uint8_t access_get_byte(CPUS390XState *env, S390Access *access,
252c9274b6bSCho, Yu-Chen int offset, uintptr_t ra)
253c9274b6bSCho, Yu-Chen {
25461dee10fSRichard Henderson target_ulong vaddr = access->vaddr1;
25561dee10fSRichard Henderson void *haddr = access->haddr1;
25661dee10fSRichard Henderson
25761dee10fSRichard Henderson if (unlikely(offset >= access->size1)) {
25861dee10fSRichard Henderson offset -= access->size1;
25961dee10fSRichard Henderson vaddr = access->vaddr2;
26061dee10fSRichard Henderson haddr = access->haddr2;
261c9274b6bSCho, Yu-Chen }
262c9274b6bSCho, Yu-Chen
26361dee10fSRichard Henderson if (user_or_likely(haddr)) {
26461dee10fSRichard Henderson return ldub_p(haddr + offset);
26596b1416fSRichard Henderson } else {
26661dee10fSRichard Henderson MemOpIdx oi = make_memop_idx(MO_UB, access->mmu_idx);
26761dee10fSRichard Henderson return cpu_ldb_mmu(env, vaddr + offset, oi, ra);
26896b1416fSRichard Henderson }
269c9274b6bSCho, Yu-Chen }
270c9274b6bSCho, Yu-Chen
access_set_byte(CPUS390XState * env,S390Access * access,int offset,uint8_t byte,uintptr_t ra)271c9274b6bSCho, Yu-Chen static void access_set_byte(CPUS390XState *env, S390Access *access,
272c9274b6bSCho, Yu-Chen int offset, uint8_t byte, uintptr_t ra)
273c9274b6bSCho, Yu-Chen {
27461dee10fSRichard Henderson target_ulong vaddr = access->vaddr1;
27561dee10fSRichard Henderson void *haddr = access->haddr1;
27661dee10fSRichard Henderson
27761dee10fSRichard Henderson if (unlikely(offset >= access->size1)) {
27861dee10fSRichard Henderson offset -= access->size1;
27961dee10fSRichard Henderson vaddr = access->vaddr2;
28061dee10fSRichard Henderson haddr = access->haddr2;
28161dee10fSRichard Henderson }
28261dee10fSRichard Henderson
28361dee10fSRichard Henderson if (user_or_likely(haddr)) {
28461dee10fSRichard Henderson stb_p(haddr + offset, byte);
285c9274b6bSCho, Yu-Chen } else {
28661dee10fSRichard Henderson MemOpIdx oi = make_memop_idx(MO_UB, access->mmu_idx);
28761dee10fSRichard Henderson cpu_stb_mmu(env, vaddr + offset, byte, oi, ra);
288c9274b6bSCho, Yu-Chen }
289c9274b6bSCho, Yu-Chen }
290c9274b6bSCho, Yu-Chen
291c9274b6bSCho, Yu-Chen /*
292c9274b6bSCho, Yu-Chen * Move data with the same semantics as memmove() in case ranges don't overlap
293c9274b6bSCho, Yu-Chen * or src > dest. Undefined behavior on destructive overlaps.
294c9274b6bSCho, Yu-Chen */
access_memmove(CPUS390XState * env,S390Access * desta,S390Access * srca,uintptr_t ra)295c9274b6bSCho, Yu-Chen static void access_memmove(CPUS390XState *env, S390Access *desta,
296c9274b6bSCho, Yu-Chen S390Access *srca, uintptr_t ra)
297c9274b6bSCho, Yu-Chen {
298e73a0f40SRichard Henderson int len = desta->size1 + desta->size2;
299c9274b6bSCho, Yu-Chen
300e73a0f40SRichard Henderson assert(len == srca->size1 + srca->size2);
301c9274b6bSCho, Yu-Chen
302c9274b6bSCho, Yu-Chen /* Fallback to slow access in case we don't have access to all host pages */
303573b7783SRichard Henderson if (user_or_likely(desta->haddr1 &&
304573b7783SRichard Henderson srca->haddr1 &&
305573b7783SRichard Henderson (!desta->size2 || desta->haddr2) &&
306573b7783SRichard Henderson (!srca->size2 || srca->haddr2))) {
307573b7783SRichard Henderson int diff = desta->size1 - srca->size1;
308c9274b6bSCho, Yu-Chen
309e73a0f40SRichard Henderson if (likely(diff == 0)) {
310c9274b6bSCho, Yu-Chen memmove(desta->haddr1, srca->haddr1, srca->size1);
311c9274b6bSCho, Yu-Chen if (unlikely(srca->size2)) {
312c9274b6bSCho, Yu-Chen memmove(desta->haddr2, srca->haddr2, srca->size2);
313c9274b6bSCho, Yu-Chen }
314e73a0f40SRichard Henderson } else if (diff > 0) {
315c9274b6bSCho, Yu-Chen memmove(desta->haddr1, srca->haddr1, srca->size1);
316c9274b6bSCho, Yu-Chen memmove(desta->haddr1 + srca->size1, srca->haddr2, diff);
317c9274b6bSCho, Yu-Chen if (likely(desta->size2)) {
318c9274b6bSCho, Yu-Chen memmove(desta->haddr2, srca->haddr2 + diff, desta->size2);
319c9274b6bSCho, Yu-Chen }
320c9274b6bSCho, Yu-Chen } else {
321e73a0f40SRichard Henderson diff = -diff;
322c9274b6bSCho, Yu-Chen memmove(desta->haddr1, srca->haddr1, desta->size1);
323c9274b6bSCho, Yu-Chen memmove(desta->haddr2, srca->haddr1 + desta->size1, diff);
324c9274b6bSCho, Yu-Chen if (likely(srca->size2)) {
325c9274b6bSCho, Yu-Chen memmove(desta->haddr2 + diff, srca->haddr2, srca->size2);
326c9274b6bSCho, Yu-Chen }
327c9274b6bSCho, Yu-Chen }
328573b7783SRichard Henderson } else {
329573b7783SRichard Henderson for (int i = 0; i < len; i++) {
330573b7783SRichard Henderson uint8_t byte = access_get_byte(env, srca, i, ra);
331573b7783SRichard Henderson access_set_byte(env, desta, i, byte, ra);
332573b7783SRichard Henderson }
333573b7783SRichard Henderson }
334c9274b6bSCho, Yu-Chen }
335c9274b6bSCho, Yu-Chen
mmu_idx_from_as(uint8_t as)336c9274b6bSCho, Yu-Chen static int mmu_idx_from_as(uint8_t as)
337c9274b6bSCho, Yu-Chen {
338c9274b6bSCho, Yu-Chen switch (as) {
339c9274b6bSCho, Yu-Chen case AS_PRIMARY:
340c9274b6bSCho, Yu-Chen return MMU_PRIMARY_IDX;
341c9274b6bSCho, Yu-Chen case AS_SECONDARY:
342c9274b6bSCho, Yu-Chen return MMU_SECONDARY_IDX;
343c9274b6bSCho, Yu-Chen case AS_HOME:
344c9274b6bSCho, Yu-Chen return MMU_HOME_IDX;
345c9274b6bSCho, Yu-Chen default:
346c9274b6bSCho, Yu-Chen /* FIXME AS_ACCREG */
347c9274b6bSCho, Yu-Chen g_assert_not_reached();
348c9274b6bSCho, Yu-Chen }
349c9274b6bSCho, Yu-Chen }
350c9274b6bSCho, Yu-Chen
351c9274b6bSCho, Yu-Chen /* and on array */
do_helper_nc(CPUS390XState * env,uint32_t l,uint64_t dest,uint64_t src,uintptr_t ra)352c9274b6bSCho, Yu-Chen static uint32_t do_helper_nc(CPUS390XState *env, uint32_t l, uint64_t dest,
353c9274b6bSCho, Yu-Chen uint64_t src, uintptr_t ra)
354c9274b6bSCho, Yu-Chen {
35590b7022eSRichard Henderson const int mmu_idx = s390x_env_mmu_index(env, false);
356c9274b6bSCho, Yu-Chen S390Access srca1, srca2, desta;
357c9274b6bSCho, Yu-Chen uint32_t i;
358c9274b6bSCho, Yu-Chen uint8_t c = 0;
359c9274b6bSCho, Yu-Chen
360c9274b6bSCho, Yu-Chen HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
361c9274b6bSCho, Yu-Chen __func__, l, dest, src);
362c9274b6bSCho, Yu-Chen
363c9274b6bSCho, Yu-Chen /* NC always processes one more byte than specified - maximum is 256 */
364c9274b6bSCho, Yu-Chen l++;
365c9274b6bSCho, Yu-Chen
3667ba5da81SRichard Henderson access_prepare(&srca1, env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
3677ba5da81SRichard Henderson access_prepare(&srca2, env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
3687ba5da81SRichard Henderson access_prepare(&desta, env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
3692730df91SRichard Henderson set_helper_retaddr(ra);
3702730df91SRichard Henderson
371c9274b6bSCho, Yu-Chen for (i = 0; i < l; i++) {
372c9274b6bSCho, Yu-Chen const uint8_t x = access_get_byte(env, &srca1, i, ra) &
373c9274b6bSCho, Yu-Chen access_get_byte(env, &srca2, i, ra);
374c9274b6bSCho, Yu-Chen
375c9274b6bSCho, Yu-Chen c |= x;
376c9274b6bSCho, Yu-Chen access_set_byte(env, &desta, i, x, ra);
377c9274b6bSCho, Yu-Chen }
3782730df91SRichard Henderson
3792730df91SRichard Henderson clear_helper_retaddr();
380c9274b6bSCho, Yu-Chen return c != 0;
381c9274b6bSCho, Yu-Chen }
382c9274b6bSCho, Yu-Chen
HELPER(nc)383c9274b6bSCho, Yu-Chen uint32_t HELPER(nc)(CPUS390XState *env, uint32_t l, uint64_t dest,
384c9274b6bSCho, Yu-Chen uint64_t src)
385c9274b6bSCho, Yu-Chen {
386c9274b6bSCho, Yu-Chen return do_helper_nc(env, l, dest, src, GETPC());
387c9274b6bSCho, Yu-Chen }
388c9274b6bSCho, Yu-Chen
389c9274b6bSCho, Yu-Chen /* xor on array */
do_helper_xc(CPUS390XState * env,uint32_t l,uint64_t dest,uint64_t src,uintptr_t ra)390c9274b6bSCho, Yu-Chen static uint32_t do_helper_xc(CPUS390XState *env, uint32_t l, uint64_t dest,
391c9274b6bSCho, Yu-Chen uint64_t src, uintptr_t ra)
392c9274b6bSCho, Yu-Chen {
39390b7022eSRichard Henderson const int mmu_idx = s390x_env_mmu_index(env, false);
394c9274b6bSCho, Yu-Chen S390Access srca1, srca2, desta;
395c9274b6bSCho, Yu-Chen uint32_t i;
396c9274b6bSCho, Yu-Chen uint8_t c = 0;
397c9274b6bSCho, Yu-Chen
398c9274b6bSCho, Yu-Chen HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
399c9274b6bSCho, Yu-Chen __func__, l, dest, src);
400c9274b6bSCho, Yu-Chen
401c9274b6bSCho, Yu-Chen /* XC always processes one more byte than specified - maximum is 256 */
402c9274b6bSCho, Yu-Chen l++;
403c9274b6bSCho, Yu-Chen
4047ba5da81SRichard Henderson access_prepare(&srca1, env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
4057ba5da81SRichard Henderson access_prepare(&srca2, env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
4067ba5da81SRichard Henderson access_prepare(&desta, env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
407c9274b6bSCho, Yu-Chen
408c9274b6bSCho, Yu-Chen /* xor with itself is the same as memset(0) */
409c9274b6bSCho, Yu-Chen if (src == dest) {
410c9274b6bSCho, Yu-Chen access_memset(env, &desta, 0, ra);
411c9274b6bSCho, Yu-Chen return 0;
412c9274b6bSCho, Yu-Chen }
413c9274b6bSCho, Yu-Chen
4142730df91SRichard Henderson set_helper_retaddr(ra);
415c9274b6bSCho, Yu-Chen for (i = 0; i < l; i++) {
416c9274b6bSCho, Yu-Chen const uint8_t x = access_get_byte(env, &srca1, i, ra) ^
417c9274b6bSCho, Yu-Chen access_get_byte(env, &srca2, i, ra);
418c9274b6bSCho, Yu-Chen
419c9274b6bSCho, Yu-Chen c |= x;
420c9274b6bSCho, Yu-Chen access_set_byte(env, &desta, i, x, ra);
421c9274b6bSCho, Yu-Chen }
4222730df91SRichard Henderson clear_helper_retaddr();
423c9274b6bSCho, Yu-Chen return c != 0;
424c9274b6bSCho, Yu-Chen }
425c9274b6bSCho, Yu-Chen
HELPER(xc)426c9274b6bSCho, Yu-Chen uint32_t HELPER(xc)(CPUS390XState *env, uint32_t l, uint64_t dest,
427c9274b6bSCho, Yu-Chen uint64_t src)
428c9274b6bSCho, Yu-Chen {
429c9274b6bSCho, Yu-Chen return do_helper_xc(env, l, dest, src, GETPC());
430c9274b6bSCho, Yu-Chen }
431c9274b6bSCho, Yu-Chen
432c9274b6bSCho, Yu-Chen /* or on array */
do_helper_oc(CPUS390XState * env,uint32_t l,uint64_t dest,uint64_t src,uintptr_t ra)433c9274b6bSCho, Yu-Chen static uint32_t do_helper_oc(CPUS390XState *env, uint32_t l, uint64_t dest,
434c9274b6bSCho, Yu-Chen uint64_t src, uintptr_t ra)
435c9274b6bSCho, Yu-Chen {
43690b7022eSRichard Henderson const int mmu_idx = s390x_env_mmu_index(env, false);
437c9274b6bSCho, Yu-Chen S390Access srca1, srca2, desta;
438c9274b6bSCho, Yu-Chen uint32_t i;
439c9274b6bSCho, Yu-Chen uint8_t c = 0;
440c9274b6bSCho, Yu-Chen
441c9274b6bSCho, Yu-Chen HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
442c9274b6bSCho, Yu-Chen __func__, l, dest, src);
443c9274b6bSCho, Yu-Chen
444c9274b6bSCho, Yu-Chen /* OC always processes one more byte than specified - maximum is 256 */
445c9274b6bSCho, Yu-Chen l++;
446c9274b6bSCho, Yu-Chen
4477ba5da81SRichard Henderson access_prepare(&srca1, env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
4487ba5da81SRichard Henderson access_prepare(&srca2, env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
4497ba5da81SRichard Henderson access_prepare(&desta, env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
4502730df91SRichard Henderson set_helper_retaddr(ra);
4512730df91SRichard Henderson
452c9274b6bSCho, Yu-Chen for (i = 0; i < l; i++) {
453c9274b6bSCho, Yu-Chen const uint8_t x = access_get_byte(env, &srca1, i, ra) |
454c9274b6bSCho, Yu-Chen access_get_byte(env, &srca2, i, ra);
455c9274b6bSCho, Yu-Chen
456c9274b6bSCho, Yu-Chen c |= x;
457c9274b6bSCho, Yu-Chen access_set_byte(env, &desta, i, x, ra);
458c9274b6bSCho, Yu-Chen }
4592730df91SRichard Henderson
4602730df91SRichard Henderson clear_helper_retaddr();
461c9274b6bSCho, Yu-Chen return c != 0;
462c9274b6bSCho, Yu-Chen }
463c9274b6bSCho, Yu-Chen
HELPER(oc)464c9274b6bSCho, Yu-Chen uint32_t HELPER(oc)(CPUS390XState *env, uint32_t l, uint64_t dest,
465c9274b6bSCho, Yu-Chen uint64_t src)
466c9274b6bSCho, Yu-Chen {
467c9274b6bSCho, Yu-Chen return do_helper_oc(env, l, dest, src, GETPC());
468c9274b6bSCho, Yu-Chen }
469c9274b6bSCho, Yu-Chen
470c9274b6bSCho, Yu-Chen /* memmove */
do_helper_mvc(CPUS390XState * env,uint32_t l,uint64_t dest,uint64_t src,uintptr_t ra)471c9274b6bSCho, Yu-Chen static uint32_t do_helper_mvc(CPUS390XState *env, uint32_t l, uint64_t dest,
472c9274b6bSCho, Yu-Chen uint64_t src, uintptr_t ra)
473c9274b6bSCho, Yu-Chen {
47490b7022eSRichard Henderson const int mmu_idx = s390x_env_mmu_index(env, false);
475c9274b6bSCho, Yu-Chen S390Access srca, desta;
476c9274b6bSCho, Yu-Chen uint32_t i;
477c9274b6bSCho, Yu-Chen
478c9274b6bSCho, Yu-Chen HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
479c9274b6bSCho, Yu-Chen __func__, l, dest, src);
480c9274b6bSCho, Yu-Chen
481c9274b6bSCho, Yu-Chen /* MVC always copies one more byte than specified - maximum is 256 */
482c9274b6bSCho, Yu-Chen l++;
483c9274b6bSCho, Yu-Chen
4847ba5da81SRichard Henderson access_prepare(&srca, env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
4857ba5da81SRichard Henderson access_prepare(&desta, env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
486c9274b6bSCho, Yu-Chen
487c9274b6bSCho, Yu-Chen /*
488c9274b6bSCho, Yu-Chen * "When the operands overlap, the result is obtained as if the operands
489c9274b6bSCho, Yu-Chen * were processed one byte at a time". Only non-destructive overlaps
490c9274b6bSCho, Yu-Chen * behave like memmove().
491c9274b6bSCho, Yu-Chen */
492c9274b6bSCho, Yu-Chen if (dest == src + 1) {
493c9274b6bSCho, Yu-Chen access_memset(env, &desta, access_get_byte(env, &srca, 0, ra), ra);
494c9274b6bSCho, Yu-Chen } else if (!is_destructive_overlap(env, dest, src, l)) {
495c9274b6bSCho, Yu-Chen access_memmove(env, &desta, &srca, ra);
496c9274b6bSCho, Yu-Chen } else {
4972730df91SRichard Henderson set_helper_retaddr(ra);
498c9274b6bSCho, Yu-Chen for (i = 0; i < l; i++) {
499c9274b6bSCho, Yu-Chen uint8_t byte = access_get_byte(env, &srca, i, ra);
500c9274b6bSCho, Yu-Chen
501c9274b6bSCho, Yu-Chen access_set_byte(env, &desta, i, byte, ra);
502c9274b6bSCho, Yu-Chen }
5032730df91SRichard Henderson clear_helper_retaddr();
504c9274b6bSCho, Yu-Chen }
505c9274b6bSCho, Yu-Chen
506c9274b6bSCho, Yu-Chen return env->cc_op;
507c9274b6bSCho, Yu-Chen }
508c9274b6bSCho, Yu-Chen
HELPER(mvc)509c9274b6bSCho, Yu-Chen void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
510c9274b6bSCho, Yu-Chen {
511c9274b6bSCho, Yu-Chen do_helper_mvc(env, l, dest, src, GETPC());
512c9274b6bSCho, Yu-Chen }
513c9274b6bSCho, Yu-Chen
514ea0a1053SDavid Miller /* move right to left */
HELPER(mvcrl)515ea0a1053SDavid Miller void HELPER(mvcrl)(CPUS390XState *env, uint64_t l, uint64_t dest, uint64_t src)
516ea0a1053SDavid Miller {
51790b7022eSRichard Henderson const int mmu_idx = s390x_env_mmu_index(env, false);
518ea0a1053SDavid Miller const uint64_t ra = GETPC();
519ea0a1053SDavid Miller S390Access srca, desta;
520ea0a1053SDavid Miller int32_t i;
521ea0a1053SDavid Miller
522ea0a1053SDavid Miller /* MVCRL always copies one more byte than specified - maximum is 256 */
52392a57534SIlya Leoshkevich l &= 0xff;
524ea0a1053SDavid Miller l++;
525ea0a1053SDavid Miller
5267ba5da81SRichard Henderson access_prepare(&srca, env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
5277ba5da81SRichard Henderson access_prepare(&desta, env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
528ea0a1053SDavid Miller
5292730df91SRichard Henderson set_helper_retaddr(ra);
530ea0a1053SDavid Miller for (i = l - 1; i >= 0; i--) {
531ea0a1053SDavid Miller uint8_t byte = access_get_byte(env, &srca, i, ra);
532ea0a1053SDavid Miller access_set_byte(env, &desta, i, byte, ra);
533ea0a1053SDavid Miller }
5342730df91SRichard Henderson clear_helper_retaddr();
535ea0a1053SDavid Miller }
536ea0a1053SDavid Miller
537c9274b6bSCho, Yu-Chen /* move inverse */
HELPER(mvcin)538c9274b6bSCho, Yu-Chen void HELPER(mvcin)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
539c9274b6bSCho, Yu-Chen {
54090b7022eSRichard Henderson const int mmu_idx = s390x_env_mmu_index(env, false);
541c9274b6bSCho, Yu-Chen S390Access srca, desta;
542c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
543c9274b6bSCho, Yu-Chen int i;
544c9274b6bSCho, Yu-Chen
545c9274b6bSCho, Yu-Chen /* MVCIN always copies one more byte than specified - maximum is 256 */
546c9274b6bSCho, Yu-Chen l++;
547c9274b6bSCho, Yu-Chen
548c9274b6bSCho, Yu-Chen src = wrap_address(env, src - l + 1);
5497ba5da81SRichard Henderson access_prepare(&srca, env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
5507ba5da81SRichard Henderson access_prepare(&desta, env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
5512730df91SRichard Henderson
5522730df91SRichard Henderson set_helper_retaddr(ra);
553c9274b6bSCho, Yu-Chen for (i = 0; i < l; i++) {
554c9274b6bSCho, Yu-Chen const uint8_t x = access_get_byte(env, &srca, l - i - 1, ra);
555c9274b6bSCho, Yu-Chen access_set_byte(env, &desta, i, x, ra);
556c9274b6bSCho, Yu-Chen }
5572730df91SRichard Henderson clear_helper_retaddr();
558c9274b6bSCho, Yu-Chen }
559c9274b6bSCho, Yu-Chen
560c9274b6bSCho, Yu-Chen /* move numerics */
HELPER(mvn)561c9274b6bSCho, Yu-Chen void HELPER(mvn)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
562c9274b6bSCho, Yu-Chen {
56390b7022eSRichard Henderson const int mmu_idx = s390x_env_mmu_index(env, false);
564c9274b6bSCho, Yu-Chen S390Access srca1, srca2, desta;
565c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
566c9274b6bSCho, Yu-Chen int i;
567c9274b6bSCho, Yu-Chen
568c9274b6bSCho, Yu-Chen /* MVN always copies one more byte than specified - maximum is 256 */
569c9274b6bSCho, Yu-Chen l++;
570c9274b6bSCho, Yu-Chen
5717ba5da81SRichard Henderson access_prepare(&srca1, env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
5727ba5da81SRichard Henderson access_prepare(&srca2, env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
5737ba5da81SRichard Henderson access_prepare(&desta, env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
5742730df91SRichard Henderson
5752730df91SRichard Henderson set_helper_retaddr(ra);
576c9274b6bSCho, Yu-Chen for (i = 0; i < l; i++) {
577c9274b6bSCho, Yu-Chen const uint8_t x = (access_get_byte(env, &srca1, i, ra) & 0x0f) |
578c9274b6bSCho, Yu-Chen (access_get_byte(env, &srca2, i, ra) & 0xf0);
579c9274b6bSCho, Yu-Chen
580c9274b6bSCho, Yu-Chen access_set_byte(env, &desta, i, x, ra);
581c9274b6bSCho, Yu-Chen }
5822730df91SRichard Henderson clear_helper_retaddr();
583c9274b6bSCho, Yu-Chen }
584c9274b6bSCho, Yu-Chen
585c9274b6bSCho, Yu-Chen /* move with offset */
HELPER(mvo)586c9274b6bSCho, Yu-Chen void HELPER(mvo)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
587c9274b6bSCho, Yu-Chen {
58890b7022eSRichard Henderson const int mmu_idx = s390x_env_mmu_index(env, false);
589c9274b6bSCho, Yu-Chen /* MVO always processes one more byte than specified - maximum is 16 */
590c9274b6bSCho, Yu-Chen const int len_dest = (l >> 4) + 1;
591c9274b6bSCho, Yu-Chen const int len_src = (l & 0xf) + 1;
592c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
593c9274b6bSCho, Yu-Chen uint8_t byte_dest, byte_src;
594c9274b6bSCho, Yu-Chen S390Access srca, desta;
595c9274b6bSCho, Yu-Chen int i, j;
596c9274b6bSCho, Yu-Chen
5977ba5da81SRichard Henderson access_prepare(&srca, env, src, len_src, MMU_DATA_LOAD, mmu_idx, ra);
5987ba5da81SRichard Henderson access_prepare(&desta, env, dest, len_dest, MMU_DATA_STORE, mmu_idx, ra);
599c9274b6bSCho, Yu-Chen
600c9274b6bSCho, Yu-Chen /* Handle rightmost byte */
601c9274b6bSCho, Yu-Chen byte_dest = cpu_ldub_data_ra(env, dest + len_dest - 1, ra);
6022730df91SRichard Henderson
6032730df91SRichard Henderson set_helper_retaddr(ra);
604c9274b6bSCho, Yu-Chen byte_src = access_get_byte(env, &srca, len_src - 1, ra);
605c9274b6bSCho, Yu-Chen byte_dest = (byte_dest & 0x0f) | (byte_src << 4);
606c9274b6bSCho, Yu-Chen access_set_byte(env, &desta, len_dest - 1, byte_dest, ra);
607c9274b6bSCho, Yu-Chen
608c9274b6bSCho, Yu-Chen /* Process remaining bytes from right to left */
609c9274b6bSCho, Yu-Chen for (i = len_dest - 2, j = len_src - 2; i >= 0; i--, j--) {
610c9274b6bSCho, Yu-Chen byte_dest = byte_src >> 4;
611c9274b6bSCho, Yu-Chen if (j >= 0) {
612c9274b6bSCho, Yu-Chen byte_src = access_get_byte(env, &srca, j, ra);
613c9274b6bSCho, Yu-Chen } else {
614c9274b6bSCho, Yu-Chen byte_src = 0;
615c9274b6bSCho, Yu-Chen }
616c9274b6bSCho, Yu-Chen byte_dest |= byte_src << 4;
617c9274b6bSCho, Yu-Chen access_set_byte(env, &desta, i, byte_dest, ra);
618c9274b6bSCho, Yu-Chen }
6192730df91SRichard Henderson clear_helper_retaddr();
620c9274b6bSCho, Yu-Chen }
621c9274b6bSCho, Yu-Chen
622c9274b6bSCho, Yu-Chen /* move zones */
HELPER(mvz)623c9274b6bSCho, Yu-Chen void HELPER(mvz)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
624c9274b6bSCho, Yu-Chen {
62590b7022eSRichard Henderson const int mmu_idx = s390x_env_mmu_index(env, false);
626c9274b6bSCho, Yu-Chen S390Access srca1, srca2, desta;
627c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
628c9274b6bSCho, Yu-Chen int i;
629c9274b6bSCho, Yu-Chen
630c9274b6bSCho, Yu-Chen /* MVZ always copies one more byte than specified - maximum is 256 */
631c9274b6bSCho, Yu-Chen l++;
632c9274b6bSCho, Yu-Chen
6337ba5da81SRichard Henderson access_prepare(&srca1, env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
6347ba5da81SRichard Henderson access_prepare(&srca2, env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
6357ba5da81SRichard Henderson access_prepare(&desta, env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
6362730df91SRichard Henderson
6372730df91SRichard Henderson set_helper_retaddr(ra);
638c9274b6bSCho, Yu-Chen for (i = 0; i < l; i++) {
639c9274b6bSCho, Yu-Chen const uint8_t x = (access_get_byte(env, &srca1, i, ra) & 0xf0) |
640c9274b6bSCho, Yu-Chen (access_get_byte(env, &srca2, i, ra) & 0x0f);
641c9274b6bSCho, Yu-Chen
642c9274b6bSCho, Yu-Chen access_set_byte(env, &desta, i, x, ra);
643c9274b6bSCho, Yu-Chen }
6442730df91SRichard Henderson clear_helper_retaddr();
645c9274b6bSCho, Yu-Chen }
646c9274b6bSCho, Yu-Chen
647c9274b6bSCho, Yu-Chen /* compare unsigned byte arrays */
do_helper_clc(CPUS390XState * env,uint32_t l,uint64_t s1,uint64_t s2,uintptr_t ra)648c9274b6bSCho, Yu-Chen static uint32_t do_helper_clc(CPUS390XState *env, uint32_t l, uint64_t s1,
649c9274b6bSCho, Yu-Chen uint64_t s2, uintptr_t ra)
650c9274b6bSCho, Yu-Chen {
651c9274b6bSCho, Yu-Chen uint32_t i;
652c9274b6bSCho, Yu-Chen uint32_t cc = 0;
653c9274b6bSCho, Yu-Chen
654c9274b6bSCho, Yu-Chen HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n",
655c9274b6bSCho, Yu-Chen __func__, l, s1, s2);
656c9274b6bSCho, Yu-Chen
657c9274b6bSCho, Yu-Chen for (i = 0; i <= l; i++) {
658c9274b6bSCho, Yu-Chen uint8_t x = cpu_ldub_data_ra(env, s1 + i, ra);
659c9274b6bSCho, Yu-Chen uint8_t y = cpu_ldub_data_ra(env, s2 + i, ra);
660c9274b6bSCho, Yu-Chen HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y);
661c9274b6bSCho, Yu-Chen if (x < y) {
662c9274b6bSCho, Yu-Chen cc = 1;
663c9274b6bSCho, Yu-Chen break;
664c9274b6bSCho, Yu-Chen } else if (x > y) {
665c9274b6bSCho, Yu-Chen cc = 2;
666c9274b6bSCho, Yu-Chen break;
667c9274b6bSCho, Yu-Chen }
668c9274b6bSCho, Yu-Chen }
669c9274b6bSCho, Yu-Chen
670c9274b6bSCho, Yu-Chen HELPER_LOG("\n");
671c9274b6bSCho, Yu-Chen return cc;
672c9274b6bSCho, Yu-Chen }
673c9274b6bSCho, Yu-Chen
HELPER(clc)674c9274b6bSCho, Yu-Chen uint32_t HELPER(clc)(CPUS390XState *env, uint32_t l, uint64_t s1, uint64_t s2)
675c9274b6bSCho, Yu-Chen {
676c9274b6bSCho, Yu-Chen return do_helper_clc(env, l, s1, s2, GETPC());
677c9274b6bSCho, Yu-Chen }
678c9274b6bSCho, Yu-Chen
679c9274b6bSCho, Yu-Chen /* compare logical under mask */
HELPER(clm)680c9274b6bSCho, Yu-Chen uint32_t HELPER(clm)(CPUS390XState *env, uint32_t r1, uint32_t mask,
681c9274b6bSCho, Yu-Chen uint64_t addr)
682c9274b6bSCho, Yu-Chen {
683c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
684c9274b6bSCho, Yu-Chen uint32_t cc = 0;
685c9274b6bSCho, Yu-Chen
686c9274b6bSCho, Yu-Chen HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1,
687c9274b6bSCho, Yu-Chen mask, addr);
688c9274b6bSCho, Yu-Chen
6894b6e4c0bSIlya Leoshkevich if (!mask) {
6904b6e4c0bSIlya Leoshkevich /* Recognize access exceptions for the first byte */
69190b7022eSRichard Henderson probe_read(env, addr, 1, s390x_env_mmu_index(env, false), ra);
6924b6e4c0bSIlya Leoshkevich }
6934b6e4c0bSIlya Leoshkevich
694c9274b6bSCho, Yu-Chen while (mask) {
695c9274b6bSCho, Yu-Chen if (mask & 8) {
696c9274b6bSCho, Yu-Chen uint8_t d = cpu_ldub_data_ra(env, addr, ra);
697c9274b6bSCho, Yu-Chen uint8_t r = extract32(r1, 24, 8);
698c9274b6bSCho, Yu-Chen HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d,
699c9274b6bSCho, Yu-Chen addr);
700c9274b6bSCho, Yu-Chen if (r < d) {
701c9274b6bSCho, Yu-Chen cc = 1;
702c9274b6bSCho, Yu-Chen break;
703c9274b6bSCho, Yu-Chen } else if (r > d) {
704c9274b6bSCho, Yu-Chen cc = 2;
705c9274b6bSCho, Yu-Chen break;
706c9274b6bSCho, Yu-Chen }
707c9274b6bSCho, Yu-Chen addr++;
708c9274b6bSCho, Yu-Chen }
709c9274b6bSCho, Yu-Chen mask = (mask << 1) & 0xf;
710c9274b6bSCho, Yu-Chen r1 <<= 8;
711c9274b6bSCho, Yu-Chen }
712c9274b6bSCho, Yu-Chen
713c9274b6bSCho, Yu-Chen HELPER_LOG("\n");
714c9274b6bSCho, Yu-Chen return cc;
715c9274b6bSCho, Yu-Chen }
716c9274b6bSCho, Yu-Chen
get_address(CPUS390XState * env,int reg)717c9274b6bSCho, Yu-Chen static inline uint64_t get_address(CPUS390XState *env, int reg)
718c9274b6bSCho, Yu-Chen {
719c9274b6bSCho, Yu-Chen return wrap_address(env, env->regs[reg]);
720c9274b6bSCho, Yu-Chen }
721c9274b6bSCho, Yu-Chen
722c9274b6bSCho, Yu-Chen /*
723c9274b6bSCho, Yu-Chen * Store the address to the given register, zeroing out unused leftmost
724c9274b6bSCho, Yu-Chen * bits in bit positions 32-63 (24-bit and 31-bit mode only).
725c9274b6bSCho, Yu-Chen */
set_address_zero(CPUS390XState * env,int reg,uint64_t address)726c9274b6bSCho, Yu-Chen static inline void set_address_zero(CPUS390XState *env, int reg,
727c9274b6bSCho, Yu-Chen uint64_t address)
728c9274b6bSCho, Yu-Chen {
729c9274b6bSCho, Yu-Chen if (env->psw.mask & PSW_MASK_64) {
730c9274b6bSCho, Yu-Chen env->regs[reg] = address;
731c9274b6bSCho, Yu-Chen } else {
732c9274b6bSCho, Yu-Chen if (!(env->psw.mask & PSW_MASK_32)) {
733c9274b6bSCho, Yu-Chen address &= 0x00ffffff;
734c9274b6bSCho, Yu-Chen } else {
735c9274b6bSCho, Yu-Chen address &= 0x7fffffff;
736c9274b6bSCho, Yu-Chen }
737c9274b6bSCho, Yu-Chen env->regs[reg] = deposit64(env->regs[reg], 0, 32, address);
738c9274b6bSCho, Yu-Chen }
739c9274b6bSCho, Yu-Chen }
740c9274b6bSCho, Yu-Chen
set_address(CPUS390XState * env,int reg,uint64_t address)741c9274b6bSCho, Yu-Chen static inline void set_address(CPUS390XState *env, int reg, uint64_t address)
742c9274b6bSCho, Yu-Chen {
743c9274b6bSCho, Yu-Chen if (env->psw.mask & PSW_MASK_64) {
744c9274b6bSCho, Yu-Chen /* 64-Bit mode */
745c9274b6bSCho, Yu-Chen env->regs[reg] = address;
746c9274b6bSCho, Yu-Chen } else {
747c9274b6bSCho, Yu-Chen if (!(env->psw.mask & PSW_MASK_32)) {
748c9274b6bSCho, Yu-Chen /* 24-Bit mode. According to the PoO it is implementation
749c9274b6bSCho, Yu-Chen dependent if bits 32-39 remain unchanged or are set to
750c9274b6bSCho, Yu-Chen zeros. Choose the former so that the function can also be
751c9274b6bSCho, Yu-Chen used for TRT. */
752c9274b6bSCho, Yu-Chen env->regs[reg] = deposit64(env->regs[reg], 0, 24, address);
753c9274b6bSCho, Yu-Chen } else {
754c9274b6bSCho, Yu-Chen /* 31-Bit mode. According to the PoO it is implementation
755c9274b6bSCho, Yu-Chen dependent if bit 32 remains unchanged or is set to zero.
756c9274b6bSCho, Yu-Chen Choose the latter so that the function can also be used for
757c9274b6bSCho, Yu-Chen TRT. */
758c9274b6bSCho, Yu-Chen address &= 0x7fffffff;
759c9274b6bSCho, Yu-Chen env->regs[reg] = deposit64(env->regs[reg], 0, 32, address);
760c9274b6bSCho, Yu-Chen }
761c9274b6bSCho, Yu-Chen }
762c9274b6bSCho, Yu-Chen }
763c9274b6bSCho, Yu-Chen
wrap_length32(CPUS390XState * env,uint64_t length)764c9274b6bSCho, Yu-Chen static inline uint64_t wrap_length32(CPUS390XState *env, uint64_t length)
765c9274b6bSCho, Yu-Chen {
766c9274b6bSCho, Yu-Chen if (!(env->psw.mask & PSW_MASK_64)) {
767c9274b6bSCho, Yu-Chen return (uint32_t)length;
768c9274b6bSCho, Yu-Chen }
769c9274b6bSCho, Yu-Chen return length;
770c9274b6bSCho, Yu-Chen }
771c9274b6bSCho, Yu-Chen
wrap_length31(CPUS390XState * env,uint64_t length)772c9274b6bSCho, Yu-Chen static inline uint64_t wrap_length31(CPUS390XState *env, uint64_t length)
773c9274b6bSCho, Yu-Chen {
774c9274b6bSCho, Yu-Chen if (!(env->psw.mask & PSW_MASK_64)) {
775c9274b6bSCho, Yu-Chen /* 24-Bit and 31-Bit mode */
776c9274b6bSCho, Yu-Chen length &= 0x7fffffff;
777c9274b6bSCho, Yu-Chen }
778c9274b6bSCho, Yu-Chen return length;
779c9274b6bSCho, Yu-Chen }
780c9274b6bSCho, Yu-Chen
get_length(CPUS390XState * env,int reg)781c9274b6bSCho, Yu-Chen static inline uint64_t get_length(CPUS390XState *env, int reg)
782c9274b6bSCho, Yu-Chen {
783c9274b6bSCho, Yu-Chen return wrap_length31(env, env->regs[reg]);
784c9274b6bSCho, Yu-Chen }
785c9274b6bSCho, Yu-Chen
set_length(CPUS390XState * env,int reg,uint64_t length)786c9274b6bSCho, Yu-Chen static inline void set_length(CPUS390XState *env, int reg, uint64_t length)
787c9274b6bSCho, Yu-Chen {
788c9274b6bSCho, Yu-Chen if (env->psw.mask & PSW_MASK_64) {
789c9274b6bSCho, Yu-Chen /* 64-Bit mode */
790c9274b6bSCho, Yu-Chen env->regs[reg] = length;
791c9274b6bSCho, Yu-Chen } else {
792c9274b6bSCho, Yu-Chen /* 24-Bit and 31-Bit mode */
793c9274b6bSCho, Yu-Chen env->regs[reg] = deposit64(env->regs[reg], 0, 32, length);
794c9274b6bSCho, Yu-Chen }
795c9274b6bSCho, Yu-Chen }
796c9274b6bSCho, Yu-Chen
797c9274b6bSCho, Yu-Chen /* search string (c is byte to search, r2 is string, r1 end of string) */
HELPER(srst)798c9274b6bSCho, Yu-Chen void HELPER(srst)(CPUS390XState *env, uint32_t r1, uint32_t r2)
799c9274b6bSCho, Yu-Chen {
800c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
801c9274b6bSCho, Yu-Chen uint64_t end, str;
802c9274b6bSCho, Yu-Chen uint32_t len;
803c9274b6bSCho, Yu-Chen uint8_t v, c = env->regs[0];
804c9274b6bSCho, Yu-Chen
805c9274b6bSCho, Yu-Chen /* Bits 32-55 must contain all 0. */
806c9274b6bSCho, Yu-Chen if (env->regs[0] & 0xffffff00u) {
807c9274b6bSCho, Yu-Chen tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
808c9274b6bSCho, Yu-Chen }
809c9274b6bSCho, Yu-Chen
810c9274b6bSCho, Yu-Chen str = get_address(env, r2);
811c9274b6bSCho, Yu-Chen end = get_address(env, r1);
812c9274b6bSCho, Yu-Chen
813c9274b6bSCho, Yu-Chen /* Lest we fail to service interrupts in a timely manner, limit the
814c9274b6bSCho, Yu-Chen amount of work we're willing to do. For now, let's cap at 8k. */
815c9274b6bSCho, Yu-Chen for (len = 0; len < 0x2000; ++len) {
816c9274b6bSCho, Yu-Chen if (str + len == end) {
817c9274b6bSCho, Yu-Chen /* Character not found. R1 & R2 are unmodified. */
818c9274b6bSCho, Yu-Chen env->cc_op = 2;
819c9274b6bSCho, Yu-Chen return;
820c9274b6bSCho, Yu-Chen }
821c9274b6bSCho, Yu-Chen v = cpu_ldub_data_ra(env, str + len, ra);
822c9274b6bSCho, Yu-Chen if (v == c) {
823c9274b6bSCho, Yu-Chen /* Character found. Set R1 to the location; R2 is unmodified. */
824c9274b6bSCho, Yu-Chen env->cc_op = 1;
825c9274b6bSCho, Yu-Chen set_address(env, r1, str + len);
826c9274b6bSCho, Yu-Chen return;
827c9274b6bSCho, Yu-Chen }
828c9274b6bSCho, Yu-Chen }
829c9274b6bSCho, Yu-Chen
830c9274b6bSCho, Yu-Chen /* CPU-determined bytes processed. Advance R2 to next byte to process. */
831c9274b6bSCho, Yu-Chen env->cc_op = 3;
832c9274b6bSCho, Yu-Chen set_address(env, r2, str + len);
833c9274b6bSCho, Yu-Chen }
834c9274b6bSCho, Yu-Chen
HELPER(srstu)835c9274b6bSCho, Yu-Chen void HELPER(srstu)(CPUS390XState *env, uint32_t r1, uint32_t r2)
836c9274b6bSCho, Yu-Chen {
837c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
838c9274b6bSCho, Yu-Chen uint32_t len;
839c9274b6bSCho, Yu-Chen uint16_t v, c = env->regs[0];
840c9274b6bSCho, Yu-Chen uint64_t end, str, adj_end;
841c9274b6bSCho, Yu-Chen
842c9274b6bSCho, Yu-Chen /* Bits 32-47 of R0 must be zero. */
843c9274b6bSCho, Yu-Chen if (env->regs[0] & 0xffff0000u) {
844c9274b6bSCho, Yu-Chen tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
845c9274b6bSCho, Yu-Chen }
846c9274b6bSCho, Yu-Chen
847c9274b6bSCho, Yu-Chen str = get_address(env, r2);
848c9274b6bSCho, Yu-Chen end = get_address(env, r1);
849c9274b6bSCho, Yu-Chen
850c9274b6bSCho, Yu-Chen /* If the LSB of the two addresses differ, use one extra byte. */
851c9274b6bSCho, Yu-Chen adj_end = end + ((str ^ end) & 1);
852c9274b6bSCho, Yu-Chen
853c9274b6bSCho, Yu-Chen /* Lest we fail to service interrupts in a timely manner, limit the
854c9274b6bSCho, Yu-Chen amount of work we're willing to do. For now, let's cap at 8k. */
855c9274b6bSCho, Yu-Chen for (len = 0; len < 0x2000; len += 2) {
856c9274b6bSCho, Yu-Chen if (str + len == adj_end) {
857c9274b6bSCho, Yu-Chen /* End of input found. */
858c9274b6bSCho, Yu-Chen env->cc_op = 2;
859c9274b6bSCho, Yu-Chen return;
860c9274b6bSCho, Yu-Chen }
861c9274b6bSCho, Yu-Chen v = cpu_lduw_data_ra(env, str + len, ra);
862c9274b6bSCho, Yu-Chen if (v == c) {
863c9274b6bSCho, Yu-Chen /* Character found. Set R1 to the location; R2 is unmodified. */
864c9274b6bSCho, Yu-Chen env->cc_op = 1;
865c9274b6bSCho, Yu-Chen set_address(env, r1, str + len);
866c9274b6bSCho, Yu-Chen return;
867c9274b6bSCho, Yu-Chen }
868c9274b6bSCho, Yu-Chen }
869c9274b6bSCho, Yu-Chen
870c9274b6bSCho, Yu-Chen /* CPU-determined bytes processed. Advance R2 to next byte to process. */
871c9274b6bSCho, Yu-Chen env->cc_op = 3;
872c9274b6bSCho, Yu-Chen set_address(env, r2, str + len);
873c9274b6bSCho, Yu-Chen }
874c9274b6bSCho, Yu-Chen
875c9274b6bSCho, Yu-Chen /* unsigned string compare (c is string terminator) */
HELPER(clst)876b71dd2a5SRichard Henderson Int128 HELPER(clst)(CPUS390XState *env, uint64_t c, uint64_t s1, uint64_t s2)
877c9274b6bSCho, Yu-Chen {
878c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
879c9274b6bSCho, Yu-Chen uint32_t len;
880c9274b6bSCho, Yu-Chen
881c9274b6bSCho, Yu-Chen c = c & 0xff;
882c9274b6bSCho, Yu-Chen s1 = wrap_address(env, s1);
883c9274b6bSCho, Yu-Chen s2 = wrap_address(env, s2);
884c9274b6bSCho, Yu-Chen
885c9274b6bSCho, Yu-Chen /* Lest we fail to service interrupts in a timely manner, limit the
886c9274b6bSCho, Yu-Chen amount of work we're willing to do. For now, let's cap at 8k. */
887c9274b6bSCho, Yu-Chen for (len = 0; len < 0x2000; ++len) {
888c9274b6bSCho, Yu-Chen uint8_t v1 = cpu_ldub_data_ra(env, s1 + len, ra);
889c9274b6bSCho, Yu-Chen uint8_t v2 = cpu_ldub_data_ra(env, s2 + len, ra);
890c9274b6bSCho, Yu-Chen if (v1 == v2) {
891c9274b6bSCho, Yu-Chen if (v1 == c) {
892c9274b6bSCho, Yu-Chen /* Equal. CC=0, and don't advance the registers. */
893c9274b6bSCho, Yu-Chen env->cc_op = 0;
894b71dd2a5SRichard Henderson return int128_make128(s2, s1);
895c9274b6bSCho, Yu-Chen }
896c9274b6bSCho, Yu-Chen } else {
897c9274b6bSCho, Yu-Chen /* Unequal. CC={1,2}, and advance the registers. Note that
898c9274b6bSCho, Yu-Chen the terminator need not be zero, but the string that contains
899c9274b6bSCho, Yu-Chen the terminator is by definition "low". */
900c9274b6bSCho, Yu-Chen env->cc_op = (v1 == c ? 1 : v2 == c ? 2 : v1 < v2 ? 1 : 2);
901b71dd2a5SRichard Henderson return int128_make128(s2 + len, s1 + len);
902c9274b6bSCho, Yu-Chen }
903c9274b6bSCho, Yu-Chen }
904c9274b6bSCho, Yu-Chen
905c9274b6bSCho, Yu-Chen /* CPU-determined bytes equal; advance the registers. */
906c9274b6bSCho, Yu-Chen env->cc_op = 3;
907b71dd2a5SRichard Henderson return int128_make128(s2 + len, s1 + len);
908c9274b6bSCho, Yu-Chen }
909c9274b6bSCho, Yu-Chen
910c9274b6bSCho, Yu-Chen /* move page */
HELPER(mvpg)911c9274b6bSCho, Yu-Chen uint32_t HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint32_t r1, uint32_t r2)
912c9274b6bSCho, Yu-Chen {
913c9274b6bSCho, Yu-Chen const uint64_t src = get_address(env, r2) & TARGET_PAGE_MASK;
914c9274b6bSCho, Yu-Chen const uint64_t dst = get_address(env, r1) & TARGET_PAGE_MASK;
91590b7022eSRichard Henderson const int mmu_idx = s390x_env_mmu_index(env, false);
916c9274b6bSCho, Yu-Chen const bool f = extract64(r0, 11, 1);
917c9274b6bSCho, Yu-Chen const bool s = extract64(r0, 10, 1);
918c9274b6bSCho, Yu-Chen const bool cco = extract64(r0, 8, 1);
919c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
920c9274b6bSCho, Yu-Chen S390Access srca, desta;
921c9274b6bSCho, Yu-Chen int exc;
922c9274b6bSCho, Yu-Chen
923c9274b6bSCho, Yu-Chen if ((f && s) || extract64(r0, 12, 4)) {
924c9274b6bSCho, Yu-Chen tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
925c9274b6bSCho, Yu-Chen }
926c9274b6bSCho, Yu-Chen
927c9274b6bSCho, Yu-Chen /*
928c9274b6bSCho, Yu-Chen * We always manually handle exceptions such that we can properly store
929c9274b6bSCho, Yu-Chen * r1/r2 to the lowcore on page-translation exceptions.
930c9274b6bSCho, Yu-Chen *
931c9274b6bSCho, Yu-Chen * TODO: Access key handling
932c9274b6bSCho, Yu-Chen */
933c9274b6bSCho, Yu-Chen exc = access_prepare_nf(&srca, env, true, src, TARGET_PAGE_SIZE,
934c9274b6bSCho, Yu-Chen MMU_DATA_LOAD, mmu_idx, ra);
935c9274b6bSCho, Yu-Chen if (exc) {
936c9274b6bSCho, Yu-Chen if (cco) {
937c9274b6bSCho, Yu-Chen return 2;
938c9274b6bSCho, Yu-Chen }
939c9274b6bSCho, Yu-Chen goto inject_exc;
940c9274b6bSCho, Yu-Chen }
941c9274b6bSCho, Yu-Chen exc = access_prepare_nf(&desta, env, true, dst, TARGET_PAGE_SIZE,
942c9274b6bSCho, Yu-Chen MMU_DATA_STORE, mmu_idx, ra);
943c9274b6bSCho, Yu-Chen if (exc) {
944c9274b6bSCho, Yu-Chen if (cco && exc != PGM_PROTECTION) {
945c9274b6bSCho, Yu-Chen return 1;
946c9274b6bSCho, Yu-Chen }
947c9274b6bSCho, Yu-Chen goto inject_exc;
948c9274b6bSCho, Yu-Chen }
949c9274b6bSCho, Yu-Chen access_memmove(env, &desta, &srca, ra);
950c9274b6bSCho, Yu-Chen return 0; /* data moved */
951c9274b6bSCho, Yu-Chen inject_exc:
952c9274b6bSCho, Yu-Chen #if !defined(CONFIG_USER_ONLY)
953c9274b6bSCho, Yu-Chen if (exc != PGM_ADDRESSING) {
954c9274b6bSCho, Yu-Chen stq_phys(env_cpu(env)->as, env->psa + offsetof(LowCore, trans_exc_code),
955c9274b6bSCho, Yu-Chen env->tlb_fill_tec);
956c9274b6bSCho, Yu-Chen }
957c9274b6bSCho, Yu-Chen if (exc == PGM_PAGE_TRANS) {
958c9274b6bSCho, Yu-Chen stb_phys(env_cpu(env)->as, env->psa + offsetof(LowCore, op_access_id),
959c9274b6bSCho, Yu-Chen r1 << 4 | r2);
960c9274b6bSCho, Yu-Chen }
961c9274b6bSCho, Yu-Chen #endif
962c9274b6bSCho, Yu-Chen tcg_s390_program_interrupt(env, exc, ra);
963c9274b6bSCho, Yu-Chen }
964c9274b6bSCho, Yu-Chen
965c9274b6bSCho, Yu-Chen /* string copy */
HELPER(mvst)966c9274b6bSCho, Yu-Chen uint32_t HELPER(mvst)(CPUS390XState *env, uint32_t r1, uint32_t r2)
967c9274b6bSCho, Yu-Chen {
96890b7022eSRichard Henderson const int mmu_idx = s390x_env_mmu_index(env, false);
969c9274b6bSCho, Yu-Chen const uint64_t d = get_address(env, r1);
970c9274b6bSCho, Yu-Chen const uint64_t s = get_address(env, r2);
971c9274b6bSCho, Yu-Chen const uint8_t c = env->regs[0];
972c9274b6bSCho, Yu-Chen const int len = MIN(-(d | TARGET_PAGE_MASK), -(s | TARGET_PAGE_MASK));
973c9274b6bSCho, Yu-Chen S390Access srca, desta;
974c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
975c9274b6bSCho, Yu-Chen int i;
976c9274b6bSCho, Yu-Chen
977c9274b6bSCho, Yu-Chen if (env->regs[0] & 0xffffff00ull) {
978c9274b6bSCho, Yu-Chen tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
979c9274b6bSCho, Yu-Chen }
980c9274b6bSCho, Yu-Chen
981c9274b6bSCho, Yu-Chen /*
982c9274b6bSCho, Yu-Chen * Our access should not exceed single pages, as we must not report access
983c9274b6bSCho, Yu-Chen * exceptions exceeding the actually copied range (which we don't know at
984c9274b6bSCho, Yu-Chen * this point). We might over-indicate watchpoints within the pages
985c9274b6bSCho, Yu-Chen * (if we ever care, we have to limit processing to a single byte).
986c9274b6bSCho, Yu-Chen */
9877ba5da81SRichard Henderson access_prepare(&srca, env, s, len, MMU_DATA_LOAD, mmu_idx, ra);
9887ba5da81SRichard Henderson access_prepare(&desta, env, d, len, MMU_DATA_STORE, mmu_idx, ra);
9892730df91SRichard Henderson
9902730df91SRichard Henderson set_helper_retaddr(ra);
991c9274b6bSCho, Yu-Chen for (i = 0; i < len; i++) {
992c9274b6bSCho, Yu-Chen const uint8_t v = access_get_byte(env, &srca, i, ra);
993c9274b6bSCho, Yu-Chen
994c9274b6bSCho, Yu-Chen access_set_byte(env, &desta, i, v, ra);
995c9274b6bSCho, Yu-Chen if (v == c) {
9962730df91SRichard Henderson clear_helper_retaddr();
997c9274b6bSCho, Yu-Chen set_address_zero(env, r1, d + i);
998c9274b6bSCho, Yu-Chen return 1;
999c9274b6bSCho, Yu-Chen }
1000c9274b6bSCho, Yu-Chen }
10012730df91SRichard Henderson clear_helper_retaddr();
1002c9274b6bSCho, Yu-Chen set_address_zero(env, r1, d + len);
1003c9274b6bSCho, Yu-Chen set_address_zero(env, r2, s + len);
1004c9274b6bSCho, Yu-Chen return 3;
1005c9274b6bSCho, Yu-Chen }
1006c9274b6bSCho, Yu-Chen
1007c9274b6bSCho, Yu-Chen /* load access registers r1 to r3 from memory at a2 */
HELPER(lam)1008c9274b6bSCho, Yu-Chen void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
1009c9274b6bSCho, Yu-Chen {
1010c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
1011c9274b6bSCho, Yu-Chen int i;
1012c9274b6bSCho, Yu-Chen
1013c9274b6bSCho, Yu-Chen if (a2 & 0x3) {
1014c9274b6bSCho, Yu-Chen tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
1015c9274b6bSCho, Yu-Chen }
1016c9274b6bSCho, Yu-Chen
1017c9274b6bSCho, Yu-Chen for (i = r1;; i = (i + 1) % 16) {
1018c9274b6bSCho, Yu-Chen env->aregs[i] = cpu_ldl_data_ra(env, a2, ra);
1019c9274b6bSCho, Yu-Chen a2 += 4;
1020c9274b6bSCho, Yu-Chen
1021c9274b6bSCho, Yu-Chen if (i == r3) {
1022c9274b6bSCho, Yu-Chen break;
1023c9274b6bSCho, Yu-Chen }
1024c9274b6bSCho, Yu-Chen }
1025c9274b6bSCho, Yu-Chen }
1026c9274b6bSCho, Yu-Chen
1027c9274b6bSCho, Yu-Chen /* store access registers r1 to r3 in memory at a2 */
HELPER(stam)1028c9274b6bSCho, Yu-Chen void HELPER(stam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
1029c9274b6bSCho, Yu-Chen {
1030c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
1031c9274b6bSCho, Yu-Chen int i;
1032c9274b6bSCho, Yu-Chen
1033c9274b6bSCho, Yu-Chen if (a2 & 0x3) {
1034c9274b6bSCho, Yu-Chen tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
1035c9274b6bSCho, Yu-Chen }
1036c9274b6bSCho, Yu-Chen
1037c9274b6bSCho, Yu-Chen for (i = r1;; i = (i + 1) % 16) {
1038c9274b6bSCho, Yu-Chen cpu_stl_data_ra(env, a2, env->aregs[i], ra);
1039c9274b6bSCho, Yu-Chen a2 += 4;
1040c9274b6bSCho, Yu-Chen
1041c9274b6bSCho, Yu-Chen if (i == r3) {
1042c9274b6bSCho, Yu-Chen break;
1043c9274b6bSCho, Yu-Chen }
1044c9274b6bSCho, Yu-Chen }
1045c9274b6bSCho, Yu-Chen }
1046c9274b6bSCho, Yu-Chen
1047c9274b6bSCho, Yu-Chen /* move long helper */
do_mvcl(CPUS390XState * env,uint64_t * dest,uint64_t * destlen,uint64_t * src,uint64_t * srclen,uint16_t pad,int wordsize,uintptr_t ra)1048c9274b6bSCho, Yu-Chen static inline uint32_t do_mvcl(CPUS390XState *env,
1049c9274b6bSCho, Yu-Chen uint64_t *dest, uint64_t *destlen,
1050c9274b6bSCho, Yu-Chen uint64_t *src, uint64_t *srclen,
1051c9274b6bSCho, Yu-Chen uint16_t pad, int wordsize, uintptr_t ra)
1052c9274b6bSCho, Yu-Chen {
105390b7022eSRichard Henderson const int mmu_idx = s390x_env_mmu_index(env, false);
1054c9274b6bSCho, Yu-Chen int len = MIN(*destlen, -(*dest | TARGET_PAGE_MASK));
1055c9274b6bSCho, Yu-Chen S390Access srca, desta;
1056c9274b6bSCho, Yu-Chen int i, cc;
1057c9274b6bSCho, Yu-Chen
1058c9274b6bSCho, Yu-Chen if (*destlen == *srclen) {
1059c9274b6bSCho, Yu-Chen cc = 0;
1060c9274b6bSCho, Yu-Chen } else if (*destlen < *srclen) {
1061c9274b6bSCho, Yu-Chen cc = 1;
1062c9274b6bSCho, Yu-Chen } else {
1063c9274b6bSCho, Yu-Chen cc = 2;
1064c9274b6bSCho, Yu-Chen }
1065c9274b6bSCho, Yu-Chen
1066c9274b6bSCho, Yu-Chen if (!*destlen) {
1067c9274b6bSCho, Yu-Chen return cc;
1068c9274b6bSCho, Yu-Chen }
1069c9274b6bSCho, Yu-Chen
1070c9274b6bSCho, Yu-Chen /*
1071c9274b6bSCho, Yu-Chen * Only perform one type of type of operation (move/pad) at a time.
1072c9274b6bSCho, Yu-Chen * Stay within single pages.
1073c9274b6bSCho, Yu-Chen */
1074c9274b6bSCho, Yu-Chen if (*srclen) {
1075c9274b6bSCho, Yu-Chen /* Copy the src array */
1076c9274b6bSCho, Yu-Chen len = MIN(MIN(*srclen, -(*src | TARGET_PAGE_MASK)), len);
1077c9274b6bSCho, Yu-Chen *destlen -= len;
1078c9274b6bSCho, Yu-Chen *srclen -= len;
10797ba5da81SRichard Henderson access_prepare(&srca, env, *src, len, MMU_DATA_LOAD, mmu_idx, ra);
10807ba5da81SRichard Henderson access_prepare(&desta, env, *dest, len, MMU_DATA_STORE, mmu_idx, ra);
1081c9274b6bSCho, Yu-Chen access_memmove(env, &desta, &srca, ra);
1082c9274b6bSCho, Yu-Chen *src = wrap_address(env, *src + len);
1083c9274b6bSCho, Yu-Chen *dest = wrap_address(env, *dest + len);
1084c9274b6bSCho, Yu-Chen } else if (wordsize == 1) {
1085c9274b6bSCho, Yu-Chen /* Pad the remaining area */
1086c9274b6bSCho, Yu-Chen *destlen -= len;
10877ba5da81SRichard Henderson access_prepare(&desta, env, *dest, len, MMU_DATA_STORE, mmu_idx, ra);
1088c9274b6bSCho, Yu-Chen access_memset(env, &desta, pad, ra);
1089c9274b6bSCho, Yu-Chen *dest = wrap_address(env, *dest + len);
1090c9274b6bSCho, Yu-Chen } else {
10917ba5da81SRichard Henderson access_prepare(&desta, env, *dest, len, MMU_DATA_STORE, mmu_idx, ra);
10922730df91SRichard Henderson set_helper_retaddr(ra);
1093c9274b6bSCho, Yu-Chen
1094c9274b6bSCho, Yu-Chen /* The remaining length selects the padding byte. */
1095c9274b6bSCho, Yu-Chen for (i = 0; i < len; (*destlen)--, i++) {
1096c9274b6bSCho, Yu-Chen if (*destlen & 1) {
1097c9274b6bSCho, Yu-Chen access_set_byte(env, &desta, i, pad, ra);
1098c9274b6bSCho, Yu-Chen } else {
1099c9274b6bSCho, Yu-Chen access_set_byte(env, &desta, i, pad >> 8, ra);
1100c9274b6bSCho, Yu-Chen }
1101c9274b6bSCho, Yu-Chen }
11022730df91SRichard Henderson clear_helper_retaddr();
1103c9274b6bSCho, Yu-Chen *dest = wrap_address(env, *dest + len);
1104c9274b6bSCho, Yu-Chen }
1105c9274b6bSCho, Yu-Chen
1106c9274b6bSCho, Yu-Chen return *destlen ? 3 : cc;
1107c9274b6bSCho, Yu-Chen }
1108c9274b6bSCho, Yu-Chen
1109c9274b6bSCho, Yu-Chen /* move long */
HELPER(mvcl)1110c9274b6bSCho, Yu-Chen uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
1111c9274b6bSCho, Yu-Chen {
111290b7022eSRichard Henderson const int mmu_idx = s390x_env_mmu_index(env, false);
1113c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
1114c9274b6bSCho, Yu-Chen uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
1115c9274b6bSCho, Yu-Chen uint64_t dest = get_address(env, r1);
1116c9274b6bSCho, Yu-Chen uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
1117c9274b6bSCho, Yu-Chen uint64_t src = get_address(env, r2);
1118c9274b6bSCho, Yu-Chen uint8_t pad = env->regs[r2 + 1] >> 24;
1119c9274b6bSCho, Yu-Chen CPUState *cs = env_cpu(env);
1120c9274b6bSCho, Yu-Chen S390Access srca, desta;
1121c9274b6bSCho, Yu-Chen uint32_t cc, cur_len;
1122c9274b6bSCho, Yu-Chen
1123c9274b6bSCho, Yu-Chen if (is_destructive_overlap(env, dest, src, MIN(srclen, destlen))) {
1124c9274b6bSCho, Yu-Chen cc = 3;
1125c9274b6bSCho, Yu-Chen } else if (srclen == destlen) {
1126c9274b6bSCho, Yu-Chen cc = 0;
1127c9274b6bSCho, Yu-Chen } else if (destlen < srclen) {
1128c9274b6bSCho, Yu-Chen cc = 1;
1129c9274b6bSCho, Yu-Chen } else {
1130c9274b6bSCho, Yu-Chen cc = 2;
1131c9274b6bSCho, Yu-Chen }
1132c9274b6bSCho, Yu-Chen
1133c9274b6bSCho, Yu-Chen /* We might have to zero-out some bits even if there was no action. */
1134c9274b6bSCho, Yu-Chen if (unlikely(!destlen || cc == 3)) {
1135c9274b6bSCho, Yu-Chen set_address_zero(env, r2, src);
1136c9274b6bSCho, Yu-Chen set_address_zero(env, r1, dest);
1137c9274b6bSCho, Yu-Chen return cc;
1138c9274b6bSCho, Yu-Chen } else if (!srclen) {
1139c9274b6bSCho, Yu-Chen set_address_zero(env, r2, src);
1140c9274b6bSCho, Yu-Chen }
1141c9274b6bSCho, Yu-Chen
1142c9274b6bSCho, Yu-Chen /*
1143c9274b6bSCho, Yu-Chen * Only perform one type of type of operation (move/pad) in one step.
1144c9274b6bSCho, Yu-Chen * Stay within single pages.
1145c9274b6bSCho, Yu-Chen */
1146c9274b6bSCho, Yu-Chen while (destlen) {
1147c9274b6bSCho, Yu-Chen cur_len = MIN(destlen, -(dest | TARGET_PAGE_MASK));
1148c9274b6bSCho, Yu-Chen if (!srclen) {
11497ba5da81SRichard Henderson access_prepare(&desta, env, dest, cur_len,
11507ba5da81SRichard Henderson MMU_DATA_STORE, mmu_idx, ra);
1151c9274b6bSCho, Yu-Chen access_memset(env, &desta, pad, ra);
1152c9274b6bSCho, Yu-Chen } else {
1153c9274b6bSCho, Yu-Chen cur_len = MIN(MIN(srclen, -(src | TARGET_PAGE_MASK)), cur_len);
1154c9274b6bSCho, Yu-Chen
11557ba5da81SRichard Henderson access_prepare(&srca, env, src, cur_len,
11567ba5da81SRichard Henderson MMU_DATA_LOAD, mmu_idx, ra);
11577ba5da81SRichard Henderson access_prepare(&desta, env, dest, cur_len,
11587ba5da81SRichard Henderson MMU_DATA_STORE, mmu_idx, ra);
1159c9274b6bSCho, Yu-Chen access_memmove(env, &desta, &srca, ra);
1160c9274b6bSCho, Yu-Chen src = wrap_address(env, src + cur_len);
1161c9274b6bSCho, Yu-Chen srclen -= cur_len;
1162c9274b6bSCho, Yu-Chen env->regs[r2 + 1] = deposit64(env->regs[r2 + 1], 0, 24, srclen);
1163c9274b6bSCho, Yu-Chen set_address_zero(env, r2, src);
1164c9274b6bSCho, Yu-Chen }
1165c9274b6bSCho, Yu-Chen dest = wrap_address(env, dest + cur_len);
1166c9274b6bSCho, Yu-Chen destlen -= cur_len;
1167c9274b6bSCho, Yu-Chen env->regs[r1 + 1] = deposit64(env->regs[r1 + 1], 0, 24, destlen);
1168c9274b6bSCho, Yu-Chen set_address_zero(env, r1, dest);
1169c9274b6bSCho, Yu-Chen
1170c9274b6bSCho, Yu-Chen /*
1171c9274b6bSCho, Yu-Chen * MVCL is interruptible. Return to the main loop if requested after
1172c9274b6bSCho, Yu-Chen * writing back all state to registers. If no interrupt will get
1173c9274b6bSCho, Yu-Chen * injected, we'll end up back in this handler and continue processing
1174c9274b6bSCho, Yu-Chen * the remaining parts.
1175c9274b6bSCho, Yu-Chen */
1176c9274b6bSCho, Yu-Chen if (destlen && unlikely(cpu_loop_exit_requested(cs))) {
1177c9274b6bSCho, Yu-Chen cpu_loop_exit_restore(cs, ra);
1178c9274b6bSCho, Yu-Chen }
1179c9274b6bSCho, Yu-Chen }
1180c9274b6bSCho, Yu-Chen return cc;
1181c9274b6bSCho, Yu-Chen }
1182c9274b6bSCho, Yu-Chen
1183c9274b6bSCho, Yu-Chen /* move long extended */
HELPER(mvcle)1184c9274b6bSCho, Yu-Chen uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
1185c9274b6bSCho, Yu-Chen uint32_t r3)
1186c9274b6bSCho, Yu-Chen {
1187c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
1188c9274b6bSCho, Yu-Chen uint64_t destlen = get_length(env, r1 + 1);
1189c9274b6bSCho, Yu-Chen uint64_t dest = get_address(env, r1);
1190c9274b6bSCho, Yu-Chen uint64_t srclen = get_length(env, r3 + 1);
1191c9274b6bSCho, Yu-Chen uint64_t src = get_address(env, r3);
1192c9274b6bSCho, Yu-Chen uint8_t pad = a2;
1193c9274b6bSCho, Yu-Chen uint32_t cc;
1194c9274b6bSCho, Yu-Chen
1195c9274b6bSCho, Yu-Chen cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 1, ra);
1196c9274b6bSCho, Yu-Chen
1197c9274b6bSCho, Yu-Chen set_length(env, r1 + 1, destlen);
1198c9274b6bSCho, Yu-Chen set_length(env, r3 + 1, srclen);
1199c9274b6bSCho, Yu-Chen set_address(env, r1, dest);
1200c9274b6bSCho, Yu-Chen set_address(env, r3, src);
1201c9274b6bSCho, Yu-Chen
1202c9274b6bSCho, Yu-Chen return cc;
1203c9274b6bSCho, Yu-Chen }
1204c9274b6bSCho, Yu-Chen
1205c9274b6bSCho, Yu-Chen /* move long unicode */
HELPER(mvclu)1206c9274b6bSCho, Yu-Chen uint32_t HELPER(mvclu)(CPUS390XState *env, uint32_t r1, uint64_t a2,
1207c9274b6bSCho, Yu-Chen uint32_t r3)
1208c9274b6bSCho, Yu-Chen {
1209c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
1210c9274b6bSCho, Yu-Chen uint64_t destlen = get_length(env, r1 + 1);
1211c9274b6bSCho, Yu-Chen uint64_t dest = get_address(env, r1);
1212c9274b6bSCho, Yu-Chen uint64_t srclen = get_length(env, r3 + 1);
1213c9274b6bSCho, Yu-Chen uint64_t src = get_address(env, r3);
1214c9274b6bSCho, Yu-Chen uint16_t pad = a2;
1215c9274b6bSCho, Yu-Chen uint32_t cc;
1216c9274b6bSCho, Yu-Chen
1217c9274b6bSCho, Yu-Chen cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 2, ra);
1218c9274b6bSCho, Yu-Chen
1219c9274b6bSCho, Yu-Chen set_length(env, r1 + 1, destlen);
1220c9274b6bSCho, Yu-Chen set_length(env, r3 + 1, srclen);
1221c9274b6bSCho, Yu-Chen set_address(env, r1, dest);
1222c9274b6bSCho, Yu-Chen set_address(env, r3, src);
1223c9274b6bSCho, Yu-Chen
1224c9274b6bSCho, Yu-Chen return cc;
1225c9274b6bSCho, Yu-Chen }
1226c9274b6bSCho, Yu-Chen
1227c9274b6bSCho, Yu-Chen /* compare logical long helper */
do_clcl(CPUS390XState * env,uint64_t * src1,uint64_t * src1len,uint64_t * src3,uint64_t * src3len,uint16_t pad,uint64_t limit,int wordsize,uintptr_t ra)1228c9274b6bSCho, Yu-Chen static inline uint32_t do_clcl(CPUS390XState *env,
1229c9274b6bSCho, Yu-Chen uint64_t *src1, uint64_t *src1len,
1230c9274b6bSCho, Yu-Chen uint64_t *src3, uint64_t *src3len,
1231c9274b6bSCho, Yu-Chen uint16_t pad, uint64_t limit,
1232c9274b6bSCho, Yu-Chen int wordsize, uintptr_t ra)
1233c9274b6bSCho, Yu-Chen {
1234c9274b6bSCho, Yu-Chen uint64_t len = MAX(*src1len, *src3len);
1235c9274b6bSCho, Yu-Chen uint32_t cc = 0;
1236c9274b6bSCho, Yu-Chen
1237c9274b6bSCho, Yu-Chen check_alignment(env, *src1len | *src3len, wordsize, ra);
1238c9274b6bSCho, Yu-Chen
1239c9274b6bSCho, Yu-Chen if (!len) {
1240c9274b6bSCho, Yu-Chen return cc;
1241c9274b6bSCho, Yu-Chen }
1242c9274b6bSCho, Yu-Chen
1243c9274b6bSCho, Yu-Chen /* Lest we fail to service interrupts in a timely manner, limit the
1244c9274b6bSCho, Yu-Chen amount of work we're willing to do. */
1245c9274b6bSCho, Yu-Chen if (len > limit) {
1246c9274b6bSCho, Yu-Chen len = limit;
1247c9274b6bSCho, Yu-Chen cc = 3;
1248c9274b6bSCho, Yu-Chen }
1249c9274b6bSCho, Yu-Chen
1250c9274b6bSCho, Yu-Chen for (; len; len -= wordsize) {
1251c9274b6bSCho, Yu-Chen uint16_t v1 = pad;
1252c9274b6bSCho, Yu-Chen uint16_t v3 = pad;
1253c9274b6bSCho, Yu-Chen
1254c9274b6bSCho, Yu-Chen if (*src1len) {
1255c9274b6bSCho, Yu-Chen v1 = cpu_ldusize_data_ra(env, *src1, wordsize, ra);
1256c9274b6bSCho, Yu-Chen }
1257c9274b6bSCho, Yu-Chen if (*src3len) {
1258c9274b6bSCho, Yu-Chen v3 = cpu_ldusize_data_ra(env, *src3, wordsize, ra);
1259c9274b6bSCho, Yu-Chen }
1260c9274b6bSCho, Yu-Chen
1261c9274b6bSCho, Yu-Chen if (v1 != v3) {
1262c9274b6bSCho, Yu-Chen cc = (v1 < v3) ? 1 : 2;
1263c9274b6bSCho, Yu-Chen break;
1264c9274b6bSCho, Yu-Chen }
1265c9274b6bSCho, Yu-Chen
1266c9274b6bSCho, Yu-Chen if (*src1len) {
1267c9274b6bSCho, Yu-Chen *src1 += wordsize;
1268c9274b6bSCho, Yu-Chen *src1len -= wordsize;
1269c9274b6bSCho, Yu-Chen }
1270c9274b6bSCho, Yu-Chen if (*src3len) {
1271c9274b6bSCho, Yu-Chen *src3 += wordsize;
1272c9274b6bSCho, Yu-Chen *src3len -= wordsize;
1273c9274b6bSCho, Yu-Chen }
1274c9274b6bSCho, Yu-Chen }
1275c9274b6bSCho, Yu-Chen
1276c9274b6bSCho, Yu-Chen return cc;
1277c9274b6bSCho, Yu-Chen }
1278c9274b6bSCho, Yu-Chen
1279c9274b6bSCho, Yu-Chen
1280c9274b6bSCho, Yu-Chen /* compare logical long */
HELPER(clcl)1281c9274b6bSCho, Yu-Chen uint32_t HELPER(clcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
1282c9274b6bSCho, Yu-Chen {
1283c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
1284c9274b6bSCho, Yu-Chen uint64_t src1len = extract64(env->regs[r1 + 1], 0, 24);
1285c9274b6bSCho, Yu-Chen uint64_t src1 = get_address(env, r1);
1286c9274b6bSCho, Yu-Chen uint64_t src3len = extract64(env->regs[r2 + 1], 0, 24);
1287c9274b6bSCho, Yu-Chen uint64_t src3 = get_address(env, r2);
1288c9274b6bSCho, Yu-Chen uint8_t pad = env->regs[r2 + 1] >> 24;
1289c9274b6bSCho, Yu-Chen uint32_t cc;
1290c9274b6bSCho, Yu-Chen
1291c9274b6bSCho, Yu-Chen cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, -1, 1, ra);
1292c9274b6bSCho, Yu-Chen
1293c9274b6bSCho, Yu-Chen env->regs[r1 + 1] = deposit64(env->regs[r1 + 1], 0, 24, src1len);
1294c9274b6bSCho, Yu-Chen env->regs[r2 + 1] = deposit64(env->regs[r2 + 1], 0, 24, src3len);
1295c9274b6bSCho, Yu-Chen set_address(env, r1, src1);
1296c9274b6bSCho, Yu-Chen set_address(env, r2, src3);
1297c9274b6bSCho, Yu-Chen
1298c9274b6bSCho, Yu-Chen return cc;
1299c9274b6bSCho, Yu-Chen }
1300c9274b6bSCho, Yu-Chen
1301c9274b6bSCho, Yu-Chen /* compare logical long extended memcompare insn with padding */
HELPER(clcle)1302c9274b6bSCho, Yu-Chen uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
1303c9274b6bSCho, Yu-Chen uint32_t r3)
1304c9274b6bSCho, Yu-Chen {
1305c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
1306c9274b6bSCho, Yu-Chen uint64_t src1len = get_length(env, r1 + 1);
1307c9274b6bSCho, Yu-Chen uint64_t src1 = get_address(env, r1);
1308c9274b6bSCho, Yu-Chen uint64_t src3len = get_length(env, r3 + 1);
1309c9274b6bSCho, Yu-Chen uint64_t src3 = get_address(env, r3);
1310c9274b6bSCho, Yu-Chen uint8_t pad = a2;
1311c9274b6bSCho, Yu-Chen uint32_t cc;
1312c9274b6bSCho, Yu-Chen
1313c9274b6bSCho, Yu-Chen cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, 0x2000, 1, ra);
1314c9274b6bSCho, Yu-Chen
1315c9274b6bSCho, Yu-Chen set_length(env, r1 + 1, src1len);
1316c9274b6bSCho, Yu-Chen set_length(env, r3 + 1, src3len);
1317c9274b6bSCho, Yu-Chen set_address(env, r1, src1);
1318c9274b6bSCho, Yu-Chen set_address(env, r3, src3);
1319c9274b6bSCho, Yu-Chen
1320c9274b6bSCho, Yu-Chen return cc;
1321c9274b6bSCho, Yu-Chen }
1322c9274b6bSCho, Yu-Chen
1323c9274b6bSCho, Yu-Chen /* compare logical long unicode memcompare insn with padding */
HELPER(clclu)1324c9274b6bSCho, Yu-Chen uint32_t HELPER(clclu)(CPUS390XState *env, uint32_t r1, uint64_t a2,
1325c9274b6bSCho, Yu-Chen uint32_t r3)
1326c9274b6bSCho, Yu-Chen {
1327c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
1328c9274b6bSCho, Yu-Chen uint64_t src1len = get_length(env, r1 + 1);
1329c9274b6bSCho, Yu-Chen uint64_t src1 = get_address(env, r1);
1330c9274b6bSCho, Yu-Chen uint64_t src3len = get_length(env, r3 + 1);
1331c9274b6bSCho, Yu-Chen uint64_t src3 = get_address(env, r3);
1332c9274b6bSCho, Yu-Chen uint16_t pad = a2;
1333c9274b6bSCho, Yu-Chen uint32_t cc = 0;
1334c9274b6bSCho, Yu-Chen
1335c9274b6bSCho, Yu-Chen cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, 0x1000, 2, ra);
1336c9274b6bSCho, Yu-Chen
1337c9274b6bSCho, Yu-Chen set_length(env, r1 + 1, src1len);
1338c9274b6bSCho, Yu-Chen set_length(env, r3 + 1, src3len);
1339c9274b6bSCho, Yu-Chen set_address(env, r1, src1);
1340c9274b6bSCho, Yu-Chen set_address(env, r3, src3);
1341c9274b6bSCho, Yu-Chen
1342c9274b6bSCho, Yu-Chen return cc;
1343c9274b6bSCho, Yu-Chen }
1344c9274b6bSCho, Yu-Chen
1345c9274b6bSCho, Yu-Chen /* checksum */
HELPER(cksm)1346c9119224SRichard Henderson Int128 HELPER(cksm)(CPUS390XState *env, uint64_t r1,
1347c9274b6bSCho, Yu-Chen uint64_t src, uint64_t src_len)
1348c9274b6bSCho, Yu-Chen {
1349c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
1350c9274b6bSCho, Yu-Chen uint64_t max_len, len;
1351c9274b6bSCho, Yu-Chen uint64_t cksm = (uint32_t)r1;
1352c9274b6bSCho, Yu-Chen
1353c9274b6bSCho, Yu-Chen /* Lest we fail to service interrupts in a timely manner, limit the
1354c9274b6bSCho, Yu-Chen amount of work we're willing to do. For now, let's cap at 8k. */
1355c9274b6bSCho, Yu-Chen max_len = (src_len > 0x2000 ? 0x2000 : src_len);
1356c9274b6bSCho, Yu-Chen
1357c9274b6bSCho, Yu-Chen /* Process full words as available. */
1358c9274b6bSCho, Yu-Chen for (len = 0; len + 4 <= max_len; len += 4, src += 4) {
1359c9274b6bSCho, Yu-Chen cksm += (uint32_t)cpu_ldl_data_ra(env, src, ra);
1360c9274b6bSCho, Yu-Chen }
1361c9274b6bSCho, Yu-Chen
1362c9274b6bSCho, Yu-Chen switch (max_len - len) {
1363c9274b6bSCho, Yu-Chen case 1:
1364c9274b6bSCho, Yu-Chen cksm += cpu_ldub_data_ra(env, src, ra) << 24;
1365c9274b6bSCho, Yu-Chen len += 1;
1366c9274b6bSCho, Yu-Chen break;
1367c9274b6bSCho, Yu-Chen case 2:
1368c9274b6bSCho, Yu-Chen cksm += cpu_lduw_data_ra(env, src, ra) << 16;
1369c9274b6bSCho, Yu-Chen len += 2;
1370c9274b6bSCho, Yu-Chen break;
1371c9274b6bSCho, Yu-Chen case 3:
1372c9274b6bSCho, Yu-Chen cksm += cpu_lduw_data_ra(env, src, ra) << 16;
1373c9274b6bSCho, Yu-Chen cksm += cpu_ldub_data_ra(env, src + 2, ra) << 8;
1374c9274b6bSCho, Yu-Chen len += 3;
1375c9274b6bSCho, Yu-Chen break;
1376c9274b6bSCho, Yu-Chen }
1377c9274b6bSCho, Yu-Chen
1378c9274b6bSCho, Yu-Chen /* Fold the carry from the checksum. Note that we can see carry-out
1379c9274b6bSCho, Yu-Chen during folding more than once (but probably not more than twice). */
1380c9274b6bSCho, Yu-Chen while (cksm > 0xffffffffull) {
1381c9274b6bSCho, Yu-Chen cksm = (uint32_t)cksm + (cksm >> 32);
1382c9274b6bSCho, Yu-Chen }
1383c9274b6bSCho, Yu-Chen
1384c9274b6bSCho, Yu-Chen /* Indicate whether or not we've processed everything. */
1385c9274b6bSCho, Yu-Chen env->cc_op = (len == src_len ? 0 : 3);
1386c9274b6bSCho, Yu-Chen
1387c9274b6bSCho, Yu-Chen /* Return both cksm and processed length. */
1388c9119224SRichard Henderson return int128_make128(cksm, len);
1389c9274b6bSCho, Yu-Chen }
1390c9274b6bSCho, Yu-Chen
HELPER(pack)1391c9274b6bSCho, Yu-Chen void HELPER(pack)(CPUS390XState *env, uint32_t len, uint64_t dest, uint64_t src)
1392c9274b6bSCho, Yu-Chen {
1393c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
1394c9274b6bSCho, Yu-Chen int len_dest = len >> 4;
1395c9274b6bSCho, Yu-Chen int len_src = len & 0xf;
1396c9274b6bSCho, Yu-Chen uint8_t b;
1397c9274b6bSCho, Yu-Chen
1398c9274b6bSCho, Yu-Chen dest += len_dest;
1399c9274b6bSCho, Yu-Chen src += len_src;
1400c9274b6bSCho, Yu-Chen
1401c9274b6bSCho, Yu-Chen /* last byte is special, it only flips the nibbles */
1402c9274b6bSCho, Yu-Chen b = cpu_ldub_data_ra(env, src, ra);
1403c9274b6bSCho, Yu-Chen cpu_stb_data_ra(env, dest, (b << 4) | (b >> 4), ra);
1404c9274b6bSCho, Yu-Chen src--;
1405c9274b6bSCho, Yu-Chen len_src--;
1406c9274b6bSCho, Yu-Chen
1407c9274b6bSCho, Yu-Chen /* now pack every value */
1408c9274b6bSCho, Yu-Chen while (len_dest > 0) {
1409c9274b6bSCho, Yu-Chen b = 0;
1410c9274b6bSCho, Yu-Chen
1411c9274b6bSCho, Yu-Chen if (len_src >= 0) {
1412c9274b6bSCho, Yu-Chen b = cpu_ldub_data_ra(env, src, ra) & 0x0f;
1413c9274b6bSCho, Yu-Chen src--;
1414c9274b6bSCho, Yu-Chen len_src--;
1415c9274b6bSCho, Yu-Chen }
1416c9274b6bSCho, Yu-Chen if (len_src >= 0) {
1417c9274b6bSCho, Yu-Chen b |= cpu_ldub_data_ra(env, src, ra) << 4;
1418c9274b6bSCho, Yu-Chen src--;
1419c9274b6bSCho, Yu-Chen len_src--;
1420c9274b6bSCho, Yu-Chen }
1421c9274b6bSCho, Yu-Chen
1422c9274b6bSCho, Yu-Chen len_dest--;
1423c9274b6bSCho, Yu-Chen dest--;
1424c9274b6bSCho, Yu-Chen cpu_stb_data_ra(env, dest, b, ra);
1425c9274b6bSCho, Yu-Chen }
1426c9274b6bSCho, Yu-Chen }
1427c9274b6bSCho, Yu-Chen
do_pkau(CPUS390XState * env,uint64_t dest,uint64_t src,uint32_t srclen,int ssize,uintptr_t ra)1428c9274b6bSCho, Yu-Chen static inline void do_pkau(CPUS390XState *env, uint64_t dest, uint64_t src,
1429c9274b6bSCho, Yu-Chen uint32_t srclen, int ssize, uintptr_t ra)
1430c9274b6bSCho, Yu-Chen {
1431c9274b6bSCho, Yu-Chen int i;
1432c9274b6bSCho, Yu-Chen /* The destination operand is always 16 bytes long. */
1433c9274b6bSCho, Yu-Chen const int destlen = 16;
1434c9274b6bSCho, Yu-Chen
1435c9274b6bSCho, Yu-Chen /* The operands are processed from right to left. */
1436c9274b6bSCho, Yu-Chen src += srclen - 1;
1437c9274b6bSCho, Yu-Chen dest += destlen - 1;
1438c9274b6bSCho, Yu-Chen
1439c9274b6bSCho, Yu-Chen for (i = 0; i < destlen; i++) {
1440c9274b6bSCho, Yu-Chen uint8_t b = 0;
1441c9274b6bSCho, Yu-Chen
1442c9274b6bSCho, Yu-Chen /* Start with a positive sign */
1443c9274b6bSCho, Yu-Chen if (i == 0) {
1444c9274b6bSCho, Yu-Chen b = 0xc;
1445c9274b6bSCho, Yu-Chen } else if (srclen > ssize) {
1446c9274b6bSCho, Yu-Chen b = cpu_ldub_data_ra(env, src, ra) & 0x0f;
1447c9274b6bSCho, Yu-Chen src -= ssize;
1448c9274b6bSCho, Yu-Chen srclen -= ssize;
1449c9274b6bSCho, Yu-Chen }
1450c9274b6bSCho, Yu-Chen
1451c9274b6bSCho, Yu-Chen if (srclen > ssize) {
1452c9274b6bSCho, Yu-Chen b |= cpu_ldub_data_ra(env, src, ra) << 4;
1453c9274b6bSCho, Yu-Chen src -= ssize;
1454c9274b6bSCho, Yu-Chen srclen -= ssize;
1455c9274b6bSCho, Yu-Chen }
1456c9274b6bSCho, Yu-Chen
1457c9274b6bSCho, Yu-Chen cpu_stb_data_ra(env, dest, b, ra);
1458c9274b6bSCho, Yu-Chen dest--;
1459c9274b6bSCho, Yu-Chen }
1460c9274b6bSCho, Yu-Chen }
1461c9274b6bSCho, Yu-Chen
1462c9274b6bSCho, Yu-Chen
HELPER(pka)1463c9274b6bSCho, Yu-Chen void HELPER(pka)(CPUS390XState *env, uint64_t dest, uint64_t src,
1464c9274b6bSCho, Yu-Chen uint32_t srclen)
1465c9274b6bSCho, Yu-Chen {
1466c9274b6bSCho, Yu-Chen do_pkau(env, dest, src, srclen, 1, GETPC());
1467c9274b6bSCho, Yu-Chen }
1468c9274b6bSCho, Yu-Chen
HELPER(pku)1469c9274b6bSCho, Yu-Chen void HELPER(pku)(CPUS390XState *env, uint64_t dest, uint64_t src,
1470c9274b6bSCho, Yu-Chen uint32_t srclen)
1471c9274b6bSCho, Yu-Chen {
1472c9274b6bSCho, Yu-Chen do_pkau(env, dest, src, srclen, 2, GETPC());
1473c9274b6bSCho, Yu-Chen }
1474c9274b6bSCho, Yu-Chen
HELPER(unpk)1475c9274b6bSCho, Yu-Chen void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest,
1476c9274b6bSCho, Yu-Chen uint64_t src)
1477c9274b6bSCho, Yu-Chen {
1478c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
1479c9274b6bSCho, Yu-Chen int len_dest = len >> 4;
1480c9274b6bSCho, Yu-Chen int len_src = len & 0xf;
1481c9274b6bSCho, Yu-Chen uint8_t b;
1482c9274b6bSCho, Yu-Chen int second_nibble = 0;
1483c9274b6bSCho, Yu-Chen
1484c9274b6bSCho, Yu-Chen dest += len_dest;
1485c9274b6bSCho, Yu-Chen src += len_src;
1486c9274b6bSCho, Yu-Chen
1487c9274b6bSCho, Yu-Chen /* last byte is special, it only flips the nibbles */
1488c9274b6bSCho, Yu-Chen b = cpu_ldub_data_ra(env, src, ra);
1489c9274b6bSCho, Yu-Chen cpu_stb_data_ra(env, dest, (b << 4) | (b >> 4), ra);
1490c9274b6bSCho, Yu-Chen src--;
1491c9274b6bSCho, Yu-Chen len_src--;
1492c9274b6bSCho, Yu-Chen
1493c9274b6bSCho, Yu-Chen /* now pad every nibble with 0xf0 */
1494c9274b6bSCho, Yu-Chen
1495c9274b6bSCho, Yu-Chen while (len_dest > 0) {
1496c9274b6bSCho, Yu-Chen uint8_t cur_byte = 0;
1497c9274b6bSCho, Yu-Chen
1498c9274b6bSCho, Yu-Chen if (len_src > 0) {
1499c9274b6bSCho, Yu-Chen cur_byte = cpu_ldub_data_ra(env, src, ra);
1500c9274b6bSCho, Yu-Chen }
1501c9274b6bSCho, Yu-Chen
1502c9274b6bSCho, Yu-Chen len_dest--;
1503c9274b6bSCho, Yu-Chen dest--;
1504c9274b6bSCho, Yu-Chen
1505c9274b6bSCho, Yu-Chen /* only advance one nibble at a time */
1506c9274b6bSCho, Yu-Chen if (second_nibble) {
1507c9274b6bSCho, Yu-Chen cur_byte >>= 4;
1508c9274b6bSCho, Yu-Chen len_src--;
1509c9274b6bSCho, Yu-Chen src--;
1510c9274b6bSCho, Yu-Chen }
1511c9274b6bSCho, Yu-Chen second_nibble = !second_nibble;
1512c9274b6bSCho, Yu-Chen
1513c9274b6bSCho, Yu-Chen /* digit */
1514c9274b6bSCho, Yu-Chen cur_byte = (cur_byte & 0xf);
1515c9274b6bSCho, Yu-Chen /* zone bits */
1516c9274b6bSCho, Yu-Chen cur_byte |= 0xf0;
1517c9274b6bSCho, Yu-Chen
1518c9274b6bSCho, Yu-Chen cpu_stb_data_ra(env, dest, cur_byte, ra);
1519c9274b6bSCho, Yu-Chen }
1520c9274b6bSCho, Yu-Chen }
1521c9274b6bSCho, Yu-Chen
do_unpkau(CPUS390XState * env,uint64_t dest,uint32_t destlen,int dsize,uint64_t src,uintptr_t ra)1522c9274b6bSCho, Yu-Chen static inline uint32_t do_unpkau(CPUS390XState *env, uint64_t dest,
1523c9274b6bSCho, Yu-Chen uint32_t destlen, int dsize, uint64_t src,
1524c9274b6bSCho, Yu-Chen uintptr_t ra)
1525c9274b6bSCho, Yu-Chen {
1526c9274b6bSCho, Yu-Chen int i;
1527c9274b6bSCho, Yu-Chen uint32_t cc;
1528c9274b6bSCho, Yu-Chen uint8_t b;
1529c9274b6bSCho, Yu-Chen /* The source operand is always 16 bytes long. */
1530c9274b6bSCho, Yu-Chen const int srclen = 16;
1531c9274b6bSCho, Yu-Chen
1532c9274b6bSCho, Yu-Chen /* The operands are processed from right to left. */
1533c9274b6bSCho, Yu-Chen src += srclen - 1;
1534c9274b6bSCho, Yu-Chen dest += destlen - dsize;
1535c9274b6bSCho, Yu-Chen
1536c9274b6bSCho, Yu-Chen /* Check for the sign. */
1537c9274b6bSCho, Yu-Chen b = cpu_ldub_data_ra(env, src, ra);
1538c9274b6bSCho, Yu-Chen src--;
1539c9274b6bSCho, Yu-Chen switch (b & 0xf) {
1540c9274b6bSCho, Yu-Chen case 0xa:
1541c9274b6bSCho, Yu-Chen case 0xc:
1542c9274b6bSCho, Yu-Chen case 0xe ... 0xf:
1543c9274b6bSCho, Yu-Chen cc = 0; /* plus */
1544c9274b6bSCho, Yu-Chen break;
1545c9274b6bSCho, Yu-Chen case 0xb:
1546c9274b6bSCho, Yu-Chen case 0xd:
1547c9274b6bSCho, Yu-Chen cc = 1; /* minus */
1548c9274b6bSCho, Yu-Chen break;
1549c9274b6bSCho, Yu-Chen default:
1550c9274b6bSCho, Yu-Chen case 0x0 ... 0x9:
1551c9274b6bSCho, Yu-Chen cc = 3; /* invalid */
1552c9274b6bSCho, Yu-Chen break;
1553c9274b6bSCho, Yu-Chen }
1554c9274b6bSCho, Yu-Chen
1555c9274b6bSCho, Yu-Chen /* Now pad every nibble with 0x30, advancing one nibble at a time. */
1556c9274b6bSCho, Yu-Chen for (i = 0; i < destlen; i += dsize) {
1557c9274b6bSCho, Yu-Chen if (i == (31 * dsize)) {
1558c9274b6bSCho, Yu-Chen /* If length is 32/64 bytes, the leftmost byte is 0. */
1559c9274b6bSCho, Yu-Chen b = 0;
1560c9274b6bSCho, Yu-Chen } else if (i % (2 * dsize)) {
1561c9274b6bSCho, Yu-Chen b = cpu_ldub_data_ra(env, src, ra);
1562c9274b6bSCho, Yu-Chen src--;
1563c9274b6bSCho, Yu-Chen } else {
1564c9274b6bSCho, Yu-Chen b >>= 4;
1565c9274b6bSCho, Yu-Chen }
1566c9274b6bSCho, Yu-Chen cpu_stsize_data_ra(env, dest, 0x30 + (b & 0xf), dsize, ra);
1567c9274b6bSCho, Yu-Chen dest -= dsize;
1568c9274b6bSCho, Yu-Chen }
1569c9274b6bSCho, Yu-Chen
1570c9274b6bSCho, Yu-Chen return cc;
1571c9274b6bSCho, Yu-Chen }
1572c9274b6bSCho, Yu-Chen
HELPER(unpka)1573c9274b6bSCho, Yu-Chen uint32_t HELPER(unpka)(CPUS390XState *env, uint64_t dest, uint32_t destlen,
1574c9274b6bSCho, Yu-Chen uint64_t src)
1575c9274b6bSCho, Yu-Chen {
1576c9274b6bSCho, Yu-Chen return do_unpkau(env, dest, destlen, 1, src, GETPC());
1577c9274b6bSCho, Yu-Chen }
1578c9274b6bSCho, Yu-Chen
HELPER(unpku)1579c9274b6bSCho, Yu-Chen uint32_t HELPER(unpku)(CPUS390XState *env, uint64_t dest, uint32_t destlen,
1580c9274b6bSCho, Yu-Chen uint64_t src)
1581c9274b6bSCho, Yu-Chen {
1582c9274b6bSCho, Yu-Chen return do_unpkau(env, dest, destlen, 2, src, GETPC());
1583c9274b6bSCho, Yu-Chen }
1584c9274b6bSCho, Yu-Chen
HELPER(tp)1585c9274b6bSCho, Yu-Chen uint32_t HELPER(tp)(CPUS390XState *env, uint64_t dest, uint32_t destlen)
1586c9274b6bSCho, Yu-Chen {
1587c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
1588c9274b6bSCho, Yu-Chen uint32_t cc = 0;
1589c9274b6bSCho, Yu-Chen int i;
1590c9274b6bSCho, Yu-Chen
1591c9274b6bSCho, Yu-Chen for (i = 0; i < destlen; i++) {
1592c9274b6bSCho, Yu-Chen uint8_t b = cpu_ldub_data_ra(env, dest + i, ra);
1593c9274b6bSCho, Yu-Chen /* digit */
1594c9274b6bSCho, Yu-Chen cc |= (b & 0xf0) > 0x90 ? 2 : 0;
1595c9274b6bSCho, Yu-Chen
1596c9274b6bSCho, Yu-Chen if (i == (destlen - 1)) {
1597c9274b6bSCho, Yu-Chen /* sign */
1598c9274b6bSCho, Yu-Chen cc |= (b & 0xf) < 0xa ? 1 : 0;
1599c9274b6bSCho, Yu-Chen } else {
1600c9274b6bSCho, Yu-Chen /* digit */
1601c9274b6bSCho, Yu-Chen cc |= (b & 0xf) > 0x9 ? 2 : 0;
1602c9274b6bSCho, Yu-Chen }
1603c9274b6bSCho, Yu-Chen }
1604c9274b6bSCho, Yu-Chen
1605c9274b6bSCho, Yu-Chen return cc;
1606c9274b6bSCho, Yu-Chen }
1607c9274b6bSCho, Yu-Chen
do_helper_tr(CPUS390XState * env,uint32_t len,uint64_t array,uint64_t trans,uintptr_t ra)1608c9274b6bSCho, Yu-Chen static uint32_t do_helper_tr(CPUS390XState *env, uint32_t len, uint64_t array,
1609c9274b6bSCho, Yu-Chen uint64_t trans, uintptr_t ra)
1610c9274b6bSCho, Yu-Chen {
1611c9274b6bSCho, Yu-Chen uint32_t i;
1612c9274b6bSCho, Yu-Chen
1613c9274b6bSCho, Yu-Chen for (i = 0; i <= len; i++) {
1614c9274b6bSCho, Yu-Chen uint8_t byte = cpu_ldub_data_ra(env, array + i, ra);
1615c9274b6bSCho, Yu-Chen uint8_t new_byte = cpu_ldub_data_ra(env, trans + byte, ra);
1616c9274b6bSCho, Yu-Chen cpu_stb_data_ra(env, array + i, new_byte, ra);
1617c9274b6bSCho, Yu-Chen }
1618c9274b6bSCho, Yu-Chen
1619c9274b6bSCho, Yu-Chen return env->cc_op;
1620c9274b6bSCho, Yu-Chen }
1621c9274b6bSCho, Yu-Chen
HELPER(tr)1622c9274b6bSCho, Yu-Chen void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array,
1623c9274b6bSCho, Yu-Chen uint64_t trans)
1624c9274b6bSCho, Yu-Chen {
1625c9274b6bSCho, Yu-Chen do_helper_tr(env, len, array, trans, GETPC());
1626c9274b6bSCho, Yu-Chen }
1627c9274b6bSCho, Yu-Chen
HELPER(tre)1628ef45f5b9SRichard Henderson Int128 HELPER(tre)(CPUS390XState *env, uint64_t array,
1629c9274b6bSCho, Yu-Chen uint64_t len, uint64_t trans)
1630c9274b6bSCho, Yu-Chen {
1631c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
1632c9274b6bSCho, Yu-Chen uint8_t end = env->regs[0] & 0xff;
1633c9274b6bSCho, Yu-Chen uint64_t l = len;
1634c9274b6bSCho, Yu-Chen uint64_t i;
1635c9274b6bSCho, Yu-Chen uint32_t cc = 0;
1636c9274b6bSCho, Yu-Chen
1637c9274b6bSCho, Yu-Chen if (!(env->psw.mask & PSW_MASK_64)) {
1638c9274b6bSCho, Yu-Chen array &= 0x7fffffff;
1639c9274b6bSCho, Yu-Chen l = (uint32_t)l;
1640c9274b6bSCho, Yu-Chen }
1641c9274b6bSCho, Yu-Chen
1642c9274b6bSCho, Yu-Chen /* Lest we fail to service interrupts in a timely manner, limit the
1643c9274b6bSCho, Yu-Chen amount of work we're willing to do. For now, let's cap at 8k. */
1644c9274b6bSCho, Yu-Chen if (l > 0x2000) {
1645c9274b6bSCho, Yu-Chen l = 0x2000;
1646c9274b6bSCho, Yu-Chen cc = 3;
1647c9274b6bSCho, Yu-Chen }
1648c9274b6bSCho, Yu-Chen
1649c9274b6bSCho, Yu-Chen for (i = 0; i < l; i++) {
1650c9274b6bSCho, Yu-Chen uint8_t byte, new_byte;
1651c9274b6bSCho, Yu-Chen
1652c9274b6bSCho, Yu-Chen byte = cpu_ldub_data_ra(env, array + i, ra);
1653c9274b6bSCho, Yu-Chen
1654c9274b6bSCho, Yu-Chen if (byte == end) {
1655c9274b6bSCho, Yu-Chen cc = 1;
1656c9274b6bSCho, Yu-Chen break;
1657c9274b6bSCho, Yu-Chen }
1658c9274b6bSCho, Yu-Chen
1659c9274b6bSCho, Yu-Chen new_byte = cpu_ldub_data_ra(env, trans + byte, ra);
1660c9274b6bSCho, Yu-Chen cpu_stb_data_ra(env, array + i, new_byte, ra);
1661c9274b6bSCho, Yu-Chen }
1662c9274b6bSCho, Yu-Chen
1663c9274b6bSCho, Yu-Chen env->cc_op = cc;
1664ef45f5b9SRichard Henderson return int128_make128(len - i, array + i);
1665c9274b6bSCho, Yu-Chen }
1666c9274b6bSCho, Yu-Chen
do_helper_trt(CPUS390XState * env,int len,uint64_t array,uint64_t trans,int inc,uintptr_t ra)1667c9274b6bSCho, Yu-Chen static inline uint32_t do_helper_trt(CPUS390XState *env, int len,
1668c9274b6bSCho, Yu-Chen uint64_t array, uint64_t trans,
1669c9274b6bSCho, Yu-Chen int inc, uintptr_t ra)
1670c9274b6bSCho, Yu-Chen {
1671c9274b6bSCho, Yu-Chen int i;
1672c9274b6bSCho, Yu-Chen
1673c9274b6bSCho, Yu-Chen for (i = 0; i <= len; i++) {
1674c9274b6bSCho, Yu-Chen uint8_t byte = cpu_ldub_data_ra(env, array + i * inc, ra);
1675c9274b6bSCho, Yu-Chen uint8_t sbyte = cpu_ldub_data_ra(env, trans + byte, ra);
1676c9274b6bSCho, Yu-Chen
1677c9274b6bSCho, Yu-Chen if (sbyte != 0) {
1678c9274b6bSCho, Yu-Chen set_address(env, 1, array + i * inc);
1679c9274b6bSCho, Yu-Chen env->regs[2] = deposit64(env->regs[2], 0, 8, sbyte);
1680c9274b6bSCho, Yu-Chen return (i == len) ? 2 : 1;
1681c9274b6bSCho, Yu-Chen }
1682c9274b6bSCho, Yu-Chen }
1683c9274b6bSCho, Yu-Chen
1684c9274b6bSCho, Yu-Chen return 0;
1685c9274b6bSCho, Yu-Chen }
1686c9274b6bSCho, Yu-Chen
do_helper_trt_fwd(CPUS390XState * env,uint32_t len,uint64_t array,uint64_t trans,uintptr_t ra)1687c9274b6bSCho, Yu-Chen static uint32_t do_helper_trt_fwd(CPUS390XState *env, uint32_t len,
1688c9274b6bSCho, Yu-Chen uint64_t array, uint64_t trans,
1689c9274b6bSCho, Yu-Chen uintptr_t ra)
1690c9274b6bSCho, Yu-Chen {
1691c9274b6bSCho, Yu-Chen return do_helper_trt(env, len, array, trans, 1, ra);
1692c9274b6bSCho, Yu-Chen }
1693c9274b6bSCho, Yu-Chen
HELPER(trt)1694c9274b6bSCho, Yu-Chen uint32_t HELPER(trt)(CPUS390XState *env, uint32_t len, uint64_t array,
1695c9274b6bSCho, Yu-Chen uint64_t trans)
1696c9274b6bSCho, Yu-Chen {
1697c9274b6bSCho, Yu-Chen return do_helper_trt(env, len, array, trans, 1, GETPC());
1698c9274b6bSCho, Yu-Chen }
1699c9274b6bSCho, Yu-Chen
do_helper_trt_bkwd(CPUS390XState * env,uint32_t len,uint64_t array,uint64_t trans,uintptr_t ra)1700c9274b6bSCho, Yu-Chen static uint32_t do_helper_trt_bkwd(CPUS390XState *env, uint32_t len,
1701c9274b6bSCho, Yu-Chen uint64_t array, uint64_t trans,
1702c9274b6bSCho, Yu-Chen uintptr_t ra)
1703c9274b6bSCho, Yu-Chen {
1704c9274b6bSCho, Yu-Chen return do_helper_trt(env, len, array, trans, -1, ra);
1705c9274b6bSCho, Yu-Chen }
1706c9274b6bSCho, Yu-Chen
HELPER(trtr)1707c9274b6bSCho, Yu-Chen uint32_t HELPER(trtr)(CPUS390XState *env, uint32_t len, uint64_t array,
1708c9274b6bSCho, Yu-Chen uint64_t trans)
1709c9274b6bSCho, Yu-Chen {
1710c9274b6bSCho, Yu-Chen return do_helper_trt(env, len, array, trans, -1, GETPC());
1711c9274b6bSCho, Yu-Chen }
1712c9274b6bSCho, Yu-Chen
1713c9274b6bSCho, Yu-Chen /* Translate one/two to one/two */
HELPER(trXX)1714c9274b6bSCho, Yu-Chen uint32_t HELPER(trXX)(CPUS390XState *env, uint32_t r1, uint32_t r2,
1715c9274b6bSCho, Yu-Chen uint32_t tst, uint32_t sizes)
1716c9274b6bSCho, Yu-Chen {
1717c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
1718c9274b6bSCho, Yu-Chen int dsize = (sizes & 1) ? 1 : 2;
1719c9274b6bSCho, Yu-Chen int ssize = (sizes & 2) ? 1 : 2;
1720c9274b6bSCho, Yu-Chen uint64_t tbl = get_address(env, 1);
1721c9274b6bSCho, Yu-Chen uint64_t dst = get_address(env, r1);
1722c9274b6bSCho, Yu-Chen uint64_t len = get_length(env, r1 + 1);
1723c9274b6bSCho, Yu-Chen uint64_t src = get_address(env, r2);
1724c9274b6bSCho, Yu-Chen uint32_t cc = 3;
1725c9274b6bSCho, Yu-Chen int i;
1726c9274b6bSCho, Yu-Chen
1727c9274b6bSCho, Yu-Chen /* The lower address bits of TBL are ignored. For TROO, TROT, it's
1728c9274b6bSCho, Yu-Chen the low 3 bits (double-word aligned). For TRTO, TRTT, it's either
1729c9274b6bSCho, Yu-Chen the low 12 bits (4K, without ETF2-ENH) or 3 bits (with ETF2-ENH). */
1730c9274b6bSCho, Yu-Chen if (ssize == 2 && !s390_has_feat(S390_FEAT_ETF2_ENH)) {
1731c9274b6bSCho, Yu-Chen tbl &= -4096;
1732c9274b6bSCho, Yu-Chen } else {
1733c9274b6bSCho, Yu-Chen tbl &= -8;
1734c9274b6bSCho, Yu-Chen }
1735c9274b6bSCho, Yu-Chen
1736c9274b6bSCho, Yu-Chen check_alignment(env, len, ssize, ra);
1737c9274b6bSCho, Yu-Chen
1738c9274b6bSCho, Yu-Chen /* Lest we fail to service interrupts in a timely manner, */
1739c9274b6bSCho, Yu-Chen /* limit the amount of work we're willing to do. */
1740c9274b6bSCho, Yu-Chen for (i = 0; i < 0x2000; i++) {
1741c9274b6bSCho, Yu-Chen uint16_t sval = cpu_ldusize_data_ra(env, src, ssize, ra);
1742c9274b6bSCho, Yu-Chen uint64_t tble = tbl + (sval * dsize);
1743c9274b6bSCho, Yu-Chen uint16_t dval = cpu_ldusize_data_ra(env, tble, dsize, ra);
1744c9274b6bSCho, Yu-Chen if (dval == tst) {
1745c9274b6bSCho, Yu-Chen cc = 1;
1746c9274b6bSCho, Yu-Chen break;
1747c9274b6bSCho, Yu-Chen }
1748c9274b6bSCho, Yu-Chen cpu_stsize_data_ra(env, dst, dval, dsize, ra);
1749c9274b6bSCho, Yu-Chen
1750c9274b6bSCho, Yu-Chen len -= ssize;
1751c9274b6bSCho, Yu-Chen src += ssize;
1752c9274b6bSCho, Yu-Chen dst += dsize;
1753c9274b6bSCho, Yu-Chen
1754c9274b6bSCho, Yu-Chen if (len == 0) {
1755c9274b6bSCho, Yu-Chen cc = 0;
1756c9274b6bSCho, Yu-Chen break;
1757c9274b6bSCho, Yu-Chen }
1758c9274b6bSCho, Yu-Chen }
1759c9274b6bSCho, Yu-Chen
1760c9274b6bSCho, Yu-Chen set_address(env, r1, dst);
1761c9274b6bSCho, Yu-Chen set_length(env, r1 + 1, len);
1762c9274b6bSCho, Yu-Chen set_address(env, r2, src);
1763c9274b6bSCho, Yu-Chen
1764c9274b6bSCho, Yu-Chen return cc;
1765c9274b6bSCho, Yu-Chen }
1766c9274b6bSCho, Yu-Chen
do_csst(CPUS390XState * env,uint32_t r3,uint64_t a1,uint64_t a2,bool parallel)1767c9274b6bSCho, Yu-Chen static uint32_t do_csst(CPUS390XState *env, uint32_t r3, uint64_t a1,
1768c9274b6bSCho, Yu-Chen uint64_t a2, bool parallel)
1769c9274b6bSCho, Yu-Chen {
177090b7022eSRichard Henderson uint32_t mem_idx = s390x_env_mmu_index(env, false);
1771ddc0ab5aSRichard Henderson MemOpIdx oi16 = make_memop_idx(MO_TE | MO_128, mem_idx);
1772ddc0ab5aSRichard Henderson MemOpIdx oi8 = make_memop_idx(MO_TE | MO_64, mem_idx);
1773ddc0ab5aSRichard Henderson MemOpIdx oi4 = make_memop_idx(MO_TE | MO_32, mem_idx);
1774ddc0ab5aSRichard Henderson MemOpIdx oi2 = make_memop_idx(MO_TE | MO_16, mem_idx);
1775ddc0ab5aSRichard Henderson MemOpIdx oi1 = make_memop_idx(MO_8, mem_idx);
1776c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
1777c9274b6bSCho, Yu-Chen uint32_t fc = extract32(env->regs[0], 0, 8);
1778c9274b6bSCho, Yu-Chen uint32_t sc = extract32(env->regs[0], 8, 8);
1779c9274b6bSCho, Yu-Chen uint64_t pl = get_address(env, 1) & -16;
1780c9274b6bSCho, Yu-Chen uint64_t svh, svl;
1781c9274b6bSCho, Yu-Chen uint32_t cc;
1782c9274b6bSCho, Yu-Chen
1783c9274b6bSCho, Yu-Chen /* Sanity check the function code and storage characteristic. */
1784c9274b6bSCho, Yu-Chen if (fc > 1 || sc > 3) {
1785c9274b6bSCho, Yu-Chen if (!s390_has_feat(S390_FEAT_COMPARE_AND_SWAP_AND_STORE_2)) {
1786c9274b6bSCho, Yu-Chen goto spec_exception;
1787c9274b6bSCho, Yu-Chen }
1788c9274b6bSCho, Yu-Chen if (fc > 2 || sc > 4 || (fc == 2 && (r3 & 1))) {
1789c9274b6bSCho, Yu-Chen goto spec_exception;
1790c9274b6bSCho, Yu-Chen }
1791c9274b6bSCho, Yu-Chen }
1792c9274b6bSCho, Yu-Chen
1793c9274b6bSCho, Yu-Chen /* Sanity check the alignments. */
1794c9274b6bSCho, Yu-Chen if (extract32(a1, 0, fc + 2) || extract32(a2, 0, sc)) {
1795c9274b6bSCho, Yu-Chen goto spec_exception;
1796c9274b6bSCho, Yu-Chen }
1797c9274b6bSCho, Yu-Chen
1798c9274b6bSCho, Yu-Chen /* Sanity check writability of the store address. */
1799c9274b6bSCho, Yu-Chen probe_write(env, a2, 1 << sc, mem_idx, ra);
1800c9274b6bSCho, Yu-Chen
1801c9274b6bSCho, Yu-Chen /*
1802c9274b6bSCho, Yu-Chen * Note that the compare-and-swap is atomic, and the store is atomic,
1803c9274b6bSCho, Yu-Chen * but the complete operation is not. Therefore we do not need to
1804c9274b6bSCho, Yu-Chen * assert serial context in order to implement this. That said,
1805c9274b6bSCho, Yu-Chen * restart early if we can't support either operation that is supposed
1806c9274b6bSCho, Yu-Chen * to be atomic.
1807c9274b6bSCho, Yu-Chen */
1808c9274b6bSCho, Yu-Chen if (parallel) {
1809c9274b6bSCho, Yu-Chen uint32_t max = 2;
1810c9274b6bSCho, Yu-Chen #ifdef CONFIG_ATOMIC64
1811c9274b6bSCho, Yu-Chen max = 3;
1812c9274b6bSCho, Yu-Chen #endif
1813c9274b6bSCho, Yu-Chen if ((HAVE_CMPXCHG128 ? 0 : fc + 2 > max) ||
181421c38f31SRichard Henderson (HAVE_ATOMIC128_RW ? 0 : sc > max)) {
1815c9274b6bSCho, Yu-Chen cpu_loop_exit_atomic(env_cpu(env), ra);
1816c9274b6bSCho, Yu-Chen }
1817c9274b6bSCho, Yu-Chen }
1818c9274b6bSCho, Yu-Chen
1819ddc0ab5aSRichard Henderson /*
1820ddc0ab5aSRichard Henderson * All loads happen before all stores. For simplicity, load the entire
1821ddc0ab5aSRichard Henderson * store value area from the parameter list.
1822ddc0ab5aSRichard Henderson */
1823ddc0ab5aSRichard Henderson svh = cpu_ldq_mmu(env, pl + 16, oi8, ra);
1824ddc0ab5aSRichard Henderson svl = cpu_ldq_mmu(env, pl + 24, oi8, ra);
1825c9274b6bSCho, Yu-Chen
1826c9274b6bSCho, Yu-Chen switch (fc) {
1827c9274b6bSCho, Yu-Chen case 0:
1828c9274b6bSCho, Yu-Chen {
1829ddc0ab5aSRichard Henderson uint32_t nv = cpu_ldl_mmu(env, pl, oi4, ra);
1830c9274b6bSCho, Yu-Chen uint32_t cv = env->regs[r3];
1831c9274b6bSCho, Yu-Chen uint32_t ov;
1832c9274b6bSCho, Yu-Chen
1833c9274b6bSCho, Yu-Chen if (parallel) {
183447ae3e40SRichard Henderson ov = cpu_atomic_cmpxchgl_be_mmu(env, a1, cv, nv, oi4, ra);
1835c9274b6bSCho, Yu-Chen } else {
1836ddc0ab5aSRichard Henderson ov = cpu_ldl_mmu(env, a1, oi4, ra);
1837ddc0ab5aSRichard Henderson cpu_stl_mmu(env, a1, (ov == cv ? nv : ov), oi4, ra);
1838c9274b6bSCho, Yu-Chen }
1839c9274b6bSCho, Yu-Chen cc = (ov != cv);
1840c9274b6bSCho, Yu-Chen env->regs[r3] = deposit64(env->regs[r3], 32, 32, ov);
1841c9274b6bSCho, Yu-Chen }
1842c9274b6bSCho, Yu-Chen break;
1843c9274b6bSCho, Yu-Chen
1844c9274b6bSCho, Yu-Chen case 1:
1845c9274b6bSCho, Yu-Chen {
1846ddc0ab5aSRichard Henderson uint64_t nv = cpu_ldq_mmu(env, pl, oi8, ra);
1847c9274b6bSCho, Yu-Chen uint64_t cv = env->regs[r3];
1848c9274b6bSCho, Yu-Chen uint64_t ov;
1849c9274b6bSCho, Yu-Chen
1850c9274b6bSCho, Yu-Chen if (parallel) {
1851c9274b6bSCho, Yu-Chen #ifdef CONFIG_ATOMIC64
1852ddc0ab5aSRichard Henderson ov = cpu_atomic_cmpxchgq_be_mmu(env, a1, cv, nv, oi8, ra);
1853c9274b6bSCho, Yu-Chen #else
1854c9274b6bSCho, Yu-Chen /* Note that we asserted !parallel above. */
1855c9274b6bSCho, Yu-Chen g_assert_not_reached();
1856c9274b6bSCho, Yu-Chen #endif
1857c9274b6bSCho, Yu-Chen } else {
1858ddc0ab5aSRichard Henderson ov = cpu_ldq_mmu(env, a1, oi8, ra);
1859ddc0ab5aSRichard Henderson cpu_stq_mmu(env, a1, (ov == cv ? nv : ov), oi8, ra);
1860c9274b6bSCho, Yu-Chen }
1861c9274b6bSCho, Yu-Chen cc = (ov != cv);
1862c9274b6bSCho, Yu-Chen env->regs[r3] = ov;
1863c9274b6bSCho, Yu-Chen }
1864c9274b6bSCho, Yu-Chen break;
1865c9274b6bSCho, Yu-Chen
1866c9274b6bSCho, Yu-Chen case 2:
1867c9274b6bSCho, Yu-Chen {
1868ddc0ab5aSRichard Henderson Int128 nv = cpu_ld16_mmu(env, pl, oi16, ra);
1869c9274b6bSCho, Yu-Chen Int128 cv = int128_make128(env->regs[r3 + 1], env->regs[r3]);
1870c9274b6bSCho, Yu-Chen Int128 ov;
1871c9274b6bSCho, Yu-Chen
1872c9274b6bSCho, Yu-Chen if (!parallel) {
1873ddc0ab5aSRichard Henderson ov = cpu_ld16_mmu(env, a1, oi16, ra);
1874c9274b6bSCho, Yu-Chen cc = !int128_eq(ov, cv);
1875c9274b6bSCho, Yu-Chen if (cc) {
1876c9274b6bSCho, Yu-Chen nv = ov;
1877c9274b6bSCho, Yu-Chen }
1878ddc0ab5aSRichard Henderson cpu_st16_mmu(env, a1, nv, oi16, ra);
1879c9274b6bSCho, Yu-Chen } else if (HAVE_CMPXCHG128) {
1880ddc0ab5aSRichard Henderson ov = cpu_atomic_cmpxchgo_be_mmu(env, a1, cv, nv, oi16, ra);
1881c9274b6bSCho, Yu-Chen cc = !int128_eq(ov, cv);
1882c9274b6bSCho, Yu-Chen } else {
1883c9274b6bSCho, Yu-Chen /* Note that we asserted !parallel above. */
1884c9274b6bSCho, Yu-Chen g_assert_not_reached();
1885c9274b6bSCho, Yu-Chen }
1886c9274b6bSCho, Yu-Chen
1887c9274b6bSCho, Yu-Chen env->regs[r3 + 0] = int128_gethi(ov);
1888c9274b6bSCho, Yu-Chen env->regs[r3 + 1] = int128_getlo(ov);
1889c9274b6bSCho, Yu-Chen }
1890c9274b6bSCho, Yu-Chen break;
1891c9274b6bSCho, Yu-Chen
1892c9274b6bSCho, Yu-Chen default:
1893c9274b6bSCho, Yu-Chen g_assert_not_reached();
1894c9274b6bSCho, Yu-Chen }
1895c9274b6bSCho, Yu-Chen
1896c9274b6bSCho, Yu-Chen /* Store only if the comparison succeeded. Note that above we use a pair
1897c9274b6bSCho, Yu-Chen of 64-bit big-endian loads, so for sc < 3 we must extract the value
1898c9274b6bSCho, Yu-Chen from the most-significant bits of svh. */
1899c9274b6bSCho, Yu-Chen if (cc == 0) {
1900c9274b6bSCho, Yu-Chen switch (sc) {
1901c9274b6bSCho, Yu-Chen case 0:
1902ddc0ab5aSRichard Henderson cpu_stb_mmu(env, a2, svh >> 56, oi1, ra);
1903c9274b6bSCho, Yu-Chen break;
1904c9274b6bSCho, Yu-Chen case 1:
1905ddc0ab5aSRichard Henderson cpu_stw_mmu(env, a2, svh >> 48, oi2, ra);
1906c9274b6bSCho, Yu-Chen break;
1907c9274b6bSCho, Yu-Chen case 2:
1908ddc0ab5aSRichard Henderson cpu_stl_mmu(env, a2, svh >> 32, oi4, ra);
1909c9274b6bSCho, Yu-Chen break;
1910c9274b6bSCho, Yu-Chen case 3:
1911ddc0ab5aSRichard Henderson cpu_stq_mmu(env, a2, svh, oi8, ra);
1912c9274b6bSCho, Yu-Chen break;
1913c9274b6bSCho, Yu-Chen case 4:
1914ddc0ab5aSRichard Henderson cpu_st16_mmu(env, a2, int128_make128(svl, svh), oi16, ra);
1915c9274b6bSCho, Yu-Chen break;
1916c9274b6bSCho, Yu-Chen default:
1917c9274b6bSCho, Yu-Chen g_assert_not_reached();
1918c9274b6bSCho, Yu-Chen }
1919c9274b6bSCho, Yu-Chen }
1920c9274b6bSCho, Yu-Chen
1921c9274b6bSCho, Yu-Chen return cc;
1922c9274b6bSCho, Yu-Chen
1923c9274b6bSCho, Yu-Chen spec_exception:
1924c9274b6bSCho, Yu-Chen tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
1925c9274b6bSCho, Yu-Chen }
1926c9274b6bSCho, Yu-Chen
HELPER(csst)1927c9274b6bSCho, Yu-Chen uint32_t HELPER(csst)(CPUS390XState *env, uint32_t r3, uint64_t a1, uint64_t a2)
1928c9274b6bSCho, Yu-Chen {
1929c9274b6bSCho, Yu-Chen return do_csst(env, r3, a1, a2, false);
1930c9274b6bSCho, Yu-Chen }
1931c9274b6bSCho, Yu-Chen
HELPER(csst_parallel)1932c9274b6bSCho, Yu-Chen uint32_t HELPER(csst_parallel)(CPUS390XState *env, uint32_t r3, uint64_t a1,
1933c9274b6bSCho, Yu-Chen uint64_t a2)
1934c9274b6bSCho, Yu-Chen {
1935c9274b6bSCho, Yu-Chen return do_csst(env, r3, a1, a2, true);
1936c9274b6bSCho, Yu-Chen }
1937c9274b6bSCho, Yu-Chen
1938c9274b6bSCho, Yu-Chen #if !defined(CONFIG_USER_ONLY)
HELPER(lctlg)1939c9274b6bSCho, Yu-Chen void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
1940c9274b6bSCho, Yu-Chen {
1941c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
1942c9274b6bSCho, Yu-Chen bool PERchanged = false;
1943c9274b6bSCho, Yu-Chen uint64_t src = a2;
1944c9274b6bSCho, Yu-Chen uint32_t i;
1945c9274b6bSCho, Yu-Chen
1946c9274b6bSCho, Yu-Chen if (src & 0x7) {
1947c9274b6bSCho, Yu-Chen tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
1948c9274b6bSCho, Yu-Chen }
1949c9274b6bSCho, Yu-Chen
1950c9274b6bSCho, Yu-Chen for (i = r1;; i = (i + 1) % 16) {
1951c9274b6bSCho, Yu-Chen uint64_t val = cpu_ldq_data_ra(env, src, ra);
1952c9274b6bSCho, Yu-Chen if (env->cregs[i] != val && i >= 9 && i <= 11) {
1953c9274b6bSCho, Yu-Chen PERchanged = true;
1954c9274b6bSCho, Yu-Chen }
1955c9274b6bSCho, Yu-Chen env->cregs[i] = val;
1956c9274b6bSCho, Yu-Chen HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
1957c9274b6bSCho, Yu-Chen i, src, val);
1958c9274b6bSCho, Yu-Chen src += sizeof(uint64_t);
1959c9274b6bSCho, Yu-Chen
1960c9274b6bSCho, Yu-Chen if (i == r3) {
1961c9274b6bSCho, Yu-Chen break;
1962c9274b6bSCho, Yu-Chen }
1963c9274b6bSCho, Yu-Chen }
1964c9274b6bSCho, Yu-Chen
1965c9274b6bSCho, Yu-Chen if (PERchanged && env->psw.mask & PSW_MASK_PER) {
1966c9274b6bSCho, Yu-Chen s390_cpu_recompute_watchpoints(env_cpu(env));
1967c9274b6bSCho, Yu-Chen }
1968c9274b6bSCho, Yu-Chen
1969c9274b6bSCho, Yu-Chen tlb_flush(env_cpu(env));
1970c9274b6bSCho, Yu-Chen }
1971c9274b6bSCho, Yu-Chen
HELPER(lctl)1972c9274b6bSCho, Yu-Chen void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
1973c9274b6bSCho, Yu-Chen {
1974c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
1975c9274b6bSCho, Yu-Chen bool PERchanged = false;
1976c9274b6bSCho, Yu-Chen uint64_t src = a2;
1977c9274b6bSCho, Yu-Chen uint32_t i;
1978c9274b6bSCho, Yu-Chen
1979c9274b6bSCho, Yu-Chen if (src & 0x3) {
1980c9274b6bSCho, Yu-Chen tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
1981c9274b6bSCho, Yu-Chen }
1982c9274b6bSCho, Yu-Chen
1983c9274b6bSCho, Yu-Chen for (i = r1;; i = (i + 1) % 16) {
1984c9274b6bSCho, Yu-Chen uint32_t val = cpu_ldl_data_ra(env, src, ra);
1985c9274b6bSCho, Yu-Chen if ((uint32_t)env->cregs[i] != val && i >= 9 && i <= 11) {
1986c9274b6bSCho, Yu-Chen PERchanged = true;
1987c9274b6bSCho, Yu-Chen }
1988c9274b6bSCho, Yu-Chen env->cregs[i] = deposit64(env->cregs[i], 0, 32, val);
1989c9274b6bSCho, Yu-Chen HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%x\n", i, src, val);
1990c9274b6bSCho, Yu-Chen src += sizeof(uint32_t);
1991c9274b6bSCho, Yu-Chen
1992c9274b6bSCho, Yu-Chen if (i == r3) {
1993c9274b6bSCho, Yu-Chen break;
1994c9274b6bSCho, Yu-Chen }
1995c9274b6bSCho, Yu-Chen }
1996c9274b6bSCho, Yu-Chen
1997c9274b6bSCho, Yu-Chen if (PERchanged && env->psw.mask & PSW_MASK_PER) {
1998c9274b6bSCho, Yu-Chen s390_cpu_recompute_watchpoints(env_cpu(env));
1999c9274b6bSCho, Yu-Chen }
2000c9274b6bSCho, Yu-Chen
2001c9274b6bSCho, Yu-Chen tlb_flush(env_cpu(env));
2002c9274b6bSCho, Yu-Chen }
2003c9274b6bSCho, Yu-Chen
HELPER(stctg)2004c9274b6bSCho, Yu-Chen void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
2005c9274b6bSCho, Yu-Chen {
2006c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
2007c9274b6bSCho, Yu-Chen uint64_t dest = a2;
2008c9274b6bSCho, Yu-Chen uint32_t i;
2009c9274b6bSCho, Yu-Chen
2010c9274b6bSCho, Yu-Chen if (dest & 0x7) {
2011c9274b6bSCho, Yu-Chen tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
2012c9274b6bSCho, Yu-Chen }
2013c9274b6bSCho, Yu-Chen
2014c9274b6bSCho, Yu-Chen for (i = r1;; i = (i + 1) % 16) {
2015c9274b6bSCho, Yu-Chen cpu_stq_data_ra(env, dest, env->cregs[i], ra);
2016c9274b6bSCho, Yu-Chen dest += sizeof(uint64_t);
2017c9274b6bSCho, Yu-Chen
2018c9274b6bSCho, Yu-Chen if (i == r3) {
2019c9274b6bSCho, Yu-Chen break;
2020c9274b6bSCho, Yu-Chen }
2021c9274b6bSCho, Yu-Chen }
2022c9274b6bSCho, Yu-Chen }
2023c9274b6bSCho, Yu-Chen
HELPER(stctl)2024c9274b6bSCho, Yu-Chen void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
2025c9274b6bSCho, Yu-Chen {
2026c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
2027c9274b6bSCho, Yu-Chen uint64_t dest = a2;
2028c9274b6bSCho, Yu-Chen uint32_t i;
2029c9274b6bSCho, Yu-Chen
2030c9274b6bSCho, Yu-Chen if (dest & 0x3) {
2031c9274b6bSCho, Yu-Chen tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
2032c9274b6bSCho, Yu-Chen }
2033c9274b6bSCho, Yu-Chen
2034c9274b6bSCho, Yu-Chen for (i = r1;; i = (i + 1) % 16) {
2035c9274b6bSCho, Yu-Chen cpu_stl_data_ra(env, dest, env->cregs[i], ra);
2036c9274b6bSCho, Yu-Chen dest += sizeof(uint32_t);
2037c9274b6bSCho, Yu-Chen
2038c9274b6bSCho, Yu-Chen if (i == r3) {
2039c9274b6bSCho, Yu-Chen break;
2040c9274b6bSCho, Yu-Chen }
2041c9274b6bSCho, Yu-Chen }
2042c9274b6bSCho, Yu-Chen }
2043c9274b6bSCho, Yu-Chen
HELPER(testblock)2044c9274b6bSCho, Yu-Chen uint32_t HELPER(testblock)(CPUS390XState *env, uint64_t real_addr)
2045c9274b6bSCho, Yu-Chen {
2046c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
2047c9274b6bSCho, Yu-Chen int i;
2048c9274b6bSCho, Yu-Chen
2049c9274b6bSCho, Yu-Chen real_addr = wrap_address(env, real_addr) & TARGET_PAGE_MASK;
2050c9274b6bSCho, Yu-Chen
2051c9274b6bSCho, Yu-Chen for (i = 0; i < TARGET_PAGE_SIZE; i += 8) {
2052c9274b6bSCho, Yu-Chen cpu_stq_mmuidx_ra(env, real_addr + i, 0, MMU_REAL_IDX, ra);
2053c9274b6bSCho, Yu-Chen }
2054c9274b6bSCho, Yu-Chen
2055c9274b6bSCho, Yu-Chen return 0;
2056c9274b6bSCho, Yu-Chen }
2057c9274b6bSCho, Yu-Chen
HELPER(tprot)2058c9274b6bSCho, Yu-Chen uint32_t HELPER(tprot)(CPUS390XState *env, uint64_t a1, uint64_t a2)
2059c9274b6bSCho, Yu-Chen {
2060c9274b6bSCho, Yu-Chen S390CPU *cpu = env_archcpu(env);
2061c9274b6bSCho, Yu-Chen CPUState *cs = env_cpu(env);
2062c9274b6bSCho, Yu-Chen
2063c9274b6bSCho, Yu-Chen /*
2064c9274b6bSCho, Yu-Chen * TODO: we currently don't handle all access protection types
2065c9274b6bSCho, Yu-Chen * (including access-list and key-controlled) as well as AR mode.
2066c9274b6bSCho, Yu-Chen */
2067c9274b6bSCho, Yu-Chen if (!s390_cpu_virt_mem_check_write(cpu, a1, 0, 1)) {
2068c9274b6bSCho, Yu-Chen /* Fetching permitted; storing permitted */
2069c9274b6bSCho, Yu-Chen return 0;
2070c9274b6bSCho, Yu-Chen }
2071c9274b6bSCho, Yu-Chen
2072c9274b6bSCho, Yu-Chen if (env->int_pgm_code == PGM_PROTECTION) {
2073c9274b6bSCho, Yu-Chen /* retry if reading is possible */
2074c9274b6bSCho, Yu-Chen cs->exception_index = -1;
2075c9274b6bSCho, Yu-Chen if (!s390_cpu_virt_mem_check_read(cpu, a1, 0, 1)) {
2076c9274b6bSCho, Yu-Chen /* Fetching permitted; storing not permitted */
2077c9274b6bSCho, Yu-Chen return 1;
2078c9274b6bSCho, Yu-Chen }
2079c9274b6bSCho, Yu-Chen }
2080c9274b6bSCho, Yu-Chen
2081c9274b6bSCho, Yu-Chen switch (env->int_pgm_code) {
2082c9274b6bSCho, Yu-Chen case PGM_PROTECTION:
2083c9274b6bSCho, Yu-Chen /* Fetching not permitted; storing not permitted */
2084c9274b6bSCho, Yu-Chen cs->exception_index = -1;
2085c9274b6bSCho, Yu-Chen return 2;
2086c9274b6bSCho, Yu-Chen case PGM_ADDRESSING:
2087c9274b6bSCho, Yu-Chen case PGM_TRANS_SPEC:
2088c9274b6bSCho, Yu-Chen /* exceptions forwarded to the guest */
2089c9274b6bSCho, Yu-Chen s390_cpu_virt_mem_handle_exc(cpu, GETPC());
2090c9274b6bSCho, Yu-Chen return 0;
2091c9274b6bSCho, Yu-Chen }
2092c9274b6bSCho, Yu-Chen
2093c9274b6bSCho, Yu-Chen /* Translation not available */
2094c9274b6bSCho, Yu-Chen cs->exception_index = -1;
2095c9274b6bSCho, Yu-Chen return 3;
2096c9274b6bSCho, Yu-Chen }
2097c9274b6bSCho, Yu-Chen
2098c9274b6bSCho, Yu-Chen /* insert storage key extended */
HELPER(iske)2099c9274b6bSCho, Yu-Chen uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2)
2100c9274b6bSCho, Yu-Chen {
2101c9274b6bSCho, Yu-Chen static S390SKeysState *ss;
2102c9274b6bSCho, Yu-Chen static S390SKeysClass *skeyclass;
2103c9274b6bSCho, Yu-Chen uint64_t addr = wrap_address(env, r2);
2104c9274b6bSCho, Yu-Chen uint8_t key;
2105eaa0feeaSDavid Hildenbrand int rc;
2106c9274b6bSCho, Yu-Chen
210706d8a10aSDavid Hildenbrand addr = mmu_real2abs(env, addr);
2108eaa0feeaSDavid Hildenbrand if (!mmu_absolute_addr_valid(addr, false)) {
2109eaa0feeaSDavid Hildenbrand tcg_s390_program_interrupt(env, PGM_ADDRESSING, GETPC());
2110c9274b6bSCho, Yu-Chen }
2111c9274b6bSCho, Yu-Chen
2112c9274b6bSCho, Yu-Chen if (unlikely(!ss)) {
2113c9274b6bSCho, Yu-Chen ss = s390_get_skeys_device();
2114c9274b6bSCho, Yu-Chen skeyclass = S390_SKEYS_GET_CLASS(ss);
2115c3562238SDavid Hildenbrand if (skeyclass->enable_skeys && !skeyclass->enable_skeys(ss)) {
2116c3562238SDavid Hildenbrand tlb_flush_all_cpus_synced(env_cpu(env));
2117c3562238SDavid Hildenbrand }
2118c9274b6bSCho, Yu-Chen }
2119c9274b6bSCho, Yu-Chen
21204860af2cSPhilippe Mathieu-Daudé rc = s390_skeys_get(ss, addr / TARGET_PAGE_SIZE, 1, &key);
2121eaa0feeaSDavid Hildenbrand if (rc) {
2122c9274b6bSCho, Yu-Chen return 0;
2123c9274b6bSCho, Yu-Chen }
2124c9274b6bSCho, Yu-Chen return key;
2125c9274b6bSCho, Yu-Chen }
2126c9274b6bSCho, Yu-Chen
2127c9274b6bSCho, Yu-Chen /* set storage key extended */
HELPER(sske)2128c9274b6bSCho, Yu-Chen void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2)
2129c9274b6bSCho, Yu-Chen {
2130c9274b6bSCho, Yu-Chen static S390SKeysState *ss;
2131c9274b6bSCho, Yu-Chen static S390SKeysClass *skeyclass;
2132c9274b6bSCho, Yu-Chen uint64_t addr = wrap_address(env, r2);
2133c9274b6bSCho, Yu-Chen uint8_t key;
2134c9274b6bSCho, Yu-Chen
213506d8a10aSDavid Hildenbrand addr = mmu_real2abs(env, addr);
2136eaa0feeaSDavid Hildenbrand if (!mmu_absolute_addr_valid(addr, false)) {
2137eaa0feeaSDavid Hildenbrand tcg_s390_program_interrupt(env, PGM_ADDRESSING, GETPC());
2138c9274b6bSCho, Yu-Chen }
2139c9274b6bSCho, Yu-Chen
2140c9274b6bSCho, Yu-Chen if (unlikely(!ss)) {
2141c9274b6bSCho, Yu-Chen ss = s390_get_skeys_device();
2142c9274b6bSCho, Yu-Chen skeyclass = S390_SKEYS_GET_CLASS(ss);
2143c3562238SDavid Hildenbrand if (skeyclass->enable_skeys && !skeyclass->enable_skeys(ss)) {
2144c3562238SDavid Hildenbrand tlb_flush_all_cpus_synced(env_cpu(env));
2145c3562238SDavid Hildenbrand }
2146c9274b6bSCho, Yu-Chen }
2147c9274b6bSCho, Yu-Chen
2148fe00c705SDavid Hildenbrand key = r1 & 0xfe;
21494860af2cSPhilippe Mathieu-Daudé s390_skeys_set(ss, addr / TARGET_PAGE_SIZE, 1, &key);
2150c9274b6bSCho, Yu-Chen /*
2151c9274b6bSCho, Yu-Chen * As we can only flush by virtual address and not all the entries
2152c9274b6bSCho, Yu-Chen * that point to a physical address we have to flush the whole TLB.
2153c9274b6bSCho, Yu-Chen */
2154c9274b6bSCho, Yu-Chen tlb_flush_all_cpus_synced(env_cpu(env));
2155c9274b6bSCho, Yu-Chen }
2156c9274b6bSCho, Yu-Chen
2157c9274b6bSCho, Yu-Chen /* reset reference bit extended */
HELPER(rrbe)2158c9274b6bSCho, Yu-Chen uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2)
2159c9274b6bSCho, Yu-Chen {
2160634a0b51SDavid Hildenbrand uint64_t addr = wrap_address(env, r2);
2161c9274b6bSCho, Yu-Chen static S390SKeysState *ss;
2162c9274b6bSCho, Yu-Chen static S390SKeysClass *skeyclass;
2163c9274b6bSCho, Yu-Chen uint8_t re, key;
2164eaa0feeaSDavid Hildenbrand int rc;
2165c9274b6bSCho, Yu-Chen
216606d8a10aSDavid Hildenbrand addr = mmu_real2abs(env, addr);
2167eaa0feeaSDavid Hildenbrand if (!mmu_absolute_addr_valid(addr, false)) {
2168eaa0feeaSDavid Hildenbrand tcg_s390_program_interrupt(env, PGM_ADDRESSING, GETPC());
2169c9274b6bSCho, Yu-Chen }
2170c9274b6bSCho, Yu-Chen
2171c9274b6bSCho, Yu-Chen if (unlikely(!ss)) {
2172c9274b6bSCho, Yu-Chen ss = s390_get_skeys_device();
2173c9274b6bSCho, Yu-Chen skeyclass = S390_SKEYS_GET_CLASS(ss);
2174c3562238SDavid Hildenbrand if (skeyclass->enable_skeys && !skeyclass->enable_skeys(ss)) {
2175c3562238SDavid Hildenbrand tlb_flush_all_cpus_synced(env_cpu(env));
2176c3562238SDavid Hildenbrand }
2177c9274b6bSCho, Yu-Chen }
2178c9274b6bSCho, Yu-Chen
21794860af2cSPhilippe Mathieu-Daudé rc = s390_skeys_get(ss, addr / TARGET_PAGE_SIZE, 1, &key);
2180eaa0feeaSDavid Hildenbrand if (rc) {
2181c9274b6bSCho, Yu-Chen return 0;
2182c9274b6bSCho, Yu-Chen }
2183c9274b6bSCho, Yu-Chen
2184c9274b6bSCho, Yu-Chen re = key & (SK_R | SK_C);
2185c9274b6bSCho, Yu-Chen key &= ~SK_R;
2186c9274b6bSCho, Yu-Chen
21874860af2cSPhilippe Mathieu-Daudé rc = s390_skeys_set(ss, addr / TARGET_PAGE_SIZE, 1, &key);
2188eaa0feeaSDavid Hildenbrand if (rc) {
2189c9274b6bSCho, Yu-Chen return 0;
2190c9274b6bSCho, Yu-Chen }
2191c9274b6bSCho, Yu-Chen /*
2192c9274b6bSCho, Yu-Chen * As we can only flush by virtual address and not all the entries
2193c9274b6bSCho, Yu-Chen * that point to a physical address we have to flush the whole TLB.
2194c9274b6bSCho, Yu-Chen */
2195c9274b6bSCho, Yu-Chen tlb_flush_all_cpus_synced(env_cpu(env));
2196c9274b6bSCho, Yu-Chen
2197c9274b6bSCho, Yu-Chen /*
2198c9274b6bSCho, Yu-Chen * cc
2199c9274b6bSCho, Yu-Chen *
2200c9274b6bSCho, Yu-Chen * 0 Reference bit zero; change bit zero
2201c9274b6bSCho, Yu-Chen * 1 Reference bit zero; change bit one
2202c9274b6bSCho, Yu-Chen * 2 Reference bit one; change bit zero
2203c9274b6bSCho, Yu-Chen * 3 Reference bit one; change bit one
2204c9274b6bSCho, Yu-Chen */
2205c9274b6bSCho, Yu-Chen
2206c9274b6bSCho, Yu-Chen return re >> 1;
2207c9274b6bSCho, Yu-Chen }
2208c9274b6bSCho, Yu-Chen
HELPER(mvcs)22093ef473e5SThomas Huth uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2,
22103ef473e5SThomas Huth uint64_t key)
2211c9274b6bSCho, Yu-Chen {
2212c9274b6bSCho, Yu-Chen const uint8_t psw_as = (env->psw.mask & PSW_MASK_ASC) >> PSW_SHIFT_ASC;
2213c9274b6bSCho, Yu-Chen S390Access srca, desta;
2214c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
2215c9274b6bSCho, Yu-Chen int cc = 0;
2216c9274b6bSCho, Yu-Chen
2217c9274b6bSCho, Yu-Chen HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
2218c9274b6bSCho, Yu-Chen __func__, l, a1, a2);
2219c9274b6bSCho, Yu-Chen
2220c9274b6bSCho, Yu-Chen if (!(env->psw.mask & PSW_MASK_DAT) || !(env->cregs[0] & CR0_SECONDARY) ||
2221c9274b6bSCho, Yu-Chen psw_as == AS_HOME || psw_as == AS_ACCREG) {
2222c9274b6bSCho, Yu-Chen s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
2223c9274b6bSCho, Yu-Chen }
2224c9274b6bSCho, Yu-Chen
22253ef473e5SThomas Huth if (!psw_key_valid(env, (key >> 4) & 0xf)) {
22263ef473e5SThomas Huth s390_program_interrupt(env, PGM_PRIVILEGED, ra);
22273ef473e5SThomas Huth }
22283ef473e5SThomas Huth
2229c9274b6bSCho, Yu-Chen l = wrap_length32(env, l);
2230c9274b6bSCho, Yu-Chen if (l > 256) {
2231c9274b6bSCho, Yu-Chen /* max 256 */
2232c9274b6bSCho, Yu-Chen l = 256;
2233c9274b6bSCho, Yu-Chen cc = 3;
2234c9274b6bSCho, Yu-Chen } else if (!l) {
2235c9274b6bSCho, Yu-Chen return cc;
2236c9274b6bSCho, Yu-Chen }
2237c9274b6bSCho, Yu-Chen
22387ba5da81SRichard Henderson access_prepare(&srca, env, a2, l, MMU_DATA_LOAD, MMU_PRIMARY_IDX, ra);
22397ba5da81SRichard Henderson access_prepare(&desta, env, a1, l, MMU_DATA_STORE, MMU_SECONDARY_IDX, ra);
2240c9274b6bSCho, Yu-Chen access_memmove(env, &desta, &srca, ra);
2241c9274b6bSCho, Yu-Chen return cc;
2242c9274b6bSCho, Yu-Chen }
2243c9274b6bSCho, Yu-Chen
HELPER(mvcp)22443ef473e5SThomas Huth uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2,
22453ef473e5SThomas Huth uint64_t key)
2246c9274b6bSCho, Yu-Chen {
2247c9274b6bSCho, Yu-Chen const uint8_t psw_as = (env->psw.mask & PSW_MASK_ASC) >> PSW_SHIFT_ASC;
2248c9274b6bSCho, Yu-Chen S390Access srca, desta;
2249c9274b6bSCho, Yu-Chen uintptr_t ra = GETPC();
2250c9274b6bSCho, Yu-Chen int cc = 0;
2251c9274b6bSCho, Yu-Chen
2252c9274b6bSCho, Yu-Chen HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
2253c9274b6bSCho, Yu-Chen __func__, l, a1, a2);
2254c9274b6bSCho, Yu-Chen
2255c9274b6bSCho, Yu-Chen if (!(env->psw.mask & PSW_MASK_DAT) || !(env->cregs[0] & CR0_SECONDARY) ||
2256c9274b6bSCho, Yu-Chen psw_as == AS_HOME || psw_as == AS_ACCREG) {
2257c9274b6bSCho, Yu-Chen s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
2258c9274b6bSCho, Yu-Chen }
2259c9274b6bSCho, Yu-Chen
22603ef473e5SThomas Huth if (!psw_key_valid(env, (key >> 4) & 0xf)) {
22613ef473e5SThomas Huth s390_program_interrupt(env, PGM_PRIVILEGED, ra);
22623ef473e5SThomas Huth }
22633ef473e5SThomas Huth
2264c9274b6bSCho, Yu-Chen l = wrap_length32(env, l);
2265c9274b6bSCho, Yu-Chen if (l > 256) {
2266c9274b6bSCho, Yu-Chen /* max 256 */
2267c9274b6bSCho, Yu-Chen l = 256;
2268c9274b6bSCho, Yu-Chen cc = 3;
2269c9274b6bSCho, Yu-Chen } else if (!l) {
2270c9274b6bSCho, Yu-Chen return cc;
2271c9274b6bSCho, Yu-Chen }
22727ba5da81SRichard Henderson access_prepare(&srca, env, a2, l, MMU_DATA_LOAD, MMU_SECONDARY_IDX, ra);
22737ba5da81SRichard Henderson access_prepare(&desta, env, a1, l, MMU_DATA_STORE, MMU_PRIMARY_IDX, ra);
2274c9274b6bSCho, Yu-Chen access_memmove(env, &desta, &srca, ra);
2275c9274b6bSCho, Yu-Chen return cc;
2276c9274b6bSCho, Yu-Chen }
2277c9274b6bSCho, Yu-Chen
HELPER(idte)2278c9274b6bSCho, Yu-Chen void HELPER(idte)(CPUS390XState *env, uint64_t r1, uint64_t r2, uint32_t m4)
2279c9274b6bSCho, Yu-Chen {
2280c9274b6bSCho, Yu-Chen CPUState *cs = env_cpu(env);
2281c9274b6bSCho, Yu-Chen const uintptr_t ra = GETPC();
2282c9274b6bSCho, Yu-Chen uint64_t table, entry, raddr;
2283c9274b6bSCho, Yu-Chen uint16_t entries, i, index = 0;
2284c9274b6bSCho, Yu-Chen
2285c9274b6bSCho, Yu-Chen if (r2 & 0xff000) {
2286c9274b6bSCho, Yu-Chen tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
2287c9274b6bSCho, Yu-Chen }
2288c9274b6bSCho, Yu-Chen
2289c9274b6bSCho, Yu-Chen if (!(r2 & 0x800)) {
2290c9274b6bSCho, Yu-Chen /* invalidation-and-clearing operation */
2291c9274b6bSCho, Yu-Chen table = r1 & ASCE_ORIGIN;
2292c9274b6bSCho, Yu-Chen entries = (r2 & 0x7ff) + 1;
2293c9274b6bSCho, Yu-Chen
2294c9274b6bSCho, Yu-Chen switch (r1 & ASCE_TYPE_MASK) {
2295c9274b6bSCho, Yu-Chen case ASCE_TYPE_REGION1:
2296c9274b6bSCho, Yu-Chen index = (r2 >> 53) & 0x7ff;
2297c9274b6bSCho, Yu-Chen break;
2298c9274b6bSCho, Yu-Chen case ASCE_TYPE_REGION2:
2299c9274b6bSCho, Yu-Chen index = (r2 >> 42) & 0x7ff;
2300c9274b6bSCho, Yu-Chen break;
2301c9274b6bSCho, Yu-Chen case ASCE_TYPE_REGION3:
2302c9274b6bSCho, Yu-Chen index = (r2 >> 31) & 0x7ff;
2303c9274b6bSCho, Yu-Chen break;
2304c9274b6bSCho, Yu-Chen case ASCE_TYPE_SEGMENT:
2305c9274b6bSCho, Yu-Chen index = (r2 >> 20) & 0x7ff;
2306c9274b6bSCho, Yu-Chen break;
2307c9274b6bSCho, Yu-Chen }
2308c9274b6bSCho, Yu-Chen for (i = 0; i < entries; i++) {
2309c9274b6bSCho, Yu-Chen /* addresses are not wrapped in 24/31bit mode but table index is */
2310c9274b6bSCho, Yu-Chen raddr = table + ((index + i) & 0x7ff) * sizeof(entry);
2311c9274b6bSCho, Yu-Chen entry = cpu_ldq_mmuidx_ra(env, raddr, MMU_REAL_IDX, ra);
2312c9274b6bSCho, Yu-Chen if (!(entry & REGION_ENTRY_I)) {
2313c9274b6bSCho, Yu-Chen /* we are allowed to not store if already invalid */
2314c9274b6bSCho, Yu-Chen entry |= REGION_ENTRY_I;
2315c9274b6bSCho, Yu-Chen cpu_stq_mmuidx_ra(env, raddr, entry, MMU_REAL_IDX, ra);
2316c9274b6bSCho, Yu-Chen }
2317c9274b6bSCho, Yu-Chen }
2318c9274b6bSCho, Yu-Chen }
2319c9274b6bSCho, Yu-Chen
2320c9274b6bSCho, Yu-Chen /* We simply flush the complete tlb, therefore we can ignore r3. */
2321c9274b6bSCho, Yu-Chen if (m4 & 1) {
2322c9274b6bSCho, Yu-Chen tlb_flush(cs);
2323c9274b6bSCho, Yu-Chen } else {
2324c9274b6bSCho, Yu-Chen tlb_flush_all_cpus_synced(cs);
2325c9274b6bSCho, Yu-Chen }
2326c9274b6bSCho, Yu-Chen }
2327c9274b6bSCho, Yu-Chen
2328c9274b6bSCho, Yu-Chen /* invalidate pte */
HELPER(ipte)2329c9274b6bSCho, Yu-Chen void HELPER(ipte)(CPUS390XState *env, uint64_t pto, uint64_t vaddr,
2330c9274b6bSCho, Yu-Chen uint32_t m4)
2331c9274b6bSCho, Yu-Chen {
2332c9274b6bSCho, Yu-Chen CPUState *cs = env_cpu(env);
2333c9274b6bSCho, Yu-Chen const uintptr_t ra = GETPC();
2334c9274b6bSCho, Yu-Chen uint64_t page = vaddr & TARGET_PAGE_MASK;
2335c9274b6bSCho, Yu-Chen uint64_t pte_addr, pte;
2336c9274b6bSCho, Yu-Chen
2337c9274b6bSCho, Yu-Chen /* Compute the page table entry address */
2338c9274b6bSCho, Yu-Chen pte_addr = (pto & SEGMENT_ENTRY_ORIGIN);
2339c9274b6bSCho, Yu-Chen pte_addr += VADDR_PAGE_TX(vaddr) * 8;
2340c9274b6bSCho, Yu-Chen
2341c9274b6bSCho, Yu-Chen /* Mark the page table entry as invalid */
2342c9274b6bSCho, Yu-Chen pte = cpu_ldq_mmuidx_ra(env, pte_addr, MMU_REAL_IDX, ra);
2343c9274b6bSCho, Yu-Chen pte |= PAGE_ENTRY_I;
2344c9274b6bSCho, Yu-Chen cpu_stq_mmuidx_ra(env, pte_addr, pte, MMU_REAL_IDX, ra);
2345c9274b6bSCho, Yu-Chen
2346c9274b6bSCho, Yu-Chen /* XXX we exploit the fact that Linux passes the exact virtual
2347c9274b6bSCho, Yu-Chen address here - it's not obliged to! */
2348c9274b6bSCho, Yu-Chen if (m4 & 1) {
2349c9274b6bSCho, Yu-Chen if (vaddr & ~VADDR_PAGE_TX_MASK) {
2350c9274b6bSCho, Yu-Chen tlb_flush_page(cs, page);
2351c9274b6bSCho, Yu-Chen /* XXX 31-bit hack */
2352c9274b6bSCho, Yu-Chen tlb_flush_page(cs, page ^ 0x80000000);
2353c9274b6bSCho, Yu-Chen } else {
2354c9274b6bSCho, Yu-Chen /* looks like we don't have a valid virtual address */
2355c9274b6bSCho, Yu-Chen tlb_flush(cs);
2356c9274b6bSCho, Yu-Chen }
2357c9274b6bSCho, Yu-Chen } else {
2358c9274b6bSCho, Yu-Chen if (vaddr & ~VADDR_PAGE_TX_MASK) {
2359c9274b6bSCho, Yu-Chen tlb_flush_page_all_cpus_synced(cs, page);
2360c9274b6bSCho, Yu-Chen /* XXX 31-bit hack */
2361c9274b6bSCho, Yu-Chen tlb_flush_page_all_cpus_synced(cs, page ^ 0x80000000);
2362c9274b6bSCho, Yu-Chen } else {
2363c9274b6bSCho, Yu-Chen /* looks like we don't have a valid virtual address */
2364c9274b6bSCho, Yu-Chen tlb_flush_all_cpus_synced(cs);
2365c9274b6bSCho, Yu-Chen }
2366c9274b6bSCho, Yu-Chen }
2367c9274b6bSCho, Yu-Chen }
2368c9274b6bSCho, Yu-Chen
2369c9274b6bSCho, Yu-Chen /* flush local tlb */
HELPER(ptlb)2370c9274b6bSCho, Yu-Chen void HELPER(ptlb)(CPUS390XState *env)
2371c9274b6bSCho, Yu-Chen {
2372c9274b6bSCho, Yu-Chen tlb_flush(env_cpu(env));
2373c9274b6bSCho, Yu-Chen }
2374c9274b6bSCho, Yu-Chen
2375c9274b6bSCho, Yu-Chen /* flush global tlb */
HELPER(purge)2376c9274b6bSCho, Yu-Chen void HELPER(purge)(CPUS390XState *env)
2377c9274b6bSCho, Yu-Chen {
2378c9274b6bSCho, Yu-Chen tlb_flush_all_cpus_synced(env_cpu(env));
2379c9274b6bSCho, Yu-Chen }
2380c9274b6bSCho, Yu-Chen
2381c9274b6bSCho, Yu-Chen /* load real address */
HELPER(lra)23826da311a6SIlya Leoshkevich uint64_t HELPER(lra)(CPUS390XState *env, uint64_t r1, uint64_t addr)
2383c9274b6bSCho, Yu-Chen {
2384c9274b6bSCho, Yu-Chen uint64_t asc = env->psw.mask & PSW_MASK_ASC;
2385c9274b6bSCho, Yu-Chen uint64_t ret, tec;
2386c9274b6bSCho, Yu-Chen int flags, exc, cc;
2387c9274b6bSCho, Yu-Chen
2388c9274b6bSCho, Yu-Chen /* XXX incomplete - has more corner cases */
2389c9274b6bSCho, Yu-Chen if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
2390c9274b6bSCho, Yu-Chen tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, GETPC());
2391c9274b6bSCho, Yu-Chen }
2392c9274b6bSCho, Yu-Chen
2393390191c6SDavid Hildenbrand exc = mmu_translate(env, addr, MMU_S390_LRA, asc, &ret, &flags, &tec);
2394c9274b6bSCho, Yu-Chen if (exc) {
2395c9274b6bSCho, Yu-Chen cc = 3;
23966da311a6SIlya Leoshkevich ret = (r1 & 0xFFFFFFFF00000000ULL) | exc | 0x80000000;
2397c9274b6bSCho, Yu-Chen } else {
2398c9274b6bSCho, Yu-Chen cc = 0;
2399c9274b6bSCho, Yu-Chen ret |= addr & ~TARGET_PAGE_MASK;
2400c9274b6bSCho, Yu-Chen }
2401c9274b6bSCho, Yu-Chen
2402c9274b6bSCho, Yu-Chen env->cc_op = cc;
2403c9274b6bSCho, Yu-Chen return ret;
2404c9274b6bSCho, Yu-Chen }
2405c9274b6bSCho, Yu-Chen #endif
2406c9274b6bSCho, Yu-Chen
2407c9274b6bSCho, Yu-Chen /* Execute instruction. This instruction executes an insn modified with
2408c9274b6bSCho, Yu-Chen the contents of r1. It does not change the executed instruction in memory;
2409c9274b6bSCho, Yu-Chen it does not change the program counter.
2410c9274b6bSCho, Yu-Chen
2411c9274b6bSCho, Yu-Chen Perform this by recording the modified instruction in env->ex_value.
2412c9274b6bSCho, Yu-Chen This will be noticed by cpu_get_tb_cpu_state and thus tb translation.
2413c9274b6bSCho, Yu-Chen */
HELPER(ex)2414c9274b6bSCho, Yu-Chen void HELPER(ex)(CPUS390XState *env, uint32_t ilen, uint64_t r1, uint64_t addr)
2415c9274b6bSCho, Yu-Chen {
2416ce7ca269SIlya Leoshkevich uint64_t insn;
2417ce7ca269SIlya Leoshkevich uint8_t opc;
2418ce7ca269SIlya Leoshkevich
2419ce7ca269SIlya Leoshkevich /* EXECUTE targets must be at even addresses. */
2420ce7ca269SIlya Leoshkevich if (addr & 1) {
2421ce7ca269SIlya Leoshkevich tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
2422ce7ca269SIlya Leoshkevich }
2423ce7ca269SIlya Leoshkevich
2424ce7ca269SIlya Leoshkevich insn = cpu_lduw_code(env, addr);
2425ce7ca269SIlya Leoshkevich opc = insn >> 8;
2426c9274b6bSCho, Yu-Chen
2427c9274b6bSCho, Yu-Chen /* Or in the contents of R1[56:63]. */
2428c9274b6bSCho, Yu-Chen insn |= r1 & 0xff;
2429c9274b6bSCho, Yu-Chen
2430c9274b6bSCho, Yu-Chen /* Load the rest of the instruction. */
2431c9274b6bSCho, Yu-Chen insn <<= 48;
2432c9274b6bSCho, Yu-Chen switch (get_ilen(opc)) {
2433c9274b6bSCho, Yu-Chen case 2:
2434c9274b6bSCho, Yu-Chen break;
2435c9274b6bSCho, Yu-Chen case 4:
2436c9274b6bSCho, Yu-Chen insn |= (uint64_t)cpu_lduw_code(env, addr + 2) << 32;
2437c9274b6bSCho, Yu-Chen break;
2438c9274b6bSCho, Yu-Chen case 6:
2439c9274b6bSCho, Yu-Chen insn |= (uint64_t)(uint32_t)cpu_ldl_code(env, addr + 2) << 16;
2440c9274b6bSCho, Yu-Chen break;
2441c9274b6bSCho, Yu-Chen default:
2442c9274b6bSCho, Yu-Chen g_assert_not_reached();
2443c9274b6bSCho, Yu-Chen }
2444c9274b6bSCho, Yu-Chen
2445c9274b6bSCho, Yu-Chen /* The very most common cases can be sped up by avoiding a new TB. */
2446c9274b6bSCho, Yu-Chen if ((opc & 0xf0) == 0xd0) {
2447c9274b6bSCho, Yu-Chen typedef uint32_t (*dx_helper)(CPUS390XState *, uint32_t, uint64_t,
2448c9274b6bSCho, Yu-Chen uint64_t, uintptr_t);
2449c9274b6bSCho, Yu-Chen static const dx_helper dx[16] = {
2450c9274b6bSCho, Yu-Chen [0x0] = do_helper_trt_bkwd,
2451c9274b6bSCho, Yu-Chen [0x2] = do_helper_mvc,
2452c9274b6bSCho, Yu-Chen [0x4] = do_helper_nc,
2453c9274b6bSCho, Yu-Chen [0x5] = do_helper_clc,
2454c9274b6bSCho, Yu-Chen [0x6] = do_helper_oc,
2455c9274b6bSCho, Yu-Chen [0x7] = do_helper_xc,
2456c9274b6bSCho, Yu-Chen [0xc] = do_helper_tr,
2457c9274b6bSCho, Yu-Chen [0xd] = do_helper_trt_fwd,
2458c9274b6bSCho, Yu-Chen };
2459c9274b6bSCho, Yu-Chen dx_helper helper = dx[opc & 0xf];
2460c9274b6bSCho, Yu-Chen
2461c9274b6bSCho, Yu-Chen if (helper) {
2462c9274b6bSCho, Yu-Chen uint32_t l = extract64(insn, 48, 8);
2463c9274b6bSCho, Yu-Chen uint32_t b1 = extract64(insn, 44, 4);
2464c9274b6bSCho, Yu-Chen uint32_t d1 = extract64(insn, 32, 12);
2465c9274b6bSCho, Yu-Chen uint32_t b2 = extract64(insn, 28, 4);
2466c9274b6bSCho, Yu-Chen uint32_t d2 = extract64(insn, 16, 12);
2467c9274b6bSCho, Yu-Chen uint64_t a1 = wrap_address(env, (b1 ? env->regs[b1] : 0) + d1);
2468c9274b6bSCho, Yu-Chen uint64_t a2 = wrap_address(env, (b2 ? env->regs[b2] : 0) + d2);
2469c9274b6bSCho, Yu-Chen
2470c9274b6bSCho, Yu-Chen env->cc_op = helper(env, l, a1, a2, 0);
2471c9274b6bSCho, Yu-Chen env->psw.addr += ilen;
2472c9274b6bSCho, Yu-Chen return;
2473c9274b6bSCho, Yu-Chen }
2474c9274b6bSCho, Yu-Chen } else if (opc == 0x0a) {
2475c9274b6bSCho, Yu-Chen env->int_svc_code = extract64(insn, 48, 8);
2476c9274b6bSCho, Yu-Chen env->int_svc_ilen = ilen;
2477c9274b6bSCho, Yu-Chen helper_exception(env, EXCP_SVC);
2478c9274b6bSCho, Yu-Chen g_assert_not_reached();
2479c9274b6bSCho, Yu-Chen }
2480c9274b6bSCho, Yu-Chen
2481c9274b6bSCho, Yu-Chen /* Record the insn we want to execute as well as the ilen to use
2482c9274b6bSCho, Yu-Chen during the execution of the target insn. This will also ensure
2483c9274b6bSCho, Yu-Chen that ex_value is non-zero, which flags that we are in a state
2484c9274b6bSCho, Yu-Chen that requires such execution. */
2485c9274b6bSCho, Yu-Chen env->ex_value = insn | ilen;
2486703d03a4SIlya Leoshkevich env->ex_target = addr;
2487c9274b6bSCho, Yu-Chen }
2488c9274b6bSCho, Yu-Chen
HELPER(mvcos)2489c9274b6bSCho, Yu-Chen uint32_t HELPER(mvcos)(CPUS390XState *env, uint64_t dest, uint64_t src,
2490c9274b6bSCho, Yu-Chen uint64_t len)
2491c9274b6bSCho, Yu-Chen {
2492c9274b6bSCho, Yu-Chen const uint8_t psw_key = (env->psw.mask & PSW_MASK_KEY) >> PSW_SHIFT_KEY;
2493c9274b6bSCho, Yu-Chen const uint8_t psw_as = (env->psw.mask & PSW_MASK_ASC) >> PSW_SHIFT_ASC;
2494c9274b6bSCho, Yu-Chen const uint64_t r0 = env->regs[0];
2495c9274b6bSCho, Yu-Chen const uintptr_t ra = GETPC();
2496c9274b6bSCho, Yu-Chen uint8_t dest_key, dest_as, dest_k, dest_a;
2497c9274b6bSCho, Yu-Chen uint8_t src_key, src_as, src_k, src_a;
2498c9274b6bSCho, Yu-Chen uint64_t val;
2499c9274b6bSCho, Yu-Chen int cc = 0;
2500c9274b6bSCho, Yu-Chen
2501c9274b6bSCho, Yu-Chen HELPER_LOG("%s dest %" PRIx64 ", src %" PRIx64 ", len %" PRIx64 "\n",
2502c9274b6bSCho, Yu-Chen __func__, dest, src, len);
2503c9274b6bSCho, Yu-Chen
2504c9274b6bSCho, Yu-Chen if (!(env->psw.mask & PSW_MASK_DAT)) {
2505c9274b6bSCho, Yu-Chen tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
2506c9274b6bSCho, Yu-Chen }
2507c9274b6bSCho, Yu-Chen
2508c9274b6bSCho, Yu-Chen /* OAC (operand access control) for the first operand -> dest */
2509c9274b6bSCho, Yu-Chen val = (r0 & 0xffff0000ULL) >> 16;
2510c9274b6bSCho, Yu-Chen dest_key = (val >> 12) & 0xf;
2511c9274b6bSCho, Yu-Chen dest_as = (val >> 6) & 0x3;
2512c9274b6bSCho, Yu-Chen dest_k = (val >> 1) & 0x1;
2513c9274b6bSCho, Yu-Chen dest_a = val & 0x1;
2514c9274b6bSCho, Yu-Chen
2515c9274b6bSCho, Yu-Chen /* OAC (operand access control) for the second operand -> src */
2516c9274b6bSCho, Yu-Chen val = (r0 & 0x0000ffffULL);
2517c9274b6bSCho, Yu-Chen src_key = (val >> 12) & 0xf;
2518c9274b6bSCho, Yu-Chen src_as = (val >> 6) & 0x3;
2519c9274b6bSCho, Yu-Chen src_k = (val >> 1) & 0x1;
2520c9274b6bSCho, Yu-Chen src_a = val & 0x1;
2521c9274b6bSCho, Yu-Chen
2522c9274b6bSCho, Yu-Chen if (!dest_k) {
2523c9274b6bSCho, Yu-Chen dest_key = psw_key;
2524c9274b6bSCho, Yu-Chen }
2525c9274b6bSCho, Yu-Chen if (!src_k) {
2526c9274b6bSCho, Yu-Chen src_key = psw_key;
2527c9274b6bSCho, Yu-Chen }
2528c9274b6bSCho, Yu-Chen if (!dest_a) {
2529c9274b6bSCho, Yu-Chen dest_as = psw_as;
2530c9274b6bSCho, Yu-Chen }
2531c9274b6bSCho, Yu-Chen if (!src_a) {
2532c9274b6bSCho, Yu-Chen src_as = psw_as;
2533c9274b6bSCho, Yu-Chen }
2534c9274b6bSCho, Yu-Chen
2535c9274b6bSCho, Yu-Chen if (dest_a && dest_as == AS_HOME && (env->psw.mask & PSW_MASK_PSTATE)) {
2536c9274b6bSCho, Yu-Chen tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
2537c9274b6bSCho, Yu-Chen }
2538c9274b6bSCho, Yu-Chen if (!(env->cregs[0] & CR0_SECONDARY) &&
2539c9274b6bSCho, Yu-Chen (dest_as == AS_SECONDARY || src_as == AS_SECONDARY)) {
2540c9274b6bSCho, Yu-Chen tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
2541c9274b6bSCho, Yu-Chen }
2542c9274b6bSCho, Yu-Chen if (!psw_key_valid(env, dest_key) || !psw_key_valid(env, src_key)) {
2543c9274b6bSCho, Yu-Chen tcg_s390_program_interrupt(env, PGM_PRIVILEGED, ra);
2544c9274b6bSCho, Yu-Chen }
2545c9274b6bSCho, Yu-Chen
2546c9274b6bSCho, Yu-Chen len = wrap_length32(env, len);
2547c9274b6bSCho, Yu-Chen if (len > 4096) {
2548c9274b6bSCho, Yu-Chen cc = 3;
2549c9274b6bSCho, Yu-Chen len = 4096;
2550c9274b6bSCho, Yu-Chen }
2551c9274b6bSCho, Yu-Chen
2552c9274b6bSCho, Yu-Chen /* FIXME: AR-mode and proper problem state mode (using PSW keys) missing */
2553c9274b6bSCho, Yu-Chen if (src_as == AS_ACCREG || dest_as == AS_ACCREG ||
2554c9274b6bSCho, Yu-Chen (env->psw.mask & PSW_MASK_PSTATE)) {
2555c9274b6bSCho, Yu-Chen qemu_log_mask(LOG_UNIMP, "%s: AR-mode and PSTATE support missing\n",
2556c9274b6bSCho, Yu-Chen __func__);
2557c9274b6bSCho, Yu-Chen tcg_s390_program_interrupt(env, PGM_ADDRESSING, ra);
2558c9274b6bSCho, Yu-Chen }
2559c9274b6bSCho, Yu-Chen
2560c9274b6bSCho, Yu-Chen /* FIXME: Access using correct keys and AR-mode */
2561c9274b6bSCho, Yu-Chen if (len) {
25627ba5da81SRichard Henderson S390Access srca, desta;
25637ba5da81SRichard Henderson
25647ba5da81SRichard Henderson access_prepare(&srca, env, src, len, MMU_DATA_LOAD,
2565c9274b6bSCho, Yu-Chen mmu_idx_from_as(src_as), ra);
25667ba5da81SRichard Henderson access_prepare(&desta, env, dest, len, MMU_DATA_STORE,
2567c9274b6bSCho, Yu-Chen mmu_idx_from_as(dest_as), ra);
2568c9274b6bSCho, Yu-Chen
2569c9274b6bSCho, Yu-Chen access_memmove(env, &desta, &srca, ra);
2570c9274b6bSCho, Yu-Chen }
2571c9274b6bSCho, Yu-Chen
2572c9274b6bSCho, Yu-Chen return cc;
2573c9274b6bSCho, Yu-Chen }
2574c9274b6bSCho, Yu-Chen
2575c9274b6bSCho, Yu-Chen /* Decode a Unicode character. A return value < 0 indicates success, storing
2576c9274b6bSCho, Yu-Chen the UTF-32 result into OCHAR and the input length into OLEN. A return
2577c9274b6bSCho, Yu-Chen value >= 0 indicates failure, and the CC value to be returned. */
2578c9274b6bSCho, Yu-Chen typedef int (*decode_unicode_fn)(CPUS390XState *env, uint64_t addr,
2579c9274b6bSCho, Yu-Chen uint64_t ilen, bool enh_check, uintptr_t ra,
2580c9274b6bSCho, Yu-Chen uint32_t *ochar, uint32_t *olen);
2581c9274b6bSCho, Yu-Chen
2582c9274b6bSCho, Yu-Chen /* Encode a Unicode character. A return value < 0 indicates success, storing
2583c9274b6bSCho, Yu-Chen the bytes into ADDR and the output length into OLEN. A return value >= 0
2584c9274b6bSCho, Yu-Chen indicates failure, and the CC value to be returned. */
2585c9274b6bSCho, Yu-Chen typedef int (*encode_unicode_fn)(CPUS390XState *env, uint64_t addr,
2586c9274b6bSCho, Yu-Chen uint64_t ilen, uintptr_t ra, uint32_t c,
2587c9274b6bSCho, Yu-Chen uint32_t *olen);
2588c9274b6bSCho, Yu-Chen
decode_utf8(CPUS390XState * env,uint64_t addr,uint64_t ilen,bool enh_check,uintptr_t ra,uint32_t * ochar,uint32_t * olen)2589c9274b6bSCho, Yu-Chen static int decode_utf8(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2590c9274b6bSCho, Yu-Chen bool enh_check, uintptr_t ra,
2591c9274b6bSCho, Yu-Chen uint32_t *ochar, uint32_t *olen)
2592c9274b6bSCho, Yu-Chen {
2593c9274b6bSCho, Yu-Chen uint8_t s0, s1, s2, s3;
2594c9274b6bSCho, Yu-Chen uint32_t c, l;
2595c9274b6bSCho, Yu-Chen
2596c9274b6bSCho, Yu-Chen if (ilen < 1) {
2597c9274b6bSCho, Yu-Chen return 0;
2598c9274b6bSCho, Yu-Chen }
2599c9274b6bSCho, Yu-Chen s0 = cpu_ldub_data_ra(env, addr, ra);
2600c9274b6bSCho, Yu-Chen if (s0 <= 0x7f) {
2601c9274b6bSCho, Yu-Chen /* one byte character */
2602c9274b6bSCho, Yu-Chen l = 1;
2603c9274b6bSCho, Yu-Chen c = s0;
2604c9274b6bSCho, Yu-Chen } else if (s0 <= (enh_check ? 0xc1 : 0xbf)) {
2605c9274b6bSCho, Yu-Chen /* invalid character */
2606c9274b6bSCho, Yu-Chen return 2;
2607c9274b6bSCho, Yu-Chen } else if (s0 <= 0xdf) {
2608c9274b6bSCho, Yu-Chen /* two byte character */
2609c9274b6bSCho, Yu-Chen l = 2;
2610c9274b6bSCho, Yu-Chen if (ilen < 2) {
2611c9274b6bSCho, Yu-Chen return 0;
2612c9274b6bSCho, Yu-Chen }
2613c9274b6bSCho, Yu-Chen s1 = cpu_ldub_data_ra(env, addr + 1, ra);
2614c9274b6bSCho, Yu-Chen c = s0 & 0x1f;
2615c9274b6bSCho, Yu-Chen c = (c << 6) | (s1 & 0x3f);
2616c9274b6bSCho, Yu-Chen if (enh_check && (s1 & 0xc0) != 0x80) {
2617c9274b6bSCho, Yu-Chen return 2;
2618c9274b6bSCho, Yu-Chen }
2619c9274b6bSCho, Yu-Chen } else if (s0 <= 0xef) {
2620c9274b6bSCho, Yu-Chen /* three byte character */
2621c9274b6bSCho, Yu-Chen l = 3;
2622c9274b6bSCho, Yu-Chen if (ilen < 3) {
2623c9274b6bSCho, Yu-Chen return 0;
2624c9274b6bSCho, Yu-Chen }
2625c9274b6bSCho, Yu-Chen s1 = cpu_ldub_data_ra(env, addr + 1, ra);
2626c9274b6bSCho, Yu-Chen s2 = cpu_ldub_data_ra(env, addr + 2, ra);
2627c9274b6bSCho, Yu-Chen c = s0 & 0x0f;
2628c9274b6bSCho, Yu-Chen c = (c << 6) | (s1 & 0x3f);
2629c9274b6bSCho, Yu-Chen c = (c << 6) | (s2 & 0x3f);
2630c9274b6bSCho, Yu-Chen /* Fold the byte-by-byte range descriptions in the PoO into
2631c9274b6bSCho, Yu-Chen tests against the complete value. It disallows encodings
2632c9274b6bSCho, Yu-Chen that could be smaller, and the UTF-16 surrogates. */
2633c9274b6bSCho, Yu-Chen if (enh_check
2634c9274b6bSCho, Yu-Chen && ((s1 & 0xc0) != 0x80
2635c9274b6bSCho, Yu-Chen || (s2 & 0xc0) != 0x80
2636c9274b6bSCho, Yu-Chen || c < 0x1000
2637c9274b6bSCho, Yu-Chen || (c >= 0xd800 && c <= 0xdfff))) {
2638c9274b6bSCho, Yu-Chen return 2;
2639c9274b6bSCho, Yu-Chen }
2640c9274b6bSCho, Yu-Chen } else if (s0 <= (enh_check ? 0xf4 : 0xf7)) {
2641c9274b6bSCho, Yu-Chen /* four byte character */
2642c9274b6bSCho, Yu-Chen l = 4;
2643c9274b6bSCho, Yu-Chen if (ilen < 4) {
2644c9274b6bSCho, Yu-Chen return 0;
2645c9274b6bSCho, Yu-Chen }
2646c9274b6bSCho, Yu-Chen s1 = cpu_ldub_data_ra(env, addr + 1, ra);
2647c9274b6bSCho, Yu-Chen s2 = cpu_ldub_data_ra(env, addr + 2, ra);
2648c9274b6bSCho, Yu-Chen s3 = cpu_ldub_data_ra(env, addr + 3, ra);
2649c9274b6bSCho, Yu-Chen c = s0 & 0x07;
2650c9274b6bSCho, Yu-Chen c = (c << 6) | (s1 & 0x3f);
2651c9274b6bSCho, Yu-Chen c = (c << 6) | (s2 & 0x3f);
2652c9274b6bSCho, Yu-Chen c = (c << 6) | (s3 & 0x3f);
2653c9274b6bSCho, Yu-Chen /* See above. */
2654c9274b6bSCho, Yu-Chen if (enh_check
2655c9274b6bSCho, Yu-Chen && ((s1 & 0xc0) != 0x80
2656c9274b6bSCho, Yu-Chen || (s2 & 0xc0) != 0x80
2657c9274b6bSCho, Yu-Chen || (s3 & 0xc0) != 0x80
2658c9274b6bSCho, Yu-Chen || c < 0x010000
2659c9274b6bSCho, Yu-Chen || c > 0x10ffff)) {
2660c9274b6bSCho, Yu-Chen return 2;
2661c9274b6bSCho, Yu-Chen }
2662c9274b6bSCho, Yu-Chen } else {
2663c9274b6bSCho, Yu-Chen /* invalid character */
2664c9274b6bSCho, Yu-Chen return 2;
2665c9274b6bSCho, Yu-Chen }
2666c9274b6bSCho, Yu-Chen
2667c9274b6bSCho, Yu-Chen *ochar = c;
2668c9274b6bSCho, Yu-Chen *olen = l;
2669c9274b6bSCho, Yu-Chen return -1;
2670c9274b6bSCho, Yu-Chen }
2671c9274b6bSCho, Yu-Chen
decode_utf16(CPUS390XState * env,uint64_t addr,uint64_t ilen,bool enh_check,uintptr_t ra,uint32_t * ochar,uint32_t * olen)2672c9274b6bSCho, Yu-Chen static int decode_utf16(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2673c9274b6bSCho, Yu-Chen bool enh_check, uintptr_t ra,
2674c9274b6bSCho, Yu-Chen uint32_t *ochar, uint32_t *olen)
2675c9274b6bSCho, Yu-Chen {
2676c9274b6bSCho, Yu-Chen uint16_t s0, s1;
2677c9274b6bSCho, Yu-Chen uint32_t c, l;
2678c9274b6bSCho, Yu-Chen
2679c9274b6bSCho, Yu-Chen if (ilen < 2) {
2680c9274b6bSCho, Yu-Chen return 0;
2681c9274b6bSCho, Yu-Chen }
2682c9274b6bSCho, Yu-Chen s0 = cpu_lduw_data_ra(env, addr, ra);
2683c9274b6bSCho, Yu-Chen if ((s0 & 0xfc00) != 0xd800) {
2684c9274b6bSCho, Yu-Chen /* one word character */
2685c9274b6bSCho, Yu-Chen l = 2;
2686c9274b6bSCho, Yu-Chen c = s0;
2687c9274b6bSCho, Yu-Chen } else {
2688c9274b6bSCho, Yu-Chen /* two word character */
2689c9274b6bSCho, Yu-Chen l = 4;
2690c9274b6bSCho, Yu-Chen if (ilen < 4) {
2691c9274b6bSCho, Yu-Chen return 0;
2692c9274b6bSCho, Yu-Chen }
2693c9274b6bSCho, Yu-Chen s1 = cpu_lduw_data_ra(env, addr + 2, ra);
2694c9274b6bSCho, Yu-Chen c = extract32(s0, 6, 4) + 1;
2695c9274b6bSCho, Yu-Chen c = (c << 6) | (s0 & 0x3f);
2696c9274b6bSCho, Yu-Chen c = (c << 10) | (s1 & 0x3ff);
2697c9274b6bSCho, Yu-Chen if (enh_check && (s1 & 0xfc00) != 0xdc00) {
2698c9274b6bSCho, Yu-Chen /* invalid surrogate character */
2699c9274b6bSCho, Yu-Chen return 2;
2700c9274b6bSCho, Yu-Chen }
2701c9274b6bSCho, Yu-Chen }
2702c9274b6bSCho, Yu-Chen
2703c9274b6bSCho, Yu-Chen *ochar = c;
2704c9274b6bSCho, Yu-Chen *olen = l;
2705c9274b6bSCho, Yu-Chen return -1;
2706c9274b6bSCho, Yu-Chen }
2707c9274b6bSCho, Yu-Chen
decode_utf32(CPUS390XState * env,uint64_t addr,uint64_t ilen,bool enh_check,uintptr_t ra,uint32_t * ochar,uint32_t * olen)2708c9274b6bSCho, Yu-Chen static int decode_utf32(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2709c9274b6bSCho, Yu-Chen bool enh_check, uintptr_t ra,
2710c9274b6bSCho, Yu-Chen uint32_t *ochar, uint32_t *olen)
2711c9274b6bSCho, Yu-Chen {
2712c9274b6bSCho, Yu-Chen uint32_t c;
2713c9274b6bSCho, Yu-Chen
2714c9274b6bSCho, Yu-Chen if (ilen < 4) {
2715c9274b6bSCho, Yu-Chen return 0;
2716c9274b6bSCho, Yu-Chen }
2717c9274b6bSCho, Yu-Chen c = cpu_ldl_data_ra(env, addr, ra);
2718c9274b6bSCho, Yu-Chen if ((c >= 0xd800 && c <= 0xdbff) || c > 0x10ffff) {
2719c9274b6bSCho, Yu-Chen /* invalid unicode character */
2720c9274b6bSCho, Yu-Chen return 2;
2721c9274b6bSCho, Yu-Chen }
2722c9274b6bSCho, Yu-Chen
2723c9274b6bSCho, Yu-Chen *ochar = c;
2724c9274b6bSCho, Yu-Chen *olen = 4;
2725c9274b6bSCho, Yu-Chen return -1;
2726c9274b6bSCho, Yu-Chen }
2727c9274b6bSCho, Yu-Chen
encode_utf8(CPUS390XState * env,uint64_t addr,uint64_t ilen,uintptr_t ra,uint32_t c,uint32_t * olen)2728c9274b6bSCho, Yu-Chen static int encode_utf8(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2729c9274b6bSCho, Yu-Chen uintptr_t ra, uint32_t c, uint32_t *olen)
2730c9274b6bSCho, Yu-Chen {
2731c9274b6bSCho, Yu-Chen uint8_t d[4];
2732c9274b6bSCho, Yu-Chen uint32_t l, i;
2733c9274b6bSCho, Yu-Chen
2734c9274b6bSCho, Yu-Chen if (c <= 0x7f) {
2735c9274b6bSCho, Yu-Chen /* one byte character */
2736c9274b6bSCho, Yu-Chen l = 1;
2737c9274b6bSCho, Yu-Chen d[0] = c;
2738c9274b6bSCho, Yu-Chen } else if (c <= 0x7ff) {
2739c9274b6bSCho, Yu-Chen /* two byte character */
2740c9274b6bSCho, Yu-Chen l = 2;
2741c9274b6bSCho, Yu-Chen d[1] = 0x80 | extract32(c, 0, 6);
2742c9274b6bSCho, Yu-Chen d[0] = 0xc0 | extract32(c, 6, 5);
2743c9274b6bSCho, Yu-Chen } else if (c <= 0xffff) {
2744c9274b6bSCho, Yu-Chen /* three byte character */
2745c9274b6bSCho, Yu-Chen l = 3;
2746c9274b6bSCho, Yu-Chen d[2] = 0x80 | extract32(c, 0, 6);
2747c9274b6bSCho, Yu-Chen d[1] = 0x80 | extract32(c, 6, 6);
2748c9274b6bSCho, Yu-Chen d[0] = 0xe0 | extract32(c, 12, 4);
2749c9274b6bSCho, Yu-Chen } else {
2750c9274b6bSCho, Yu-Chen /* four byte character */
2751c9274b6bSCho, Yu-Chen l = 4;
2752c9274b6bSCho, Yu-Chen d[3] = 0x80 | extract32(c, 0, 6);
2753c9274b6bSCho, Yu-Chen d[2] = 0x80 | extract32(c, 6, 6);
2754c9274b6bSCho, Yu-Chen d[1] = 0x80 | extract32(c, 12, 6);
2755c9274b6bSCho, Yu-Chen d[0] = 0xf0 | extract32(c, 18, 3);
2756c9274b6bSCho, Yu-Chen }
2757c9274b6bSCho, Yu-Chen
2758c9274b6bSCho, Yu-Chen if (ilen < l) {
2759c9274b6bSCho, Yu-Chen return 1;
2760c9274b6bSCho, Yu-Chen }
2761c9274b6bSCho, Yu-Chen for (i = 0; i < l; ++i) {
2762c9274b6bSCho, Yu-Chen cpu_stb_data_ra(env, addr + i, d[i], ra);
2763c9274b6bSCho, Yu-Chen }
2764c9274b6bSCho, Yu-Chen
2765c9274b6bSCho, Yu-Chen *olen = l;
2766c9274b6bSCho, Yu-Chen return -1;
2767c9274b6bSCho, Yu-Chen }
2768c9274b6bSCho, Yu-Chen
encode_utf16(CPUS390XState * env,uint64_t addr,uint64_t ilen,uintptr_t ra,uint32_t c,uint32_t * olen)2769c9274b6bSCho, Yu-Chen static int encode_utf16(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2770c9274b6bSCho, Yu-Chen uintptr_t ra, uint32_t c, uint32_t *olen)
2771c9274b6bSCho, Yu-Chen {
2772c9274b6bSCho, Yu-Chen uint16_t d0, d1;
2773c9274b6bSCho, Yu-Chen
2774c9274b6bSCho, Yu-Chen if (c <= 0xffff) {
2775c9274b6bSCho, Yu-Chen /* one word character */
2776c9274b6bSCho, Yu-Chen if (ilen < 2) {
2777c9274b6bSCho, Yu-Chen return 1;
2778c9274b6bSCho, Yu-Chen }
2779c9274b6bSCho, Yu-Chen cpu_stw_data_ra(env, addr, c, ra);
2780c9274b6bSCho, Yu-Chen *olen = 2;
2781c9274b6bSCho, Yu-Chen } else {
2782c9274b6bSCho, Yu-Chen /* two word character */
2783c9274b6bSCho, Yu-Chen if (ilen < 4) {
2784c9274b6bSCho, Yu-Chen return 1;
2785c9274b6bSCho, Yu-Chen }
2786c9274b6bSCho, Yu-Chen d1 = 0xdc00 | extract32(c, 0, 10);
2787c9274b6bSCho, Yu-Chen d0 = 0xd800 | extract32(c, 10, 6);
2788c9274b6bSCho, Yu-Chen d0 = deposit32(d0, 6, 4, extract32(c, 16, 5) - 1);
2789c9274b6bSCho, Yu-Chen cpu_stw_data_ra(env, addr + 0, d0, ra);
2790c9274b6bSCho, Yu-Chen cpu_stw_data_ra(env, addr + 2, d1, ra);
2791c9274b6bSCho, Yu-Chen *olen = 4;
2792c9274b6bSCho, Yu-Chen }
2793c9274b6bSCho, Yu-Chen
2794c9274b6bSCho, Yu-Chen return -1;
2795c9274b6bSCho, Yu-Chen }
2796c9274b6bSCho, Yu-Chen
encode_utf32(CPUS390XState * env,uint64_t addr,uint64_t ilen,uintptr_t ra,uint32_t c,uint32_t * olen)2797c9274b6bSCho, Yu-Chen static int encode_utf32(CPUS390XState *env, uint64_t addr, uint64_t ilen,
2798c9274b6bSCho, Yu-Chen uintptr_t ra, uint32_t c, uint32_t *olen)
2799c9274b6bSCho, Yu-Chen {
2800c9274b6bSCho, Yu-Chen if (ilen < 4) {
2801c9274b6bSCho, Yu-Chen return 1;
2802c9274b6bSCho, Yu-Chen }
2803c9274b6bSCho, Yu-Chen cpu_stl_data_ra(env, addr, c, ra);
2804c9274b6bSCho, Yu-Chen *olen = 4;
2805c9274b6bSCho, Yu-Chen return -1;
2806c9274b6bSCho, Yu-Chen }
2807c9274b6bSCho, Yu-Chen
convert_unicode(CPUS390XState * env,uint32_t r1,uint32_t r2,uint32_t m3,uintptr_t ra,decode_unicode_fn decode,encode_unicode_fn encode)2808c9274b6bSCho, Yu-Chen static inline uint32_t convert_unicode(CPUS390XState *env, uint32_t r1,
2809c9274b6bSCho, Yu-Chen uint32_t r2, uint32_t m3, uintptr_t ra,
2810c9274b6bSCho, Yu-Chen decode_unicode_fn decode,
2811c9274b6bSCho, Yu-Chen encode_unicode_fn encode)
2812c9274b6bSCho, Yu-Chen {
2813c9274b6bSCho, Yu-Chen uint64_t dst = get_address(env, r1);
2814c9274b6bSCho, Yu-Chen uint64_t dlen = get_length(env, r1 + 1);
2815c9274b6bSCho, Yu-Chen uint64_t src = get_address(env, r2);
2816c9274b6bSCho, Yu-Chen uint64_t slen = get_length(env, r2 + 1);
2817c9274b6bSCho, Yu-Chen bool enh_check = m3 & 1;
2818c9274b6bSCho, Yu-Chen int cc, i;
2819c9274b6bSCho, Yu-Chen
2820c9274b6bSCho, Yu-Chen /* Lest we fail to service interrupts in a timely manner, limit the
2821c9274b6bSCho, Yu-Chen amount of work we're willing to do. For now, let's cap at 256. */
2822c9274b6bSCho, Yu-Chen for (i = 0; i < 256; ++i) {
2823c9274b6bSCho, Yu-Chen uint32_t c, ilen, olen;
2824c9274b6bSCho, Yu-Chen
2825c9274b6bSCho, Yu-Chen cc = decode(env, src, slen, enh_check, ra, &c, &ilen);
2826c9274b6bSCho, Yu-Chen if (unlikely(cc >= 0)) {
2827c9274b6bSCho, Yu-Chen break;
2828c9274b6bSCho, Yu-Chen }
2829c9274b6bSCho, Yu-Chen cc = encode(env, dst, dlen, ra, c, &olen);
2830c9274b6bSCho, Yu-Chen if (unlikely(cc >= 0)) {
2831c9274b6bSCho, Yu-Chen break;
2832c9274b6bSCho, Yu-Chen }
2833c9274b6bSCho, Yu-Chen
2834c9274b6bSCho, Yu-Chen src += ilen;
2835c9274b6bSCho, Yu-Chen slen -= ilen;
2836c9274b6bSCho, Yu-Chen dst += olen;
2837c9274b6bSCho, Yu-Chen dlen -= olen;
2838c9274b6bSCho, Yu-Chen cc = 3;
2839c9274b6bSCho, Yu-Chen }
2840c9274b6bSCho, Yu-Chen
2841c9274b6bSCho, Yu-Chen set_address(env, r1, dst);
2842c9274b6bSCho, Yu-Chen set_length(env, r1 + 1, dlen);
2843c9274b6bSCho, Yu-Chen set_address(env, r2, src);
2844c9274b6bSCho, Yu-Chen set_length(env, r2 + 1, slen);
2845c9274b6bSCho, Yu-Chen
2846c9274b6bSCho, Yu-Chen return cc;
2847c9274b6bSCho, Yu-Chen }
2848c9274b6bSCho, Yu-Chen
HELPER(cu12)2849c9274b6bSCho, Yu-Chen uint32_t HELPER(cu12)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2850c9274b6bSCho, Yu-Chen {
2851c9274b6bSCho, Yu-Chen return convert_unicode(env, r1, r2, m3, GETPC(),
2852c9274b6bSCho, Yu-Chen decode_utf8, encode_utf16);
2853c9274b6bSCho, Yu-Chen }
2854c9274b6bSCho, Yu-Chen
HELPER(cu14)2855c9274b6bSCho, Yu-Chen uint32_t HELPER(cu14)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2856c9274b6bSCho, Yu-Chen {
2857c9274b6bSCho, Yu-Chen return convert_unicode(env, r1, r2, m3, GETPC(),
2858c9274b6bSCho, Yu-Chen decode_utf8, encode_utf32);
2859c9274b6bSCho, Yu-Chen }
2860c9274b6bSCho, Yu-Chen
HELPER(cu21)2861c9274b6bSCho, Yu-Chen uint32_t HELPER(cu21)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2862c9274b6bSCho, Yu-Chen {
2863c9274b6bSCho, Yu-Chen return convert_unicode(env, r1, r2, m3, GETPC(),
2864c9274b6bSCho, Yu-Chen decode_utf16, encode_utf8);
2865c9274b6bSCho, Yu-Chen }
2866c9274b6bSCho, Yu-Chen
HELPER(cu24)2867c9274b6bSCho, Yu-Chen uint32_t HELPER(cu24)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2868c9274b6bSCho, Yu-Chen {
2869c9274b6bSCho, Yu-Chen return convert_unicode(env, r1, r2, m3, GETPC(),
2870c9274b6bSCho, Yu-Chen decode_utf16, encode_utf32);
2871c9274b6bSCho, Yu-Chen }
2872c9274b6bSCho, Yu-Chen
HELPER(cu41)2873c9274b6bSCho, Yu-Chen uint32_t HELPER(cu41)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2874c9274b6bSCho, Yu-Chen {
2875c9274b6bSCho, Yu-Chen return convert_unicode(env, r1, r2, m3, GETPC(),
2876c9274b6bSCho, Yu-Chen decode_utf32, encode_utf8);
2877c9274b6bSCho, Yu-Chen }
2878c9274b6bSCho, Yu-Chen
HELPER(cu42)2879c9274b6bSCho, Yu-Chen uint32_t HELPER(cu42)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t m3)
2880c9274b6bSCho, Yu-Chen {
2881c9274b6bSCho, Yu-Chen return convert_unicode(env, r1, r2, m3, GETPC(),
2882c9274b6bSCho, Yu-Chen decode_utf32, encode_utf16);
2883c9274b6bSCho, Yu-Chen }
2884c9274b6bSCho, Yu-Chen
probe_write_access(CPUS390XState * env,uint64_t addr,uint64_t len,uintptr_t ra)2885c9274b6bSCho, Yu-Chen void probe_write_access(CPUS390XState *env, uint64_t addr, uint64_t len,
2886c9274b6bSCho, Yu-Chen uintptr_t ra)
2887c9274b6bSCho, Yu-Chen {
288890b7022eSRichard Henderson const int mmu_idx = s390x_env_mmu_index(env, false);
288990b7022eSRichard Henderson
2890c9274b6bSCho, Yu-Chen /* test the actual access, not just any access to the page due to LAP */
2891c9274b6bSCho, Yu-Chen while (len) {
2892c9274b6bSCho, Yu-Chen const uint64_t pagelen = -(addr | TARGET_PAGE_MASK);
2893c9274b6bSCho, Yu-Chen const uint64_t curlen = MIN(pagelen, len);
2894c9274b6bSCho, Yu-Chen
289590b7022eSRichard Henderson probe_write(env, addr, curlen, mmu_idx, ra);
2896c9274b6bSCho, Yu-Chen addr = wrap_address(env, addr + curlen);
2897c9274b6bSCho, Yu-Chen len -= curlen;
2898c9274b6bSCho, Yu-Chen }
2899c9274b6bSCho, Yu-Chen }
2900c9274b6bSCho, Yu-Chen
HELPER(probe_write_access)2901c9274b6bSCho, Yu-Chen void HELPER(probe_write_access)(CPUS390XState *env, uint64_t addr, uint64_t len)
2902c9274b6bSCho, Yu-Chen {
2903c9274b6bSCho, Yu-Chen probe_write_access(env, addr, len, GETPC());
2904c9274b6bSCho, Yu-Chen }
2905