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" 23c3347ed0SJanosch Frank #include "hw/s390x/pv.h" 24c3347ed0SJanosch 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 { 57c3347ed0SJanosch Frank /* Handled by the Ultravisor */ 58c3347ed0SJanosch Frank if (s390_is_pv()) { 59c3347ed0SJanosch Frank return 0; 60c3347ed0SJanosch 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 { 76c3347ed0SJanosch Frank bool valid; 77dc79e928SRichard Henderson CPUState *cs = env_cpu(env); 78*9c61e112SJanosch Frank S390CPU *cpu = S390_CPU(cs); 793d672205SThomas Huth uint64_t addr = env->regs[r1]; 803d672205SThomas Huth uint64_t subcode = env->regs[r3]; 813d672205SThomas Huth IplParameterBlock *iplb; 823d672205SThomas Huth 833d672205SThomas Huth if (env->psw.mask & PSW_MASK_PSTATE) { 8477b703f8SRichard Henderson s390_program_interrupt(env, PGM_PRIVILEGED, ra); 853d672205SThomas Huth return; 863d672205SThomas Huth } 873d672205SThomas Huth 880b7fd817SJanosch Frank if (subcode & ~0x0ffffULL) { 8977b703f8SRichard Henderson s390_program_interrupt(env, PGM_SPECIFICATION, ra); 903d672205SThomas Huth return; 913d672205SThomas Huth } 923d672205SThomas Huth 93c3347ed0SJanosch Frank if (subcode >= DIAG308_PV_SET && !s390_has_feat(S390_FEAT_UNPACK)) { 94c3347ed0SJanosch Frank s390_program_interrupt(env, PGM_SPECIFICATION, ra); 95c3347ed0SJanosch Frank return; 96c3347ed0SJanosch Frank } 97c3347ed0SJanosch Frank 983d672205SThomas Huth switch (subcode) { 990b7fd817SJanosch Frank case DIAG308_RESET_MOD_CLR: 100a30fb811SDavid Hildenbrand s390_ipl_reset_request(cs, S390_RESET_MODIFIED_CLEAR); 1013d672205SThomas Huth break; 1020b7fd817SJanosch Frank case DIAG308_RESET_LOAD_NORM: 103a30fb811SDavid Hildenbrand s390_ipl_reset_request(cs, S390_RESET_LOAD_NORMAL); 1043d672205SThomas Huth break; 1050b7fd817SJanosch Frank case DIAG308_LOAD_CLEAR: 1060b7fd817SJanosch Frank /* Well we still lack the clearing bit... */ 107a30fb811SDavid Hildenbrand s390_ipl_reset_request(cs, S390_RESET_REIPL); 1083d672205SThomas Huth break; 1090b7fd817SJanosch Frank case DIAG308_SET: 110c3347ed0SJanosch Frank case DIAG308_PV_SET: 1110b7fd817SJanosch Frank if (diag308_parm_check(env, r1, addr, ra, false)) { 1123d672205SThomas Huth return; 1133d672205SThomas Huth } 11496f64aa8SMarc-André Lureau iplb = g_new0(IplParameterBlock, 1); 115*9c61e112SJanosch Frank if (!s390_is_pv()) { 1163d672205SThomas Huth cpu_physical_memory_read(addr, iplb, sizeof(iplb->len)); 117*9c61e112SJanosch Frank } else { 118*9c61e112SJanosch Frank s390_cpu_pv_mem_read(cpu, 0, iplb, sizeof(iplb->len)); 119*9c61e112SJanosch Frank } 120*9c61e112SJanosch Frank 1213d672205SThomas Huth if (!iplb_valid_len(iplb)) { 1223d672205SThomas Huth env->regs[r1 + 1] = DIAG_308_RC_INVALID; 1233d672205SThomas Huth goto out; 1243d672205SThomas Huth } 1253d672205SThomas Huth 126*9c61e112SJanosch Frank if (!s390_is_pv()) { 1273d672205SThomas Huth cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len)); 128*9c61e112SJanosch Frank } else { 129*9c61e112SJanosch Frank s390_cpu_pv_mem_read(cpu, 0, iplb, be32_to_cpu(iplb->len)); 130*9c61e112SJanosch Frank } 1313d672205SThomas Huth 132c3347ed0SJanosch Frank valid = subcode == DIAG308_PV_SET ? iplb_valid_pv(iplb) : iplb_valid(iplb); 133c3347ed0SJanosch Frank if (!valid) { 1343d672205SThomas Huth env->regs[r1 + 1] = DIAG_308_RC_INVALID; 1353d672205SThomas Huth goto out; 1363d672205SThomas Huth } 1373d672205SThomas Huth 1383d672205SThomas Huth s390_ipl_update_diag308(iplb); 1393d672205SThomas Huth env->regs[r1 + 1] = DIAG_308_RC_OK; 1403d672205SThomas Huth out: 1413d672205SThomas Huth g_free(iplb); 1423d672205SThomas Huth return; 1430b7fd817SJanosch Frank case DIAG308_STORE: 144c3347ed0SJanosch Frank case DIAG308_PV_STORE: 1450b7fd817SJanosch Frank if (diag308_parm_check(env, r1, addr, ra, true)) { 1463d672205SThomas Huth return; 1473d672205SThomas Huth } 148c3347ed0SJanosch Frank if (subcode == DIAG308_PV_STORE) { 149c3347ed0SJanosch Frank iplb = s390_ipl_get_iplb_pv(); 150c3347ed0SJanosch Frank } else { 1513d672205SThomas Huth iplb = s390_ipl_get_iplb(); 152c3347ed0SJanosch Frank } 153*9c61e112SJanosch Frank if (!iplb) { 1543d672205SThomas Huth env->regs[r1 + 1] = DIAG_308_RC_NO_CONF; 155*9c61e112SJanosch Frank return; 1563d672205SThomas Huth } 157*9c61e112SJanosch Frank 158*9c61e112SJanosch Frank if (!s390_is_pv()) { 159*9c61e112SJanosch Frank cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len)); 160*9c61e112SJanosch Frank } else { 161*9c61e112SJanosch Frank s390_cpu_pv_mem_write(cpu, 0, iplb, be32_to_cpu(iplb->len)); 162*9c61e112SJanosch Frank } 163*9c61e112SJanosch Frank env->regs[r1 + 1] = DIAG_308_RC_OK; 1643d672205SThomas Huth return; 165c3347ed0SJanosch Frank case DIAG308_PV_START: 166c3347ed0SJanosch Frank iplb = s390_ipl_get_iplb_pv(); 167c3347ed0SJanosch Frank if (!iplb) { 168c3347ed0SJanosch Frank env->regs[r1 + 1] = DIAG_308_RC_NO_PV_CONF; 169c3347ed0SJanosch Frank return; 170c3347ed0SJanosch Frank } 171c3347ed0SJanosch Frank 172c3347ed0SJanosch Frank if (kvm_s390_get_hpage_1m()) { 173c3347ed0SJanosch Frank error_report("Protected VMs can currently not be backed with " 174c3347ed0SJanosch Frank "huge pages"); 175c3347ed0SJanosch Frank env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV; 176c3347ed0SJanosch Frank return; 177c3347ed0SJanosch Frank } 178c3347ed0SJanosch Frank 179c3347ed0SJanosch Frank s390_ipl_reset_request(cs, S390_RESET_PV); 180c3347ed0SJanosch Frank break; 1813d672205SThomas Huth default: 18277b703f8SRichard Henderson s390_program_interrupt(env, PGM_SPECIFICATION, ra); 1833d672205SThomas Huth break; 1843d672205SThomas Huth } 1853d672205SThomas Huth } 186