diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2015-06-17 12:43:26 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2015-06-17 12:43:26 +0100 |
commit | f754c3c9cce3c4789733d9068394be4256dfe6a8 (patch) | |
tree | d3052dae9462cb7ed58b1aca1b3aecb84f115c35 /target-s390x/helper.c | |
parent | a09f4a9d19c500ea5cbcdc0bd7f0d540cf54f9f5 (diff) | |
parent | 1f68f1d36c3af09ed31a529ad69c3d09880d10fd (diff) |
Merge remote-tracking branch 'remotes/agraf/tags/signed-s390-for-upstream' into staging
Patch queue for s390 - 2015-06-17
This is a special one. Two awesome features in one pull request:
- CCW support for TCG
- Watchpoint support for TCG
To celebrate this, we also switch the default machine model from s390-virtio
to s390-ccw and give users a fully working s390x model again!
# gpg: Signature made Wed Jun 17 11:42:26 2015 BST using RSA key ID 03FEDC60
# gpg: Good signature from "Alexander Graf <agraf@suse.de>"
# gpg: aka "Alexander Graf <alex@csgraf.de>"
* remotes/agraf/tags/signed-s390-for-upstream: (26 commits)
s390x: Switch to s390-ccw machine as default
target-s390x: PER: add Breaking-Event-Address register
target-s390x: PER instruction-fetch nullification event support
target-s390x: PER store-using-real-address event support
target-s390x: PER storage-alteration event support
translate-all: fix watchpoints if retranslation not possible
target-s390x: PER instruction-fetch event support
target-s390x: PER successful-branching event support
target-s390x: basic PER event handling
target-s390x: add get_per_in_range function
target-s390x: add get_per_atmid function
target-s390x: add PER related constants
target-s390x: mvc_fast_memmove: access memory through softmmu
target-s390x: mvc_fast_memset: access memory through softmmu
target-s390x: function to adjust the length wrt page boundary
softmmu: provide tlb_vaddr_to_host function for user mode
target-s390x: wire up I/O instructions in TCG mode
target-s390x: wire up DIAG REIPL in TCG mode
target-s390x: wire up DIAG IPL in TCG mode
target-s390x: fix s390_cpu_initial_reset
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target-s390x/helper.c')
-rw-r--r-- | target-s390x/helper.c | 130 |
1 files changed, 111 insertions, 19 deletions
diff --git a/target-s390x/helper.c b/target-s390x/helper.c index 90d273c098..d88700695e 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -181,12 +181,18 @@ hwaddr s390_cpu_get_phys_addr_debug(CPUState *cs, vaddr vaddr) 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; if (tcg_enabled()) { env->cc_op = (mask >> 44) & 3; } + if ((old_mask ^ mask) & PSW_MASK_PER) { + s390_cpu_recompute_watchpoints(CPU(s390_env_get_cpu(env))); + } + if (mask & PSW_MASK_WAIT) { S390CPU *cpu = s390_env_get_cpu(env); if (s390_cpu_halt(cpu) == 0) { @@ -250,25 +256,6 @@ void do_restart_interrupt(CPUS390XState *env) load_psw(env, mask, addr); } -static void do_svc_interrupt(CPUS390XState *env) -{ - uint64_t mask, addr; - LowCore *lowcore; - - lowcore = cpu_map_lowcore(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.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); -} - static void do_program_interrupt(CPUS390XState *env) { uint64_t mask, addr; @@ -292,12 +279,21 @@ static void do_program_interrupt(CPUS390XState *env) lowcore = cpu_map_lowcore(env); + /* Signal PER events with the exception. */ + if (env->per_perc_atmid) { + env->int_pgm_code |= PGM_PER; + lowcore->per_address = cpu_to_be64(env->per_address); + lowcore->per_perc_atmid = cpu_to_be16(env->per_perc_atmid); + env->per_perc_atmid = 0; + } + 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.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); + lowcore->per_breaking_event_addr = cpu_to_be64(env->gbea); cpu_unmap_lowcore(lowcore); @@ -308,6 +304,33 @@ static void do_program_interrupt(CPUS390XState *env) load_psw(env, mask, addr); } +static void do_svc_interrupt(CPUS390XState *env) +{ + uint64_t mask, addr; + LowCore *lowcore; + + lowcore = cpu_map_lowcore(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.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); + + /* When a PER event is pending, the PER exception has to happen + immediately after the SERVICE CALL one. */ + if (env->per_perc_atmid) { + env->int_pgm_code = PGM_PER; + env->int_pgm_ilen = env->int_svc_ilen; + do_program_interrupt(env); + } +} + #define VIRTIO_SUBCODE_64 0x0D00 static void do_ext_interrupt(CPUS390XState *env) @@ -557,4 +580,73 @@ bool s390_cpu_exec_interrupt(CPUState *cs, int interrupt_request) } return false; } + +void s390_cpu_recompute_watchpoints(CPUState *cs) +{ + const int wp_flags = BP_CPU | BP_MEM_WRITE | BP_STOP_BEFORE_ACCESS; + S390CPU *cpu = S390_CPU(cs); + CPUS390XState *env = &cpu->env; + + /* We are called when the watchpoints have changed. First + remove them all. */ + cpu_watchpoint_remove_all(cs, BP_CPU); + + /* Return if PER is not enabled */ + if (!(env->psw.mask & PSW_MASK_PER)) { + return; + } + + /* Return if storage-alteration event is not enabled. */ + if (!(env->cregs[9] & PER_CR9_EVENT_STORE)) { + return; + } + + if (env->cregs[10] == 0 && env->cregs[11] == -1LL) { + /* We can't create a watchoint spanning the whole memory range, so + split it in two parts. */ + cpu_watchpoint_insert(cs, 0, 1ULL << 63, wp_flags, NULL); + cpu_watchpoint_insert(cs, 1ULL << 63, 1ULL << 63, wp_flags, NULL); + } else if (env->cregs[10] > env->cregs[11]) { + /* The address range loops, create two watchpoints. */ + cpu_watchpoint_insert(cs, env->cregs[10], -env->cregs[10], + wp_flags, NULL); + cpu_watchpoint_insert(cs, 0, env->cregs[11] + 1, wp_flags, NULL); + + } else { + /* Default case, create a single watchpoint. */ + cpu_watchpoint_insert(cs, env->cregs[10], + env->cregs[11] - env->cregs[10] + 1, + wp_flags, NULL); + } +} + +void s390x_cpu_debug_excp_handler(CPUState *cs) +{ + S390CPU *cpu = S390_CPU(cs); + CPUS390XState *env = &cpu->env; + CPUWatchpoint *wp_hit = cs->watchpoint_hit; + + if (wp_hit && wp_hit->flags & BP_CPU) { + /* FIXME: When the storage-alteration-space control bit is set, + the exception should only be triggered if the memory access + is done using an address space with the storage-alteration-event + bit set. We have no way to detect that with the current + watchpoint code. */ + cs->watchpoint_hit = NULL; + + env->per_address = env->psw.addr; + env->per_perc_atmid |= PER_CODE_EVENT_STORE | get_per_atmid(env); + /* FIXME: We currently no way to detect the address space used + to trigger the watchpoint. For now just consider it is the + current default ASC. This turn to be true except when MVCP + 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. */ + cpu_watchpoint_remove_all(cs, BP_CPU); + cpu_resume_from_signal(cs, NULL); + } +} #endif /* CONFIG_USER_ONLY */ |