]> Git Repo - qemu.git/blob - target-s390x/helper.c
Remove exec-all.h include directives
[qemu.git] / target-s390x / helper.c
1 /*
2  *  S/390 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 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 <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "cpu.h"
26 #include "gdbstub.h"
27 #include "qemu-common.h"
28 #include "qemu-timer.h"
29
30 //#define DEBUG_S390
31 //#define DEBUG_S390_PTE
32 //#define DEBUG_S390_STDOUT
33
34 #ifdef DEBUG_S390
35 #ifdef DEBUG_S390_STDOUT
36 #define DPRINTF(fmt, ...) \
37     do { fprintf(stderr, fmt, ## __VA_ARGS__); \
38          qemu_log(fmt, ##__VA_ARGS__); } while (0)
39 #else
40 #define DPRINTF(fmt, ...) \
41     do { qemu_log(fmt, ## __VA_ARGS__); } while (0)
42 #endif
43 #else
44 #define DPRINTF(fmt, ...) \
45     do { } while (0)
46 #endif
47
48 #ifdef DEBUG_S390_PTE
49 #define PTE_DPRINTF DPRINTF
50 #else
51 #define PTE_DPRINTF(fmt, ...) \
52     do { } while (0)
53 #endif
54
55 #ifndef CONFIG_USER_ONLY
56 static void s390x_tod_timer(void *opaque)
57 {
58     CPUState *env = opaque;
59
60     env->pending_int |= INTERRUPT_TOD;
61     cpu_interrupt(env, CPU_INTERRUPT_HARD);
62 }
63
64 static void s390x_cpu_timer(void *opaque)
65 {
66     CPUState *env = opaque;
67
68     env->pending_int |= INTERRUPT_CPUTIMER;
69     cpu_interrupt(env, CPU_INTERRUPT_HARD);
70 }
71 #endif
72
73 CPUS390XState *cpu_s390x_init(const char *cpu_model)
74 {
75     CPUS390XState *env;
76 #if !defined (CONFIG_USER_ONLY)
77     struct tm tm;
78 #endif
79     static int inited = 0;
80     static int cpu_num = 0;
81
82     env = qemu_mallocz(sizeof(CPUS390XState));
83     cpu_exec_init(env);
84     if (!inited) {
85         inited = 1;
86         s390x_translate_init();
87     }
88
89 #if !defined(CONFIG_USER_ONLY)
90     qemu_get_timedate(&tm, 0);
91     env->tod_offset = TOD_UNIX_EPOCH +
92                       (time2tod(mktimegm(&tm)) * 1000000000ULL);
93     env->tod_basetime = 0;
94     env->tod_timer = qemu_new_timer_ns(vm_clock, s390x_tod_timer, env);
95     env->cpu_timer = qemu_new_timer_ns(vm_clock, s390x_cpu_timer, env);
96 #endif
97     env->cpu_model_str = cpu_model;
98     env->cpu_num = cpu_num++;
99     env->ext_index = -1;
100     cpu_reset(env);
101     qemu_init_vcpu(env);
102     return env;
103 }
104
105 #if defined(CONFIG_USER_ONLY)
106
107 void do_interrupt (CPUState *env)
108 {
109     env->exception_index = -1;
110 }
111
112 int cpu_s390x_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
113                               int mmu_idx, int is_softmmu)
114 {
115     /* fprintf(stderr,"%s: address 0x%lx rw %d mmu_idx %d is_softmmu %d\n",
116             __FUNCTION__, address, rw, mmu_idx, is_softmmu); */
117     env->exception_index = EXCP_ADDR;
118     env->__excp_addr = address; /* FIXME: find out how this works on a real machine */
119     return 1;
120 }
121
122 #endif /* CONFIG_USER_ONLY */
123
124 void cpu_reset(CPUS390XState *env)
125 {
126     if (qemu_loglevel_mask(CPU_LOG_RESET)) {
127         qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
128         log_cpu_state(env, 0);
129     }
130
131     memset(env, 0, offsetof(CPUS390XState, breakpoints));
132     /* FIXME: reset vector? */
133     tlb_flush(env, 1);
134 }
135
136 #ifndef CONFIG_USER_ONLY
137
138 /* Ensure to exit the TB after this call! */
139 static void trigger_pgm_exception(CPUState *env, uint32_t code, uint32_t ilc)
140 {
141     env->exception_index = EXCP_PGM;
142     env->int_pgm_code = code;
143     env->int_pgm_ilc = ilc;
144 }
145
146 static int trans_bits(CPUState *env, uint64_t mode)
147 {
148     int bits = 0;
149
150     switch (mode) {
151     case PSW_ASC_PRIMARY:
152         bits = 1;
153         break;
154     case PSW_ASC_SECONDARY:
155         bits = 2;
156         break;
157     case PSW_ASC_HOME:
158         bits = 3;
159         break;
160     default:
161         cpu_abort(env, "unknown asc mode\n");
162         break;
163     }
164
165     return bits;
166 }
167
168 static void trigger_prot_fault(CPUState *env, target_ulong vaddr, uint64_t mode)
169 {
170     int ilc = ILC_LATER_INC_2;
171     int bits = trans_bits(env, mode) | 4;
172
173     DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __FUNCTION__, vaddr, bits);
174
175     stq_phys(env->psa + offsetof(LowCore, trans_exc_code), vaddr | bits);
176     trigger_pgm_exception(env, PGM_PROTECTION, ilc);
177 }
178
179 static void trigger_page_fault(CPUState *env, target_ulong vaddr, uint32_t type,
180                                uint64_t asc, int rw)
181 {
182     int ilc = ILC_LATER;
183     int bits = trans_bits(env, asc);
184
185     if (rw == 2) {
186         /* code has is undefined ilc */
187         ilc = 2;
188     }
189
190     DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __FUNCTION__, vaddr, bits);
191
192     stq_phys(env->psa + offsetof(LowCore, trans_exc_code), vaddr | bits);
193     trigger_pgm_exception(env, type, ilc);
194 }
195
196 static int mmu_translate_asce(CPUState *env, target_ulong vaddr, uint64_t asc,
197                               uint64_t asce, int level, target_ulong *raddr,
198                               int *flags, int rw)
199 {
200     uint64_t offs = 0;
201     uint64_t origin;
202     uint64_t new_asce;
203
204     PTE_DPRINTF("%s: 0x%" PRIx64 "\n", __FUNCTION__, asce);
205
206     if (((level != _ASCE_TYPE_SEGMENT) && (asce & _REGION_ENTRY_INV)) ||
207         ((level == _ASCE_TYPE_SEGMENT) && (asce & _SEGMENT_ENTRY_INV))) {
208         /* XXX different regions have different faults */
209         DPRINTF("%s: invalid region\n", __FUNCTION__);
210         trigger_page_fault(env, vaddr, PGM_SEGMENT_TRANS, asc, rw);
211         return -1;
212     }
213
214     if ((level <= _ASCE_TYPE_MASK) && ((asce & _ASCE_TYPE_MASK) != level)) {
215         trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw);
216         return -1;
217     }
218
219     if (asce & _ASCE_REAL_SPACE) {
220         /* direct mapping */
221
222         *raddr = vaddr;
223         return 0;
224     }
225
226     origin = asce & _ASCE_ORIGIN;
227
228     switch (level) {
229     case _ASCE_TYPE_REGION1 + 4:
230         offs = (vaddr >> 50) & 0x3ff8;
231         break;
232     case _ASCE_TYPE_REGION1:
233         offs = (vaddr >> 39) & 0x3ff8;
234         break;
235     case _ASCE_TYPE_REGION2:
236         offs = (vaddr >> 28) & 0x3ff8;
237         break;
238     case _ASCE_TYPE_REGION3:
239         offs = (vaddr >> 17) & 0x3ff8;
240         break;
241     case _ASCE_TYPE_SEGMENT:
242         offs = (vaddr >> 9) & 0x07f8;
243         origin = asce & _SEGMENT_ENTRY_ORIGIN;
244         break;
245     }
246
247     /* XXX region protection flags */
248     /* *flags &= ~PAGE_WRITE */
249
250     new_asce = ldq_phys(origin + offs);
251     PTE_DPRINTF("%s: 0x%" PRIx64 " + 0x%" PRIx64 " => 0x%016" PRIx64 "\n",
252                 __FUNCTION__, origin, offs, new_asce);
253
254     if (level != _ASCE_TYPE_SEGMENT) {
255         /* yet another region */
256         return mmu_translate_asce(env, vaddr, asc, new_asce, level - 4, raddr,
257                                   flags, rw);
258     }
259
260     /* PTE */
261     if (new_asce & _PAGE_INVALID) {
262         DPRINTF("%s: PTE=0x%" PRIx64 " invalid\n", __FUNCTION__, new_asce);
263         trigger_page_fault(env, vaddr, PGM_PAGE_TRANS, asc, rw);
264         return -1;
265     }
266
267     if (new_asce & _PAGE_RO) {
268         *flags &= ~PAGE_WRITE;
269     }
270
271     *raddr = new_asce & _ASCE_ORIGIN;
272
273     PTE_DPRINTF("%s: PTE=0x%" PRIx64 "\n", __FUNCTION__, new_asce);
274
275     return 0;
276 }
277
278 static int mmu_translate_asc(CPUState *env, target_ulong vaddr, uint64_t asc,
279                              target_ulong *raddr, int *flags, int rw)
280 {
281     uint64_t asce = 0;
282     int level, new_level;
283     int r;
284
285     switch (asc) {
286     case PSW_ASC_PRIMARY:
287         PTE_DPRINTF("%s: asc=primary\n", __FUNCTION__);
288         asce = env->cregs[1];
289         break;
290     case PSW_ASC_SECONDARY:
291         PTE_DPRINTF("%s: asc=secondary\n", __FUNCTION__);
292         asce = env->cregs[7];
293         break;
294     case PSW_ASC_HOME:
295         PTE_DPRINTF("%s: asc=home\n", __FUNCTION__);
296         asce = env->cregs[13];
297         break;
298     }
299
300     switch (asce & _ASCE_TYPE_MASK) {
301     case _ASCE_TYPE_REGION1:
302         break;
303     case _ASCE_TYPE_REGION2:
304         if (vaddr & 0xffe0000000000000ULL) {
305             DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64
306                         " 0xffe0000000000000ULL\n", __FUNCTION__,
307                         vaddr);
308             trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw);
309             return -1;
310         }
311         break;
312     case _ASCE_TYPE_REGION3:
313         if (vaddr & 0xfffffc0000000000ULL) {
314             DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64
315                         " 0xfffffc0000000000ULL\n", __FUNCTION__,
316                         vaddr);
317             trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw);
318             return -1;
319         }
320         break;
321     case _ASCE_TYPE_SEGMENT:
322         if (vaddr & 0xffffffff80000000ULL) {
323             DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64
324                         " 0xffffffff80000000ULL\n", __FUNCTION__,
325                         vaddr);
326             trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw);
327             return -1;
328         }
329         break;
330     }
331
332     /* fake level above current */
333     level = asce & _ASCE_TYPE_MASK;
334     new_level = level + 4;
335     asce = (asce & ~_ASCE_TYPE_MASK) | (new_level & _ASCE_TYPE_MASK);
336
337     r = mmu_translate_asce(env, vaddr, asc, asce, new_level, raddr, flags, rw);
338
339     if ((rw == 1) && !(*flags & PAGE_WRITE)) {
340         trigger_prot_fault(env, vaddr, asc);
341         return -1;
342     }
343
344     return r;
345 }
346
347 int mmu_translate(CPUState *env, target_ulong vaddr, int rw, uint64_t asc,
348                   target_ulong *raddr, int *flags)
349 {
350     int r = -1;
351
352     *flags = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
353     vaddr &= TARGET_PAGE_MASK;
354
355     if (!(env->psw.mask & PSW_MASK_DAT)) {
356         *raddr = vaddr;
357         r = 0;
358         goto out;
359     }
360
361     switch (asc) {
362     case PSW_ASC_PRIMARY:
363     case PSW_ASC_HOME:
364         r = mmu_translate_asc(env, vaddr, asc, raddr, flags, rw);
365         break;
366     case PSW_ASC_SECONDARY:
367         /*
368          * Instruction: Primary
369          * Data: Secondary
370          */
371         if (rw == 2) {
372             r = mmu_translate_asc(env, vaddr, PSW_ASC_PRIMARY, raddr, flags,
373                                   rw);
374             *flags &= ~(PAGE_READ | PAGE_WRITE);
375         } else {
376             r = mmu_translate_asc(env, vaddr, PSW_ASC_SECONDARY, raddr, flags,
377                                   rw);
378             *flags &= ~(PAGE_EXEC);
379         }
380         break;
381     case PSW_ASC_ACCREG:
382     default:
383         hw_error("guest switched to unknown asc mode\n");
384         break;
385     }
386
387 out:
388     /* Convert real address -> absolute address */
389     if (*raddr < 0x2000) {
390         *raddr = *raddr + env->psa;
391     }
392
393     return r;
394 }
395
396 int cpu_s390x_handle_mmu_fault (CPUState *env, target_ulong _vaddr, int rw,
397                                 int mmu_idx, int is_softmmu)
398 {
399     uint64_t asc = env->psw.mask & PSW_MASK_ASC;
400     target_ulong vaddr, raddr;
401     int prot;
402
403     DPRINTF("%s: address 0x%" PRIx64 " rw %d mmu_idx %d is_softmmu %d\n",
404             __FUNCTION__, _vaddr, rw, mmu_idx, is_softmmu);
405
406     _vaddr &= TARGET_PAGE_MASK;
407     vaddr = _vaddr;
408
409     /* 31-Bit mode */
410     if (!(env->psw.mask & PSW_MASK_64)) {
411         vaddr &= 0x7fffffff;
412     }
413
414     if (mmu_translate(env, vaddr, rw, asc, &raddr, &prot)) {
415         /* Translation ended in exception */
416         return 1;
417     }
418
419     /* check out of RAM access */
420     if (raddr > (ram_size + virtio_size)) {
421         DPRINTF("%s: aaddr %" PRIx64 " > ram_size %" PRIx64 "\n", __FUNCTION__,
422                 (uint64_t)aaddr, (uint64_t)ram_size);
423         trigger_pgm_exception(env, PGM_ADDRESSING, ILC_LATER);
424         return 1;
425     }
426
427     DPRINTF("%s: set tlb %" PRIx64 " -> %" PRIx64 " (%x)\n", __FUNCTION__,
428             (uint64_t)vaddr, (uint64_t)raddr, prot);
429
430     tlb_set_page(env, _vaddr, raddr, prot,
431                  mmu_idx, TARGET_PAGE_SIZE);
432
433     return 0;
434 }
435
436 target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong vaddr)
437 {
438     target_ulong raddr;
439     int prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
440     int old_exc = env->exception_index;
441     uint64_t asc = env->psw.mask & PSW_MASK_ASC;
442
443     /* 31-Bit mode */
444     if (!(env->psw.mask & PSW_MASK_64)) {
445         vaddr &= 0x7fffffff;
446     }
447
448     mmu_translate(env, vaddr, 2, asc, &raddr, &prot);
449     env->exception_index = old_exc;
450
451     return raddr;
452 }
453
454 void load_psw(CPUState *env, uint64_t mask, uint64_t addr)
455 {
456     if (mask & PSW_MASK_WAIT) {
457         env->halted = 1;
458         env->exception_index = EXCP_HLT;
459         if (!(mask & (PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK))) {
460             /* XXX disabled wait state - CPU is dead */
461         }
462     }
463
464     env->psw.addr = addr;
465     env->psw.mask = mask;
466     env->cc_op = (mask >> 13) & 3;
467 }
468
469 static uint64_t get_psw_mask(CPUState *env)
470 {
471     uint64_t r = env->psw.mask;
472
473     env->cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst, env->cc_vr);
474
475     r &= ~(3ULL << 13);
476     assert(!(env->cc_op & ~3));
477     r |= env->cc_op << 13;
478
479     return r;
480 }
481
482 static void do_svc_interrupt(CPUState *env)
483 {
484     uint64_t mask, addr;
485     LowCore *lowcore;
486     target_phys_addr_t len = TARGET_PAGE_SIZE;
487
488     lowcore = cpu_physical_memory_map(env->psa, &len, 1);
489
490     lowcore->svc_code = cpu_to_be16(env->int_svc_code);
491     lowcore->svc_ilc = cpu_to_be16(env->int_svc_ilc);
492     lowcore->svc_old_psw.mask = cpu_to_be64(get_psw_mask(env));
493     lowcore->svc_old_psw.addr = cpu_to_be64(env->psw.addr + (env->int_svc_ilc));
494     mask = be64_to_cpu(lowcore->svc_new_psw.mask);
495     addr = be64_to_cpu(lowcore->svc_new_psw.addr);
496
497     cpu_physical_memory_unmap(lowcore, len, 1, len);
498
499     load_psw(env, mask, addr);
500 }
501
502 static void do_program_interrupt(CPUState *env)
503 {
504     uint64_t mask, addr;
505     LowCore *lowcore;
506     target_phys_addr_t len = TARGET_PAGE_SIZE;
507     int ilc = env->int_pgm_ilc;
508
509     switch (ilc) {
510     case ILC_LATER:
511         ilc = get_ilc(ldub_code(env->psw.addr));
512         break;
513     case ILC_LATER_INC:
514         ilc = get_ilc(ldub_code(env->psw.addr));
515         env->psw.addr += ilc * 2;
516         break;
517     case ILC_LATER_INC_2:
518         ilc = get_ilc(ldub_code(env->psw.addr)) * 2;
519         env->psw.addr += ilc;
520         break;
521     }
522
523     qemu_log("%s: code=0x%x ilc=%d\n", __FUNCTION__, env->int_pgm_code, ilc);
524
525     lowcore = cpu_physical_memory_map(env->psa, &len, 1);
526
527     lowcore->pgm_ilc = cpu_to_be16(ilc);
528     lowcore->pgm_code = cpu_to_be16(env->int_pgm_code);
529     lowcore->program_old_psw.mask = cpu_to_be64(get_psw_mask(env));
530     lowcore->program_old_psw.addr = cpu_to_be64(env->psw.addr);
531     mask = be64_to_cpu(lowcore->program_new_psw.mask);
532     addr = be64_to_cpu(lowcore->program_new_psw.addr);
533
534     cpu_physical_memory_unmap(lowcore, len, 1, len);
535
536     DPRINTF("%s: %x %x %" PRIx64 " %" PRIx64 "\n", __FUNCTION__,
537             env->int_pgm_code, ilc, env->psw.mask,
538             env->psw.addr);
539
540     load_psw(env, mask, addr);
541 }
542
543 #define VIRTIO_SUBCODE_64 0x0D00
544
545 static void do_ext_interrupt(CPUState *env)
546 {
547     uint64_t mask, addr;
548     LowCore *lowcore;
549     target_phys_addr_t len = TARGET_PAGE_SIZE;
550     ExtQueue *q;
551
552     if (!(env->psw.mask & PSW_MASK_EXT)) {
553         cpu_abort(env, "Ext int w/o ext mask\n");
554     }
555
556     if (env->ext_index < 0 || env->ext_index > MAX_EXT_QUEUE) {
557         cpu_abort(env, "Ext queue overrun: %d\n", env->ext_index);
558     }
559
560     q = &env->ext_queue[env->ext_index];
561     lowcore = cpu_physical_memory_map(env->psa, &len, 1);
562
563     lowcore->ext_int_code = cpu_to_be16(q->code);
564     lowcore->ext_params = cpu_to_be32(q->param);
565     lowcore->ext_params2 = cpu_to_be64(q->param64);
566     lowcore->external_old_psw.mask = cpu_to_be64(get_psw_mask(env));
567     lowcore->external_old_psw.addr = cpu_to_be64(env->psw.addr);
568     lowcore->cpu_addr = cpu_to_be16(env->cpu_num | VIRTIO_SUBCODE_64);
569     mask = be64_to_cpu(lowcore->external_new_psw.mask);
570     addr = be64_to_cpu(lowcore->external_new_psw.addr);
571
572     cpu_physical_memory_unmap(lowcore, len, 1, len);
573
574     env->ext_index--;
575     if (env->ext_index == -1) {
576         env->pending_int &= ~INTERRUPT_EXT;
577     }
578
579     DPRINTF("%s: %" PRIx64 " %" PRIx64 "\n", __FUNCTION__,
580             env->psw.mask, env->psw.addr);
581
582     load_psw(env, mask, addr);
583 }
584
585 void do_interrupt (CPUState *env)
586 {
587     qemu_log("%s: %d at pc=%" PRIx64 "\n", __FUNCTION__, env->exception_index,
588              env->psw.addr);
589
590     /* handle external interrupts */
591     if ((env->psw.mask & PSW_MASK_EXT) &&
592         env->exception_index == -1) {
593         if (env->pending_int & INTERRUPT_EXT) {
594             /* code is already in env */
595             env->exception_index = EXCP_EXT;
596         } else if (env->pending_int & INTERRUPT_TOD) {
597             cpu_inject_ext(env, 0x1004, 0, 0);
598             env->exception_index = EXCP_EXT;
599             env->pending_int &= ~INTERRUPT_EXT;
600             env->pending_int &= ~INTERRUPT_TOD;
601         } else if (env->pending_int & INTERRUPT_CPUTIMER) {
602             cpu_inject_ext(env, 0x1005, 0, 0);
603             env->exception_index = EXCP_EXT;
604             env->pending_int &= ~INTERRUPT_EXT;
605             env->pending_int &= ~INTERRUPT_TOD;
606         }
607     }
608
609     switch (env->exception_index) {
610     case EXCP_PGM:
611         do_program_interrupt(env);
612         break;
613     case EXCP_SVC:
614         do_svc_interrupt(env);
615         break;
616     case EXCP_EXT:
617         do_ext_interrupt(env);
618         break;
619     }
620     env->exception_index = -1;
621
622     if (!env->pending_int) {
623         env->interrupt_request &= ~CPU_INTERRUPT_HARD;
624     }
625 }
626
627 #endif /* CONFIG_USER_ONLY */
This page took 0.059322 seconds and 4 git commands to generate.