#include "hw.h"
#include "block.h"
+#include "blockdev.h"
#include "sysemu.h"
#include "net.h"
#include "boards.h"
#include "hw/virtio.h"
#include "hw/sysbus.h"
#include "kvm.h"
+#include "exec-memory.h"
#include "hw/s390-virtio-bus.h"
#define MAX_BLK_DEVS 10
static VirtIOS390Bus *s390_bus;
-static CPUState **ipi_states;
+static CPUS390XState **ipi_states;
-void irq_info(Monitor *mon);
-void pic_info(Monitor *mon);
-
-void irq_info(Monitor *mon)
-{
-}
-
-void pic_info(Monitor *mon)
-{
-}
-
-CPUState *s390_cpu_addr2state(uint16_t cpu_addr)
+CPUS390XState *s390_cpu_addr2state(uint16_t cpu_addr)
{
if (cpu_addr >= smp_cpus) {
return NULL;
return ipi_states[cpu_addr];
}
-int s390_virtio_hypercall(CPUState *env)
+int s390_virtio_hypercall(CPUS390XState *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,
dev = s390_virtio_bus_find_mem(s390_bus, mem);
virtio_reset(dev->vdev);
+ stb_phys(dev->dev_offs + VIRTIO_DEV_OFFS_STATUS, 0);
s390_virtio_device_sync(dev);
break;
}
break;
}
- env->regs[2] = r;
- return 0;
+ return r;
+}
+
+/*
+ * The number of running CPUs. On s390 a shutdown is the state of all CPUs
+ * being either stopped or disabled (for interrupts) waiting. We have to
+ * track this number to call the shutdown sequence accordingly. This
+ * number is modified either on startup or while holding the big qemu lock.
+ */
+static unsigned s390_running_cpus;
+
+void s390_add_running_cpu(CPUS390XState *env)
+{
+ if (env->halted) {
+ s390_running_cpus++;
+ env->halted = 0;
+ env->exception_index = -1;
+ }
+}
+
+unsigned s390_del_running_cpu(CPUS390XState *env)
+{
+ if (env->halted == 0) {
+ assert(s390_running_cpus >= 1);
+ s390_running_cpus--;
+ env->halted = 1;
+ env->exception_index = EXCP_HLT;
+ }
+ return s390_running_cpus;
}
/* 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,
const char *initrd_filename,
const char *cpu_model)
{
- CPUState *env = NULL;
- ram_addr_t ram_addr;
+ CPUS390XState *env = NULL;
+ MemoryRegion *sysmem = get_system_memory();
+ MemoryRegion *ram = g_new(MemoryRegion, 1);
ram_addr_t kernel_size = 0;
ram_addr_t initrd_offset;
ram_addr_t initrd_size = 0;
+ int shift = 0;
+ uint8_t *storage_keys;
+ void *virtio_region;
+ target_phys_addr_t virtio_region_len;
+ target_phys_addr_t virtio_region_start;
int i;
- /* XXX we only work on KVM for now */
-
- if (!kvm_enabled()) {
- fprintf(stderr, "The S390 target only works with KVM enabled\n");
- exit(1);
+ /* 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);
+ memory_region_init_ram(ram, "s390.ram", my_ram_size);
+ vmstate_register_ram_global(ram);
+ memory_region_add_subregion(sysmem, 0, ram);
+
+ /* clear virtio region */
+ virtio_region_len = my_ram_size - ram_size;
+ virtio_region_start = ram_size;
+ virtio_region = cpu_physical_memory_map(virtio_region_start,
+ &virtio_region_len, true);
+ memset(virtio_region, 0, virtio_region_len);
+ cpu_physical_memory_unmap(virtio_region, virtio_region_len, 1,
+ virtio_region_len);
+
+ /* allocate storage keys */
+ storage_keys = g_malloc0(my_ram_size / TARGET_PAGE_SIZE);
/* init CPUs */
if (cpu_model == NULL) {
cpu_model = "host";
}
- ipi_states = qemu_malloc(sizeof(CPUState *) * smp_cpus);
+ ipi_states = g_malloc(sizeof(CPUS390XState *) * smp_cpus);
for (i = 0; i < smp_cpus; i++) {
- CPUState *tmp_env;
+ CPUS390XState *tmp_env;
tmp_env = cpu_init(cpu_model);
if (!env) {
ipi_states[i] = tmp_env;
tmp_env->halted = 1;
tmp_env->exception_index = EXCP_HLT;
+ tmp_env->storage_keys = storage_keys;
}
- env->halted = 0;
- env->exception_index = 0;
+ /* One CPU has to run */
+ s390_add_running_cpu(env);
if (kernel_filename) {
- kernel_size = load_image(kernel_filename, qemu_get_ram_ptr(0));
- if (lduw_phys(KERN_IMAGE_START) != 0x0dd0) {
- fprintf(stderr, "Specified image is not an s390 boot image\n");
- exit(1);
+ kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, NULL,
+ NULL, 1, ELF_MACHINE, 0);
+ if (kernel_size == -1UL) {
+ kernel_size = load_image_targphys(kernel_filename, 0, ram_size);
}
-
+ /*
+ * we can not rely on the ELF entry point, since up to 3.2 this
+ * value was 0x800 (the SALIPL loader) and it wont work. For
+ * all (Linux) cases 0x10000 (KERN_IMAGE_START) should be fine.
+ */
env->psw.addr = KERN_IMAGE_START;
env->psw.mask = 0x0000000180000000ULL;
} else {
}
bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
- bios_size = load_image(bios_filename, qemu_get_ram_ptr(ZIPL_LOAD_ADDR));
+ bios_size = load_image_targphys(bios_filename, ZIPL_LOAD_ADDR, 4096);
+ g_free(bios_filename);
if ((long)bios_size < 0) {
hw_error("could not load bootloader '%s'\n", bios_name);
while (kernel_size + 0x100000 > initrd_offset) {
initrd_offset += 0x100000;
}
- initrd_size = load_image(initrd_filename, qemu_get_ram_ptr(initrd_offset));
-
- stq_phys(INITRD_PARM_START, initrd_offset);
- stq_phys(INITRD_PARM_SIZE, initrd_size);
+ initrd_size = load_image_targphys(initrd_filename, initrd_offset,
+ ram_size - initrd_offset);
+ /* we have to overwrite values in the kernel image, which are "rom" */
+ memcpy(rom_ptr(INITRD_PARM_START), &initrd_offset, 8);
+ memcpy(rom_ptr(INITRD_PARM_SIZE), &initrd_size, 8);
}
if (kernel_cmdline) {
- cpu_physical_memory_rw(KERN_PARM_AREA, (uint8_t *)kernel_cmdline,
- strlen(kernel_cmdline), 1);
+ /* we have to overwrite values in the kernel image, which are "rom" */
+ memcpy(rom_ptr(KERN_PARM_AREA), kernel_cmdline,
+ strlen(kernel_cmdline) + 1);
}
/* Create VirtIO network adapters */
DeviceState *dev;
if (!nd->model) {
- nd->model = qemu_strdup("virtio");
+ nd->model = g_strdup("virtio");
}
if (strcmp(nd->model, "virtio")) {
.no_serial = 1,
.no_parallel = 1,
.use_virtcon = 1,
- .no_vga = 1,
.max_cpus = 255,
.is_default = 1,
};