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); 207d5a103cdSRichard Henderson trigger_pgm_exception(env, PGM_ADDRESSING, ILEN_LATER); 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 269ef81522bSAlexander Graf qemu_system_shutdown_request(); 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 334d5a103cdSRichard Henderson switch (ilen) { 335d5a103cdSRichard Henderson case ILEN_LATER: 336d5a103cdSRichard Henderson ilen = get_ilen(cpu_ldub_code(env, env->psw.addr)); 337d5a43964SAlexander Graf break; 338d5a103cdSRichard Henderson case ILEN_LATER_INC: 339d5a103cdSRichard Henderson ilen = get_ilen(cpu_ldub_code(env, env->psw.addr)); 340d5a103cdSRichard Henderson env->psw.addr += ilen; 341d5a43964SAlexander Graf break; 342d5a103cdSRichard Henderson default: 343d5a103cdSRichard Henderson assert(ilen == 2 || ilen == 4 || ilen == 6); 344d5a43964SAlexander Graf } 345d5a43964SAlexander Graf 346d5a103cdSRichard Henderson qemu_log_mask(CPU_LOG_INT, "%s: code=0x%x ilen=%d\n", 347d5a103cdSRichard Henderson __func__, env->int_pgm_code, ilen); 348d5a43964SAlexander Graf 3494782a23bSCornelia Huck lowcore = cpu_map_lowcore(env); 350d5a43964SAlexander Graf 351777c98c3SAurelien Jarno /* Signal PER events with the exception. */ 352777c98c3SAurelien Jarno if (env->per_perc_atmid) { 353777c98c3SAurelien Jarno env->int_pgm_code |= PGM_PER; 354777c98c3SAurelien Jarno lowcore->per_address = cpu_to_be64(env->per_address); 355777c98c3SAurelien Jarno lowcore->per_perc_atmid = cpu_to_be16(env->per_perc_atmid); 356777c98c3SAurelien Jarno env->per_perc_atmid = 0; 357777c98c3SAurelien Jarno } 358777c98c3SAurelien Jarno 359d5a103cdSRichard Henderson lowcore->pgm_ilen = cpu_to_be16(ilen); 360d5a43964SAlexander Graf lowcore->pgm_code = cpu_to_be16(env->int_pgm_code); 361d5a43964SAlexander Graf lowcore->program_old_psw.mask = cpu_to_be64(get_psw_mask(env)); 362d5a43964SAlexander Graf lowcore->program_old_psw.addr = cpu_to_be64(env->psw.addr); 363d5a43964SAlexander Graf mask = be64_to_cpu(lowcore->program_new_psw.mask); 364d5a43964SAlexander Graf addr = be64_to_cpu(lowcore->program_new_psw.addr); 3653da0ab35SAurelien Jarno lowcore->per_breaking_event_addr = cpu_to_be64(env->gbea); 366d5a43964SAlexander Graf 3674782a23bSCornelia Huck cpu_unmap_lowcore(lowcore); 368d5a43964SAlexander Graf 36971e47088SBlue Swirl DPRINTF("%s: %x %x %" PRIx64 " %" PRIx64 "\n", __func__, 370d5a103cdSRichard Henderson env->int_pgm_code, ilen, env->psw.mask, 371d5a43964SAlexander Graf env->psw.addr); 372d5a43964SAlexander Graf 373d5a43964SAlexander Graf load_psw(env, mask, addr); 374d5a43964SAlexander Graf } 375d5a43964SAlexander Graf 376777c98c3SAurelien Jarno static void do_svc_interrupt(CPUS390XState *env) 377777c98c3SAurelien Jarno { 378777c98c3SAurelien Jarno uint64_t mask, addr; 379777c98c3SAurelien Jarno LowCore *lowcore; 380777c98c3SAurelien Jarno 381777c98c3SAurelien Jarno lowcore = cpu_map_lowcore(env); 382777c98c3SAurelien Jarno 383777c98c3SAurelien Jarno lowcore->svc_code = cpu_to_be16(env->int_svc_code); 384777c98c3SAurelien Jarno lowcore->svc_ilen = cpu_to_be16(env->int_svc_ilen); 385777c98c3SAurelien Jarno lowcore->svc_old_psw.mask = cpu_to_be64(get_psw_mask(env)); 386777c98c3SAurelien Jarno lowcore->svc_old_psw.addr = cpu_to_be64(env->psw.addr + env->int_svc_ilen); 387777c98c3SAurelien Jarno mask = be64_to_cpu(lowcore->svc_new_psw.mask); 388777c98c3SAurelien Jarno addr = be64_to_cpu(lowcore->svc_new_psw.addr); 389777c98c3SAurelien Jarno 390777c98c3SAurelien Jarno cpu_unmap_lowcore(lowcore); 391777c98c3SAurelien Jarno 392777c98c3SAurelien Jarno load_psw(env, mask, addr); 393777c98c3SAurelien Jarno 394777c98c3SAurelien Jarno /* When a PER event is pending, the PER exception has to happen 395777c98c3SAurelien Jarno immediately after the SERVICE CALL one. */ 396777c98c3SAurelien Jarno if (env->per_perc_atmid) { 397777c98c3SAurelien Jarno env->int_pgm_code = PGM_PER; 398777c98c3SAurelien Jarno env->int_pgm_ilen = env->int_svc_ilen; 399777c98c3SAurelien Jarno do_program_interrupt(env); 400777c98c3SAurelien Jarno } 401777c98c3SAurelien Jarno } 402777c98c3SAurelien Jarno 403d5a43964SAlexander Graf #define VIRTIO_SUBCODE_64 0x0D00 404d5a43964SAlexander Graf 405a4e3ad19SAndreas Färber static void do_ext_interrupt(CPUS390XState *env) 406d5a43964SAlexander Graf { 407a47dddd7SAndreas Färber S390CPU *cpu = s390_env_get_cpu(env); 408d5a43964SAlexander Graf uint64_t mask, addr; 409d5a43964SAlexander Graf LowCore *lowcore; 410d5a43964SAlexander Graf ExtQueue *q; 411d5a43964SAlexander Graf 412d5a43964SAlexander Graf if (!(env->psw.mask & PSW_MASK_EXT)) { 413a47dddd7SAndreas Färber cpu_abort(CPU(cpu), "Ext int w/o ext mask\n"); 414d5a43964SAlexander Graf } 415d5a43964SAlexander Graf 4161a719923Szhanghailiang if (env->ext_index < 0 || env->ext_index >= MAX_EXT_QUEUE) { 417a47dddd7SAndreas Färber cpu_abort(CPU(cpu), "Ext queue overrun: %d\n", env->ext_index); 418d5a43964SAlexander Graf } 419d5a43964SAlexander Graf 420d5a43964SAlexander Graf q = &env->ext_queue[env->ext_index]; 4214782a23bSCornelia Huck lowcore = cpu_map_lowcore(env); 422d5a43964SAlexander Graf 423d5a43964SAlexander Graf lowcore->ext_int_code = cpu_to_be16(q->code); 424d5a43964SAlexander Graf lowcore->ext_params = cpu_to_be32(q->param); 425d5a43964SAlexander Graf lowcore->ext_params2 = cpu_to_be64(q->param64); 426d5a43964SAlexander Graf lowcore->external_old_psw.mask = cpu_to_be64(get_psw_mask(env)); 427d5a43964SAlexander Graf lowcore->external_old_psw.addr = cpu_to_be64(env->psw.addr); 428d5a43964SAlexander Graf lowcore->cpu_addr = cpu_to_be16(env->cpu_num | VIRTIO_SUBCODE_64); 429d5a43964SAlexander Graf mask = be64_to_cpu(lowcore->external_new_psw.mask); 430d5a43964SAlexander Graf addr = be64_to_cpu(lowcore->external_new_psw.addr); 431d5a43964SAlexander Graf 4324782a23bSCornelia Huck cpu_unmap_lowcore(lowcore); 433d5a43964SAlexander Graf 434d5a43964SAlexander Graf env->ext_index--; 435d5a43964SAlexander Graf if (env->ext_index == -1) { 436d5a43964SAlexander Graf env->pending_int &= ~INTERRUPT_EXT; 437d5a43964SAlexander Graf } 438d5a43964SAlexander Graf 43971e47088SBlue Swirl DPRINTF("%s: %" PRIx64 " %" PRIx64 "\n", __func__, 440d5a43964SAlexander Graf env->psw.mask, env->psw.addr); 441d5a43964SAlexander Graf 442d5a43964SAlexander Graf load_psw(env, mask, addr); 443d5a43964SAlexander Graf } 4443110e292SAlexander Graf 4455d69c547SCornelia Huck static void do_io_interrupt(CPUS390XState *env) 4465d69c547SCornelia Huck { 447a47dddd7SAndreas Färber S390CPU *cpu = s390_env_get_cpu(env); 4485d69c547SCornelia Huck LowCore *lowcore; 4495d69c547SCornelia Huck IOIntQueue *q; 4505d69c547SCornelia Huck uint8_t isc; 4515d69c547SCornelia Huck int disable = 1; 4525d69c547SCornelia Huck int found = 0; 4535d69c547SCornelia Huck 4545d69c547SCornelia Huck if (!(env->psw.mask & PSW_MASK_IO)) { 455a47dddd7SAndreas Färber cpu_abort(CPU(cpu), "I/O int w/o I/O mask\n"); 4565d69c547SCornelia Huck } 4575d69c547SCornelia Huck 4585d69c547SCornelia Huck for (isc = 0; isc < ARRAY_SIZE(env->io_index); isc++) { 45991b0a8f3SCornelia Huck uint64_t isc_bits; 46091b0a8f3SCornelia Huck 4615d69c547SCornelia Huck if (env->io_index[isc] < 0) { 4625d69c547SCornelia Huck continue; 4635d69c547SCornelia Huck } 4641a719923Szhanghailiang if (env->io_index[isc] >= MAX_IO_QUEUE) { 465a47dddd7SAndreas Färber cpu_abort(CPU(cpu), "I/O queue overrun for isc %d: %d\n", 4665d69c547SCornelia Huck isc, env->io_index[isc]); 4675d69c547SCornelia Huck } 4685d69c547SCornelia Huck 4695d69c547SCornelia Huck q = &env->io_queue[env->io_index[isc]][isc]; 47091b0a8f3SCornelia Huck isc_bits = ISC_TO_ISC_BITS(IO_INT_WORD_ISC(q->word)); 47191b0a8f3SCornelia Huck if (!(env->cregs[6] & isc_bits)) { 4725d69c547SCornelia Huck disable = 0; 4735d69c547SCornelia Huck continue; 4745d69c547SCornelia Huck } 475bd9a8d85SCornelia Huck if (!found) { 476bd9a8d85SCornelia Huck uint64_t mask, addr; 477bd9a8d85SCornelia Huck 4785d69c547SCornelia Huck found = 1; 4795d69c547SCornelia Huck lowcore = cpu_map_lowcore(env); 4805d69c547SCornelia Huck 4815d69c547SCornelia Huck lowcore->subchannel_id = cpu_to_be16(q->id); 4825d69c547SCornelia Huck lowcore->subchannel_nr = cpu_to_be16(q->nr); 4835d69c547SCornelia Huck lowcore->io_int_parm = cpu_to_be32(q->parm); 4845d69c547SCornelia Huck lowcore->io_int_word = cpu_to_be32(q->word); 4855d69c547SCornelia Huck lowcore->io_old_psw.mask = cpu_to_be64(get_psw_mask(env)); 4865d69c547SCornelia Huck lowcore->io_old_psw.addr = cpu_to_be64(env->psw.addr); 4875d69c547SCornelia Huck mask = be64_to_cpu(lowcore->io_new_psw.mask); 4885d69c547SCornelia Huck addr = be64_to_cpu(lowcore->io_new_psw.addr); 4895d69c547SCornelia Huck 4905d69c547SCornelia Huck cpu_unmap_lowcore(lowcore); 4915d69c547SCornelia Huck 4925d69c547SCornelia Huck env->io_index[isc]--; 493bd9a8d85SCornelia Huck 494bd9a8d85SCornelia Huck DPRINTF("%s: %" PRIx64 " %" PRIx64 "\n", __func__, 495bd9a8d85SCornelia Huck env->psw.mask, env->psw.addr); 496bd9a8d85SCornelia Huck load_psw(env, mask, addr); 497bd9a8d85SCornelia Huck } 498b22dd124SStefan Weil if (env->io_index[isc] >= 0) { 4995d69c547SCornelia Huck disable = 0; 5005d69c547SCornelia Huck } 501bd9a8d85SCornelia Huck continue; 5025d69c547SCornelia Huck } 5035d69c547SCornelia Huck 5045d69c547SCornelia Huck if (disable) { 5055d69c547SCornelia Huck env->pending_int &= ~INTERRUPT_IO; 5065d69c547SCornelia Huck } 5075d69c547SCornelia Huck 5085d69c547SCornelia Huck } 5095d69c547SCornelia Huck 5105d69c547SCornelia Huck static void do_mchk_interrupt(CPUS390XState *env) 5115d69c547SCornelia Huck { 512a47dddd7SAndreas Färber S390CPU *cpu = s390_env_get_cpu(env); 5135d69c547SCornelia Huck uint64_t mask, addr; 5145d69c547SCornelia Huck LowCore *lowcore; 5155d69c547SCornelia Huck MchkQueue *q; 5165d69c547SCornelia Huck int i; 5175d69c547SCornelia Huck 5185d69c547SCornelia Huck if (!(env->psw.mask & PSW_MASK_MCHECK)) { 519a47dddd7SAndreas Färber cpu_abort(CPU(cpu), "Machine check w/o mchk mask\n"); 5205d69c547SCornelia Huck } 5215d69c547SCornelia Huck 5221a719923Szhanghailiang if (env->mchk_index < 0 || env->mchk_index >= MAX_MCHK_QUEUE) { 523a47dddd7SAndreas Färber cpu_abort(CPU(cpu), "Mchk queue overrun: %d\n", env->mchk_index); 5245d69c547SCornelia Huck } 5255d69c547SCornelia Huck 5265d69c547SCornelia Huck q = &env->mchk_queue[env->mchk_index]; 5275d69c547SCornelia Huck 5285d69c547SCornelia Huck if (q->type != 1) { 5295d69c547SCornelia Huck /* Don't know how to handle this... */ 530a47dddd7SAndreas Färber cpu_abort(CPU(cpu), "Unknown machine check type %d\n", q->type); 5315d69c547SCornelia Huck } 5325d69c547SCornelia Huck if (!(env->cregs[14] & (1 << 28))) { 5335d69c547SCornelia Huck /* CRW machine checks disabled */ 5345d69c547SCornelia Huck return; 5355d69c547SCornelia Huck } 5365d69c547SCornelia Huck 5375d69c547SCornelia Huck lowcore = cpu_map_lowcore(env); 5385d69c547SCornelia Huck 5395d69c547SCornelia Huck for (i = 0; i < 16; i++) { 540c498d8e3SEric Farman lowcore->floating_pt_save_area[i] = cpu_to_be64(get_freg(env, i)->ll); 5415d69c547SCornelia Huck lowcore->gpregs_save_area[i] = cpu_to_be64(env->regs[i]); 5425d69c547SCornelia Huck lowcore->access_regs_save_area[i] = cpu_to_be32(env->aregs[i]); 5435d69c547SCornelia Huck lowcore->cregs_save_area[i] = cpu_to_be64(env->cregs[i]); 5445d69c547SCornelia Huck } 5455d69c547SCornelia Huck lowcore->prefixreg_save_area = cpu_to_be32(env->psa); 5465d69c547SCornelia Huck lowcore->fpt_creg_save_area = cpu_to_be32(env->fpc); 5475d69c547SCornelia Huck lowcore->tod_progreg_save_area = cpu_to_be32(env->todpr); 5485d69c547SCornelia Huck lowcore->cpu_timer_save_area[0] = cpu_to_be32(env->cputm >> 32); 5495d69c547SCornelia Huck lowcore->cpu_timer_save_area[1] = cpu_to_be32((uint32_t)env->cputm); 5505d69c547SCornelia Huck lowcore->clock_comp_save_area[0] = cpu_to_be32(env->ckc >> 32); 5515d69c547SCornelia Huck lowcore->clock_comp_save_area[1] = cpu_to_be32((uint32_t)env->ckc); 5525d69c547SCornelia Huck 5535d69c547SCornelia Huck lowcore->mcck_interruption_code[0] = cpu_to_be32(0x00400f1d); 5545d69c547SCornelia Huck lowcore->mcck_interruption_code[1] = cpu_to_be32(0x40330000); 5555d69c547SCornelia Huck lowcore->mcck_old_psw.mask = cpu_to_be64(get_psw_mask(env)); 5565d69c547SCornelia Huck lowcore->mcck_old_psw.addr = cpu_to_be64(env->psw.addr); 5575d69c547SCornelia Huck mask = be64_to_cpu(lowcore->mcck_new_psw.mask); 5585d69c547SCornelia Huck addr = be64_to_cpu(lowcore->mcck_new_psw.addr); 5595d69c547SCornelia Huck 5605d69c547SCornelia Huck cpu_unmap_lowcore(lowcore); 5615d69c547SCornelia Huck 5625d69c547SCornelia Huck env->mchk_index--; 5635d69c547SCornelia Huck if (env->mchk_index == -1) { 5645d69c547SCornelia Huck env->pending_int &= ~INTERRUPT_MCHK; 5655d69c547SCornelia Huck } 5665d69c547SCornelia Huck 5675d69c547SCornelia Huck DPRINTF("%s: %" PRIx64 " %" PRIx64 "\n", __func__, 5685d69c547SCornelia Huck env->psw.mask, env->psw.addr); 5695d69c547SCornelia Huck 5705d69c547SCornelia Huck load_psw(env, mask, addr); 5715d69c547SCornelia Huck } 5725d69c547SCornelia Huck 57397a8ea5aSAndreas Färber void s390_cpu_do_interrupt(CPUState *cs) 5743110e292SAlexander Graf { 57597a8ea5aSAndreas Färber S390CPU *cpu = S390_CPU(cs); 57697a8ea5aSAndreas Färber CPUS390XState *env = &cpu->env; 577f9466733SAndreas Färber 5780d404541SRichard Henderson qemu_log_mask(CPU_LOG_INT, "%s: %d at pc=%" PRIx64 "\n", 57927103424SAndreas Färber __func__, cs->exception_index, env->psw.addr); 580d5a43964SAlexander Graf 581eb24f7c6SDavid Hildenbrand s390_cpu_set_state(CPU_STATE_OPERATING, cpu); 5825d69c547SCornelia Huck /* handle machine checks */ 5835d69c547SCornelia Huck if ((env->psw.mask & PSW_MASK_MCHECK) && 58427103424SAndreas Färber (cs->exception_index == -1)) { 5855d69c547SCornelia Huck if (env->pending_int & INTERRUPT_MCHK) { 58627103424SAndreas Färber cs->exception_index = EXCP_MCHK; 5875d69c547SCornelia Huck } 5885d69c547SCornelia Huck } 589d5a43964SAlexander Graf /* handle external interrupts */ 590d5a43964SAlexander Graf if ((env->psw.mask & PSW_MASK_EXT) && 59127103424SAndreas Färber cs->exception_index == -1) { 592d5a43964SAlexander Graf if (env->pending_int & INTERRUPT_EXT) { 593d5a43964SAlexander Graf /* code is already in env */ 59427103424SAndreas Färber cs->exception_index = EXCP_EXT; 595d5a43964SAlexander Graf } else if (env->pending_int & INTERRUPT_TOD) { 596f9466733SAndreas Färber cpu_inject_ext(cpu, 0x1004, 0, 0); 59727103424SAndreas Färber cs->exception_index = EXCP_EXT; 598d5a43964SAlexander Graf env->pending_int &= ~INTERRUPT_EXT; 599d5a43964SAlexander Graf env->pending_int &= ~INTERRUPT_TOD; 600d5a43964SAlexander Graf } else if (env->pending_int & INTERRUPT_CPUTIMER) { 601f9466733SAndreas Färber cpu_inject_ext(cpu, 0x1005, 0, 0); 60227103424SAndreas Färber cs->exception_index = EXCP_EXT; 603d5a43964SAlexander Graf env->pending_int &= ~INTERRUPT_EXT; 604d5a43964SAlexander Graf env->pending_int &= ~INTERRUPT_TOD; 6053110e292SAlexander Graf } 606d5a43964SAlexander Graf } 6075d69c547SCornelia Huck /* handle I/O interrupts */ 6085d69c547SCornelia Huck if ((env->psw.mask & PSW_MASK_IO) && 60927103424SAndreas Färber (cs->exception_index == -1)) { 6105d69c547SCornelia Huck if (env->pending_int & INTERRUPT_IO) { 61127103424SAndreas Färber cs->exception_index = EXCP_IO; 6125d69c547SCornelia Huck } 6135d69c547SCornelia Huck } 614d5a43964SAlexander Graf 61527103424SAndreas Färber switch (cs->exception_index) { 616d5a43964SAlexander Graf case EXCP_PGM: 617d5a43964SAlexander Graf do_program_interrupt(env); 618d5a43964SAlexander Graf break; 619d5a43964SAlexander Graf case EXCP_SVC: 620d5a43964SAlexander Graf do_svc_interrupt(env); 621d5a43964SAlexander Graf break; 622d5a43964SAlexander Graf case EXCP_EXT: 623d5a43964SAlexander Graf do_ext_interrupt(env); 624d5a43964SAlexander Graf break; 6255d69c547SCornelia Huck case EXCP_IO: 6265d69c547SCornelia Huck do_io_interrupt(env); 6275d69c547SCornelia Huck break; 6285d69c547SCornelia Huck case EXCP_MCHK: 6295d69c547SCornelia Huck do_mchk_interrupt(env); 6305d69c547SCornelia Huck break; 631d5a43964SAlexander Graf } 63227103424SAndreas Färber cs->exception_index = -1; 633d5a43964SAlexander Graf 634d5a43964SAlexander Graf if (!env->pending_int) { 635259186a7SAndreas Färber cs->interrupt_request &= ~CPU_INTERRUPT_HARD; 636d5a43964SAlexander Graf } 637d5a43964SAlexander Graf } 638d5a43964SAlexander Graf 63902bb9bbfSRichard Henderson bool s390_cpu_exec_interrupt(CPUState *cs, int interrupt_request) 64002bb9bbfSRichard Henderson { 64102bb9bbfSRichard Henderson if (interrupt_request & CPU_INTERRUPT_HARD) { 64202bb9bbfSRichard Henderson S390CPU *cpu = S390_CPU(cs); 64302bb9bbfSRichard Henderson CPUS390XState *env = &cpu->env; 64402bb9bbfSRichard Henderson 64502bb9bbfSRichard Henderson if (env->psw.mask & PSW_MASK_EXT) { 64602bb9bbfSRichard Henderson s390_cpu_do_interrupt(cs); 64702bb9bbfSRichard Henderson return true; 64802bb9bbfSRichard Henderson } 64902bb9bbfSRichard Henderson } 65002bb9bbfSRichard Henderson return false; 65102bb9bbfSRichard Henderson } 652311918b9SAurelien Jarno 653311918b9SAurelien Jarno void s390_cpu_recompute_watchpoints(CPUState *cs) 654311918b9SAurelien Jarno { 655311918b9SAurelien Jarno const int wp_flags = BP_CPU | BP_MEM_WRITE | BP_STOP_BEFORE_ACCESS; 656311918b9SAurelien Jarno S390CPU *cpu = S390_CPU(cs); 657311918b9SAurelien Jarno CPUS390XState *env = &cpu->env; 658311918b9SAurelien Jarno 659311918b9SAurelien Jarno /* We are called when the watchpoints have changed. First 660311918b9SAurelien Jarno remove them all. */ 661311918b9SAurelien Jarno cpu_watchpoint_remove_all(cs, BP_CPU); 662311918b9SAurelien Jarno 663311918b9SAurelien Jarno /* Return if PER is not enabled */ 664311918b9SAurelien Jarno if (!(env->psw.mask & PSW_MASK_PER)) { 665311918b9SAurelien Jarno return; 666311918b9SAurelien Jarno } 667311918b9SAurelien Jarno 668311918b9SAurelien Jarno /* Return if storage-alteration event is not enabled. */ 669311918b9SAurelien Jarno if (!(env->cregs[9] & PER_CR9_EVENT_STORE)) { 670311918b9SAurelien Jarno return; 671311918b9SAurelien Jarno } 672311918b9SAurelien Jarno 673311918b9SAurelien Jarno if (env->cregs[10] == 0 && env->cregs[11] == -1LL) { 674311918b9SAurelien Jarno /* We can't create a watchoint spanning the whole memory range, so 675311918b9SAurelien Jarno split it in two parts. */ 676311918b9SAurelien Jarno cpu_watchpoint_insert(cs, 0, 1ULL << 63, wp_flags, NULL); 677311918b9SAurelien Jarno cpu_watchpoint_insert(cs, 1ULL << 63, 1ULL << 63, wp_flags, NULL); 678311918b9SAurelien Jarno } else if (env->cregs[10] > env->cregs[11]) { 679311918b9SAurelien Jarno /* The address range loops, create two watchpoints. */ 680311918b9SAurelien Jarno cpu_watchpoint_insert(cs, env->cregs[10], -env->cregs[10], 681311918b9SAurelien Jarno wp_flags, NULL); 682311918b9SAurelien Jarno cpu_watchpoint_insert(cs, 0, env->cregs[11] + 1, wp_flags, NULL); 683311918b9SAurelien Jarno 684311918b9SAurelien Jarno } else { 685311918b9SAurelien Jarno /* Default case, create a single watchpoint. */ 686311918b9SAurelien Jarno cpu_watchpoint_insert(cs, env->cregs[10], 687311918b9SAurelien Jarno env->cregs[11] - env->cregs[10] + 1, 688311918b9SAurelien Jarno wp_flags, NULL); 689311918b9SAurelien Jarno } 690311918b9SAurelien Jarno } 691311918b9SAurelien Jarno 692311918b9SAurelien Jarno void s390x_cpu_debug_excp_handler(CPUState *cs) 693311918b9SAurelien Jarno { 694311918b9SAurelien Jarno S390CPU *cpu = S390_CPU(cs); 695311918b9SAurelien Jarno CPUS390XState *env = &cpu->env; 696311918b9SAurelien Jarno CPUWatchpoint *wp_hit = cs->watchpoint_hit; 697311918b9SAurelien Jarno 698311918b9SAurelien Jarno if (wp_hit && wp_hit->flags & BP_CPU) { 699311918b9SAurelien Jarno /* FIXME: When the storage-alteration-space control bit is set, 700311918b9SAurelien Jarno the exception should only be triggered if the memory access 701311918b9SAurelien Jarno is done using an address space with the storage-alteration-event 702311918b9SAurelien Jarno bit set. We have no way to detect that with the current 703311918b9SAurelien Jarno watchpoint code. */ 704311918b9SAurelien Jarno cs->watchpoint_hit = NULL; 705311918b9SAurelien Jarno 706311918b9SAurelien Jarno env->per_address = env->psw.addr; 707311918b9SAurelien Jarno env->per_perc_atmid |= PER_CODE_EVENT_STORE | get_per_atmid(env); 708311918b9SAurelien Jarno /* FIXME: We currently no way to detect the address space used 709311918b9SAurelien Jarno to trigger the watchpoint. For now just consider it is the 710311918b9SAurelien Jarno current default ASC. This turn to be true except when MVCP 711311918b9SAurelien Jarno and MVCS instrutions are not used. */ 712311918b9SAurelien Jarno env->per_perc_atmid |= env->psw.mask & (PSW_MASK_ASC) >> 46; 713311918b9SAurelien Jarno 714311918b9SAurelien Jarno /* Remove all watchpoints to re-execute the code. A PER exception 715311918b9SAurelien Jarno will be triggered, it will call load_psw which will recompute 716311918b9SAurelien Jarno the watchpoints. */ 717311918b9SAurelien Jarno cpu_watchpoint_remove_all(cs, BP_CPU); 7186886b980SPeter Maydell cpu_loop_exit_noexc(cs); 719311918b9SAurelien Jarno } 720311918b9SAurelien Jarno } 721*44977a8fSRichard Henderson 722*44977a8fSRichard Henderson /* Unaligned accesses are only diagnosed with MO_ALIGN. At the moment, 723*44977a8fSRichard Henderson this is only for the atomic operations, for which we want to raise a 724*44977a8fSRichard Henderson specification exception. */ 725*44977a8fSRichard Henderson void s390x_cpu_do_unaligned_access(CPUState *cs, vaddr addr, 726*44977a8fSRichard Henderson MMUAccessType access_type, 727*44977a8fSRichard Henderson int mmu_idx, uintptr_t retaddr) 728*44977a8fSRichard Henderson { 729*44977a8fSRichard Henderson S390CPU *cpu = S390_CPU(cs); 730*44977a8fSRichard Henderson CPUS390XState *env = &cpu->env; 731*44977a8fSRichard Henderson 732*44977a8fSRichard Henderson if (retaddr) { 733*44977a8fSRichard Henderson cpu_restore_state(cs, retaddr); 734*44977a8fSRichard Henderson } 735*44977a8fSRichard Henderson program_interrupt(env, PGM_SPECIFICATION, ILEN_LATER); 736*44977a8fSRichard Henderson } 737d5a43964SAlexander Graf #endif /* CONFIG_USER_ONLY */ 738