* Mark Nios II as orphan

* Many s390x emulation fixes
 * Disable flaky complete_in_standby blockjob unit test
 * White space cleanups in various files
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCAAvFiEEJ7iIR+7gJQEY8+q5LtnXdP5wLbUFAmQYVEoRHHRodXRoQHJl
 ZGhhdC5jb20ACgkQLtnXdP5wLbWu/A//QdVG7wS66lhdkPPu/GN+eDNaNsTzPPZd
 YwH0bpy2YoopInwa1ggZ1zPatmbSOVUcKjUfNYLcQzUBQnmeFtpuAF+4IGDhYfa+
 agkjWvmrCrIww4Wn+OLdLReW1+GtRlKZKu7xbYKkeLyqr9SHUD2lNUZ5RXj2t9Lw
 BXkPDXkMFqfVDzHtAxyXL7Z7yk3UTnZKBjDxiwE3tZ4S+N4r7m/TvNHiopI2bTVg
 JeDTxN40ylbOlBfOLC/qhlLUVnyBsDalIfKffIdLZ5Qn+FnKfZhkt9km4i7OL+ZX
 1wKnTh/J8OCYqHOyhJdZGT8QxZH79qDm12/nKXzIQkxtJoKuz6Fm5FY3ZJNrb+IJ
 ybxSpAFBJB/8sUjbzl8ZjGxbZecIyEBKT518+oBoqjNcy3n8/m2BhBFr6f6F4cJC
 kdTnRS0XYKGLbJLz0+VBARE7hoHNckYsup/DGscppyYKNA6rFXbq/MI3+oMGAnPw
 Ua/+gXU/hwq8TPg97A7O0hS4TKSKMtdZFEDmAGzkejVHvm/3BvcYrVoKDljnUAQV
 SaERp/Elefbt3EufkuZp77AwLU8RcEFscitEIACmLbmwm3aKpqS+R2u1EJ4ZcoFT
 dHUBkokXW1/i+FtNRmjEKV9z398cNYXGEDLPfMnFbknHwbS53pqeQqqlvUidltGk
 LWviyiqKihk=
 =tYCc
 -----END PGP SIGNATURE-----

Merge tag 'pull-request-2023-03-20' of https://gitlab.com/thuth/qemu into staging

* Mark Nios II as orphan
* Many s390x emulation fixes
* Disable flaky complete_in_standby blockjob unit test
* White space cleanups in various files

# -----BEGIN PGP SIGNATURE-----
#
# iQJFBAABCAAvFiEEJ7iIR+7gJQEY8+q5LtnXdP5wLbUFAmQYVEoRHHRodXRoQHJl
# ZGhhdC5jb20ACgkQLtnXdP5wLbWu/A//QdVG7wS66lhdkPPu/GN+eDNaNsTzPPZd
# YwH0bpy2YoopInwa1ggZ1zPatmbSOVUcKjUfNYLcQzUBQnmeFtpuAF+4IGDhYfa+
# agkjWvmrCrIww4Wn+OLdLReW1+GtRlKZKu7xbYKkeLyqr9SHUD2lNUZ5RXj2t9Lw
# BXkPDXkMFqfVDzHtAxyXL7Z7yk3UTnZKBjDxiwE3tZ4S+N4r7m/TvNHiopI2bTVg
# JeDTxN40ylbOlBfOLC/qhlLUVnyBsDalIfKffIdLZ5Qn+FnKfZhkt9km4i7OL+ZX
# 1wKnTh/J8OCYqHOyhJdZGT8QxZH79qDm12/nKXzIQkxtJoKuz6Fm5FY3ZJNrb+IJ
# ybxSpAFBJB/8sUjbzl8ZjGxbZecIyEBKT518+oBoqjNcy3n8/m2BhBFr6f6F4cJC
# kdTnRS0XYKGLbJLz0+VBARE7hoHNckYsup/DGscppyYKNA6rFXbq/MI3+oMGAnPw
# Ua/+gXU/hwq8TPg97A7O0hS4TKSKMtdZFEDmAGzkejVHvm/3BvcYrVoKDljnUAQV
# SaERp/Elefbt3EufkuZp77AwLU8RcEFscitEIACmLbmwm3aKpqS+R2u1EJ4ZcoFT
# dHUBkokXW1/i+FtNRmjEKV9z398cNYXGEDLPfMnFbknHwbS53pqeQqqlvUidltGk
# LWviyiqKihk=
# =tYCc
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 20 Mar 2023 12:40:42 GMT
# gpg:                using RSA key 27B88847EEE0250118F3EAB92ED9D774FE702DB5
# gpg:                issuer "thuth@redhat.com"
# gpg: Good signature from "Thomas Huth <th.huth@gmx.de>" [full]
# gpg:                 aka "Thomas Huth <thuth@redhat.com>" [full]
# gpg:                 aka "Thomas Huth <huth@tuxfamily.org>" [full]
# gpg:                 aka "Thomas Huth <th.huth@posteo.de>" [unknown]
# Primary key fingerprint: 27B8 8847 EEE0 2501 18F3  EAB9 2ED9 D774 FE70 2DB5

* tag 'pull-request-2023-03-20' of https://gitlab.com/thuth/qemu: (24 commits)
  replace TABs with spaces
  qemu/osdep: Switch position of "extern" and "G_NORETURN"
  tests/unit/test-blockjob: Disable complete_in_standby test
  target/s390x/tcg/mem_helper: Remove bad assert() statement
  tests/tcg/s390x: Test unaligned accesses
  target/s390x: Update do_unaligned_access() comment
  target/s390x: Handle STGRL to non-aligned addresses
  target/s390x: Handle STRL to non-aligned addresses
  target/s390x: Handle CLRL and CLGFRL with non-aligned addresses
  target/s390x: Handle CGRL and CLGRL with non-aligned addresses
  target/s390x: Handle CRL and CGFRL with non-aligned addresses
  target/s390x: Handle LLGFRL from non-aligned addresses
  target/s390x: Handle LRL and LGFRL from non-aligned addresses
  target/s390x: Handle LGRL from non-aligned addresses
  target/s390x: Handle EXECUTE of odd addresses
  target/s390x: Handle branching to odd addresses
  tests/tcg/s390x: Add ex-relative-long.c
  target/s390x: Fix EXECUTE of relative long instructions
  tests/tcg/s390x: Add rxsbg.c
  target/s390x: Fix R[NOX]SBG with T=1
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2023-03-20 13:43:14 +00:00
commit 4c6f44644d
65 changed files with 2890 additions and 2078 deletions

View File

@ -257,9 +257,9 @@ F: docs/system/cpu-models-mips.rst.inc
F: tests/tcg/mips/ F: tests/tcg/mips/
NiosII TCG CPUs NiosII TCG CPUs
M: Chris Wulff <crwulff@gmail.com> R: Chris Wulff <crwulff@gmail.com>
M: Marek Vasut <marex@denx.de> R: Marek Vasut <marex@denx.de>
S: Maintained S: Orphan
F: target/nios2/ F: target/nios2/
F: hw/nios2/ F: hw/nios2/
F: disas/nios2.c F: disas/nios2.c

View File

@ -237,7 +237,7 @@ extern "C" {
* supports QEMU_ERROR, this will be reported at compile time; otherwise * supports QEMU_ERROR, this will be reported at compile time; otherwise
* this will be reported at link time due to the missing symbol. * this will be reported at link time due to the missing symbol.
*/ */
extern G_NORETURN G_NORETURN extern
void QEMU_ERROR("code path is reachable") void QEMU_ERROR("code path is reachable")
qemu_build_not_reached_always(void); qemu_build_not_reached_always(void);
#if defined(__OPTIMIZE__) && !defined(__NO_INLINE__) #if defined(__OPTIMIZE__) && !defined(__NO_INLINE__)

View File

@ -41,6 +41,26 @@
#define CR0_RESET 0xE0UL #define CR0_RESET 0xE0UL
#define CR14_RESET 0xC2000000UL; #define CR14_RESET 0xC2000000UL;
#ifndef CONFIG_USER_ONLY
static bool is_early_exception_psw(uint64_t mask, uint64_t addr)
{
if (mask & PSW_MASK_RESERVED) {
return true;
}
switch (mask & (PSW_MASK_32 | PSW_MASK_64)) {
case 0:
return addr & ~0xffffffULL;
case PSW_MASK_32:
return addr & ~0x7fffffffULL;
case PSW_MASK_32 | PSW_MASK_64:
return false;
default: /* PSW_MASK_64 */
return true;
}
}
#endif
void s390_cpu_set_psw(CPUS390XState *env, uint64_t mask, uint64_t addr) void s390_cpu_set_psw(CPUS390XState *env, uint64_t mask, uint64_t addr)
{ {
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
@ -57,6 +77,12 @@ void s390_cpu_set_psw(CPUS390XState *env, uint64_t mask, uint64_t addr)
env->cc_op = (mask >> 44) & 3; env->cc_op = (mask >> 44) & 3;
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
if (is_early_exception_psw(mask, addr)) {
env->int_pgm_ilen = 0;
trigger_pgm_exception(env, PGM_SPECIFICATION);
return;
}
if ((old_mask ^ mask) & PSW_MASK_PER) { if ((old_mask ^ mask) & PSW_MASK_PER) {
s390_cpu_recompute_watchpoints(env_cpu(env)); s390_cpu_recompute_watchpoints(env_cpu(env));
} }

View File

@ -29,6 +29,7 @@
#include "cpu_models.h" #include "cpu_models.h"
#include "exec/cpu-defs.h" #include "exec/cpu-defs.h"
#include "qemu/cpu-float.h" #include "qemu/cpu-float.h"
#include "tcg/tcg_s390x.h"
#define ELF_MACHINE_UNAME "S390X" #define ELF_MACHINE_UNAME "S390X"
@ -87,6 +88,7 @@ struct CPUArchState {
uint64_t cc_vr; uint64_t cc_vr;
uint64_t ex_value; uint64_t ex_value;
uint64_t ex_target;
uint64_t __excp_addr; uint64_t __excp_addr;
uint64_t psa; uint64_t psa;
@ -292,6 +294,7 @@ extern const VMStateDescription vmstate_s390_cpu;
#define PSW_MASK_32 0x0000000080000000ULL #define PSW_MASK_32 0x0000000080000000ULL
#define PSW_MASK_SHORT_ADDR 0x000000007fffffffULL #define PSW_MASK_SHORT_ADDR 0x000000007fffffffULL
#define PSW_MASK_SHORT_CTRL 0xffffffff80000000ULL #define PSW_MASK_SHORT_CTRL 0xffffffff80000000ULL
#define PSW_MASK_RESERVED 0xb80800fe7fffffffULL
#undef PSW_ASC_PRIMARY #undef PSW_ASC_PRIMARY
#undef PSW_ASC_ACCREG #undef PSW_ASC_ACCREG
@ -381,6 +384,14 @@ static inline int cpu_mmu_index(CPUS390XState *env, bool ifetch)
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,
target_ulong *cs_base, uint32_t *flags) target_ulong *cs_base, uint32_t *flags)
{ {
if (env->psw.addr & 1) {
/*
* Instructions must be at even addresses.
* This needs to be checked before address translation.
*/
env->int_pgm_ilen = 2; /* see s390_cpu_tlb_fill() */
tcg_s390_program_interrupt(env, PGM_SPECIFICATION, 0);
}
*pc = env->psw.addr; *pc = env->psw.addr;
*cs_base = env->ex_value; *cs_base = env->ex_value;
*flags = (env->psw.mask >> FLAG_MASK_PSW_SHIFT) & FLAG_MASK_PSW; *flags = (env->psw.mask >> FLAG_MASK_PSW_SHIFT) & FLAG_MASK_PSW;

View File

@ -85,8 +85,8 @@ void HELPER(data_exception)(CPUS390XState *env, uint32_t dxc)
/* /*
* Unaligned accesses are only diagnosed with MO_ALIGN. At the moment, * Unaligned accesses are only diagnosed with MO_ALIGN. At the moment,
* this is only for the atomic operations, for which we want to raise a * this is only for the atomic and relative long operations, for which we want
* specification exception. * to raise a specification exception.
*/ */
static G_NORETURN static G_NORETURN
void do_unaligned_access(CPUState *cs, uintptr_t retaddr) void do_unaligned_access(CPUState *cs, uintptr_t retaddr)
@ -212,7 +212,8 @@ static void do_program_interrupt(CPUS390XState *env)
LowCore *lowcore; LowCore *lowcore;
int ilen = env->int_pgm_ilen; int ilen = env->int_pgm_ilen;
assert(ilen == 2 || ilen == 4 || ilen == 6); assert((env->int_pgm_code == PGM_SPECIFICATION && ilen == 0) ||
ilen == 2 || ilen == 4 || ilen == 6);
switch (env->int_pgm_code) { switch (env->int_pgm_code) {
case PGM_PER: case PGM_PER:

View File

@ -410,12 +410,12 @@
/* LOAD */ /* LOAD */
C(0x1800, LR, RR_a, Z, 0, r2_o, 0, cond_r1r2_32, mov2, 0) C(0x1800, LR, RR_a, Z, 0, r2_o, 0, cond_r1r2_32, mov2, 0)
C(0x5800, L, RX_a, Z, 0, a2, new, r1_32, ld32s, 0) D(0x5800, L, RX_a, Z, 0, a2, new, r1_32, ld32s, 0, 0)
C(0xe358, LY, RXY_a, LD, 0, a2, new, r1_32, ld32s, 0) D(0xe358, LY, RXY_a, LD, 0, a2, new, r1_32, ld32s, 0, 0)
C(0xb904, LGR, RRE, Z, 0, r2_o, 0, r1, mov2, 0) C(0xb904, LGR, RRE, Z, 0, r2_o, 0, r1, mov2, 0)
C(0xb914, LGFR, RRE, Z, 0, r2_32s, 0, r1, mov2, 0) C(0xb914, LGFR, RRE, Z, 0, r2_32s, 0, r1, mov2, 0)
C(0xe304, LG, RXY_a, Z, 0, a2, r1, 0, ld64, 0) D(0xe304, LG, RXY_a, Z, 0, a2, r1, 0, ld64, 0, 0)
C(0xe314, LGF, RXY_a, Z, 0, a2, r1, 0, ld32s, 0) D(0xe314, LGF, RXY_a, Z, 0, a2, r1, 0, ld32s, 0, 0)
F(0x2800, LDR, RR_a, Z, 0, f2, 0, f1, mov2, 0, IF_AFP1 | IF_AFP2) F(0x2800, LDR, RR_a, Z, 0, f2, 0, f1, mov2, 0, IF_AFP1 | IF_AFP2)
F(0x6800, LD, RX_a, Z, 0, m2_64, 0, f1, mov2, 0, IF_AFP1) F(0x6800, LD, RX_a, Z, 0, m2_64, 0, f1, mov2, 0, IF_AFP1)
F(0xed65, LDY, RXY_a, LD, 0, m2_64, 0, f1, mov2, 0, IF_AFP1) F(0xed65, LDY, RXY_a, LD, 0, m2_64, 0, f1, mov2, 0, IF_AFP1)
@ -426,9 +426,9 @@
/* LOAD IMMEDIATE */ /* LOAD IMMEDIATE */
C(0xc001, LGFI, RIL_a, EI, 0, i2, 0, r1, mov2, 0) C(0xc001, LGFI, RIL_a, EI, 0, i2, 0, r1, mov2, 0)
/* LOAD RELATIVE LONG */ /* LOAD RELATIVE LONG */
C(0xc40d, LRL, RIL_b, GIE, 0, ri2, new, r1_32, ld32s, 0) D(0xc40d, LRL, RIL_b, GIE, 0, ri2, new, r1_32, ld32s, 0, MO_ALIGN)
C(0xc408, LGRL, RIL_b, GIE, 0, ri2, r1, 0, ld64, 0) D(0xc408, LGRL, RIL_b, GIE, 0, ri2, r1, 0, ld64, 0, MO_ALIGN)
C(0xc40c, LGFRL, RIL_b, GIE, 0, ri2, r1, 0, ld32s, 0) D(0xc40c, LGFRL, RIL_b, GIE, 0, ri2, r1, 0, ld32s, 0, MO_ALIGN)
/* LOAD ADDRESS */ /* LOAD ADDRESS */
C(0x4100, LA, RX_a, Z, 0, a2, 0, r1, mov2, 0) C(0x4100, LA, RX_a, Z, 0, a2, 0, r1, mov2, 0)
C(0xe371, LAY, RXY_a, LD, 0, a2, 0, r1, mov2, 0) C(0xe371, LAY, RXY_a, LD, 0, a2, 0, r1, mov2, 0)
@ -456,9 +456,9 @@
C(0x1200, LTR, RR_a, Z, 0, r2_o, 0, cond_r1r2_32, mov2, s32) C(0x1200, LTR, RR_a, Z, 0, r2_o, 0, cond_r1r2_32, mov2, s32)
C(0xb902, LTGR, RRE, Z, 0, r2_o, 0, r1, mov2, s64) C(0xb902, LTGR, RRE, Z, 0, r2_o, 0, r1, mov2, s64)
C(0xb912, LTGFR, RRE, Z, 0, r2_32s, 0, r1, mov2, s64) C(0xb912, LTGFR, RRE, Z, 0, r2_32s, 0, r1, mov2, s64)
C(0xe312, LT, RXY_a, EI, 0, a2, new, r1_32, ld32s, s64) D(0xe312, LT, RXY_a, EI, 0, a2, new, r1_32, ld32s, s64, 0)
C(0xe302, LTG, RXY_a, EI, 0, a2, r1, 0, ld64, s64) D(0xe302, LTG, RXY_a, EI, 0, a2, r1, 0, ld64, s64, 0)
C(0xe332, LTGF, RXY_a, GIE, 0, a2, r1, 0, ld32s, s64) D(0xe332, LTGF, RXY_a, GIE, 0, a2, r1, 0, ld32s, s64, 0)
F(0xb302, LTEBR, RRE, Z, 0, e2, 0, cond_e1e2, mov2, f32, IF_BFP) F(0xb302, LTEBR, RRE, Z, 0, e2, 0, cond_e1e2, mov2, f32, IF_BFP)
F(0xb312, LTDBR, RRE, Z, 0, f2, 0, f1, mov2, f64, IF_BFP) F(0xb312, LTDBR, RRE, Z, 0, f2, 0, f1, mov2, f64, IF_BFP)
F(0xb342, LTXBR, RRE, Z, x2h, x2l, 0, x1_P, movx, f128, IF_BFP) F(0xb342, LTXBR, RRE, Z, x2h, x2l, 0, x1_P, movx, f128, IF_BFP)
@ -502,16 +502,16 @@
C(0xc405, LHRL, RIL_b, GIE, 0, ri2, new, r1_32, ld16s, 0) C(0xc405, LHRL, RIL_b, GIE, 0, ri2, new, r1_32, ld16s, 0)
C(0xc404, LGHRL, RIL_b, GIE, 0, ri2, r1, 0, ld16s, 0) C(0xc404, LGHRL, RIL_b, GIE, 0, ri2, r1, 0, ld16s, 0)
/* LOAD HIGH */ /* LOAD HIGH */
C(0xe3ca, LFH, RXY_a, HW, 0, a2, new, r1_32h, ld32u, 0) D(0xe3ca, LFH, RXY_a, HW, 0, a2, new, r1_32h, ld32u, 0, 0)
/* LOAG HIGH AND TRAP */ /* LOAG HIGH AND TRAP */
C(0xe3c8, LFHAT, RXY_a, LAT, 0, m2_32u, r1, 0, lfhat, 0) C(0xe3c8, LFHAT, RXY_a, LAT, 0, m2_32u, r1, 0, lfhat, 0)
/* LOAD LOGICAL */ /* LOAD LOGICAL */
C(0xb916, LLGFR, RRE, Z, 0, r2_32u, 0, r1, mov2, 0) C(0xb916, LLGFR, RRE, Z, 0, r2_32u, 0, r1, mov2, 0)
C(0xe316, LLGF, RXY_a, Z, 0, a2, r1, 0, ld32u, 0) D(0xe316, LLGF, RXY_a, Z, 0, a2, r1, 0, ld32u, 0, 0)
/* LOAD LOGICAL AND TRAP */ /* LOAD LOGICAL AND TRAP */
C(0xe39d, LLGFAT, RXY_a, LAT, 0, a2, r1, 0, llgfat, 0) C(0xe39d, LLGFAT, RXY_a, LAT, 0, a2, r1, 0, llgfat, 0)
/* LOAD LOGICAL RELATIVE LONG */ /* LOAD LOGICAL RELATIVE LONG */
C(0xc40e, LLGFRL, RIL_b, GIE, 0, ri2, r1, 0, ld32u, 0) D(0xc40e, LLGFRL, RIL_b, GIE, 0, ri2, r1, 0, ld32u, 0, MO_ALIGN)
/* LOAD LOGICAL CHARACTER */ /* LOAD LOGICAL CHARACTER */
C(0xb994, LLCR, RRE, EI, 0, r2_8u, 0, r1_32, mov2, 0) C(0xb994, LLCR, RRE, EI, 0, r2_8u, 0, r1_32, mov2, 0)
C(0xb984, LLGCR, RRE, EI, 0, r2_8u, 0, r1, mov2, 0) C(0xb984, LLGCR, RRE, EI, 0, r2_8u, 0, r1, mov2, 0)
@ -840,16 +840,16 @@
F(0xed15, SQDB, RXE, Z, 0, m2_64, new, f1, sqdb, 0, IF_BFP) F(0xed15, SQDB, RXE, Z, 0, m2_64, new, f1, sqdb, 0, IF_BFP)
/* STORE */ /* STORE */
C(0x5000, ST, RX_a, Z, r1_o, a2, 0, 0, st32, 0) D(0x5000, ST, RX_a, Z, r1_o, a2, 0, 0, st32, 0, 0)
C(0xe350, STY, RXY_a, LD, r1_o, a2, 0, 0, st32, 0) D(0xe350, STY, RXY_a, LD, r1_o, a2, 0, 0, st32, 0, 0)
C(0xe324, STG, RXY_a, Z, r1_o, a2, 0, 0, st64, 0) D(0xe324, STG, RXY_a, Z, r1_o, a2, 0, 0, st64, 0, 0)
F(0x6000, STD, RX_a, Z, f1, a2, 0, 0, st64, 0, IF_AFP1) E(0x6000, STD, RX_a, Z, f1, a2, 0, 0, st64, 0, 0, IF_AFP1)
F(0xed67, STDY, RXY_a, LD, f1, a2, 0, 0, st64, 0, IF_AFP1) E(0xed67, STDY, RXY_a, LD, f1, a2, 0, 0, st64, 0, 0, IF_AFP1)
F(0x7000, STE, RX_a, Z, e1, a2, 0, 0, st32, 0, IF_AFP1) E(0x7000, STE, RX_a, Z, e1, a2, 0, 0, st32, 0, 0, IF_AFP1)
F(0xed66, STEY, RXY_a, LD, e1, a2, 0, 0, st32, 0, IF_AFP1) E(0xed66, STEY, RXY_a, LD, e1, a2, 0, 0, st32, 0, 0, IF_AFP1)
/* STORE RELATIVE LONG */ /* STORE RELATIVE LONG */
C(0xc40f, STRL, RIL_b, GIE, r1_o, ri2, 0, 0, st32, 0) D(0xc40f, STRL, RIL_b, GIE, r1_o, ri2, 0, 0, st32, 0, MO_ALIGN)
C(0xc40b, STGRL, RIL_b, GIE, r1_o, ri2, 0, 0, st64, 0) D(0xc40b, STGRL, RIL_b, GIE, r1_o, ri2, 0, 0, st64, 0, MO_ALIGN)
/* STORE CHARACTER */ /* STORE CHARACTER */
C(0x4200, STC, RX_a, Z, r1_o, a2, 0, 0, st8, 0) C(0x4200, STC, RX_a, Z, r1_o, a2, 0, 0, st8, 0)
C(0xe372, STCY, RXY_a, LD, r1_o, a2, 0, 0, st8, 0) C(0xe372, STCY, RXY_a, LD, r1_o, a2, 0, 0, st8, 0)
@ -867,7 +867,7 @@
/* STORE HALFWORD RELATIVE LONG */ /* STORE HALFWORD RELATIVE LONG */
C(0xc407, STHRL, RIL_b, GIE, r1_o, ri2, 0, 0, st16, 0) C(0xc407, STHRL, RIL_b, GIE, r1_o, ri2, 0, 0, st16, 0)
/* STORE HIGH */ /* STORE HIGH */
C(0xe3cb, STFH, RXY_a, HW, r1_sr32, a2, 0, 0, st32, 0) D(0xe3cb, STFH, RXY_a, HW, r1_sr32, a2, 0, 0, st32, 0, 0)
/* STORE ON CONDITION */ /* STORE ON CONDITION */
D(0xebf3, STOC, RSY_b, LOC, 0, 0, 0, 0, soc, 0, 0) D(0xebf3, STOC, RSY_b, LOC, 0, 0, 0, 0, soc, 0, 0)
D(0xebe3, STOCG, RSY_b, LOC, 0, 0, 0, 0, soc, 0, 1) D(0xebe3, STOCG, RSY_b, LOC, 0, 0, 0, 0, soc, 0, 1)

View File

@ -149,7 +149,6 @@ static inline int s390_probe_access(CPUArchState *env, target_ulong addr,
nonfault, phost, ra); nonfault, phost, ra);
if (unlikely(flags & TLB_INVALID_MASK)) { if (unlikely(flags & TLB_INVALID_MASK)) {
assert(!nonfault);
#ifdef CONFIG_USER_ONLY #ifdef CONFIG_USER_ONLY
/* Address is in TEC in system mode; see s390_cpu_record_sigsegv. */ /* Address is in TEC in system mode; see s390_cpu_record_sigsegv. */
env->__excp_addr = addr & TARGET_PAGE_MASK; env->__excp_addr = addr & TARGET_PAGE_MASK;
@ -2468,8 +2467,16 @@ void HELPER(stpq_parallel)(CPUS390XState *env, uint64_t addr,
*/ */
void HELPER(ex)(CPUS390XState *env, uint32_t ilen, uint64_t r1, uint64_t addr) void HELPER(ex)(CPUS390XState *env, uint32_t ilen, uint64_t r1, uint64_t addr)
{ {
uint64_t insn = cpu_lduw_code(env, addr); uint64_t insn;
uint8_t opc = insn >> 8; uint8_t opc;
/* EXECUTE targets must be at even addresses. */
if (addr & 1) {
tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
}
insn = cpu_lduw_code(env, addr);
opc = insn >> 8;
/* Or in the contents of R1[56:63]. */ /* Or in the contents of R1[56:63]. */
insn |= r1 & 0xff; insn |= r1 & 0xff;
@ -2530,6 +2537,7 @@ void HELPER(ex)(CPUS390XState *env, uint32_t ilen, uint64_t r1, uint64_t addr)
that ex_value is non-zero, which flags that we are in a state that ex_value is non-zero, which flags that we are in a state
that requires such execution. */ that requires such execution. */
env->ex_value = insn | ilen; env->ex_value = insn | ilen;
env->ex_target = addr;
} }
uint32_t HELPER(mvcos)(CPUS390XState *env, uint64_t dest, uint64_t src, uint32_t HELPER(mvcos)(CPUS390XState *env, uint64_t dest, uint64_t src,

View File

@ -2770,19 +2770,22 @@ static DisasJumpType op_ld16u(DisasContext *s, DisasOps *o)
static DisasJumpType op_ld32s(DisasContext *s, DisasOps *o) static DisasJumpType op_ld32s(DisasContext *s, DisasOps *o)
{ {
tcg_gen_qemu_ld32s(o->out, o->in2, get_mem_index(s)); tcg_gen_qemu_ld_tl(o->out, o->in2, get_mem_index(s),
MO_TESL | s->insn->data);
return DISAS_NEXT; return DISAS_NEXT;
} }
static DisasJumpType op_ld32u(DisasContext *s, DisasOps *o) static DisasJumpType op_ld32u(DisasContext *s, DisasOps *o)
{ {
tcg_gen_qemu_ld32u(o->out, o->in2, get_mem_index(s)); tcg_gen_qemu_ld_tl(o->out, o->in2, get_mem_index(s),
MO_TEUL | s->insn->data);
return DISAS_NEXT; return DISAS_NEXT;
} }
static DisasJumpType op_ld64(DisasContext *s, DisasOps *o) static DisasJumpType op_ld64(DisasContext *s, DisasOps *o)
{ {
tcg_gen_qemu_ld64(o->out, o->in2, get_mem_index(s)); tcg_gen_qemu_ld_i64(o->out, o->in2, get_mem_index(s),
MO_TEUQ | s->insn->data);
return DISAS_NEXT; return DISAS_NEXT;
} }
@ -2910,19 +2913,21 @@ static DisasJumpType op_lpp(DisasContext *s, DisasOps *o)
static DisasJumpType op_lpsw(DisasContext *s, DisasOps *o) static DisasJumpType op_lpsw(DisasContext *s, DisasOps *o)
{ {
TCGv_i64 t1, t2; TCGv_i64 mask, addr;
per_breaking_event(s); per_breaking_event(s);
t1 = tcg_temp_new_i64(); /*
t2 = tcg_temp_new_i64(); * Convert the short PSW into the normal PSW, similar to what
tcg_gen_qemu_ld_i64(t1, o->in2, get_mem_index(s), * s390_cpu_load_normal() does.
MO_TEUL | MO_ALIGN_8); */
tcg_gen_addi_i64(o->in2, o->in2, 4); mask = tcg_temp_new_i64();
tcg_gen_qemu_ld32u(t2, o->in2, get_mem_index(s)); addr = tcg_temp_new_i64();
/* Convert the 32-bit PSW_MASK into the 64-bit PSW_MASK. */ tcg_gen_qemu_ld_i64(mask, o->in2, get_mem_index(s), MO_TEUQ | MO_ALIGN_8);
tcg_gen_shli_i64(t1, t1, 32); tcg_gen_andi_i64(addr, mask, PSW_MASK_SHORT_ADDR);
gen_helper_load_psw(cpu_env, t1, t2); tcg_gen_andi_i64(mask, mask, PSW_MASK_SHORT_CTRL);
tcg_gen_xori_i64(mask, mask, PSW_MASK_SHORTPSW);
gen_helper_load_psw(cpu_env, mask, addr);
return DISAS_NORETURN; return DISAS_NORETURN;
} }
@ -3695,11 +3700,15 @@ static DisasJumpType op_rosbg(DisasContext *s, DisasOps *o)
int i3 = get_field(s, i3); int i3 = get_field(s, i3);
int i4 = get_field(s, i4); int i4 = get_field(s, i4);
int i5 = get_field(s, i5); int i5 = get_field(s, i5);
TCGv_i64 orig_out;
uint64_t mask; uint64_t mask;
/* If this is a test-only form, arrange to discard the result. */ /* If this is a test-only form, arrange to discard the result. */
if (i3 & 0x80) { if (i3 & 0x80) {
tcg_debug_assert(o->out != NULL);
orig_out = o->out;
o->out = tcg_temp_new_i64(); o->out = tcg_temp_new_i64();
tcg_gen_mov_i64(o->out, orig_out);
} }
i3 &= 63; i3 &= 63;
@ -4066,9 +4075,23 @@ static DisasJumpType op_sske(DisasContext *s, DisasOps *o)
return DISAS_NEXT; return DISAS_NEXT;
} }
static void gen_check_psw_mask(DisasContext *s)
{
TCGv_i64 reserved = tcg_temp_new_i64();
TCGLabel *ok = gen_new_label();
tcg_gen_andi_i64(reserved, psw_mask, PSW_MASK_RESERVED);
tcg_gen_brcondi_i64(TCG_COND_EQ, reserved, 0, ok);
gen_program_exception(s, PGM_SPECIFICATION);
gen_set_label(ok);
}
static DisasJumpType op_ssm(DisasContext *s, DisasOps *o) static DisasJumpType op_ssm(DisasContext *s, DisasOps *o)
{ {
tcg_gen_deposit_i64(psw_mask, psw_mask, o->in2, 56, 8); tcg_gen_deposit_i64(psw_mask, psw_mask, o->in2, 56, 8);
gen_check_psw_mask(s);
/* Exit to main loop to reevaluate s390_cpu_exec_interrupt. */ /* Exit to main loop to reevaluate s390_cpu_exec_interrupt. */
s->exit_to_mainloop = true; s->exit_to_mainloop = true;
return DISAS_TOO_MANY; return DISAS_TOO_MANY;
@ -4329,6 +4352,8 @@ static DisasJumpType op_stnosm(DisasContext *s, DisasOps *o)
tcg_gen_ori_i64(psw_mask, psw_mask, i2 << 56); tcg_gen_ori_i64(psw_mask, psw_mask, i2 << 56);
} }
gen_check_psw_mask(s);
/* Exit to main loop to reevaluate s390_cpu_exec_interrupt. */ /* Exit to main loop to reevaluate s390_cpu_exec_interrupt. */
s->exit_to_mainloop = true; s->exit_to_mainloop = true;
return DISAS_TOO_MANY; return DISAS_TOO_MANY;
@ -4367,13 +4392,15 @@ static DisasJumpType op_st16(DisasContext *s, DisasOps *o)
static DisasJumpType op_st32(DisasContext *s, DisasOps *o) static DisasJumpType op_st32(DisasContext *s, DisasOps *o)
{ {
tcg_gen_qemu_st32(o->in1, o->in2, get_mem_index(s)); tcg_gen_qemu_st_tl(o->in1, o->in2, get_mem_index(s),
MO_TEUL | s->insn->data);
return DISAS_NEXT; return DISAS_NEXT;
} }
static DisasJumpType op_st64(DisasContext *s, DisasOps *o) static DisasJumpType op_st64(DisasContext *s, DisasOps *o)
{ {
tcg_gen_qemu_st64(o->in1, o->in2, get_mem_index(s)); tcg_gen_qemu_st_i64(o->in1, o->in2, get_mem_index(s),
MO_TEUQ | s->insn->data);
return DISAS_NEXT; return DISAS_NEXT;
} }
@ -5747,7 +5774,18 @@ static void in2_a2(DisasContext *s, DisasOps *o)
static TCGv gen_ri2(DisasContext *s) static TCGv gen_ri2(DisasContext *s)
{ {
return tcg_constant_i64(s->base.pc_next + (int64_t)get_field(s, i2) * 2); int64_t delta = (int64_t)get_field(s, i2) * 2;
TCGv ri2;
if (unlikely(s->ex_value)) {
ri2 = tcg_temp_new_i64();
tcg_gen_ld_i64(ri2, cpu_env, offsetof(CPUS390XState, ex_target));
tcg_gen_addi_i64(ri2, ri2, delta);
} else {
ri2 = tcg_constant_i64(s->base.pc_next + delta);
}
return ri2;
} }
static void in2_ri2(DisasContext *s, DisasOps *o) static void in2_ri2(DisasContext *s, DisasOps *o)
@ -5855,21 +5893,24 @@ static void in2_mri2_16u(DisasContext *s, DisasOps *o)
static void in2_mri2_32s(DisasContext *s, DisasOps *o) static void in2_mri2_32s(DisasContext *s, DisasOps *o)
{ {
o->in2 = tcg_temp_new_i64(); o->in2 = tcg_temp_new_i64();
tcg_gen_qemu_ld32s(o->in2, gen_ri2(s), get_mem_index(s)); tcg_gen_qemu_ld_tl(o->in2, gen_ri2(s), get_mem_index(s),
MO_TESL | MO_ALIGN);
} }
#define SPEC_in2_mri2_32s 0 #define SPEC_in2_mri2_32s 0
static void in2_mri2_32u(DisasContext *s, DisasOps *o) static void in2_mri2_32u(DisasContext *s, DisasOps *o)
{ {
o->in2 = tcg_temp_new_i64(); o->in2 = tcg_temp_new_i64();
tcg_gen_qemu_ld32u(o->in2, gen_ri2(s), get_mem_index(s)); tcg_gen_qemu_ld_tl(o->in2, gen_ri2(s), get_mem_index(s),
MO_TEUL | MO_ALIGN);
} }
#define SPEC_in2_mri2_32u 0 #define SPEC_in2_mri2_32u 0
static void in2_mri2_64(DisasContext *s, DisasOps *o) static void in2_mri2_64(DisasContext *s, DisasOps *o)
{ {
o->in2 = tcg_temp_new_i64(); o->in2 = tcg_temp_new_i64();
tcg_gen_qemu_ld64(o->in2, gen_ri2(s), get_mem_index(s)); tcg_gen_qemu_ld_i64(o->in2, gen_ri2(s), get_mem_index(s),
MO_TEUQ | MO_ALIGN);
} }
#define SPEC_in2_mri2_64 0 #define SPEC_in2_mri2_64 0

View File

@ -1,11 +1,25 @@
S390X_SRC=$(SRC_PATH)/tests/tcg/s390x S390X_SRC=$(SRC_PATH)/tests/tcg/s390x
VPATH+=$(S390X_SRC) VPATH+=$(S390X_SRC)
QEMU_OPTS=-action panic=exit-failure -kernel QEMU_OPTS=-action panic=exit-failure -kernel
LINK_SCRIPT=$(S390X_SRC)/softmmu.ld
LDFLAGS=-nostdlib -static -Wl,-T$(LINK_SCRIPT) -Wl,--build-id=none
%: %.S %.o: %.S
$(CC) -march=z13 -m64 -nostdlib -static -Wl,-Ttext=0 \ $(CC) -march=z13 -m64 -c $< -o $@
-Wl,--build-id=none $< -o $@
%: %.o $(LINK_SCRIPT)
$(CC) $< -o $@ $(LDFLAGS)
TESTS += unaligned-lowcore TESTS += unaligned-lowcore
TESTS += bal TESTS += bal
TESTS += sam TESTS += sam
TESTS += lpsw
TESTS += lpswe-early
TESTS += ssm-early
TESTS += stosm-early
TESTS += exrl-ssm-early
include $(S390X_SRC)/pgm-specification.mak
$(PGM_SPECIFICATION_TESTS): pgm-specification-softmmu.o
$(PGM_SPECIFICATION_TESTS): LDFLAGS+=pgm-specification-softmmu.o
TESTS += $(PGM_SPECIFICATION_TESTS)

View File

@ -2,6 +2,9 @@ S390X_SRC=$(SRC_PATH)/tests/tcg/s390x
VPATH+=$(S390X_SRC) VPATH+=$(S390X_SRC)
CFLAGS+=-march=zEC12 -m64 CFLAGS+=-march=zEC12 -m64
%.o: %.c
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c $< -o $@
config-cc.mak: Makefile config-cc.mak: Makefile
$(quiet-@)( \ $(quiet-@)( \
$(call cc-option,-march=z14, CROSS_CC_HAS_Z14); \ $(call cc-option,-march=z14, CROSS_CC_HAS_Z14); \
@ -29,10 +32,19 @@ TESTS+=clst
TESTS+=long-double TESTS+=long-double
TESTS+=cdsg TESTS+=cdsg
TESTS+=chrl TESTS+=chrl
TESTS+=rxsbg
TESTS+=ex-relative-long
cdsg: CFLAGS+=-pthread cdsg: CFLAGS+=-pthread
cdsg: LDFLAGS+=-pthread cdsg: LDFLAGS+=-pthread
rxsbg: CFLAGS+=-O2
include $(S390X_SRC)/pgm-specification.mak
$(PGM_SPECIFICATION_TESTS): pgm-specification-user.o
$(PGM_SPECIFICATION_TESTS): LDFLAGS+=pgm-specification-user.o
TESTS += $(PGM_SPECIFICATION_TESTS)
Z13_TESTS=vistr Z13_TESTS=vistr
$(Z13_TESTS): CFLAGS+=-march=z13 -O2 $(Z13_TESTS): CFLAGS+=-march=z13 -O2
TESTS+=$(Z13_TESTS) TESTS+=$(Z13_TESTS)

16
tests/tcg/s390x/br-odd.S Normal file
View File

@ -0,0 +1,16 @@
/*
* Test BRanching to a non-mapped odd address.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
.globl test
test:
lgrl %r1,odd_addr
br %r1
.align 8
odd_addr:
.quad 0xDDDDDDDDDDDDDDDD
.globl expected_old_psw
expected_old_psw:
.quad 0x180000000,0xDDDDDDDDDDDDDDDD

View File

@ -0,0 +1,16 @@
/*
* Test CGRL with a non-doubleword aligned address.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
.globl test
test:
cgrl %r1,unaligned
.align 8
.globl expected_old_psw
expected_old_psw:
.quad 0x180000000,test
.long 0
unaligned:
.quad 0

View File

@ -0,0 +1,16 @@
/*
* Test CLRL with a non-word aligned address.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
.globl test
test:
clrl %r1,unaligned
.align 8
.globl expected_old_psw
expected_old_psw:
.quad 0x180000000,test
.short 0
unaligned:
.long 0

View File

@ -0,0 +1,16 @@
/*
* Test CRL with a non-word aligned address.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
.globl test
test:
crl %r1,unaligned
.align 8
.globl expected_old_psw
expected_old_psw:
.quad 0x180000000,test
.short 0
unaligned:
.long 0

17
tests/tcg/s390x/ex-odd.S Normal file
View File

@ -0,0 +1,17 @@
/*
* Test EXECUTing a non-mapped odd address.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
.globl test
test:
lgrl %r1,odd_addr
fail:
ex 0,0(%r1)
.align 8
odd_addr:
.quad 0xDDDDDDDDDDDDDDDD
.globl expected_old_psw
expected_old_psw:
.quad 0x180000000,fail

View File

@ -0,0 +1,156 @@
/* Check EXECUTE with relative long instructions as targets. */
#include <stdlib.h>
#include <stdio.h>
struct test {
const char *name;
long (*func)(long reg, long *cc);
long exp_reg;
long exp_mem;
long exp_cc;
};
/*
* Each test sets the MEM_IDXth element of the mem array to MEM and uses a
* single relative long instruction on it. The other elements remain zero.
* This is in order to prevent stumbling upon MEM in random memory in case
* there is an off-by-a-small-value bug.
*
* Note that while gcc supports the ZL constraint for relative long operands,
* clang doesn't, so the assembly code accesses mem[MEM_IDX] using MEM_ASM.
*/
static long mem[0x1000];
#define MEM_IDX 0x800
#define MEM_ASM "mem+0x800*8"
/* Initial %r2 value. */
#define REG 0x1234567887654321
/* Initial mem[MEM_IDX] value. */
#define MEM 0xfedcba9889abcdef
/* Initial cc value. */
#define CC 0
/* Relative long instructions and their expected effects. */
#define FOR_EACH_INSN(F) \
F(cgfrl, REG, MEM, 2) \
F(cghrl, REG, MEM, 2) \
F(cgrl, REG, MEM, 2) \
F(chrl, REG, MEM, 1) \
F(clgfrl, REG, MEM, 2) \
F(clghrl, REG, MEM, 2) \
F(clgrl, REG, MEM, 1) \
F(clhrl, REG, MEM, 2) \
F(clrl, REG, MEM, 1) \
F(crl, REG, MEM, 1) \
F(larl, (long)&mem[MEM_IDX], MEM, CC) \
F(lgfrl, 0xfffffffffedcba98, MEM, CC) \
F(lghrl, 0xfffffffffffffedc, MEM, CC) \
F(lgrl, MEM, MEM, CC) \
F(lhrl, 0x12345678fffffedc, MEM, CC) \
F(llghrl, 0x000000000000fedc, MEM, CC) \
F(llhrl, 0x123456780000fedc, MEM, CC) \
F(lrl, 0x12345678fedcba98, MEM, CC) \
F(stgrl, REG, REG, CC) \
F(sthrl, REG, 0x4321ba9889abcdef, CC) \
F(strl, REG, 0x8765432189abcdef, CC)
/* Test functions. */
#define DEFINE_EX_TEST(insn, exp_reg, exp_mem, exp_cc) \
static long test_ex_ ## insn(long reg, long *cc) \
{ \
register long r2 asm("r2"); \
char mask = 0x20; /* make target use %r2 */ \
long pm, target; \
\
r2 = reg; \
asm("larl %[target],0f\n" \
"cr %%r0,%%r0\n" /* initial cc */ \
"ex %[mask],0(%[target])\n" \
"jg 1f\n" \
"0: " #insn " %%r0," MEM_ASM "\n" \
"1: ipm %[pm]\n" \
: [target] "=&a" (target), [r2] "+r" (r2), [pm] "=r" (pm) \
: [mask] "a" (mask) \
: "cc", "memory"); \
reg = r2; \
*cc = (pm >> 28) & 3; \
\
return reg; \
}
#define DEFINE_EXRL_TEST(insn, exp_reg, exp_mem, exp_cc) \
static long test_exrl_ ## insn(long reg, long *cc) \
{ \
register long r2 asm("r2"); \
char mask = 0x20; /* make target use %r2 */ \
long pm; \
\
r2 = reg; \
asm("cr %%r0,%%r0\n" /* initial cc */ \
"exrl %[mask],0f\n" \
"jg 1f\n" \
"0: " #insn " %%r0," MEM_ASM "\n" \
"1: ipm %[pm]\n" \
: [r2] "+r" (r2), [pm] "=r" (pm) \
: [mask] "a" (mask) \
: "cc", "memory"); \
reg = r2; \
*cc = (pm >> 28) & 3; \
\
return reg; \
}
FOR_EACH_INSN(DEFINE_EX_TEST)
FOR_EACH_INSN(DEFINE_EXRL_TEST)
/* Test definitions. */
#define REGISTER_EX_EXRL_TEST(ex_insn, insn, _exp_reg, _exp_mem, _exp_cc) \
{ \
.name = #ex_insn " " #insn, \
.func = test_ ## ex_insn ## _ ## insn, \
.exp_reg = (_exp_reg), \
.exp_mem = (_exp_mem), \
.exp_cc = (_exp_cc), \
},
#define REGISTER_EX_TEST(insn, exp_reg, exp_mem, exp_cc) \
REGISTER_EX_EXRL_TEST(ex, insn, exp_reg, exp_mem, exp_cc)
#define REGISTER_EXRL_TEST(insn, exp_reg, exp_mem, exp_cc) \
REGISTER_EX_EXRL_TEST(exrl, insn, exp_reg, exp_mem, exp_cc)
static const struct test tests[] = {
FOR_EACH_INSN(REGISTER_EX_TEST)
FOR_EACH_INSN(REGISTER_EXRL_TEST)
};
/* Loop over all tests and run them. */
int main(void)
{
const struct test *test;
int ret = EXIT_SUCCESS;
long reg, cc;
size_t i;
for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
test = &tests[i];
mem[MEM_IDX] = MEM;
cc = -1;
reg = test->func(REG, &cc);
#define ASSERT_EQ(expected, actual) do { \
if (expected != actual) { \
fprintf(stderr, "%s: " #expected " (0x%lx) != " #actual " (0x%lx)\n", \
test->name, expected, actual); \
ret = EXIT_FAILURE; \
} \
} while (0)
ASSERT_EQ(test->exp_reg, reg);
ASSERT_EQ(test->exp_mem, mem[MEM_IDX]);
ASSERT_EQ(test->exp_cc, cc);
#undef ASSERT_EQ
}
return ret;
}

View File

@ -0,0 +1,43 @@
/*
* Test early exception recognition using EXRL + SSM.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
.org 0x8d
ilc:
.org 0x8e
program_interruption_code:
.org 0x150
program_old_psw:
.org 0x1D0 /* program new PSW */
.quad 0,pgm
.org 0x200 /* lowcore padding */
.globl _start
_start:
exrl %r0,ssm
expected_pswa:
j failure
ssm:
ssm ssm_op
pgm:
chhsi program_interruption_code,0x6 /* specification exception? */
jne failure
cli ilc,6 /* ilc for EXRL? */
jne failure
clc program_old_psw(16),expected_old_psw /* correct old PSW? */
jne failure
lpswe success_psw
failure:
lpswe failure_psw
ssm_op:
.byte 0x08 /* bit 4 set */
.align 8
expected_old_psw:
.quad 0x0800000180000000,expected_pswa /* bit 2 set */
success_psw:
.quad 0x2000000000000,0xfff /* see is_special_wait_psw() */
failure_psw:
.quad 0x2000000000000,0 /* disabled wait */

View File

@ -0,0 +1,16 @@
/*
* Test LGRL from a non-doubleword aligned address.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
.globl test
test:
lgrl %r1,unaligned
.align 8
.globl expected_old_psw
expected_old_psw:
.quad 0x180000000,test
.long 0
unaligned:
.quad 0

View File

@ -0,0 +1,16 @@
/*
* Test LLGFRL from a non-word aligned address.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
.globl test
test:
llgfrl %r1,unaligned
.align 8
.globl expected_old_psw
expected_old_psw:
.quad 0x180000000,test
.short 0
unaligned:
.long 0

36
tests/tcg/s390x/lpsw.S Normal file
View File

@ -0,0 +1,36 @@
/*
* Test the LPSW instruction.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
.org 0x140
svc_old_psw:
.org 0x1c0 /* supervisor call new PSW */
.quad 0x80000000,svc /* 31-bit mode */
.org 0x200 /* lowcore padding */
.globl _start
_start:
lpsw short_psw
lpsw_target:
svc 0
expected_pswa:
j failure
svc:
clc svc_old_psw(16),expected_psw /* correct full PSW? */
jne failure
lpswe success_psw
failure:
lpswe failure_psw
.align 8
short_psw:
.long 0x90001,0x80000000+lpsw_target /* problem state,
64-bit mode */
expected_psw:
.quad 0x1000180000000,expected_pswa /* corresponds to short_psw */
success_psw:
.quad 0x2000000000000,0xfff /* see is_special_wait_psw() */
failure_psw:
.quad 0x2000000000000,0 /* disabled wait */

View File

@ -0,0 +1,38 @@
/*
* Test early exception recognition using LPSWE.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
.org 0x8d
ilc:
.org 0x8e
program_interruption_code:
.org 0x150
program_old_psw:
.org 0x1D0 /* program new PSW */
.quad 0,pgm
.org 0x200 /* lowcore padding */
.globl _start
_start:
lpswe bad_psw
j failure
pgm:
chhsi program_interruption_code,0x6 /* specification exception? */
jne failure
cli ilc,0 /* ilc zero? */
jne failure
clc program_old_psw(16),bad_psw /* correct old PSW? */
jne failure
lpswe success_psw
failure:
lpswe failure_psw
.align 8
bad_psw:
.quad 0x8000000000000000,0xfedcba9876543210 /* bit 0 set */
success_psw:
.quad 0x2000000000000,0xfff /* see is_special_wait_psw() */
failure_psw:
.quad 0x2000000000000,0 /* disabled wait */

View File

@ -0,0 +1,18 @@
/*
* Test LPSWE from a non-doubleword aligned address.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
.globl test
test:
larl %r1,unaligned
fail:
lpswe 0(%r1)
.align 8
.globl expected_old_psw
expected_old_psw:
.quad 0x180000000,fail
.long 0
unaligned:
.quad 0

View File

@ -0,0 +1,16 @@
/*
* Test LRL from a non-word aligned address.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
.globl test
test:
lrl %r1,unaligned
.align 8
.globl expected_old_psw
expected_old_psw:
.quad 0x180000000,test
.short 0
unaligned:
.long 0

View File

@ -0,0 +1,40 @@
/*
* Common softmmu code for specification exception testing.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
.section .head
.org 0x8d
ilc:
.org 0x8e
program_interruption_code:
.org 0x150
program_old_psw:
.org 0x1D0 /* program new PSW */
.quad 0x180000000,pgm /* 64-bit mode */
.org 0x200 /* lowcore padding */
.globl _start
_start:
lpswe test_psw
pgm:
chhsi program_interruption_code,0x6 /* PGM_SPECIFICATION? */
jne failure
lg %r0,expected_old_psw+8 /* ilc adjustment */
llgc %r1,ilc
agr %r0,%r1
stg %r0,expected_old_psw+8
clc expected_old_psw(16),program_old_psw /* correct location? */
jne failure
lpswe success_psw
failure:
lpswe failure_psw
.align 8
test_psw:
.quad 0x180000000,test /* 64-bit mode */
success_psw:
.quad 0x2000180000000,0xfff /* see is_special_wait_psw() */
failure_psw:
.quad 0x2000180000000,0 /* disabled wait */

View File

@ -0,0 +1,37 @@
/*
* Common user code for specification exception testing.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <assert.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
extern void test(void);
extern long expected_old_psw[2];
static void handle_sigill(int sig, siginfo_t *info, void *ucontext)
{
if ((long)info->si_addr != expected_old_psw[1]) {
_exit(EXIT_FAILURE);
}
_exit(EXIT_SUCCESS);
}
int main(void)
{
struct sigaction act;
int err;
memset(&act, 0, sizeof(act));
act.sa_sigaction = handle_sigill;
act.sa_flags = SA_SIGINFO;
err = sigaction(SIGILL, &act, NULL);
assert(err == 0);
test();
return EXIT_FAILURE;
}

View File

@ -0,0 +1,15 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# List of specification exception tests.
# Shared between the softmmu and the user makefiles.
PGM_SPECIFICATION_TESTS = \
br-odd \
cgrl-unaligned \
clrl-unaligned \
crl-unaligned \
ex-odd \
lgrl-unaligned \
llgfrl-unaligned \
lpswe-unaligned \
lrl-unaligned \
stgrl-unaligned \
strl-unaligned

46
tests/tcg/s390x/rxsbg.c Normal file
View File

@ -0,0 +1,46 @@
/*
* Test the RXSBG instruction.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <assert.h>
#include <stdlib.h>
static inline __attribute__((__always_inline__)) void
rxsbg(unsigned long *r1, unsigned long r2, int i3, int i4, int i5, int *cc)
{
asm("rxsbg %[r1],%[r2],%[i3],%[i4],%[i5]\n"
"ipm %[cc]"
: [r1] "+r" (*r1), [cc] "=r" (*cc)
: [r2] "r" (r2) , [i3] "i" (i3) , [i4] "i" (i4) , [i5] "i" (i5)
: "cc");
*cc = (*cc >> 28) & 3;
}
void test_cc0(void)
{
unsigned long r1 = 6;
int cc;
rxsbg(&r1, 3, 61 | 0x80, 62, 1, &cc);
assert(r1 == 6);
assert(cc == 0);
}
void test_cc1(void)
{
unsigned long r1 = 2;
int cc;
rxsbg(&r1, 3, 61 | 0x80, 62, 1, &cc);
assert(r1 == 2);
assert(cc == 1);
}
int main(void)
{
test_cc0();
test_cc1();
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,20 @@
/*
* Linker script for the softmmu test kernels.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
ENTRY(_start)
SECTIONS {
. = 0;
.text : {
*(.head)
*(.text)
}
/DISCARD/ : {
*(*)
}
}

View File

@ -0,0 +1,41 @@
/*
* Test early exception recognition using SSM.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
.org 0x8d
ilc:
.org 0x8e
program_interruption_code:
.org 0x150
program_old_psw:
.org 0x1D0 /* program new PSW */
.quad 0,pgm
.org 0x200 /* lowcore padding */
.globl _start
_start:
ssm ssm_op
expected_pswa:
j failure
pgm:
chhsi program_interruption_code,0x6 /* specification exception? */
jne failure
cli ilc,4 /* ilc for SSM? */
jne failure
clc program_old_psw(16),expected_old_psw /* correct old PSW? */
jne failure
lpswe success_psw
failure:
lpswe failure_psw
ssm_op:
.byte 0x20 /* bit 2 set */
.align 8
expected_old_psw:
.quad 0x2000000180000000,expected_pswa /* bit 2 set */
success_psw:
.quad 0x2000000000000,0xfff /* see is_special_wait_psw() */
failure_psw:
.quad 0x2000000000000,0 /* disabled wait */

View File

@ -0,0 +1,16 @@
/*
* Test STGRL to a non-doubleword aligned address.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
.globl test
test:
stgrl %r1,unaligned
.align 8
.globl expected_old_psw
expected_old_psw:
.quad 0x180000000,test
.long 0
unaligned:
.quad 0

View File

@ -0,0 +1,41 @@
/*
* Test early exception recognition using STOSM.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
.org 0x8d
ilc:
.org 0x8e
program_interruption_code:
.org 0x150
program_old_psw:
.org 0x1D0 /* program new PSW */
.quad 0,pgm
.org 0x200 /* lowcore padding */
.globl _start
_start:
stosm ssm_op,0x10 /* bit 3 set */
expected_pswa:
j failure
pgm:
chhsi program_interruption_code,0x6 /* specification exception? */
jne failure
cli ilc,4 /* ilc for STOSM? */
jne failure
clc program_old_psw(16),expected_old_psw /* correct old PSW? */
jne failure
lpswe success_psw
failure:
lpswe failure_psw
ssm_op:
.byte 0
.align 8
expected_old_psw:
.quad 0x1000000180000000,expected_pswa /* bit 3 set */
success_psw:
.quad 0x2000000000000,0xfff /* see is_special_wait_psw() */
failure_psw:
.quad 0x2000000000000,0 /* disabled wait */

View File

@ -0,0 +1,16 @@
/*
* Test STRL to a non-word aligned address.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
.globl test
test:
strl %r1,unaligned
.align 8
.globl expected_old_psw
expected_old_psw:
.quad 0x180000000,test
.short 0
unaligned:
.long 0

View File

@ -531,6 +531,13 @@ int main(int argc, char **argv)
g_test_add_func("/blockjob/cancel/standby", test_cancel_standby); g_test_add_func("/blockjob/cancel/standby", test_cancel_standby);
g_test_add_func("/blockjob/cancel/pending", test_cancel_pending); g_test_add_func("/blockjob/cancel/pending", test_cancel_pending);
g_test_add_func("/blockjob/cancel/concluded", test_cancel_concluded); g_test_add_func("/blockjob/cancel/concluded", test_cancel_concluded);
/*
* This test is flaky and sometimes fails in CI and otherwise:
* don't run unless user opts in via environment variable.
*/
if (getenv("QEMU_TEST_FLAKY_TESTS")) {
g_test_add_func("/blockjob/complete_in_standby", test_complete_in_standby); g_test_add_func("/blockjob/complete_in_standby", test_complete_in_standby);
}
return g_test_run(); return g_test_run();
} }