mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
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:
@@ -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."
|
||||
|
||||
@@ -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) {
|
||||
|
||||
+63
-24
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
+15
-13
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+2
-13
@@ -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;
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
|
||||
+55
-46
@@ -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++) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user