qemu/hw/s390x/s390-virtio.c
<<
>>
Prefs
   1/*
   2 * QEMU S390 virtio target
   3 *
   4 * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
   5 * Copyright IBM Corp 2012
   6 *
   7 * This library is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU Lesser General Public
   9 * License as published by the Free Software Foundation; either
  10 * version 2 of the License, or (at your option) any later version.
  11 *
  12 * This library is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15 * Lesser General Public License for more details.
  16 *
  17 * Contributions after 2012-10-29 are licensed under the terms of the
  18 * GNU GPL, version 2 or (at your option) any later version.
  19 *
  20 * You should have received a copy of the GNU (Lesser) General Public
  21 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  22 */
  23
  24#include "hw/hw.h"
  25#include "block/block.h"
  26#include "sysemu/blockdev.h"
  27#include "sysemu/sysemu.h"
  28#include "net/net.h"
  29#include "hw/boards.h"
  30#include "monitor/monitor.h"
  31#include "hw/loader.h"
  32#include "hw/virtio/virtio.h"
  33#include "hw/sysbus.h"
  34#include "sysemu/kvm.h"
  35#include "exec/address-spaces.h"
  36
  37#include "hw/s390x/s390-virtio-bus.h"
  38#include "hw/s390x/sclp.h"
  39#include "hw/s390x/s390-virtio.h"
  40
  41//#define DEBUG_S390
  42
  43#ifdef DEBUG_S390
  44#define dprintf(fmt, ...) \
  45    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
  46#else
  47#define dprintf(fmt, ...) \
  48    do { } while (0)
  49#endif
  50
  51#define MAX_BLK_DEVS                    10
  52#define ZIPL_FILENAME                   "s390-zipl.rom"
  53
  54static VirtIOS390Bus *s390_bus;
  55static S390CPU **ipi_states;
  56
  57S390CPU *s390_cpu_addr2state(uint16_t cpu_addr)
  58{
  59    if (cpu_addr >= smp_cpus) {
  60        return NULL;
  61    }
  62
  63    return ipi_states[cpu_addr];
  64}
  65
  66static int s390_virtio_hcall_notify(const uint64_t *args)
  67{
  68    uint64_t mem = args[0];
  69    int r = 0, i;
  70
  71    if (mem > ram_size) {
  72        VirtIOS390Device *dev = s390_virtio_bus_find_vring(s390_bus, mem, &i);
  73        if (dev) {
  74            virtio_queue_notify(dev->vdev, i);
  75        } else {
  76            r = -EINVAL;
  77        }
  78    } else {
  79        /* Early printk */
  80    }
  81    return r;
  82}
  83
  84static int s390_virtio_hcall_reset(const uint64_t *args)
  85{
  86    uint64_t mem = args[0];
  87    VirtIOS390Device *dev;
  88
  89    dev = s390_virtio_bus_find_mem(s390_bus, mem);
  90    if (dev == NULL) {
  91        return -EINVAL;
  92    }
  93    virtio_reset(dev->vdev);
  94    stb_phys(dev->dev_offs + VIRTIO_DEV_OFFS_STATUS, 0);
  95    s390_virtio_device_sync(dev);
  96    s390_virtio_reset_idx(dev);
  97
  98    return 0;
  99}
 100
 101static int s390_virtio_hcall_set_status(const uint64_t *args)
 102{
 103    uint64_t mem = args[0];
 104    int r = 0;
 105    VirtIOS390Device *dev;
 106
 107    dev = s390_virtio_bus_find_mem(s390_bus, mem);
 108    if (dev) {
 109        s390_virtio_device_update_status(dev);
 110    } else {
 111        r = -EINVAL;
 112    }
 113    return r;
 114}
 115
 116static void s390_virtio_register_hcalls(void)
 117{
 118    s390_register_virtio_hypercall(KVM_S390_VIRTIO_NOTIFY,
 119                                   s390_virtio_hcall_notify);
 120    s390_register_virtio_hypercall(KVM_S390_VIRTIO_RESET,
 121                                   s390_virtio_hcall_reset);
 122    s390_register_virtio_hypercall(KVM_S390_VIRTIO_SET_STATUS,
 123                                   s390_virtio_hcall_set_status);
 124}
 125
 126/*
 127 * The number of running CPUs. On s390 a shutdown is the state of all CPUs
 128 * being either stopped or disabled (for interrupts) waiting. We have to
 129 * track this number to call the shutdown sequence accordingly. This
 130 * number is modified either on startup or while holding the big qemu lock.
 131 */
 132static unsigned s390_running_cpus;
 133
 134void s390_add_running_cpu(S390CPU *cpu)
 135{
 136    CPUState *cs = CPU(cpu);
 137    CPUS390XState *env = &cpu->env;
 138
 139    if (cs->halted) {
 140        s390_running_cpus++;
 141        cs->halted = 0;
 142        env->exception_index = -1;
 143    }
 144}
 145
 146unsigned s390_del_running_cpu(S390CPU *cpu)
 147{
 148    CPUState *cs = CPU(cpu);
 149    CPUS390XState *env = &cpu->env;
 150
 151    if (cs->halted == 0) {
 152        assert(s390_running_cpus >= 1);
 153        s390_running_cpus--;
 154        cs->halted = 1;
 155        env->exception_index = EXCP_HLT;
 156    }
 157    return s390_running_cpus;
 158}
 159
 160void s390_init_ipl_dev(const char *kernel_filename,
 161                       const char *kernel_cmdline,
 162                       const char *initrd_filename,
 163                       const char *firmware)
 164{
 165    DeviceState *dev;
 166
 167    dev  = qdev_create(NULL, "s390-ipl");
 168    if (kernel_filename) {
 169        qdev_prop_set_string(dev, "kernel", kernel_filename);
 170    }
 171    if (initrd_filename) {
 172        qdev_prop_set_string(dev, "initrd", initrd_filename);
 173    }
 174    qdev_prop_set_string(dev, "cmdline", kernel_cmdline);
 175    qdev_prop_set_string(dev, "firmware", firmware);
 176    qdev_init_nofail(dev);
 177}
 178
 179void s390_init_cpus(const char *cpu_model, uint8_t *storage_keys)
 180{
 181    int i;
 182
 183    if (cpu_model == NULL) {
 184        cpu_model = "host";
 185    }
 186
 187    ipi_states = g_malloc(sizeof(S390CPU *) * smp_cpus);
 188
 189    for (i = 0; i < smp_cpus; i++) {
 190        S390CPU *cpu;
 191        CPUState *cs;
 192
 193        cpu = cpu_s390x_init(cpu_model);
 194        cs = CPU(cpu);
 195
 196        ipi_states[i] = cpu;
 197        cs->halted = 1;
 198        cpu->env.exception_index = EXCP_HLT;
 199        cpu->env.storage_keys = storage_keys;
 200    }
 201}
 202
 203
 204void s390_create_virtio_net(BusState *bus, const char *name)
 205{
 206    int i;
 207
 208    for (i = 0; i < nb_nics; i++) {
 209        NICInfo *nd = &nd_table[i];
 210        DeviceState *dev;
 211
 212        if (!nd->model) {
 213            nd->model = g_strdup("virtio");
 214        }
 215
 216        if (strcmp(nd->model, "virtio")) {
 217            fprintf(stderr, "S390 only supports VirtIO nics\n");
 218            exit(1);
 219        }
 220
 221        dev = qdev_create(bus, name);
 222        qdev_set_nic_properties(dev, nd);
 223        qdev_init_nofail(dev);
 224    }
 225}
 226
 227/* PC hardware initialisation */
 228static void s390_init(QEMUMachineInitArgs *args)
 229{
 230    ram_addr_t my_ram_size = args->ram_size;
 231    MemoryRegion *sysmem = get_system_memory();
 232    MemoryRegion *ram = g_new(MemoryRegion, 1);
 233    int shift = 0;
 234    uint8_t *storage_keys;
 235    void *virtio_region;
 236    hwaddr virtio_region_len;
 237    hwaddr virtio_region_start;
 238
 239    /* s390x ram size detection needs a 16bit multiplier + an increment. So
 240       guests > 64GB can be specified in 2MB steps etc. */
 241    while ((my_ram_size >> (20 + shift)) > 65535) {
 242        shift++;
 243    }
 244    my_ram_size = my_ram_size >> (20 + shift) << (20 + shift);
 245
 246    /* let's propagate the changed ram size into the global variable. */
 247    ram_size = my_ram_size;
 248
 249    /* get a BUS */
 250    s390_bus = s390_virtio_bus_init(&my_ram_size);
 251    s390_sclp_init();
 252    s390_init_ipl_dev(args->kernel_filename, args->kernel_cmdline,
 253                      args->initrd_filename, ZIPL_FILENAME);
 254
 255    /* register hypercalls */
 256    s390_virtio_register_hcalls();
 257
 258    /* allocate RAM */
 259    memory_region_init_ram(ram, "s390.ram", my_ram_size);
 260    vmstate_register_ram_global(ram);
 261    memory_region_add_subregion(sysmem, 0, ram);
 262
 263    /* clear virtio region */
 264    virtio_region_len = my_ram_size - ram_size;
 265    virtio_region_start = ram_size;
 266    virtio_region = cpu_physical_memory_map(virtio_region_start,
 267                                            &virtio_region_len, true);
 268    memset(virtio_region, 0, virtio_region_len);
 269    cpu_physical_memory_unmap(virtio_region, virtio_region_len, 1,
 270                              virtio_region_len);
 271
 272    /* allocate storage keys */
 273    storage_keys = g_malloc0(my_ram_size / TARGET_PAGE_SIZE);
 274
 275    /* init CPUs */
 276    s390_init_cpus(args->cpu_model, storage_keys);
 277
 278    /* Create VirtIO network adapters */
 279    s390_create_virtio_net((BusState *)s390_bus, "virtio-net-s390");
 280}
 281
 282static QEMUMachine s390_machine = {
 283    .name = "s390-virtio",
 284    .alias = "s390",
 285    .desc = "VirtIO based S390 machine",
 286    .init = s390_init,
 287    .block_default_type = IF_VIRTIO,
 288    .no_cdrom = 1,
 289    .no_floppy = 1,
 290    .no_serial = 1,
 291    .no_parallel = 1,
 292    .no_sdcard = 1,
 293    .use_virtcon = 1,
 294    .max_cpus = 255,
 295    .is_default = 1,
 296    DEFAULT_MACHINE_OPTIONS,
 297};
 298
 299static void s390_machine_init(void)
 300{
 301    qemu_register_machine(&s390_machine);
 302}
 303
 304machine_init(s390_machine_init);
 305