|
|
1.1 root 1: /*
2: * S/390 helpers
3: *
4: * Copyright (c) 2009 Ulrich Hecht
1.1.1.3 ! root 5: * Copyright (c) 2011 Alexander Graf
1.1 root 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
1.1.1.2 root 18: * License along with this library; if not, see <http://www.gnu.org/licenses/>.
1.1 root 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"
1.1.1.3 ! root 28: #include "qemu-timer.h"
1.1 root 29:
1.1.1.3 ! root 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
1.1 root 72:
73: CPUS390XState *cpu_s390x_init(const char *cpu_model)
74: {
75: CPUS390XState *env;
1.1.1.3 ! root 76: #if !defined (CONFIG_USER_ONLY)
! 77: struct tm tm;
! 78: #endif
1.1 root 79: static int inited = 0;
1.1.1.3 ! root 80: static int cpu_num = 0;
1.1 root 81:
82: env = qemu_mallocz(sizeof(CPUS390XState));
83: cpu_exec_init(env);
84: if (!inited) {
85: inited = 1;
1.1.1.3 ! root 86: s390x_translate_init();
1.1 root 87: }
88:
1.1.1.3 ! root 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
1.1 root 97: env->cpu_model_str = cpu_model;
1.1.1.3 ! root 98: env->cpu_num = cpu_num++;
! 99: env->ext_index = -1;
1.1 root 100: cpu_reset(env);
101: qemu_init_vcpu(env);
102: return env;
103: }
104:
1.1.1.3 ! root 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:
1.1 root 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:
1.1.1.3 ! root 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)
1.1.1.2 root 169: {
1.1.1.3 ! root 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:
1.1.1.2 root 275: return 0;
276: }
277:
1.1.1.3 ! root 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: }
1.1 root 299:
1.1.1.3 ! root 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,
1.1 root 397: int mmu_idx, int is_softmmu)
398: {
1.1.1.3 ! root 399: uint64_t asc = env->psw.mask & PSW_MASK_ASC;
! 400: target_ulong vaddr, raddr;
1.1 root 401: int prot;
402:
1.1.1.3 ! root 403: DPRINTF("%s: address 0x%" PRIx64 " rw %d mmu_idx %d is_softmmu %d\n",
! 404: __FUNCTION__, _vaddr, rw, mmu_idx, is_softmmu);
1.1 root 405:
1.1.1.3 ! root 406: _vaddr &= TARGET_PAGE_MASK;
! 407: vaddr = _vaddr;
1.1 root 408:
1.1.1.3 ! root 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,
1.1.1.2 root 431: mmu_idx, TARGET_PAGE_SIZE);
1.1.1.3 ! root 432:
1.1.1.2 root 433: return 0;
1.1 root 434: }
1.1.1.3 ! root 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:
1.1 root 627: #endif /* CONFIG_USER_ONLY */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.