s390x update:

- tcg: implement the vector enhancements facility and bump the
   'qemu' cpu model to a stripped-down z14 GA2
 - fix psw.mask handling in signals
 - fix vfio-ccw sense data handling
 -----BEGIN PGP SIGNATURE-----
 
 iQJGBAABCAAwFiEEw9DWbcNiT/aowBjO3s9rk8bwL68FAmDQYXwSHGNvaHVja0By
 ZWRoYXQuY29tAAoJEN7Pa5PG8C+vrDAQALLimgzAm6br4SHP49T7ZsDkuhZwyYpP
 Fg09vxjMmKWgLOIQNp7Xd1vQJ5voGc5D0KleVMuX2feycfmon0yVeIBMan6DTcfr
 lygtiBYrgPWVAs36OXQ/rJUHt2ZUZaQsS57lTgn+Jtn7p+AMjiMrDlam+iqoAnU+
 o5RtTFG+bhqa72WI7mCG54hRfXS1b/K8Ts1qs0oJJVDrDWlmLWfpjuJU3ehvhepA
 hJYnhIRQgbFHPsaJI47s25aa6KC+cGTGGRMl4YmFPACMh1KNXqmGP1XbxyEhz5tl
 LUdU9JRikbBsErcItHfZabGktLtBi7B9Vyh9KhxG9vK7ol8GUD4pomHrLNH2UUtH
 MyhTcuVCcEakuhgRr8GwA+7KO2Y3quqHDC3/kCkIarrE4X+YJl9Glv76we6XvbYL
 4SAPE87Ub465C3J3tUjLDtfq8LpCIUh7zCYLBfk2Yf4pIbjnWMzUBu3UD2XYrKGF
 +g+J8ZVjE/WFsZzWUJL54lLuT8+FjPLgNOsth1WTENGUEK+JgWGpHbpR1XdqQFj8
 f+bk1nrL94iq3KRdmCaO1w6vc+5xDG0tSY4tVJ1Nip1w3ZxmJFOUWGWLs04hz4mn
 WLx3vHbq3g1HZn9dtqwh6BvAP9fdLw2xkBcRtepR7vPM0ydqp2dvBbu99MrZN3H1
 3Sa6lIpr4bII
 =bMQp
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/cohuck-gitlab/tags/s390x-20210621' into staging

s390x update:
- tcg: implement the vector enhancements facility and bump the
  'qemu' cpu model to a stripped-down z14 GA2
- fix psw.mask handling in signals
- fix vfio-ccw sense data handling

# gpg: Signature made Mon 21 Jun 2021 10:53:00 BST
# gpg:                using RSA key C3D0D66DC3624FF6A8C018CEDECF6B93C6F02FAF
# gpg:                issuer "cohuck@redhat.com"
# gpg: Good signature from "Cornelia Huck <conny@cornelia-huck.de>" [unknown]
# gpg:                 aka "Cornelia Huck <huckc@linux.vnet.ibm.com>" [full]
# gpg:                 aka "Cornelia Huck <cornelia.huck@de.ibm.com>" [full]
# gpg:                 aka "Cornelia Huck <cohuck@kernel.org>" [unknown]
# gpg:                 aka "Cornelia Huck <cohuck@redhat.com>" [unknown]
# Primary key fingerprint: C3D0 D66D C362 4FF6 A8C0  18CE DECF 6B93 C6F0 2FAF

* remotes/cohuck-gitlab/tags/s390x-20210621: (37 commits)
  s390x/css: Add passthrough IRB
  s390x/css: Refactor IRB construction
  s390x/css: Split out the IRB sense data
  s390x/css: Introduce an ESW struct
  linux-user/s390x: Save and restore psw.mask properly
  target/s390x: Use s390_cpu_{set_psw, get_psw_mask} in gdbstub
  target/s390x: Improve s390_cpu_dump_state vs cc_op
  target/s390x: Do not modify cpu state in s390_cpu_get_psw_mask
  target/s390x: Expose load_psw and get_psw_mask to cpu.h
  configure: Check whether we can compile the s390-ccw bios with -msoft-float
  s390x/cpumodel: Bump up QEMU model to a stripped-down IBM z14 GA2
  s390x/tcg: We support Vector enhancements facility
  linux-user: elf: s390x: Prepare for Vector enhancements facility
  s390x/tcg: Implement VECTOR FP (MAXIMUM|MINIMUM)
  s390x/tcg: Implement VECTOR FP NEGATIVE MULTIPLY AND (ADD|SUBTRACT)
  s390x/tcg: Implement 32/128 bit for VECTOR FP MULTIPLY AND (ADD|SUBTRACT)
  s390x/tcg: Implement 32/128 bit for VECTOR FP TEST DATA CLASS IMMEDIATE
  s390x/tcg: Implement 32/128 bit for VECTOR FP PERFORM SIGN OPERATION
  s390x/tcg: Implement 128 bit for VECTOR FP LOAD ROUNDED
  s390x/tcg: Implement 64 bit for VECTOR FP LOAD LENGTHENED
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2021-06-22 14:36:58 +01:00
commit bf7942e406
30 changed files with 1649 additions and 619 deletions

2
configure vendored
View file

@ -5424,7 +5424,7 @@ if test "$cpu" = "s390x" ; then
write_c_skeleton
compile_prog "-march=z900" ""
has_z900=$?
if [ $has_z900 = 0 ] || compile_prog "-march=z10" ""; then
if [ $has_z900 = 0 ] || compile_object "-march=z10 -msoft-float -Werror"; then
if [ $has_z900 != 0 ]; then
echo "WARNING: Your compiler does not support the z900!"
echo " The s390-ccw bios will only work with guest CPUs >= z10."

View file

@ -129,6 +129,7 @@ static void emulated_ccw_3270_realize(DeviceState *ds, Error **errp)
EMULATED_CCW_3270_CHPID_TYPE);
sch->do_subchannel_work = do_subchannel_work_virtual;
sch->ccw_cb = emulated_ccw_3270_cb;
sch->irb_cb = build_irb_virtual;
ck->init(dev, &err);
if (err) {

View file

@ -1335,6 +1335,14 @@ static void copy_schib_to_guest(SCHIB *dest, const SCHIB *src)
}
}
void copy_esw_to_guest(ESW *dest, const ESW *src)
{
dest->word0 = cpu_to_be32(src->word0);
dest->erw = cpu_to_be32(src->erw);
dest->word2 = cpu_to_be64(src->word2);
dest->word4 = cpu_to_be32(src->word4);
}
IOInstEnding css_do_stsch(SubchDev *sch, SCHIB *schib)
{
int ret;
@ -1604,9 +1612,8 @@ static void copy_irb_to_guest(IRB *dest, const IRB *src, const PMCW *pmcw,
copy_scsw_to_guest(&dest->scsw, &src->scsw);
for (i = 0; i < ARRAY_SIZE(dest->esw); i++) {
dest->esw[i] = cpu_to_be32(src->esw[i]);
}
copy_esw_to_guest(&dest->esw, &src->esw);
for (i = 0; i < ARRAY_SIZE(dest->ecw); i++) {
dest->ecw[i] = cpu_to_be32(src->ecw[i]);
}
@ -1632,6 +1639,55 @@ static void copy_irb_to_guest(IRB *dest, const IRB *src, const PMCW *pmcw,
*irb_len = sizeof(*dest);
}
static void build_irb_sense_data(SubchDev *sch, IRB *irb)
{
int i;
/* Attention: sense_data is already BE! */
memcpy(irb->ecw, sch->sense_data, sizeof(sch->sense_data));
for (i = 0; i < ARRAY_SIZE(irb->ecw); i++) {
irb->ecw[i] = be32_to_cpu(irb->ecw[i]);
}
}
void build_irb_passthrough(SubchDev *sch, IRB *irb)
{
/* Copy ESW from hardware */
irb->esw = sch->esw;
/*
* If (irb->esw.erw & ESW_ERW_SENSE) is true, then the contents
* of the ECW is sense data. If false, then it is model-dependent
* information. Either way, copy it into the IRB for the guest to
* read/decide what to do with.
*/
build_irb_sense_data(sch, irb);
}
void build_irb_virtual(SubchDev *sch, IRB *irb)
{
SCHIB *schib = &sch->curr_status;
uint16_t stctl = schib->scsw.ctrl & SCSW_CTRL_MASK_STCTL;
if (stctl & SCSW_STCTL_STATUS_PEND) {
if (schib->scsw.cstat & (SCSW_CSTAT_DATA_CHECK |
SCSW_CSTAT_CHN_CTRL_CHK |
SCSW_CSTAT_INTF_CTRL_CHK)) {
irb->scsw.flags |= SCSW_FLAGS_MASK_ESWF;
irb->esw.word0 = 0x04804000;
} else {
irb->esw.word0 = 0x00800000;
}
/* If a unit check is pending, copy sense data. */
if ((schib->scsw.dstat & SCSW_DSTAT_UNIT_CHECK) &&
(schib->pmcw.chars & PMCW_CHARS_MASK_CSENSE)) {
irb->scsw.flags |= SCSW_FLAGS_MASK_ESWF | SCSW_FLAGS_MASK_ECTL;
build_irb_sense_data(sch, irb);
irb->esw.erw = ESW_ERW_SENSE | (sizeof(sch->sense_data) << 8);
}
}
}
int css_do_tsch_get_irb(SubchDev *sch, IRB *target_irb, int *irb_len)
{
SCHIB *schib = &sch->curr_status;
@ -1650,29 +1706,12 @@ int css_do_tsch_get_irb(SubchDev *sch, IRB *target_irb, int *irb_len)
/* Copy scsw from current status. */
irb.scsw = schib->scsw;
if (stctl & SCSW_STCTL_STATUS_PEND) {
if (schib->scsw.cstat & (SCSW_CSTAT_DATA_CHECK |
SCSW_CSTAT_CHN_CTRL_CHK |
SCSW_CSTAT_INTF_CTRL_CHK)) {
irb.scsw.flags |= SCSW_FLAGS_MASK_ESWF;
irb.esw[0] = 0x04804000;
} else {
irb.esw[0] = 0x00800000;
}
/* If a unit check is pending, copy sense data. */
if ((schib->scsw.dstat & SCSW_DSTAT_UNIT_CHECK) &&
(schib->pmcw.chars & PMCW_CHARS_MASK_CSENSE)) {
int i;
irb.scsw.flags |= SCSW_FLAGS_MASK_ESWF | SCSW_FLAGS_MASK_ECTL;
/* Attention: sense_data is already BE! */
memcpy(irb.ecw, sch->sense_data, sizeof(sch->sense_data));
for (i = 0; i < ARRAY_SIZE(irb.ecw); i++) {
irb.ecw[i] = be32_to_cpu(irb.ecw[i]);
}
irb.esw[1] = 0x01000000 | (sizeof(sch->sense_data) << 8);
}
/* Build other IRB data, if necessary */
if (sch->irb_cb) {
sch->irb_cb(sch, &irb);
}
/* Store the irb to the guest. */
p = schib->pmcw;
copy_irb_to_guest(target_irb, &irb, &p, irb_len);

View file

@ -124,6 +124,7 @@ static void s390_ccw_realize(S390CCWDevice *cdev, char *sysfsdev, Error **errp)
}
sch->driver_data = cdev;
sch->do_subchannel_work = do_subchannel_work_passthrough;
sch->irb_cb = build_irb_passthrough;
ccw_dev->sch = sch;
ret = css_sch_build_schib(sch, &cdev->hostid);

View file

@ -802,7 +802,10 @@ DEFINE_CCW_MACHINE(6_1, "6.1", true);
static void ccw_machine_6_0_instance_options(MachineState *machine)
{
static const S390FeatInit qemu_cpu_feat = { S390_FEAT_LIST_QEMU_V6_0 };
ccw_machine_6_1_instance_options(machine);
s390_set_qemu_cpu_model(0x2964, 13, 2, qemu_cpu_feat);
}
static void ccw_machine_6_0_class_options(MachineClass *mc)

View file

@ -753,6 +753,7 @@ static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp)
sch->id.reserved = 0xff;
sch->id.cu_type = VIRTIO_CCW_CU_TYPE;
sch->do_subchannel_work = do_subchannel_work_virtual;
sch->irb_cb = build_irb_virtual;
ccw_dev->sch = sch;
dev->indicators = NULL;
dev->revision = -1;

View file

@ -321,6 +321,7 @@ static void vfio_ccw_io_notifier_handler(void *opaque)
SCHIB *schib = &sch->curr_status;
SCSW s;
IRB irb;
ESW esw;
int size;
if (!event_notifier_test_and_clear(&vcdev->io_notifier)) {
@ -371,6 +372,9 @@ static void vfio_ccw_io_notifier_handler(void *opaque)
copy_scsw_to_guest(&s, &irb.scsw);
schib->scsw = s;
copy_esw_to_guest(&esw, &irb.esw);
sch->esw = esw;
/* If a uint check is pending, copy sense data. */
if ((schib->scsw.dstat & SCSW_DSTAT_UNIT_CHECK) &&
(schib->pmcw.chars & PMCW_CHARS_MASK_CSENSE)) {

View file

@ -605,6 +605,13 @@ typedef struct {
#define HWCAP_S390_HIGH_GPRS 512
#define HWCAP_S390_TE 1024
#define HWCAP_S390_VXRS 2048
#define HWCAP_S390_VXRS_BCD 4096
#define HWCAP_S390_VXRS_EXT 8192
#define HWCAP_S390_GS 16384
#define HWCAP_S390_VXRS_EXT2 32768
#define HWCAP_S390_VXRS_PDE 65536
#define HWCAP_S390_SORT 131072
#define HWCAP_S390_DFLT 262144
/* M68K specific definitions. */
/* We use the top 24 bits to encode information about the

View file

@ -138,8 +138,10 @@ struct SubchDev {
int (*ccw_cb) (SubchDev *, CCW1);
void (*disable_cb)(SubchDev *);
IOInstEnding (*do_subchannel_work) (SubchDev *);
void (*irb_cb)(SubchDev *, IRB *);
SenseId id;
void *driver_data;
ESW esw;
};
static inline void sch_gen_unit_exception(SubchDev *sch)
@ -201,6 +203,7 @@ int css_sch_build_schib(SubchDev *sch, CssDevId *dev_id);
unsigned int css_find_free_chpid(uint8_t cssid);
uint16_t css_build_subchannel_id(SubchDev *sch);
void copy_scsw_to_guest(SCSW *dest, const SCSW *src);
void copy_esw_to_guest(ESW *dest, const ESW *src);
void css_inject_io_interrupt(SubchDev *sch);
void css_reset(void);
void css_reset_sch(SubchDev *sch);
@ -215,6 +218,8 @@ void css_clear_sei_pending(void);
IOInstEnding s390_ccw_cmd_request(SubchDev *sch);
IOInstEnding do_subchannel_work_virtual(SubchDev *sub);
IOInstEnding do_subchannel_work_passthrough(SubchDev *sub);
void build_irb_passthrough(SubchDev *sch, IRB *irb);
void build_irb_virtual(SubchDev *sch, IRB *irb);
int s390_ccw_halt(SubchDev *sch);
int s390_ccw_clear(SubchDev *sch);

View file

@ -123,10 +123,20 @@ typedef struct SCHIB {
uint8_t mda[4];
} QEMU_PACKED SCHIB;
/* format-0 extended-status word */
typedef struct ESW {
uint32_t word0; /* subchannel logout for format 0 */
uint32_t erw;
uint64_t word2; /* failing-storage address for format 0 */
uint32_t word4; /* secondary-CCW address for format 0 */
} QEMU_PACKED ESW;
#define ESW_ERW_SENSE 0x01000000
/* interruption response block */
typedef struct IRB {
SCSW scsw;
uint32_t esw[5];
ESW esw;
uint32_t ecw[8];
uint32_t emw[8];
} IRB;

View file

@ -1376,6 +1376,7 @@ static uint32_t get_elf_hwcap(void)
hwcap |= HWCAP_S390_ETF3EH;
}
GET_FEATURE(S390_FEAT_VECTOR, HWCAP_S390_VXRS);
GET_FEATURE(S390_FEAT_VECTOR_ENH, HWCAP_S390_VXRS_EXT);
return hwcap;
}

View file

@ -112,15 +112,23 @@ get_sigframe(struct target_sigaction *ka, CPUS390XState *env, size_t frame_size)
return (sp - frame_size) & -8ul;
}
#define PSW_USER_BITS (PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT | \
PSW_MASK_MCHECK | PSW_MASK_PSTATE | PSW_ASC_PRIMARY)
#define PSW_MASK_USER (PSW_MASK_ASC | PSW_MASK_CC | PSW_MASK_PM | \
PSW_MASK_64 | PSW_MASK_32)
static void save_sigregs(CPUS390XState *env, target_sigregs *sregs)
{
uint64_t psw_mask = s390_cpu_get_psw_mask(env);
int i;
/*
* Copy a 'clean' PSW mask to the user to avoid leaking
* information about whether PER is currently on.
* TODO: qemu does not support PSW_MASK_RI; it will never be set.
*/
__put_user(env->psw.mask, &sregs->regs.psw.mask);
psw_mask = PSW_USER_BITS | (psw_mask & PSW_MASK_USER);
__put_user(psw_mask, &sregs->regs.psw.mask);
__put_user(env->psw.addr, &sregs->regs.psw.addr);
for (i = 0; i < 16; i++) {
@ -289,7 +297,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
static void restore_sigregs(CPUS390XState *env, target_sigregs *sc)
{
target_ulong prev_addr;
uint64_t prev_addr, prev_mask, mask, addr;
int i;
for (i = 0; i < 16; i++) {
@ -297,9 +305,28 @@ static void restore_sigregs(CPUS390XState *env, target_sigregs *sc)
}
prev_addr = env->psw.addr;
__get_user(env->psw.mask, &sc->regs.psw.mask);
__get_user(env->psw.addr, &sc->regs.psw.addr);
trace_user_s390x_restore_sigregs(env, env->psw.addr, prev_addr);
__get_user(mask, &sc->regs.psw.mask);
__get_user(addr, &sc->regs.psw.addr);
trace_user_s390x_restore_sigregs(env, addr, prev_addr);
/*
* Use current psw.mask to preserve PER bit.
* TODO:
* if (!is_ri_task(current) && (user_sregs.regs.psw.mask & PSW_MASK_RI))
* return -EINVAL;
* Simply do not allow it to be set in mask.
*/
prev_mask = s390_cpu_get_psw_mask(env);
mask = (prev_mask & ~PSW_MASK_USER) | (mask & PSW_MASK_USER);
/* Check for invalid user address space control. */
if ((mask & PSW_MASK_ASC) == PSW_ASC_HOME) {
mask = (mask & ~PSW_MASK_ASC) | PSW_ASC_PRIMARY;
}
/* Check for invalid amode. */
if (mask & PSW_MASK_64) {
mask |= PSW_MASK_32;
}
s390_cpu_set_psw(env, mask, addr);
for (i = 0; i < 16; i++) {
__get_user(env->aregs[i], &sc->regs.acrs[i]);

View file

@ -509,7 +509,7 @@ uint32_t HELPER(calc_cc)(CPUS390XState *env, uint32_t cc_op, uint64_t src,
#ifndef CONFIG_USER_ONLY
void HELPER(load_psw)(CPUS390XState *env, uint64_t mask, uint64_t addr)
{
load_psw(env, mask, addr);
s390_cpu_set_psw(env, mask, addr);
cpu_loop_exit(env_cpu(env));
}

View file

@ -845,6 +845,9 @@ int s390_cpu_pv_mem_rw(S390CPU *cpu, unsigned int offset, void *hostbuf,
int s390_cpu_restart(S390CPU *cpu);
void s390_init_sigp(void);
/* helper.c */
void s390_cpu_set_psw(CPUS390XState *env, uint64_t mask, uint64_t addr);
uint64_t s390_cpu_get_psw_mask(CPUS390XState *env);
/* outside of target/s390x/ */
S390CPU *s390_cpu_addr2state(uint16_t cpu_addr);

View file

@ -90,8 +90,8 @@ static S390CPUDef s390_cpu_defs[] = {
CPUDEF_INIT(0x8562, 15, 1, 47, 0x08000000U, "gen15b", "IBM z15 T02 GA1"),
};
#define QEMU_MAX_CPU_TYPE 0x2964
#define QEMU_MAX_CPU_GEN 13
#define QEMU_MAX_CPU_TYPE 0x3906
#define QEMU_MAX_CPU_GEN 14
#define QEMU_MAX_CPU_EC_GA 2
static const S390FeatInit qemu_max_cpu_feat_init = { S390_FEAT_LIST_QEMU_MAX };
static S390FeatBitmap qemu_max_cpu_feat;

View file

@ -252,7 +252,7 @@ static void do_program_interrupt(CPUS390XState *env)
lowcore->pgm_ilen = cpu_to_be16(ilen);
lowcore->pgm_code = cpu_to_be16(env->int_pgm_code);
lowcore->program_old_psw.mask = cpu_to_be64(get_psw_mask(env));
lowcore->program_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
lowcore->program_old_psw.addr = cpu_to_be64(env->psw.addr);
mask = be64_to_cpu(lowcore->program_new_psw.mask);
addr = be64_to_cpu(lowcore->program_new_psw.addr);
@ -260,7 +260,7 @@ static void do_program_interrupt(CPUS390XState *env)
cpu_unmap_lowcore(lowcore);
load_psw(env, mask, addr);
s390_cpu_set_psw(env, mask, addr);
}
static void do_svc_interrupt(CPUS390XState *env)
@ -272,14 +272,14 @@ static void do_svc_interrupt(CPUS390XState *env)
lowcore->svc_code = cpu_to_be16(env->int_svc_code);
lowcore->svc_ilen = cpu_to_be16(env->int_svc_ilen);
lowcore->svc_old_psw.mask = cpu_to_be64(get_psw_mask(env));
lowcore->svc_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
lowcore->svc_old_psw.addr = cpu_to_be64(env->psw.addr + env->int_svc_ilen);
mask = be64_to_cpu(lowcore->svc_new_psw.mask);
addr = be64_to_cpu(lowcore->svc_new_psw.addr);
cpu_unmap_lowcore(lowcore);
load_psw(env, mask, addr);
s390_cpu_set_psw(env, mask, addr);
/* When a PER event is pending, the PER exception has to happen
immediately after the SERVICE CALL one. */
@ -348,12 +348,12 @@ static void do_ext_interrupt(CPUS390XState *env)
mask = be64_to_cpu(lowcore->external_new_psw.mask);
addr = be64_to_cpu(lowcore->external_new_psw.addr);
lowcore->external_old_psw.mask = cpu_to_be64(get_psw_mask(env));
lowcore->external_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
lowcore->external_old_psw.addr = cpu_to_be64(env->psw.addr);
cpu_unmap_lowcore(lowcore);
load_psw(env, mask, addr);
s390_cpu_set_psw(env, mask, addr);
}
static void do_io_interrupt(CPUS390XState *env)
@ -373,7 +373,7 @@ static void do_io_interrupt(CPUS390XState *env)
lowcore->subchannel_nr = cpu_to_be16(io->nr);
lowcore->io_int_parm = cpu_to_be32(io->parm);
lowcore->io_int_word = cpu_to_be32(io->word);
lowcore->io_old_psw.mask = cpu_to_be64(get_psw_mask(env));
lowcore->io_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
lowcore->io_old_psw.addr = cpu_to_be64(env->psw.addr);
mask = be64_to_cpu(lowcore->io_new_psw.mask);
addr = be64_to_cpu(lowcore->io_new_psw.addr);
@ -381,7 +381,7 @@ static void do_io_interrupt(CPUS390XState *env)
cpu_unmap_lowcore(lowcore);
g_free(io);
load_psw(env, mask, addr);
s390_cpu_set_psw(env, mask, addr);
}
typedef struct MchkExtSaveArea {
@ -457,14 +457,14 @@ static void do_mchk_interrupt(CPUS390XState *env)
lowcore->clock_comp_save_area = cpu_to_be64(env->ckc >> 8);
lowcore->mcic = cpu_to_be64(mcic);
lowcore->mcck_old_psw.mask = cpu_to_be64(get_psw_mask(env));
lowcore->mcck_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
lowcore->mcck_old_psw.addr = cpu_to_be64(env->psw.addr);
mask = be64_to_cpu(lowcore->mcck_new_psw.mask);
addr = be64_to_cpu(lowcore->mcck_new_psw.addr);
cpu_unmap_lowcore(lowcore);
load_psw(env, mask, addr);
s390_cpu_set_psw(env, mask, addr);
}
void s390_cpu_do_interrupt(CPUState *cs)
@ -592,9 +592,11 @@ void s390x_cpu_debug_excp_handler(CPUState *cs)
and MVCS instrutions are not used. */
env->per_perc_atmid |= env->psw.mask & (PSW_MASK_ASC) >> 46;
/* Remove all watchpoints to re-execute the code. A PER exception
will be triggered, it will call load_psw which will recompute
the watchpoints. */
/*
* Remove all watchpoints to re-execute the code. A PER exception
* will be triggered, it will call s390_cpu_set_psw which will
* recompute the watchpoints.
*/
cpu_watchpoint_remove_all(cs, BP_CPU);
cpu_loop_exit_noexc(cs);
}

View file

@ -509,6 +509,9 @@ uint64_t HELPER(cgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
if (float32_is_any_nan(v2)) {
return INT64_MIN;
}
return ret;
}
@ -520,6 +523,9 @@ uint64_t HELPER(cgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
if (float64_is_any_nan(v2)) {
return INT64_MIN;
}
return ret;
}
@ -532,6 +538,9 @@ uint64_t HELPER(cgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
if (float128_is_any_nan(v2)) {
return INT64_MIN;
}
return ret;
}
@ -543,6 +552,9 @@ uint64_t HELPER(cfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
if (float32_is_any_nan(v2)) {
return INT32_MIN;
}
return ret;
}
@ -554,6 +566,9 @@ uint64_t HELPER(cfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
if (float64_is_any_nan(v2)) {
return INT32_MIN;
}
return ret;
}
@ -566,6 +581,9 @@ uint64_t HELPER(cfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
if (float128_is_any_nan(v2)) {
return INT32_MIN;
}
return ret;
}
@ -573,12 +591,12 @@ uint64_t HELPER(cfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
uint64_t HELPER(clgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
uint64_t ret;
v2 = float32_to_float64(v2, &env->fpu_status);
ret = float64_to_uint64(v2, &env->fpu_status);
uint64_t ret = float32_to_uint64(v2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
if (float32_is_any_nan(v2)) {
return 0;
}
return ret;
}
@ -590,6 +608,9 @@ uint64_t HELPER(clgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
if (float64_is_any_nan(v2)) {
return 0;
}
return ret;
}
@ -601,6 +622,9 @@ uint64_t HELPER(clgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
if (float128_is_any_nan(make_float128(h, l))) {
return 0;
}
return ret;
}
@ -612,6 +636,9 @@ uint64_t HELPER(clfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
if (float32_is_any_nan(v2)) {
return 0;
}
return ret;
}
@ -623,6 +650,9 @@ uint64_t HELPER(clfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
if (float64_is_any_nan(v2)) {
return 0;
}
return ret;
}
@ -634,6 +664,9 @@ uint64_t HELPER(clfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
if (float128_is_any_nan(make_float128(h, l))) {
return 0;
}
return ret;
}

View file

@ -31,18 +31,10 @@ int s390_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
{
S390CPU *cpu = S390_CPU(cs);
CPUS390XState *env = &cpu->env;
uint64_t val;
int cc_op;
switch (n) {
case S390_PSWM_REGNUM:
if (tcg_enabled()) {
cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst,
env->cc_vr);
val = deposit64(env->psw.mask, 44, 2, cc_op);
return gdb_get_regl(mem_buf, val);
}
return gdb_get_regl(mem_buf, env->psw.mask);
return gdb_get_regl(mem_buf, s390_cpu_get_psw_mask(env));
case S390_PSWA_REGNUM:
return gdb_get_regl(mem_buf, env->psw.addr);
case S390_R0_REGNUM ... S390_R15_REGNUM:
@ -59,10 +51,7 @@ int s390_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
switch (n) {
case S390_PSWM_REGNUM:
env->psw.mask = tmpl;
if (tcg_enabled()) {
env->cc_op = extract64(tmpl, 44, 2);
}
s390_cpu_set_psw(env, tmpl, env->psw.addr);
break;
case S390_PSWA_REGNUM:
env->psw.addr = tmpl;

View file

@ -706,20 +706,23 @@ static uint16_t qemu_V4_1[] = {
S390_FEAT_VECTOR,
};
static uint16_t qemu_LATEST[] = {
static uint16_t qemu_V6_0[] = {
S390_FEAT_ACCESS_EXCEPTION_FS_INDICATION,
S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2,
S390_FEAT_ESOP,
};
static uint16_t qemu_LATEST[] = {
S390_FEAT_INSTRUCTION_EXEC_PROT,
S390_FEAT_MISC_INSTRUCTION_EXT2,
S390_FEAT_MSA_EXT_8,
S390_FEAT_VECTOR_ENH,
};
/* add all new definitions before this point */
static uint16_t qemu_MAX[] = {
/* generates a dependency warning, leave it out for now */
S390_FEAT_MSA_EXT_5,
/* features introduced after the z13 */
S390_FEAT_INSTRUCTION_EXEC_PROT,
S390_FEAT_MISC_INSTRUCTION_EXT2,
S390_FEAT_MSA_EXT_8,
};
/****** END FEATURE DEFS ******/
@ -838,6 +841,7 @@ static FeatGroupDefSpec QemuFeatDef[] = {
QEMU_FEAT_INITIALIZER(V3_1),
QEMU_FEAT_INITIALIZER(V4_0),
QEMU_FEAT_INITIALIZER(V4_1),
QEMU_FEAT_INITIALIZER(V6_0),
QEMU_FEAT_INITIALIZER(LATEST),
QEMU_FEAT_INITIALIZER(MAX),
};

View file

@ -104,44 +104,6 @@ void s390_handle_wait(S390CPU *cpu)
}
}
void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr)
{
uint64_t old_mask = env->psw.mask;
env->psw.addr = addr;
env->psw.mask = mask;
/* KVM will handle all WAITs and trigger a WAIT exit on disabled_wait */
if (!tcg_enabled()) {
return;
}
env->cc_op = (mask >> 44) & 3;
if ((old_mask ^ mask) & PSW_MASK_PER) {
s390_cpu_recompute_watchpoints(env_cpu(env));
}
if (mask & PSW_MASK_WAIT) {
s390_handle_wait(env_archcpu(env));
}
}
uint64_t get_psw_mask(CPUS390XState *env)
{
uint64_t r = env->psw.mask;
if (tcg_enabled()) {
env->cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst,
env->cc_vr);
r &= ~PSW_MASK_CC;
assert(!(env->cc_op & ~3));
r |= (uint64_t)env->cc_op << 44;
}
return r;
}
LowCore *cpu_map_lowcore(CPUS390XState *env)
{
LowCore *lowcore;
@ -168,7 +130,7 @@ void do_restart_interrupt(CPUS390XState *env)
lowcore = cpu_map_lowcore(env);
lowcore->restart_old_psw.mask = cpu_to_be64(get_psw_mask(env));
lowcore->restart_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
lowcore->restart_old_psw.addr = cpu_to_be64(env->psw.addr);
mask = be64_to_cpu(lowcore->restart_new_psw.mask);
addr = be64_to_cpu(lowcore->restart_new_psw.addr);
@ -176,7 +138,7 @@ void do_restart_interrupt(CPUS390XState *env)
cpu_unmap_lowcore(lowcore);
env->pending_int &= ~INTERRUPT_RESTART;
load_psw(env, mask, addr);
s390_cpu_set_psw(env, mask, addr);
}
void s390_cpu_recompute_watchpoints(CPUState *cs)
@ -266,7 +228,7 @@ int s390_store_status(S390CPU *cpu, hwaddr addr, bool store_arch)
sa->grs[i] = cpu_to_be64(cpu->env.regs[i]);
}
sa->psw.addr = cpu_to_be64(cpu->env.psw.addr);
sa->psw.mask = cpu_to_be64(get_psw_mask(&cpu->env));
sa->psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(&cpu->env));
sa->prefix = cpu_to_be32(cpu->env.psa);
sa->fpc = cpu_to_be32(cpu->env.fpc);
sa->todpr = cpu_to_be32(cpu->env.todpr);
@ -323,20 +285,67 @@ int s390_store_adtl_status(S390CPU *cpu, hwaddr addr, hwaddr len)
cpu_physical_memory_unmap(sa, len, 1, len);
return 0;
}
#else
/* For user-only, tcg is always enabled. */
#define tcg_enabled() true
#endif /* CONFIG_USER_ONLY */
void s390_cpu_set_psw(CPUS390XState *env, uint64_t mask, uint64_t addr)
{
#ifndef CONFIG_USER_ONLY
uint64_t old_mask = env->psw.mask;
#endif
env->psw.addr = addr;
env->psw.mask = mask;
/* KVM will handle all WAITs and trigger a WAIT exit on disabled_wait */
if (!tcg_enabled()) {
return;
}
env->cc_op = (mask >> 44) & 3;
#ifndef CONFIG_USER_ONLY
if ((old_mask ^ mask) & PSW_MASK_PER) {
s390_cpu_recompute_watchpoints(env_cpu(env));
}
if (mask & PSW_MASK_WAIT) {
s390_handle_wait(env_archcpu(env));
}
#endif
}
uint64_t s390_cpu_get_psw_mask(CPUS390XState *env)
{
uint64_t r = env->psw.mask;
if (tcg_enabled()) {
uint64_t cc = calc_cc(env, env->cc_op, env->cc_src,
env->cc_dst, env->cc_vr);
assert(cc <= 3);
r &= ~PSW_MASK_CC;
r |= cc << 44;
}
return r;
}
void s390_cpu_dump_state(CPUState *cs, FILE *f, int flags)
{
S390CPU *cpu = S390_CPU(cs);
CPUS390XState *env = &cpu->env;
int i;
if (env->cc_op > 3) {
qemu_fprintf(f, "PSW=mask %016" PRIx64 " addr %016" PRIx64 " cc %15s\n",
env->psw.mask, env->psw.addr, cc_name(env->cc_op));
qemu_fprintf(f, "PSW=mask %016" PRIx64 " addr %016" PRIx64,
s390_cpu_get_psw_mask(env), env->psw.addr);
if (!tcg_enabled()) {
qemu_fprintf(f, "\n");
} else if (env->cc_op > 3) {
qemu_fprintf(f, " cc %15s\n", cc_name(env->cc_op));
} else {
qemu_fprintf(f, "PSW=mask %016" PRIx64 " addr %016" PRIx64 " cc %02x\n",
env->psw.mask, env->psw.addr, env->cc_op);
qemu_fprintf(f, " cc %02x\n", env->cc_op);
}
for (i = 0; i < 16; i++) {

View file

@ -126,6 +126,7 @@ DEF_HELPER_FLAGS_1(stck, TCG_CALL_NO_RWG_SE, i64, env)
DEF_HELPER_FLAGS_3(probe_write_access, TCG_CALL_NO_WG, void, env, i64, i64)
/* === Vector Support Instructions === */
DEF_HELPER_FLAGS_4(gvec_vbperm, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(vll, TCG_CALL_NO_WG, void, env, ptr, i64, i64)
DEF_HELPER_FLAGS_4(gvec_vpk16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vpk32, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
@ -246,50 +247,77 @@ DEF_HELPER_6(gvec_vstrc_cc_rt16, void, ptr, cptr, cptr, cptr, env, i32)
DEF_HELPER_6(gvec_vstrc_cc_rt32, void, ptr, cptr, cptr, cptr, env, i32)
/* === Vector Floating-Point Instructions */
DEF_HELPER_FLAGS_5(gvec_vfa32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfa64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfa64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfa128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_4(gvec_wfc32, void, cptr, cptr, env, i32)
DEF_HELPER_4(gvec_wfk32, void, cptr, cptr, env, i32)
DEF_HELPER_4(gvec_wfc64, void, cptr, cptr, env, i32)
DEF_HELPER_4(gvec_wfk64, void, cptr, cptr, env, i32)
DEF_HELPER_4(gvec_wfc128, void, cptr, cptr, env, i32)
DEF_HELPER_4(gvec_wfk128, void, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfce32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_5(gvec_vfce32_cc, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfce64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfce64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_5(gvec_vfce64_cc, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_5(gvec_vfce64s_cc, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfce128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_5(gvec_vfce128_cc, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfch32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_5(gvec_vfch32_cc, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfch64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfch64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_5(gvec_vfch64_cc, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_5(gvec_vfch64s_cc, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfch128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_5(gvec_vfch128_cc, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfche32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_5(gvec_vfche32_cc, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfche64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfche64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_5(gvec_vfche64_cc, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_5(gvec_vfche64s_cc, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfche128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_5(gvec_vfche128_cc, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vcdg64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vcdg64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vcdlg64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vcdlg64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vcgd64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vcgd64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vclgd64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vclgd64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfd32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfd64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfd64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfd128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vfi32, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vfi64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vfi64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vfi128, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vfll32, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vfll32s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vfll64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vflr64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vflr64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vflr128, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfm32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfm64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfm64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfm128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfmax32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfmax64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfmax128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfmin32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfmin64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfmin128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_6(gvec_vfma32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_6(gvec_vfma64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_6(gvec_vfma64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_6(gvec_vfma128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_6(gvec_vfms32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_6(gvec_vfms64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_6(gvec_vfms64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_6(gvec_vfms128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_6(gvec_vfnma32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_6(gvec_vfnma64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_6(gvec_vfnma128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_6(gvec_vfnms32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_6(gvec_vfnms64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_6(gvec_vfnms128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vfsq32, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vfsq64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vfsq64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vfsq128, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfs32, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfs64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfs64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfs128, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_4(gvec_vftci32, void, ptr, cptr, env, i32)
DEF_HELPER_4(gvec_vftci64, void, ptr, cptr, env, i32)
DEF_HELPER_4(gvec_vftci64s, void, ptr, cptr, env, i32)
DEF_HELPER_4(gvec_vftci128, void, ptr, cptr, env, i32)
#ifndef CONFIG_USER_ONLY
DEF_HELPER_3(servc, i32, env, i64, i64)

View file

@ -989,6 +989,8 @@
/* === Vector Support Instructions === */
/* VECTOR BIT PERMUTE */
E(0xe785, VBPERM, VRR_c, VE, 0, 0, 0, 0, vbperm, 0, 0, IF_VEC)
/* VECTOR GATHER ELEMENT */
E(0xe713, VGEF, VRV, V, la2, 0, 0, 0, vge, 0, ES_32, IF_VEC)
E(0xe712, VGEG, VRV, V, la2, 0, 0, 0, vge, 0, ES_64, IF_VEC)
@ -1149,6 +1151,8 @@
F(0xe7a7, VMO, VRR_c, V, 0, 0, 0, 0, vm, 0, IF_VEC)
/* VECTOR MULTIPLY LOGICAL ODD */
F(0xe7a5, VMLO, VRR_c, V, 0, 0, 0, 0, vm, 0, IF_VEC)
/* VECTOR MULTIPLY SUM LOGICAL */
F(0xe7b8, VMSL, VRR_d, VE, 0, 0, 0, 0, vmsl, 0, IF_VEC)
/* VECTOR NAND */
F(0xe76e, VNN, VRR_c, VE, 0, 0, 0, 0, vnn, 0, IF_VEC)
/* VECTOR NOR */
@ -1245,16 +1249,24 @@
F(0xe7e5, VFD, VRR_c, V, 0, 0, 0, 0, vfa, 0, IF_VEC)
/* VECTOR LOAD FP INTEGER */
F(0xe7c7, VFI, VRR_a, V, 0, 0, 0, 0, vcdg, 0, IF_VEC)
/* VECTOR LOAD LENGTHENED */
/* VECTOR FP LOAD LENGTHENED */
F(0xe7c4, VFLL, VRR_a, V, 0, 0, 0, 0, vfll, 0, IF_VEC)
/* VECTOR LOAD ROUNDED */
/* VECTOR FP LOAD ROUNDED */
F(0xe7c5, VFLR, VRR_a, V, 0, 0, 0, 0, vcdg, 0, IF_VEC)
/* VECTOR FP MAXIMUM */
F(0xe7ef, VFMAX, VRR_c, VE, 0, 0, 0, 0, vfmax, 0, IF_VEC)
/* VECTOR FP MINIMUM */
F(0xe7ee, VFMIN, VRR_c, VE, 0, 0, 0, 0, vfmax, 0, IF_VEC)
/* VECTOR FP MULTIPLY */
F(0xe7e7, VFM, VRR_c, V, 0, 0, 0, 0, vfa, 0, IF_VEC)
/* VECTOR FP MULTIPLY AND ADD */
F(0xe78f, VFMA, VRR_e, V, 0, 0, 0, 0, vfma, 0, IF_VEC)
/* VECTOR FP MULTIPLY AND SUBTRACT */
F(0xe78e, VFMS, VRR_e, V, 0, 0, 0, 0, vfma, 0, IF_VEC)
/* VECTOR FP NEGATIVE MULTIPLY AND ADD */
F(0xe79f, VFNMA, VRR_e, VE, 0, 0, 0, 0, vfma, 0, IF_VEC)
/* VECTOR FP NEGATIVE MULTIPLY AND SUBTRACT */
F(0xe79e, VFNMS, VRR_e, VE, 0, 0, 0, 0, vfma, 0, IF_VEC)
/* VECTOR FP PERFORM SIGN OPERATION */
F(0xe7cc, VFPSO, VRR_a, V, 0, 0, 0, 0, vfpso, 0, IF_VEC)
/* VECTOR FP SQUARE ROOT */

View file

@ -235,10 +235,6 @@ int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
const char *cc_name(enum cc_op cc_op);
uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
uint64_t vr);
#ifndef CONFIG_USER_ONLY
void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr);
#endif /* CONFIG_USER_ONLY */
/* cpu.c */
#ifndef CONFIG_USER_ONLY
@ -288,6 +284,15 @@ uint8_t s390_softfloat_exc_to_ieee(unsigned int exc);
int s390_swap_bfp_rounding_mode(CPUS390XState *env, int m3);
void s390_restore_bfp_rounding_mode(CPUS390XState *env, int old_mode);
int float_comp_to_cc(CPUS390XState *env, int float_compare);
#define DCMASK_ZERO 0x0c00
#define DCMASK_NORMAL 0x0300
#define DCMASK_SUBNORMAL 0x00c0
#define DCMASK_INFINITY 0x0030
#define DCMASK_QUIET_NAN 0x000c
#define DCMASK_SIGNALING_NAN 0x0003
#define DCMASK_NAN 0x000f
#define DCMASK_NEGATIVE 0x0555
uint16_t float32_dcmask(CPUS390XState *env, float32 f1);
uint16_t float64_dcmask(CPUS390XState *env, float64 f1);
uint16_t float128_dcmask(CPUS390XState *env, float128 f1);
@ -303,7 +308,6 @@ void s390_cpu_gdb_init(CPUState *cs);
void s390_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
void do_restart_interrupt(CPUS390XState *env);
#ifndef CONFIG_USER_ONLY
uint64_t get_psw_mask(CPUS390XState *env);
void s390_cpu_recompute_watchpoints(CPUState *cs);
void s390x_tod_timer(void *opaque);
void s390x_cpu_timer(void *opaque);

View file

@ -49,11 +49,6 @@ int kvm_s390_get_ri(void)
return 0;
}
int kvm_s390_get_gs(void)
{
return 0;
}
int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_low)
{
return -ENOSYS;

View file

@ -154,7 +154,6 @@ static int cap_async_pf;
static int cap_mem_op;
static int cap_s390_irq;
static int cap_ri;
static int cap_gs;
static int cap_hpage_1m;
static int cap_vcpu_resets;
static int cap_protected;
@ -369,9 +368,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
}
}
if (cpu_model_allowed()) {
if (kvm_vm_enable_cap(s, KVM_CAP_S390_GS, 0) == 0) {
cap_gs = 1;
}
kvm_vm_enable_cap(s, KVM_CAP_S390_GS, 0);
}
/*
@ -2039,11 +2036,6 @@ int kvm_s390_get_ri(void)
return cap_ri;
}
int kvm_s390_get_gs(void)
{
return cap_gs;
}
int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state)
{
struct kvm_mp_state mp_state = {};

View file

@ -27,7 +27,6 @@ void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu);
int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu);
int kvm_s390_get_hpage_1m(void);
int kvm_s390_get_ri(void);
int kvm_s390_get_gs(void);
int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_clock);
int kvm_s390_get_clock_ext(uint8_t *tod_high, uint64_t *tod_clock);
int kvm_s390_set_clock(uint8_t tod_high, uint64_t tod_clock);

View file

@ -235,7 +235,8 @@ static void sigp_restart(CPUState *cs, run_on_cpu_data arg)
cpu_synchronize_state(cs);
/*
* Set OPERATING (and unhalting) before loading the restart PSW.
* load_psw() will then properly halt the CPU again if necessary (TCG).
* s390_cpu_set_psw() will then properly halt the CPU again if
* necessary (TCG).
*/
s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
do_restart_interrupt(&cpu->env);

View file

@ -327,6 +327,14 @@ static void gen_addi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
tcg_temp_free_i64(bh);
}
static DisasJumpType op_vbperm(DisasContext *s, DisasOps *o)
{
gen_gvec_3_ool(get_field(s, v1), get_field(s, v2), get_field(s, v3), 0,
gen_helper_gvec_vbperm);
return DISAS_NEXT;
}
static DisasJumpType op_vge(DisasContext *s, DisasOps *o)
{
const uint8_t es = s->insn->data;
@ -1771,6 +1779,56 @@ static DisasJumpType op_vm(DisasContext *s, DisasOps *o)
return DISAS_NEXT;
}
static DisasJumpType op_vmsl(DisasContext *s, DisasOps *o)
{
TCGv_i64 l1, h1, l2, h2;
if (get_field(s, m4) != ES_64) {
gen_program_exception(s, PGM_SPECIFICATION);
return DISAS_NORETURN;
}
l1 = tcg_temp_new_i64();
h1 = tcg_temp_new_i64();
l2 = tcg_temp_new_i64();
h2 = tcg_temp_new_i64();
/* Multipy both even elements from v2 and v3 */
read_vec_element_i64(l1, get_field(s, v2), 0, ES_64);
read_vec_element_i64(h1, get_field(s, v3), 0, ES_64);
tcg_gen_mulu2_i64(l1, h1, l1, h1);
/* Shift result left by one (x2) if requested */
if (extract32(get_field(s, m6), 3, 1)) {
tcg_gen_add2_i64(l1, h1, l1, h1, l1, h1);
}
/* Multipy both odd elements from v2 and v3 */
read_vec_element_i64(l2, get_field(s, v2), 1, ES_64);
read_vec_element_i64(h2, get_field(s, v3), 1, ES_64);
tcg_gen_mulu2_i64(l2, h2, l2, h2);
/* Shift result left by one (x2) if requested */
if (extract32(get_field(s, m6), 2, 1)) {
tcg_gen_add2_i64(l2, h2, l2, h2, l2, h2);
}
/* Add both intermediate results */
tcg_gen_add2_i64(l1, h1, l1, h1, l2, h2);
/* Add whole v4 */
read_vec_element_i64(h2, get_field(s, v4), 0, ES_64);
read_vec_element_i64(l2, get_field(s, v4), 1, ES_64);
tcg_gen_add2_i64(l1, h1, l1, h1, l2, h2);
/* Store final result into v1. */
write_vec_element_i64(h1, get_field(s, v1), 0, ES_64);
write_vec_element_i64(l1, get_field(s, v1), 1, ES_64);
tcg_temp_free_i64(l1);
tcg_temp_free_i64(h1);
tcg_temp_free_i64(l2);
tcg_temp_free_i64(h2);
return DISAS_NEXT;
}
static DisasJumpType op_vnn(DisasContext *s, DisasOps *o)
{
gen_gvec_fn_3(nand, ES_8, get_field(s, v1),
@ -2443,32 +2501,96 @@ static DisasJumpType op_vfa(DisasContext *s, DisasOps *o)
{
const uint8_t fpf = get_field(s, m4);
const uint8_t m5 = get_field(s, m5);
const bool se = extract32(m5, 3, 1);
gen_helper_gvec_3_ptr *fn;
if (fpf != FPF_LONG || extract32(m5, 0, 3)) {
gen_program_exception(s, PGM_SPECIFICATION);
return DISAS_NORETURN;
}
gen_helper_gvec_3_ptr *fn = NULL;
switch (s->fields.op2) {
case 0xe3:
fn = se ? gen_helper_gvec_vfa64s : gen_helper_gvec_vfa64;
switch (fpf) {
case FPF_SHORT:
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
fn = gen_helper_gvec_vfa32;
}
break;
case FPF_LONG:
fn = gen_helper_gvec_vfa64;
break;
case FPF_EXT:
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
fn = gen_helper_gvec_vfa128;
}
break;
default:
break;
}
break;
case 0xe5:
fn = se ? gen_helper_gvec_vfd64s : gen_helper_gvec_vfd64;
switch (fpf) {
case FPF_SHORT:
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
fn = gen_helper_gvec_vfd32;
}
break;
case FPF_LONG:
fn = gen_helper_gvec_vfd64;
break;
case FPF_EXT:
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
fn = gen_helper_gvec_vfd128;
}
break;
default:
break;
}
break;
case 0xe7:
fn = se ? gen_helper_gvec_vfm64s : gen_helper_gvec_vfm64;
switch (fpf) {
case FPF_SHORT:
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
fn = gen_helper_gvec_vfm32;
}
break;
case FPF_LONG:
fn = gen_helper_gvec_vfm64;
break;
case FPF_EXT:
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
fn = gen_helper_gvec_vfm128;
}
break;
default:
break;
}
break;
case 0xe2:
fn = se ? gen_helper_gvec_vfs64s : gen_helper_gvec_vfs64;
switch (fpf) {
case FPF_SHORT:
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
fn = gen_helper_gvec_vfs32;
}
break;
case FPF_LONG:
fn = gen_helper_gvec_vfs64;
break;
case FPF_EXT:
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
fn = gen_helper_gvec_vfs128;
}
break;
default:
break;
}
break;
default:
g_assert_not_reached();
}
if (!fn || extract32(m5, 0, 3)) {
gen_program_exception(s, PGM_SPECIFICATION);
return DISAS_NORETURN;
}
gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2),
get_field(s, v3), cpu_env, 0, fn);
get_field(s, v3), cpu_env, m5, fn);
return DISAS_NEXT;
}
@ -2476,19 +2598,41 @@ static DisasJumpType op_wfc(DisasContext *s, DisasOps *o)
{
const uint8_t fpf = get_field(s, m3);
const uint8_t m4 = get_field(s, m4);
gen_helper_gvec_2_ptr *fn = NULL;
if (fpf != FPF_LONG || m4) {
switch (fpf) {
case FPF_SHORT:
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
fn = gen_helper_gvec_wfk32;
if (s->fields.op2 == 0xcb) {
fn = gen_helper_gvec_wfc32;
}
}
break;
case FPF_LONG:
fn = gen_helper_gvec_wfk64;
if (s->fields.op2 == 0xcb) {
fn = gen_helper_gvec_wfc64;
}
break;
case FPF_EXT:
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
fn = gen_helper_gvec_wfk128;
if (s->fields.op2 == 0xcb) {
fn = gen_helper_gvec_wfc128;
}
}
break;
default:
break;
};
if (!fn || m4) {
gen_program_exception(s, PGM_SPECIFICATION);
return DISAS_NORETURN;
}
if (s->fields.op2 == 0xcb) {
gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2),
cpu_env, 0, gen_helper_gvec_wfc64);
} else {
gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2),
cpu_env, 0, gen_helper_gvec_wfk64);
}
gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, 0, fn);
set_cc_static(s);
return DISAS_NEXT;
}
@ -2498,46 +2642,68 @@ static DisasJumpType op_vfc(DisasContext *s, DisasOps *o)
const uint8_t fpf = get_field(s, m4);
const uint8_t m5 = get_field(s, m5);
const uint8_t m6 = get_field(s, m6);
const bool se = extract32(m5, 3, 1);
const bool cs = extract32(m6, 0, 1);
gen_helper_gvec_3_ptr *fn;
const bool sq = extract32(m5, 2, 1);
gen_helper_gvec_3_ptr *fn = NULL;
if (fpf != FPF_LONG || extract32(m5, 0, 3) || extract32(m6, 1, 3)) {
switch (s->fields.op2) {
case 0xe8:
switch (fpf) {
case FPF_SHORT:
fn = cs ? gen_helper_gvec_vfce32_cc : gen_helper_gvec_vfce32;
break;
case FPF_LONG:
fn = cs ? gen_helper_gvec_vfce64_cc : gen_helper_gvec_vfce64;
break;
case FPF_EXT:
fn = cs ? gen_helper_gvec_vfce128_cc : gen_helper_gvec_vfce128;
break;
default:
break;
}
break;
case 0xeb:
switch (fpf) {
case FPF_SHORT:
fn = cs ? gen_helper_gvec_vfch32_cc : gen_helper_gvec_vfch32;
break;
case FPF_LONG:
fn = cs ? gen_helper_gvec_vfch64_cc : gen_helper_gvec_vfch64;
break;
case FPF_EXT:
fn = cs ? gen_helper_gvec_vfch128_cc : gen_helper_gvec_vfch128;
break;
default:
break;
}
break;
case 0xea:
switch (fpf) {
case FPF_SHORT:
fn = cs ? gen_helper_gvec_vfche32_cc : gen_helper_gvec_vfche32;
break;
case FPF_LONG:
fn = cs ? gen_helper_gvec_vfche64_cc : gen_helper_gvec_vfche64;
break;
case FPF_EXT:
fn = cs ? gen_helper_gvec_vfche128_cc : gen_helper_gvec_vfche128;
break;
default:
break;
}
break;
default:
g_assert_not_reached();
}
if (!fn || extract32(m5, 0, 2) || extract32(m6, 1, 3) ||
(!s390_has_feat(S390_FEAT_VECTOR_ENH) && (fpf != FPF_LONG || sq))) {
gen_program_exception(s, PGM_SPECIFICATION);
return DISAS_NORETURN;
}
if (cs) {
switch (s->fields.op2) {
case 0xe8:
fn = se ? gen_helper_gvec_vfce64s_cc : gen_helper_gvec_vfce64_cc;
break;
case 0xeb:
fn = se ? gen_helper_gvec_vfch64s_cc : gen_helper_gvec_vfch64_cc;
break;
case 0xea:
fn = se ? gen_helper_gvec_vfche64s_cc : gen_helper_gvec_vfche64_cc;
break;
default:
g_assert_not_reached();
}
} else {
switch (s->fields.op2) {
case 0xe8:
fn = se ? gen_helper_gvec_vfce64s : gen_helper_gvec_vfce64;
break;
case 0xeb:
fn = se ? gen_helper_gvec_vfch64s : gen_helper_gvec_vfch64;
break;
case 0xea:
fn = se ? gen_helper_gvec_vfche64s : gen_helper_gvec_vfche64;
break;
default:
g_assert_not_reached();
}
}
gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2),
get_field(s, v3), cpu_env, 0, fn);
gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2), get_field(s, v3),
cpu_env, m5, fn);
if (cs) {
set_cc_static(s);
}
@ -2549,36 +2715,72 @@ static DisasJumpType op_vcdg(DisasContext *s, DisasOps *o)
const uint8_t fpf = get_field(s, m3);
const uint8_t m4 = get_field(s, m4);
const uint8_t erm = get_field(s, m5);
const bool se = extract32(m4, 3, 1);
gen_helper_gvec_2_ptr *fn;
gen_helper_gvec_2_ptr *fn = NULL;
if (fpf != FPF_LONG || extract32(m4, 0, 2) || erm > 7 || erm == 2) {
gen_program_exception(s, PGM_SPECIFICATION);
return DISAS_NORETURN;
}
switch (s->fields.op2) {
case 0xc3:
fn = se ? gen_helper_gvec_vcdg64s : gen_helper_gvec_vcdg64;
if (fpf == FPF_LONG) {
fn = gen_helper_gvec_vcdg64;
}
break;
case 0xc1:
fn = se ? gen_helper_gvec_vcdlg64s : gen_helper_gvec_vcdlg64;
if (fpf == FPF_LONG) {
fn = gen_helper_gvec_vcdlg64;
}
break;
case 0xc2:
fn = se ? gen_helper_gvec_vcgd64s : gen_helper_gvec_vcgd64;
if (fpf == FPF_LONG) {
fn = gen_helper_gvec_vcgd64;
}
break;
case 0xc0:
fn = se ? gen_helper_gvec_vclgd64s : gen_helper_gvec_vclgd64;
if (fpf == FPF_LONG) {
fn = gen_helper_gvec_vclgd64;
}
break;
case 0xc7:
fn = se ? gen_helper_gvec_vfi64s : gen_helper_gvec_vfi64;
switch (fpf) {
case FPF_SHORT:
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
fn = gen_helper_gvec_vfi32;
}
break;
case FPF_LONG:
fn = gen_helper_gvec_vfi64;
break;
case FPF_EXT:
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
fn = gen_helper_gvec_vfi128;
}
break;
default:
break;
}
break;
case 0xc5:
fn = se ? gen_helper_gvec_vflr64s : gen_helper_gvec_vflr64;
switch (fpf) {
case FPF_LONG:
fn = gen_helper_gvec_vflr64;
break;
case FPF_EXT:
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
fn = gen_helper_gvec_vflr128;
}
break;
default:
break;
}
break;
default:
g_assert_not_reached();
}
if (!fn || extract32(m4, 0, 2) || erm > 7 || erm == 2) {
gen_program_exception(s, PGM_SPECIFICATION);
return DISAS_NORETURN;
}
gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env,
deposit32(m4, 4, 4, erm), fn);
return DISAS_NEXT;
@ -2588,18 +2790,71 @@ static DisasJumpType op_vfll(DisasContext *s, DisasOps *o)
{
const uint8_t fpf = get_field(s, m3);
const uint8_t m4 = get_field(s, m4);
gen_helper_gvec_2_ptr *fn = gen_helper_gvec_vfll32;
gen_helper_gvec_2_ptr *fn = NULL;
if (fpf != FPF_SHORT || extract32(m4, 0, 3)) {
switch (fpf) {
case FPF_SHORT:
fn = gen_helper_gvec_vfll32;
break;
case FPF_LONG:
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
fn = gen_helper_gvec_vfll64;
}
break;
default:
break;
}
if (!fn || extract32(m4, 0, 3)) {
gen_program_exception(s, PGM_SPECIFICATION);
return DISAS_NORETURN;
}
if (extract32(m4, 3, 1)) {
fn = gen_helper_gvec_vfll32s;
gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, m4, fn);
return DISAS_NEXT;
}
static DisasJumpType op_vfmax(DisasContext *s, DisasOps *o)
{
const uint8_t fpf = get_field(s, m4);
const uint8_t m6 = get_field(s, m6);
const uint8_t m5 = get_field(s, m5);
gen_helper_gvec_3_ptr *fn;
if (m6 == 5 || m6 == 6 || m6 == 7 || m6 > 13) {
gen_program_exception(s, PGM_SPECIFICATION);
return DISAS_NORETURN;
}
gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env,
0, fn);
switch (fpf) {
case FPF_SHORT:
if (s->fields.op2 == 0xef) {
fn = gen_helper_gvec_vfmax32;
} else {
fn = gen_helper_gvec_vfmin32;
}
break;
case FPF_LONG:
if (s->fields.op2 == 0xef) {
fn = gen_helper_gvec_vfmax64;
} else {
fn = gen_helper_gvec_vfmin64;
}
break;
case FPF_EXT:
if (s->fields.op2 == 0xef) {
fn = gen_helper_gvec_vfmax128;
} else {
fn = gen_helper_gvec_vfmin128;
}
break;
default:
gen_program_exception(s, PGM_SPECIFICATION);
return DISAS_NORETURN;
}
gen_gvec_3_ptr(get_field(s, v1), get_field(s, v2), get_field(s, v3),
cpu_env, deposit32(m5, 4, 4, m6), fn);
return DISAS_NEXT;
}
@ -2607,22 +2862,88 @@ static DisasJumpType op_vfma(DisasContext *s, DisasOps *o)
{
const uint8_t m5 = get_field(s, m5);
const uint8_t fpf = get_field(s, m6);
const bool se = extract32(m5, 3, 1);
gen_helper_gvec_4_ptr *fn;
gen_helper_gvec_4_ptr *fn = NULL;
if (fpf != FPF_LONG || extract32(m5, 0, 3)) {
switch (s->fields.op2) {
case 0x8f:
switch (fpf) {
case FPF_SHORT:
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
fn = gen_helper_gvec_vfma32;
}
break;
case FPF_LONG:
fn = gen_helper_gvec_vfma64;
break;
case FPF_EXT:
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
fn = gen_helper_gvec_vfma128;
}
break;
default:
break;
}
break;
case 0x8e:
switch (fpf) {
case FPF_SHORT:
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
fn = gen_helper_gvec_vfms32;
}
break;
case FPF_LONG:
fn = gen_helper_gvec_vfms64;
break;
case FPF_EXT:
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
fn = gen_helper_gvec_vfms128;
}
break;
default:
break;
}
break;
case 0x9f:
switch (fpf) {
case FPF_SHORT:
fn = gen_helper_gvec_vfnma32;
break;
case FPF_LONG:
fn = gen_helper_gvec_vfnma64;
break;
case FPF_EXT:
fn = gen_helper_gvec_vfnma128;
break;
default:
break;
}
break;
case 0x9e:
switch (fpf) {
case FPF_SHORT:
fn = gen_helper_gvec_vfnms32;
break;
case FPF_LONG:
fn = gen_helper_gvec_vfnms64;
break;
case FPF_EXT:
fn = gen_helper_gvec_vfnms128;
break;
default:
break;
}
break;
default:
g_assert_not_reached();
}
if (!fn || extract32(m5, 0, 3)) {
gen_program_exception(s, PGM_SPECIFICATION);
return DISAS_NORETURN;
}
if (s->fields.op2 == 0x8f) {
fn = se ? gen_helper_gvec_vfma64s : gen_helper_gvec_vfma64;
} else {
fn = se ? gen_helper_gvec_vfms64s : gen_helper_gvec_vfms64;
}
gen_gvec_4_ptr(get_field(s, v1), get_field(s, v2),
get_field(s, v3), get_field(s, v4), cpu_env,
0, fn);
get_field(s, v3), get_field(s, v4), cpu_env, m5, fn);
return DISAS_NEXT;
}
@ -2633,48 +2954,88 @@ static DisasJumpType op_vfpso(DisasContext *s, DisasOps *o)
const uint8_t fpf = get_field(s, m3);
const uint8_t m4 = get_field(s, m4);
const uint8_t m5 = get_field(s, m5);
const bool se = extract32(m4, 3, 1);
TCGv_i64 tmp;
if (fpf != FPF_LONG || extract32(m4, 0, 3) || m5 > 2) {
if ((fpf != FPF_LONG && !s390_has_feat(S390_FEAT_VECTOR_ENH)) ||
extract32(m4, 0, 3) || m5 > 2) {
gen_program_exception(s, PGM_SPECIFICATION);
return DISAS_NORETURN;
}
if (extract32(m4, 3, 1)) {
tmp = tcg_temp_new_i64();
read_vec_element_i64(tmp, v2, 0, ES_64);
switch (m5) {
case 0:
/* sign bit is inverted (complement) */
tcg_gen_xori_i64(tmp, tmp, 1ull << 63);
break;
case 1:
/* sign bit is set to one (negative) */
tcg_gen_ori_i64(tmp, tmp, 1ull << 63);
break;
case 2:
/* sign bit is set to zero (positive) */
tcg_gen_andi_i64(tmp, tmp, (1ull << 63) - 1);
break;
switch (fpf) {
case FPF_SHORT:
if (!se) {
switch (m5) {
case 0:
/* sign bit is inverted (complement) */
gen_gvec_fn_2i(xori, ES_32, v1, v2, 1ull << 31);
break;
case 1:
/* sign bit is set to one (negative) */
gen_gvec_fn_2i(ori, ES_32, v1, v2, 1ull << 31);
break;
case 2:
/* sign bit is set to zero (positive) */
gen_gvec_fn_2i(andi, ES_32, v1, v2, (1ull << 31) - 1);
break;
}
return DISAS_NEXT;
}
write_vec_element_i64(tmp, v1, 0, ES_64);
tcg_temp_free_i64(tmp);
} else {
switch (m5) {
case 0:
/* sign bit is inverted (complement) */
gen_gvec_fn_2i(xori, ES_64, v1, v2, 1ull << 63);
break;
case 1:
/* sign bit is set to one (negative) */
gen_gvec_fn_2i(ori, ES_64, v1, v2, 1ull << 63);
break;
case 2:
/* sign bit is set to zero (positive) */
gen_gvec_fn_2i(andi, ES_64, v1, v2, (1ull << 63) - 1);
break;
break;
case FPF_LONG:
if (!se) {
switch (m5) {
case 0:
/* sign bit is inverted (complement) */
gen_gvec_fn_2i(xori, ES_64, v1, v2, 1ull << 63);
break;
case 1:
/* sign bit is set to one (negative) */
gen_gvec_fn_2i(ori, ES_64, v1, v2, 1ull << 63);
break;
case 2:
/* sign bit is set to zero (positive) */
gen_gvec_fn_2i(andi, ES_64, v1, v2, (1ull << 63) - 1);
break;
}
return DISAS_NEXT;
}
break;
case FPF_EXT:
/* Only a single element. */
break;
default:
gen_program_exception(s, PGM_SPECIFICATION);
return DISAS_NORETURN;
}
/* With a single element, we are only interested in bit 0. */
tmp = tcg_temp_new_i64();
read_vec_element_i64(tmp, v2, 0, ES_64);
switch (m5) {
case 0:
/* sign bit is inverted (complement) */
tcg_gen_xori_i64(tmp, tmp, 1ull << 63);
break;
case 1:
/* sign bit is set to one (negative) */
tcg_gen_ori_i64(tmp, tmp, 1ull << 63);
break;
case 2:
/* sign bit is set to zero (positive) */
tcg_gen_andi_i64(tmp, tmp, (1ull << 63) - 1);
break;
}
write_vec_element_i64(tmp, v1, 0, ES_64);
if (fpf == FPF_EXT) {
read_vec_element_i64(tmp, v2, 1, ES_64);
write_vec_element_i64(tmp, v1, 1, ES_64);
}
tcg_temp_free_i64(tmp);
return DISAS_NEXT;
}
@ -2682,18 +3043,32 @@ static DisasJumpType op_vfsq(DisasContext *s, DisasOps *o)
{
const uint8_t fpf = get_field(s, m3);
const uint8_t m4 = get_field(s, m4);
gen_helper_gvec_2_ptr *fn = gen_helper_gvec_vfsq64;
gen_helper_gvec_2_ptr *fn = NULL;
if (fpf != FPF_LONG || extract32(m4, 0, 3)) {
switch (fpf) {
case FPF_SHORT:
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
fn = gen_helper_gvec_vfsq32;
}
break;
case FPF_LONG:
fn = gen_helper_gvec_vfsq64;
break;
case FPF_EXT:
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
fn = gen_helper_gvec_vfsq128;
}
break;
default:
break;
}
if (!fn || extract32(m4, 0, 3)) {
gen_program_exception(s, PGM_SPECIFICATION);
return DISAS_NORETURN;
}
if (extract32(m4, 3, 1)) {
fn = gen_helper_gvec_vfsq64s;
}
gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env,
0, fn);
gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, m4, fn);
return DISAS_NEXT;
}
@ -2702,17 +3077,33 @@ static DisasJumpType op_vftci(DisasContext *s, DisasOps *o)
const uint16_t i3 = get_field(s, i3);
const uint8_t fpf = get_field(s, m4);
const uint8_t m5 = get_field(s, m5);
gen_helper_gvec_2_ptr *fn = gen_helper_gvec_vftci64;
gen_helper_gvec_2_ptr *fn = NULL;
if (fpf != FPF_LONG || extract32(m5, 0, 3)) {
switch (fpf) {
case FPF_SHORT:
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
fn = gen_helper_gvec_vftci32;
}
break;
case FPF_LONG:
fn = gen_helper_gvec_vftci64;
break;
case FPF_EXT:
if (s390_has_feat(S390_FEAT_VECTOR_ENH)) {
fn = gen_helper_gvec_vftci128;
}
break;
default:
break;
}
if (!fn || extract32(m5, 0, 3)) {
gen_program_exception(s, PGM_SPECIFICATION);
return DISAS_NORETURN;
}
if (extract32(m5, 3, 1)) {
fn = gen_helper_gvec_vftci64s;
}
gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env, i3, fn);
gen_gvec_2_ptr(get_field(s, v1), get_field(s, v2), cpu_env,
deposit32(m5, 4, 12, i3), fn);
set_cc_static(s);
return DISAS_NEXT;
}

File diff suppressed because it is too large Load diff

View file

@ -19,6 +19,28 @@
#include "exec/cpu_ldst.h"
#include "exec/exec-all.h"
void HELPER(gvec_vbperm)(void *v1, const void *v2, const void *v3,
uint32_t desc)
{
S390Vector tmp = {};
uint16_t result = 0;
int i;
for (i = 0; i < 16; i++) {
const uint8_t bit_nr = s390_vec_read_element8(v3, i);
uint16_t bit;
if (bit_nr >= 128) {
continue;
}
bit = (s390_vec_read_element8(v2, bit_nr / 8)
>> (7 - (bit_nr % 8))) & 1;
result |= (bit << (15 - i));
}
s390_vec_write_element16(&tmp, 3, result);
*(S390Vector *)v1 = tmp;
}
void HELPER(vll)(CPUS390XState *env, void *v1, uint64_t addr, uint64_t bytes)
{
if (likely(bytes >= 16)) {