|
|
1.1 ! root 1: /* ! 2: * QEMU S390x KVM implementation ! 3: * ! 4: * Copyright (c) 2009 Alexander Graf <[email protected]> ! 5: * ! 6: * This library is free software; you can redistribute it and/or ! 7: * modify it under the terms of the GNU Lesser General Public ! 8: * License as published by the Free Software Foundation; either ! 9: * version 2 of the License, or (at your option) any later version. ! 10: * ! 11: * This library is distributed in the hope that it will be useful, ! 12: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 14: * Lesser General Public License for more details. ! 15: * ! 16: * You should have received a copy of the GNU Lesser General Public ! 17: * License along with this library; if not, see <http://www.gnu.org/licenses/>. ! 18: */ ! 19: ! 20: #include <sys/types.h> ! 21: #include <sys/ioctl.h> ! 22: #include <sys/mman.h> ! 23: ! 24: #include <linux/kvm.h> ! 25: #include <asm/ptrace.h> ! 26: ! 27: #include "qemu-common.h" ! 28: #include "qemu-timer.h" ! 29: #include "sysemu.h" ! 30: #include "kvm.h" ! 31: #include "cpu.h" ! 32: #include "device_tree.h" ! 33: ! 34: /* #define DEBUG_KVM */ ! 35: ! 36: #ifdef DEBUG_KVM ! 37: #define dprintf(fmt, ...) \ ! 38: do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) ! 39: #else ! 40: #define dprintf(fmt, ...) \ ! 41: do { } while (0) ! 42: #endif ! 43: ! 44: #define IPA0_DIAG 0x8300 ! 45: #define IPA0_SIGP 0xae00 ! 46: #define IPA0_PRIV 0xb200 ! 47: ! 48: #define PRIV_SCLP_CALL 0x20 ! 49: #define DIAG_KVM_HYPERCALL 0x500 ! 50: #define DIAG_KVM_BREAKPOINT 0x501 ! 51: ! 52: #define SCP_LENGTH 0x00 ! 53: #define SCP_FUNCTION_CODE 0x02 ! 54: #define SCP_CONTROL_MASK 0x03 ! 55: #define SCP_RESPONSE_CODE 0x06 ! 56: #define SCP_MEM_CODE 0x08 ! 57: #define SCP_INCREMENT 0x0a ! 58: ! 59: #define ICPT_INSTRUCTION 0x04 ! 60: #define ICPT_WAITPSW 0x1c ! 61: #define ICPT_SOFT_INTERCEPT 0x24 ! 62: #define ICPT_CPU_STOP 0x28 ! 63: #define ICPT_IO 0x40 ! 64: ! 65: #define SIGP_RESTART 0x06 ! 66: #define SIGP_INITIAL_CPU_RESET 0x0b ! 67: #define SIGP_STORE_STATUS_ADDR 0x0e ! 68: #define SIGP_SET_ARCH 0x12 ! 69: ! 70: #define SCLP_CMDW_READ_SCP_INFO 0x00020001 ! 71: #define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001 ! 72: ! 73: int kvm_arch_init(KVMState *s, int smp_cpus) ! 74: { ! 75: return 0; ! 76: } ! 77: ! 78: int kvm_arch_init_vcpu(CPUState *env) ! 79: { ! 80: int ret = 0; ! 81: ! 82: if (kvm_vcpu_ioctl(env, KVM_S390_INITIAL_RESET, NULL) < 0) { ! 83: perror("cannot init reset vcpu"); ! 84: } ! 85: ! 86: return ret; ! 87: } ! 88: ! 89: void kvm_arch_reset_vcpu(CPUState *env) ! 90: { ! 91: /* FIXME: add code to reset vcpu. */ ! 92: } ! 93: ! 94: int kvm_arch_put_registers(CPUState *env) ! 95: { ! 96: struct kvm_regs regs; ! 97: int ret; ! 98: int i; ! 99: ! 100: ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, ®s); ! 101: if (ret < 0) { ! 102: return ret; ! 103: } ! 104: ! 105: for (i = 0; i < 16; i++) { ! 106: regs.gprs[i] = env->regs[i]; ! 107: } ! 108: ! 109: ret = kvm_vcpu_ioctl(env, KVM_SET_REGS, ®s); ! 110: if (ret < 0) { ! 111: return ret; ! 112: } ! 113: ! 114: env->kvm_run->psw_addr = env->psw.addr; ! 115: env->kvm_run->psw_mask = env->psw.mask; ! 116: ! 117: return ret; ! 118: } ! 119: ! 120: int kvm_arch_get_registers(CPUState *env) ! 121: { ! 122: uint32_t ret; ! 123: struct kvm_regs regs; ! 124: int i; ! 125: ! 126: ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, ®s); ! 127: if (ret < 0) { ! 128: return ret; ! 129: } ! 130: ! 131: for (i = 0; i < 16; i++) { ! 132: env->regs[i] = regs.gprs[i]; ! 133: } ! 134: ! 135: env->psw.addr = env->kvm_run->psw_addr; ! 136: env->psw.mask = env->kvm_run->psw_mask; ! 137: ! 138: return 0; ! 139: } ! 140: ! 141: int kvm_arch_insert_sw_breakpoint(CPUState *env, struct kvm_sw_breakpoint *bp) ! 142: { ! 143: static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01}; ! 144: ! 145: if (cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) || ! 146: cpu_memory_rw_debug(env, bp->pc, (uint8_t *)diag_501, 4, 1)) { ! 147: return -EINVAL; ! 148: } ! 149: return 0; ! 150: } ! 151: ! 152: int kvm_arch_remove_sw_breakpoint(CPUState *env, struct kvm_sw_breakpoint *bp) ! 153: { ! 154: uint8_t t[4]; ! 155: static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01}; ! 156: ! 157: if (cpu_memory_rw_debug(env, bp->pc, t, 4, 0)) { ! 158: return -EINVAL; ! 159: } else if (memcmp(t, diag_501, 4)) { ! 160: return -EINVAL; ! 161: } else if (cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&bp->saved_insn, 1, 1)) { ! 162: return -EINVAL; ! 163: } ! 164: ! 165: return 0; ! 166: } ! 167: ! 168: int kvm_arch_pre_run(CPUState *env, struct kvm_run *run) ! 169: { ! 170: return 0; ! 171: } ! 172: ! 173: int kvm_arch_post_run(CPUState *env, struct kvm_run *run) ! 174: { ! 175: return 0; ! 176: } ! 177: ! 178: static void kvm_s390_interrupt_internal(CPUState *env, int type, uint32_t parm, ! 179: uint64_t parm64, int vm) ! 180: { ! 181: struct kvm_s390_interrupt kvmint; ! 182: int r; ! 183: ! 184: if (!env->kvm_state) { ! 185: return; ! 186: } ! 187: ! 188: env->halted = 0; ! 189: env->exception_index = 0; ! 190: ! 191: kvmint.type = type; ! 192: kvmint.parm = parm; ! 193: kvmint.parm64 = parm64; ! 194: ! 195: if (vm) { ! 196: r = kvm_vm_ioctl(env->kvm_state, KVM_S390_INTERRUPT, &kvmint); ! 197: } else { ! 198: r = kvm_vcpu_ioctl(env, KVM_S390_INTERRUPT, &kvmint); ! 199: } ! 200: ! 201: if (r < 0) { ! 202: fprintf(stderr, "KVM failed to inject interrupt\n"); ! 203: exit(1); ! 204: } ! 205: } ! 206: ! 207: void kvm_s390_virtio_irq(CPUState *env, int config_change, uint64_t token) ! 208: { ! 209: kvm_s390_interrupt_internal(env, KVM_S390_INT_VIRTIO, config_change, ! 210: token, 1); ! 211: } ! 212: ! 213: static void kvm_s390_interrupt(CPUState *env, int type, uint32_t code) ! 214: { ! 215: kvm_s390_interrupt_internal(env, type, code, 0, 0); ! 216: } ! 217: ! 218: static void enter_pgmcheck(CPUState *env, uint16_t code) ! 219: { ! 220: kvm_s390_interrupt(env, KVM_S390_PROGRAM_INT, code); ! 221: } ! 222: ! 223: static void setcc(CPUState *env, uint64_t cc) ! 224: { ! 225: env->kvm_run->psw_mask &= ~(3ul << 44); ! 226: env->kvm_run->psw_mask |= (cc & 3) << 44; ! 227: ! 228: env->psw.mask &= ~(3ul << 44); ! 229: env->psw.mask |= (cc & 3) << 44; ! 230: } ! 231: ! 232: static int sclp_service_call(CPUState *env, struct kvm_run *run, uint16_t ipbh0) ! 233: { ! 234: uint32_t sccb; ! 235: uint64_t code; ! 236: int r = 0; ! 237: ! 238: cpu_synchronize_state(env); ! 239: sccb = env->regs[ipbh0 & 0xf]; ! 240: code = env->regs[(ipbh0 & 0xf0) >> 4]; ! 241: ! 242: dprintf("sclp(0x%x, 0x%lx)\n", sccb, code); ! 243: ! 244: if (sccb & ~0x7ffffff8ul) { ! 245: fprintf(stderr, "KVM: invalid sccb address 0x%x\n", sccb); ! 246: r = -1; ! 247: goto out; ! 248: } ! 249: ! 250: switch(code) { ! 251: case SCLP_CMDW_READ_SCP_INFO: ! 252: case SCLP_CMDW_READ_SCP_INFO_FORCED: ! 253: stw_phys(sccb + SCP_MEM_CODE, ram_size >> 20); ! 254: stb_phys(sccb + SCP_INCREMENT, 1); ! 255: stw_phys(sccb + SCP_RESPONSE_CODE, 0x10); ! 256: setcc(env, 0); ! 257: ! 258: kvm_s390_interrupt_internal(env, KVM_S390_INT_SERVICE, ! 259: sccb & ~3, 0, 1); ! 260: break; ! 261: default: ! 262: dprintf("KVM: invalid sclp call 0x%x / 0x%lx\n", sccb, code); ! 263: r = -1; ! 264: break; ! 265: } ! 266: ! 267: out: ! 268: if (r < 0) { ! 269: setcc(env, 3); ! 270: } ! 271: return 0; ! 272: } ! 273: ! 274: static int handle_priv(CPUState *env, struct kvm_run *run, uint8_t ipa1) ! 275: { ! 276: int r = 0; ! 277: uint16_t ipbh0 = (run->s390_sieic.ipb & 0xffff0000) >> 16; ! 278: ! 279: dprintf("KVM: PRIV: %d\n", ipa1); ! 280: switch (ipa1) { ! 281: case PRIV_SCLP_CALL: ! 282: r = sclp_service_call(env, run, ipbh0); ! 283: break; ! 284: default: ! 285: dprintf("KVM: unknown PRIV: 0x%x\n", ipa1); ! 286: r = -1; ! 287: break; ! 288: } ! 289: ! 290: return r; ! 291: } ! 292: ! 293: static int handle_hypercall(CPUState *env, struct kvm_run *run) ! 294: { ! 295: int r; ! 296: ! 297: cpu_synchronize_state(env); ! 298: r = s390_virtio_hypercall(env); ! 299: kvm_arch_put_registers(env); ! 300: ! 301: return r; ! 302: } ! 303: ! 304: static int handle_diag(CPUState *env, struct kvm_run *run, int ipb_code) ! 305: { ! 306: int r = 0; ! 307: ! 308: switch (ipb_code) { ! 309: case DIAG_KVM_HYPERCALL: ! 310: r = handle_hypercall(env, run); ! 311: break; ! 312: case DIAG_KVM_BREAKPOINT: ! 313: sleep(10); ! 314: break; ! 315: default: ! 316: dprintf("KVM: unknown DIAG: 0x%x\n", ipb_code); ! 317: r = -1; ! 318: break; ! 319: } ! 320: ! 321: return r; ! 322: } ! 323: ! 324: static int s390_cpu_restart(CPUState *env) ! 325: { ! 326: kvm_s390_interrupt(env, KVM_S390_RESTART, 0); ! 327: env->halted = 0; ! 328: env->exception_index = 0; ! 329: qemu_cpu_kick(env); ! 330: dprintf("DONE: SIGP cpu restart: %p\n", env); ! 331: return 0; ! 332: } ! 333: ! 334: static int s390_store_status(CPUState *env, uint32_t parameter) ! 335: { ! 336: /* XXX */ ! 337: fprintf(stderr, "XXX SIGP store status\n"); ! 338: return -1; ! 339: } ! 340: ! 341: static int s390_cpu_initial_reset(CPUState *env) ! 342: { ! 343: /* XXX */ ! 344: fprintf(stderr, "XXX SIGP init\n"); ! 345: return -1; ! 346: } ! 347: ! 348: static int handle_sigp(CPUState *env, struct kvm_run *run, uint8_t ipa1) ! 349: { ! 350: uint8_t order_code; ! 351: uint32_t parameter; ! 352: uint16_t cpu_addr; ! 353: uint8_t t; ! 354: int r = -1; ! 355: CPUState *target_env; ! 356: ! 357: cpu_synchronize_state(env); ! 358: ! 359: /* get order code */ ! 360: order_code = run->s390_sieic.ipb >> 28; ! 361: if (order_code > 0) { ! 362: order_code = env->regs[order_code]; ! 363: } ! 364: order_code += (run->s390_sieic.ipb & 0x0fff0000) >> 16; ! 365: ! 366: /* get parameters */ ! 367: t = (ipa1 & 0xf0) >> 4; ! 368: if (!(t % 2)) { ! 369: t++; ! 370: } ! 371: ! 372: parameter = env->regs[t] & 0x7ffffe00; ! 373: cpu_addr = env->regs[ipa1 & 0x0f]; ! 374: ! 375: target_env = s390_cpu_addr2state(cpu_addr); ! 376: if (!target_env) { ! 377: goto out; ! 378: } ! 379: ! 380: switch (order_code) { ! 381: case SIGP_RESTART: ! 382: r = s390_cpu_restart(target_env); ! 383: break; ! 384: case SIGP_STORE_STATUS_ADDR: ! 385: r = s390_store_status(target_env, parameter); ! 386: break; ! 387: case SIGP_SET_ARCH: ! 388: /* make the caller panic */ ! 389: return -1; ! 390: case SIGP_INITIAL_CPU_RESET: ! 391: r = s390_cpu_initial_reset(target_env); ! 392: break; ! 393: default: ! 394: fprintf(stderr, "KVM: unknown SIGP: 0x%x\n", ipa1); ! 395: break; ! 396: } ! 397: ! 398: out: ! 399: setcc(env, r ? 3 : 0); ! 400: return 0; ! 401: } ! 402: ! 403: static int handle_instruction(CPUState *env, struct kvm_run *run) ! 404: { ! 405: unsigned int ipa0 = (run->s390_sieic.ipa & 0xff00); ! 406: uint8_t ipa1 = run->s390_sieic.ipa & 0x00ff; ! 407: int ipb_code = (run->s390_sieic.ipb & 0x0fff0000) >> 16; ! 408: int r = -1; ! 409: ! 410: dprintf("handle_instruction 0x%x 0x%x\n", run->s390_sieic.ipa, run->s390_sieic.ipb); ! 411: switch (ipa0) { ! 412: case IPA0_PRIV: ! 413: r = handle_priv(env, run, ipa1); ! 414: break; ! 415: case IPA0_DIAG: ! 416: r = handle_diag(env, run, ipb_code); ! 417: break; ! 418: case IPA0_SIGP: ! 419: r = handle_sigp(env, run, ipa1); ! 420: break; ! 421: } ! 422: ! 423: if (r < 0) { ! 424: enter_pgmcheck(env, 0x0001); ! 425: } ! 426: return r; ! 427: } ! 428: ! 429: static int handle_intercept(CPUState *env) ! 430: { ! 431: struct kvm_run *run = env->kvm_run; ! 432: int icpt_code = run->s390_sieic.icptcode; ! 433: int r = 0; ! 434: ! 435: dprintf("intercept: 0x%x (at 0x%lx)\n", icpt_code, env->kvm_run->psw_addr); ! 436: switch (icpt_code) { ! 437: case ICPT_INSTRUCTION: ! 438: r = handle_instruction(env, run); ! 439: break; ! 440: case ICPT_WAITPSW: ! 441: /* XXX What to do on system shutdown? */ ! 442: env->halted = 1; ! 443: env->exception_index = EXCP_HLT; ! 444: break; ! 445: case ICPT_SOFT_INTERCEPT: ! 446: fprintf(stderr, "KVM unimplemented icpt SOFT\n"); ! 447: exit(1); ! 448: break; ! 449: case ICPT_CPU_STOP: ! 450: qemu_system_shutdown_request(); ! 451: break; ! 452: case ICPT_IO: ! 453: fprintf(stderr, "KVM unimplemented icpt IO\n"); ! 454: exit(1); ! 455: break; ! 456: default: ! 457: fprintf(stderr, "Unknown intercept code: %d\n", icpt_code); ! 458: exit(1); ! 459: break; ! 460: } ! 461: ! 462: return r; ! 463: } ! 464: ! 465: int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run) ! 466: { ! 467: int ret = 0; ! 468: ! 469: switch (run->exit_reason) { ! 470: case KVM_EXIT_S390_SIEIC: ! 471: ret = handle_intercept(env); ! 472: break; ! 473: case KVM_EXIT_S390_RESET: ! 474: fprintf(stderr, "RESET not implemented\n"); ! 475: exit(1); ! 476: break; ! 477: default: ! 478: fprintf(stderr, "Unknown KVM exit: %d\n", run->exit_reason); ! 479: break; ! 480: } ! 481: ! 482: return ret; ! 483: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.