Queued s390 patches
-----BEGIN PGP SIGNATURE----- iQEcBAABAgAGBQJZQEmRAAoJEK0ScMxN0Cebl2QH/2RdrNvNkSf4ggozhhHt1Eob f2EsC56eQsPz2+87gaPDumcWUFsxmvyUbZyKCoA0+90V7Ylb/Z9qLOdQdTCtQJtx y3xktII+52T8xTusqLuAfUQw8wG7eVblMzBurBPI16ptWWtrlecrvyWvlBMOard9 pMFKUkhGfO3leWYUBsVujV71bHf+blnLQAgKIgmbD+Qlkao1YxcyS3WHyV7nNSDp L5HaR/i0aDG1niDE960GpOT+Ku8CA/UJSubfM8Vge3ollsupDf7798wJr+yqd3Mj inwiOWoCf7Vsz7x78lKaMxn1+Fj3BQLI4FUN3mB+9Gky6S3BGjNNsWhB0Z5yzK8= =KANG -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/rth/tags/pull-s390-20170613' into staging Queued s390 patches # gpg: Signature made Tue 13 Jun 2017 21:22:41 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-20170613: s390x/cpumodel: wire up cpu type + id for TCG target/s390x: rework PGM interrupt psw.addr handling target/s390x: correctly indicate PER nullification Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
edf8bc9842
|
@ -149,7 +149,7 @@ typedef struct CPUS390XState {
|
|||
CPU_COMMON
|
||||
|
||||
uint32_t cpu_num;
|
||||
uint32_t machine_type;
|
||||
uint64_t cpuid;
|
||||
|
||||
uint64_t tod_offset;
|
||||
uint64_t tod_basetime;
|
||||
|
@ -460,11 +460,6 @@ static inline bool get_per_in_range(CPUS390XState *env, uint64_t addr)
|
|||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
/* In several cases of runtime exceptions, we havn't recorded the true
|
||||
instruction length. Use these codes when raising exceptions in order
|
||||
to re-compute the length by examining the insn in memory. */
|
||||
#define ILEN_LATER 0x20
|
||||
#define ILEN_LATER_INC 0x21
|
||||
void trigger_pgm_exception(CPUS390XState *env, uint32_t code, uint32_t ilen);
|
||||
#endif
|
||||
|
||||
|
@ -1133,6 +1128,8 @@ uint32_t set_cc_nz_f128(float128 v);
|
|||
int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3);
|
||||
void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3);
|
||||
#endif
|
||||
/* automatically detect the instruction length */
|
||||
#define ILEN_AUTO 0xff
|
||||
void program_interrupt(CPUS390XState *env, uint32_t code, int ilen);
|
||||
void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
|
||||
uintptr_t retaddr);
|
||||
|
|
|
@ -737,8 +737,6 @@ static inline void apply_cpu_model(const S390CPUModel *model, Error **errp)
|
|||
|
||||
if (kvm_enabled()) {
|
||||
kvm_s390_apply_cpu_model(model, errp);
|
||||
} else if (model) {
|
||||
/* FIXME TCG - use data for stdip/stfl */
|
||||
}
|
||||
|
||||
if (!*errp) {
|
||||
|
@ -786,6 +784,12 @@ void s390_realize_cpu_model(CPUState *cs, Error **errp)
|
|||
}
|
||||
|
||||
apply_cpu_model(cpu->model, errp);
|
||||
|
||||
cpu->env.cpuid = s390_cpuid_from_cpu_model(cpu->model);
|
||||
if (tcg_enabled()) {
|
||||
/* basic mode, write the cpu address into the first 4 bit of the ID */
|
||||
cpu->env.cpuid = deposit64(cpu->env.cpuid, 54, 4, cpu->env.cpu_num);
|
||||
}
|
||||
}
|
||||
|
||||
static void get_feature(Object *obj, Visitor *v, const char *name,
|
||||
|
|
|
@ -204,7 +204,7 @@ int s390_cpu_handle_mmu_fault(CPUState *cs, vaddr orig_vaddr,
|
|||
if (raddr > ram_size) {
|
||||
DPRINTF("%s: raddr %" PRIx64 " > ram_size %" PRIx64 "\n", __func__,
|
||||
(uint64_t)raddr, (uint64_t)ram_size);
|
||||
trigger_pgm_exception(env, PGM_ADDRESSING, ILEN_LATER_INC);
|
||||
trigger_pgm_exception(env, PGM_ADDRESSING, ILEN_AUTO);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -331,16 +331,42 @@ static void do_program_interrupt(CPUS390XState *env)
|
|||
LowCore *lowcore;
|
||||
int ilen = env->int_pgm_ilen;
|
||||
|
||||
switch (ilen) {
|
||||
case ILEN_LATER:
|
||||
ilen = get_ilen(cpu_ldub_code(env, env->psw.addr));
|
||||
break;
|
||||
case ILEN_LATER_INC:
|
||||
if (ilen == ILEN_AUTO) {
|
||||
ilen = get_ilen(cpu_ldub_code(env, env->psw.addr));
|
||||
}
|
||||
assert(ilen == 2 || ilen == 4 || ilen == 6);
|
||||
|
||||
switch (env->int_pgm_code) {
|
||||
case PGM_PER:
|
||||
if (env->per_perc_atmid & PER_CODE_EVENT_NULLIFICATION) {
|
||||
break;
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
case PGM_OPERATION:
|
||||
case PGM_PRIVILEGED:
|
||||
case PGM_EXECUTE:
|
||||
case PGM_PROTECTION:
|
||||
case PGM_ADDRESSING:
|
||||
case PGM_SPECIFICATION:
|
||||
case PGM_DATA:
|
||||
case PGM_FIXPT_OVERFLOW:
|
||||
case PGM_FIXPT_DIVIDE:
|
||||
case PGM_DEC_OVERFLOW:
|
||||
case PGM_DEC_DIVIDE:
|
||||
case PGM_HFP_EXP_OVERFLOW:
|
||||
case PGM_HFP_EXP_UNDERFLOW:
|
||||
case PGM_HFP_SIGNIFICANCE:
|
||||
case PGM_HFP_DIVIDE:
|
||||
case PGM_TRANS_SPEC:
|
||||
case PGM_SPECIAL_OP:
|
||||
case PGM_OPERAND:
|
||||
case PGM_HFP_SQRT:
|
||||
case PGM_PC_TRANS_SPEC:
|
||||
case PGM_ALET_SPEC:
|
||||
case PGM_MONITOR:
|
||||
/* advance the PSW if our exception is not nullifying */
|
||||
env->psw.addr += ilen;
|
||||
break;
|
||||
default:
|
||||
assert(ilen == 2 || ilen == 4 || ilen == 6);
|
||||
}
|
||||
|
||||
qemu_log_mask(CPU_LOG_INT, "%s: code=0x%x ilen=%d\n",
|
||||
|
@ -737,6 +763,6 @@ void s390x_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
|
|||
if (retaddr) {
|
||||
cpu_restore_state(cs, retaddr);
|
||||
}
|
||||
program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER);
|
||||
program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO);
|
||||
}
|
||||
#endif /* CONFIG_USER_ONLY */
|
||||
|
|
|
@ -960,7 +960,7 @@
|
|||
/* STORE CPU ADDRESS */
|
||||
C(0xb212, STAP, S, Z, la2, 0, new, m1_16, stap, 0)
|
||||
/* STORE CPU ID */
|
||||
C(0xb202, STIDP, S, Z, la2, 0, new, m1_64, stidp, 0)
|
||||
C(0xb202, STIDP, S, Z, la2, 0, new, 0, stidp, 0)
|
||||
/* STORE CPU TIMER */
|
||||
C(0xb209, STPT, S, Z, la2, 0, new, m1_64, stpt, 0)
|
||||
/* STORE FACILITY LIST */
|
||||
|
|
|
@ -54,19 +54,14 @@ void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
|
|||
uintptr_t retaddr)
|
||||
{
|
||||
CPUState *cs = CPU(s390_env_get_cpu(env));
|
||||
int t;
|
||||
|
||||
cs->exception_index = EXCP_PGM;
|
||||
env->int_pgm_code = excp;
|
||||
env->int_pgm_ilen = ILEN_AUTO;
|
||||
|
||||
/* Use the (ultimate) callers address to find the insn that trapped. */
|
||||
cpu_restore_state(cs, retaddr);
|
||||
|
||||
/* Advance past the insn. */
|
||||
t = cpu_ldub_code(env, env->psw.addr);
|
||||
env->int_pgm_ilen = t = get_ilen(t);
|
||||
env->psw.addr += t;
|
||||
|
||||
cpu_loop_exit(cs);
|
||||
}
|
||||
|
||||
|
@ -199,12 +194,12 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3)
|
|||
IplParameterBlock *iplb;
|
||||
|
||||
if (env->psw.mask & PSW_MASK_PSTATE) {
|
||||
program_interrupt(env, PGM_PRIVILEGED, ILEN_LATER_INC);
|
||||
program_interrupt(env, PGM_PRIVILEGED, ILEN_AUTO);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((subcode & ~0x0ffffULL) || (subcode > 6)) {
|
||||
program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
|
||||
program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -229,12 +224,12 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3)
|
|||
break;
|
||||
case 5:
|
||||
if ((r1 & 1) || (addr & 0x0fffULL)) {
|
||||
program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
|
||||
program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO);
|
||||
return;
|
||||
}
|
||||
if (!address_space_access_valid(&address_space_memory, addr,
|
||||
sizeof(IplParameterBlock), false)) {
|
||||
program_interrupt(env, PGM_ADDRESSING, ILEN_LATER_INC);
|
||||
program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO);
|
||||
return;
|
||||
}
|
||||
iplb = g_malloc0(sizeof(IplParameterBlock));
|
||||
|
@ -258,12 +253,12 @@ out:
|
|||
return;
|
||||
case 6:
|
||||
if ((r1 & 1) || (addr & 0x0fffULL)) {
|
||||
program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
|
||||
program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO);
|
||||
return;
|
||||
}
|
||||
if (!address_space_access_valid(&address_space_memory, addr,
|
||||
sizeof(IplParameterBlock), true)) {
|
||||
program_interrupt(env, PGM_ADDRESSING, ILEN_LATER_INC);
|
||||
program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO);
|
||||
return;
|
||||
}
|
||||
iplb = s390_ipl_get_iplb();
|
||||
|
@ -307,7 +302,7 @@ void HELPER(diag)(CPUS390XState *env, uint32_t r1, uint32_t r3, uint32_t num)
|
|||
}
|
||||
|
||||
if (r) {
|
||||
program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC);
|
||||
program_interrupt(env, PGM_OPERATION, ILEN_AUTO);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -383,6 +378,7 @@ uint64_t HELPER(stpt)(CPUS390XState *env)
|
|||
uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0,
|
||||
uint64_t r0, uint64_t r1)
|
||||
{
|
||||
S390CPU *cpu = s390_env_get_cpu(env);
|
||||
int cc = 0;
|
||||
int sel1, sel2;
|
||||
|
||||
|
@ -402,12 +398,14 @@ uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0,
|
|||
if ((sel1 == 1) && (sel2 == 1)) {
|
||||
/* Basic Machine Configuration */
|
||||
struct sysib_111 sysib;
|
||||
char type[5] = {};
|
||||
|
||||
memset(&sysib, 0, sizeof(sysib));
|
||||
ebcdic_put(sysib.manuf, "QEMU ", 16);
|
||||
/* same as machine type number in STORE CPU ID */
|
||||
ebcdic_put(sysib.type, "QEMU", 4);
|
||||
/* same as model number in STORE CPU ID */
|
||||
/* same as machine type number in STORE CPU ID, but in EBCDIC */
|
||||
snprintf(type, ARRAY_SIZE(type), "%X", cpu->model->def->type);
|
||||
ebcdic_put(sysib.type, type, 4);
|
||||
/* model number (not stored in STORE CPU ID for z/Architecure) */
|
||||
ebcdic_put(sysib.model, "QEMU ", 16);
|
||||
ebcdic_put(sysib.sequence, "QEMU ", 16);
|
||||
ebcdic_put(sysib.plant, "QEMU", 4);
|
||||
|
@ -668,6 +666,7 @@ void HELPER(per_ifetch)(CPUS390XState *env, uint64_t addr)
|
|||
if (env->cregs[9] & PER_CR9_EVENT_NULLIFICATION) {
|
||||
CPUState *cs = CPU(s390_env_get_cpu(env));
|
||||
|
||||
env->per_perc_atmid |= PER_CODE_EVENT_NULLIFICATION;
|
||||
env->int_pgm_code = PGM_PER;
|
||||
env->int_pgm_ilen = get_ilen(cpu_ldub_code(env, addr));
|
||||
|
||||
|
|
|
@ -79,13 +79,13 @@ static void trigger_prot_fault(CPUS390XState *env, target_ulong vaddr,
|
|||
return;
|
||||
}
|
||||
|
||||
trigger_access_exception(env, PGM_PROTECTION, ILEN_LATER_INC, tec);
|
||||
trigger_access_exception(env, PGM_PROTECTION, ILEN_AUTO, tec);
|
||||
}
|
||||
|
||||
static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr,
|
||||
uint32_t type, uint64_t asc, int rw, bool exc)
|
||||
{
|
||||
int ilen = ILEN_LATER;
|
||||
int ilen = ILEN_AUTO;
|
||||
uint64_t tec;
|
||||
|
||||
tec = vaddr | (rw == MMU_DATA_STORE ? FS_WRITE : FS_READ) | asc >> 46;
|
||||
|
@ -431,7 +431,7 @@ static int translate_pages(S390CPU *cpu, vaddr addr, int nr_pages,
|
|||
for (i = 0; i < nr_pages; i++) {
|
||||
/* Low-address protection? */
|
||||
if (lowprot && (addr < 512 || (addr >= 4096 && addr < 4096 + 512))) {
|
||||
trigger_access_exception(env, PGM_PROTECTION, ILEN_LATER_INC, 0);
|
||||
trigger_access_exception(env, PGM_PROTECTION, ILEN_AUTO, 0);
|
||||
return -EACCES;
|
||||
}
|
||||
ret = mmu_translate(env, addr, is_write, asc, &pages[i], &pflags, true);
|
||||
|
|
|
@ -355,8 +355,7 @@ static void gen_program_exception(DisasContext *s, int code)
|
|||
tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_ilen));
|
||||
tcg_temp_free_i32(tmp);
|
||||
|
||||
/* Advance past instruction. */
|
||||
s->pc = s->next_pc;
|
||||
/* update the psw */
|
||||
update_psw_addr(s);
|
||||
|
||||
/* Save off cc. */
|
||||
|
@ -3877,14 +3876,9 @@ static ExitStatus op_stctl(DisasContext *s, DisasOps *o)
|
|||
|
||||
static ExitStatus op_stidp(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
TCGv_i64 t1 = tcg_temp_new_i64();
|
||||
|
||||
check_privileged(s);
|
||||
tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, cpu_num));
|
||||
tcg_gen_ld32u_i64(t1, cpu_env, offsetof(CPUS390XState, machine_type));
|
||||
tcg_gen_deposit_i64(o->out, o->out, t1, 32, 32);
|
||||
tcg_temp_free_i64(t1);
|
||||
|
||||
tcg_gen_ld_i64(o->out, cpu_env, offsetof(CPUS390XState, cpuid));
|
||||
tcg_gen_qemu_st_i64(o->out, o->addr1, get_mem_index(s), MO_TEQ | MO_ALIGN);
|
||||
return NO_EXIT;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue