]> Git Repo - qemu.git/blob - target/s390x/excp_helper.c
Merge remote-tracking branch 'remotes/rth/tags/pull-tcg-20191013' into staging
[qemu.git] / target / s390x / excp_helper.c
1 /*
2  * s390x exception / interrupt helpers
3  *
4  *  Copyright (c) 2009 Ulrich Hecht
5  *  Copyright (c) 2011 Alexander Graf
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "qemu/osdep.h"
22 #include "cpu.h"
23 #include "internal.h"
24 #include "exec/helper-proto.h"
25 #include "qemu/timer.h"
26 #include "exec/exec-all.h"
27 #include "exec/cpu_ldst.h"
28 #include "hw/s390x/ioinst.h"
29 #include "exec/address-spaces.h"
30 #include "tcg_s390x.h"
31 #ifndef CONFIG_USER_ONLY
32 #include "sysemu/sysemu.h"
33 #include "hw/s390x/s390_flic.h"
34 #include "hw/boards.h"
35 #endif
36
37 void QEMU_NORETURN tcg_s390_program_interrupt(CPUS390XState *env,
38                                               uint32_t code, uintptr_t ra)
39 {
40     CPUState *cs = env_cpu(env);
41
42     cpu_restore_state(cs, ra, true);
43     qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
44                   env->psw.addr);
45     trigger_pgm_exception(env, code);
46     cpu_loop_exit(cs);
47 }
48
49 void QEMU_NORETURN tcg_s390_data_exception(CPUS390XState *env, uint32_t dxc,
50                                            uintptr_t ra)
51 {
52     g_assert(dxc <= 0xff);
53 #if !defined(CONFIG_USER_ONLY)
54     /* Store the DXC into the lowcore */
55     stl_phys(env_cpu(env)->as,
56              env->psa + offsetof(LowCore, data_exc_code), dxc);
57 #endif
58
59     /* Store the DXC into the FPC if AFP is enabled */
60     if (env->cregs[0] & CR0_AFP) {
61         env->fpc = deposit32(env->fpc, 8, 8, dxc);
62     }
63     tcg_s390_program_interrupt(env, PGM_DATA, ra);
64 }
65
66 void QEMU_NORETURN tcg_s390_vector_exception(CPUS390XState *env, uint32_t vxc,
67                                              uintptr_t ra)
68 {
69     g_assert(vxc <= 0xff);
70 #if !defined(CONFIG_USER_ONLY)
71     /* Always store the VXC into the lowcore, without AFP it is undefined */
72     stl_phys(env_cpu(env)->as,
73              env->psa + offsetof(LowCore, data_exc_code), vxc);
74 #endif
75
76     /* Always store the VXC into the FPC, without AFP it is undefined */
77     env->fpc = deposit32(env->fpc, 8, 8, vxc);
78     tcg_s390_program_interrupt(env, PGM_VECTOR_PROCESSING, ra);
79 }
80
81 void HELPER(data_exception)(CPUS390XState *env, uint32_t dxc)
82 {
83     tcg_s390_data_exception(env, dxc, GETPC());
84 }
85
86 #if defined(CONFIG_USER_ONLY)
87
88 void s390_cpu_do_interrupt(CPUState *cs)
89 {
90     cs->exception_index = -1;
91 }
92
93 bool s390_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
94                        MMUAccessType access_type, int mmu_idx,
95                        bool probe, uintptr_t retaddr)
96 {
97     S390CPU *cpu = S390_CPU(cs);
98
99     trigger_pgm_exception(&cpu->env, PGM_ADDRESSING);
100     /* On real machines this value is dropped into LowMem.  Since this
101        is userland, simply put this someplace that cpu_loop can find it.  */
102     cpu->env.__excp_addr = address;
103     cpu_loop_exit_restore(cs, retaddr);
104 }
105
106 #else /* !CONFIG_USER_ONLY */
107
108 static inline uint64_t cpu_mmu_idx_to_asc(int mmu_idx)
109 {
110     switch (mmu_idx) {
111     case MMU_PRIMARY_IDX:
112         return PSW_ASC_PRIMARY;
113     case MMU_SECONDARY_IDX:
114         return PSW_ASC_SECONDARY;
115     case MMU_HOME_IDX:
116         return PSW_ASC_HOME;
117     default:
118         abort();
119     }
120 }
121
122 bool s390_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
123                        MMUAccessType access_type, int mmu_idx,
124                        bool probe, uintptr_t retaddr)
125 {
126     S390CPU *cpu = S390_CPU(cs);
127     CPUS390XState *env = &cpu->env;
128     target_ulong vaddr, raddr;
129     uint64_t asc, tec;
130     int prot, excp;
131
132     qemu_log_mask(CPU_LOG_MMU, "%s: addr 0x%" VADDR_PRIx " rw %d mmu_idx %d\n",
133                   __func__, address, access_type, mmu_idx);
134
135     vaddr = address;
136
137     if (mmu_idx < MMU_REAL_IDX) {
138         asc = cpu_mmu_idx_to_asc(mmu_idx);
139         /* 31-Bit mode */
140         if (!(env->psw.mask & PSW_MASK_64)) {
141             vaddr &= 0x7fffffff;
142         }
143         excp = mmu_translate(env, vaddr, access_type, asc, &raddr, &prot, &tec);
144     } else if (mmu_idx == MMU_REAL_IDX) {
145         /* 31-Bit mode */
146         if (!(env->psw.mask & PSW_MASK_64)) {
147             vaddr &= 0x7fffffff;
148         }
149         excp = mmu_translate_real(env, vaddr, access_type, &raddr, &prot, &tec);
150     } else {
151         g_assert_not_reached();
152     }
153
154     /* check out of RAM access */
155     if (!excp &&
156         !address_space_access_valid(&address_space_memory, raddr,
157                                     TARGET_PAGE_SIZE, access_type,
158                                     MEMTXATTRS_UNSPECIFIED)) {
159         qemu_log_mask(CPU_LOG_MMU,
160                       "%s: raddr %" PRIx64 " > ram_size %" PRIx64 "\n",
161                       __func__, (uint64_t)raddr, (uint64_t)ram_size);
162         excp = PGM_ADDRESSING;
163         tec = 0; /* unused */
164     }
165
166     if (!excp) {
167         qemu_log_mask(CPU_LOG_MMU,
168                       "%s: set tlb %" PRIx64 " -> %" PRIx64 " (%x)\n",
169                       __func__, (uint64_t)vaddr, (uint64_t)raddr, prot);
170         tlb_set_page(cs, address & TARGET_PAGE_MASK, raddr, prot,
171                      mmu_idx, TARGET_PAGE_SIZE);
172         return true;
173     }
174     if (probe) {
175         return false;
176     }
177
178     if (excp != PGM_ADDRESSING) {
179         stq_phys(env_cpu(env)->as,
180                  env->psa + offsetof(LowCore, trans_exc_code), tec);
181     }
182
183     /*
184      * For data accesses, ILEN will be filled in from the unwind info,
185      * within cpu_loop_exit_restore.  For code accesses, retaddr == 0,
186      * and so unwinding will not occur.  However, ILEN is also undefined
187      * for that case -- we choose to set ILEN = 2.
188      */
189     env->int_pgm_ilen = 2;
190     trigger_pgm_exception(env, excp);
191     cpu_loop_exit_restore(cs, retaddr);
192 }
193
194 static void do_program_interrupt(CPUS390XState *env)
195 {
196     uint64_t mask, addr;
197     LowCore *lowcore;
198     int ilen = env->int_pgm_ilen;
199
200     assert(ilen == 2 || ilen == 4 || ilen == 6);
201
202     switch (env->int_pgm_code) {
203     case PGM_PER:
204         if (env->per_perc_atmid & PER_CODE_EVENT_NULLIFICATION) {
205             break;
206         }
207         /* FALL THROUGH */
208     case PGM_OPERATION:
209     case PGM_PRIVILEGED:
210     case PGM_EXECUTE:
211     case PGM_PROTECTION:
212     case PGM_ADDRESSING:
213     case PGM_SPECIFICATION:
214     case PGM_DATA:
215     case PGM_FIXPT_OVERFLOW:
216     case PGM_FIXPT_DIVIDE:
217     case PGM_DEC_OVERFLOW:
218     case PGM_DEC_DIVIDE:
219     case PGM_HFP_EXP_OVERFLOW:
220     case PGM_HFP_EXP_UNDERFLOW:
221     case PGM_HFP_SIGNIFICANCE:
222     case PGM_HFP_DIVIDE:
223     case PGM_TRANS_SPEC:
224     case PGM_SPECIAL_OP:
225     case PGM_OPERAND:
226     case PGM_HFP_SQRT:
227     case PGM_PC_TRANS_SPEC:
228     case PGM_ALET_SPEC:
229     case PGM_MONITOR:
230         /* advance the PSW if our exception is not nullifying */
231         env->psw.addr += ilen;
232         break;
233     }
234
235     qemu_log_mask(CPU_LOG_INT,
236                   "%s: code=0x%x ilen=%d psw: %" PRIx64 " %" PRIx64 "\n",
237                   __func__, env->int_pgm_code, ilen, env->psw.mask,
238                   env->psw.addr);
239
240     lowcore = cpu_map_lowcore(env);
241
242     /* Signal PER events with the exception.  */
243     if (env->per_perc_atmid) {
244         env->int_pgm_code |= PGM_PER;
245         lowcore->per_address = cpu_to_be64(env->per_address);
246         lowcore->per_perc_atmid = cpu_to_be16(env->per_perc_atmid);
247         env->per_perc_atmid = 0;
248     }
249
250     lowcore->pgm_ilen = cpu_to_be16(ilen);
251     lowcore->pgm_code = cpu_to_be16(env->int_pgm_code);
252     lowcore->program_old_psw.mask = cpu_to_be64(get_psw_mask(env));
253     lowcore->program_old_psw.addr = cpu_to_be64(env->psw.addr);
254     mask = be64_to_cpu(lowcore->program_new_psw.mask);
255     addr = be64_to_cpu(lowcore->program_new_psw.addr);
256     lowcore->per_breaking_event_addr = cpu_to_be64(env->gbea);
257
258     cpu_unmap_lowcore(lowcore);
259
260     load_psw(env, mask, addr);
261 }
262
263 static void do_svc_interrupt(CPUS390XState *env)
264 {
265     uint64_t mask, addr;
266     LowCore *lowcore;
267
268     lowcore = cpu_map_lowcore(env);
269
270     lowcore->svc_code = cpu_to_be16(env->int_svc_code);
271     lowcore->svc_ilen = cpu_to_be16(env->int_svc_ilen);
272     lowcore->svc_old_psw.mask = cpu_to_be64(get_psw_mask(env));
273     lowcore->svc_old_psw.addr = cpu_to_be64(env->psw.addr + env->int_svc_ilen);
274     mask = be64_to_cpu(lowcore->svc_new_psw.mask);
275     addr = be64_to_cpu(lowcore->svc_new_psw.addr);
276
277     cpu_unmap_lowcore(lowcore);
278
279     load_psw(env, mask, addr);
280
281     /* When a PER event is pending, the PER exception has to happen
282        immediately after the SERVICE CALL one.  */
283     if (env->per_perc_atmid) {
284         env->int_pgm_code = PGM_PER;
285         env->int_pgm_ilen = env->int_svc_ilen;
286         do_program_interrupt(env);
287     }
288 }
289
290 #define VIRTIO_SUBCODE_64 0x0D00
291
292 static void do_ext_interrupt(CPUS390XState *env)
293 {
294     QEMUS390FLICState *flic = QEMU_S390_FLIC(s390_get_flic());
295     S390CPU *cpu = env_archcpu(env);
296     uint64_t mask, addr;
297     uint16_t cpu_addr;
298     LowCore *lowcore;
299
300     if (!(env->psw.mask & PSW_MASK_EXT)) {
301         cpu_abort(CPU(cpu), "Ext int w/o ext mask\n");
302     }
303
304     lowcore = cpu_map_lowcore(env);
305
306     if ((env->pending_int & INTERRUPT_EMERGENCY_SIGNAL) &&
307         (env->cregs[0] & CR0_EMERGENCY_SIGNAL_SC)) {
308         lowcore->ext_int_code = cpu_to_be16(EXT_EMERGENCY);
309         cpu_addr = find_first_bit(env->emergency_signals, S390_MAX_CPUS);
310         g_assert(cpu_addr < S390_MAX_CPUS);
311         lowcore->cpu_addr = cpu_to_be16(cpu_addr);
312         clear_bit(cpu_addr, env->emergency_signals);
313 #ifndef CONFIG_USER_ONLY
314         MachineState *ms = MACHINE(qdev_get_machine());
315         unsigned int max_cpus = ms->smp.max_cpus;
316 #endif
317         if (bitmap_empty(env->emergency_signals, max_cpus)) {
318             env->pending_int &= ~INTERRUPT_EMERGENCY_SIGNAL;
319         }
320     } else if ((env->pending_int & INTERRUPT_EXTERNAL_CALL) &&
321                (env->cregs[0] & CR0_EXTERNAL_CALL_SC)) {
322         lowcore->ext_int_code = cpu_to_be16(EXT_EXTERNAL_CALL);
323         lowcore->cpu_addr = cpu_to_be16(env->external_call_addr);
324         env->pending_int &= ~INTERRUPT_EXTERNAL_CALL;
325     } else if ((env->pending_int & INTERRUPT_EXT_CLOCK_COMPARATOR) &&
326                (env->cregs[0] & CR0_CKC_SC)) {
327         lowcore->ext_int_code = cpu_to_be16(EXT_CLOCK_COMP);
328         lowcore->cpu_addr = 0;
329         env->pending_int &= ~INTERRUPT_EXT_CLOCK_COMPARATOR;
330     } else if ((env->pending_int & INTERRUPT_EXT_CPU_TIMER) &&
331                (env->cregs[0] & CR0_CPU_TIMER_SC)) {
332         lowcore->ext_int_code = cpu_to_be16(EXT_CPU_TIMER);
333         lowcore->cpu_addr = 0;
334         env->pending_int &= ~INTERRUPT_EXT_CPU_TIMER;
335     } else if (qemu_s390_flic_has_service(flic) &&
336                (env->cregs[0] & CR0_SERVICE_SC)) {
337         uint32_t param;
338
339         param = qemu_s390_flic_dequeue_service(flic);
340         lowcore->ext_int_code = cpu_to_be16(EXT_SERVICE);
341         lowcore->ext_params = cpu_to_be32(param);
342         lowcore->cpu_addr = 0;
343     } else {
344         g_assert_not_reached();
345     }
346
347     mask = be64_to_cpu(lowcore->external_new_psw.mask);
348     addr = be64_to_cpu(lowcore->external_new_psw.addr);
349     lowcore->external_old_psw.mask = cpu_to_be64(get_psw_mask(env));
350     lowcore->external_old_psw.addr = cpu_to_be64(env->psw.addr);
351
352     cpu_unmap_lowcore(lowcore);
353
354     load_psw(env, mask, addr);
355 }
356
357 static void do_io_interrupt(CPUS390XState *env)
358 {
359     QEMUS390FLICState *flic = QEMU_S390_FLIC(s390_get_flic());
360     uint64_t mask, addr;
361     QEMUS390FlicIO *io;
362     LowCore *lowcore;
363
364     g_assert(env->psw.mask & PSW_MASK_IO);
365     io = qemu_s390_flic_dequeue_io(flic, env->cregs[6]);
366     g_assert(io);
367
368     lowcore = cpu_map_lowcore(env);
369
370     lowcore->subchannel_id = cpu_to_be16(io->id);
371     lowcore->subchannel_nr = cpu_to_be16(io->nr);
372     lowcore->io_int_parm = cpu_to_be32(io->parm);
373     lowcore->io_int_word = cpu_to_be32(io->word);
374     lowcore->io_old_psw.mask = cpu_to_be64(get_psw_mask(env));
375     lowcore->io_old_psw.addr = cpu_to_be64(env->psw.addr);
376     mask = be64_to_cpu(lowcore->io_new_psw.mask);
377     addr = be64_to_cpu(lowcore->io_new_psw.addr);
378
379     cpu_unmap_lowcore(lowcore);
380     g_free(io);
381
382     load_psw(env, mask, addr);
383 }
384
385 typedef struct MchkExtSaveArea {
386     uint64_t    vregs[32][2];                     /* 0x0000 */
387     uint8_t     pad_0x0200[0x0400 - 0x0200];      /* 0x0200 */
388 } MchkExtSaveArea;
389 QEMU_BUILD_BUG_ON(sizeof(MchkExtSaveArea) != 1024);
390
391 static int mchk_store_vregs(CPUS390XState *env, uint64_t mcesao)
392 {
393     hwaddr len = sizeof(MchkExtSaveArea);
394     MchkExtSaveArea *sa;
395     int i;
396
397     sa = cpu_physical_memory_map(mcesao, &len, 1);
398     if (!sa) {
399         return -EFAULT;
400     }
401     if (len != sizeof(MchkExtSaveArea)) {
402         cpu_physical_memory_unmap(sa, len, 1, 0);
403         return -EFAULT;
404     }
405
406     for (i = 0; i < 32; i++) {
407         sa->vregs[i][0] = cpu_to_be64(env->vregs[i][0]);
408         sa->vregs[i][1] = cpu_to_be64(env->vregs[i][1]);
409     }
410
411     cpu_physical_memory_unmap(sa, len, 1, len);
412     return 0;
413 }
414
415 static void do_mchk_interrupt(CPUS390XState *env)
416 {
417     QEMUS390FLICState *flic = QEMU_S390_FLIC(s390_get_flic());
418     uint64_t mcic = s390_build_validity_mcic() | MCIC_SC_CP;
419     uint64_t mask, addr, mcesao = 0;
420     LowCore *lowcore;
421     int i;
422
423     /* for now we only support channel report machine checks (floating) */
424     g_assert(env->psw.mask & PSW_MASK_MCHECK);
425     g_assert(env->cregs[14] & CR14_CHANNEL_REPORT_SC);
426
427     qemu_s390_flic_dequeue_crw_mchk(flic);
428
429     lowcore = cpu_map_lowcore(env);
430
431     /* extended save area */
432     if (mcic & MCIC_VB_VR) {
433         /* length and alignment is 1024 bytes */
434         mcesao = be64_to_cpu(lowcore->mcesad) & ~0x3ffull;
435     }
436
437     /* try to store vector registers */
438     if (!mcesao || mchk_store_vregs(env, mcesao)) {
439         mcic &= ~MCIC_VB_VR;
440     }
441
442     /* we are always in z/Architecture mode */
443     lowcore->ar_access_id = 1;
444
445     for (i = 0; i < 16; i++) {
446         lowcore->floating_pt_save_area[i] = cpu_to_be64(*get_freg(env, i));
447         lowcore->gpregs_save_area[i] = cpu_to_be64(env->regs[i]);
448         lowcore->access_regs_save_area[i] = cpu_to_be32(env->aregs[i]);
449         lowcore->cregs_save_area[i] = cpu_to_be64(env->cregs[i]);
450     }
451     lowcore->prefixreg_save_area = cpu_to_be32(env->psa);
452     lowcore->fpt_creg_save_area = cpu_to_be32(env->fpc);
453     lowcore->tod_progreg_save_area = cpu_to_be32(env->todpr);
454     lowcore->cpu_timer_save_area = cpu_to_be64(env->cputm);
455     lowcore->clock_comp_save_area = cpu_to_be64(env->ckc >> 8);
456
457     lowcore->mcic = cpu_to_be64(mcic);
458     lowcore->mcck_old_psw.mask = cpu_to_be64(get_psw_mask(env));
459     lowcore->mcck_old_psw.addr = cpu_to_be64(env->psw.addr);
460     mask = be64_to_cpu(lowcore->mcck_new_psw.mask);
461     addr = be64_to_cpu(lowcore->mcck_new_psw.addr);
462
463     cpu_unmap_lowcore(lowcore);
464
465     load_psw(env, mask, addr);
466 }
467
468 void s390_cpu_do_interrupt(CPUState *cs)
469 {
470     QEMUS390FLICState *flic = QEMU_S390_FLIC(s390_get_flic());
471     S390CPU *cpu = S390_CPU(cs);
472     CPUS390XState *env = &cpu->env;
473     bool stopped = false;
474
475     qemu_log_mask(CPU_LOG_INT, "%s: %d at psw=%" PRIx64 ":%" PRIx64 "\n",
476                   __func__, cs->exception_index, env->psw.mask, env->psw.addr);
477
478 try_deliver:
479     /* handle machine checks */
480     if (cs->exception_index == -1 && s390_cpu_has_mcck_int(cpu)) {
481         cs->exception_index = EXCP_MCHK;
482     }
483     /* handle external interrupts */
484     if (cs->exception_index == -1 && s390_cpu_has_ext_int(cpu)) {
485         cs->exception_index = EXCP_EXT;
486     }
487     /* handle I/O interrupts */
488     if (cs->exception_index == -1 && s390_cpu_has_io_int(cpu)) {
489         cs->exception_index = EXCP_IO;
490     }
491     /* RESTART interrupt */
492     if (cs->exception_index == -1 && s390_cpu_has_restart_int(cpu)) {
493         cs->exception_index = EXCP_RESTART;
494     }
495     /* STOP interrupt has least priority */
496     if (cs->exception_index == -1 && s390_cpu_has_stop_int(cpu)) {
497         cs->exception_index = EXCP_STOP;
498     }
499
500     switch (cs->exception_index) {
501     case EXCP_PGM:
502         do_program_interrupt(env);
503         break;
504     case EXCP_SVC:
505         do_svc_interrupt(env);
506         break;
507     case EXCP_EXT:
508         do_ext_interrupt(env);
509         break;
510     case EXCP_IO:
511         do_io_interrupt(env);
512         break;
513     case EXCP_MCHK:
514         do_mchk_interrupt(env);
515         break;
516     case EXCP_RESTART:
517         do_restart_interrupt(env);
518         break;
519     case EXCP_STOP:
520         do_stop_interrupt(env);
521         stopped = true;
522         break;
523     }
524
525     if (cs->exception_index != -1 && !stopped) {
526         /* check if there are more pending interrupts to deliver */
527         cs->exception_index = -1;
528         goto try_deliver;
529     }
530     cs->exception_index = -1;
531
532     /* we might still have pending interrupts, but not deliverable */
533     if (!env->pending_int && !qemu_s390_flic_has_any(flic)) {
534         cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
535     }
536
537     /* WAIT PSW during interrupt injection or STOP interrupt */
538     if ((env->psw.mask & PSW_MASK_WAIT) || stopped) {
539         /* don't trigger a cpu_loop_exit(), use an interrupt instead */
540         cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HALT);
541     } else if (cs->halted) {
542         /* unhalt if we had a WAIT PSW somehwere in our injection chain */
543         s390_cpu_unhalt(cpu);
544     }
545 }
546
547 bool s390_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
548 {
549     if (interrupt_request & CPU_INTERRUPT_HARD) {
550         S390CPU *cpu = S390_CPU(cs);
551         CPUS390XState *env = &cpu->env;
552
553         if (env->ex_value) {
554             /* Execution of the target insn is indivisible from
555                the parent EXECUTE insn.  */
556             return false;
557         }
558         if (s390_cpu_has_int(cpu)) {
559             s390_cpu_do_interrupt(cs);
560             return true;
561         }
562         if (env->psw.mask & PSW_MASK_WAIT) {
563             /* Woken up because of a floating interrupt but it has already
564              * been delivered. Go back to sleep. */
565             cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HALT);
566         }
567     }
568     return false;
569 }
570
571 void s390x_cpu_debug_excp_handler(CPUState *cs)
572 {
573     S390CPU *cpu = S390_CPU(cs);
574     CPUS390XState *env = &cpu->env;
575     CPUWatchpoint *wp_hit = cs->watchpoint_hit;
576
577     if (wp_hit && wp_hit->flags & BP_CPU) {
578         /* FIXME: When the storage-alteration-space control bit is set,
579            the exception should only be triggered if the memory access
580            is done using an address space with the storage-alteration-event
581            bit set.  We have no way to detect that with the current
582            watchpoint code.  */
583         cs->watchpoint_hit = NULL;
584
585         env->per_address = env->psw.addr;
586         env->per_perc_atmid |= PER_CODE_EVENT_STORE | get_per_atmid(env);
587         /* FIXME: We currently no way to detect the address space used
588            to trigger the watchpoint.  For now just consider it is the
589            current default ASC. This turn to be true except when MVCP
590            and MVCS instrutions are not used.  */
591         env->per_perc_atmid |= env->psw.mask & (PSW_MASK_ASC) >> 46;
592
593         /* Remove all watchpoints to re-execute the code.  A PER exception
594            will be triggered, it will call load_psw which will recompute
595            the watchpoints.  */
596         cpu_watchpoint_remove_all(cs, BP_CPU);
597         cpu_loop_exit_noexc(cs);
598     }
599 }
600
601 /* Unaligned accesses are only diagnosed with MO_ALIGN.  At the moment,
602    this is only for the atomic operations, for which we want to raise a
603    specification exception.  */
604 void s390x_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
605                                    MMUAccessType access_type,
606                                    int mmu_idx, uintptr_t retaddr)
607 {
608     S390CPU *cpu = S390_CPU(cs);
609     CPUS390XState *env = &cpu->env;
610
611     tcg_s390_program_interrupt(env, PGM_SPECIFICATION, retaddr);
612 }
613
614 #endif /* CONFIG_USER_ONLY */
This page took 0.061342 seconds and 4 git commands to generate.