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
|
CPU_COMMON
|
||||||
|
|
||||||
uint32_t cpu_num;
|
uint32_t cpu_num;
|
||||||
uint32_t machine_type;
|
uint64_t cpuid;
|
||||||
|
|
||||||
uint64_t tod_offset;
|
uint64_t tod_offset;
|
||||||
uint64_t tod_basetime;
|
uint64_t tod_basetime;
|
||||||
@ -460,11 +460,6 @@ static inline bool get_per_in_range(CPUS390XState *env, uint64_t addr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
#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);
|
void trigger_pgm_exception(CPUS390XState *env, uint32_t code, uint32_t ilen);
|
||||||
#endif
|
#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);
|
int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3);
|
||||||
void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3);
|
void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3);
|
||||||
#endif
|
#endif
|
||||||
|
/* automatically detect the instruction length */
|
||||||
|
#define ILEN_AUTO 0xff
|
||||||
void program_interrupt(CPUS390XState *env, uint32_t code, int ilen);
|
void program_interrupt(CPUS390XState *env, uint32_t code, int ilen);
|
||||||
void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
|
void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
|
||||||
uintptr_t retaddr);
|
uintptr_t retaddr);
|
||||||
|
@ -737,8 +737,6 @@ static inline void apply_cpu_model(const S390CPUModel *model, Error **errp)
|
|||||||
|
|
||||||
if (kvm_enabled()) {
|
if (kvm_enabled()) {
|
||||||
kvm_s390_apply_cpu_model(model, errp);
|
kvm_s390_apply_cpu_model(model, errp);
|
||||||
} else if (model) {
|
|
||||||
/* FIXME TCG - use data for stdip/stfl */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!*errp) {
|
if (!*errp) {
|
||||||
@ -786,6 +784,12 @@ void s390_realize_cpu_model(CPUState *cs, Error **errp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
apply_cpu_model(cpu->model, 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,
|
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) {
|
if (raddr > ram_size) {
|
||||||
DPRINTF("%s: raddr %" PRIx64 " > ram_size %" PRIx64 "\n", __func__,
|
DPRINTF("%s: raddr %" PRIx64 " > ram_size %" PRIx64 "\n", __func__,
|
||||||
(uint64_t)raddr, (uint64_t)ram_size);
|
(uint64_t)raddr, (uint64_t)ram_size);
|
||||||
trigger_pgm_exception(env, PGM_ADDRESSING, ILEN_LATER_INC);
|
trigger_pgm_exception(env, PGM_ADDRESSING, ILEN_AUTO);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,16 +331,42 @@ static void do_program_interrupt(CPUS390XState *env)
|
|||||||
LowCore *lowcore;
|
LowCore *lowcore;
|
||||||
int ilen = env->int_pgm_ilen;
|
int ilen = env->int_pgm_ilen;
|
||||||
|
|
||||||
switch (ilen) {
|
if (ilen == ILEN_AUTO) {
|
||||||
case ILEN_LATER:
|
|
||||||
ilen = get_ilen(cpu_ldub_code(env, env->psw.addr));
|
|
||||||
break;
|
|
||||||
case ILEN_LATER_INC:
|
|
||||||
ilen = get_ilen(cpu_ldub_code(env, env->psw.addr));
|
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;
|
env->psw.addr += ilen;
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
assert(ilen == 2 || ilen == 4 || ilen == 6);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_log_mask(CPU_LOG_INT, "%s: code=0x%x ilen=%d\n",
|
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) {
|
if (retaddr) {
|
||||||
cpu_restore_state(cs, retaddr);
|
cpu_restore_state(cs, retaddr);
|
||||||
}
|
}
|
||||||
program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER);
|
program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO);
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_USER_ONLY */
|
#endif /* CONFIG_USER_ONLY */
|
||||||
|
@ -960,7 +960,7 @@
|
|||||||
/* STORE CPU ADDRESS */
|
/* STORE CPU ADDRESS */
|
||||||
C(0xb212, STAP, S, Z, la2, 0, new, m1_16, stap, 0)
|
C(0xb212, STAP, S, Z, la2, 0, new, m1_16, stap, 0)
|
||||||
/* STORE CPU ID */
|
/* 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 */
|
/* STORE CPU TIMER */
|
||||||
C(0xb209, STPT, S, Z, la2, 0, new, m1_64, stpt, 0)
|
C(0xb209, STPT, S, Z, la2, 0, new, m1_64, stpt, 0)
|
||||||
/* STORE FACILITY LIST */
|
/* STORE FACILITY LIST */
|
||||||
|
@ -54,19 +54,14 @@ void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
|
|||||||
uintptr_t retaddr)
|
uintptr_t retaddr)
|
||||||
{
|
{
|
||||||
CPUState *cs = CPU(s390_env_get_cpu(env));
|
CPUState *cs = CPU(s390_env_get_cpu(env));
|
||||||
int t;
|
|
||||||
|
|
||||||
cs->exception_index = EXCP_PGM;
|
cs->exception_index = EXCP_PGM;
|
||||||
env->int_pgm_code = excp;
|
env->int_pgm_code = excp;
|
||||||
|
env->int_pgm_ilen = ILEN_AUTO;
|
||||||
|
|
||||||
/* Use the (ultimate) callers address to find the insn that trapped. */
|
/* Use the (ultimate) callers address to find the insn that trapped. */
|
||||||
cpu_restore_state(cs, retaddr);
|
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);
|
cpu_loop_exit(cs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,12 +194,12 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3)
|
|||||||
IplParameterBlock *iplb;
|
IplParameterBlock *iplb;
|
||||||
|
|
||||||
if (env->psw.mask & PSW_MASK_PSTATE) {
|
if (env->psw.mask & PSW_MASK_PSTATE) {
|
||||||
program_interrupt(env, PGM_PRIVILEGED, ILEN_LATER_INC);
|
program_interrupt(env, PGM_PRIVILEGED, ILEN_AUTO);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((subcode & ~0x0ffffULL) || (subcode > 6)) {
|
if ((subcode & ~0x0ffffULL) || (subcode > 6)) {
|
||||||
program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
|
program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,12 +224,12 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3)
|
|||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
if ((r1 & 1) || (addr & 0x0fffULL)) {
|
if ((r1 & 1) || (addr & 0x0fffULL)) {
|
||||||
program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
|
program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!address_space_access_valid(&address_space_memory, addr,
|
if (!address_space_access_valid(&address_space_memory, addr,
|
||||||
sizeof(IplParameterBlock), false)) {
|
sizeof(IplParameterBlock), false)) {
|
||||||
program_interrupt(env, PGM_ADDRESSING, ILEN_LATER_INC);
|
program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
iplb = g_malloc0(sizeof(IplParameterBlock));
|
iplb = g_malloc0(sizeof(IplParameterBlock));
|
||||||
@ -258,12 +253,12 @@ out:
|
|||||||
return;
|
return;
|
||||||
case 6:
|
case 6:
|
||||||
if ((r1 & 1) || (addr & 0x0fffULL)) {
|
if ((r1 & 1) || (addr & 0x0fffULL)) {
|
||||||
program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER_INC);
|
program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!address_space_access_valid(&address_space_memory, addr,
|
if (!address_space_access_valid(&address_space_memory, addr,
|
||||||
sizeof(IplParameterBlock), true)) {
|
sizeof(IplParameterBlock), true)) {
|
||||||
program_interrupt(env, PGM_ADDRESSING, ILEN_LATER_INC);
|
program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
iplb = s390_ipl_get_iplb();
|
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) {
|
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,
|
uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0,
|
||||||
uint64_t r0, uint64_t r1)
|
uint64_t r0, uint64_t r1)
|
||||||
{
|
{
|
||||||
|
S390CPU *cpu = s390_env_get_cpu(env);
|
||||||
int cc = 0;
|
int cc = 0;
|
||||||
int sel1, sel2;
|
int sel1, sel2;
|
||||||
|
|
||||||
@ -402,12 +398,14 @@ uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0,
|
|||||||
if ((sel1 == 1) && (sel2 == 1)) {
|
if ((sel1 == 1) && (sel2 == 1)) {
|
||||||
/* Basic Machine Configuration */
|
/* Basic Machine Configuration */
|
||||||
struct sysib_111 sysib;
|
struct sysib_111 sysib;
|
||||||
|
char type[5] = {};
|
||||||
|
|
||||||
memset(&sysib, 0, sizeof(sysib));
|
memset(&sysib, 0, sizeof(sysib));
|
||||||
ebcdic_put(sysib.manuf, "QEMU ", 16);
|
ebcdic_put(sysib.manuf, "QEMU ", 16);
|
||||||
/* same as machine type number in STORE CPU ID */
|
/* same as machine type number in STORE CPU ID, but in EBCDIC */
|
||||||
ebcdic_put(sysib.type, "QEMU", 4);
|
snprintf(type, ARRAY_SIZE(type), "%X", cpu->model->def->type);
|
||||||
/* same as model number in STORE CPU ID */
|
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.model, "QEMU ", 16);
|
||||||
ebcdic_put(sysib.sequence, "QEMU ", 16);
|
ebcdic_put(sysib.sequence, "QEMU ", 16);
|
||||||
ebcdic_put(sysib.plant, "QEMU", 4);
|
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) {
|
if (env->cregs[9] & PER_CR9_EVENT_NULLIFICATION) {
|
||||||
CPUState *cs = CPU(s390_env_get_cpu(env));
|
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_code = PGM_PER;
|
||||||
env->int_pgm_ilen = get_ilen(cpu_ldub_code(env, addr));
|
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;
|
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,
|
static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr,
|
||||||
uint32_t type, uint64_t asc, int rw, bool exc)
|
uint32_t type, uint64_t asc, int rw, bool exc)
|
||||||
{
|
{
|
||||||
int ilen = ILEN_LATER;
|
int ilen = ILEN_AUTO;
|
||||||
uint64_t tec;
|
uint64_t tec;
|
||||||
|
|
||||||
tec = vaddr | (rw == MMU_DATA_STORE ? FS_WRITE : FS_READ) | asc >> 46;
|
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++) {
|
for (i = 0; i < nr_pages; i++) {
|
||||||
/* Low-address protection? */
|
/* Low-address protection? */
|
||||||
if (lowprot && (addr < 512 || (addr >= 4096 && addr < 4096 + 512))) {
|
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;
|
return -EACCES;
|
||||||
}
|
}
|
||||||
ret = mmu_translate(env, addr, is_write, asc, &pages[i], &pflags, true);
|
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_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_ilen));
|
||||||
tcg_temp_free_i32(tmp);
|
tcg_temp_free_i32(tmp);
|
||||||
|
|
||||||
/* Advance past instruction. */
|
/* update the psw */
|
||||||
s->pc = s->next_pc;
|
|
||||||
update_psw_addr(s);
|
update_psw_addr(s);
|
||||||
|
|
||||||
/* Save off cc. */
|
/* Save off cc. */
|
||||||
@ -3877,14 +3876,9 @@ static ExitStatus op_stctl(DisasContext *s, DisasOps *o)
|
|||||||
|
|
||||||
static ExitStatus op_stidp(DisasContext *s, DisasOps *o)
|
static ExitStatus op_stidp(DisasContext *s, DisasOps *o)
|
||||||
{
|
{
|
||||||
TCGv_i64 t1 = tcg_temp_new_i64();
|
|
||||||
|
|
||||||
check_privileged(s);
|
check_privileged(s);
|
||||||
tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, cpu_num));
|
tcg_gen_ld_i64(o->out, cpu_env, offsetof(CPUS390XState, cpuid));
|
||||||
tcg_gen_ld32u_i64(t1, cpu_env, offsetof(CPUS390XState, machine_type));
|
tcg_gen_qemu_st_i64(o->out, o->addr1, get_mem_index(s), MO_TEQ | MO_ALIGN);
|
||||||
tcg_gen_deposit_i64(o->out, o->out, t1, 32, 32);
|
|
||||||
tcg_temp_free_i64(t1);
|
|
||||||
|
|
||||||
return NO_EXIT;
|
return NO_EXIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user