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 library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation; either
  12 * version 2.1 of the License, or (at your option) any later version.
  13 *
  14 * This library 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 * Lesser General Public License for more details.
  18 *
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, see
  21 * <http://www.gnu.org/licenses/lgpl-2.1.html>
  22 * Contributions after 2012-12-11 are licensed under the terms of the
  23 * GNU GPL, version 2 or (at your option) any later version.
  24 */
  25
  26#include "qemu/osdep.h"
  27#include "qapi/error.h"
  28#include "cpu.h"
  29#include "internal.h"
  30#include "kvm_s390x.h"
  31#include "sysemu/kvm.h"
  32#include "qemu-common.h"
  33#include "qemu/cutils.h"
  34#include "qemu/timer.h"
  35#include "qemu/error-report.h"
  36#include "trace.h"
  37#include "qapi/visitor.h"
  38#include "exec/exec-all.h"
  39#include "hw/qdev-properties.h"
  40#ifndef CONFIG_USER_ONLY
  41#include "hw/hw.h"
  42#include "sysemu/arch_init.h"
  43#include "sysemu/sysemu.h"
  44#endif
  45
  46#define CR0_RESET       0xE0UL
  47#define CR14_RESET      0xC2000000UL;
  48
  49static void s390_cpu_set_pc(CPUState *cs, vaddr value)
  50{
  51    S390CPU *cpu = S390_CPU(cs);
  52
  53    cpu->env.psw.addr = value;
  54}
  55
  56static bool s390_cpu_has_work(CPUState *cs)
  57{
  58    S390CPU *cpu = S390_CPU(cs);
  59
  60    /* STOPPED cpus can never wake up */
  61    if (s390_cpu_get_state(cpu) != CPU_STATE_LOAD &&
  62        s390_cpu_get_state(cpu) != CPU_STATE_OPERATING) {
  63        return false;
  64    }
  65
  66    if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
  67        return false;
  68    }
  69
  70    return s390_cpu_has_int(cpu);
  71}
  72
  73#if !defined(CONFIG_USER_ONLY)
  74/* S390CPUClass::load_normal() */
  75static void s390_cpu_load_normal(CPUState *s)
  76{
  77    S390CPU *cpu = S390_CPU(s);
  78    cpu->env.psw.addr = ldl_phys(s->as, 4) & PSW_MASK_ESA_ADDR;
  79    cpu->env.psw.mask = PSW_MASK_32 | PSW_MASK_64;
  80    s390_cpu_set_state(CPU_STATE_OPERATING, cpu);
  81}
  82#endif
  83
  84/* S390CPUClass::cpu_reset() */
  85static void s390_cpu_reset(CPUState *s)
  86{
  87    S390CPU *cpu = S390_CPU(s);
  88    S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
  89    CPUS390XState *env = &cpu->env;
  90
  91    env->pfault_token = -1UL;
  92    env->bpbc = false;
  93    scc->parent_reset(s);
  94    cpu->env.sigp_order = 0;
  95    s390_cpu_set_state(CPU_STATE_STOPPED, cpu);
  96}
  97
  98/* S390CPUClass::initial_reset() */
  99static void s390_cpu_initial_reset(CPUState *s)
 100{
 101    S390CPU *cpu = S390_CPU(s);
 102    CPUS390XState *env = &cpu->env;
 103    int i;
 104
 105    s390_cpu_reset(s);
 106    /* initial reset does not clear everything! */
 107    memset(&env->start_initial_reset_fields, 0,
 108        offsetof(CPUS390XState, end_reset_fields) -
 109        offsetof(CPUS390XState, start_initial_reset_fields));
 110
 111    /* architectured initial values for CR 0 and 14 */
 112    env->cregs[0] = CR0_RESET;
 113    env->cregs[14] = CR14_RESET;
 114
 115    /* architectured initial value for Breaking-Event-Address register */
 116    env->gbea = 1;
 117
 118    env->pfault_token = -1UL;
 119    for (i = 0; i < ARRAY_SIZE(env->io_index); i++) {
 120        env->io_index[i] = -1;
 121    }
 122    env->mchk_index = -1;
 123
 124    /* tininess for underflow is detected before rounding */
 125    set_float_detect_tininess(float_tininess_before_rounding,
 126                              &env->fpu_status);
 127
 128    /* Reset state inside the kernel that we cannot access yet from QEMU. */
 129    if (kvm_enabled()) {
 130        kvm_s390_reset_vcpu(cpu);
 131    }
 132}
 133
 134/* CPUClass:reset() */
 135static void s390_cpu_full_reset(CPUState *s)
 136{
 137    S390CPU *cpu = S390_CPU(s);
 138    S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
 139    CPUS390XState *env = &cpu->env;
 140    int i;
 141
 142    scc->parent_reset(s);
 143    cpu->env.sigp_order = 0;
 144    s390_cpu_set_state(CPU_STATE_STOPPED, cpu);
 145
 146    memset(env, 0, offsetof(CPUS390XState, end_reset_fields));
 147
 148    /* architectured initial values for CR 0 and 14 */
 149    env->cregs[0] = CR0_RESET;
 150    env->cregs[14] = CR14_RESET;
 151
 152    /* architectured initial value for Breaking-Event-Address register */
 153    env->gbea = 1;
 154
 155    env->pfault_token = -1UL;
 156    for (i = 0; i < ARRAY_SIZE(env->io_index); i++) {
 157        env->io_index[i] = -1;
 158    }
 159    env->mchk_index = -1;
 160
 161    /* tininess for underflow is detected before rounding */
 162    set_float_detect_tininess(float_tininess_before_rounding,
 163                              &env->fpu_status);
 164
 165    /* Reset state inside the kernel that we cannot access yet from QEMU. */
 166    if (kvm_enabled()) {
 167        kvm_s390_reset_vcpu(cpu);
 168    }
 169}
 170
 171#if !defined(CONFIG_USER_ONLY)
 172static void s390_cpu_machine_reset_cb(void *opaque)
 173{
 174    S390CPU *cpu = opaque;
 175
 176    run_on_cpu(CPU(cpu), s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
 177}
 178#endif
 179
 180static void s390_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
 181{
 182    info->mach = bfd_mach_s390_64;
 183    info->print_insn = print_insn_s390;
 184}
 185
 186static void s390_cpu_realizefn(DeviceState *dev, Error **errp)
 187{
 188    CPUState *cs = CPU(dev);
 189    S390CPUClass *scc = S390_CPU_GET_CLASS(dev);
 190#if !defined(CONFIG_USER_ONLY)
 191    S390CPU *cpu = S390_CPU(dev);
 192#endif
 193    Error *err = NULL;
 194
 195    /* the model has to be realized before qemu_init_vcpu() due to kvm */
 196    s390_realize_cpu_model(cs, &err);
 197    if (err) {
 198        goto out;
 199    }
 200
 201#if !defined(CONFIG_USER_ONLY)
 202    if (cpu->env.core_id >= max_cpus) {
 203        error_setg(&err, "Unable to add CPU with core-id: %" PRIu32
 204                   ", maximum core-id: %d", cpu->env.core_id,
 205                   max_cpus - 1);
 206        goto out;
 207    }
 208
 209    if (cpu_exists(cpu->env.core_id)) {
 210        error_setg(&err, "Unable to add CPU with core-id: %" PRIu32
 211                   ", it already exists", cpu->env.core_id);
 212        goto out;
 213    }
 214
 215    /* sync cs->cpu_index and env->core_id. The latter is needed for TCG. */
 216    cs->cpu_index = cpu->env.core_id;
 217#endif
 218
 219    cpu_exec_realizefn(cs, &err);
 220    if (err != NULL) {
 221        goto out;
 222    }
 223
 224#if !defined(CONFIG_USER_ONLY)
 225    qemu_register_reset(s390_cpu_machine_reset_cb, cpu);
 226#endif
 227    s390_cpu_gdb_init(cs);
 228    qemu_init_vcpu(cs);
 229#if !defined(CONFIG_USER_ONLY)
 230    run_on_cpu(cs, s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
 231#else
 232    cpu_reset(cs);
 233#endif
 234
 235    scc->parent_realize(dev, &err);
 236out:
 237    error_propagate(errp, err);
 238}
 239
 240static void s390_cpu_initfn(Object *obj)
 241{
 242    CPUState *cs = CPU(obj);
 243    S390CPU *cpu = S390_CPU(obj);
 244    CPUS390XState *env = &cpu->env;
 245#if !defined(CONFIG_USER_ONLY)
 246    struct tm tm;
 247#endif
 248
 249    cs->env_ptr = env;
 250    cs->halted = 1;
 251    cs->exception_index = EXCP_HLT;
 252    s390_cpu_model_register_props(obj);
 253#if !defined(CONFIG_USER_ONLY)
 254    qemu_get_timedate(&tm, 0);
 255    env->tod_offset = TOD_UNIX_EPOCH +
 256                      (time2tod(mktimegm(&tm)) * 1000000000ULL);
 257    env->tod_basetime = 0;
 258    env->tod_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_tod_timer, cpu);
 259    env->cpu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_cpu_timer, cpu);
 260    s390_cpu_set_state(CPU_STATE_STOPPED, cpu);
 261#endif
 262}
 263
 264static void s390_cpu_finalize(Object *obj)
 265{
 266#if !defined(CONFIG_USER_ONLY)
 267    S390CPU *cpu = S390_CPU(obj);
 268
 269    qemu_unregister_reset(s390_cpu_machine_reset_cb, cpu);
 270    g_free(cpu->irqstate);
 271#endif
 272}
 273
 274#if !defined(CONFIG_USER_ONLY)
 275static bool disabled_wait(CPUState *cpu)
 276{
 277    return cpu->halted && !(S390_CPU(cpu)->env.psw.mask &
 278                            (PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK));
 279}
 280
 281static unsigned s390_count_running_cpus(void)
 282{
 283    CPUState *cpu;
 284    int nr_running = 0;
 285
 286    CPU_FOREACH(cpu) {
 287        uint8_t state = S390_CPU(cpu)->env.cpu_state;
 288        if (state == CPU_STATE_OPERATING ||
 289            state == CPU_STATE_LOAD) {
 290            if (!disabled_wait(cpu)) {
 291                nr_running++;
 292            }
 293        }
 294    }
 295
 296    return nr_running;
 297}
 298
 299unsigned int s390_cpu_halt(S390CPU *cpu)
 300{
 301    CPUState *cs = CPU(cpu);
 302    trace_cpu_halt(cs->cpu_index);
 303
 304    if (!cs->halted) {
 305        cs->halted = 1;
 306        cs->exception_index = EXCP_HLT;
 307    }
 308
 309    return s390_count_running_cpus();
 310}
 311
 312void s390_cpu_unhalt(S390CPU *cpu)
 313{
 314    CPUState *cs = CPU(cpu);
 315    trace_cpu_unhalt(cs->cpu_index);
 316
 317    if (cs->halted) {
 318        cs->halted = 0;
 319        cs->exception_index = -1;
 320    }
 321}
 322
 323unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu)
 324 {
 325    trace_cpu_set_state(CPU(cpu)->cpu_index, cpu_state);
 326
 327    switch (cpu_state) {
 328    case CPU_STATE_STOPPED:
 329    case CPU_STATE_CHECK_STOP:
 330        /* halt the cpu for common infrastructure */
 331        s390_cpu_halt(cpu);
 332        break;
 333    case CPU_STATE_OPERATING:
 334    case CPU_STATE_LOAD:
 335        /*
 336         * Starting a CPU with a PSW WAIT bit set:
 337         * KVM: handles this internally and triggers another WAIT exit.
 338         * TCG: will actually try to continue to run. Don't unhalt, will
 339         *      be done when the CPU actually has work (an interrupt).
 340         */
 341        if (!tcg_enabled() || !(cpu->env.psw.mask & PSW_MASK_WAIT)) {
 342            s390_cpu_unhalt(cpu);
 343        }
 344        break;
 345    default:
 346        error_report("Requested CPU state is not a valid S390 CPU state: %u",
 347                     cpu_state);
 348        exit(1);
 349    }
 350    if (kvm_enabled() && cpu->env.cpu_state != cpu_state) {
 351        kvm_s390_set_cpu_state(cpu, cpu_state);
 352    }
 353    cpu->env.cpu_state = cpu_state;
 354
 355    return s390_count_running_cpus();
 356}
 357
 358int s390_get_clock(uint8_t *tod_high, uint64_t *tod_low)
 359{
 360    int r = 0;
 361
 362    if (kvm_enabled()) {
 363        r = kvm_s390_get_clock_ext(tod_high, tod_low);
 364        if (r == -ENXIO) {
 365            return kvm_s390_get_clock(tod_high, tod_low);
 366        }
 367    } else {
 368        /* Fixme TCG */
 369        *tod_high = 0;
 370        *tod_low = 0;
 371    }
 372
 373    return r;
 374}
 375
 376int s390_set_clock(uint8_t *tod_high, uint64_t *tod_low)
 377{
 378    int r = 0;
 379
 380    if (kvm_enabled()) {
 381        r = kvm_s390_set_clock_ext(tod_high, tod_low);
 382        if (r == -ENXIO) {
 383            return kvm_s390_set_clock(tod_high, tod_low);
 384        }
 385    }
 386    /* Fixme TCG */
 387    return r;
 388}
 389
 390int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit)
 391{
 392    if (kvm_enabled()) {
 393        return kvm_s390_set_mem_limit(new_limit, hw_limit);
 394    }
 395    return 0;
 396}
 397
 398void s390_cmma_reset(void)
 399{
 400    if (kvm_enabled()) {
 401        kvm_s390_cmma_reset();
 402    }
 403}
 404
 405int s390_get_memslot_count(void)
 406{
 407    if (kvm_enabled()) {
 408        return kvm_s390_get_memslot_count();
 409    } else {
 410        return MAX_AVAIL_SLOTS;
 411    }
 412}
 413
 414int s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch_id,
 415                                int vq, bool assign)
 416{
 417    if (kvm_enabled()) {
 418        return kvm_s390_assign_subch_ioeventfd(notifier, sch_id, vq, assign);
 419    } else {
 420        return 0;
 421    }
 422}
 423
 424void s390_crypto_reset(void)
 425{
 426    if (kvm_enabled()) {
 427        kvm_s390_crypto_reset();
 428    }
 429}
 430
 431bool s390_get_squash_mcss(void)
 432{
 433    if (object_property_get_bool(OBJECT(qdev_get_machine()), "s390-squash-mcss",
 434                                 NULL)) {
 435        return true;
 436    }
 437
 438    return false;
 439}
 440
 441void s390_enable_css_support(S390CPU *cpu)
 442{
 443    if (kvm_enabled()) {
 444        kvm_s390_enable_css_support(cpu);
 445    }
 446}
 447#endif
 448
 449static gchar *s390_gdb_arch_name(CPUState *cs)
 450{
 451    return g_strdup("s390:64-bit");
 452}
 453
 454static Property s390x_cpu_properties[] = {
 455#if !defined(CONFIG_USER_ONLY)
 456    DEFINE_PROP_UINT32("core-id", S390CPU, env.core_id, 0),
 457#endif
 458    DEFINE_PROP_END_OF_LIST()
 459};
 460
 461static void s390_cpu_class_init(ObjectClass *oc, void *data)
 462{
 463    S390CPUClass *scc = S390_CPU_CLASS(oc);
 464    CPUClass *cc = CPU_CLASS(scc);
 465    DeviceClass *dc = DEVICE_CLASS(oc);
 466
 467    scc->parent_realize = dc->realize;
 468    dc->realize = s390_cpu_realizefn;
 469    dc->props = s390x_cpu_properties;
 470    dc->user_creatable = true;
 471
 472    scc->parent_reset = cc->reset;
 473#if !defined(CONFIG_USER_ONLY)
 474    scc->load_normal = s390_cpu_load_normal;
 475#endif
 476    scc->cpu_reset = s390_cpu_reset;
 477    scc->initial_cpu_reset = s390_cpu_initial_reset;
 478    cc->reset = s390_cpu_full_reset;
 479    cc->class_by_name = s390_cpu_class_by_name,
 480    cc->has_work = s390_cpu_has_work;
 481#ifdef CONFIG_TCG
 482    cc->do_interrupt = s390_cpu_do_interrupt;
 483#endif
 484    cc->dump_state = s390_cpu_dump_state;
 485    cc->set_pc = s390_cpu_set_pc;
 486    cc->gdb_read_register = s390_cpu_gdb_read_register;
 487    cc->gdb_write_register = s390_cpu_gdb_write_register;
 488#ifdef CONFIG_USER_ONLY
 489    cc->handle_mmu_fault = s390_cpu_handle_mmu_fault;
 490#else
 491    cc->get_phys_page_debug = s390_cpu_get_phys_page_debug;
 492    cc->vmsd = &vmstate_s390_cpu;
 493    cc->write_elf64_note = s390_cpu_write_elf64_note;
 494#ifdef CONFIG_TCG
 495    cc->cpu_exec_interrupt = s390_cpu_exec_interrupt;
 496    cc->debug_excp_handler = s390x_cpu_debug_excp_handler;
 497    cc->do_unaligned_access = s390x_cpu_do_unaligned_access;
 498#endif
 499#endif
 500    cc->disas_set_info = s390_cpu_disas_set_info;
 501#ifdef CONFIG_TCG
 502    cc->tcg_initialize = s390x_translate_init;
 503#endif
 504
 505    cc->gdb_num_core_regs = S390_NUM_CORE_REGS;
 506    cc->gdb_core_xml_file = "s390x-core64.xml";
 507    cc->gdb_arch_name = s390_gdb_arch_name;
 508
 509    s390_cpu_model_class_register_props(oc);
 510}
 511
 512static const TypeInfo s390_cpu_type_info = {
 513    .name = TYPE_S390_CPU,
 514    .parent = TYPE_CPU,
 515    .instance_size = sizeof(S390CPU),
 516    .instance_init = s390_cpu_initfn,
 517    .instance_finalize = s390_cpu_finalize,
 518    .abstract = true,
 519    .class_size = sizeof(S390CPUClass),
 520    .class_init = s390_cpu_class_init,
 521};
 522
 523static void s390_cpu_register_types(void)
 524{
 525    type_register_static(&s390_cpu_type_info);
 526}
 527
 528type_init(s390_cpu_register_types)
 529