提交 edf8bc98 编写于 作者: P Peter Maydell

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: NPeter Maydell <peter.maydell@linaro.org>
...@@ -149,7 +149,7 @@ typedef struct CPUS390XState { ...@@ -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) ...@@ -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); ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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 @@ ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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: ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册