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/compat.h"
  28#include "ipl.h"
  29#include "hw/s390x/s390-virtio-ccw.h"
  30#include "hw/s390x/css-bridge.h"
  31
  32static const char *const reset_dev_types[] = {
  33    TYPE_VIRTUAL_CSS_BRIDGE,
  34    "s390-sclp-event-facility",
  35    "s390-flic",
  36    "diag288",
  37};
  38
  39void subsystem_reset(void)
  40{
  41    DeviceState *dev;
  42    int i;
  43
  44    for (i = 0; i < ARRAY_SIZE(reset_dev_types); i++) {
  45        dev = DEVICE(object_resolve_path_type("", reset_dev_types[i], NULL));
  46        if (dev) {
  47            qdev_reset_all(dev);
  48        }
  49    }
  50}
  51
  52static int virtio_ccw_hcall_notify(const uint64_t *args)
  53{
  54    uint64_t subch_id = args[0];
  55    uint64_t queue = args[1];
  56    SubchDev *sch;
  57    int cssid, ssid, schid, m;
  58
  59    if (ioinst_disassemble_sch_ident(subch_id, &m, &cssid, &ssid, &schid)) {
  60        return -EINVAL;
  61    }
  62    sch = css_find_subch(m, cssid, ssid, schid);
  63    if (!sch || !css_subch_visible(sch)) {
  64        return -EINVAL;
  65    }
  66    if (queue >= VIRTIO_CCW_QUEUE_MAX) {
  67        return -EINVAL;
  68    }
  69    virtio_queue_notify(virtio_ccw_get_vdev(sch), queue);
  70    return 0;
  71
  72}
  73
  74static int virtio_ccw_hcall_early_printk(const uint64_t *args)
  75{
  76    uint64_t mem = args[0];
  77
  78    if (mem < ram_size) {
  79        /* Early printk */
  80        return 0;
  81    }
  82    return -EINVAL;
  83}
  84
  85static void virtio_ccw_register_hcalls(void)
  86{
  87    s390_register_virtio_hypercall(KVM_S390_VIRTIO_CCW_NOTIFY,
  88                                   virtio_ccw_hcall_notify);
  89    /* Tolerate early printk. */
  90    s390_register_virtio_hypercall(KVM_S390_VIRTIO_NOTIFY,
  91                                   virtio_ccw_hcall_early_printk);
  92}
  93
  94void s390_memory_init(ram_addr_t mem_size)
  95{
  96    MemoryRegion *sysmem = get_system_memory();
  97    MemoryRegion *ram = g_new(MemoryRegion, 1);
  98
  99    /* allocate RAM for core */
 100    memory_region_allocate_system_memory(ram, NULL, "s390.ram", mem_size);
 101    memory_region_add_subregion(sysmem, 0, ram);
 102
 103    /* Initialize storage key device */
 104    s390_skeys_init();
 105}
 106
 107static void ccw_init(MachineState *machine)
 108{
 109    int ret;
 110    VirtualCssBus *css_bus;
 111    DeviceState *dev;
 112
 113    s390_sclp_init();
 114    s390_memory_init(machine->ram_size);
 115
 116    /* get a BUS */
 117    css_bus = virtual_css_bus_init();
 118    s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline,
 119                      machine->initrd_filename, "s390-ccw.img", true);
 120    s390_flic_init();
 121
 122    dev = qdev_create(NULL, TYPE_S390_PCI_HOST_BRIDGE);
 123    object_property_add_child(qdev_get_machine(), TYPE_S390_PCI_HOST_BRIDGE,
 124                              OBJECT(dev), NULL);
 125    qdev_init_nofail(dev);
 126
 127    /* register hypercalls */
 128    virtio_ccw_register_hcalls();
 129
 130    /* init CPUs */
 131    s390_init_cpus(machine);
 132
 133    if (kvm_enabled()) {
 134        kvm_s390_enable_css_support(s390_cpu_addr2state(0));
 135    }
 136    /*
 137     * Create virtual css and set it as default so that non mcss-e
 138     * enabled guests only see virtio devices.
 139     */
 140    ret = css_create_css_image(VIRTUAL_CSSID, true);
 141    assert(ret == 0);
 142
 143    /* Create VirtIO network adapters */
 144    s390_create_virtio_net(BUS(css_bus), "virtio-net-ccw");
 145
 146    /* Register savevm handler for guest TOD clock */
 147    register_savevm(NULL, "todclock", 0, 1,
 148                    gtod_save, gtod_load, kvm_state);
 149}
 150
 151static void s390_cpu_plug(HotplugHandler *hotplug_dev,
 152                        DeviceState *dev, Error **errp)
 153{
 154    gchar *name;
 155    S390CPU *cpu = S390_CPU(dev);
 156    CPUState *cs = CPU(dev);
 157
 158    name = g_strdup_printf("cpu[%i]", cpu->env.cpu_num);
 159    object_property_set_link(OBJECT(hotplug_dev), OBJECT(cs), name,
 160                             errp);
 161    g_free(name);
 162}
 163
 164static void s390_machine_device_plug(HotplugHandler *hotplug_dev,
 165                                     DeviceState *dev, Error **errp)
 166{
 167    if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
 168        s390_cpu_plug(hotplug_dev, dev, errp);
 169    }
 170}
 171
 172static HotplugHandler *s390_get_hotplug_handler(MachineState *machine,
 173                                                DeviceState *dev)
 174{
 175    if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
 176        return HOTPLUG_HANDLER(machine);
 177    }
 178    return NULL;
 179}
 180
 181static void s390_hot_add_cpu(const int64_t id, Error **errp)
 182{
 183    MachineState *machine = MACHINE(qdev_get_machine());
 184
 185    s390x_new_cpu(machine->cpu_model, id, errp);
 186}
 187
 188static void ccw_machine_class_init(ObjectClass *oc, void *data)
 189{
 190    MachineClass *mc = MACHINE_CLASS(oc);
 191    NMIClass *nc = NMI_CLASS(oc);
 192    HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
 193    S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
 194
 195    s390mc->ri_allowed = true;
 196    s390mc->cpu_model_allowed = true;
 197    mc->init = ccw_init;
 198    mc->reset = s390_machine_reset;
 199    mc->hot_add_cpu = s390_hot_add_cpu;
 200    mc->block_default_type = IF_VIRTIO;
 201    mc->no_cdrom = 1;
 202    mc->no_floppy = 1;
 203    mc->no_serial = 1;
 204    mc->no_parallel = 1;
 205    mc->no_sdcard = 1;
 206    mc->use_sclp = 1;
 207    mc->max_cpus = 248;
 208    mc->get_hotplug_handler = s390_get_hotplug_handler;
 209    hc->plug = s390_machine_device_plug;
 210    nc->nmi_monitor_handler = s390_nmi;
 211}
 212
 213static inline bool machine_get_aes_key_wrap(Object *obj, Error **errp)
 214{
 215    S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
 216
 217    return ms->aes_key_wrap;
 218}
 219
 220static inline void machine_set_aes_key_wrap(Object *obj, bool value,
 221                                            Error **errp)
 222{
 223    S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
 224
 225    ms->aes_key_wrap = value;
 226}
 227
 228static inline bool machine_get_dea_key_wrap(Object *obj, Error **errp)
 229{
 230    S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
 231
 232    return ms->dea_key_wrap;
 233}
 234
 235static inline void machine_set_dea_key_wrap(Object *obj, bool value,
 236                                            Error **errp)
 237{
 238    S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
 239
 240    ms->dea_key_wrap = value;
 241}
 242
 243bool ri_allowed(void)
 244{
 245    if (kvm_enabled()) {
 246        MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
 247        if (object_class_dynamic_cast(OBJECT_CLASS(mc),
 248                                      TYPE_S390_CCW_MACHINE)) {
 249            S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
 250
 251            return s390mc->ri_allowed;
 252        }
 253        /*
 254         * Make sure the "none" machine can have ri, otherwise it won't * be
 255         * unlocked in KVM and therefore the host CPU model might be wrong.
 256         */
 257        return true;
 258    }
 259    return 0;
 260}
 261
 262bool cpu_model_allowed(void)
 263{
 264    MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
 265    if (object_class_dynamic_cast(OBJECT_CLASS(mc),
 266                                  TYPE_S390_CCW_MACHINE)) {
 267        S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
 268
 269        return s390mc->cpu_model_allowed;
 270    }
 271    /* allow CPU model qmp queries with the "none" machine */
 272    return true;
 273}
 274
 275static inline void s390_machine_initfn(Object *obj)
 276{
 277    object_property_add_bool(obj, "aes-key-wrap",
 278                             machine_get_aes_key_wrap,
 279                             machine_set_aes_key_wrap, NULL);
 280    object_property_set_description(obj, "aes-key-wrap",
 281            "enable/disable AES key wrapping using the CPACF wrapping key",
 282            NULL);
 283    object_property_set_bool(obj, true, "aes-key-wrap", NULL);
 284
 285    object_property_add_bool(obj, "dea-key-wrap",
 286                             machine_get_dea_key_wrap,
 287                             machine_set_dea_key_wrap, NULL);
 288    object_property_set_description(obj, "dea-key-wrap",
 289            "enable/disable DEA key wrapping using the CPACF wrapping key",
 290            NULL);
 291    object_property_set_bool(obj, true, "dea-key-wrap", NULL);
 292}
 293
 294static const TypeInfo ccw_machine_info = {
 295    .name          = TYPE_S390_CCW_MACHINE,
 296    .parent        = TYPE_MACHINE,
 297    .abstract      = true,
 298    .instance_size = sizeof(S390CcwMachineState),
 299    .instance_init = s390_machine_initfn,
 300    .class_size = sizeof(S390CcwMachineClass),
 301    .class_init    = ccw_machine_class_init,
 302    .interfaces = (InterfaceInfo[]) {
 303        { TYPE_NMI },
 304        { TYPE_HOTPLUG_HANDLER},
 305        { }
 306    },
 307};
 308
 309#define DEFINE_CCW_MACHINE(suffix, verstr, latest)                            \
 310    static void ccw_machine_##suffix##_class_init(ObjectClass *oc,            \
 311                                                  void *data)                 \
 312    {                                                                         \
 313        MachineClass *mc = MACHINE_CLASS(oc);                                 \
 314        ccw_machine_##suffix##_class_options(mc);                             \
 315        mc->desc = "VirtIO-ccw based S390 machine v" verstr;                  \
 316        if (latest) {                                                         \
 317            mc->alias = "s390-ccw-virtio";                                    \
 318            mc->is_default = 1;                                               \
 319        }                                                                     \
 320    }                                                                         \
 321    static void ccw_machine_##suffix##_instance_init(Object *obj)             \
 322    {                                                                         \
 323        MachineState *machine = MACHINE(obj);                                 \
 324        ccw_machine_##suffix##_instance_options(machine);                     \
 325    }                                                                         \
 326    static const TypeInfo ccw_machine_##suffix##_info = {                     \
 327        .name = MACHINE_TYPE_NAME("s390-ccw-virtio-" verstr),                 \
 328        .parent = TYPE_S390_CCW_MACHINE,                                      \
 329        .class_init = ccw_machine_##suffix##_class_init,                      \
 330        .instance_init = ccw_machine_##suffix##_instance_init,                \
 331    };                                                                        \
 332    static void ccw_machine_register_##suffix(void)                           \
 333    {                                                                         \
 334        type_register_static(&ccw_machine_##suffix##_info);                   \
 335    }                                                                         \
 336    type_init(ccw_machine_register_##suffix)
 337
 338#define CCW_COMPAT_2_7 \
 339        HW_COMPAT_2_7
 340
 341#define CCW_COMPAT_2_6 \
 342        CCW_COMPAT_2_7 \
 343        HW_COMPAT_2_6 \
 344        {\
 345            .driver   = TYPE_S390_IPL,\
 346            .property = "iplbext_migration",\
 347            .value    = "off",\
 348        }, {\
 349            .driver   = TYPE_VIRTUAL_CSS_BRIDGE,\
 350            .property = "css_dev_path",\
 351            .value    = "off",\
 352        },
 353
 354#define CCW_COMPAT_2_5 \
 355        CCW_COMPAT_2_6 \
 356        HW_COMPAT_2_5
 357
 358#define CCW_COMPAT_2_4 \
 359        HW_COMPAT_2_4 \
 360        {\
 361            .driver   = TYPE_S390_SKEYS,\
 362            .property = "migration-enabled",\
 363            .value    = "off",\
 364        },{\
 365            .driver   = "virtio-blk-ccw",\
 366            .property = "max_revision",\
 367            .value    = "0",\
 368        },{\
 369            .driver   = "virtio-balloon-ccw",\
 370            .property = "max_revision",\
 371            .value    = "0",\
 372        },{\
 373            .driver   = "virtio-serial-ccw",\
 374            .property = "max_revision",\
 375            .value    = "0",\
 376        },{\
 377            .driver   = "virtio-9p-ccw",\
 378            .property = "max_revision",\
 379            .value    = "0",\
 380        },{\
 381            .driver   = "virtio-rng-ccw",\
 382            .property = "max_revision",\
 383            .value    = "0",\
 384        },{\
 385            .driver   = "virtio-net-ccw",\
 386            .property = "max_revision",\
 387            .value    = "0",\
 388        },{\
 389            .driver   = "virtio-scsi-ccw",\
 390            .property = "max_revision",\
 391            .value    = "0",\
 392        },{\
 393            .driver   = "vhost-scsi-ccw",\
 394            .property = "max_revision",\
 395            .value    = "0",\
 396        },
 397
 398static void ccw_machine_2_8_instance_options(MachineState *machine)
 399{
 400}
 401
 402static void ccw_machine_2_8_class_options(MachineClass *mc)
 403{
 404}
 405DEFINE_CCW_MACHINE(2_8, "2.8", true);
 406
 407static void ccw_machine_2_7_instance_options(MachineState *machine)
 408{
 409    ccw_machine_2_8_instance_options(machine);
 410}
 411
 412static void ccw_machine_2_7_class_options(MachineClass *mc)
 413{
 414    S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
 415
 416    s390mc->cpu_model_allowed = false;
 417    ccw_machine_2_8_class_options(mc);
 418    SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_7);
 419}
 420DEFINE_CCW_MACHINE(2_7, "2.7", false);
 421
 422static void ccw_machine_2_6_instance_options(MachineState *machine)
 423{
 424    ccw_machine_2_7_instance_options(machine);
 425}
 426
 427static void ccw_machine_2_6_class_options(MachineClass *mc)
 428{
 429    S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
 430
 431    s390mc->ri_allowed = false;
 432    ccw_machine_2_7_class_options(mc);
 433    SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_6);
 434}
 435DEFINE_CCW_MACHINE(2_6, "2.6", false);
 436
 437static void ccw_machine_2_5_instance_options(MachineState *machine)
 438{
 439    ccw_machine_2_6_instance_options(machine);
 440}
 441
 442static void ccw_machine_2_5_class_options(MachineClass *mc)
 443{
 444    ccw_machine_2_6_class_options(mc);
 445    SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_5);
 446}
 447DEFINE_CCW_MACHINE(2_5, "2.5", false);
 448
 449static void ccw_machine_2_4_instance_options(MachineState *machine)
 450{
 451    ccw_machine_2_5_instance_options(machine);
 452}
 453
 454static void ccw_machine_2_4_class_options(MachineClass *mc)
 455{
 456    ccw_machine_2_5_class_options(mc);
 457    SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_4);
 458}
 459DEFINE_CCW_MACHINE(2_4, "2.4", false);
 460
 461static void ccw_machine_register_types(void)
 462{
 463    type_register_static(&ccw_machine_info);
 464}
 465
 466type_init(ccw_machine_register_types)
 467