#include "hw.h"
#include "block.h"
+#include "blockdev.h"
#include "sysemu.h"
#include "net.h"
#include "boards.h"
#include "loader.h"
#include "elf.h"
#include "hw/virtio.h"
-#include "hw/virtio-console.h"
#include "hw/sysbus.h"
#include "kvm.h"
#define INITRD_PARM_SIZE 0x010410UL
#define PARMFILE_START 0x001000UL
+#define ZIPL_START 0x009000UL
+#define ZIPL_LOAD_ADDR 0x009000UL
+#define ZIPL_FILENAME "s390-zipl.rom"
+
#define MAX_BLK_DEVS 10
static VirtIOS390Bus *s390_bus;
return ipi_states[cpu_addr];
}
-int s390_virtio_hypercall(CPUState *env)
+int s390_virtio_hypercall(CPUState *env, uint64_t mem, uint64_t hypercall)
{
int r = 0, i;
- target_ulong mem = env->regs[2];
- dprintf("KVM hypercall: %ld\n", env->regs[1]);
- switch (env->regs[1]) {
+ dprintf("KVM hypercall: %ld\n", hypercall);
+ switch (hypercall) {
case KVM_S390_VIRTIO_NOTIFY:
if (mem > ram_size) {
VirtIOS390Device *dev = s390_virtio_bus_find_vring(s390_bus,
break;
case KVM_S390_VIRTIO_RESET:
{
- /* Virtio_reset resets the internal addresses, so we'd have to sync
- them up again. We don't want to reallocate a vring though, so let's
- just not reset. */
- /* virtio_reset(dev->vdev); */
+ VirtIOS390Device *dev;
+
+ dev = s390_virtio_bus_find_mem(s390_bus, mem);
+ virtio_reset(dev->vdev);
+ s390_virtio_device_sync(dev);
break;
}
case KVM_S390_VIRTIO_SET_STATUS:
break;
}
- env->regs[2] = r;
- return 0;
+ return r;
}
/* PC hardware initialisation */
-static void s390_init(ram_addr_t ram_size,
+static void s390_init(ram_addr_t my_ram_size,
const char *boot_device,
const char *kernel_filename,
const char *kernel_cmdline,
ram_addr_t kernel_size = 0;
ram_addr_t initrd_offset;
ram_addr_t initrd_size = 0;
+ int shift = 0;
+ uint8_t *storage_keys;
int i;
+ /* s390x ram size detection needs a 16bit multiplier + an increment. So
+ guests > 64GB can be specified in 2MB steps etc. */
+ while ((my_ram_size >> (20 + shift)) > 65535) {
+ shift++;
+ }
+ my_ram_size = my_ram_size >> (20 + shift) << (20 + shift);
+
+ /* lets propagate the changed ram size into the global variable. */
+ ram_size = my_ram_size;
+
/* get a BUS */
- s390_bus = s390_virtio_bus_init(&ram_size);
+ s390_bus = s390_virtio_bus_init(&my_ram_size);
/* allocate RAM */
- ram_addr = qemu_ram_alloc(ram_size);
- cpu_register_physical_memory(0, ram_size, ram_addr);
+ ram_addr = qemu_ram_alloc(NULL, "s390.ram", my_ram_size);
+ cpu_register_physical_memory(0, my_ram_size, ram_addr);
+
+ /* allocate storage keys */
+ storage_keys = qemu_mallocz(my_ram_size / TARGET_PAGE_SIZE);
/* init CPUs */
if (cpu_model == NULL) {
ipi_states[i] = tmp_env;
tmp_env->halted = 1;
tmp_env->exception_index = EXCP_HLT;
+ tmp_env->storage_keys = storage_keys;
}
env->halted = 0;
exit(1);
}
- cpu_synchronize_state(env);
env->psw.addr = KERN_IMAGE_START;
- env->psw.mask = 0x0000000180000000UL;
+ env->psw.mask = 0x0000000180000000ULL;
+ } else {
+ ram_addr_t bios_size = 0;
+ char *bios_filename;
+
+ /* Load zipl bootloader */
+ if (bios_name == NULL) {
+ bios_name = ZIPL_FILENAME;
+ }
+
+ bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+ bios_size = load_image(bios_filename, qemu_get_ram_ptr(ZIPL_LOAD_ADDR));
+ qemu_free(bios_filename);
+
+ if ((long)bios_size < 0) {
+ hw_error("could not load bootloader '%s'\n", bios_name);
+ }
+
+ if (bios_size > 4096) {
+ hw_error("stage1 bootloader is > 4k\n");
+ }
+
+ env->psw.addr = ZIPL_START;
+ env->psw.mask = 0x0000000180000000ULL;
}
if (initrd_filename) {
}
if (kernel_cmdline) {
- cpu_physical_memory_rw(KERN_PARM_AREA, (uint8_t *)kernel_cmdline,
- strlen(kernel_cmdline), 1);
+ cpu_physical_memory_write(KERN_PARM_AREA, kernel_cmdline,
+ strlen(kernel_cmdline));
}
- /* Create VirtIO console */
- qdev_init_nofail(qdev_create((BusState *)s390_bus, "virtio-console-s390"));
-
/* Create VirtIO network adapters */
for(i = 0; i < nb_nics; i++) {
NICInfo *nd = &nd_table[i];
DeviceState *dev;
if (!nd->model) {
- nd->model = (char*)"virtio";
+ nd->model = qemu_strdup("virtio");
}
if (strcmp(nd->model, "virtio")) {
}
dev = qdev_create((BusState *)s390_bus, "virtio-blk-s390");
- qdev_prop_set_drive(dev, "drive", dinfo);
+ qdev_prop_set_drive_nofail(dev, "drive", dinfo->bdrv);
qdev_init_nofail(dev);
}
}
.alias = "s390",
.desc = "VirtIO based S390 machine",
.init = s390_init,
+ .no_serial = 1,
+ .no_parallel = 1,
+ .use_virtcon = 1,
+ .no_vga = 1,
.max_cpus = 255,
.is_default = 1,
};