Queued s390 patches

-----BEGIN PGP SIGNATURE-----
 
 iQEcBAABAgAGBQJZN0ZVAAoJEK0ScMxN0CebytMIAIwTia8mBPc7Oa42F4OBvv5y
 jX8vTnI63Xg7TfLQVlufk69xvJw6z+xagPlHVJcpINtxXQhg7ER3Gc4Ny0U9cmAj
 Sw7Es4ErxYizs11mZotAxcXU71paLoJ+kDa/l7HGni//6GQ7qIlFyvBjS26FQD9/
 V6ZiQxEprgpGVjNbTwRFrJpVu8tSi/bHXkPJWW6PZ6qfFJBS85mT0xsS7pCHCQAL
 rxGtoS2cPU5sqP7jrNNJkc95Hkzp+ffYdF5JtBOcH7Nf8G8UkLzopdlE3Z6YqvV7
 ABawNcRSBDEs7O2CIRnB6AlISWV19TUjCjW3gKiSaS+p08flAdHHrGJ/w5hHAY0=
 =3bqT
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/rth/tags/pull-s390-20170606' into staging

Queued s390 patches

# gpg: Signature made Wed 07 Jun 2017 01:18:29 BST
# gpg:                using RSA key 0xAD1270CC4DD0279B
# gpg: Good signature from "Richard Henderson <rth7680@gmail.com>"
# gpg:                 aka "Richard Henderson <rth@redhat.com>"
# gpg:                 aka "Richard Henderson <rth@twiddle.net>"
# Primary key fingerprint: 9CB1 8DDA F8E8 49AD 2AFC  16A4 AD12 70CC 4DD0 279B

* remotes/rth/tags/pull-s390-20170606: (70 commits)
  target/s390x: addressing exceptions are suppressing
  target/s390x: mark ETF2 and ETF2-ENH facilities as available
  target/s390x: check alignment in CDSG in the !CONFIG_ATOMIC128 case
  target/s390x: implement STORE PAIR TO QUADWORD
  target/s390x: implement LOAD PAIR FROM QUADWORD
  target/s390x: implement TRANSLATE ONE/TWO TO ONE/TWO
  target/s390x: implement TEST DECIMAL
  target/s390x: implement UNPACK UNICODE
  target/s390x: implement UNPACK ASCII
  target/s390x: implement PACK UNICODE
  target/s390x: implement PACK ASCII
  target/s390x: implement MOVE LONG UNICODE
  target/s390x: implement COMPARE LOGICAL LONG UNICODE
  target/s390x: improve MOVE LONG and MOVE LONG EXTENDED
  target/s390x: fix adj_len_to_page
  target/s390x: implement COMPARE LOGICAL LONG
  target/s390x: fix COMPARE LOGICAL LONG EXTENDED
  target/s390x: improve 24-bit and 31-bit lengths read/write
  target/s390x: improve 24-bit and 31-bit addresses write
  target/s390x: improve 24-bit and 31-bit addresses read
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2017-06-07 10:14:54 +01:00
commit 8b3e9ca74c
11 changed files with 1565 additions and 508 deletions

View File

@ -107,6 +107,8 @@ typedef struct CPUS390XState {
uint64_t cc_dst; uint64_t cc_dst;
uint64_t cc_vr; uint64_t cc_vr;
uint64_t ex_value;
uint64_t __excp_addr; uint64_t __excp_addr;
uint64_t psa; uint64_t psa;
@ -393,7 +395,7 @@ 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)
{ {
*pc = env->psw.addr; *pc = env->psw.addr;
*cs_base = 0; *cs_base = env->ex_value;
*flags = ((env->psw.mask >> 32) & ~FLAG_MASK_CC) | *flags = ((env->psw.mask >> 32) & ~FLAG_MASK_CC) |
((env->psw.mask & PSW_MASK_32) ? FLAG_MASK_32 : 0); ((env->psw.mask & PSW_MASK_32) ? FLAG_MASK_32 : 0);
} }
@ -1033,6 +1035,8 @@ struct sysib_322 {
#define _SEGMENT_ENTRY_RO 0x200 /* page protection bit */ #define _SEGMENT_ENTRY_RO 0x200 /* page protection bit */
#define _SEGMENT_ENTRY_INV 0x20 /* invalid segment table entry */ #define _SEGMENT_ENTRY_INV 0x20 /* invalid segment table entry */
#define VADDR_PX 0xff000 /* page index bits */
#define _PAGE_RO 0x200 /* HW read-only bit */ #define _PAGE_RO 0x200 /* HW read-only bit */
#define _PAGE_INVALID 0x400 /* HW invalid bit */ #define _PAGE_INVALID 0x400 /* HW invalid bit */
#define _PAGE_RES0 0x800 /* bit must be zero */ #define _PAGE_RES0 0x800 /* bit must be zero */
@ -1084,6 +1088,7 @@ struct sysib_322 {
#define SIGP_ORDER_MASK 0x000000ff #define SIGP_ORDER_MASK 0x000000ff
void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr); void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr);
target_ulong mmu_real2abs(CPUS390XState *env, target_ulong raddr);
int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc, int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
target_ulong *raddr, int *flags, bool exc); target_ulong *raddr, int *flags, bool exc);
int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code); int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code);

View File

@ -658,6 +658,32 @@ static void check_compatibility(const S390CPUModel *max_model,
"available in the configuration: "); "available in the configuration: ");
} }
/**
* The base TCG CPU model "qemu" is based on the z900. However, we already
* can also emulate some additional features of later CPU generations, so
* we add these additional feature bits here.
*/
static void add_qemu_cpu_model_features(S390FeatBitmap fbm)
{
static const int feats[] = {
S390_FEAT_STFLE,
S390_FEAT_EXTENDED_IMMEDIATE,
S390_FEAT_EXTENDED_TRANSLATION_2,
S390_FEAT_LONG_DISPLACEMENT,
S390_FEAT_LONG_DISPLACEMENT_FAST,
S390_FEAT_ETF2_ENH,
S390_FEAT_STORE_CLOCK_FAST,
S390_FEAT_GENERAL_INSTRUCTIONS_EXT,
S390_FEAT_EXECUTE_EXT,
S390_FEAT_STFLE_45,
};
int i;
for (i = 0; i < ARRAY_SIZE(feats); i++) {
set_bit(feats[i], fbm);
}
}
static S390CPUModel *get_max_cpu_model(Error **errp) static S390CPUModel *get_max_cpu_model(Error **errp)
{ {
static S390CPUModel max_model; static S390CPUModel max_model;
@ -670,10 +696,11 @@ static S390CPUModel *get_max_cpu_model(Error **errp)
if (kvm_enabled()) { if (kvm_enabled()) {
kvm_s390_get_host_cpu_model(&max_model, errp); kvm_s390_get_host_cpu_model(&max_model, errp);
} else { } else {
/* TCG emulates a z900 */ /* TCG emulates a z900 (with some optional additional features) */
max_model.def = &s390_cpu_defs[0]; max_model.def = &s390_cpu_defs[0];
bitmap_copy(max_model.features, max_model.def->default_feat, bitmap_copy(max_model.features, max_model.def->default_feat,
S390_FEAT_MAX); S390_FEAT_MAX);
add_qemu_cpu_model_features(max_model.features);
} }
if (!*errp) { if (!*errp) {
cached = true; cached = true;
@ -925,11 +952,14 @@ static void s390_host_cpu_model_initfn(Object *obj)
static void s390_qemu_cpu_model_initfn(Object *obj) static void s390_qemu_cpu_model_initfn(Object *obj)
{ {
static S390CPUDef s390_qemu_cpu_defs;
S390CPU *cpu = S390_CPU(obj); S390CPU *cpu = S390_CPU(obj);
cpu->model = g_malloc0(sizeof(*cpu->model)); cpu->model = g_malloc0(sizeof(*cpu->model));
/* TCG emulates a z900 */ /* TCG emulates a z900 (with some optional additional features) */
cpu->model->def = &s390_cpu_defs[0]; memcpy(&s390_qemu_cpu_defs, &s390_cpu_defs[0], sizeof(s390_qemu_cpu_defs));
add_qemu_cpu_model_features(s390_qemu_cpu_defs.full_feat);
cpu->model->def = &s390_qemu_cpu_defs;
bitmap_copy(cpu->model->features, cpu->model->def->default_feat, bitmap_copy(cpu->model->features, cpu->model->def->default_feat,
S390_FEAT_MAX); S390_FEAT_MAX);
} }

View File

@ -585,6 +585,33 @@ uint64_t HELPER(fixb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint32_t m3)
return RET128(ret); return RET128(ret);
} }
/* 32-bit FP compare and signal */
uint32_t HELPER(keb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
{
int cmp = float32_compare(f1, f2, &env->fpu_status);
handle_exceptions(env, GETPC());
return float_comp_to_cc(env, cmp);
}
/* 64-bit FP compare and signal */
uint32_t HELPER(kdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
{
int cmp = float64_compare(f1, f2, &env->fpu_status);
handle_exceptions(env, GETPC());
return float_comp_to_cc(env, cmp);
}
/* 128-bit FP compare and signal */
uint32_t HELPER(kxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
uint64_t bh, uint64_t bl)
{
int cmp = float128_compare(make_float128(ah, al),
make_float128(bh, bl),
&env->fpu_status);
handle_exceptions(env, GETPC());
return float_comp_to_cc(env, cmp);
}
/* 32-bit FP multiply and add */ /* 32-bit FP multiply and add */
uint64_t HELPER(maeb)(CPUS390XState *env, uint64_t f1, uint64_t HELPER(maeb)(CPUS390XState *env, uint64_t f1,
uint64_t f2, uint64_t f3) uint64_t f2, uint64_t f3)

View File

@ -204,7 +204,7 @@ int s390_cpu_handle_mmu_fault(CPUState *cs, vaddr orig_vaddr,
if (raddr > ram_size) { if (raddr > ram_size) {
DPRINTF("%s: raddr %" PRIx64 " > ram_size %" PRIx64 "\n", __func__, DPRINTF("%s: raddr %" PRIx64 " > ram_size %" PRIx64 "\n", __func__,
(uint64_t)raddr, (uint64_t)ram_size); (uint64_t)raddr, (uint64_t)ram_size);
trigger_pgm_exception(env, PGM_ADDRESSING, ILEN_LATER); trigger_pgm_exception(env, PGM_ADDRESSING, ILEN_LATER_INC);
return 1; return 1;
} }
@ -642,6 +642,11 @@ bool s390_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
S390CPU *cpu = S390_CPU(cs); S390CPU *cpu = S390_CPU(cs);
CPUS390XState *env = &cpu->env; CPUS390XState *env = &cpu->env;
if (env->ex_value) {
/* Execution of the target insn is indivisible from
the parent EXECUTE insn. */
return false;
}
if (env->psw.mask & PSW_MASK_EXT) { if (env->psw.mask & PSW_MASK_EXT) {
s390_cpu_do_interrupt(cs); s390_cpu_do_interrupt(cs);
return true; return true;

View File

@ -3,8 +3,10 @@ DEF_HELPER_FLAGS_4(nc, TCG_CALL_NO_WG, i32, env, i32, i64, i64)
DEF_HELPER_FLAGS_4(oc, TCG_CALL_NO_WG, i32, env, i32, i64, i64) DEF_HELPER_FLAGS_4(oc, TCG_CALL_NO_WG, i32, env, i32, i64, i64)
DEF_HELPER_FLAGS_4(xc, TCG_CALL_NO_WG, i32, env, i32, i64, i64) DEF_HELPER_FLAGS_4(xc, TCG_CALL_NO_WG, i32, env, i32, i64, i64)
DEF_HELPER_FLAGS_4(mvc, TCG_CALL_NO_WG, void, env, i32, i64, i64) DEF_HELPER_FLAGS_4(mvc, TCG_CALL_NO_WG, void, env, i32, i64, i64)
DEF_HELPER_FLAGS_4(mvcin, TCG_CALL_NO_WG, void, env, i32, i64, i64)
DEF_HELPER_FLAGS_4(clc, TCG_CALL_NO_WG, i32, env, i32, i64, i64) DEF_HELPER_FLAGS_4(clc, TCG_CALL_NO_WG, i32, env, i32, i64, i64)
DEF_HELPER_3(mvcl, i32, env, i32, i32) DEF_HELPER_3(mvcl, i32, env, i32, i32)
DEF_HELPER_3(clcl, i32, env, i32, i32)
DEF_HELPER_FLAGS_4(clm, TCG_CALL_NO_WG, i32, env, i32, i32, i64) DEF_HELPER_FLAGS_4(clm, TCG_CALL_NO_WG, i32, env, i32, i32, i64)
DEF_HELPER_FLAGS_3(divs32, TCG_CALL_NO_WG, s64, env, s64, s64) DEF_HELPER_FLAGS_3(divs32, TCG_CALL_NO_WG, s64, env, s64, s64)
DEF_HELPER_FLAGS_3(divu32, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_3(divu32, TCG_CALL_NO_WG, i64, env, i64, i64)
@ -12,13 +14,18 @@ DEF_HELPER_FLAGS_3(divs64, TCG_CALL_NO_WG, s64, env, s64, s64)
DEF_HELPER_FLAGS_4(divu64, TCG_CALL_NO_WG, i64, env, i64, i64, i64) DEF_HELPER_FLAGS_4(divu64, TCG_CALL_NO_WG, i64, env, i64, i64, i64)
DEF_HELPER_4(srst, i64, env, i64, i64, i64) DEF_HELPER_4(srst, i64, env, i64, i64, i64)
DEF_HELPER_4(clst, i64, env, i64, i64, i64) DEF_HELPER_4(clst, i64, env, i64, i64, i64)
DEF_HELPER_4(mvpg, void, env, i64, i64, i64) 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(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_4(mvst, i64, env, i64, i64, i64) DEF_HELPER_4(mvst, i64, env, i64, i64, i64)
DEF_HELPER_5(ex, i32, env, i32, i64, 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)
DEF_HELPER_4(mvcle, i32, env, i32, i64, i32) DEF_HELPER_4(mvcle, i32, env, i32, i64, i32)
DEF_HELPER_4(mvclu, i32, env, i32, i64, i32)
DEF_HELPER_4(clcle, i32, env, i32, i64, i32) DEF_HELPER_4(clcle, i32, env, i32, i64, i32)
DEF_HELPER_4(clclu, i32, env, i32, i64, i32)
DEF_HELPER_3(cegb, i64, env, s64, i32) DEF_HELPER_3(cegb, i64, env, s64, i32)
DEF_HELPER_3(cdgb, i64, env, s64, i32) DEF_HELPER_3(cdgb, i64, env, s64, i32)
DEF_HELPER_3(cxgb, i64, env, s64, i32) DEF_HELPER_3(cxgb, i64, env, s64, i32)
@ -49,6 +56,9 @@ DEF_HELPER_FLAGS_3(lexb, TCG_CALL_NO_WG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(ceb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) DEF_HELPER_FLAGS_3(ceb, TCG_CALL_NO_WG_SE, i32, env, i64, i64)
DEF_HELPER_FLAGS_3(cdb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) DEF_HELPER_FLAGS_3(cdb, TCG_CALL_NO_WG_SE, i32, env, i64, i64)
DEF_HELPER_FLAGS_5(cxb, TCG_CALL_NO_WG_SE, i32, env, i64, i64, i64, i64) DEF_HELPER_FLAGS_5(cxb, TCG_CALL_NO_WG_SE, i32, env, i64, i64, i64, i64)
DEF_HELPER_FLAGS_3(keb, TCG_CALL_NO_WG, i32, env, i64, i64)
DEF_HELPER_FLAGS_3(kdb, TCG_CALL_NO_WG, i32, env, i64, i64)
DEF_HELPER_FLAGS_5(kxb, TCG_CALL_NO_WG, i32, env, i64, i64, i64, i64)
DEF_HELPER_FLAGS_3(cgeb, TCG_CALL_NO_WG, i64, env, i64, i32) DEF_HELPER_FLAGS_3(cgeb, TCG_CALL_NO_WG, i64, env, i64, i32)
DEF_HELPER_FLAGS_3(cgdb, TCG_CALL_NO_WG, i64, env, i64, i32) DEF_HELPER_FLAGS_3(cgdb, TCG_CALL_NO_WG, i64, env, i64, i32)
DEF_HELPER_FLAGS_4(cgxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32) DEF_HELPER_FLAGS_4(cgxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32)
@ -75,10 +85,17 @@ DEF_HELPER_FLAGS_2(sqeb, TCG_CALL_NO_WG, i64, env, i64)
DEF_HELPER_FLAGS_2(sqdb, TCG_CALL_NO_WG, i64, env, i64) DEF_HELPER_FLAGS_2(sqdb, TCG_CALL_NO_WG, i64, env, i64)
DEF_HELPER_FLAGS_3(sqxb, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_3(sqxb, TCG_CALL_NO_WG, i64, env, i64, i64)
DEF_HELPER_FLAGS_1(cvd, TCG_CALL_NO_RWG_SE, i64, s32) DEF_HELPER_FLAGS_1(cvd, TCG_CALL_NO_RWG_SE, i64, s32)
DEF_HELPER_FLAGS_4(pack, TCG_CALL_NO_WG, void, env, i32, i64, i64)
DEF_HELPER_FLAGS_4(pka, TCG_CALL_NO_WG, void, env, i64, i64, i32)
DEF_HELPER_FLAGS_4(pku, TCG_CALL_NO_WG, void, env, i64, i64, i32)
DEF_HELPER_FLAGS_4(unpk, TCG_CALL_NO_WG, void, env, i32, i64, i64) DEF_HELPER_FLAGS_4(unpk, TCG_CALL_NO_WG, void, env, i32, i64, i64)
DEF_HELPER_FLAGS_4(unpka, TCG_CALL_NO_WG, i32, env, i64, i32, i64)
DEF_HELPER_FLAGS_4(unpku, TCG_CALL_NO_WG, i32, env, i64, i32, i64)
DEF_HELPER_FLAGS_3(tp, TCG_CALL_NO_WG, i32, env, i64, i32)
DEF_HELPER_FLAGS_4(tr, TCG_CALL_NO_WG, void, env, i32, i64, i64) DEF_HELPER_FLAGS_4(tr, TCG_CALL_NO_WG, void, env, i32, i64, i64)
DEF_HELPER_4(tre, i64, env, i64, i64, i64) DEF_HELPER_4(tre, i64, env, i64, i64, i64)
DEF_HELPER_4(trt, i32, env, i32, i64, i64) DEF_HELPER_4(trt, i32, env, i32, i64, i64)
DEF_HELPER_5(trXX, i32, env, i32, i32, i32, i32)
DEF_HELPER_4(cksm, i64, env, i64, i64, i64) DEF_HELPER_4(cksm, i64, env, i64, i64, i64)
DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, i32, env, i32, i64, i64, i64) DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, i32, env, i32, i64, i64, i64)
DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_NO_RWG, void, env, i64)
@ -86,6 +103,8 @@ DEF_HELPER_FLAGS_2(sfas, TCG_CALL_NO_WG, void, env, i64)
DEF_HELPER_FLAGS_1(popcnt, TCG_CALL_NO_RWG_SE, i64, i64) DEF_HELPER_FLAGS_1(popcnt, TCG_CALL_NO_RWG_SE, i64, i64)
DEF_HELPER_FLAGS_1(stfl, TCG_CALL_NO_RWG, void, env) DEF_HELPER_FLAGS_1(stfl, TCG_CALL_NO_RWG, void, env)
DEF_HELPER_2(stfle, i32, env, i64) DEF_HELPER_2(stfle, i32, env, i64)
DEF_HELPER_FLAGS_2(lpq, TCG_CALL_NO_WG, i64, env, i64)
DEF_HELPER_FLAGS_4(stpq, TCG_CALL_NO_WG, void, env, i64, i64, i64)
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
DEF_HELPER_3(servc, i32, env, i64, i64) DEF_HELPER_3(servc, i32, env, i64, i64)
@ -102,17 +121,18 @@ DEF_HELPER_FLAGS_4(lctl, TCG_CALL_NO_WG, void, env, i32, i64, i32)
DEF_HELPER_FLAGS_4(lctlg, TCG_CALL_NO_WG, void, env, i32, i64, i32) DEF_HELPER_FLAGS_4(lctlg, TCG_CALL_NO_WG, void, env, i32, i64, i32)
DEF_HELPER_FLAGS_4(stctl, TCG_CALL_NO_WG, void, env, i32, i64, i32) DEF_HELPER_FLAGS_4(stctl, TCG_CALL_NO_WG, void, env, i32, i64, i32)
DEF_HELPER_FLAGS_4(stctg, TCG_CALL_NO_WG, void, env, i32, i64, i32) DEF_HELPER_FLAGS_4(stctg, TCG_CALL_NO_WG, void, env, i32, i64, i32)
DEF_HELPER_FLAGS_2(testblock, TCG_CALL_NO_WG, i32, env, i64)
DEF_HELPER_FLAGS_2(tprot, TCG_CALL_NO_RWG, i32, i64, i64) DEF_HELPER_FLAGS_2(tprot, TCG_CALL_NO_RWG, i32, i64, i64)
DEF_HELPER_FLAGS_2(iske, TCG_CALL_NO_RWG_SE, i64, env, i64) DEF_HELPER_FLAGS_2(iske, TCG_CALL_NO_RWG_SE, i64, env, i64)
DEF_HELPER_FLAGS_3(sske, TCG_CALL_NO_RWG, void, env, i64, i64) DEF_HELPER_FLAGS_3(sske, TCG_CALL_NO_RWG, void, env, i64, i64)
DEF_HELPER_FLAGS_2(rrbe, TCG_CALL_NO_RWG, i32, env, i64) DEF_HELPER_FLAGS_2(rrbe, TCG_CALL_NO_RWG, i32, env, i64)
DEF_HELPER_3(csp, i32, env, i32, i64)
DEF_HELPER_4(mvcs, i32, env, i64, i64, i64) DEF_HELPER_4(mvcs, i32, env, i64, i64, i64)
DEF_HELPER_4(mvcp, i32, env, i64, i64, i64) DEF_HELPER_4(mvcp, i32, env, i64, i64, i64)
DEF_HELPER_4(sigp, i32, env, i64, i32, i64) DEF_HELPER_4(sigp, i32, env, i64, i32, i64)
DEF_HELPER_FLAGS_2(sacf, TCG_CALL_NO_WG, void, env, i64) DEF_HELPER_FLAGS_2(sacf, TCG_CALL_NO_WG, void, env, i64)
DEF_HELPER_FLAGS_3(ipte, TCG_CALL_NO_RWG, void, env, i64, i64) DEF_HELPER_FLAGS_4(ipte, TCG_CALL_NO_RWG, void, env, i64, i64, i32)
DEF_HELPER_FLAGS_1(ptlb, TCG_CALL_NO_RWG, void, env) DEF_HELPER_FLAGS_1(ptlb, TCG_CALL_NO_RWG, void, env)
DEF_HELPER_FLAGS_1(purge, TCG_CALL_NO_RWG, void, env)
DEF_HELPER_2(lra, i64, env, i64) DEF_HELPER_2(lra, i64, env, i64)
DEF_HELPER_FLAGS_2(lura, TCG_CALL_NO_WG, i64, env, i64) DEF_HELPER_FLAGS_2(lura, TCG_CALL_NO_WG, i64, env, i64)
DEF_HELPER_FLAGS_2(lurag, TCG_CALL_NO_WG, i64, env, i64) DEF_HELPER_FLAGS_2(lurag, TCG_CALL_NO_WG, i64, env, i64)

View File

@ -154,6 +154,12 @@
C(0xb349, CXBR, RRE, Z, x1_o, x2_o, 0, 0, cxb, 0) C(0xb349, CXBR, RRE, Z, x1_o, x2_o, 0, 0, cxb, 0)
C(0xed09, CEB, RXE, Z, e1, m2_32u, 0, 0, ceb, 0) C(0xed09, CEB, RXE, Z, e1, m2_32u, 0, 0, ceb, 0)
C(0xed19, CDB, RXE, Z, f1_o, m2_64, 0, 0, cdb, 0) C(0xed19, CDB, RXE, Z, f1_o, m2_64, 0, 0, cdb, 0)
/* COMPARE AND SIGNAL */
C(0xb308, KEBR, RRE, Z, e1, e2, 0, 0, keb, 0)
C(0xb318, KDBR, RRE, Z, f1_o, f2_o, 0, 0, kdb, 0)
C(0xb348, KXBR, RRE, Z, x1_o, x2_o, 0, 0, kxb, 0)
C(0xed08, KEB, RXE, Z, e1, m2_32u, 0, 0, keb, 0)
C(0xed18, KDB, RXE, Z, f1_o, m2_64, 0, 0, kdb, 0)
/* COMPARE IMMEDIATE */ /* COMPARE IMMEDIATE */
C(0xc20d, CFI, RIL_a, EI, r1, i2, 0, 0, 0, cmps32) C(0xc20d, CFI, RIL_a, EI, r1, i2, 0, 0, 0, cmps32)
C(0xc20c, CGFI, RIL_a, EI, r1, i2, 0, 0, 0, cmps64) C(0xc20c, CGFI, RIL_a, EI, r1, i2, 0, 0, 0, cmps64)
@ -210,8 +216,12 @@
C(0xc60e, CLGFRL, RIL_b, GIE, r1_o, mri2_32u, 0, 0, 0, cmpu64) C(0xc60e, CLGFRL, RIL_b, GIE, r1_o, mri2_32u, 0, 0, 0, cmpu64)
C(0xc607, CLHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu32) C(0xc607, CLHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu32)
C(0xc606, CLGHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu64) C(0xc606, CLGHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu64)
/* COMPARE LOGICAL LONG */
C(0x0f00, CLCL, RR_a, Z, 0, 0, 0, 0, clcl, 0)
/* COMPARE LOGICAL LONG EXTENDED */ /* COMPARE LOGICAL LONG EXTENDED */
C(0xa900, CLCLE, RS_a, Z, 0, a2, 0, 0, clcle, 0) C(0xa900, CLCLE, RS_a, Z, 0, a2, 0, 0, clcle, 0)
/* COMPARE LOGICAL LONG UNICODE */
C(0xeb8f, CLCLU, RSY_a, E2, 0, a2, 0, 0, clclu, 0)
/* COMPARE LOGICAL CHARACTERS UNDER MASK */ /* COMPARE LOGICAL CHARACTERS UNDER MASK */
C(0xbd00, CLM, RS_b, Z, r1_o, a2, 0, 0, clm, 0) C(0xbd00, CLM, RS_b, Z, r1_o, a2, 0, 0, clm, 0)
C(0xeb21, CLMY, RSY_b, LD, r1_o, a2, 0, 0, clm, 0) C(0xeb21, CLMY, RSY_b, LD, r1_o, a2, 0, 0, clm, 0)
@ -327,9 +337,9 @@
C(0xeb57, XIY, SIY, LD, m1_8u, i2_8u, new, m1_8, xor, nz64) C(0xeb57, XIY, SIY, LD, m1_8u, i2_8u, new, m1_8, xor, nz64)
/* EXECUTE */ /* EXECUTE */
C(0x4400, EX, RX_a, Z, r1_o, a2, 0, 0, ex, 0) C(0x4400, EX, RX_a, Z, 0, a2, 0, 0, ex, 0)
/* EXECUTE RELATIVE LONG */ /* EXECUTE RELATIVE LONG */
C(0xc600, EXRL, RIL_b, EE, r1_o, ri2, 0, 0, ex, 0) C(0xc600, EXRL, RIL_b, EE, 0, ri2, 0, 0, ex, 0)
/* EXTRACT ACCESS */ /* EXTRACT ACCESS */
C(0xb24f, EAR, RRE, Z, 0, 0, new, r1_32, ear, 0) C(0xb24f, EAR, RRE, Z, 0, 0, new, r1_32, ear, 0)
@ -507,6 +517,8 @@
/* LOAD PAIR DISJOINT */ /* LOAD PAIR DISJOINT */
D(0xc804, LPD, SSF, ILA, 0, 0, new_P, r3_P32, lpd, 0, MO_TEUL) D(0xc804, LPD, SSF, ILA, 0, 0, new_P, r3_P32, lpd, 0, MO_TEUL)
D(0xc805, LPDG, SSF, ILA, 0, 0, new_P, r3_P64, lpd, 0, MO_TEQ) D(0xc805, LPDG, SSF, ILA, 0, 0, new_P, r3_P64, lpd, 0, MO_TEQ)
/* LOAD PAIR FROM QUADWORD */
C(0xe38f, LPQ, RXY_a, Z, 0, a2, r1_P, 0, lpq, 0)
/* LOAD POSITIVE */ /* LOAD POSITIVE */
C(0x1000, LPR, RR_a, Z, 0, r2_32s, new, r1_32, abs, abs32) C(0x1000, LPR, RR_a, Z, 0, r2_32s, new, r1_32, abs, abs32)
C(0xb900, LPGR, RRE, Z, 0, r2, r1, 0, abs, abs64) C(0xb900, LPGR, RRE, Z, 0, r2, r1, 0, abs, abs64)
@ -564,14 +576,26 @@
C(0xe548, MVGHI, SIL, GIE, la1, i2, 0, m1_64, mov2, 0) C(0xe548, MVGHI, SIL, GIE, la1, i2, 0, m1_64, mov2, 0)
C(0x9200, MVI, SI, Z, la1, i2, 0, m1_8, mov2, 0) C(0x9200, MVI, SI, Z, la1, i2, 0, m1_8, mov2, 0)
C(0xeb52, MVIY, SIY, LD, la1, i2, 0, m1_8, mov2, 0) C(0xeb52, MVIY, SIY, LD, la1, i2, 0, m1_8, mov2, 0)
/* MOVE INVERSE */
C(0xe800, MVCIN, SS_a, Z, la1, a2, 0, 0, mvcin, 0)
/* MOVE LONG */ /* MOVE LONG */
C(0x0e00, MVCL, RR_a, Z, 0, 0, 0, 0, mvcl, 0) C(0x0e00, MVCL, RR_a, Z, 0, 0, 0, 0, mvcl, 0)
/* MOVE LONG EXTENDED */ /* MOVE LONG EXTENDED */
C(0xa800, MVCLE, RS_a, Z, 0, a2, 0, 0, mvcle, 0) C(0xa800, MVCLE, RS_a, Z, 0, a2, 0, 0, mvcle, 0)
/* MOVE LONG UNICODE */
C(0xeb8e, MVCLU, RSY_a, E2, 0, a2, 0, 0, mvclu, 0)
/* MOVE NUMERICS */
C(0xd100, MVN, SS_a, Z, la1, a2, 0, 0, mvn, 0)
/* 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, r1_o, r2_o, 0, 0, mvst, 0)
/* MOVE WITH OFFSET */
/* Really format SS_b, but we pack both lengths into one argument
for the helper call, so we might as well leave one 8-bit field. */
C(0xf100, MVO, SS_a, Z, la1, a2, 0, 0, mvo, 0)
/* MOVE ZONES */
C(0xd300, MVZ, SS_a, Z, la1, a2, 0, 0, mvz, 0)
/* MULTIPLY */ /* MULTIPLY */
C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0) C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0)
@ -639,6 +663,15 @@
C(0x9600, OI, SI, Z, m1_8u, i2_8u, new, m1_8, or, nz64) C(0x9600, OI, SI, Z, m1_8u, i2_8u, new, m1_8, or, nz64)
C(0xeb56, OIY, SIY, LD, m1_8u, i2_8u, new, m1_8, or, nz64) C(0xeb56, OIY, SIY, LD, m1_8u, i2_8u, new, m1_8, or, nz64)
/* PACK */
/* Really format SS_b, but we pack both lengths into one argument
for the helper call, so we might as well leave one 8-bit field. */
C(0xf200, PACK, SS_a, Z, la1, a2, 0, 0, pack, 0)
/* PACK ASCII */
C(0xe900, PKA, SS_f, E2, la1, a2, 0, 0, pka, 0)
/* PACK UNICODE */
C(0xe100, PKU, SS_f, E2, la1, a2, 0, 0, pku, 0)
/* PREFETCH */ /* PREFETCH */
/* Implemented as nops of course. */ /* Implemented as nops of course. */
C(0xe336, PFD, RXY_b, GIE, 0, 0, 0, 0, 0, 0) C(0xe336, PFD, RXY_b, GIE, 0, 0, 0, 0, 0, 0)
@ -763,6 +796,8 @@
/* STORE ACCESS MULTIPLE */ /* STORE ACCESS MULTIPLE */
C(0x9b00, STAM, RS_a, Z, 0, a2, 0, 0, stam, 0) C(0x9b00, STAM, RS_a, Z, 0, a2, 0, 0, stam, 0)
C(0xeb9b, STAMY, RSY_a, LD, 0, a2, 0, 0, stam, 0) C(0xeb9b, STAMY, RSY_a, LD, 0, a2, 0, 0, stam, 0)
/* STORE PAIR TO QUADWORD */
C(0xe38e, STPQ, RXY_a, Z, 0, a2, r1_P, 0, stpq, 0)
/* SUBTRACT */ /* SUBTRACT */
C(0x1b00, SR, RR_a, Z, r1, r2, new, r1_32, sub, subs32) C(0x1b00, SR, RR_a, Z, r1, r2, new, r1_32, sub, subs32)
@ -810,11 +845,20 @@
/* SUPERVISOR CALL */ /* SUPERVISOR CALL */
C(0x0a00, SVC, I, Z, 0, 0, 0, 0, svc, 0) C(0x0a00, SVC, I, Z, 0, 0, 0, 0, svc, 0)
/* TEST ADDRESSING MODE */
C(0x010b, TAM, E, Z, 0, 0, 0, 0, tam, 0)
/* TEST AND SET */
C(0x9300, TS, S, Z, 0, a2, 0, 0, ts, 0)
/* TEST DATA CLASS */ /* TEST DATA CLASS */
C(0xed10, TCEB, RXE, Z, e1, a2, 0, 0, tceb, 0) C(0xed10, TCEB, RXE, Z, e1, a2, 0, 0, tceb, 0)
C(0xed11, TCDB, RXE, Z, f1_o, a2, 0, 0, tcdb, 0) C(0xed11, TCDB, RXE, Z, f1_o, a2, 0, 0, tcdb, 0)
C(0xed12, TCXB, RXE, Z, x1_o, a2, 0, 0, tcxb, 0) C(0xed12, TCXB, RXE, Z, x1_o, a2, 0, 0, tcxb, 0)
/* TEST DECIMAL */
C(0xebc0, TP, RSL, E2, la1, 0, 0, 0, tp, 0)
/* TEST UNDER MASK */ /* TEST UNDER MASK */
C(0x9100, TM, SI, Z, m1_8u, i2_8u, 0, 0, 0, tm32) C(0x9100, TM, SI, Z, m1_8u, i2_8u, 0, 0, 0, tm32)
C(0xeb51, TMY, SIY, LD, m1_8u, i2_8u, 0, 0, 0, tm32) C(0xeb51, TMY, SIY, LD, m1_8u, i2_8u, 0, 0, 0, tm32)
@ -830,14 +874,28 @@
/* TRANSLATE EXTENDED */ /* TRANSLATE EXTENDED */
C(0xb2a5, TRE, RRE, Z, 0, r2, r1_P, 0, tre, 0) C(0xb2a5, TRE, RRE, Z, 0, r2, r1_P, 0, tre, 0)
/* TRANSLATE ONE TO ONE */
C(0xb993, TROO, RRF_c, E2, 0, 0, 0, 0, trXX, 0)
/* TRANSLATE ONE TO TWO */
C(0xb992, TROT, RRF_c, E2, 0, 0, 0, 0, trXX, 0)
/* TRANSLATE TWO TO ONE */
C(0xb991, TRTO, RRF_c, E2, 0, 0, 0, 0, trXX, 0)
/* TRANSLATE TWO TO TWO */
C(0xb990, TRTT, RRF_c, E2, 0, 0, 0, 0, trXX, 0)
/* UNPACK */ /* UNPACK */
/* Really format SS_b, but we pack both lengths into one argument /* Really format SS_b, but we pack both lengths into one argument
for the helper call, so we might as well leave one 8-bit field. */ for the helper call, so we might as well leave one 8-bit field. */
C(0xf300, UNPK, SS_a, Z, la1, a2, 0, 0, unpk, 0) C(0xf300, UNPK, SS_a, Z, la1, a2, 0, 0, unpk, 0)
/* UNPACK ASCII */
C(0xea00, UNPKA, SS_a, E2, la1, a2, 0, 0, unpka, 0)
/* UNPACK UNICODE */
C(0xe200, UNPKU, SS_a, E2, la1, a2, 0, 0, unpku, 0)
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
/* COMPARE AND SWAP AND PURGE */ /* COMPARE AND SWAP AND PURGE */
C(0xb250, CSP, RRE, Z, 0, ra2, 0, 0, csp, 0) D(0xb250, CSP, RRE, Z, r1_32u, ra2, r1_P, 0, csp, 0, MO_TEUL)
D(0xb98a, CSPG, RRE, DAT_ENH, r1_o, ra2, r1_P, 0, csp, 0, MO_TEQ)
/* DIAGNOSE (KVM hypercall) */ /* DIAGNOSE (KVM hypercall) */
C(0x8300, DIAG, RSI, Z, 0, 0, 0, 0, diag, 0) C(0x8300, DIAG, RSI, Z, 0, 0, 0, 0, diag, 0)
/* INSERT STORAGE KEY EXTENDED */ /* INSERT STORAGE KEY EXTENDED */
@ -918,6 +976,8 @@
/* STORE USING REAL ADDRESS */ /* STORE USING REAL ADDRESS */
C(0xb246, STURA, RRE, Z, r1_o, r2_o, 0, 0, stura, 0) C(0xb246, STURA, RRE, Z, r1_o, r2_o, 0, 0, stura, 0)
C(0xb925, STURG, RRE, Z, r1_o, r2_o, 0, 0, sturg, 0) C(0xb925, STURG, RRE, Z, r1_o, r2_o, 0, 0, sturg, 0)
/* TEST BLOCK */
C(0xb22c, TB, RRE, Z, 0, r2_o, 0, 0, testblock, 0)
/* TEST PROTECTION */ /* TEST PROTECTION */
C(0xe501, TPROT, SSE, Z, la1, a2, 0, 0, tprot, 0) C(0xe501, TPROT, SSE, Z, la1, a2, 0, 0, tprot, 0)

View File

@ -34,6 +34,7 @@ static int cpu_post_load(void *opaque, int version_id)
return 0; return 0;
} }
static void cpu_pre_save(void *opaque) static void cpu_pre_save(void *opaque)
{ {
S390CPU *cpu = opaque; S390CPU *cpu = opaque;
@ -156,6 +157,23 @@ const VMStateDescription vmstate_riccb = {
} }
}; };
static bool exval_needed(void *opaque)
{
S390CPU *cpu = opaque;
return cpu->env.ex_value != 0;
}
const VMStateDescription vmstate_exval = {
.name = "cpu/exval",
.version_id = 1,
.minimum_version_id = 1,
.needed = exval_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT64(env.ex_value, S390CPU),
VMSTATE_END_OF_LIST()
}
};
const VMStateDescription vmstate_s390_cpu = { const VMStateDescription vmstate_s390_cpu = {
.name = "cpu", .name = "cpu",
.post_load = cpu_post_load, .post_load = cpu_post_load,
@ -188,6 +206,7 @@ const VMStateDescription vmstate_s390_cpu = {
&vmstate_fpu, &vmstate_fpu,
&vmstate_vregs, &vmstate_vregs,
&vmstate_riccb, &vmstate_riccb,
&vmstate_exval,
NULL NULL
}, },
}; };

File diff suppressed because it is too large Load Diff

View File

@ -80,8 +80,6 @@ void HELPER(exception)(CPUS390XState *env, uint32_t excp)
cpu_loop_exit(cs); cpu_loop_exit(cs);
} }
#ifndef CONFIG_USER_ONLY
void program_interrupt(CPUS390XState *env, uint32_t code, int ilen) void program_interrupt(CPUS390XState *env, uint32_t code, int ilen)
{ {
S390CPU *cpu = s390_env_get_cpu(env); S390CPU *cpu = s390_env_get_cpu(env);
@ -108,6 +106,8 @@ void program_interrupt(CPUS390XState *env, uint32_t code, int ilen)
} }
} }
#ifndef CONFIG_USER_ONLY
/* SCLP service call */ /* SCLP service call */
uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2) uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2)
{ {

View File

@ -108,7 +108,7 @@ static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr,
* Translate real address to absolute (= physical) * Translate real address to absolute (= physical)
* address by taking care of the prefix mapping. * address by taking care of the prefix mapping.
*/ */
static target_ulong mmu_real2abs(CPUS390XState *env, target_ulong raddr) target_ulong mmu_real2abs(CPUS390XState *env, target_ulong raddr)
{ {
if (raddr < 0x2000) { if (raddr < 0x2000) {
return raddr + env->psa; /* Map the lowcore. */ return raddr + env->psa; /* Map the lowcore. */
@ -143,8 +143,6 @@ static int mmu_translate_pte(CPUS390XState *env, target_ulong vaddr,
return 0; return 0;
} }
#define VADDR_PX 0xff000 /* Page index bits */
/* Decode segment table entry */ /* Decode segment table entry */
static int mmu_translate_segment(CPUS390XState *env, target_ulong vaddr, static int mmu_translate_segment(CPUS390XState *env, target_ulong vaddr,
uint64_t asc, uint64_t st_entry, uint64_t asc, uint64_t st_entry,

View File

@ -57,7 +57,9 @@ struct DisasContext {
struct TranslationBlock *tb; struct TranslationBlock *tb;
const DisasInsn *insn; const DisasInsn *insn;
DisasFields *fields; DisasFields *fields;
uint64_t ex_value;
uint64_t pc, next_pc; uint64_t pc, next_pc;
uint32_t ilen;
enum cc_op cc_op; enum cc_op cc_op;
bool singlestep_enabled; bool singlestep_enabled;
}; };
@ -349,7 +351,7 @@ static void gen_program_exception(DisasContext *s, int code)
tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_code)); tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_code));
tcg_temp_free_i32(tmp); tcg_temp_free_i32(tmp);
tmp = tcg_const_i32(s->next_pc - s->pc); tmp = tcg_const_i32(s->ilen);
tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_ilen)); tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_ilen));
tcg_temp_free_i32(tmp); tcg_temp_free_i32(tmp);
@ -1167,6 +1169,8 @@ typedef enum {
the PC (for whatever reason), so there's no need to do it again on the PC (for whatever reason), so there's no need to do it again on
exiting the TB. */ exiting the TB. */
EXIT_PC_UPDATED, EXIT_PC_UPDATED,
/* We have updated the PC and CC values. */
EXIT_PC_CC_UPDATED,
/* We are exiting the TB, but have neither emitted a goto_tb, nor /* We are exiting the TB, but have neither emitted a goto_tb, nor
updated the PC for the next instruction to be executed. */ updated the PC for the next instruction to be executed. */
EXIT_PC_STALE, EXIT_PC_STALE,
@ -1200,6 +1204,8 @@ typedef enum DisasFacility {
FAC_SFLE, /* store facility list extended */ FAC_SFLE, /* store facility list extended */
FAC_ILA, /* interlocked access facility 1 */ FAC_ILA, /* interlocked access facility 1 */
FAC_LPP, /* load-program-parameter */ FAC_LPP, /* load-program-parameter */
FAC_DAT_ENH, /* DAT-enhancement */
FAC_E2, /* extended-translation facility 2 */
} DisasFacility; } DisasFacility;
struct DisasInsn { struct DisasInsn {
@ -1871,7 +1877,6 @@ static ExitStatus op_cksm(DisasContext *s, DisasOps *o)
int r2 = get_field(s->fields, r2); int r2 = get_field(s->fields, r2);
TCGv_i64 len = tcg_temp_new_i64(); TCGv_i64 len = tcg_temp_new_i64();
potential_page_fault(s);
gen_helper_cksm(len, cpu_env, o->in1, o->in2, regs[r2 + 1]); gen_helper_cksm(len, cpu_env, o->in1, o->in2, regs[r2 + 1]);
set_cc_static(s); set_cc_static(s);
return_low128(o->out); return_low128(o->out);
@ -1906,7 +1911,6 @@ static ExitStatus op_clc(DisasContext *s, DisasOps *o)
tcg_gen_qemu_ld64(cc_dst, o->in2, get_mem_index(s)); tcg_gen_qemu_ld64(cc_dst, o->in2, get_mem_index(s));
break; break;
default: default:
potential_page_fault(s);
vl = tcg_const_i32(l); vl = tcg_const_i32(l);
gen_helper_clc(cc_op, cpu_env, vl, o->addr1, o->in2); gen_helper_clc(cc_op, cpu_env, vl, o->addr1, o->in2);
tcg_temp_free_i32(vl); tcg_temp_free_i32(vl);
@ -1917,14 +1921,65 @@ static ExitStatus op_clc(DisasContext *s, DisasOps *o)
return NO_EXIT; return NO_EXIT;
} }
static ExitStatus op_clcl(DisasContext *s, DisasOps *o)
{
int r1 = get_field(s->fields, r1);
int r2 = get_field(s->fields, r2);
TCGv_i32 t1, t2;
/* r1 and r2 must be even. */
if (r1 & 1 || r2 & 1) {
gen_program_exception(s, PGM_SPECIFICATION);
return EXIT_NORETURN;
}
t1 = tcg_const_i32(r1);
t2 = tcg_const_i32(r2);
gen_helper_clcl(cc_op, cpu_env, t1, t2);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t2);
set_cc_static(s);
return NO_EXIT;
}
static ExitStatus op_clcle(DisasContext *s, DisasOps *o) static ExitStatus op_clcle(DisasContext *s, DisasOps *o)
{ {
TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); int r1 = get_field(s->fields, r1);
TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); int r3 = get_field(s->fields, r3);
potential_page_fault(s); TCGv_i32 t1, t3;
gen_helper_clcle(cc_op, cpu_env, r1, o->in2, r3);
tcg_temp_free_i32(r1); /* r1 and r3 must be even. */
tcg_temp_free_i32(r3); if (r1 & 1 || r3 & 1) {
gen_program_exception(s, PGM_SPECIFICATION);
return EXIT_NORETURN;
}
t1 = tcg_const_i32(r1);
t3 = tcg_const_i32(r3);
gen_helper_clcle(cc_op, cpu_env, t1, o->in2, t3);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t3);
set_cc_static(s);
return NO_EXIT;
}
static ExitStatus op_clclu(DisasContext *s, DisasOps *o)
{
int r1 = get_field(s->fields, r1);
int r3 = get_field(s->fields, r3);
TCGv_i32 t1, t3;
/* r1 and r3 must be even. */
if (r1 & 1 || r3 & 1) {
gen_program_exception(s, PGM_SPECIFICATION);
return EXIT_NORETURN;
}
t1 = tcg_const_i32(r1);
t3 = tcg_const_i32(r3);
gen_helper_clclu(cc_op, cpu_env, t1, o->in2, t3);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t3);
set_cc_static(s); set_cc_static(s);
return NO_EXIT; return NO_EXIT;
} }
@ -1934,7 +1989,6 @@ static ExitStatus op_clm(DisasContext *s, DisasOps *o)
TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3));
TCGv_i32 t1 = tcg_temp_new_i32(); TCGv_i32 t1 = tcg_temp_new_i32();
tcg_gen_extrl_i64_i32(t1, o->in1); tcg_gen_extrl_i64_i32(t1, o->in1);
potential_page_fault(s);
gen_helper_clm(cc_op, cpu_env, t1, m3, o->in2); gen_helper_clm(cc_op, cpu_env, t1, m3, o->in2);
set_cc_static(s); set_cc_static(s);
tcg_temp_free_i32(t1); tcg_temp_free_i32(t1);
@ -1944,7 +1998,6 @@ static ExitStatus op_clm(DisasContext *s, DisasOps *o)
static ExitStatus op_clst(DisasContext *s, DisasOps *o) static ExitStatus op_clst(DisasContext *s, DisasOps *o)
{ {
potential_page_fault(s);
gen_helper_clst(o->in1, cpu_env, regs[0], o->in1, o->in2); gen_helper_clst(o->in1, cpu_env, regs[0], o->in1, o->in2);
set_cc_static(s); set_cc_static(s);
return_low128(o->in2); return_low128(o->in2);
@ -2011,11 +2064,45 @@ static ExitStatus op_cdsg(DisasContext *s, DisasOps *o)
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
static ExitStatus op_csp(DisasContext *s, DisasOps *o) static ExitStatus op_csp(DisasContext *s, DisasOps *o)
{ {
TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); TCGMemOp mop = s->insn->data;
TCGv_i64 addr, old, cc;
TCGLabel *lab = gen_new_label();
/* Note that in1 = R1 (zero-extended expected value),
out = R1 (original reg), out2 = R1+1 (new value). */
check_privileged(s); check_privileged(s);
gen_helper_csp(cc_op, cpu_env, r1, o->in2); addr = tcg_temp_new_i64();
tcg_temp_free_i32(r1); old = tcg_temp_new_i64();
set_cc_static(s); tcg_gen_andi_i64(addr, o->in2, -1ULL << (mop & MO_SIZE));
tcg_gen_atomic_cmpxchg_i64(old, addr, o->in1, o->out2,
get_mem_index(s), mop | MO_ALIGN);
tcg_temp_free_i64(addr);
/* Are the memory and expected values (un)equal? */
cc = tcg_temp_new_i64();
tcg_gen_setcond_i64(TCG_COND_NE, cc, o->in1, old);
tcg_gen_extrl_i64_i32(cc_op, cc);
/* Write back the output now, so that it happens before the
following branch, so that we don't need local temps. */
if ((mop & MO_SIZE) == MO_32) {
tcg_gen_deposit_i64(o->out, o->out, old, 0, 32);
} else {
tcg_gen_mov_i64(o->out, old);
}
tcg_temp_free_i64(old);
/* If the comparison was equal, and the LSB of R2 was set,
then we need to flush the TLB (for all cpus). */
tcg_gen_xori_i64(cc, cc, 1);
tcg_gen_and_i64(cc, cc, o->in2);
tcg_gen_brcondi_i64(TCG_COND_EQ, cc, 0, lab);
tcg_temp_free_i64(cc);
gen_helper_purge(cpu_env);
gen_set_label(lab);
return NO_EXIT; return NO_EXIT;
} }
#endif #endif
@ -2158,27 +2245,34 @@ static ExitStatus op_epsw(DisasContext *s, DisasOps *o)
static ExitStatus op_ex(DisasContext *s, DisasOps *o) static ExitStatus op_ex(DisasContext *s, DisasOps *o)
{ {
/* ??? Perhaps a better way to implement EXECUTE is to set a bit in int r1 = get_field(s->fields, r1);
tb->flags, (ab)use the tb->cs_base field as the address of TCGv_i32 ilen;
the template in memory, and grab 8 bits of tb->flags/cflags for TCGv_i64 v1;
the contents of the register. We would then recognize all this
in gen_intermediate_code_internal, generating code for exactly
one instruction. This new TB then gets executed normally.
On the other hand, this seems to be mostly used for modifying /* Nested EXECUTE is not allowed. */
MVC inside of memcpy, which needs a helper call anyway. So if (unlikely(s->ex_value)) {
perhaps this doesn't bear thinking about any further. */ gen_program_exception(s, PGM_EXECUTE);
return EXIT_NORETURN;
TCGv_i64 tmp; }
update_psw_addr(s); update_psw_addr(s);
gen_op_calc_cc(s); update_cc_op(s);
tmp = tcg_const_i64(s->next_pc); if (r1 == 0) {
gen_helper_ex(cc_op, cpu_env, cc_op, o->in1, o->in2, tmp); v1 = tcg_const_i64(0);
tcg_temp_free_i64(tmp); } else {
v1 = regs[r1];
}
return NO_EXIT; ilen = tcg_const_i32(s->ilen);
gen_helper_ex(cpu_env, ilen, v1, o->in2);
tcg_temp_free_i32(ilen);
if (r1 == 0) {
tcg_temp_free_i64(v1);
}
return EXIT_PC_CC_UPDATED;
} }
static ExitStatus op_fieb(DisasContext *s, DisasOps *o) static ExitStatus op_fieb(DisasContext *s, DisasOps *o)
@ -2316,8 +2410,12 @@ static ExitStatus op_ipm(DisasContext *s, DisasOps *o)
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
static ExitStatus op_ipte(DisasContext *s, DisasOps *o) static ExitStatus op_ipte(DisasContext *s, DisasOps *o)
{ {
TCGv_i32 m4;
check_privileged(s); check_privileged(s);
gen_helper_ipte(cpu_env, o->in1, o->in2); m4 = tcg_const_i32(get_field(s->fields, m4));
gen_helper_ipte(cpu_env, o->in1, o->in2, m4);
tcg_temp_free_i32(m4);
return NO_EXIT; return NO_EXIT;
} }
@ -2329,6 +2427,27 @@ static ExitStatus op_iske(DisasContext *s, DisasOps *o)
} }
#endif #endif
static ExitStatus op_keb(DisasContext *s, DisasOps *o)
{
gen_helper_keb(cc_op, cpu_env, o->in1, o->in2);
set_cc_static(s);
return NO_EXIT;
}
static ExitStatus op_kdb(DisasContext *s, DisasOps *o)
{
gen_helper_kdb(cc_op, cpu_env, o->in1, o->in2);
set_cc_static(s);
return NO_EXIT;
}
static ExitStatus op_kxb(DisasContext *s, DisasOps *o)
{
gen_helper_kxb(cc_op, cpu_env, o->out, o->out2, o->in1, o->in2);
set_cc_static(s);
return NO_EXIT;
}
static ExitStatus op_laa(DisasContext *s, DisasOps *o) static ExitStatus op_laa(DisasContext *s, DisasOps *o)
{ {
/* The real output is indeed the original value in memory; /* The real output is indeed the original value in memory;
@ -2550,7 +2669,6 @@ static ExitStatus op_lctl(DisasContext *s, DisasOps *o)
TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1));
TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3));
check_privileged(s); check_privileged(s);
potential_page_fault(s);
gen_helper_lctl(cpu_env, r1, o->in2, r3); gen_helper_lctl(cpu_env, r1, o->in2, r3);
tcg_temp_free_i32(r1); tcg_temp_free_i32(r1);
tcg_temp_free_i32(r3); tcg_temp_free_i32(r3);
@ -2562,7 +2680,6 @@ static ExitStatus op_lctlg(DisasContext *s, DisasOps *o)
TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1));
TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3));
check_privileged(s); check_privileged(s);
potential_page_fault(s);
gen_helper_lctlg(cpu_env, r1, o->in2, r3); gen_helper_lctlg(cpu_env, r1, o->in2, r3);
tcg_temp_free_i32(r1); tcg_temp_free_i32(r1);
tcg_temp_free_i32(r3); tcg_temp_free_i32(r3);
@ -2572,7 +2689,6 @@ static ExitStatus op_lctlg(DisasContext *s, DisasOps *o)
static ExitStatus op_lra(DisasContext *s, DisasOps *o) static ExitStatus op_lra(DisasContext *s, DisasOps *o)
{ {
check_privileged(s); check_privileged(s);
potential_page_fault(s);
gen_helper_lra(o->out, cpu_env, o->in2); gen_helper_lra(o->out, cpu_env, o->in2);
set_cc_static(s); set_cc_static(s);
return NO_EXIT; return NO_EXIT;
@ -2629,7 +2745,6 @@ static ExitStatus op_lam(DisasContext *s, DisasOps *o)
{ {
TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1));
TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3));
potential_page_fault(s);
gen_helper_lam(cpu_env, r1, o->in2, r3); gen_helper_lam(cpu_env, r1, o->in2, r3);
tcg_temp_free_i32(r1); tcg_temp_free_i32(r1);
tcg_temp_free_i32(r3); tcg_temp_free_i32(r3);
@ -2794,6 +2909,13 @@ static ExitStatus op_lpd(DisasContext *s, DisasOps *o)
return NO_EXIT; return NO_EXIT;
} }
static ExitStatus op_lpq(DisasContext *s, DisasOps *o)
{
gen_helper_lpq(o->out, cpu_env, o->in2);
return_low128(o->out2);
return NO_EXIT;
}
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
static ExitStatus op_lura(DisasContext *s, DisasOps *o) static ExitStatus op_lura(DisasContext *s, DisasOps *o)
{ {
@ -2871,32 +2993,78 @@ static ExitStatus op_movx(DisasContext *s, DisasOps *o)
static ExitStatus op_mvc(DisasContext *s, DisasOps *o) static ExitStatus op_mvc(DisasContext *s, DisasOps *o)
{ {
TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1));
potential_page_fault(s);
gen_helper_mvc(cpu_env, l, o->addr1, o->in2); gen_helper_mvc(cpu_env, l, o->addr1, o->in2);
tcg_temp_free_i32(l); tcg_temp_free_i32(l);
return NO_EXIT; return NO_EXIT;
} }
static ExitStatus op_mvcin(DisasContext *s, DisasOps *o)
{
TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1));
gen_helper_mvcin(cpu_env, l, o->addr1, o->in2);
tcg_temp_free_i32(l);
return NO_EXIT;
}
static ExitStatus op_mvcl(DisasContext *s, DisasOps *o) static ExitStatus op_mvcl(DisasContext *s, DisasOps *o)
{ {
TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); int r1 = get_field(s->fields, r1);
TCGv_i32 r2 = tcg_const_i32(get_field(s->fields, r2)); int r2 = get_field(s->fields, r2);
potential_page_fault(s); TCGv_i32 t1, t2;
gen_helper_mvcl(cc_op, cpu_env, r1, r2);
tcg_temp_free_i32(r1); /* r1 and r2 must be even. */
tcg_temp_free_i32(r2); if (r1 & 1 || r2 & 1) {
gen_program_exception(s, PGM_SPECIFICATION);
return EXIT_NORETURN;
}
t1 = tcg_const_i32(r1);
t2 = tcg_const_i32(r2);
gen_helper_mvcl(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 NO_EXIT; return NO_EXIT;
} }
static ExitStatus op_mvcle(DisasContext *s, DisasOps *o) static ExitStatus op_mvcle(DisasContext *s, DisasOps *o)
{ {
TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); int r1 = get_field(s->fields, r1);
TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); int r3 = get_field(s->fields, r3);
potential_page_fault(s); TCGv_i32 t1, t3;
gen_helper_mvcle(cc_op, cpu_env, r1, o->in2, r3);
tcg_temp_free_i32(r1); /* r1 and r3 must be even. */
tcg_temp_free_i32(r3); if (r1 & 1 || r3 & 1) {
gen_program_exception(s, PGM_SPECIFICATION);
return EXIT_NORETURN;
}
t1 = tcg_const_i32(r1);
t3 = tcg_const_i32(r3);
gen_helper_mvcle(cc_op, cpu_env, t1, o->in2, t3);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t3);
set_cc_static(s);
return NO_EXIT;
}
static ExitStatus op_mvclu(DisasContext *s, DisasOps *o)
{
int r1 = get_field(s->fields, r1);
int r3 = get_field(s->fields, r3);
TCGv_i32 t1, t3;
/* r1 and r3 must be even. */
if (r1 & 1 || r3 & 1) {
gen_program_exception(s, PGM_SPECIFICATION);
return EXIT_NORETURN;
}
t1 = tcg_const_i32(r1);
t3 = tcg_const_i32(r3);
gen_helper_mvclu(cc_op, cpu_env, t1, o->in2, t3);
tcg_temp_free_i32(t1);
tcg_temp_free_i32(t3);
set_cc_static(s); set_cc_static(s);
return NO_EXIT; return NO_EXIT;
} }
@ -2906,7 +3074,6 @@ static ExitStatus op_mvcp(DisasContext *s, DisasOps *o)
{ {
int r1 = get_field(s->fields, l1); int r1 = get_field(s->fields, l1);
check_privileged(s); check_privileged(s);
potential_page_fault(s);
gen_helper_mvcp(cc_op, cpu_env, regs[r1], o->addr1, o->in2); gen_helper_mvcp(cc_op, cpu_env, regs[r1], o->addr1, o->in2);
set_cc_static(s); set_cc_static(s);
return NO_EXIT; return NO_EXIT;
@ -2916,30 +3083,51 @@ static ExitStatus op_mvcs(DisasContext *s, DisasOps *o)
{ {
int r1 = get_field(s->fields, l1); int r1 = get_field(s->fields, l1);
check_privileged(s); check_privileged(s);
potential_page_fault(s);
gen_helper_mvcs(cc_op, cpu_env, regs[r1], o->addr1, o->in2); gen_helper_mvcs(cc_op, cpu_env, regs[r1], o->addr1, o->in2);
set_cc_static(s); set_cc_static(s);
return NO_EXIT; return NO_EXIT;
} }
#endif #endif
static ExitStatus op_mvn(DisasContext *s, DisasOps *o)
{
TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1));
gen_helper_mvn(cpu_env, l, o->addr1, o->in2);
tcg_temp_free_i32(l);
return NO_EXIT;
}
static ExitStatus op_mvo(DisasContext *s, DisasOps *o)
{
TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1));
gen_helper_mvo(cpu_env, l, o->addr1, o->in2);
tcg_temp_free_i32(l);
return NO_EXIT;
}
static ExitStatus op_mvpg(DisasContext *s, DisasOps *o) static ExitStatus op_mvpg(DisasContext *s, DisasOps *o)
{ {
potential_page_fault(s); gen_helper_mvpg(cc_op, cpu_env, regs[0], o->in1, o->in2);
gen_helper_mvpg(cpu_env, regs[0], o->in1, o->in2);
set_cc_static(s); set_cc_static(s);
return NO_EXIT; return NO_EXIT;
} }
static ExitStatus op_mvst(DisasContext *s, DisasOps *o) static ExitStatus op_mvst(DisasContext *s, DisasOps *o)
{ {
potential_page_fault(s);
gen_helper_mvst(o->in1, cpu_env, regs[0], o->in1, o->in2); gen_helper_mvst(o->in1, cpu_env, regs[0], o->in1, o->in2);
set_cc_static(s); set_cc_static(s);
return_low128(o->in2); return_low128(o->in2);
return NO_EXIT; return NO_EXIT;
} }
static ExitStatus op_mvz(DisasContext *s, DisasOps *o)
{
TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1));
gen_helper_mvz(cpu_env, l, o->addr1, o->in2);
tcg_temp_free_i32(l);
return NO_EXIT;
}
static ExitStatus op_mul(DisasContext *s, DisasOps *o) static ExitStatus op_mul(DisasContext *s, DisasOps *o)
{ {
tcg_gen_mul_i64(o->out, o->in1, o->in2); tcg_gen_mul_i64(o->out, o->in1, o->in2);
@ -3048,7 +3236,6 @@ static ExitStatus op_nabsf128(DisasContext *s, DisasOps *o)
static ExitStatus op_nc(DisasContext *s, DisasOps *o) static ExitStatus op_nc(DisasContext *s, DisasOps *o)
{ {
TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1));
potential_page_fault(s);
gen_helper_nc(cc_op, cpu_env, l, o->addr1, o->in2); gen_helper_nc(cc_op, cpu_env, l, o->addr1, o->in2);
tcg_temp_free_i32(l); tcg_temp_free_i32(l);
set_cc_static(s); set_cc_static(s);
@ -3083,7 +3270,6 @@ static ExitStatus op_negf128(DisasContext *s, DisasOps *o)
static ExitStatus op_oc(DisasContext *s, DisasOps *o) static ExitStatus op_oc(DisasContext *s, DisasOps *o)
{ {
TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1));
potential_page_fault(s);
gen_helper_oc(cc_op, cpu_env, l, o->addr1, o->in2); gen_helper_oc(cc_op, cpu_env, l, o->addr1, o->in2);
tcg_temp_free_i32(l); tcg_temp_free_i32(l);
set_cc_static(s); set_cc_static(s);
@ -3112,6 +3298,46 @@ static ExitStatus op_ori(DisasContext *s, DisasOps *o)
return NO_EXIT; return NO_EXIT;
} }
static ExitStatus op_pack(DisasContext *s, DisasOps *o)
{
TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1));
gen_helper_pack(cpu_env, l, o->addr1, o->in2);
tcg_temp_free_i32(l);
return NO_EXIT;
}
static ExitStatus op_pka(DisasContext *s, DisasOps *o)
{
int l2 = get_field(s->fields, l2) + 1;
TCGv_i32 l;
/* The length must not exceed 32 bytes. */
if (l2 > 32) {
gen_program_exception(s, PGM_SPECIFICATION);
return EXIT_NORETURN;
}
l = tcg_const_i32(l2);
gen_helper_pka(cpu_env, o->addr1, o->in2, l);
tcg_temp_free_i32(l);
return NO_EXIT;
}
static ExitStatus op_pku(DisasContext *s, DisasOps *o)
{
int l2 = get_field(s->fields, l2) + 1;
TCGv_i32 l;
/* The length must be even and should not exceed 64 bytes. */
if ((l2 & 1) || (l2 > 64)) {
gen_program_exception(s, PGM_SPECIFICATION);
return EXIT_NORETURN;
}
l = tcg_const_i32(l2);
gen_helper_pku(cpu_env, o->addr1, o->in2, l);
tcg_temp_free_i32(l);
return NO_EXIT;
}
static ExitStatus op_popcnt(DisasContext *s, DisasOps *o) static ExitStatus op_popcnt(DisasContext *s, DisasOps *o)
{ {
gen_helper_popcnt(o->out, o->in2); gen_helper_popcnt(o->out, o->in2);
@ -3632,7 +3858,6 @@ static ExitStatus op_stctg(DisasContext *s, DisasOps *o)
TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1));
TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3));
check_privileged(s); check_privileged(s);
potential_page_fault(s);
gen_helper_stctg(cpu_env, r1, o->in2, r3); gen_helper_stctg(cpu_env, r1, o->in2, r3);
tcg_temp_free_i32(r1); tcg_temp_free_i32(r1);
tcg_temp_free_i32(r3); tcg_temp_free_i32(r3);
@ -3644,7 +3869,6 @@ static ExitStatus op_stctl(DisasContext *s, DisasOps *o)
TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1));
TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3));
check_privileged(s); check_privileged(s);
potential_page_fault(s);
gen_helper_stctl(cpu_env, r1, o->in2, r3); gen_helper_stctl(cpu_env, r1, o->in2, r3);
tcg_temp_free_i32(r1); tcg_temp_free_i32(r1);
tcg_temp_free_i32(r3); tcg_temp_free_i32(r3);
@ -3876,7 +4100,6 @@ static ExitStatus op_stam(DisasContext *s, DisasOps *o)
{ {
TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1));
TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3));
potential_page_fault(s);
gen_helper_stam(cpu_env, r1, o->in2, r3); gen_helper_stam(cpu_env, r1, o->in2, r3);
tcg_temp_free_i32(r1); tcg_temp_free_i32(r1);
tcg_temp_free_i32(r3); tcg_temp_free_i32(r3);
@ -3980,9 +4203,14 @@ static ExitStatus op_stmh(DisasContext *s, DisasOps *o)
return NO_EXIT; return NO_EXIT;
} }
static ExitStatus op_stpq(DisasContext *s, DisasOps *o)
{
gen_helper_stpq(cpu_env, o->in2, o->out2, o->out);
return NO_EXIT;
}
static ExitStatus op_srst(DisasContext *s, DisasOps *o) static ExitStatus op_srst(DisasContext *s, DisasOps *o)
{ {
potential_page_fault(s);
gen_helper_srst(o->in1, cpu_env, regs[0], o->in1, o->in2); gen_helper_srst(o->in1, cpu_env, regs[0], o->in1, o->in2);
set_cc_static(s); set_cc_static(s);
return_low128(o->in2); return_low128(o->in2);
@ -4032,7 +4260,7 @@ static ExitStatus op_svc(DisasContext *s, DisasOps *o)
tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, int_svc_code)); tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, int_svc_code));
tcg_temp_free_i32(t); tcg_temp_free_i32(t);
t = tcg_const_i32(s->next_pc - s->pc); t = tcg_const_i32(s->ilen);
tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, int_svc_ilen)); tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, int_svc_ilen));
tcg_temp_free_i32(t); tcg_temp_free_i32(t);
@ -4040,6 +4268,16 @@ static ExitStatus op_svc(DisasContext *s, DisasOps *o)
return EXIT_NORETURN; return EXIT_NORETURN;
} }
static ExitStatus op_tam(DisasContext *s, DisasOps *o)
{
int cc = 0;
cc |= (s->tb->flags & FLAG_MASK_64) ? 2 : 0;
cc |= (s->tb->flags & FLAG_MASK_32) ? 1 : 0;
gen_op_movi_cc(s, cc);
return NO_EXIT;
}
static ExitStatus op_tceb(DisasContext *s, DisasOps *o) static ExitStatus op_tceb(DisasContext *s, DisasOps *o)
{ {
gen_helper_tceb(cc_op, cpu_env, o->in1, o->in2); gen_helper_tceb(cc_op, cpu_env, o->in1, o->in2);
@ -4062,19 +4300,36 @@ static ExitStatus op_tcxb(DisasContext *s, DisasOps *o)
} }
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
static ExitStatus op_testblock(DisasContext *s, DisasOps *o)
{
check_privileged(s);
gen_helper_testblock(cc_op, cpu_env, o->in2);
set_cc_static(s);
return NO_EXIT;
}
static ExitStatus op_tprot(DisasContext *s, DisasOps *o) static ExitStatus op_tprot(DisasContext *s, DisasOps *o)
{ {
potential_page_fault(s);
gen_helper_tprot(cc_op, o->addr1, o->in2); gen_helper_tprot(cc_op, o->addr1, o->in2);
set_cc_static(s); set_cc_static(s);
return NO_EXIT; return NO_EXIT;
} }
#endif #endif
static ExitStatus op_tp(DisasContext *s, DisasOps *o)
{
TCGv_i32 l1 = tcg_const_i32(get_field(s->fields, l1) + 1);
gen_helper_tp(cc_op, cpu_env, o->addr1, l1);
tcg_temp_free_i32(l1);
set_cc_static(s);
return NO_EXIT;
}
static ExitStatus op_tr(DisasContext *s, DisasOps *o) static ExitStatus op_tr(DisasContext *s, DisasOps *o)
{ {
TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1));
potential_page_fault(s);
gen_helper_tr(cpu_env, l, o->addr1, o->in2); gen_helper_tr(cpu_env, l, o->addr1, o->in2);
tcg_temp_free_i32(l); tcg_temp_free_i32(l);
set_cc_static(s); set_cc_static(s);
@ -4083,7 +4338,6 @@ static ExitStatus op_tr(DisasContext *s, DisasOps *o)
static ExitStatus op_tre(DisasContext *s, DisasOps *o) static ExitStatus op_tre(DisasContext *s, DisasOps *o)
{ {
potential_page_fault(s);
gen_helper_tre(o->out, cpu_env, o->out, o->out2, o->in2); gen_helper_tre(o->out, cpu_env, o->out, o->out2, o->in2);
return_low128(o->out2); return_low128(o->out2);
set_cc_static(s); set_cc_static(s);
@ -4093,22 +4347,95 @@ static ExitStatus op_tre(DisasContext *s, DisasOps *o)
static ExitStatus op_trt(DisasContext *s, DisasOps *o) static ExitStatus op_trt(DisasContext *s, DisasOps *o)
{ {
TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1));
potential_page_fault(s);
gen_helper_trt(cc_op, cpu_env, l, o->addr1, o->in2); gen_helper_trt(cc_op, cpu_env, l, o->addr1, o->in2);
tcg_temp_free_i32(l); tcg_temp_free_i32(l);
set_cc_static(s); set_cc_static(s);
return NO_EXIT; return NO_EXIT;
} }
static ExitStatus op_trXX(DisasContext *s, DisasOps *o)
{
TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1));
TCGv_i32 r2 = tcg_const_i32(get_field(s->fields, r2));
TCGv_i32 sizes = tcg_const_i32(s->insn->opc & 3);
TCGv_i32 tst = tcg_temp_new_i32();
int m3 = get_field(s->fields, m3);
/* XXX: the C bit in M3 should be considered as 0 when the
ETF2-enhancement facility is not installed. */
if (m3 & 1) {
tcg_gen_movi_i32(tst, -1);
} else {
tcg_gen_extrl_i64_i32(tst, regs[0]);
if (s->insn->opc & 3) {
tcg_gen_ext8u_i32(tst, tst);
} else {
tcg_gen_ext16u_i32(tst, tst);
}
}
gen_helper_trXX(cc_op, cpu_env, r1, r2, tst, sizes);
tcg_temp_free_i32(r1);
tcg_temp_free_i32(r2);
tcg_temp_free_i32(sizes);
tcg_temp_free_i32(tst);
set_cc_static(s);
return NO_EXIT;
}
static ExitStatus op_ts(DisasContext *s, DisasOps *o)
{
TCGv_i32 t1 = tcg_const_i32(0xff);
tcg_gen_atomic_xchg_i32(t1, o->in2, t1, get_mem_index(s), MO_UB);
tcg_gen_extract_i32(cc_op, t1, 7, 1);
tcg_temp_free_i32(t1);
set_cc_static(s);
return NO_EXIT;
}
static ExitStatus op_unpk(DisasContext *s, DisasOps *o) static ExitStatus op_unpk(DisasContext *s, DisasOps *o)
{ {
TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1));
potential_page_fault(s);
gen_helper_unpk(cpu_env, l, o->addr1, o->in2); gen_helper_unpk(cpu_env, l, o->addr1, o->in2);
tcg_temp_free_i32(l); tcg_temp_free_i32(l);
return NO_EXIT; return NO_EXIT;
} }
static ExitStatus op_unpka(DisasContext *s, DisasOps *o)
{
int l1 = get_field(s->fields, l1) + 1;
TCGv_i32 l;
/* The length must not exceed 32 bytes. */
if (l1 > 32) {
gen_program_exception(s, PGM_SPECIFICATION);
return EXIT_NORETURN;
}
l = tcg_const_i32(l1);
gen_helper_unpka(cc_op, cpu_env, o->addr1, l, o->in2);
tcg_temp_free_i32(l);
set_cc_static(s);
return NO_EXIT;
}
static ExitStatus op_unpku(DisasContext *s, DisasOps *o)
{
int l1 = get_field(s->fields, l1) + 1;
TCGv_i32 l;
/* The length must be even and should not exceed 64 bytes. */
if ((l1 & 1) || (l1 > 64)) {
gen_program_exception(s, PGM_SPECIFICATION);
return EXIT_NORETURN;
}
l = tcg_const_i32(l1);
gen_helper_unpku(cc_op, cpu_env, o->addr1, l, o->in2);
tcg_temp_free_i32(l);
set_cc_static(s);
return NO_EXIT;
}
static ExitStatus op_xc(DisasContext *s, DisasOps *o) static ExitStatus op_xc(DisasContext *s, DisasOps *o)
{ {
int d1 = get_field(s->fields, d1); int d1 = get_field(s->fields, d1);
@ -4156,7 +4483,6 @@ static ExitStatus op_xc(DisasContext *s, DisasOps *o)
/* But in general we'll defer to a helper. */ /* But in general we'll defer to a helper. */
o->in2 = get_address(s, 0, b2, d2); o->in2 = get_address(s, 0, b2, d2);
t32 = tcg_const_i32(l); t32 = tcg_const_i32(l);
potential_page_fault(s);
gen_helper_xc(cc_op, cpu_env, t32, o->addr1, o->in2); gen_helper_xc(cc_op, cpu_env, t32, o->addr1, o->in2);
tcg_temp_free_i32(t32); tcg_temp_free_i32(t32);
set_cc_static(s); set_cc_static(s);
@ -5163,24 +5489,36 @@ static const DisasInsn *extract_insn(CPUS390XState *env, DisasContext *s,
int op, op2, ilen; int op, op2, ilen;
const DisasInsn *info; const DisasInsn *info;
insn = ld_code2(env, pc); if (unlikely(s->ex_value)) {
op = (insn >> 8) & 0xff; /* Drop the EX data now, so that it's clear on exception paths. */
ilen = get_ilen(op); TCGv_i64 zero = tcg_const_i64(0);
s->next_pc = s->pc + ilen; tcg_gen_st_i64(zero, cpu_env, offsetof(CPUS390XState, ex_value));
tcg_temp_free_i64(zero);
switch (ilen) { /* Extract the values saved by EXECUTE. */
case 2: insn = s->ex_value & 0xffffffffffff0000ull;
insn = insn << 48; ilen = s->ex_value & 0xf;
break; op = insn >> 56;
case 4: } else {
insn = ld_code4(env, pc) << 32; insn = ld_code2(env, pc);
break; op = (insn >> 8) & 0xff;
case 6: ilen = get_ilen(op);
insn = (insn << 48) | (ld_code4(env, pc + 2) << 16); switch (ilen) {
break; case 2:
default: insn = insn << 48;
abort(); break;
case 4:
insn = ld_code4(env, pc) << 32;
break;
case 6:
insn = (insn << 48) | (ld_code4(env, pc + 2) << 16);
break;
default:
g_assert_not_reached();
}
} }
s->next_pc = s->pc + ilen;
s->ilen = ilen;
/* We can't actually determine the insn format until we've looked up /* We can't actually determine the insn format until we've looked up
the full insn opcode. Which we can't do without locating the the full insn opcode. Which we can't do without locating the
@ -5397,6 +5735,7 @@ void gen_intermediate_code(CPUS390XState *env, struct TranslationBlock *tb)
dc.tb = tb; dc.tb = tb;
dc.pc = pc_start; dc.pc = pc_start;
dc.cc_op = CC_OP_DYNAMIC; dc.cc_op = CC_OP_DYNAMIC;
dc.ex_value = tb->cs_base;
do_debug = dc.singlestep_enabled = cs->singlestep_enabled; do_debug = dc.singlestep_enabled = cs->singlestep_enabled;
next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
@ -5431,10 +5770,7 @@ void gen_intermediate_code(CPUS390XState *env, struct TranslationBlock *tb)
gen_io_start(); gen_io_start();
} }
status = NO_EXIT; status = translate_one(env, &dc);
if (status == NO_EXIT) {
status = translate_one(env, &dc);
}
/* If we reach a page boundary, are single stepping, /* If we reach a page boundary, are single stepping,
or exhaust instruction count, stop generation. */ or exhaust instruction count, stop generation. */
@ -5443,7 +5779,8 @@ void gen_intermediate_code(CPUS390XState *env, struct TranslationBlock *tb)
|| tcg_op_buf_full() || tcg_op_buf_full()
|| num_insns >= max_insns || num_insns >= max_insns
|| singlestep || singlestep
|| cs->singlestep_enabled)) { || cs->singlestep_enabled
|| dc.ex_value)) {
status = EXIT_PC_STALE; status = EXIT_PC_STALE;
} }
} while (status == NO_EXIT); } while (status == NO_EXIT);
@ -5463,6 +5800,8 @@ void gen_intermediate_code(CPUS390XState *env, struct TranslationBlock *tb)
/* Next TB starts off with CC_OP_DYNAMIC, so make sure the /* Next TB starts off with CC_OP_DYNAMIC, so make sure the
cc op type is in env */ cc op type is in env */
update_cc_op(&dc); update_cc_op(&dc);
/* FALLTHRU */
case EXIT_PC_CC_UPDATED:
/* Exit the TB, either by raising a debug exception or by return. */ /* Exit the TB, either by raising a debug exception or by return. */
if (do_debug) { if (do_debug) {
gen_exception(EXCP_DEBUG); gen_exception(EXCP_DEBUG);
@ -5485,9 +5824,14 @@ void gen_intermediate_code(CPUS390XState *env, struct TranslationBlock *tb)
if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
&& qemu_log_in_addr_range(pc_start)) { && qemu_log_in_addr_range(pc_start)) {
qemu_log_lock(); qemu_log_lock();
qemu_log("IN: %s\n", lookup_symbol(pc_start)); if (unlikely(dc.ex_value)) {
log_target_disas(cs, pc_start, dc.pc - pc_start, 1); /* ??? Unfortunately log_target_disas can't use host memory. */
qemu_log("\n"); qemu_log("IN: EXECUTE %016" PRIx64 "\n", dc.ex_value);
} else {
qemu_log("IN: %s\n", lookup_symbol(pc_start));
log_target_disas(cs, pc_start, dc.pc - pc_start, 1);
qemu_log("\n");
}
qemu_log_unlock(); qemu_log_unlock();
} }
#endif #endif