qemu/target-s390x/misc_helper.c
<<
>>
Prefs
   1/*
   2 *  S/390 misc helper routines
   3 *
   4 *  Copyright (c) 2009 Ulrich Hecht
   5 *  Copyright (c) 2009 Alexander Graf
   6 *
   7 * This library is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU Lesser General Public
   9 * License as published by the Free Software Foundation; either
  10 * version 2 of the License, or (at your option) any later version.
  11 *
  12 * This library is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15 * Lesser General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU Lesser General Public
  18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  19 */
  20
  21#include "cpu.h"
  22#include "exec/memory.h"
  23#include "qemu/host-utils.h"
  24#include "helper.h"
  25#include <string.h>
  26#include "sysemu/kvm.h"
  27#include "qemu/timer.h"
  28#ifdef CONFIG_KVM
  29#include <linux/kvm.h>
  30#endif
  31
  32#if !defined(CONFIG_USER_ONLY)
  33#include "exec/softmmu_exec.h"
  34#include "sysemu/sysemu.h"
  35#endif
  36
  37/* #define DEBUG_HELPER */
  38#ifdef DEBUG_HELPER
  39#define HELPER_LOG(x...) qemu_log(x)
  40#else
  41#define HELPER_LOG(x...)
  42#endif
  43
  44/* Raise an exception dynamically from a helper function.  */
  45void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
  46                                     uintptr_t retaddr)
  47{
  48    int t;
  49
  50    env->exception_index = EXCP_PGM;
  51    env->int_pgm_code = excp;
  52
  53    /* Use the (ultimate) callers address to find the insn that trapped.  */
  54    cpu_restore_state(env, retaddr);
  55
  56    /* Advance past the insn.  */
  57    t = cpu_ldub_code(env, env->psw.addr);
  58    env->int_pgm_ilen = t = get_ilen(t);
  59    env->psw.addr += 2 * t;
  60
  61    cpu_loop_exit(env);
  62}
  63
  64/* Raise an exception statically from a TB.  */
  65void HELPER(exception)(CPUS390XState *env, uint32_t excp)
  66{
  67    HELPER_LOG("%s: exception %d\n", __func__, excp);
  68    env->exception_index = excp;
  69    cpu_loop_exit(env);
  70}
  71
  72#ifndef CONFIG_USER_ONLY
  73
  74/* EBCDIC handling */
  75static const uint8_t ebcdic2ascii[] = {
  76    0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
  77    0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
  78    0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
  79    0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
  80    0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
  81    0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
  82    0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
  83    0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
  84    0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
  85    0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21,
  86    0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
  87    0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
  88    0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
  89    0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
  90    0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
  91    0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
  92    0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
  93    0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
  94    0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
  95    0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
  96    0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
  97    0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
  98    0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
  99    0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07,
 100    0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
 101    0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
 102    0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
 103    0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
 104    0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
 105    0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
 106    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
 107    0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07,
 108};
 109
 110static const uint8_t ascii2ebcdic[] = {
 111    0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
 112    0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
 113    0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
 114    0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
 115    0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
 116    0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
 117    0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
 118    0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
 119    0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
 120    0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
 121    0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
 122    0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,
 123    0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
 124    0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
 125    0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
 126    0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
 127    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
 128    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
 129    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
 130    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
 131    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
 132    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
 133    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
 134    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
 135    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
 136    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
 137    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
 138    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
 139    0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
 140    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
 141    0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
 142    0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
 143};
 144
 145static inline void ebcdic_put(uint8_t *p, const char *ascii, int len)
 146{
 147    int i;
 148
 149    for (i = 0; i < len; i++) {
 150        p[i] = ascii2ebcdic[(uint8_t)ascii[i]];
 151    }
 152}
 153
 154void program_interrupt(CPUS390XState *env, uint32_t code, int ilen)
 155{
 156    qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
 157                  env->psw.addr);
 158
 159    if (kvm_enabled()) {
 160#ifdef CONFIG_KVM
 161        kvm_s390_interrupt(s390_env_get_cpu(env), KVM_S390_PROGRAM_INT, code);
 162#endif
 163    } else {
 164        env->int_pgm_code = code;
 165        env->int_pgm_ilen = ilen;
 166        env->exception_index = EXCP_PGM;
 167        cpu_loop_exit(env);
 168    }
 169}
 170
 171/* SCLP service call */
 172uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2)
 173{
 174    int r = sclp_service_call(r1, r2);
 175    if (r < 0) {
 176        program_interrupt(env, -r, 4);
 177        return 0;
 178    }
 179    return r;
 180}
 181
 182/* DIAG */
 183uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem,
 184                      uint64_t code)
 185{
 186    uint64_t r;
 187
 188    switch (num) {
 189    case 0x500:
 190        /* KVM hypercall */
 191        r = s390_virtio_hypercall(env);
 192        break;
 193    case 0x44:
 194        /* yield */
 195        r = 0;
 196        break;
 197    case 0x308:
 198        /* ipl */
 199        r = 0;
 200        break;
 201    default:
 202        r = -1;
 203        break;
 204    }
 205
 206    if (r) {
 207        program_interrupt(env, PGM_OPERATION, ILEN_LATER_INC);
 208    }
 209
 210    return r;
 211}
 212
 213/* Set Prefix */
 214void HELPER(spx)(CPUS390XState *env, uint64_t a1)
 215{
 216    uint32_t prefix = a1 & 0x7fffe000;
 217    env->psa = prefix;
 218    qemu_log("prefix: %#x\n", prefix);
 219    tlb_flush_page(env, 0);
 220    tlb_flush_page(env, TARGET_PAGE_SIZE);
 221}
 222
 223static inline uint64_t clock_value(CPUS390XState *env)
 224{
 225    uint64_t time;
 226
 227    time = env->tod_offset +
 228        time2tod(qemu_get_clock_ns(vm_clock) - env->tod_basetime);
 229
 230    return time;
 231}
 232
 233/* Store Clock */
 234uint64_t HELPER(stck)(CPUS390XState *env)
 235{
 236    return clock_value(env);
 237}
 238
 239/* Set Clock Comparator */
 240void HELPER(sckc)(CPUS390XState *env, uint64_t time)
 241{
 242    if (time == -1ULL) {
 243        return;
 244    }
 245
 246    /* difference between now and then */
 247    time -= clock_value(env);
 248    /* nanoseconds */
 249    time = (time * 125) >> 9;
 250
 251    qemu_mod_timer(env->tod_timer, qemu_get_clock_ns(vm_clock) + time);
 252}
 253
 254/* Store Clock Comparator */
 255uint64_t HELPER(stckc)(CPUS390XState *env)
 256{
 257    /* XXX implement */
 258    return 0;
 259}
 260
 261/* Set CPU Timer */
 262void HELPER(spt)(CPUS390XState *env, uint64_t time)
 263{
 264    if (time == -1ULL) {
 265        return;
 266    }
 267
 268    /* nanoseconds */
 269    time = (time * 125) >> 9;
 270
 271    qemu_mod_timer(env->cpu_timer, qemu_get_clock_ns(vm_clock) + time);
 272}
 273
 274/* Store CPU Timer */
 275uint64_t HELPER(stpt)(CPUS390XState *env)
 276{
 277    /* XXX implement */
 278    return 0;
 279}
 280
 281/* Store System Information */
 282uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0,
 283                      uint64_t r0, uint64_t r1)
 284{
 285    int cc = 0;
 286    int sel1, sel2;
 287
 288    if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 &&
 289        ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) {
 290        /* valid function code, invalid reserved bits */
 291        program_interrupt(env, PGM_SPECIFICATION, 2);
 292    }
 293
 294    sel1 = r0 & STSI_R0_SEL1_MASK;
 295    sel2 = r1 & STSI_R1_SEL2_MASK;
 296
 297    /* XXX: spec exception if sysib is not 4k-aligned */
 298
 299    switch (r0 & STSI_LEVEL_MASK) {
 300    case STSI_LEVEL_1:
 301        if ((sel1 == 1) && (sel2 == 1)) {
 302            /* Basic Machine Configuration */
 303            struct sysib_111 sysib;
 304
 305            memset(&sysib, 0, sizeof(sysib));
 306            ebcdic_put(sysib.manuf, "QEMU            ", 16);
 307            /* same as machine type number in STORE CPU ID */
 308            ebcdic_put(sysib.type, "QEMU", 4);
 309            /* same as model number in STORE CPU ID */
 310            ebcdic_put(sysib.model, "QEMU            ", 16);
 311            ebcdic_put(sysib.sequence, "QEMU            ", 16);
 312            ebcdic_put(sysib.plant, "QEMU", 4);
 313            cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
 314        } else if ((sel1 == 2) && (sel2 == 1)) {
 315            /* Basic Machine CPU */
 316            struct sysib_121 sysib;
 317
 318            memset(&sysib, 0, sizeof(sysib));
 319            /* XXX make different for different CPUs? */
 320            ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
 321            ebcdic_put(sysib.plant, "QEMU", 4);
 322            stw_p(&sysib.cpu_addr, env->cpu_num);
 323            cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
 324        } else if ((sel1 == 2) && (sel2 == 2)) {
 325            /* Basic Machine CPUs */
 326            struct sysib_122 sysib;
 327
 328            memset(&sysib, 0, sizeof(sysib));
 329            stl_p(&sysib.capability, 0x443afc29);
 330            /* XXX change when SMP comes */
 331            stw_p(&sysib.total_cpus, 1);
 332            stw_p(&sysib.active_cpus, 1);
 333            stw_p(&sysib.standby_cpus, 0);
 334            stw_p(&sysib.reserved_cpus, 0);
 335            cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
 336        } else {
 337            cc = 3;
 338        }
 339        break;
 340    case STSI_LEVEL_2:
 341        {
 342            if ((sel1 == 2) && (sel2 == 1)) {
 343                /* LPAR CPU */
 344                struct sysib_221 sysib;
 345
 346                memset(&sysib, 0, sizeof(sysib));
 347                /* XXX make different for different CPUs? */
 348                ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
 349                ebcdic_put(sysib.plant, "QEMU", 4);
 350                stw_p(&sysib.cpu_addr, env->cpu_num);
 351                stw_p(&sysib.cpu_id, 0);
 352                cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
 353            } else if ((sel1 == 2) && (sel2 == 2)) {
 354                /* LPAR CPUs */
 355                struct sysib_222 sysib;
 356
 357                memset(&sysib, 0, sizeof(sysib));
 358                stw_p(&sysib.lpar_num, 0);
 359                sysib.lcpuc = 0;
 360                /* XXX change when SMP comes */
 361                stw_p(&sysib.total_cpus, 1);
 362                stw_p(&sysib.conf_cpus, 1);
 363                stw_p(&sysib.standby_cpus, 0);
 364                stw_p(&sysib.reserved_cpus, 0);
 365                ebcdic_put(sysib.name, "QEMU    ", 8);
 366                stl_p(&sysib.caf, 1000);
 367                stw_p(&sysib.dedicated_cpus, 0);
 368                stw_p(&sysib.shared_cpus, 0);
 369                cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
 370            } else {
 371                cc = 3;
 372            }
 373            break;
 374        }
 375    case STSI_LEVEL_3:
 376        {
 377            if ((sel1 == 2) && (sel2 == 2)) {
 378                /* VM CPUs */
 379                struct sysib_322 sysib;
 380
 381                memset(&sysib, 0, sizeof(sysib));
 382                sysib.count = 1;
 383                /* XXX change when SMP comes */
 384                stw_p(&sysib.vm[0].total_cpus, 1);
 385                stw_p(&sysib.vm[0].conf_cpus, 1);
 386                stw_p(&sysib.vm[0].standby_cpus, 0);
 387                stw_p(&sysib.vm[0].reserved_cpus, 0);
 388                ebcdic_put(sysib.vm[0].name, "KVMguest", 8);
 389                stl_p(&sysib.vm[0].caf, 1000);
 390                ebcdic_put(sysib.vm[0].cpi, "KVM/Linux       ", 16);
 391                cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
 392            } else {
 393                cc = 3;
 394            }
 395            break;
 396        }
 397    case STSI_LEVEL_CURRENT:
 398        env->regs[0] = STSI_LEVEL_3;
 399        break;
 400    default:
 401        cc = 3;
 402        break;
 403    }
 404
 405    return cc;
 406}
 407
 408uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
 409                      uint64_t cpu_addr)
 410{
 411    int cc = 0;
 412
 413    HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n",
 414               __func__, order_code, r1, cpu_addr);
 415
 416    /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register"
 417       as parameter (input). Status (output) is always R1. */
 418
 419    switch (order_code) {
 420    case SIGP_SET_ARCH:
 421        /* switch arch */
 422        break;
 423    case SIGP_SENSE:
 424        /* enumerate CPU status */
 425        if (cpu_addr) {
 426            /* XXX implement when SMP comes */
 427            return 3;
 428        }
 429        env->regs[r1] &= 0xffffffff00000000ULL;
 430        cc = 1;
 431        break;
 432#if !defined(CONFIG_USER_ONLY)
 433    case SIGP_RESTART:
 434        qemu_system_reset_request();
 435        cpu_loop_exit(env);
 436        break;
 437    case SIGP_STOP:
 438        qemu_system_shutdown_request();
 439        cpu_loop_exit(env);
 440        break;
 441#endif
 442    default:
 443        /* unknown sigp */
 444        fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);
 445        cc = 3;
 446    }
 447
 448    return cc;
 449}
 450#endif
 451