Annotation of qemu/target-s390x/helper.c, revision 1.1.1.4

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.