提交 2f93a3ec 编写于 作者: P Peter Maydell

Merge remote-tracking branch 'remotes/davidhildenbrand/tags/s390x-tcg-2019-09-23' into staging

Fix a bunch of BUGs in the mem-helpers (including the MVC instruction),
especially, to make them behave correctly on faults.

# gpg: Signature made Mon 23 Sep 2019 09:01:21 BST
# gpg:                using RSA key 1BD9CAAD735C4C3A460DFCCA4DDE10F700FF835A
# gpg:                issuer "david@redhat.com"
# gpg: Good signature from "David Hildenbrand <david@redhat.com>" [unknown]
# gpg:                 aka "David Hildenbrand <davidhildenbrand@gmail.com>" [full]
# Primary key fingerprint: 1BD9 CAAD 735C 4C3A 460D  FCCA 4DDE 10F7 00FF 835A

* remotes/davidhildenbrand/tags/s390x-tcg-2019-09-23: (30 commits)
  tests/tcg: target/s390x: Test MVC
  tests/tcg: target/s390x: Test MVO
  s390x/tcg: MVO: Fault-safe handling
  s390x/tcg: MVST: Fault-safe handling
  s390x/tcg: MVZ: Fault-safe handling
  s390x/tcg: MVN: Fault-safe handling
  s390x/tcg: MVCIN: Fault-safe handling
  s390x/tcg: NC: Fault-safe handling
  s390x/tcg: XC: Fault-safe handling
  s390x/tcg: OC: Fault-safe handling
  s390x/tcg: MVCLU: Fault-safe handling
  s390x/tcg: MVC: Fault-safe handling on destructive overlaps
  s390x/tcg: MVCS/MVCP: Use access_memmove()
  s390x/tcg: Fault-safe memmove
  s390x/tcg: Fault-safe memset
  s390x/tcg: Always use MMU_USER_IDX for CONFIG_USER_ONLY
  s390x/tcg: MVST: Fix storing back the addresses to registers
  s390x/tcg: MVST: Check for specification exceptions
  s390x/tcg: MVCS/MVCP: Properly wrap the length
  s390x/tcg: MVCOS: Lengths are 32 bit in 24/31-bit mode
  ...
Signed-off-by: NPeter Maydell <peter.maydell@linaro.org>
...@@ -328,6 +328,9 @@ extern const VMStateDescription vmstate_s390_cpu; ...@@ -328,6 +328,9 @@ extern const VMStateDescription vmstate_s390_cpu;
static inline int cpu_mmu_index(CPUS390XState *env, bool ifetch) static inline int cpu_mmu_index(CPUS390XState *env, bool ifetch)
{ {
#ifdef CONFIG_USER_ONLY
return MMU_USER_IDX;
#else
if (!(env->psw.mask & PSW_MASK_DAT)) { if (!(env->psw.mask & PSW_MASK_DAT)) {
return MMU_REAL_IDX; return MMU_REAL_IDX;
} }
...@@ -351,6 +354,7 @@ static inline int cpu_mmu_index(CPUS390XState *env, bool ifetch) ...@@ -351,6 +354,7 @@ static inline int cpu_mmu_index(CPUS390XState *env, bool ifetch)
default: default:
abort(); abort();
} }
#endif
} }
static inline void cpu_get_tb_cpu_state(CPUS390XState* env, target_ulong *pc, static inline void cpu_get_tb_cpu_state(CPUS390XState* env, target_ulong *pc,
......
...@@ -20,7 +20,7 @@ DEF_HELPER_FLAGS_4(mvn, TCG_CALL_NO_WG, void, env, i32, i64, i64) ...@@ -20,7 +20,7 @@ DEF_HELPER_FLAGS_4(mvn, TCG_CALL_NO_WG, void, env, i32, i64, i64)
DEF_HELPER_FLAGS_4(mvo, TCG_CALL_NO_WG, void, env, i32, i64, i64) DEF_HELPER_FLAGS_4(mvo, TCG_CALL_NO_WG, void, env, i32, i64, i64)
DEF_HELPER_FLAGS_4(mvpg, TCG_CALL_NO_WG, i32, env, i64, i64, i64) DEF_HELPER_FLAGS_4(mvpg, TCG_CALL_NO_WG, i32, env, i64, i64, i64)
DEF_HELPER_FLAGS_4(mvz, TCG_CALL_NO_WG, void, env, i32, i64, i64) DEF_HELPER_FLAGS_4(mvz, TCG_CALL_NO_WG, void, env, i32, i64, i64)
DEF_HELPER_4(mvst, i64, env, i64, i64, i64) DEF_HELPER_3(mvst, i32, env, i32, i32)
DEF_HELPER_4(ex, void, env, i32, i64, i64) DEF_HELPER_4(ex, void, env, i32, i64, i64)
DEF_HELPER_FLAGS_4(stam, TCG_CALL_NO_WG, void, env, i32, i64, i32) DEF_HELPER_FLAGS_4(stam, TCG_CALL_NO_WG, void, env, i32, i64, i32)
DEF_HELPER_FLAGS_4(lam, TCG_CALL_NO_WG, void, env, i32, i64, i32) DEF_HELPER_FLAGS_4(lam, TCG_CALL_NO_WG, void, env, i32, i64, i32)
......
...@@ -637,7 +637,7 @@ ...@@ -637,7 +637,7 @@
/* MOVE PAGE */ /* MOVE PAGE */
C(0xb254, MVPG, RRE, Z, r1_o, r2_o, 0, 0, mvpg, 0) C(0xb254, MVPG, RRE, Z, r1_o, r2_o, 0, 0, mvpg, 0)
/* MOVE STRING */ /* MOVE STRING */
C(0xb255, MVST, RRE, Z, r1_o, r2_o, 0, 0, mvst, 0) C(0xb255, MVST, RRE, Z, 0, 0, 0, 0, mvst, 0)
/* MOVE WITH OPTIONAL SPECIFICATION */ /* MOVE WITH OPTIONAL SPECIFICATION */
C(0xc800, MVCOS, SSF, MVCOS, la1, a2, 0, 0, mvcos, 0) C(0xc800, MVCOS, SSF, MVCOS, la1, a2, 0, 0, mvcos, 0)
/* MOVE WITH OFFSET */ /* MOVE WITH OFFSET */
......
此差异已折叠。
...@@ -318,6 +318,9 @@ static inline uint64_t ld_code4(CPUS390XState *env, uint64_t pc) ...@@ -318,6 +318,9 @@ static inline uint64_t ld_code4(CPUS390XState *env, uint64_t pc)
static int get_mem_index(DisasContext *s) static int get_mem_index(DisasContext *s)
{ {
#ifdef CONFIG_USER_ONLY
return MMU_USER_IDX;
#else
if (!(s->base.tb->flags & FLAG_MASK_DAT)) { if (!(s->base.tb->flags & FLAG_MASK_DAT)) {
return MMU_REAL_IDX; return MMU_REAL_IDX;
} }
...@@ -333,6 +336,7 @@ static int get_mem_index(DisasContext *s) ...@@ -333,6 +336,7 @@ static int get_mem_index(DisasContext *s)
tcg_abort(); tcg_abort();
break; break;
} }
#endif
} }
static void gen_exception(int excp) static void gen_exception(int excp)
...@@ -3488,9 +3492,13 @@ static DisasJumpType op_mvpg(DisasContext *s, DisasOps *o) ...@@ -3488,9 +3492,13 @@ static DisasJumpType op_mvpg(DisasContext *s, DisasOps *o)
static DisasJumpType op_mvst(DisasContext *s, DisasOps *o) static DisasJumpType op_mvst(DisasContext *s, DisasOps *o)
{ {
gen_helper_mvst(o->in1, cpu_env, regs[0], o->in1, o->in2); TCGv_i32 t1 = tcg_const_i32(get_field(s->fields, r1));
TCGv_i32 t2 = tcg_const_i32(get_field(s->fields, r2));
gen_helper_mvst(cc_op, cpu_env, t1, t2);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t2);
set_cc_static(s); set_cc_static(s);
return_low128(o->in2);
return DISAS_NEXT; return DISAS_NEXT;
} }
......
...@@ -6,3 +6,5 @@ TESTS+=ipm ...@@ -6,3 +6,5 @@ TESTS+=ipm
TESTS+=exrl-trt TESTS+=exrl-trt
TESTS+=exrl-trtr TESTS+=exrl-trtr
TESTS+=pack TESTS+=pack
TESTS+=mvo
TESTS+=mvc
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <signal.h>
#include <setjmp.h>
jmp_buf jmp_env;
static void handle_sigsegv(int sig)
{
siglongjmp(jmp_env, 1);
}
#define ALLOC_SIZE (2 * 4096)
static inline void mvc_256(const char *dst, const char *src)
{
asm volatile (
" mvc 0(256,%[dst]),0(%[src])\n"
:
: [dst] "d" (dst),
[src] "d" (src)
: "memory");
}
int main(void)
{
char *src, *dst;
int i;
/* register the SIGSEGV handler */
if (signal(SIGSEGV, handle_sigsegv) == SIG_ERR) {
fprintf(stderr, "SIGSEGV not registered\n");
return 1;
}
/* prepare the buffers - two consecutive pages */
src = valloc(ALLOC_SIZE);
dst = valloc(ALLOC_SIZE);
memset(src, 0xff, ALLOC_SIZE);
memset(dst, 0x0, ALLOC_SIZE);
/* protect the second pages */
if (mprotect(src + 4096, 4096, PROT_NONE) ||
mprotect(dst + 4096, 4096, PROT_NONE)) {
fprintf(stderr, "mprotect failed\n");
return 1;
}
/* fault on second destination page */
if (sigsetjmp(jmp_env, 1) == 0) {
mvc_256(dst + 4096 - 128, src);
fprintf(stderr, "fault not triggered\n");
return 1;
}
/* fault on second source page */
if (sigsetjmp(jmp_env, 1) == 0) {
mvc_256(dst, src + 4096 - 128);
fprintf(stderr, "fault not triggered\n");
return 1;
}
/* fault on second source and second destination page */
if (sigsetjmp(jmp_env, 1) == 0) {
mvc_256(dst + 4096 - 128, src + 4096 - 128);
fprintf(stderr, "fault not triggered\n");
return 1;
}
/* restore permissions */
if (mprotect(src + 4096, 4096, PROT_READ | PROT_WRITE) ||
mprotect(dst + 4096, 4096, PROT_READ | PROT_WRITE)) {
fprintf(stderr, "mprotect failed\n");
return 1;
}
/* no data must be touched during the faults */
for (i = 0; i < ALLOC_SIZE; i++) {
if (src[i] != 0xff || dst[i]) {
fprintf(stderr, "data modified during a fault\n");
return 1;
}
}
/* test if MVC works now correctly accross page boundaries */
mvc_256(dst + 4096 - 128, src + 4096 - 128);
for (i = 0; i < ALLOC_SIZE; i++) {
if (src[i] != 0xff) {
fprintf(stderr, "src modified\n");
return 1;
}
if (i < 4096 - 128 || i >= 4096 + 128) {
if (dst[i]) {
fprintf(stderr, "wrong dst modified\n");
return 1;
}
} else {
if (dst[i] != 0xff) {
fprintf(stderr, "wrong data moved\n");
return 1;
}
}
}
return 0;
}
#include <stdint.h>
#include <stdio.h>
int main(void)
{
uint8_t dest[6] = {0xff, 0x77, 0x88, 0x99, 0x0c, 0xff};
uint8_t src[5] = {0xee, 0x12, 0x34, 0x56, 0xee};
uint8_t expected[6] = {0xff, 0x01, 0x23, 0x45, 0x6c, 0xff};
int i;
asm volatile (
" mvo 0(4,%[dest]),0(3,%[src])\n"
:
: [dest] "d" (dest + 1),
[src] "d" (src + 1)
: "memory");
for (i = 0; i < sizeof(expected); i++) {
if (dest[i] != expected[i]) {
fprintf(stderr, "bad data\n");
return 1;
}
}
return 0;
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册