4 * Copyright (c) 2009 Ulrich Hecht
5 * Copyright (c) 2011 Alexander Graf
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.
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.
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/>.
23 #include "qemu-timer.h"
24 #ifndef CONFIG_USER_ONLY
29 //#define DEBUG_S390_PTE
30 //#define DEBUG_S390_STDOUT
33 #ifdef DEBUG_S390_STDOUT
34 #define DPRINTF(fmt, ...) \
35 do { fprintf(stderr, fmt, ## __VA_ARGS__); \
36 qemu_log(fmt, ##__VA_ARGS__); } while (0)
38 #define DPRINTF(fmt, ...) \
39 do { qemu_log(fmt, ## __VA_ARGS__); } while (0)
42 #define DPRINTF(fmt, ...) \
47 #define PTE_DPRINTF DPRINTF
49 #define PTE_DPRINTF(fmt, ...) \
53 #ifndef CONFIG_USER_ONLY
54 static void s390x_tod_timer(void *opaque
)
56 CPUS390XState
*env
= opaque
;
58 env
->pending_int
|= INTERRUPT_TOD
;
59 cpu_interrupt(env
, CPU_INTERRUPT_HARD
);
62 static void s390x_cpu_timer(void *opaque
)
64 CPUS390XState
*env
= opaque
;
66 env
->pending_int
|= INTERRUPT_CPUTIMER
;
67 cpu_interrupt(env
, CPU_INTERRUPT_HARD
);
71 CPUS390XState
*cpu_s390x_init(const char *cpu_model
)
74 #if !defined (CONFIG_USER_ONLY)
77 static int inited
= 0;
78 static int cpu_num
= 0;
80 env
= g_malloc0(sizeof(CPUS390XState
));
82 if (tcg_enabled() && !inited
) {
84 s390x_translate_init();
87 #if !defined(CONFIG_USER_ONLY)
88 qemu_get_timedate(&tm
, 0);
89 env
->tod_offset
= TOD_UNIX_EPOCH
+
90 (time2tod(mktimegm(&tm
)) * 1000000000ULL);
91 env
->tod_basetime
= 0;
92 env
->tod_timer
= qemu_new_timer_ns(vm_clock
, s390x_tod_timer
, env
);
93 env
->cpu_timer
= qemu_new_timer_ns(vm_clock
, s390x_cpu_timer
, env
);
95 env
->cpu_model_str
= cpu_model
;
96 env
->cpu_num
= cpu_num
++;
103 #if defined(CONFIG_USER_ONLY)
105 void do_interrupt (CPUS390XState
*env
)
107 env
->exception_index
= -1;
110 int cpu_s390x_handle_mmu_fault (CPUS390XState
*env
, target_ulong address
, int rw
,
113 /* fprintf(stderr,"%s: address 0x%lx rw %d mmu_idx %d\n",
114 __FUNCTION__, address, rw, mmu_idx); */
115 env
->exception_index
= EXCP_ADDR
;
116 env
->__excp_addr
= address
; /* FIXME: find out how this works on a real machine */
120 #endif /* CONFIG_USER_ONLY */
122 void cpu_state_reset(CPUS390XState
*env
)
124 if (qemu_loglevel_mask(CPU_LOG_RESET
)) {
125 qemu_log("CPU Reset (CPU %d)\n", env
->cpu_index
);
126 log_cpu_state(env
, 0);
129 memset(env
, 0, offsetof(CPUS390XState
, breakpoints
));
130 /* FIXME: reset vector? */
132 s390_add_running_cpu(env
);
135 #ifndef CONFIG_USER_ONLY
137 /* Ensure to exit the TB after this call! */
138 static void trigger_pgm_exception(CPUS390XState
*env
, uint32_t code
, uint32_t ilc
)
140 env
->exception_index
= EXCP_PGM
;
141 env
->int_pgm_code
= code
;
142 env
->int_pgm_ilc
= ilc
;
145 static int trans_bits(CPUS390XState
*env
, uint64_t mode
)
150 case PSW_ASC_PRIMARY
:
153 case PSW_ASC_SECONDARY
:
160 cpu_abort(env
, "unknown asc mode\n");
167 static void trigger_prot_fault(CPUS390XState
*env
, target_ulong vaddr
, uint64_t mode
)
169 int ilc
= ILC_LATER_INC_2
;
170 int bits
= trans_bits(env
, mode
) | 4;
172 DPRINTF("%s: vaddr=%016" PRIx64
" bits=%d\n", __FUNCTION__
, vaddr
, bits
);
174 stq_phys(env
->psa
+ offsetof(LowCore
, trans_exc_code
), vaddr
| bits
);
175 trigger_pgm_exception(env
, PGM_PROTECTION
, ilc
);
178 static void trigger_page_fault(CPUS390XState
*env
, target_ulong vaddr
, uint32_t type
,
179 uint64_t asc
, int rw
)
182 int bits
= trans_bits(env
, asc
);
185 /* code has is undefined ilc */
189 DPRINTF("%s: vaddr=%016" PRIx64
" bits=%d\n", __FUNCTION__
, vaddr
, bits
);
191 stq_phys(env
->psa
+ offsetof(LowCore
, trans_exc_code
), vaddr
| bits
);
192 trigger_pgm_exception(env
, type
, ilc
);
195 static int mmu_translate_asce(CPUS390XState
*env
, target_ulong vaddr
, uint64_t asc
,
196 uint64_t asce
, int level
, target_ulong
*raddr
,
203 PTE_DPRINTF("%s: 0x%" PRIx64
"\n", __FUNCTION__
, asce
);
205 if (((level
!= _ASCE_TYPE_SEGMENT
) && (asce
& _REGION_ENTRY_INV
)) ||
206 ((level
== _ASCE_TYPE_SEGMENT
) && (asce
& _SEGMENT_ENTRY_INV
))) {
207 /* XXX different regions have different faults */
208 DPRINTF("%s: invalid region\n", __FUNCTION__
);
209 trigger_page_fault(env
, vaddr
, PGM_SEGMENT_TRANS
, asc
, rw
);
213 if ((level
<= _ASCE_TYPE_MASK
) && ((asce
& _ASCE_TYPE_MASK
) != level
)) {
214 trigger_page_fault(env
, vaddr
, PGM_TRANS_SPEC
, asc
, rw
);
218 if (asce
& _ASCE_REAL_SPACE
) {
225 origin
= asce
& _ASCE_ORIGIN
;
228 case _ASCE_TYPE_REGION1
+ 4:
229 offs
= (vaddr
>> 50) & 0x3ff8;
231 case _ASCE_TYPE_REGION1
:
232 offs
= (vaddr
>> 39) & 0x3ff8;
234 case _ASCE_TYPE_REGION2
:
235 offs
= (vaddr
>> 28) & 0x3ff8;
237 case _ASCE_TYPE_REGION3
:
238 offs
= (vaddr
>> 17) & 0x3ff8;
240 case _ASCE_TYPE_SEGMENT
:
241 offs
= (vaddr
>> 9) & 0x07f8;
242 origin
= asce
& _SEGMENT_ENTRY_ORIGIN
;
246 /* XXX region protection flags */
247 /* *flags &= ~PAGE_WRITE */
249 new_asce
= ldq_phys(origin
+ offs
);
250 PTE_DPRINTF("%s: 0x%" PRIx64
" + 0x%" PRIx64
" => 0x%016" PRIx64
"\n",
251 __FUNCTION__
, origin
, offs
, new_asce
);
253 if (level
!= _ASCE_TYPE_SEGMENT
) {
254 /* yet another region */
255 return mmu_translate_asce(env
, vaddr
, asc
, new_asce
, level
- 4, raddr
,
260 if (new_asce
& _PAGE_INVALID
) {
261 DPRINTF("%s: PTE=0x%" PRIx64
" invalid\n", __FUNCTION__
, new_asce
);
262 trigger_page_fault(env
, vaddr
, PGM_PAGE_TRANS
, asc
, rw
);
266 if (new_asce
& _PAGE_RO
) {
267 *flags
&= ~PAGE_WRITE
;
270 *raddr
= new_asce
& _ASCE_ORIGIN
;
272 PTE_DPRINTF("%s: PTE=0x%" PRIx64
"\n", __FUNCTION__
, new_asce
);
277 static int mmu_translate_asc(CPUS390XState
*env
, target_ulong vaddr
, uint64_t asc
,
278 target_ulong
*raddr
, int *flags
, int rw
)
281 int level
, new_level
;
285 case PSW_ASC_PRIMARY
:
286 PTE_DPRINTF("%s: asc=primary\n", __FUNCTION__
);
287 asce
= env
->cregs
[1];
289 case PSW_ASC_SECONDARY
:
290 PTE_DPRINTF("%s: asc=secondary\n", __FUNCTION__
);
291 asce
= env
->cregs
[7];
294 PTE_DPRINTF("%s: asc=home\n", __FUNCTION__
);
295 asce
= env
->cregs
[13];
299 switch (asce
& _ASCE_TYPE_MASK
) {
300 case _ASCE_TYPE_REGION1
:
302 case _ASCE_TYPE_REGION2
:
303 if (vaddr
& 0xffe0000000000000ULL
) {
304 DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64
305 " 0xffe0000000000000ULL\n", __FUNCTION__
,
307 trigger_page_fault(env
, vaddr
, PGM_TRANS_SPEC
, asc
, rw
);
311 case _ASCE_TYPE_REGION3
:
312 if (vaddr
& 0xfffffc0000000000ULL
) {
313 DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64
314 " 0xfffffc0000000000ULL\n", __FUNCTION__
,
316 trigger_page_fault(env
, vaddr
, PGM_TRANS_SPEC
, asc
, rw
);
320 case _ASCE_TYPE_SEGMENT
:
321 if (vaddr
& 0xffffffff80000000ULL
) {
322 DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64
323 " 0xffffffff80000000ULL\n", __FUNCTION__
,
325 trigger_page_fault(env
, vaddr
, PGM_TRANS_SPEC
, asc
, rw
);
331 /* fake level above current */
332 level
= asce
& _ASCE_TYPE_MASK
;
333 new_level
= level
+ 4;
334 asce
= (asce
& ~_ASCE_TYPE_MASK
) | (new_level
& _ASCE_TYPE_MASK
);
336 r
= mmu_translate_asce(env
, vaddr
, asc
, asce
, new_level
, raddr
, flags
, rw
);
338 if ((rw
== 1) && !(*flags
& PAGE_WRITE
)) {
339 trigger_prot_fault(env
, vaddr
, asc
);
346 int mmu_translate(CPUS390XState
*env
, target_ulong vaddr
, int rw
, uint64_t asc
,
347 target_ulong
*raddr
, int *flags
)
352 *flags
= PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
;
353 vaddr
&= TARGET_PAGE_MASK
;
355 if (!(env
->psw
.mask
& PSW_MASK_DAT
)) {
362 case PSW_ASC_PRIMARY
:
364 r
= mmu_translate_asc(env
, vaddr
, asc
, raddr
, flags
, rw
);
366 case PSW_ASC_SECONDARY
:
368 * Instruction: Primary
372 r
= mmu_translate_asc(env
, vaddr
, PSW_ASC_PRIMARY
, raddr
, flags
,
374 *flags
&= ~(PAGE_READ
| PAGE_WRITE
);
376 r
= mmu_translate_asc(env
, vaddr
, PSW_ASC_SECONDARY
, raddr
, flags
,
378 *flags
&= ~(PAGE_EXEC
);
383 hw_error("guest switched to unknown asc mode\n");
388 /* Convert real address -> absolute address */
389 if (*raddr
< 0x2000) {
390 *raddr
= *raddr
+ env
->psa
;
393 if (*raddr
<= ram_size
) {
394 sk
= &env
->storage_keys
[*raddr
/ TARGET_PAGE_SIZE
];
395 if (*flags
& PAGE_READ
) {
399 if (*flags
& PAGE_WRITE
) {
407 int cpu_s390x_handle_mmu_fault (CPUS390XState
*env
, target_ulong _vaddr
, int rw
,
410 uint64_t asc
= env
->psw
.mask
& PSW_MASK_ASC
;
411 target_ulong vaddr
, raddr
;
414 DPRINTF("%s: address 0x%" PRIx64
" rw %d mmu_idx %d\n",
415 __FUNCTION__
, _vaddr
, rw
, mmu_idx
);
417 _vaddr
&= TARGET_PAGE_MASK
;
421 if (!(env
->psw
.mask
& PSW_MASK_64
)) {
425 if (mmu_translate(env
, vaddr
, rw
, asc
, &raddr
, &prot
)) {
426 /* Translation ended in exception */
430 /* check out of RAM access */
431 if (raddr
> (ram_size
+ virtio_size
)) {
432 DPRINTF("%s: aaddr %" PRIx64
" > ram_size %" PRIx64
"\n", __FUNCTION__
,
433 (uint64_t)aaddr
, (uint64_t)ram_size
);
434 trigger_pgm_exception(env
, PGM_ADDRESSING
, ILC_LATER
);
438 DPRINTF("%s: set tlb %" PRIx64
" -> %" PRIx64
" (%x)\n", __FUNCTION__
,
439 (uint64_t)vaddr
, (uint64_t)raddr
, prot
);
441 tlb_set_page(env
, _vaddr
, raddr
, prot
,
442 mmu_idx
, TARGET_PAGE_SIZE
);
447 target_phys_addr_t
cpu_get_phys_page_debug(CPUS390XState
*env
, target_ulong vaddr
)
450 int prot
= PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
;
451 int old_exc
= env
->exception_index
;
452 uint64_t asc
= env
->psw
.mask
& PSW_MASK_ASC
;
455 if (!(env
->psw
.mask
& PSW_MASK_64
)) {
459 mmu_translate(env
, vaddr
, 2, asc
, &raddr
, &prot
);
460 env
->exception_index
= old_exc
;
465 void load_psw(CPUS390XState
*env
, uint64_t mask
, uint64_t addr
)
467 if (mask
& PSW_MASK_WAIT
) {
468 if (!(mask
& (PSW_MASK_IO
| PSW_MASK_EXT
| PSW_MASK_MCHECK
))) {
469 if (s390_del_running_cpu(env
) == 0) {
470 #ifndef CONFIG_USER_ONLY
471 qemu_system_shutdown_request();
476 env
->exception_index
= EXCP_HLT
;
479 env
->psw
.addr
= addr
;
480 env
->psw
.mask
= mask
;
481 env
->cc_op
= (mask
>> 13) & 3;
484 static uint64_t get_psw_mask(CPUS390XState
*env
)
486 uint64_t r
= env
->psw
.mask
;
488 env
->cc_op
= calc_cc(env
, env
->cc_op
, env
->cc_src
, env
->cc_dst
, env
->cc_vr
);
491 assert(!(env
->cc_op
& ~3));
492 r
|= env
->cc_op
<< 13;
497 static void do_svc_interrupt(CPUS390XState
*env
)
501 target_phys_addr_t len
= TARGET_PAGE_SIZE
;
503 lowcore
= cpu_physical_memory_map(env
->psa
, &len
, 1);
505 lowcore
->svc_code
= cpu_to_be16(env
->int_svc_code
);
506 lowcore
->svc_ilc
= cpu_to_be16(env
->int_svc_ilc
);
507 lowcore
->svc_old_psw
.mask
= cpu_to_be64(get_psw_mask(env
));
508 lowcore
->svc_old_psw
.addr
= cpu_to_be64(env
->psw
.addr
+ (env
->int_svc_ilc
));
509 mask
= be64_to_cpu(lowcore
->svc_new_psw
.mask
);
510 addr
= be64_to_cpu(lowcore
->svc_new_psw
.addr
);
512 cpu_physical_memory_unmap(lowcore
, len
, 1, len
);
514 load_psw(env
, mask
, addr
);
517 static void do_program_interrupt(CPUS390XState
*env
)
521 target_phys_addr_t len
= TARGET_PAGE_SIZE
;
522 int ilc
= env
->int_pgm_ilc
;
526 ilc
= get_ilc(ldub_code(env
->psw
.addr
));
529 ilc
= get_ilc(ldub_code(env
->psw
.addr
));
530 env
->psw
.addr
+= ilc
* 2;
532 case ILC_LATER_INC_2
:
533 ilc
= get_ilc(ldub_code(env
->psw
.addr
)) * 2;
534 env
->psw
.addr
+= ilc
;
538 qemu_log("%s: code=0x%x ilc=%d\n", __FUNCTION__
, env
->int_pgm_code
, ilc
);
540 lowcore
= cpu_physical_memory_map(env
->psa
, &len
, 1);
542 lowcore
->pgm_ilc
= cpu_to_be16(ilc
);
543 lowcore
->pgm_code
= cpu_to_be16(env
->int_pgm_code
);
544 lowcore
->program_old_psw
.mask
= cpu_to_be64(get_psw_mask(env
));
545 lowcore
->program_old_psw
.addr
= cpu_to_be64(env
->psw
.addr
);
546 mask
= be64_to_cpu(lowcore
->program_new_psw
.mask
);
547 addr
= be64_to_cpu(lowcore
->program_new_psw
.addr
);
549 cpu_physical_memory_unmap(lowcore
, len
, 1, len
);
551 DPRINTF("%s: %x %x %" PRIx64
" %" PRIx64
"\n", __FUNCTION__
,
552 env
->int_pgm_code
, ilc
, env
->psw
.mask
,
555 load_psw(env
, mask
, addr
);
558 #define VIRTIO_SUBCODE_64 0x0D00
560 static void do_ext_interrupt(CPUS390XState
*env
)
564 target_phys_addr_t len
= TARGET_PAGE_SIZE
;
567 if (!(env
->psw
.mask
& PSW_MASK_EXT
)) {
568 cpu_abort(env
, "Ext int w/o ext mask\n");
571 if (env
->ext_index
< 0 || env
->ext_index
> MAX_EXT_QUEUE
) {
572 cpu_abort(env
, "Ext queue overrun: %d\n", env
->ext_index
);
575 q
= &env
->ext_queue
[env
->ext_index
];
576 lowcore
= cpu_physical_memory_map(env
->psa
, &len
, 1);
578 lowcore
->ext_int_code
= cpu_to_be16(q
->code
);
579 lowcore
->ext_params
= cpu_to_be32(q
->param
);
580 lowcore
->ext_params2
= cpu_to_be64(q
->param64
);
581 lowcore
->external_old_psw
.mask
= cpu_to_be64(get_psw_mask(env
));
582 lowcore
->external_old_psw
.addr
= cpu_to_be64(env
->psw
.addr
);
583 lowcore
->cpu_addr
= cpu_to_be16(env
->cpu_num
| VIRTIO_SUBCODE_64
);
584 mask
= be64_to_cpu(lowcore
->external_new_psw
.mask
);
585 addr
= be64_to_cpu(lowcore
->external_new_psw
.addr
);
587 cpu_physical_memory_unmap(lowcore
, len
, 1, len
);
590 if (env
->ext_index
== -1) {
591 env
->pending_int
&= ~INTERRUPT_EXT
;
594 DPRINTF("%s: %" PRIx64
" %" PRIx64
"\n", __FUNCTION__
,
595 env
->psw
.mask
, env
->psw
.addr
);
597 load_psw(env
, mask
, addr
);
600 void do_interrupt (CPUS390XState
*env
)
602 qemu_log("%s: %d at pc=%" PRIx64
"\n", __FUNCTION__
, env
->exception_index
,
605 s390_add_running_cpu(env
);
606 /* handle external interrupts */
607 if ((env
->psw
.mask
& PSW_MASK_EXT
) &&
608 env
->exception_index
== -1) {
609 if (env
->pending_int
& INTERRUPT_EXT
) {
610 /* code is already in env */
611 env
->exception_index
= EXCP_EXT
;
612 } else if (env
->pending_int
& INTERRUPT_TOD
) {
613 cpu_inject_ext(env
, 0x1004, 0, 0);
614 env
->exception_index
= EXCP_EXT
;
615 env
->pending_int
&= ~INTERRUPT_EXT
;
616 env
->pending_int
&= ~INTERRUPT_TOD
;
617 } else if (env
->pending_int
& INTERRUPT_CPUTIMER
) {
618 cpu_inject_ext(env
, 0x1005, 0, 0);
619 env
->exception_index
= EXCP_EXT
;
620 env
->pending_int
&= ~INTERRUPT_EXT
;
621 env
->pending_int
&= ~INTERRUPT_TOD
;
625 switch (env
->exception_index
) {
627 do_program_interrupt(env
);
630 do_svc_interrupt(env
);
633 do_ext_interrupt(env
);
636 env
->exception_index
= -1;
638 if (!env
->pending_int
) {
639 env
->interrupt_request
&= ~CPU_INTERRUPT_HARD
;
643 #endif /* CONFIG_USER_ONLY */