@@ -1026,40 +1026,26 @@ uint32_t HELPER(csp)(CPUS390XState *env, uint32_t r1, uint64_t r2)
return cc;
}
-static uint32_t mvc_asc(CPUS390XState *env, int64_t l, uint64_t a1,
- uint64_t mode1, uint64_t a2, uint64_t mode2)
+static uint32_t mvc_asc(CPUS390XState *env, uint64_t l, uint64_t a1,
+ int idx1, uint64_t a2, int idx2, uintptr_t retaddr)
{
- CPUState *cs = CPU(s390_env_get_cpu(env));
- target_ulong src, dest;
- int flags, cc = 0, i;
+ int cc = 0;
- if (!l) {
- return 0;
- } else if (l > 256) {
+ if (l > 256) {
/* max 256 */
l = 256;
cc = 3;
}
- if (mmu_translate(env, a1, 1, mode1, &dest, &flags, true)) {
- cpu_loop_exit(CPU(s390_env_get_cpu(env)));
- }
- dest |= a1 & ~TARGET_PAGE_MASK;
-
- if (mmu_translate(env, a2, 0, mode2, &src, &flags, true)) {
- cpu_loop_exit(CPU(s390_env_get_cpu(env)));
- }
- src |= a2 & ~TARGET_PAGE_MASK;
-
- /* XXX replace w/ memcpy */
- for (i = 0; i < l; i++) {
- /* XXX be more clever */
- if ((((dest + i) & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) ||
- (((src + i) & TARGET_PAGE_MASK) != (src & TARGET_PAGE_MASK))) {
- mvc_asc(env, l - i, a1 + i, mode1, a2 + i, mode2);
- break;
- }
- stb_phys(cs->as, dest + i, ldub_phys(cs->as, src + i));
+ while (l > 0) {
+ void *src = tlb_vaddr_to_host_fill(env, a2, MMU_DATA_LOAD, idx2, retaddr);
+ void *dest = tlb_vaddr_to_host_fill(env, a1, MMU_DATA_STORE, idx1, retaddr);
+ int len = adj_len_to_page(l, a1);
+ len = adj_len_to_page(len, a2);
+ memcpy(dest, src, len);
+ l -= len;
+ a1 += len;
+ a2 += len;
}
return cc;
@@ -1070,7 +1056,7 @@ uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
__func__, l, a1, a2);
- return mvc_asc(env, l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY);
+ return mvc_asc(env, l, a1, MMU_SECONDARY_IDX, a2, MMU_PRIMARY_IDX, GETPC());
}
uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
@@ -1078,7 +1064,7 @@ uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
__func__, l, a1, a2);
- return mvc_asc(env, l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY);
+ return mvc_asc(env, l, a1, MMU_PRIMARY_IDX, a2, MMU_SECONDARY_IDX, GETPC());
}
/* invalidate pte */
@@ -2793,7 +2793,6 @@ static ExitStatus op_mvcp(DisasContext *s, DisasOps *o)
{
int r1 = get_field(s->fields, l1);
check_privileged(s);
- potential_page_fault(s);
gen_helper_mvcp(cc_op, cpu_env, regs[r1], o->addr1, o->in2);
set_cc_static(s);
return NO_EXIT;
@@ -2803,7 +2802,6 @@ static ExitStatus op_mvcs(DisasContext *s, DisasOps *o)
{
int r1 = get_field(s->fields, l1);
check_privileged(s);
- potential_page_fault(s);
gen_helper_mvcs(cc_op, cpu_env, regs[r1], o->addr1, o->in2);
set_cc_static(s);
return NO_EXIT;
mvcp and mvcs helper get access to the physical memory by a call to mmu_translate for the virtual to real conversion and then using ldb_phys and stb_phys to physically access the data. In practice this is quite slow because it bypasses the QEMU softmmu TLB and because stb_phys calls try to invalidate the corresponding memory for each access. Instead use the new softmmu guest virtual address to host address conversion and call memcpy, taking care of not crossing page boundaries. As we pass the return address, we can skip saving the registers in the TCG code, a page fault trigger code retranslation instead. This improves the boot time of a guest by a factor 2. Cc: Alexander Graf <agraf@suse.de> Cc: Richard Henderson <rth@twiddle.net> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- target-s390x/mem_helper.c | 44 +++++++++++++++----------------------------- target-s390x/translate.c | 2 -- 2 files changed, 15 insertions(+), 31 deletions(-)