qemu/target/s390x/cpu.c
<<
>>
Prefs
   1/*
   2 * QEMU S/390 CPU
   3 *
   4 * Copyright (c) 2009 Ulrich Hecht
   5 * Copyright (c) 2011 Alexander Graf
   6 * Copyright (c) 2012 SUSE LINUX Products GmbH
   7 * Copyright (c) 2012 IBM Corp.
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License as published by
  11 * the Free Software Foundation; either version 2 of the License, or
  12 * (at your option) any later version.
  13 *
  14 * This program is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * General Public License for more details.
  18 *
  19 * You should have received a copy of the GNU General Public License
  20 * along with this program; if not, see <http://www.gnu.org/licenses/>.
  21 */
  22
  23#include "qemu/osdep.h"
  24#include "qapi/error.h"
  25#include "cpu.h"
  26#include "s390x-internal.h"
  27#include "kvm/kvm_s390x.h"
  28#include "sysemu/kvm.h"
  29#include "qemu/module.h"
  30#include "trace.h"
  31#include "qapi/qapi-types-machine.h"
  32#include "sysemu/hw_accel.h"
  33#include "hw/qdev-properties.h"
  34#include "fpu/softfloat-helpers.h"
  35#include "disas/capstone.h"
  36#include "sysemu/tcg.h"
  37#ifndef CONFIG_USER_ONLY
  38#include "sysemu/reset.h"
  39#endif
  40
  41#define CR0_RESET       0xE0UL
  42#define CR14_RESET      0xC2000000UL;
  43
  44#ifndef CONFIG_USER_ONLY
  45static bool is_early_exception_psw(uint64_t mask, uint64_t addr)
  46{
  47    if (mask & PSW_MASK_RESERVED) {
  48        return true;
  49    }
  50
  51    switch (mask & (PSW_MASK_32 | PSW_MASK_64)) {
  52    case 0:
  53        return addr & ~0xffffffULL;
  54    case PSW_MASK_32:
  55        return addr & ~0x7fffffffULL;
  56    case PSW_MASK_32 | PSW_MASK_64:
  57        return false;
  58    default: /* PSW_MASK_64 */
  59        return true;
  60    }
  61}
  62#endif
  63
  64void s390_cpu_set_psw(CPUS390XState *env, uint64_t mask, uint64_t addr)
  65{
  66#ifndef CONFIG_USER_ONLY
  67    uint64_t old_mask = env->psw.mask;
  68#endif
  69
  70    env->psw.addr = addr;
  71    env->psw.mask = mask;
  72
  73    /* KVM will handle all WAITs and trigger a WAIT exit on disabled_wait */
  74    if (!tcg_enabled()) {
  75        return;
  76    }
  77    env->cc_op = (mask >> 44) & 3;
  78
  79#ifndef CONFIG_USER_ONLY
  80    if (is_early_exception_psw(mask, addr)) {
  81        env->int_pgm_ilen = 0;
  82        trigger_pgm_exception(env, PGM_SPECIFICATION);
  83        return;
  84    }
  85
  86    if ((old_mask ^ mask) & PSW_MASK_PER) {
  87        s390_cpu_recompute_watchpoints(env_cpu(env));
  88    }
  89
  90    if (mask & PSW_MASK_WAIT) {
  91        s390_handle_wait(env_archcpu(env));
  92    }
  93#endif
  94}
  95
  96uint64_t s390_cpu_get_psw_mask(CPUS390XState *env)
  97{
  98    uint64_t r = env->psw.mask;
  99
 100    if (tcg_enabled()) {
 101        uint64_t cc = calc_cc(env, env->cc_op, env->cc_src,
 102                              env->cc_dst, env->cc_vr);
 103
 104        assert(cc <= 3);
 105        r &= ~PSW_MASK_CC;
 106        r |= cc << 44;
 107    }
 108
 109    return r;
 110}
 111
 112static void s390_cpu_set_pc(CPUState *cs, vaddr value)
 113{
 114    S390CPU *cpu = S390_CPU(cs);
 115
 116    cpu->env.psw.addr = value;
 117}
 118
 119static vaddr s390_cpu_get_pc(CPUState *cs)
 120{
 121    S390CPU *cpu = S390_CPU(cs);
 122
 123    return cpu->env.psw.addr;
 124}
 125
 126static bool s390_cpu_has_work(CPUState *cs)
 127{
 128    S390CPU *cpu = S390_CPU(cs);
 129
 130    /* STOPPED cpus can never wake up */
 131    if (s390_cpu_get_state(cpu) != S390_CPU_STATE_LOAD &&
 132        s390_cpu_get_state(cpu) != S390_CPU_STATE_OPERATING) {
 133        return false;
 134    }
 135
 136    if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
 137        return false;
 138    }
 139
 140    return s390_cpu_has_int(cpu);
 141}
 142
 143/* S390CPUClass::reset() */
 144static void s390_cpu_reset(CPUState *s, cpu_reset_type type)
 145{
 146    S390CPU *cpu = S390_CPU(s);
 147    S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
 148    CPUS390XState *env = &cpu->env;
 149    DeviceState *dev = DEVICE(s);
 150
 151    scc->parent_reset(dev);
 152    cpu->env.sigp_order = 0;
 153    s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu);
 154
 155    switch (type) {
 156    case S390_CPU_RESET_CLEAR:
 157        memset(env, 0, offsetof(CPUS390XState, start_initial_reset_fields));
 158        /* fall through */
 159    case S390_CPU_RESET_INITIAL:
 160        /* initial reset does not clear everything! */
 161        memset(&env->start_initial_reset_fields, 0,
 162               offsetof(CPUS390XState, start_normal_reset_fields) -
 163               offsetof(CPUS390XState, start_initial_reset_fields));
 164
 165        /* architectured initial value for Breaking-Event-Address register */
 166        env->gbea = 1;
 167
 168        /* architectured initial values for CR 0 and 14 */
 169        env->cregs[0] = CR0_RESET;
 170        env->cregs[14] = CR14_RESET;
 171
 172#if defined(CONFIG_USER_ONLY)
 173        /* user mode should always be allowed to use the full FPU */
 174        env->cregs[0] |= CR0_AFP;
 175        if (s390_has_feat(S390_FEAT_VECTOR)) {
 176            env->cregs[0] |= CR0_VECTOR;
 177        }
 178#endif
 179
 180        /* tininess for underflow is detected before rounding */
 181        set_float_detect_tininess(float_tininess_before_rounding,
 182                                  &env->fpu_status);
 183       /* fall through */
 184    case S390_CPU_RESET_NORMAL:
 185        env->psw.mask &= ~PSW_MASK_RI;
 186        memset(&env->start_normal_reset_fields, 0,
 187               offsetof(CPUS390XState, end_reset_fields) -
 188               offsetof(CPUS390XState, start_normal_reset_fields));
 189
 190        env->pfault_token = -1UL;
 191        env->bpbc = false;
 192        break;
 193    default:
 194        g_assert_not_reached();
 195    }
 196
 197    /* Reset state inside the kernel that we cannot access yet from QEMU. */
 198    if (kvm_enabled()) {
 199        switch (type) {
 200        case S390_CPU_RESET_CLEAR:
 201            kvm_s390_reset_vcpu_clear(cpu);
 202            break;
 203        case S390_CPU_RESET_INITIAL:
 204            kvm_s390_reset_vcpu_initial(cpu);
 205            break;
 206        case S390_CPU_RESET_NORMAL:
 207            kvm_s390_reset_vcpu_normal(cpu);
 208            break;
 209        }
 210    }
 211}
 212
 213static void s390_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
 214{
 215    info->mach = bfd_mach_s390_64;
 216    info->cap_arch = CS_ARCH_SYSZ;
 217    info->cap_insn_unit = 2;
 218    info->cap_insn_split = 6;
 219}
 220
 221static void s390_cpu_realizefn(DeviceState *dev, Error **errp)
 222{
 223    CPUState *cs = CPU(dev);
 224    S390CPUClass *scc = S390_CPU_GET_CLASS(dev);
 225    Error *err = NULL;
 226
 227    /* the model has to be realized before qemu_init_vcpu() due to kvm */
 228    s390_realize_cpu_model(cs, &err);
 229    if (err) {
 230        goto out;
 231    }
 232
 233#if !defined(CONFIG_USER_ONLY)
 234    if (!s390_cpu_realize_sysemu(dev, &err)) {
 235        goto out;
 236    }
 237#endif
 238
 239    cpu_exec_realizefn(cs, &err);
 240    if (err != NULL) {
 241        goto out;
 242    }
 243
 244#if !defined(CONFIG_USER_ONLY)
 245    qemu_register_reset(s390_cpu_machine_reset_cb, S390_CPU(dev));
 246#endif
 247    s390_cpu_gdb_init(cs);
 248    qemu_init_vcpu(cs);
 249
 250    /*
 251     * KVM requires the initial CPU reset ioctl to be executed on the target
 252     * CPU thread. CPU hotplug under single-threaded TCG will not work with
 253     * run_on_cpu(), as run_on_cpu() will not work properly if called while
 254     * the main thread is already running but the CPU hasn't been realized.
 255     */
 256    if (kvm_enabled()) {
 257        run_on_cpu(cs, s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
 258    } else {
 259        cpu_reset(cs);
 260    }
 261
 262    scc->parent_realize(dev, &err);
 263out:
 264    error_propagate(errp, err);
 265}
 266
 267static void s390_cpu_initfn(Object *obj)
 268{
 269    CPUState *cs = CPU(obj);
 270    S390CPU *cpu = S390_CPU(obj);
 271
 272    cpu_set_cpustate_pointers(cpu);
 273    cs->exception_index = EXCP_HLT;
 274
 275#if !defined(CONFIG_USER_ONLY)
 276    s390_cpu_init_sysemu(obj);
 277#endif
 278}
 279
 280static gchar *s390_gdb_arch_name(CPUState *cs)
 281{
 282    return g_strdup("s390:64-bit");
 283}
 284
 285static Property s390x_cpu_properties[] = {
 286#if !defined(CONFIG_USER_ONLY)
 287    DEFINE_PROP_UINT32("core-id", S390CPU, env.core_id, 0),
 288#endif
 289    DEFINE_PROP_END_OF_LIST()
 290};
 291
 292static void s390_cpu_reset_full(DeviceState *dev)
 293{
 294    CPUState *s = CPU(dev);
 295    return s390_cpu_reset(s, S390_CPU_RESET_CLEAR);
 296}
 297
 298#ifdef CONFIG_TCG
 299#include "hw/core/tcg-cpu-ops.h"
 300
 301static const struct TCGCPUOps s390_tcg_ops = {
 302    .initialize = s390x_translate_init,
 303    .restore_state_to_opc = s390x_restore_state_to_opc,
 304
 305#ifdef CONFIG_USER_ONLY
 306    .record_sigsegv = s390_cpu_record_sigsegv,
 307    .record_sigbus = s390_cpu_record_sigbus,
 308#else
 309    .tlb_fill = s390_cpu_tlb_fill,
 310    .cpu_exec_interrupt = s390_cpu_exec_interrupt,
 311    .do_interrupt = s390_cpu_do_interrupt,
 312    .debug_excp_handler = s390x_cpu_debug_excp_handler,
 313    .do_unaligned_access = s390x_cpu_do_unaligned_access,
 314#endif /* !CONFIG_USER_ONLY */
 315};
 316#endif /* CONFIG_TCG */
 317
 318static void s390_cpu_class_init(ObjectClass *oc, void *data)
 319{
 320    S390CPUClass *scc = S390_CPU_CLASS(oc);
 321    CPUClass *cc = CPU_CLASS(scc);
 322    DeviceClass *dc = DEVICE_CLASS(oc);
 323
 324    device_class_set_parent_realize(dc, s390_cpu_realizefn,
 325                                    &scc->parent_realize);
 326    device_class_set_props(dc, s390x_cpu_properties);
 327    dc->user_creatable = true;
 328
 329    device_class_set_parent_reset(dc, s390_cpu_reset_full, &scc->parent_reset);
 330
 331    scc->reset = s390_cpu_reset;
 332    cc->class_by_name = s390_cpu_class_by_name,
 333    cc->has_work = s390_cpu_has_work;
 334    cc->dump_state = s390_cpu_dump_state;
 335    cc->set_pc = s390_cpu_set_pc;
 336    cc->get_pc = s390_cpu_get_pc;
 337    cc->gdb_read_register = s390_cpu_gdb_read_register;
 338    cc->gdb_write_register = s390_cpu_gdb_write_register;
 339#ifndef CONFIG_USER_ONLY
 340    s390_cpu_class_init_sysemu(cc);
 341#endif
 342    cc->disas_set_info = s390_cpu_disas_set_info;
 343    cc->gdb_num_core_regs = S390_NUM_CORE_REGS;
 344    cc->gdb_core_xml_file = "s390x-core64.xml";
 345    cc->gdb_arch_name = s390_gdb_arch_name;
 346
 347    s390_cpu_model_class_register_props(oc);
 348
 349#ifdef CONFIG_TCG
 350    cc->tcg_ops = &s390_tcg_ops;
 351#endif /* CONFIG_TCG */
 352}
 353
 354static const TypeInfo s390_cpu_type_info = {
 355    .name = TYPE_S390_CPU,
 356    .parent = TYPE_CPU,
 357    .instance_size = sizeof(S390CPU),
 358    .instance_align = __alignof__(S390CPU),
 359    .instance_init = s390_cpu_initfn,
 360
 361#ifndef CONFIG_USER_ONLY
 362    .instance_finalize = s390_cpu_finalize,
 363#endif /* !CONFIG_USER_ONLY */
 364
 365    .abstract = true,
 366    .class_size = sizeof(S390CPUClass),
 367    .class_init = s390_cpu_class_init,
 368};
 369
 370static void s390_cpu_register_types(void)
 371{
 372    type_register_static(&s390_cpu_type_info);
 373}
 374
 375type_init(s390_cpu_register_types)
 376