110ec5117SAlexander Graf /* 210ec5117SAlexander Graf * S/390 helpers 310ec5117SAlexander Graf * 410ec5117SAlexander Graf * Copyright (c) 2009 Ulrich Hecht 5d5a43964SAlexander Graf * Copyright (c) 2011 Alexander Graf 610ec5117SAlexander Graf * 710ec5117SAlexander Graf * This library is free software; you can redistribute it and/or 810ec5117SAlexander Graf * modify it under the terms of the GNU Lesser General Public 910ec5117SAlexander Graf * License as published by the Free Software Foundation; either 1010ec5117SAlexander Graf * version 2 of the License, or (at your option) any later version. 1110ec5117SAlexander Graf * 1210ec5117SAlexander Graf * This library is distributed in the hope that it will be useful, 1310ec5117SAlexander Graf * but WITHOUT ANY WARRANTY; without even the implied warranty of 1410ec5117SAlexander Graf * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1510ec5117SAlexander Graf * Lesser General Public License for more details. 1610ec5117SAlexander Graf * 1710ec5117SAlexander Graf * You should have received a copy of the GNU Lesser General Public 1870539e18SBlue Swirl * License along with this library; if not, see <http://www.gnu.org/licenses/>. 1910ec5117SAlexander Graf */ 2010ec5117SAlexander Graf 219615495aSPeter Maydell #include "qemu/osdep.h" 22da34e65cSMarkus Armbruster #include "qapi/error.h" 2310ec5117SAlexander Graf #include "cpu.h" 24022c62cbSPaolo Bonzini #include "exec/gdbstub.h" 251de7afc9SPaolo Bonzini #include "qemu/timer.h" 2663c91552SPaolo Bonzini #include "exec/exec-all.h" 27f08b6170SPaolo Bonzini #include "exec/cpu_ldst.h" 28bd3f16acSPaolo Bonzini #include "hw/s390x/ioinst.h" 29ef81522bSAlexander Graf #ifndef CONFIG_USER_ONLY 309c17d615SPaolo Bonzini #include "sysemu/sysemu.h" 31ef81522bSAlexander Graf #endif 3210ec5117SAlexander Graf 33d5a43964SAlexander Graf //#define DEBUG_S390 34d5a43964SAlexander Graf //#define DEBUG_S390_STDOUT 35d5a43964SAlexander Graf 36d5a43964SAlexander Graf #ifdef DEBUG_S390 37d5a43964SAlexander Graf #ifdef DEBUG_S390_STDOUT 38d5a43964SAlexander Graf #define DPRINTF(fmt, ...) \ 39d5a43964SAlexander Graf do { fprintf(stderr, fmt, ## __VA_ARGS__); \ 40013a2942SPaolo Bonzini if (qemu_log_separate()) qemu_log(fmt, ##__VA_ARGS__); } while (0) 41d5a43964SAlexander Graf #else 42d5a43964SAlexander Graf #define DPRINTF(fmt, ...) \ 43d5a43964SAlexander Graf do { qemu_log(fmt, ## __VA_ARGS__); } while (0) 44d5a43964SAlexander Graf #endif 45d5a43964SAlexander Graf #else 46d5a43964SAlexander Graf #define DPRINTF(fmt, ...) \ 47d5a43964SAlexander Graf do { } while (0) 48d5a43964SAlexander Graf #endif 49d5a43964SAlexander Graf 50d5a43964SAlexander Graf 51d5a43964SAlexander Graf #ifndef CONFIG_USER_ONLY 528f22e0dfSAndreas Färber void s390x_tod_timer(void *opaque) 53d5a43964SAlexander Graf { 54b8ba6799SAndreas Färber S390CPU *cpu = opaque; 55b8ba6799SAndreas Färber CPUS390XState *env = &cpu->env; 56d5a43964SAlexander Graf 57d5a43964SAlexander Graf env->pending_int |= INTERRUPT_TOD; 58c3affe56SAndreas Färber cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 59d5a43964SAlexander Graf } 60d5a43964SAlexander Graf 618f22e0dfSAndreas Färber void s390x_cpu_timer(void *opaque) 62d5a43964SAlexander Graf { 63b8ba6799SAndreas Färber S390CPU *cpu = opaque; 64b8ba6799SAndreas Färber CPUS390XState *env = &cpu->env; 65d5a43964SAlexander Graf 66d5a43964SAlexander Graf env->pending_int |= INTERRUPT_CPUTIMER; 67c3affe56SAndreas Färber cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD); 68d5a43964SAlexander Graf } 69d5a43964SAlexander Graf #endif 7010c339a0SAlexander Graf 7196b1a8bbSMatthew Rosato S390CPU *cpu_s390x_create(const char *cpu_model, Error **errp) 7210ec5117SAlexander Graf { 7341868f84SDavid Hildenbrand static bool features_parsed; 7441868f84SDavid Hildenbrand char *name, *features; 7541868f84SDavid Hildenbrand const char *typename; 7641868f84SDavid Hildenbrand ObjectClass *oc; 7741868f84SDavid Hildenbrand CPUClass *cc; 7841868f84SDavid Hildenbrand 7941868f84SDavid Hildenbrand name = g_strdup(cpu_model); 8041868f84SDavid Hildenbrand features = strchr(name, ','); 8141868f84SDavid Hildenbrand if (features) { 8241868f84SDavid Hildenbrand features[0] = 0; 8341868f84SDavid Hildenbrand features++; 8441868f84SDavid Hildenbrand } 8541868f84SDavid Hildenbrand 8641868f84SDavid Hildenbrand oc = cpu_class_by_name(TYPE_S390_CPU, name); 8741868f84SDavid Hildenbrand if (!oc) { 8841868f84SDavid Hildenbrand error_setg(errp, "Unknown CPU definition \'%s\'", name); 8941868f84SDavid Hildenbrand g_free(name); 9041868f84SDavid Hildenbrand return NULL; 9141868f84SDavid Hildenbrand } 9241868f84SDavid Hildenbrand typename = object_class_get_name(oc); 9341868f84SDavid Hildenbrand 9441868f84SDavid Hildenbrand if (!features_parsed) { 9541868f84SDavid Hildenbrand features_parsed = true; 9641868f84SDavid Hildenbrand cc = CPU_CLASS(oc); 9741868f84SDavid Hildenbrand cc->parse_features(typename, features, errp); 9841868f84SDavid Hildenbrand } 9941868f84SDavid Hildenbrand g_free(name); 10041868f84SDavid Hildenbrand 10141868f84SDavid Hildenbrand if (*errp) { 10241868f84SDavid Hildenbrand return NULL; 10341868f84SDavid Hildenbrand } 10441868f84SDavid Hildenbrand return S390_CPU(CPU(object_new(typename))); 10596b1a8bbSMatthew Rosato } 1061f136632SAndreas Färber 10796b1a8bbSMatthew Rosato S390CPU *s390x_new_cpu(const char *cpu_model, int64_t id, Error **errp) 10896b1a8bbSMatthew Rosato { 10996b1a8bbSMatthew Rosato S390CPU *cpu; 11096b1a8bbSMatthew Rosato Error *err = NULL; 11196b1a8bbSMatthew Rosato 11296b1a8bbSMatthew Rosato cpu = cpu_s390x_create(cpu_model, &err); 11396b1a8bbSMatthew Rosato if (err != NULL) { 11496b1a8bbSMatthew Rosato goto out; 11596b1a8bbSMatthew Rosato } 11696b1a8bbSMatthew Rosato 11796b1a8bbSMatthew Rosato object_property_set_int(OBJECT(cpu), id, "id", &err); 11896b1a8bbSMatthew Rosato if (err != NULL) { 11996b1a8bbSMatthew Rosato goto out; 12096b1a8bbSMatthew Rosato } 12196b1a8bbSMatthew Rosato object_property_set_bool(OBJECT(cpu), true, "realized", &err); 12296b1a8bbSMatthew Rosato 12396b1a8bbSMatthew Rosato out: 12496b1a8bbSMatthew Rosato if (err) { 12596b1a8bbSMatthew Rosato error_propagate(errp, err); 12696b1a8bbSMatthew Rosato object_unref(OBJECT(cpu)); 12796b1a8bbSMatthew Rosato cpu = NULL; 12896b1a8bbSMatthew Rosato } 12996b1a8bbSMatthew Rosato return cpu; 13096b1a8bbSMatthew Rosato } 13196b1a8bbSMatthew Rosato 13296b1a8bbSMatthew Rosato S390CPU *cpu_s390x_init(const char *cpu_model) 13396b1a8bbSMatthew Rosato { 13496b1a8bbSMatthew Rosato Error *err = NULL; 13596b1a8bbSMatthew Rosato S390CPU *cpu; 13696b1a8bbSMatthew Rosato /* Use to track CPU ID for linux-user only */ 13796b1a8bbSMatthew Rosato static int64_t next_cpu_id; 13896b1a8bbSMatthew Rosato 13996b1a8bbSMatthew Rosato cpu = s390x_new_cpu(cpu_model, next_cpu_id++, &err); 14096b1a8bbSMatthew Rosato if (err) { 14196b1a8bbSMatthew Rosato error_report_err(err); 14296b1a8bbSMatthew Rosato } 143564b863dSAndreas Färber return cpu; 14410ec5117SAlexander Graf } 14510ec5117SAlexander Graf 146d5a43964SAlexander Graf #if defined(CONFIG_USER_ONLY) 147d5a43964SAlexander Graf 14897a8ea5aSAndreas Färber void s390_cpu_do_interrupt(CPUState *cs) 149d5a43964SAlexander Graf { 15027103424SAndreas Färber cs->exception_index = -1; 151d5a43964SAlexander Graf } 152d5a43964SAlexander Graf 1537510454eSAndreas Färber int s390_cpu_handle_mmu_fault(CPUState *cs, vaddr address, 15471e47088SBlue Swirl int rw, int mmu_idx) 155d5a43964SAlexander Graf { 1567510454eSAndreas Färber S390CPU *cpu = S390_CPU(cs); 1577510454eSAndreas Färber 15827103424SAndreas Färber cs->exception_index = EXCP_PGM; 1597510454eSAndreas Färber cpu->env.int_pgm_code = PGM_ADDRESSING; 160d5a103cdSRichard Henderson /* On real machines this value is dropped into LowMem. Since this 161d5a103cdSRichard Henderson is userland, simply put this someplace that cpu_loop can find it. */ 1627510454eSAndreas Färber cpu->env.__excp_addr = address; 163d5a43964SAlexander Graf return 1; 164d5a43964SAlexander Graf } 165d5a43964SAlexander Graf 166b7e516ceSAndreas Färber #else /* !CONFIG_USER_ONLY */ 16710c339a0SAlexander Graf 168d5a43964SAlexander Graf /* Ensure to exit the TB after this call! */ 169dfebd7a7SThomas Huth void trigger_pgm_exception(CPUS390XState *env, uint32_t code, uint32_t ilen) 17010c339a0SAlexander Graf { 17127103424SAndreas Färber CPUState *cs = CPU(s390_env_get_cpu(env)); 17227103424SAndreas Färber 17327103424SAndreas Färber cs->exception_index = EXCP_PGM; 174d5a43964SAlexander Graf env->int_pgm_code = code; 175d5a103cdSRichard Henderson env->int_pgm_ilen = ilen; 176d5a43964SAlexander Graf } 17710c339a0SAlexander Graf 1787510454eSAndreas Färber int s390_cpu_handle_mmu_fault(CPUState *cs, vaddr orig_vaddr, 17971e47088SBlue Swirl int rw, int mmu_idx) 180d5a43964SAlexander Graf { 1817510454eSAndreas Färber S390CPU *cpu = S390_CPU(cs); 1827510454eSAndreas Färber CPUS390XState *env = &cpu->env; 183c255ac60SAurelien Jarno uint64_t asc = cpu_mmu_idx_to_asc(mmu_idx); 184d5a43964SAlexander Graf target_ulong vaddr, raddr; 185d5a43964SAlexander Graf int prot; 186d5a43964SAlexander Graf 1877510454eSAndreas Färber DPRINTF("%s: address 0x%" VADDR_PRIx " rw %d mmu_idx %d\n", 18807cc7d12SAndreas Färber __func__, orig_vaddr, rw, mmu_idx); 189d5a43964SAlexander Graf 19071e47088SBlue Swirl orig_vaddr &= TARGET_PAGE_MASK; 19171e47088SBlue Swirl vaddr = orig_vaddr; 192d5a43964SAlexander Graf 193d5a43964SAlexander Graf /* 31-Bit mode */ 194d5a43964SAlexander Graf if (!(env->psw.mask & PSW_MASK_64)) { 195d5a43964SAlexander Graf vaddr &= 0x7fffffff; 196d5a43964SAlexander Graf } 197d5a43964SAlexander Graf 198e3e09d87SThomas Huth if (mmu_translate(env, vaddr, rw, asc, &raddr, &prot, true)) { 199d5a43964SAlexander Graf /* Translation ended in exception */ 200d5a43964SAlexander Graf return 1; 201d5a43964SAlexander Graf } 202d5a43964SAlexander Graf 203d5a43964SAlexander Graf /* check out of RAM access */ 2047b3fdbd9SPierre Morel if (raddr > ram_size) { 205a6f921b0SAndreas Färber DPRINTF("%s: raddr %" PRIx64 " > ram_size %" PRIx64 "\n", __func__, 206a6f921b0SAndreas Färber (uint64_t)raddr, (uint64_t)ram_size); 207becf8217SDavid Hildenbrand trigger_pgm_exception(env, PGM_ADDRESSING, ILEN_AUTO); 208d5a43964SAlexander Graf return 1; 209d5a43964SAlexander Graf } 210d5a43964SAlexander Graf 211339aaf5bSAntony Pavlov qemu_log_mask(CPU_LOG_MMU, "%s: set tlb %" PRIx64 " -> %" PRIx64 " (%x)\n", 212339aaf5bSAntony Pavlov __func__, (uint64_t)vaddr, (uint64_t)raddr, prot); 213d5a43964SAlexander Graf 2140c591eb0SAndreas Färber tlb_set_page(cs, orig_vaddr, raddr, prot, 215d5a43964SAlexander Graf mmu_idx, TARGET_PAGE_SIZE); 216d5a43964SAlexander Graf 217d5a43964SAlexander Graf return 0; 218d5a43964SAlexander Graf } 219d5a43964SAlexander Graf 22000b941e5SAndreas Färber hwaddr s390_cpu_get_phys_page_debug(CPUState *cs, vaddr vaddr) 221d5a43964SAlexander Graf { 22200b941e5SAndreas Färber S390CPU *cpu = S390_CPU(cs); 22300b941e5SAndreas Färber CPUS390XState *env = &cpu->env; 224d5a43964SAlexander Graf target_ulong raddr; 225e3e09d87SThomas Huth int prot; 226d5a43964SAlexander Graf uint64_t asc = env->psw.mask & PSW_MASK_ASC; 227d5a43964SAlexander Graf 228d5a43964SAlexander Graf /* 31-Bit mode */ 229d5a43964SAlexander Graf if (!(env->psw.mask & PSW_MASK_64)) { 230d5a43964SAlexander Graf vaddr &= 0x7fffffff; 231d5a43964SAlexander Graf } 232d5a43964SAlexander Graf 233234779a2SDavid Hildenbrand if (mmu_translate(env, vaddr, MMU_INST_FETCH, asc, &raddr, &prot, false)) { 234234779a2SDavid Hildenbrand return -1; 235234779a2SDavid Hildenbrand } 236d5a43964SAlexander Graf return raddr; 237d5a43964SAlexander Graf } 238d5a43964SAlexander Graf 239770a6379SDavid Hildenbrand hwaddr s390_cpu_get_phys_addr_debug(CPUState *cs, vaddr vaddr) 240770a6379SDavid Hildenbrand { 241770a6379SDavid Hildenbrand hwaddr phys_addr; 242770a6379SDavid Hildenbrand target_ulong page; 243770a6379SDavid Hildenbrand 244770a6379SDavid Hildenbrand page = vaddr & TARGET_PAGE_MASK; 245770a6379SDavid Hildenbrand phys_addr = cpu_get_phys_page_debug(cs, page); 246770a6379SDavid Hildenbrand phys_addr += (vaddr & ~TARGET_PAGE_MASK); 247770a6379SDavid Hildenbrand 248770a6379SDavid Hildenbrand return phys_addr; 249770a6379SDavid Hildenbrand } 250770a6379SDavid Hildenbrand 251a4e3ad19SAndreas Färber void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr) 252d5a43964SAlexander Graf { 253311918b9SAurelien Jarno uint64_t old_mask = env->psw.mask; 254311918b9SAurelien Jarno 255eb24f7c6SDavid Hildenbrand env->psw.addr = addr; 256eb24f7c6SDavid Hildenbrand env->psw.mask = mask; 2573f10341fSDavid Hildenbrand if (tcg_enabled()) { 258eb24f7c6SDavid Hildenbrand env->cc_op = (mask >> 44) & 3; 2593f10341fSDavid Hildenbrand } 260eb24f7c6SDavid Hildenbrand 261311918b9SAurelien Jarno if ((old_mask ^ mask) & PSW_MASK_PER) { 262311918b9SAurelien Jarno s390_cpu_recompute_watchpoints(CPU(s390_env_get_cpu(env))); 263311918b9SAurelien Jarno } 264311918b9SAurelien Jarno 265d5a43964SAlexander Graf if (mask & PSW_MASK_WAIT) { 26649e15878SAndreas Färber S390CPU *cpu = s390_env_get_cpu(env); 267eb24f7c6SDavid Hildenbrand if (s390_cpu_halt(cpu) == 0) { 268ef81522bSAlexander Graf #ifndef CONFIG_USER_ONLY 269cf83f140SEric Blake qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); 270ef81522bSAlexander Graf #endif 271ef81522bSAlexander Graf } 272ef81522bSAlexander Graf } 273d5a43964SAlexander Graf } 274d5a43964SAlexander Graf 275a4e3ad19SAndreas Färber static uint64_t get_psw_mask(CPUS390XState *env) 276d5a43964SAlexander Graf { 2773f10341fSDavid Hildenbrand uint64_t r = env->psw.mask; 278d5a43964SAlexander Graf 2793f10341fSDavid Hildenbrand if (tcg_enabled()) { 2803f10341fSDavid Hildenbrand env->cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst, 2813f10341fSDavid Hildenbrand env->cc_vr); 282d5a43964SAlexander Graf 28351855ecfSRichard Henderson r &= ~PSW_MASK_CC; 284d5a43964SAlexander Graf assert(!(env->cc_op & ~3)); 28551855ecfSRichard Henderson r |= (uint64_t)env->cc_op << 44; 2863f10341fSDavid Hildenbrand } 287d5a43964SAlexander Graf 288d5a43964SAlexander Graf return r; 289d5a43964SAlexander Graf } 290d5a43964SAlexander Graf 2914782a23bSCornelia Huck static LowCore *cpu_map_lowcore(CPUS390XState *env) 2924782a23bSCornelia Huck { 293a47dddd7SAndreas Färber S390CPU *cpu = s390_env_get_cpu(env); 2944782a23bSCornelia Huck LowCore *lowcore; 2954782a23bSCornelia Huck hwaddr len = sizeof(LowCore); 2964782a23bSCornelia Huck 2974782a23bSCornelia Huck lowcore = cpu_physical_memory_map(env->psa, &len, 1); 2984782a23bSCornelia Huck 2994782a23bSCornelia Huck if (len < sizeof(LowCore)) { 300a47dddd7SAndreas Färber cpu_abort(CPU(cpu), "Could not map lowcore\n"); 3014782a23bSCornelia Huck } 3024782a23bSCornelia Huck 3034782a23bSCornelia Huck return lowcore; 3044782a23bSCornelia Huck } 3054782a23bSCornelia Huck 3064782a23bSCornelia Huck static void cpu_unmap_lowcore(LowCore *lowcore) 3074782a23bSCornelia Huck { 3084782a23bSCornelia Huck cpu_physical_memory_unmap(lowcore, sizeof(LowCore), 1, sizeof(LowCore)); 3094782a23bSCornelia Huck } 3104782a23bSCornelia Huck 3113f10341fSDavid Hildenbrand void do_restart_interrupt(CPUS390XState *env) 3123f10341fSDavid Hildenbrand { 3133f10341fSDavid Hildenbrand uint64_t mask, addr; 3143f10341fSDavid Hildenbrand LowCore *lowcore; 3153f10341fSDavid Hildenbrand 3163f10341fSDavid Hildenbrand lowcore = cpu_map_lowcore(env); 3173f10341fSDavid Hildenbrand 3183f10341fSDavid Hildenbrand lowcore->restart_old_psw.mask = cpu_to_be64(get_psw_mask(env)); 3193f10341fSDavid Hildenbrand lowcore->restart_old_psw.addr = cpu_to_be64(env->psw.addr); 3203f10341fSDavid Hildenbrand mask = be64_to_cpu(lowcore->restart_new_psw.mask); 3213f10341fSDavid Hildenbrand addr = be64_to_cpu(lowcore->restart_new_psw.addr); 3223f10341fSDavid Hildenbrand 3233f10341fSDavid Hildenbrand cpu_unmap_lowcore(lowcore); 3243f10341fSDavid Hildenbrand 3253f10341fSDavid Hildenbrand load_psw(env, mask, addr); 3263f10341fSDavid Hildenbrand } 3273f10341fSDavid Hildenbrand 328a4e3ad19SAndreas Färber static void do_program_interrupt(CPUS390XState *env) 329d5a43964SAlexander Graf { 330d5a43964SAlexander Graf uint64_t mask, addr; 331d5a43964SAlexander Graf LowCore *lowcore; 332d5a103cdSRichard Henderson int ilen = env->int_pgm_ilen; 333d5a43964SAlexander Graf 334becf8217SDavid Hildenbrand if (ilen == ILEN_AUTO) { 335d5a103cdSRichard Henderson ilen = get_ilen(cpu_ldub_code(env, env->psw.addr)); 336becf8217SDavid Hildenbrand } 337becf8217SDavid Hildenbrand assert(ilen == 2 || ilen == 4 || ilen == 6); 338becf8217SDavid Hildenbrand 339becf8217SDavid Hildenbrand switch (env->int_pgm_code) { 340becf8217SDavid Hildenbrand case PGM_PER: 341becf8217SDavid Hildenbrand if (env->per_perc_atmid & PER_CODE_EVENT_NULLIFICATION) { 342d5a43964SAlexander Graf break; 343becf8217SDavid Hildenbrand } 344becf8217SDavid Hildenbrand /* FALL THROUGH */ 345becf8217SDavid Hildenbrand case PGM_OPERATION: 346becf8217SDavid Hildenbrand case PGM_PRIVILEGED: 347becf8217SDavid Hildenbrand case PGM_EXECUTE: 348becf8217SDavid Hildenbrand case PGM_PROTECTION: 349becf8217SDavid Hildenbrand case PGM_ADDRESSING: 350becf8217SDavid Hildenbrand case PGM_SPECIFICATION: 351becf8217SDavid Hildenbrand case PGM_DATA: 352becf8217SDavid Hildenbrand case PGM_FIXPT_OVERFLOW: 353becf8217SDavid Hildenbrand case PGM_FIXPT_DIVIDE: 354becf8217SDavid Hildenbrand case PGM_DEC_OVERFLOW: 355becf8217SDavid Hildenbrand case PGM_DEC_DIVIDE: 356becf8217SDavid Hildenbrand case PGM_HFP_EXP_OVERFLOW: 357becf8217SDavid Hildenbrand case PGM_HFP_EXP_UNDERFLOW: 358becf8217SDavid Hildenbrand case PGM_HFP_SIGNIFICANCE: 359becf8217SDavid Hildenbrand case PGM_HFP_DIVIDE: 360becf8217SDavid Hildenbrand case PGM_TRANS_SPEC: 361becf8217SDavid Hildenbrand case PGM_SPECIAL_OP: 362becf8217SDavid Hildenbrand case PGM_OPERAND: 363becf8217SDavid Hildenbrand case PGM_HFP_SQRT: 364becf8217SDavid Hildenbrand case PGM_PC_TRANS_SPEC: 365becf8217SDavid Hildenbrand case PGM_ALET_SPEC: 366becf8217SDavid Hildenbrand case PGM_MONITOR: 367becf8217SDavid Hildenbrand /* advance the PSW if our exception is not nullifying */ 368d5a103cdSRichard Henderson env->psw.addr += ilen; 369d5a43964SAlexander Graf break; 370d5a43964SAlexander Graf } 371d5a43964SAlexander Graf 372d5a103cdSRichard Henderson qemu_log_mask(CPU_LOG_INT, "%s: code=0x%x ilen=%d\n", 373d5a103cdSRichard Henderson __func__, env->int_pgm_code, ilen); 374d5a43964SAlexander Graf 3754782a23bSCornelia Huck lowcore = cpu_map_lowcore(env); 376d5a43964SAlexander Graf 377777c98c3SAurelien Jarno /* Signal PER events with the exception. */ 378777c98c3SAurelien Jarno if (env->per_perc_atmid) { 379777c98c3SAurelien Jarno env->int_pgm_code |= PGM_PER; 380777c98c3SAurelien Jarno lowcore->per_address = cpu_to_be64(env->per_address); 381777c98c3SAurelien Jarno lowcore->per_perc_atmid = cpu_to_be16(env->per_perc_atmid); 382777c98c3SAurelien Jarno env->per_perc_atmid = 0; 383777c98c3SAurelien Jarno } 384777c98c3SAurelien Jarno 385d5a103cdSRichard Henderson lowcore->pgm_ilen = cpu_to_be16(ilen); 386d5a43964SAlexander Graf lowcore->pgm_code = cpu_to_be16(env->int_pgm_code); 387d5a43964SAlexander Graf lowcore->program_old_psw.mask = cpu_to_be64(get_psw_mask(env)); 388d5a43964SAlexander Graf lowcore->program_old_psw.addr = cpu_to_be64(env->psw.addr); 389d5a43964SAlexander Graf mask = be64_to_cpu(lowcore->program_new_psw.mask); 390d5a43964SAlexander Graf addr = be64_to_cpu(lowcore->program_new_psw.addr); 3913da0ab35SAurelien Jarno lowcore->per_breaking_event_addr = cpu_to_be64(env->gbea); 392d5a43964SAlexander Graf 3934782a23bSCornelia Huck cpu_unmap_lowcore(lowcore); 394d5a43964SAlexander Graf 39571e47088SBlue Swirl DPRINTF("%s: %x %x %" PRIx64 " %" PRIx64 "\n", __func__, 396d5a103cdSRichard Henderson env->int_pgm_code, ilen, env->psw.mask, 397d5a43964SAlexander Graf env->psw.addr); 398d5a43964SAlexander Graf 399d5a43964SAlexander Graf load_psw(env, mask, addr); 400d5a43964SAlexander Graf } 401d5a43964SAlexander Graf 402777c98c3SAurelien Jarno static void do_svc_interrupt(CPUS390XState *env) 403777c98c3SAurelien Jarno { 404777c98c3SAurelien Jarno uint64_t mask, addr; 405777c98c3SAurelien Jarno LowCore *lowcore; 406777c98c3SAurelien Jarno 407777c98c3SAurelien Jarno lowcore = cpu_map_lowcore(env); 408777c98c3SAurelien Jarno 409777c98c3SAurelien Jarno lowcore->svc_code = cpu_to_be16(env->int_svc_code); 410777c98c3SAurelien Jarno lowcore->svc_ilen = cpu_to_be16(env->int_svc_ilen); 411777c98c3SAurelien Jarno lowcore->svc_old_psw.mask = cpu_to_be64(get_psw_mask(env)); 412777c98c3SAurelien Jarno lowcore->svc_old_psw.addr = cpu_to_be64(env->psw.addr + env->int_svc_ilen); 413777c98c3SAurelien Jarno mask = be64_to_cpu(lowcore->svc_new_psw.mask); 414777c98c3SAurelien Jarno addr = be64_to_cpu(lowcore->svc_new_psw.addr); 415777c98c3SAurelien Jarno 416777c98c3SAurelien Jarno cpu_unmap_lowcore(lowcore); 417777c98c3SAurelien Jarno 418777c98c3SAurelien Jarno load_psw(env, mask, addr); 419777c98c3SAurelien Jarno 420777c98c3SAurelien Jarno /* When a PER event is pending, the PER exception has to happen 421777c98c3SAurelien Jarno immediately after the SERVICE CALL one. */ 422777c98c3SAurelien Jarno if (env->per_perc_atmid) { 423777c98c3SAurelien Jarno env->int_pgm_code = PGM_PER; 424777c98c3SAurelien Jarno env->int_pgm_ilen = env->int_svc_ilen; 425777c98c3SAurelien Jarno do_program_interrupt(env); 426777c98c3SAurelien Jarno } 427777c98c3SAurelien Jarno } 428777c98c3SAurelien Jarno 429d5a43964SAlexander Graf #define VIRTIO_SUBCODE_64 0x0D00 430d5a43964SAlexander Graf 431a4e3ad19SAndreas Färber static void do_ext_interrupt(CPUS390XState *env) 432d5a43964SAlexander Graf { 433a47dddd7SAndreas Färber S390CPU *cpu = s390_env_get_cpu(env); 434d5a43964SAlexander Graf uint64_t mask, addr; 435d5a43964SAlexander Graf LowCore *lowcore; 436d5a43964SAlexander Graf ExtQueue *q; 437d5a43964SAlexander Graf 438d5a43964SAlexander Graf if (!(env->psw.mask & PSW_MASK_EXT)) { 439a47dddd7SAndreas Färber cpu_abort(CPU(cpu), "Ext int w/o ext mask\n"); 440d5a43964SAlexander Graf } 441d5a43964SAlexander Graf 4421a719923Szhanghailiang if (env->ext_index < 0 || env->ext_index >= MAX_EXT_QUEUE) { 443a47dddd7SAndreas Färber cpu_abort(CPU(cpu), "Ext queue overrun: %d\n", env->ext_index); 444d5a43964SAlexander Graf } 445d5a43964SAlexander Graf 446d5a43964SAlexander Graf q = &env->ext_queue[env->ext_index]; 4474782a23bSCornelia Huck lowcore = cpu_map_lowcore(env); 448d5a43964SAlexander Graf 449d5a43964SAlexander Graf lowcore->ext_int_code = cpu_to_be16(q->code); 450d5a43964SAlexander Graf lowcore->ext_params = cpu_to_be32(q->param); 451d5a43964SAlexander Graf lowcore->ext_params2 = cpu_to_be64(q->param64); 452d5a43964SAlexander Graf lowcore->external_old_psw.mask = cpu_to_be64(get_psw_mask(env)); 453d5a43964SAlexander Graf lowcore->external_old_psw.addr = cpu_to_be64(env->psw.addr); 454d5a43964SAlexander Graf lowcore->cpu_addr = cpu_to_be16(env->cpu_num | VIRTIO_SUBCODE_64); 455d5a43964SAlexander Graf mask = be64_to_cpu(lowcore->external_new_psw.mask); 456d5a43964SAlexander Graf addr = be64_to_cpu(lowcore->external_new_psw.addr); 457d5a43964SAlexander Graf 4584782a23bSCornelia Huck cpu_unmap_lowcore(lowcore); 459d5a43964SAlexander Graf 460d5a43964SAlexander Graf env->ext_index--; 461d5a43964SAlexander Graf if (env->ext_index == -1) { 462d5a43964SAlexander Graf env->pending_int &= ~INTERRUPT_EXT; 463d5a43964SAlexander Graf } 464d5a43964SAlexander Graf 46571e47088SBlue Swirl DPRINTF("%s: %" PRIx64 " %" PRIx64 "\n", __func__, 466d5a43964SAlexander Graf env->psw.mask, env->psw.addr); 467d5a43964SAlexander Graf 468d5a43964SAlexander Graf load_psw(env, mask, addr); 469d5a43964SAlexander Graf } 4703110e292SAlexander Graf 4715d69c547SCornelia Huck static void do_io_interrupt(CPUS390XState *env) 4725d69c547SCornelia Huck { 473a47dddd7SAndreas Färber S390CPU *cpu = s390_env_get_cpu(env); 4745d69c547SCornelia Huck LowCore *lowcore; 4755d69c547SCornelia Huck IOIntQueue *q; 4765d69c547SCornelia Huck uint8_t isc; 4775d69c547SCornelia Huck int disable = 1; 4785d69c547SCornelia Huck int found = 0; 4795d69c547SCornelia Huck 4805d69c547SCornelia Huck if (!(env->psw.mask & PSW_MASK_IO)) { 481a47dddd7SAndreas Färber cpu_abort(CPU(cpu), "I/O int w/o I/O mask\n"); 4825d69c547SCornelia Huck } 4835d69c547SCornelia Huck 4845d69c547SCornelia Huck for (isc = 0; isc < ARRAY_SIZE(env->io_index); isc++) { 48591b0a8f3SCornelia Huck uint64_t isc_bits; 48691b0a8f3SCornelia Huck 4875d69c547SCornelia Huck if (env->io_index[isc] < 0) { 4885d69c547SCornelia Huck continue; 4895d69c547SCornelia Huck } 4901a719923Szhanghailiang if (env->io_index[isc] >= MAX_IO_QUEUE) { 491a47dddd7SAndreas Färber cpu_abort(CPU(cpu), "I/O queue overrun for isc %d: %d\n", 4925d69c547SCornelia Huck isc, env->io_index[isc]); 4935d69c547SCornelia Huck } 4945d69c547SCornelia Huck 4955d69c547SCornelia Huck q = &env->io_queue[env->io_index[isc]][isc]; 49691b0a8f3SCornelia Huck isc_bits = ISC_TO_ISC_BITS(IO_INT_WORD_ISC(q->word)); 49791b0a8f3SCornelia Huck if (!(env->cregs[6] & isc_bits)) { 4985d69c547SCornelia Huck disable = 0; 4995d69c547SCornelia Huck continue; 5005d69c547SCornelia Huck } 501bd9a8d85SCornelia Huck if (!found) { 502bd9a8d85SCornelia Huck uint64_t mask, addr; 503bd9a8d85SCornelia Huck 5045d69c547SCornelia Huck found = 1; 5055d69c547SCornelia Huck lowcore = cpu_map_lowcore(env); 5065d69c547SCornelia Huck 5075d69c547SCornelia Huck lowcore->subchannel_id = cpu_to_be16(q->id); 5085d69c547SCornelia Huck lowcore->subchannel_nr = cpu_to_be16(q->nr); 5095d69c547SCornelia Huck lowcore->io_int_parm = cpu_to_be32(q->parm); 5105d69c547SCornelia Huck lowcore->io_int_word = cpu_to_be32(q->word); 5115d69c547SCornelia Huck lowcore->io_old_psw.mask = cpu_to_be64(get_psw_mask(env)); 5125d69c547SCornelia Huck lowcore->io_old_psw.addr = cpu_to_be64(env->psw.addr); 5135d69c547SCornelia Huck mask = be64_to_cpu(lowcore->io_new_psw.mask); 5145d69c547SCornelia Huck addr = be64_to_cpu(lowcore->io_new_psw.addr); 5155d69c547SCornelia Huck 5165d69c547SCornelia Huck cpu_unmap_lowcore(lowcore); 5175d69c547SCornelia Huck 5185d69c547SCornelia Huck env->io_index[isc]--; 519bd9a8d85SCornelia Huck 520bd9a8d85SCornelia Huck DPRINTF("%s: %" PRIx64 " %" PRIx64 "\n", __func__, 521bd9a8d85SCornelia Huck env->psw.mask, env->psw.addr); 522bd9a8d85SCornelia Huck load_psw(env, mask, addr); 523bd9a8d85SCornelia Huck } 524b22dd124SStefan Weil if (env->io_index[isc] >= 0) { 5255d69c547SCornelia Huck disable = 0; 5265d69c547SCornelia Huck } 527bd9a8d85SCornelia Huck continue; 5285d69c547SCornelia Huck } 5295d69c547SCornelia Huck 5305d69c547SCornelia Huck if (disable) { 5315d69c547SCornelia Huck env->pending_int &= ~INTERRUPT_IO; 5325d69c547SCornelia Huck } 5335d69c547SCornelia Huck 5345d69c547SCornelia Huck } 5355d69c547SCornelia Huck 5365d69c547SCornelia Huck static void do_mchk_interrupt(CPUS390XState *env) 5375d69c547SCornelia Huck { 538a47dddd7SAndreas Färber S390CPU *cpu = s390_env_get_cpu(env); 5395d69c547SCornelia Huck uint64_t mask, addr; 5405d69c547SCornelia Huck LowCore *lowcore; 5415d69c547SCornelia Huck MchkQueue *q; 5425d69c547SCornelia Huck int i; 5435d69c547SCornelia Huck 5445d69c547SCornelia Huck if (!(env->psw.mask & PSW_MASK_MCHECK)) { 545a47dddd7SAndreas Färber cpu_abort(CPU(cpu), "Machine check w/o mchk mask\n"); 5465d69c547SCornelia Huck } 5475d69c547SCornelia Huck 5481a719923Szhanghailiang if (env->mchk_index < 0 || env->mchk_index >= MAX_MCHK_QUEUE) { 549a47dddd7SAndreas Färber cpu_abort(CPU(cpu), "Mchk queue overrun: %d\n", env->mchk_index); 5505d69c547SCornelia Huck } 5515d69c547SCornelia Huck 5525d69c547SCornelia Huck q = &env->mchk_queue[env->mchk_index]; 5535d69c547SCornelia Huck 5545d69c547SCornelia Huck if (q->type != 1) { 5555d69c547SCornelia Huck /* Don't know how to handle this... */ 556a47dddd7SAndreas Färber cpu_abort(CPU(cpu), "Unknown machine check type %d\n", q->type); 5575d69c547SCornelia Huck } 5585d69c547SCornelia Huck if (!(env->cregs[14] & (1 << 28))) { 5595d69c547SCornelia Huck /* CRW machine checks disabled */ 5605d69c547SCornelia Huck return; 5615d69c547SCornelia Huck } 5625d69c547SCornelia Huck 5635d69c547SCornelia Huck lowcore = cpu_map_lowcore(env); 5645d69c547SCornelia Huck 5655d69c547SCornelia Huck for (i = 0; i < 16; i++) { 566c498d8e3SEric Farman lowcore->floating_pt_save_area[i] = cpu_to_be64(get_freg(env, i)->ll); 5675d69c547SCornelia Huck lowcore->gpregs_save_area[i] = cpu_to_be64(env->regs[i]); 5685d69c547SCornelia Huck lowcore->access_regs_save_area[i] = cpu_to_be32(env->aregs[i]); 5695d69c547SCornelia Huck lowcore->cregs_save_area[i] = cpu_to_be64(env->cregs[i]); 5705d69c547SCornelia Huck } 5715d69c547SCornelia Huck lowcore->prefixreg_save_area = cpu_to_be32(env->psa); 5725d69c547SCornelia Huck lowcore->fpt_creg_save_area = cpu_to_be32(env->fpc); 5735d69c547SCornelia Huck lowcore->tod_progreg_save_area = cpu_to_be32(env->todpr); 5745d69c547SCornelia Huck lowcore->cpu_timer_save_area[0] = cpu_to_be32(env->cputm >> 32); 5755d69c547SCornelia Huck lowcore->cpu_timer_save_area[1] = cpu_to_be32((uint32_t)env->cputm); 5765d69c547SCornelia Huck lowcore->clock_comp_save_area[0] = cpu_to_be32(env->ckc >> 32); 5775d69c547SCornelia Huck lowcore->clock_comp_save_area[1] = cpu_to_be32((uint32_t)env->ckc); 5785d69c547SCornelia Huck 5795d69c547SCornelia Huck lowcore->mcck_interruption_code[0] = cpu_to_be32(0x00400f1d); 5805d69c547SCornelia Huck lowcore->mcck_interruption_code[1] = cpu_to_be32(0x40330000); 5815d69c547SCornelia Huck lowcore->mcck_old_psw.mask = cpu_to_be64(get_psw_mask(env)); 5825d69c547SCornelia Huck lowcore->mcck_old_psw.addr = cpu_to_be64(env->psw.addr); 5835d69c547SCornelia Huck mask = be64_to_cpu(lowcore->mcck_new_psw.mask); 5845d69c547SCornelia Huck addr = be64_to_cpu(lowcore->mcck_new_psw.addr); 5855d69c547SCornelia Huck 5865d69c547SCornelia Huck cpu_unmap_lowcore(lowcore); 5875d69c547SCornelia Huck 5885d69c547SCornelia Huck env->mchk_index--; 5895d69c547SCornelia Huck if (env->mchk_index == -1) { 5905d69c547SCornelia Huck env->pending_int &= ~INTERRUPT_MCHK; 5915d69c547SCornelia Huck } 5925d69c547SCornelia Huck 5935d69c547SCornelia Huck DPRINTF("%s: %" PRIx64 " %" PRIx64 "\n", __func__, 5945d69c547SCornelia Huck env->psw.mask, env->psw.addr); 5955d69c547SCornelia Huck 5965d69c547SCornelia Huck load_psw(env, mask, addr); 5975d69c547SCornelia Huck } 5985d69c547SCornelia Huck 59997a8ea5aSAndreas Färber void s390_cpu_do_interrupt(CPUState *cs) 6003110e292SAlexander Graf { 60197a8ea5aSAndreas Färber S390CPU *cpu = S390_CPU(cs); 60297a8ea5aSAndreas Färber CPUS390XState *env = &cpu->env; 603f9466733SAndreas Färber 6040d404541SRichard Henderson qemu_log_mask(CPU_LOG_INT, "%s: %d at pc=%" PRIx64 "\n", 60527103424SAndreas Färber __func__, cs->exception_index, env->psw.addr); 606d5a43964SAlexander Graf 607eb24f7c6SDavid Hildenbrand s390_cpu_set_state(CPU_STATE_OPERATING, cpu); 6085d69c547SCornelia Huck /* handle machine checks */ 6095d69c547SCornelia Huck if ((env->psw.mask & PSW_MASK_MCHECK) && 61027103424SAndreas Färber (cs->exception_index == -1)) { 6115d69c547SCornelia Huck if (env->pending_int & INTERRUPT_MCHK) { 61227103424SAndreas Färber cs->exception_index = EXCP_MCHK; 6135d69c547SCornelia Huck } 6145d69c547SCornelia Huck } 615d5a43964SAlexander Graf /* handle external interrupts */ 616d5a43964SAlexander Graf if ((env->psw.mask & PSW_MASK_EXT) && 61727103424SAndreas Färber cs->exception_index == -1) { 618d5a43964SAlexander Graf if (env->pending_int & INTERRUPT_EXT) { 619d5a43964SAlexander Graf /* code is already in env */ 62027103424SAndreas Färber cs->exception_index = EXCP_EXT; 621d5a43964SAlexander Graf } else if (env->pending_int & INTERRUPT_TOD) { 622f9466733SAndreas Färber cpu_inject_ext(cpu, 0x1004, 0, 0); 62327103424SAndreas Färber cs->exception_index = EXCP_EXT; 624d5a43964SAlexander Graf env->pending_int &= ~INTERRUPT_EXT; 625d5a43964SAlexander Graf env->pending_int &= ~INTERRUPT_TOD; 626d5a43964SAlexander Graf } else if (env->pending_int & INTERRUPT_CPUTIMER) { 627f9466733SAndreas Färber cpu_inject_ext(cpu, 0x1005, 0, 0); 62827103424SAndreas Färber cs->exception_index = EXCP_EXT; 629d5a43964SAlexander Graf env->pending_int &= ~INTERRUPT_EXT; 630d5a43964SAlexander Graf env->pending_int &= ~INTERRUPT_TOD; 6313110e292SAlexander Graf } 632d5a43964SAlexander Graf } 6335d69c547SCornelia Huck /* handle I/O interrupts */ 6345d69c547SCornelia Huck if ((env->psw.mask & PSW_MASK_IO) && 63527103424SAndreas Färber (cs->exception_index == -1)) { 6365d69c547SCornelia Huck if (env->pending_int & INTERRUPT_IO) { 63727103424SAndreas Färber cs->exception_index = EXCP_IO; 6385d69c547SCornelia Huck } 6395d69c547SCornelia Huck } 640d5a43964SAlexander Graf 64127103424SAndreas Färber switch (cs->exception_index) { 642d5a43964SAlexander Graf case EXCP_PGM: 643d5a43964SAlexander Graf do_program_interrupt(env); 644d5a43964SAlexander Graf break; 645d5a43964SAlexander Graf case EXCP_SVC: 646d5a43964SAlexander Graf do_svc_interrupt(env); 647d5a43964SAlexander Graf break; 648d5a43964SAlexander Graf case EXCP_EXT: 649d5a43964SAlexander Graf do_ext_interrupt(env); 650d5a43964SAlexander Graf break; 6515d69c547SCornelia Huck case EXCP_IO: 6525d69c547SCornelia Huck do_io_interrupt(env); 6535d69c547SCornelia Huck break; 6545d69c547SCornelia Huck case EXCP_MCHK: 6555d69c547SCornelia Huck do_mchk_interrupt(env); 6565d69c547SCornelia Huck break; 657d5a43964SAlexander Graf } 65827103424SAndreas Färber cs->exception_index = -1; 659d5a43964SAlexander Graf 660d5a43964SAlexander Graf if (!env->pending_int) { 661259186a7SAndreas Färber cs->interrupt_request &= ~CPU_INTERRUPT_HARD; 662d5a43964SAlexander Graf } 663d5a43964SAlexander Graf } 664d5a43964SAlexander Graf 66502bb9bbfSRichard Henderson bool s390_cpu_exec_interrupt(CPUState *cs, int interrupt_request) 66602bb9bbfSRichard Henderson { 66702bb9bbfSRichard Henderson if (interrupt_request & CPU_INTERRUPT_HARD) { 66802bb9bbfSRichard Henderson S390CPU *cpu = S390_CPU(cs); 66902bb9bbfSRichard Henderson CPUS390XState *env = &cpu->env; 67002bb9bbfSRichard Henderson 671303c681aSRichard Henderson if (env->ex_value) { 672303c681aSRichard Henderson /* Execution of the target insn is indivisible from 673303c681aSRichard Henderson the parent EXECUTE insn. */ 674303c681aSRichard Henderson return false; 675303c681aSRichard Henderson } 67602bb9bbfSRichard Henderson if (env->psw.mask & PSW_MASK_EXT) { 67702bb9bbfSRichard Henderson s390_cpu_do_interrupt(cs); 67802bb9bbfSRichard Henderson return true; 67902bb9bbfSRichard Henderson } 68002bb9bbfSRichard Henderson } 68102bb9bbfSRichard Henderson return false; 68202bb9bbfSRichard Henderson } 683311918b9SAurelien Jarno 684311918b9SAurelien Jarno void s390_cpu_recompute_watchpoints(CPUState *cs) 685311918b9SAurelien Jarno { 686311918b9SAurelien Jarno const int wp_flags = BP_CPU | BP_MEM_WRITE | BP_STOP_BEFORE_ACCESS; 687311918b9SAurelien Jarno S390CPU *cpu = S390_CPU(cs); 688311918b9SAurelien Jarno CPUS390XState *env = &cpu->env; 689311918b9SAurelien Jarno 690311918b9SAurelien Jarno /* We are called when the watchpoints have changed. First 691311918b9SAurelien Jarno remove them all. */ 692311918b9SAurelien Jarno cpu_watchpoint_remove_all(cs, BP_CPU); 693311918b9SAurelien Jarno 694311918b9SAurelien Jarno /* Return if PER is not enabled */ 695311918b9SAurelien Jarno if (!(env->psw.mask & PSW_MASK_PER)) { 696311918b9SAurelien Jarno return; 697311918b9SAurelien Jarno } 698311918b9SAurelien Jarno 699311918b9SAurelien Jarno /* Return if storage-alteration event is not enabled. */ 700311918b9SAurelien Jarno if (!(env->cregs[9] & PER_CR9_EVENT_STORE)) { 701311918b9SAurelien Jarno return; 702311918b9SAurelien Jarno } 703311918b9SAurelien Jarno 704311918b9SAurelien Jarno if (env->cregs[10] == 0 && env->cregs[11] == -1LL) { 705311918b9SAurelien Jarno /* We can't create a watchoint spanning the whole memory range, so 706311918b9SAurelien Jarno split it in two parts. */ 707311918b9SAurelien Jarno cpu_watchpoint_insert(cs, 0, 1ULL << 63, wp_flags, NULL); 708311918b9SAurelien Jarno cpu_watchpoint_insert(cs, 1ULL << 63, 1ULL << 63, wp_flags, NULL); 709311918b9SAurelien Jarno } else if (env->cregs[10] > env->cregs[11]) { 710311918b9SAurelien Jarno /* The address range loops, create two watchpoints. */ 711311918b9SAurelien Jarno cpu_watchpoint_insert(cs, env->cregs[10], -env->cregs[10], 712311918b9SAurelien Jarno wp_flags, NULL); 713311918b9SAurelien Jarno cpu_watchpoint_insert(cs, 0, env->cregs[11] + 1, wp_flags, NULL); 714311918b9SAurelien Jarno 715311918b9SAurelien Jarno } else { 716311918b9SAurelien Jarno /* Default case, create a single watchpoint. */ 717311918b9SAurelien Jarno cpu_watchpoint_insert(cs, env->cregs[10], 718311918b9SAurelien Jarno env->cregs[11] - env->cregs[10] + 1, 719311918b9SAurelien Jarno wp_flags, NULL); 720311918b9SAurelien Jarno } 721311918b9SAurelien Jarno } 722311918b9SAurelien Jarno 723311918b9SAurelien Jarno void s390x_cpu_debug_excp_handler(CPUState *cs) 724311918b9SAurelien Jarno { 725311918b9SAurelien Jarno S390CPU *cpu = S390_CPU(cs); 726311918b9SAurelien Jarno CPUS390XState *env = &cpu->env; 727311918b9SAurelien Jarno CPUWatchpoint *wp_hit = cs->watchpoint_hit; 728311918b9SAurelien Jarno 729311918b9SAurelien Jarno if (wp_hit && wp_hit->flags & BP_CPU) { 730311918b9SAurelien Jarno /* FIXME: When the storage-alteration-space control bit is set, 731311918b9SAurelien Jarno the exception should only be triggered if the memory access 732311918b9SAurelien Jarno is done using an address space with the storage-alteration-event 733311918b9SAurelien Jarno bit set. We have no way to detect that with the current 734311918b9SAurelien Jarno watchpoint code. */ 735311918b9SAurelien Jarno cs->watchpoint_hit = NULL; 736311918b9SAurelien Jarno 737311918b9SAurelien Jarno env->per_address = env->psw.addr; 738311918b9SAurelien Jarno env->per_perc_atmid |= PER_CODE_EVENT_STORE | get_per_atmid(env); 739311918b9SAurelien Jarno /* FIXME: We currently no way to detect the address space used 740311918b9SAurelien Jarno to trigger the watchpoint. For now just consider it is the 741311918b9SAurelien Jarno current default ASC. This turn to be true except when MVCP 742311918b9SAurelien Jarno and MVCS instrutions are not used. */ 743311918b9SAurelien Jarno env->per_perc_atmid |= env->psw.mask & (PSW_MASK_ASC) >> 46; 744311918b9SAurelien Jarno 745311918b9SAurelien Jarno /* Remove all watchpoints to re-execute the code. A PER exception 746311918b9SAurelien Jarno will be triggered, it will call load_psw which will recompute 747311918b9SAurelien Jarno the watchpoints. */ 748311918b9SAurelien Jarno cpu_watchpoint_remove_all(cs, BP_CPU); 7496886b980SPeter Maydell cpu_loop_exit_noexc(cs); 750311918b9SAurelien Jarno } 751311918b9SAurelien Jarno } 75244977a8fSRichard Henderson 75344977a8fSRichard Henderson /* Unaligned accesses are only diagnosed with MO_ALIGN. At the moment, 75444977a8fSRichard Henderson this is only for the atomic operations, for which we want to raise a 75544977a8fSRichard Henderson specification exception. */ 75644977a8fSRichard Henderson void s390x_cpu_do_unaligned_access(CPUState *cs, vaddr addr, 75744977a8fSRichard Henderson MMUAccessType access_type, 75844977a8fSRichard Henderson int mmu_idx, uintptr_t retaddr) 75944977a8fSRichard Henderson { 76044977a8fSRichard Henderson S390CPU *cpu = S390_CPU(cs); 76144977a8fSRichard Henderson CPUS390XState *env = &cpu->env; 76244977a8fSRichard Henderson 76344977a8fSRichard Henderson if (retaddr) { 76444977a8fSRichard Henderson cpu_restore_state(cs, retaddr); 76544977a8fSRichard Henderson } 766becf8217SDavid Hildenbrand program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO); 76744977a8fSRichard Henderson } 768d5a43964SAlexander Graf #endif /* CONFIG_USER_ONLY */ 769*b5bd2e91SThomas Huth 770*b5bd2e91SThomas Huth void s390_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, 771*b5bd2e91SThomas Huth int flags) 772*b5bd2e91SThomas Huth { 773*b5bd2e91SThomas Huth S390CPU *cpu = S390_CPU(cs); 774*b5bd2e91SThomas Huth CPUS390XState *env = &cpu->env; 775*b5bd2e91SThomas Huth int i; 776*b5bd2e91SThomas Huth 777*b5bd2e91SThomas Huth if (env->cc_op > 3) { 778*b5bd2e91SThomas Huth cpu_fprintf(f, "PSW=mask %016" PRIx64 " addr %016" PRIx64 " cc %15s\n", 779*b5bd2e91SThomas Huth env->psw.mask, env->psw.addr, cc_name(env->cc_op)); 780*b5bd2e91SThomas Huth } else { 781*b5bd2e91SThomas Huth cpu_fprintf(f, "PSW=mask %016" PRIx64 " addr %016" PRIx64 " cc %02x\n", 782*b5bd2e91SThomas Huth env->psw.mask, env->psw.addr, env->cc_op); 783*b5bd2e91SThomas Huth } 784*b5bd2e91SThomas Huth 785*b5bd2e91SThomas Huth for (i = 0; i < 16; i++) { 786*b5bd2e91SThomas Huth cpu_fprintf(f, "R%02d=%016" PRIx64, i, env->regs[i]); 787*b5bd2e91SThomas Huth if ((i % 4) == 3) { 788*b5bd2e91SThomas Huth cpu_fprintf(f, "\n"); 789*b5bd2e91SThomas Huth } else { 790*b5bd2e91SThomas Huth cpu_fprintf(f, " "); 791*b5bd2e91SThomas Huth } 792*b5bd2e91SThomas Huth } 793*b5bd2e91SThomas Huth 794*b5bd2e91SThomas Huth for (i = 0; i < 16; i++) { 795*b5bd2e91SThomas Huth cpu_fprintf(f, "F%02d=%016" PRIx64, i, get_freg(env, i)->ll); 796*b5bd2e91SThomas Huth if ((i % 4) == 3) { 797*b5bd2e91SThomas Huth cpu_fprintf(f, "\n"); 798*b5bd2e91SThomas Huth } else { 799*b5bd2e91SThomas Huth cpu_fprintf(f, " "); 800*b5bd2e91SThomas Huth } 801*b5bd2e91SThomas Huth } 802*b5bd2e91SThomas Huth 803*b5bd2e91SThomas Huth for (i = 0; i < 32; i++) { 804*b5bd2e91SThomas Huth cpu_fprintf(f, "V%02d=%016" PRIx64 "%016" PRIx64, i, 805*b5bd2e91SThomas Huth env->vregs[i][0].ll, env->vregs[i][1].ll); 806*b5bd2e91SThomas Huth cpu_fprintf(f, (i % 2) ? "\n" : " "); 807*b5bd2e91SThomas Huth } 808*b5bd2e91SThomas Huth 809*b5bd2e91SThomas Huth #ifndef CONFIG_USER_ONLY 810*b5bd2e91SThomas Huth for (i = 0; i < 16; i++) { 811*b5bd2e91SThomas Huth cpu_fprintf(f, "C%02d=%016" PRIx64, i, env->cregs[i]); 812*b5bd2e91SThomas Huth if ((i % 4) == 3) { 813*b5bd2e91SThomas Huth cpu_fprintf(f, "\n"); 814*b5bd2e91SThomas Huth } else { 815*b5bd2e91SThomas Huth cpu_fprintf(f, " "); 816*b5bd2e91SThomas Huth } 817*b5bd2e91SThomas Huth } 818*b5bd2e91SThomas Huth #endif 819*b5bd2e91SThomas Huth 820*b5bd2e91SThomas Huth #ifdef DEBUG_INLINE_BRANCHES 821*b5bd2e91SThomas Huth for (i = 0; i < CC_OP_MAX; i++) { 822*b5bd2e91SThomas Huth cpu_fprintf(f, " %15s = %10ld\t%10ld\n", cc_name(i), 823*b5bd2e91SThomas Huth inline_branch_miss[i], inline_branch_hit[i]); 824*b5bd2e91SThomas Huth } 825*b5bd2e91SThomas Huth #endif 826*b5bd2e91SThomas Huth 827*b5bd2e91SThomas Huth cpu_fprintf(f, "\n"); 828*b5bd2e91SThomas Huth } 829