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