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" 233d672205SThomas Huth 243d672205SThomas Huth int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3) 253d672205SThomas Huth { 263d672205SThomas Huth uint64_t func = env->regs[r1]; 273d672205SThomas Huth uint64_t timeout = env->regs[r1 + 1]; 283d672205SThomas Huth uint64_t action = env->regs[r3]; 293d672205SThomas Huth Object *obj; 303d672205SThomas Huth DIAG288State *diag288; 313d672205SThomas Huth DIAG288Class *diag288_class; 323d672205SThomas Huth 333d672205SThomas Huth if (r1 % 2 || action != 0) { 343d672205SThomas Huth return -1; 353d672205SThomas Huth } 363d672205SThomas Huth 373d672205SThomas Huth /* Timeout must be more than 15 seconds except for timer deletion */ 383d672205SThomas Huth if (func != WDT_DIAG288_CANCEL && timeout < 15) { 393d672205SThomas Huth return -1; 403d672205SThomas Huth } 413d672205SThomas Huth 423d672205SThomas Huth obj = object_resolve_path_type("", TYPE_WDT_DIAG288, NULL); 433d672205SThomas Huth if (!obj) { 443d672205SThomas Huth return -1; 453d672205SThomas Huth } 463d672205SThomas Huth 473d672205SThomas Huth diag288 = DIAG288(obj); 483d672205SThomas Huth diag288_class = DIAG288_GET_CLASS(diag288); 493d672205SThomas Huth return diag288_class->handle_timer(diag288, func, timeout); 503d672205SThomas Huth } 513d672205SThomas Huth 523d672205SThomas Huth #define DIAG_308_RC_OK 0x0001 533d672205SThomas Huth #define DIAG_308_RC_NO_CONF 0x0102 543d672205SThomas Huth #define DIAG_308_RC_INVALID 0x0402 553d672205SThomas Huth 56968db419SDavid Hildenbrand void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra) 573d672205SThomas Huth { 58*dc79e928SRichard Henderson CPUState *cs = env_cpu(env); 593d672205SThomas Huth uint64_t addr = env->regs[r1]; 603d672205SThomas Huth uint64_t subcode = env->regs[r3]; 613d672205SThomas Huth IplParameterBlock *iplb; 623d672205SThomas Huth 633d672205SThomas Huth if (env->psw.mask & PSW_MASK_PSTATE) { 64968db419SDavid Hildenbrand s390_program_interrupt(env, PGM_PRIVILEGED, ILEN_AUTO, ra); 653d672205SThomas Huth return; 663d672205SThomas Huth } 673d672205SThomas Huth 683d672205SThomas Huth if ((subcode & ~0x0ffffULL) || (subcode > 6)) { 69968db419SDavid Hildenbrand s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, ra); 703d672205SThomas Huth return; 713d672205SThomas Huth } 723d672205SThomas Huth 733d672205SThomas Huth switch (subcode) { 743d672205SThomas Huth case 0: 75a30fb811SDavid Hildenbrand s390_ipl_reset_request(cs, S390_RESET_MODIFIED_CLEAR); 763d672205SThomas Huth break; 773d672205SThomas Huth case 1: 78a30fb811SDavid Hildenbrand s390_ipl_reset_request(cs, S390_RESET_LOAD_NORMAL); 793d672205SThomas Huth break; 803d672205SThomas Huth case 3: 81a30fb811SDavid Hildenbrand s390_ipl_reset_request(cs, S390_RESET_REIPL); 823d672205SThomas Huth break; 833d672205SThomas Huth case 5: 843d672205SThomas Huth if ((r1 & 1) || (addr & 0x0fffULL)) { 85968db419SDavid Hildenbrand s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, ra); 863d672205SThomas Huth return; 873d672205SThomas Huth } 883d672205SThomas Huth if (!address_space_access_valid(&address_space_memory, addr, 89fddffa42SPeter Maydell sizeof(IplParameterBlock), false, 90fddffa42SPeter Maydell MEMTXATTRS_UNSPECIFIED)) { 91968db419SDavid Hildenbrand s390_program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO, ra); 923d672205SThomas Huth return; 933d672205SThomas Huth } 9496f64aa8SMarc-André Lureau iplb = g_new0(IplParameterBlock, 1); 953d672205SThomas Huth cpu_physical_memory_read(addr, iplb, sizeof(iplb->len)); 963d672205SThomas Huth if (!iplb_valid_len(iplb)) { 973d672205SThomas Huth env->regs[r1 + 1] = DIAG_308_RC_INVALID; 983d672205SThomas Huth goto out; 993d672205SThomas Huth } 1003d672205SThomas Huth 1013d672205SThomas Huth cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len)); 1023d672205SThomas Huth 1033d672205SThomas Huth if (!iplb_valid_ccw(iplb) && !iplb_valid_fcp(iplb)) { 1043d672205SThomas Huth env->regs[r1 + 1] = DIAG_308_RC_INVALID; 1053d672205SThomas Huth goto out; 1063d672205SThomas Huth } 1073d672205SThomas Huth 1083d672205SThomas Huth s390_ipl_update_diag308(iplb); 1093d672205SThomas Huth env->regs[r1 + 1] = DIAG_308_RC_OK; 1103d672205SThomas Huth out: 1113d672205SThomas Huth g_free(iplb); 1123d672205SThomas Huth return; 1133d672205SThomas Huth case 6: 1143d672205SThomas Huth if ((r1 & 1) || (addr & 0x0fffULL)) { 115968db419SDavid Hildenbrand s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, ra); 1163d672205SThomas Huth return; 1173d672205SThomas Huth } 1183d672205SThomas Huth if (!address_space_access_valid(&address_space_memory, addr, 119fddffa42SPeter Maydell sizeof(IplParameterBlock), true, 120fddffa42SPeter Maydell MEMTXATTRS_UNSPECIFIED)) { 121968db419SDavid Hildenbrand s390_program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO, ra); 1223d672205SThomas Huth return; 1233d672205SThomas Huth } 1243d672205SThomas Huth iplb = s390_ipl_get_iplb(); 1253d672205SThomas Huth if (iplb) { 1263d672205SThomas Huth cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len)); 1273d672205SThomas Huth env->regs[r1 + 1] = DIAG_308_RC_OK; 1283d672205SThomas Huth } else { 1293d672205SThomas Huth env->regs[r1 + 1] = DIAG_308_RC_NO_CONF; 1303d672205SThomas Huth } 1313d672205SThomas Huth return; 1323d672205SThomas Huth default: 13337dbd1f4SJanosch Frank s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, ra); 1343d672205SThomas Huth break; 1353d672205SThomas Huth } 1363d672205SThomas Huth } 137