13d672205SThomas Huth /* 23d672205SThomas Huth * S390x DIAG instruction helper functions 33d672205SThomas Huth * 43d672205SThomas Huth * This program is free software; you can redistribute it and/or modify 53d672205SThomas Huth * it under the terms of the GNU General Public License as published by 63d672205SThomas Huth * the Free Software Foundation; either version 2 of the License, or 73d672205SThomas Huth * (at your option) any later version. 83d672205SThomas Huth * 93d672205SThomas Huth * This program is distributed in the hope that it will be useful, 103d672205SThomas Huth * but WITHOUT ANY WARRANTY; without even the implied warranty of 113d672205SThomas Huth * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 123d672205SThomas Huth * GNU General Public License for more details. 133d672205SThomas Huth */ 143d672205SThomas Huth 153d672205SThomas Huth #include "qemu/osdep.h" 163d672205SThomas Huth #include "cpu.h" 174e58b838SDavid Hildenbrand #include "internal.h" 183d672205SThomas Huth #include "exec/address-spaces.h" 193d672205SThomas Huth #include "hw/watchdog/wdt_diag288.h" 203d672205SThomas Huth #include "sysemu/cpus.h" 213d672205SThomas Huth #include "hw/s390x/ipl.h" 2219c69829SDavid Hildenbrand #include "hw/s390x/s390-virtio-ccw.h" 23*c3347ed0SJanosch Frank #include "hw/s390x/pv.h" 24*c3347ed0SJanosch Frank #include "kvm_s390x.h" 253d672205SThomas Huth 263d672205SThomas Huth int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3) 273d672205SThomas Huth { 283d672205SThomas Huth uint64_t func = env->regs[r1]; 293d672205SThomas Huth uint64_t timeout = env->regs[r1 + 1]; 303d672205SThomas Huth uint64_t action = env->regs[r3]; 313d672205SThomas Huth Object *obj; 323d672205SThomas Huth DIAG288State *diag288; 333d672205SThomas Huth DIAG288Class *diag288_class; 343d672205SThomas Huth 353d672205SThomas Huth if (r1 % 2 || action != 0) { 363d672205SThomas Huth return -1; 373d672205SThomas Huth } 383d672205SThomas Huth 393d672205SThomas Huth /* Timeout must be more than 15 seconds except for timer deletion */ 403d672205SThomas Huth if (func != WDT_DIAG288_CANCEL && timeout < 15) { 413d672205SThomas Huth return -1; 423d672205SThomas Huth } 433d672205SThomas Huth 443d672205SThomas Huth obj = object_resolve_path_type("", TYPE_WDT_DIAG288, NULL); 453d672205SThomas Huth if (!obj) { 463d672205SThomas Huth return -1; 473d672205SThomas Huth } 483d672205SThomas Huth 493d672205SThomas Huth diag288 = DIAG288(obj); 503d672205SThomas Huth diag288_class = DIAG288_GET_CLASS(diag288); 513d672205SThomas Huth return diag288_class->handle_timer(diag288, func, timeout); 523d672205SThomas Huth } 533d672205SThomas Huth 540b7fd817SJanosch Frank static int diag308_parm_check(CPUS390XState *env, uint64_t r1, uint64_t addr, 550b7fd817SJanosch Frank uintptr_t ra, bool write) 560b7fd817SJanosch Frank { 57*c3347ed0SJanosch Frank /* Handled by the Ultravisor */ 58*c3347ed0SJanosch Frank if (s390_is_pv()) { 59*c3347ed0SJanosch Frank return 0; 60*c3347ed0SJanosch Frank } 610b7fd817SJanosch Frank if ((r1 & 1) || (addr & ~TARGET_PAGE_MASK)) { 620b7fd817SJanosch Frank s390_program_interrupt(env, PGM_SPECIFICATION, ra); 630b7fd817SJanosch Frank return -1; 640b7fd817SJanosch Frank } 650b7fd817SJanosch Frank if (!address_space_access_valid(&address_space_memory, addr, 660b7fd817SJanosch Frank sizeof(IplParameterBlock), write, 670b7fd817SJanosch Frank MEMTXATTRS_UNSPECIFIED)) { 680b7fd817SJanosch Frank s390_program_interrupt(env, PGM_ADDRESSING, ra); 690b7fd817SJanosch Frank return -1; 700b7fd817SJanosch Frank } 710b7fd817SJanosch Frank return 0; 720b7fd817SJanosch Frank } 730b7fd817SJanosch Frank 74968db419SDavid Hildenbrand void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra) 753d672205SThomas Huth { 76*c3347ed0SJanosch Frank bool valid; 77dc79e928SRichard Henderson CPUState *cs = env_cpu(env); 783d672205SThomas Huth uint64_t addr = env->regs[r1]; 793d672205SThomas Huth uint64_t subcode = env->regs[r3]; 803d672205SThomas Huth IplParameterBlock *iplb; 813d672205SThomas Huth 823d672205SThomas Huth if (env->psw.mask & PSW_MASK_PSTATE) { 8377b703f8SRichard Henderson s390_program_interrupt(env, PGM_PRIVILEGED, ra); 843d672205SThomas Huth return; 853d672205SThomas Huth } 863d672205SThomas Huth 870b7fd817SJanosch Frank if (subcode & ~0x0ffffULL) { 8877b703f8SRichard Henderson s390_program_interrupt(env, PGM_SPECIFICATION, ra); 893d672205SThomas Huth return; 903d672205SThomas Huth } 913d672205SThomas Huth 92*c3347ed0SJanosch Frank if (subcode >= DIAG308_PV_SET && !s390_has_feat(S390_FEAT_UNPACK)) { 93*c3347ed0SJanosch Frank s390_program_interrupt(env, PGM_SPECIFICATION, ra); 94*c3347ed0SJanosch Frank return; 95*c3347ed0SJanosch Frank } 96*c3347ed0SJanosch Frank 973d672205SThomas Huth switch (subcode) { 980b7fd817SJanosch Frank case DIAG308_RESET_MOD_CLR: 99a30fb811SDavid Hildenbrand s390_ipl_reset_request(cs, S390_RESET_MODIFIED_CLEAR); 1003d672205SThomas Huth break; 1010b7fd817SJanosch Frank case DIAG308_RESET_LOAD_NORM: 102a30fb811SDavid Hildenbrand s390_ipl_reset_request(cs, S390_RESET_LOAD_NORMAL); 1033d672205SThomas Huth break; 1040b7fd817SJanosch Frank case DIAG308_LOAD_CLEAR: 1050b7fd817SJanosch Frank /* Well we still lack the clearing bit... */ 106a30fb811SDavid Hildenbrand s390_ipl_reset_request(cs, S390_RESET_REIPL); 1073d672205SThomas Huth break; 1080b7fd817SJanosch Frank case DIAG308_SET: 109*c3347ed0SJanosch Frank case DIAG308_PV_SET: 1100b7fd817SJanosch Frank if (diag308_parm_check(env, r1, addr, ra, false)) { 1113d672205SThomas Huth return; 1123d672205SThomas Huth } 11396f64aa8SMarc-André Lureau iplb = g_new0(IplParameterBlock, 1); 1143d672205SThomas Huth cpu_physical_memory_read(addr, iplb, sizeof(iplb->len)); 1153d672205SThomas Huth if (!iplb_valid_len(iplb)) { 1163d672205SThomas Huth env->regs[r1 + 1] = DIAG_308_RC_INVALID; 1173d672205SThomas Huth goto out; 1183d672205SThomas Huth } 1193d672205SThomas Huth 1203d672205SThomas Huth cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len)); 1213d672205SThomas Huth 122*c3347ed0SJanosch Frank valid = subcode == DIAG308_PV_SET ? iplb_valid_pv(iplb) : iplb_valid(iplb); 123*c3347ed0SJanosch Frank if (!valid) { 1243d672205SThomas Huth env->regs[r1 + 1] = DIAG_308_RC_INVALID; 1253d672205SThomas Huth goto out; 1263d672205SThomas Huth } 1273d672205SThomas Huth 1283d672205SThomas Huth s390_ipl_update_diag308(iplb); 1293d672205SThomas Huth env->regs[r1 + 1] = DIAG_308_RC_OK; 1303d672205SThomas Huth out: 1313d672205SThomas Huth g_free(iplb); 1323d672205SThomas Huth return; 1330b7fd817SJanosch Frank case DIAG308_STORE: 134*c3347ed0SJanosch Frank case DIAG308_PV_STORE: 1350b7fd817SJanosch Frank if (diag308_parm_check(env, r1, addr, ra, true)) { 1363d672205SThomas Huth return; 1373d672205SThomas Huth } 138*c3347ed0SJanosch Frank if (subcode == DIAG308_PV_STORE) { 139*c3347ed0SJanosch Frank iplb = s390_ipl_get_iplb_pv(); 140*c3347ed0SJanosch Frank } else { 1413d672205SThomas Huth iplb = s390_ipl_get_iplb(); 142*c3347ed0SJanosch Frank } 1433d672205SThomas Huth if (iplb) { 1443d672205SThomas Huth cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len)); 1453d672205SThomas Huth env->regs[r1 + 1] = DIAG_308_RC_OK; 1463d672205SThomas Huth } else { 1473d672205SThomas Huth env->regs[r1 + 1] = DIAG_308_RC_NO_CONF; 1483d672205SThomas Huth } 1493d672205SThomas Huth return; 150*c3347ed0SJanosch Frank case DIAG308_PV_START: 151*c3347ed0SJanosch Frank iplb = s390_ipl_get_iplb_pv(); 152*c3347ed0SJanosch Frank if (!iplb) { 153*c3347ed0SJanosch Frank env->regs[r1 + 1] = DIAG_308_RC_NO_PV_CONF; 154*c3347ed0SJanosch Frank return; 155*c3347ed0SJanosch Frank } 156*c3347ed0SJanosch Frank 157*c3347ed0SJanosch Frank if (kvm_s390_get_hpage_1m()) { 158*c3347ed0SJanosch Frank error_report("Protected VMs can currently not be backed with " 159*c3347ed0SJanosch Frank "huge pages"); 160*c3347ed0SJanosch Frank env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV; 161*c3347ed0SJanosch Frank return; 162*c3347ed0SJanosch Frank } 163*c3347ed0SJanosch Frank 164*c3347ed0SJanosch Frank s390_ipl_reset_request(cs, S390_RESET_PV); 165*c3347ed0SJanosch Frank break; 1663d672205SThomas Huth default: 16777b703f8SRichard Henderson s390_program_interrupt(env, PGM_SPECIFICATION, ra); 1683d672205SThomas Huth break; 1693d672205SThomas Huth } 1703d672205SThomas Huth } 171