qemu/hw/s390x/s390-virtio-ccw.c
<<
>>
Prefs
   1/*
   2 * virtio ccw machine
   3 *
   4 * Copyright 2012 IBM Corp.
   5 * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
   6 *
   7 * This work is licensed under the terms of the GNU GPL, version 2 or (at
   8 * your option) any later version. See the COPYING file in the top-level
   9 * directory.
  10 */
  11
  12#include "qemu/osdep.h"
  13#include "qapi/error.h"
  14#include "qemu-common.h"
  15#include "cpu.h"
  16#include "hw/boards.h"
  17#include "exec/address-spaces.h"
  18#include "s390-virtio.h"
  19#include "hw/s390x/sclp.h"
  20#include "hw/s390x/s390_flic.h"
  21#include "hw/s390x/ioinst.h"
  22#include "hw/s390x/css.h"
  23#include "virtio-ccw.h"
  24#include "qemu/config-file.h"
  25#include "s390-pci-bus.h"
  26#include "hw/s390x/storage-keys.h"
  27#include "hw/s390x/storage-attributes.h"
  28#include "hw/compat.h"
  29#include "ipl.h"
  30#include "hw/s390x/s390-virtio-ccw.h"
  31#include "hw/s390x/css-bridge.h"
  32#include "migration/register.h"
  33#include "cpu_models.h"
  34
  35static const char *const reset_dev_types[] = {
  36    TYPE_VIRTUAL_CSS_BRIDGE,
  37    "s390-sclp-event-facility",
  38    "s390-flic",
  39    "diag288",
  40};
  41
  42void subsystem_reset(void)
  43{
  44    DeviceState *dev;
  45    int i;
  46
  47    for (i = 0; i < ARRAY_SIZE(reset_dev_types); i++) {
  48        dev = DEVICE(object_resolve_path_type("", reset_dev_types[i], NULL));
  49        if (dev) {
  50            qdev_reset_all(dev);
  51        }
  52    }
  53}
  54
  55static int virtio_ccw_hcall_notify(const uint64_t *args)
  56{
  57    uint64_t subch_id = args[0];
  58    uint64_t queue = args[1];
  59    SubchDev *sch;
  60    int cssid, ssid, schid, m;
  61
  62    if (ioinst_disassemble_sch_ident(subch_id, &m, &cssid, &ssid, &schid)) {
  63        return -EINVAL;
  64    }
  65    sch = css_find_subch(m, cssid, ssid, schid);
  66    if (!sch || !css_subch_visible(sch)) {
  67        return -EINVAL;
  68    }
  69    if (queue >= VIRTIO_QUEUE_MAX) {
  70        return -EINVAL;
  71    }
  72    virtio_queue_notify(virtio_ccw_get_vdev(sch), queue);
  73    return 0;
  74
  75}
  76
  77static int virtio_ccw_hcall_early_printk(const uint64_t *args)
  78{
  79    uint64_t mem = args[0];
  80
  81    if (mem < ram_size) {
  82        /* Early printk */
  83        return 0;
  84    }
  85    return -EINVAL;
  86}
  87
  88static void virtio_ccw_register_hcalls(void)
  89{
  90    s390_register_virtio_hypercall(KVM_S390_VIRTIO_CCW_NOTIFY,
  91                                   virtio_ccw_hcall_notify);
  92    /* Tolerate early printk. */
  93    s390_register_virtio_hypercall(KVM_S390_VIRTIO_NOTIFY,
  94                                   virtio_ccw_hcall_early_printk);
  95}
  96
  97void s390_memory_init(ram_addr_t mem_size)
  98{
  99    MemoryRegion *sysmem = get_system_memory();
 100    MemoryRegion *ram = g_new(MemoryRegion, 1);
 101
 102    /* allocate RAM for core */
 103    memory_region_allocate_system_memory(ram, NULL, "s390.ram", mem_size);
 104    memory_region_add_subregion(sysmem, 0, ram);
 105
 106    /* Initialize storage key device */
 107    s390_skeys_init();
 108    /* Initialize storage attributes device */
 109    s390_stattrib_init();
 110}
 111
 112static SaveVMHandlers savevm_gtod = {
 113    .save_state = gtod_save,
 114    .load_state = gtod_load,
 115};
 116
 117static void ccw_init(MachineState *machine)
 118{
 119    int ret;
 120    VirtualCssBus *css_bus;
 121    DeviceState *dev;
 122
 123    s390_sclp_init();
 124    s390_memory_init(machine->ram_size);
 125
 126    /* init CPUs */
 127    s390_init_cpus(machine);
 128
 129    s390_flic_init();
 130
 131    /* get a BUS */
 132    css_bus = virtual_css_bus_init();
 133    s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline,
 134                      machine->initrd_filename, "s390-ccw.img",
 135                      "s390-netboot.img", true);
 136
 137    dev = qdev_create(NULL, TYPE_S390_PCI_HOST_BRIDGE);
 138    object_property_add_child(qdev_get_machine(), TYPE_S390_PCI_HOST_BRIDGE,
 139                              OBJECT(dev), NULL);
 140    qdev_init_nofail(dev);
 141
 142    /* register hypercalls */
 143    virtio_ccw_register_hcalls();
 144
 145    if (kvm_enabled()) {
 146        kvm_s390_enable_css_support(s390_cpu_addr2state(0));
 147    }
 148    /*
 149     * Non mcss-e enabled guests only see the devices from the default
 150     * css, which is determined by the value of the squash_mcss property.
 151     * Note: we must not squash non virtual devices to css 0xFE.
 152     */
 153    if (css_bus->squash_mcss) {
 154        ret = css_create_css_image(0, true);
 155    } else {
 156        ret = css_create_css_image(VIRTUAL_CSSID, true);
 157    }
 158    assert(ret == 0);
 159
 160    /* Create VirtIO network adapters */
 161    s390_create_virtio_net(BUS(css_bus), "virtio-net-ccw");
 162
 163    /* Register savevm handler for guest TOD clock */
 164    register_savevm_live(NULL, "todclock", 0, 1, &savevm_gtod, kvm_state);
 165}
 166
 167static void s390_cpu_plug(HotplugHandler *hotplug_dev,
 168                        DeviceState *dev, Error **errp)
 169{
 170    gchar *name;
 171    S390CPU *cpu = S390_CPU(dev);
 172    CPUState *cs = CPU(dev);
 173
 174    name = g_strdup_printf("cpu[%i]", cpu->env.cpu_num);
 175    object_property_set_link(OBJECT(hotplug_dev), OBJECT(cs), name,
 176                             errp);
 177    g_free(name);
 178}
 179
 180static void s390_machine_device_plug(HotplugHandler *hotplug_dev,
 181                                     DeviceState *dev, Error **errp)
 182{
 183    if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
 184        s390_cpu_plug(hotplug_dev, dev, errp);
 185    }
 186}
 187
 188static HotplugHandler *s390_get_hotplug_handler(MachineState *machine,
 189                                                DeviceState *dev)
 190{
 191    if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
 192        return HOTPLUG_HANDLER(machine);
 193    }
 194    return NULL;
 195}
 196
 197static void s390_hot_add_cpu(const int64_t id, Error **errp)
 198{
 199    MachineState *machine = MACHINE(qdev_get_machine());
 200
 201    s390x_new_cpu(machine->cpu_model, id, errp);
 202}
 203
 204static void ccw_machine_class_init(ObjectClass *oc, void *data)
 205{
 206    MachineClass *mc = MACHINE_CLASS(oc);
 207    NMIClass *nc = NMI_CLASS(oc);
 208    HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
 209    S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
 210
 211    s390mc->ri_allowed = true;
 212    s390mc->cpu_model_allowed = true;
 213    s390mc->css_migration_enabled = true;
 214    s390mc->gs_allowed = true;
 215    mc->init = ccw_init;
 216    mc->reset = s390_machine_reset;
 217    mc->hot_add_cpu = s390_hot_add_cpu;
 218    mc->block_default_type = IF_VIRTIO;
 219    mc->no_cdrom = 1;
 220    mc->no_floppy = 1;
 221    mc->no_serial = 1;
 222    mc->no_parallel = 1;
 223    mc->no_sdcard = 1;
 224    mc->use_sclp = 1;
 225    mc->max_cpus = 248;
 226    mc->get_hotplug_handler = s390_get_hotplug_handler;
 227    hc->plug = s390_machine_device_plug;
 228    nc->nmi_monitor_handler = s390_nmi;
 229}
 230
 231static inline bool machine_get_aes_key_wrap(Object *obj, Error **errp)
 232{
 233    S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
 234
 235    return ms->aes_key_wrap;
 236}
 237
 238static inline void machine_set_aes_key_wrap(Object *obj, bool value,
 239                                            Error **errp)
 240{
 241    S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
 242
 243    ms->aes_key_wrap = value;
 244}
 245
 246static inline bool machine_get_dea_key_wrap(Object *obj, Error **errp)
 247{
 248    S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
 249
 250    return ms->dea_key_wrap;
 251}
 252
 253static inline void machine_set_dea_key_wrap(Object *obj, bool value,
 254                                            Error **errp)
 255{
 256    S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
 257
 258    ms->dea_key_wrap = value;
 259}
 260
 261static S390CcwMachineClass *current_mc;
 262
 263static S390CcwMachineClass *get_machine_class(void)
 264{
 265    if (unlikely(!current_mc)) {
 266        /*
 267        * No s390 ccw machine was instantiated, we are likely to
 268        * be called for the 'none' machine. The properties will
 269        * have their after-initialization values.
 270        */
 271        current_mc = S390_MACHINE_CLASS(
 272                     object_class_by_name(TYPE_S390_CCW_MACHINE));
 273    }
 274    return current_mc;
 275}
 276
 277bool ri_allowed(void)
 278{
 279    if (!kvm_enabled()) {
 280        return false;
 281    }
 282    /* for "none" machine this results in true */
 283    return get_machine_class()->ri_allowed;
 284}
 285
 286bool cpu_model_allowed(void)
 287{
 288    /* for "none" machine this results in true */
 289    return get_machine_class()->cpu_model_allowed;
 290}
 291
 292bool gs_allowed(void)
 293{
 294    if (kvm_enabled()) {
 295        MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
 296        if (object_class_dynamic_cast(OBJECT_CLASS(mc),
 297                                      TYPE_S390_CCW_MACHINE)) {
 298            S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
 299
 300            return s390mc->gs_allowed;
 301        }
 302        /* Make sure the "none" machine can have gs */
 303        return true;
 304    }
 305    return false;
 306}
 307
 308static char *machine_get_loadparm(Object *obj, Error **errp)
 309{
 310    S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
 311
 312    return g_memdup(ms->loadparm, sizeof(ms->loadparm));
 313}
 314
 315static void machine_set_loadparm(Object *obj, const char *val, Error **errp)
 316{
 317    S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
 318    int i;
 319
 320    for (i = 0; i < sizeof(ms->loadparm) && val[i]; i++) {
 321        uint8_t c = qemu_toupper(val[i]); /* mimic HMC */
 322
 323        if (('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || (c == '.') ||
 324            (c == ' ')) {
 325            ms->loadparm[i] = c;
 326        } else {
 327            error_setg(errp, "LOADPARM: invalid character '%c' (ASCII 0x%02x)",
 328                       c, c);
 329            return;
 330        }
 331    }
 332
 333    for (; i < sizeof(ms->loadparm); i++) {
 334        ms->loadparm[i] = ' '; /* pad right with spaces */
 335    }
 336}
 337static inline bool machine_get_squash_mcss(Object *obj, Error **errp)
 338{
 339    S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
 340
 341    return ms->s390_squash_mcss;
 342}
 343
 344static inline void machine_set_squash_mcss(Object *obj, bool value,
 345                                           Error **errp)
 346{
 347    S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
 348
 349    ms->s390_squash_mcss = value;
 350}
 351
 352static inline void s390_machine_initfn(Object *obj)
 353{
 354    object_property_add_bool(obj, "aes-key-wrap",
 355                             machine_get_aes_key_wrap,
 356                             machine_set_aes_key_wrap, NULL);
 357    object_property_set_description(obj, "aes-key-wrap",
 358            "enable/disable AES key wrapping using the CPACF wrapping key",
 359            NULL);
 360    object_property_set_bool(obj, true, "aes-key-wrap", NULL);
 361
 362    object_property_add_bool(obj, "dea-key-wrap",
 363                             machine_get_dea_key_wrap,
 364                             machine_set_dea_key_wrap, NULL);
 365    object_property_set_description(obj, "dea-key-wrap",
 366            "enable/disable DEA key wrapping using the CPACF wrapping key",
 367            NULL);
 368    object_property_set_bool(obj, true, "dea-key-wrap", NULL);
 369    object_property_add_str(obj, "loadparm",
 370            machine_get_loadparm, machine_set_loadparm, NULL);
 371    object_property_set_description(obj, "loadparm",
 372            "Up to 8 chars in set of [A-Za-z0-9. ] (lower case chars converted"
 373            " to upper case) to pass to machine loader, boot manager,"
 374            " and guest kernel",
 375            NULL);
 376    object_property_add_bool(obj, "s390-squash-mcss",
 377                             machine_get_squash_mcss,
 378                             machine_set_squash_mcss, NULL);
 379    object_property_set_description(obj, "s390-squash-mcss",
 380            "enable/disable squashing subchannels into the default css",
 381            NULL);
 382    object_property_set_bool(obj, false, "s390-squash-mcss", NULL);
 383}
 384
 385static const TypeInfo ccw_machine_info = {
 386    .name          = TYPE_S390_CCW_MACHINE,
 387    .parent        = TYPE_MACHINE,
 388    .abstract      = true,
 389    .instance_size = sizeof(S390CcwMachineState),
 390    .instance_init = s390_machine_initfn,
 391    .class_size = sizeof(S390CcwMachineClass),
 392    .class_init    = ccw_machine_class_init,
 393    .interfaces = (InterfaceInfo[]) {
 394        { TYPE_NMI },
 395        { TYPE_HOTPLUG_HANDLER},
 396        { }
 397    },
 398};
 399
 400bool css_migration_enabled(void)
 401{
 402    return get_machine_class()->css_migration_enabled;
 403}
 404
 405#define DEFINE_CCW_MACHINE(suffix, verstr, latest)                            \
 406    static void ccw_machine_##suffix##_class_init(ObjectClass *oc,            \
 407                                                  void *data)                 \
 408    {                                                                         \
 409        MachineClass *mc = MACHINE_CLASS(oc);                                 \
 410        ccw_machine_##suffix##_class_options(mc);                             \
 411        mc->desc = "VirtIO-ccw based S390 machine v" verstr;                  \
 412        if (latest) {                                                         \
 413            mc->alias = "s390-ccw-virtio";                                    \
 414            mc->is_default = 1;                                               \
 415        }                                                                     \
 416    }                                                                         \
 417    static void ccw_machine_##suffix##_instance_init(Object *obj)             \
 418    {                                                                         \
 419        MachineState *machine = MACHINE(obj);                                 \
 420        current_mc = S390_MACHINE_CLASS(MACHINE_GET_CLASS(machine));          \
 421        ccw_machine_##suffix##_instance_options(machine);                     \
 422    }                                                                         \
 423    static const TypeInfo ccw_machine_##suffix##_info = {                     \
 424        .name = MACHINE_TYPE_NAME("s390-ccw-virtio-" verstr),                 \
 425        .parent = TYPE_S390_CCW_MACHINE,                                      \
 426        .class_init = ccw_machine_##suffix##_class_init,                      \
 427        .instance_init = ccw_machine_##suffix##_instance_init,                \
 428    };                                                                        \
 429    static void ccw_machine_register_##suffix(void)                           \
 430    {                                                                         \
 431        type_register_static(&ccw_machine_##suffix##_info);                   \
 432    }                                                                         \
 433    type_init(ccw_machine_register_##suffix)
 434
 435#define CCW_COMPAT_2_9 \
 436        HW_COMPAT_2_9 \
 437        {\
 438            .driver   = TYPE_S390_STATTRIB,\
 439            .property = "migration-enabled",\
 440            .value    = "off",\
 441        },
 442
 443#define CCW_COMPAT_2_8 \
 444        HW_COMPAT_2_8 \
 445        {\
 446            .driver   = TYPE_S390_FLIC_COMMON,\
 447            .property = "adapter_routes_max_batch",\
 448            .value    = "64",\
 449        },
 450
 451#define CCW_COMPAT_2_7 \
 452        HW_COMPAT_2_7
 453
 454#define CCW_COMPAT_2_6 \
 455        HW_COMPAT_2_6 \
 456        {\
 457            .driver   = TYPE_S390_IPL,\
 458            .property = "iplbext_migration",\
 459            .value    = "off",\
 460        }, {\
 461            .driver   = TYPE_VIRTUAL_CSS_BRIDGE,\
 462            .property = "css_dev_path",\
 463            .value    = "off",\
 464        },
 465
 466#define CCW_COMPAT_2_5 \
 467        HW_COMPAT_2_5
 468
 469#define CCW_COMPAT_2_4 \
 470        HW_COMPAT_2_4 \
 471        {\
 472            .driver   = TYPE_S390_SKEYS,\
 473            .property = "migration-enabled",\
 474            .value    = "off",\
 475        },{\
 476            .driver   = "virtio-blk-ccw",\
 477            .property = "max_revision",\
 478            .value    = "0",\
 479        },{\
 480            .driver   = "virtio-balloon-ccw",\
 481            .property = "max_revision",\
 482            .value    = "0",\
 483        },{\
 484            .driver   = "virtio-serial-ccw",\
 485            .property = "max_revision",\
 486            .value    = "0",\
 487        },{\
 488            .driver   = "virtio-9p-ccw",\
 489            .property = "max_revision",\
 490            .value    = "0",\
 491        },{\
 492            .driver   = "virtio-rng-ccw",\
 493            .property = "max_revision",\
 494            .value    = "0",\
 495        },{\
 496            .driver   = "virtio-net-ccw",\
 497            .property = "max_revision",\
 498            .value    = "0",\
 499        },{\
 500            .driver   = "virtio-scsi-ccw",\
 501            .property = "max_revision",\
 502            .value    = "0",\
 503        },{\
 504            .driver   = "vhost-scsi-ccw",\
 505            .property = "max_revision",\
 506            .value    = "0",\
 507        },
 508
 509static void ccw_machine_2_10_instance_options(MachineState *machine)
 510{
 511    if (css_migration_enabled()) {
 512        css_register_vmstate();
 513    }
 514}
 515
 516static void ccw_machine_2_10_class_options(MachineClass *mc)
 517{
 518}
 519DEFINE_CCW_MACHINE(2_10, "2.10", true);
 520
 521static void ccw_machine_2_9_instance_options(MachineState *machine)
 522{
 523    ccw_machine_2_10_instance_options(machine);
 524    s390_cpudef_featoff_greater(12, 1, S390_FEAT_ESOP);
 525    s390_cpudef_featoff_greater(12, 1, S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2);
 526    s390_cpudef_featoff_greater(12, 1, S390_FEAT_ZPCI);
 527    s390_cpudef_featoff_greater(12, 1, S390_FEAT_ADAPTER_INT_SUPPRESSION);
 528    s390_cpudef_featoff_greater(12, 1, S390_FEAT_ADAPTER_EVENT_NOTIFICATION);
 529}
 530
 531static void ccw_machine_2_9_class_options(MachineClass *mc)
 532{
 533    S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
 534
 535    s390mc->gs_allowed = false;
 536    ccw_machine_2_10_class_options(mc);
 537    SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_9);
 538    s390mc->css_migration_enabled = false;
 539}
 540DEFINE_CCW_MACHINE(2_9, "2.9", false);
 541
 542static void ccw_machine_2_8_instance_options(MachineState *machine)
 543{
 544    ccw_machine_2_9_instance_options(machine);
 545}
 546
 547static void ccw_machine_2_8_class_options(MachineClass *mc)
 548{
 549    ccw_machine_2_9_class_options(mc);
 550    SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_8);
 551}
 552DEFINE_CCW_MACHINE(2_8, "2.8", false);
 553
 554static void ccw_machine_2_7_instance_options(MachineState *machine)
 555{
 556    ccw_machine_2_8_instance_options(machine);
 557}
 558
 559static void ccw_machine_2_7_class_options(MachineClass *mc)
 560{
 561    S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
 562
 563    s390mc->cpu_model_allowed = false;
 564    ccw_machine_2_8_class_options(mc);
 565    SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_7);
 566}
 567DEFINE_CCW_MACHINE(2_7, "2.7", false);
 568
 569static void ccw_machine_2_6_instance_options(MachineState *machine)
 570{
 571    ccw_machine_2_7_instance_options(machine);
 572}
 573
 574static void ccw_machine_2_6_class_options(MachineClass *mc)
 575{
 576    S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
 577
 578    s390mc->ri_allowed = false;
 579    ccw_machine_2_7_class_options(mc);
 580    SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_6);
 581}
 582DEFINE_CCW_MACHINE(2_6, "2.6", false);
 583
 584static void ccw_machine_2_5_instance_options(MachineState *machine)
 585{
 586    ccw_machine_2_6_instance_options(machine);
 587}
 588
 589static void ccw_machine_2_5_class_options(MachineClass *mc)
 590{
 591    ccw_machine_2_6_class_options(mc);
 592    SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_5);
 593}
 594DEFINE_CCW_MACHINE(2_5, "2.5", false);
 595
 596static void ccw_machine_2_4_instance_options(MachineState *machine)
 597{
 598    ccw_machine_2_5_instance_options(machine);
 599}
 600
 601static void ccw_machine_2_4_class_options(MachineClass *mc)
 602{
 603    ccw_machine_2_5_class_options(mc);
 604    SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_4);
 605}
 606DEFINE_CCW_MACHINE(2_4, "2.4", false);
 607
 608static void ccw_machine_register_types(void)
 609{
 610    type_register_static(&ccw_machine_info);
 611}
 612
 613type_init(ccw_machine_register_types)
 614