Merge branch 's390-for-upstream' of git://repo.or.cz/qemu/agraf

* 's390-for-upstream' of git://repo.or.cz/qemu/agraf:
  s390: Add a hypercall registration interface.
  target-s390x: Unregister reset callback on finalization
  s390x: fix indentation
  s390: Add CPU reset handler
  s390x: Remove inline function ebcdic_put and related data from cpu.h
  S390: Enable -cpu help and QMP query-cpu-definitions
  s390: Move IPL code into a separate device
  s390: new contributions GPLv2 or later
This commit is contained in:
Blue Swirl 2013-01-19 09:55:46 +00:00
commit 67c4f2d0e1
9 changed files with 472 additions and 222 deletions

View File

@ -2,6 +2,7 @@
* QEMU S390 virtio target * QEMU S390 virtio target
* *
* Copyright (c) 2009 Alexander Graf <agraf@suse.de> * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
* Copyright IBM Corp 2012
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -13,7 +14,10 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * Contributions after 2012-10-29 are licensed under the terms of the
* GNU GPL, version 2 or (at your option) any later version.
*
* You should have received a copy of the GNU (Lesser) General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/ */
@ -25,7 +29,6 @@
#include "boards.h" #include "boards.h"
#include "monitor/monitor.h" #include "monitor/monitor.h"
#include "loader.h" #include "loader.h"
#include "elf.h"
#include "hw/virtio.h" #include "hw/virtio.h"
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "sysemu/kvm.h" #include "sysemu/kvm.h"
@ -33,6 +36,7 @@
#include "hw/s390-virtio-bus.h" #include "hw/s390-virtio-bus.h"
#include "hw/s390x/sclp.h" #include "hw/s390x/sclp.h"
#include "hw/s390-virtio.h"
//#define DEBUG_S390 //#define DEBUG_S390
@ -44,21 +48,6 @@
do { } while (0) do { } while (0)
#endif #endif
#define KVM_S390_VIRTIO_NOTIFY 0
#define KVM_S390_VIRTIO_RESET 1
#define KVM_S390_VIRTIO_SET_STATUS 2
#define KERN_IMAGE_START 0x010000UL
#define KERN_PARM_AREA 0x010480UL
#define INITRD_START 0x800000UL
#define INITRD_PARM_START 0x010408UL
#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 #define MAX_BLK_DEVS 10
static VirtIOS390Bus *s390_bus; static VirtIOS390Bus *s390_bus;
@ -73,56 +62,63 @@ S390CPU *s390_cpu_addr2state(uint16_t cpu_addr)
return ipi_states[cpu_addr]; return ipi_states[cpu_addr];
} }
int s390_virtio_hypercall(CPUS390XState *env, uint64_t mem, uint64_t hypercall) static int s390_virtio_hcall_notify(const uint64_t *args)
{ {
uint64_t mem = args[0];
int r = 0, i; int r = 0, i;
dprintf("KVM hypercall: %ld\n", hypercall); if (mem > ram_size) {
switch (hypercall) { VirtIOS390Device *dev = s390_virtio_bus_find_vring(s390_bus, mem, &i);
case KVM_S390_VIRTIO_NOTIFY:
if (mem > ram_size) {
VirtIOS390Device *dev = s390_virtio_bus_find_vring(s390_bus,
mem, &i);
if (dev) {
virtio_queue_notify(dev->vdev, i);
} else {
r = -EINVAL;
}
} else {
/* Early printk */
}
break;
case KVM_S390_VIRTIO_RESET:
{
VirtIOS390Device *dev;
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);
s390_virtio_reset_idx(dev);
break;
}
case KVM_S390_VIRTIO_SET_STATUS:
{
VirtIOS390Device *dev;
dev = s390_virtio_bus_find_mem(s390_bus, mem);
if (dev) { if (dev) {
s390_virtio_device_update_status(dev); virtio_queue_notify(dev->vdev, i);
} else { } else {
r = -EINVAL; r = -EINVAL;
} }
break; } else {
/* Early printk */
} }
default:
r = -EINVAL;
break;
}
return r; return r;
} }
static int s390_virtio_hcall_reset(const uint64_t *args)
{
uint64_t mem = args[0];
VirtIOS390Device *dev;
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);
s390_virtio_reset_idx(dev);
return 0;
}
static int s390_virtio_hcall_set_status(const uint64_t *args)
{
uint64_t mem = args[0];
int r = 0;
VirtIOS390Device *dev;
dev = s390_virtio_bus_find_mem(s390_bus, mem);
if (dev) {
s390_virtio_device_update_status(dev);
} else {
r = -EINVAL;
}
return r;
}
static void s390_virtio_register_hcalls(void)
{
s390_register_virtio_hypercall(KVM_S390_VIRTIO_NOTIFY,
s390_virtio_hcall_notify);
s390_register_virtio_hypercall(KVM_S390_VIRTIO_RESET,
s390_virtio_hcall_reset);
s390_register_virtio_hypercall(KVM_S390_VIRTIO_SET_STATUS,
s390_virtio_hcall_set_status);
}
/* /*
* The number of running CPUs. On s390 a shutdown is the state of all CPUs * 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 * being either stopped or disabled (for interrupts) waiting. We have to
@ -156,15 +152,10 @@ static void s390_init(QEMUMachineInitArgs *args)
{ {
ram_addr_t my_ram_size = args->ram_size; ram_addr_t my_ram_size = args->ram_size;
const char *cpu_model = args->cpu_model; const char *cpu_model = args->cpu_model;
const char *kernel_filename = args->kernel_filename;
const char *kernel_cmdline = args->kernel_cmdline;
const char *initrd_filename = args->initrd_filename;
CPUS390XState *env = NULL; CPUS390XState *env = NULL;
DeviceState *dev;
MemoryRegion *sysmem = get_system_memory(); MemoryRegion *sysmem = get_system_memory();
MemoryRegion *ram = g_new(MemoryRegion, 1); 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; int shift = 0;
uint8_t *storage_keys; uint8_t *storage_keys;
void *virtio_region; void *virtio_region;
@ -185,6 +176,18 @@ static void s390_init(QEMUMachineInitArgs *args)
/* get a BUS */ /* get a BUS */
s390_bus = s390_virtio_bus_init(&my_ram_size); s390_bus = s390_virtio_bus_init(&my_ram_size);
s390_sclp_init(); s390_sclp_init();
dev = qdev_create(NULL, "s390-ipl");
if (args->kernel_filename) {
qdev_prop_set_string(dev, "kernel", args->kernel_filename);
}
if (args->initrd_filename) {
qdev_prop_set_string(dev, "initrd", args->initrd_filename);
}
qdev_prop_set_string(dev, "cmdline", args->kernel_cmdline);
qdev_init_nofail(dev);
/* register hypercalls */
s390_virtio_register_hcalls();
/* allocate RAM */ /* allocate RAM */
memory_region_init_ram(ram, "s390.ram", my_ram_size); memory_region_init_ram(ram, "s390.ram", my_ram_size);
@ -225,76 +228,6 @@ static void s390_init(QEMUMachineInitArgs *args)
tmp_env->storage_keys = storage_keys; tmp_env->storage_keys = storage_keys;
} }
/* One CPU has to run */
s390_add_running_cpu(env);
if (kernel_filename) {
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);
}
if (kernel_size == -1UL) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
kernel_filename);
exit(1);
}
/*
* 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 {
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_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);
}
if (bios_size > 4096) {
hw_error("stage1 bootloader is > 4k\n");
}
env->psw.addr = ZIPL_START;
env->psw.mask = 0x0000000180000000ULL;
}
if (initrd_filename) {
initrd_offset = INITRD_START;
while (kernel_size + 0x100000 > initrd_offset) {
initrd_offset += 0x100000;
}
initrd_size = load_image_targphys(initrd_filename, initrd_offset,
ram_size - initrd_offset);
if (initrd_size == -1UL) {
fprintf(stderr, "qemu: could not load initrd '%s'\n",
initrd_filename);
exit(1);
}
/* we have to overwrite values in the kernel image, which are "rom" */
stq_p(rom_ptr(INITRD_PARM_START), initrd_offset);
stq_p(rom_ptr(INITRD_PARM_SIZE), initrd_size);
}
if (rom_ptr(KERN_PARM_AREA)) {
/* 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 */ /* Create VirtIO network adapters */
for(i = 0; i < nb_nics; i++) { for(i = 0; i < nb_nics; i++) {
@ -339,4 +272,3 @@ static void s390_machine_init(void)
} }
machine_init(s390_machine_init); machine_init(s390_machine_init);

22
hw/s390-virtio.h Normal file
View File

@ -0,0 +1,22 @@
/*
* Virtio interfaces for s390
*
* Copyright 2012 IBM Corp.
* Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at
* your option) any later version. See the COPYING file in the top-level
* directory.
*/
#ifndef HW_S390_VIRTIO_H
#define HW_S390_VIRTIO_H 1
#define KVM_S390_VIRTIO_NOTIFY 0
#define KVM_S390_VIRTIO_RESET 1
#define KVM_S390_VIRTIO_SET_STATUS 2
typedef int (*s390_virtio_fn)(const uint64_t *args);
void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn);
#endif

View File

@ -1,6 +1,8 @@
obj-y = s390-virtio-bus.o s390-virtio.o obj-y = s390-virtio-bus.o s390-virtio.o
obj-y := $(addprefix ../,$(obj-y)) obj-y := $(addprefix ../,$(obj-y))
obj-y += s390-virtio-hcall.o
obj-y += sclp.o obj-y += sclp.o
obj-y += event-facility.o obj-y += event-facility.o
obj-y += sclpquiesce.o sclpconsole.o obj-y += sclpquiesce.o sclpconsole.o
obj-y += ipl.o

174
hw/s390x/ipl.c Normal file
View File

@ -0,0 +1,174 @@
/*
* bootloader support
*
* Copyright IBM, Corp. 2012
*
* Authors:
* Christian Borntraeger <borntraeger@de.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at your
* option) any later version. See the COPYING file in the top-level directory.
*
*/
#include "sysemu/sysemu.h"
#include "cpu.h"
#include "elf.h"
#include "hw/loader.h"
#include "hw/sysbus.h"
#define KERN_IMAGE_START 0x010000UL
#define KERN_PARM_AREA 0x010480UL
#define INITRD_START 0x800000UL
#define INITRD_PARM_START 0x010408UL
#define INITRD_PARM_SIZE 0x010410UL
#define PARMFILE_START 0x001000UL
#define ZIPL_FILENAME "s390-zipl.rom"
#define ZIPL_IMAGE_START 0x009000UL
#define IPL_PSW_MASK (PSW_MASK_32 | PSW_MASK_64)
#define TYPE_S390_IPL "s390-ipl"
#define S390_IPL(obj) \
OBJECT_CHECK(S390IPLState, (obj), TYPE_S390_IPL)
#if 0
#define S390_IPL_CLASS(klass) \
OBJECT_CLASS_CHECK(S390IPLState, (klass), TYPE_S390_IPL)
#define S390_IPL_GET_CLASS(obj) \
OBJECT_GET_CLASS(S390IPLState, (obj), TYPE_S390_IPL)
#endif
typedef struct S390IPLClass {
/*< private >*/
SysBusDeviceClass parent_class;
/*< public >*/
void (*parent_reset) (SysBusDevice *dev);
} S390IPLClass;
typedef struct S390IPLState {
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
char *kernel;
char *initrd;
char *cmdline;
} S390IPLState;
static void s390_ipl_cpu(uint64_t pswaddr)
{
CPUS390XState *env = &S390_CPU(qemu_get_cpu(0))->env;
env->psw.addr = pswaddr;
env->psw.mask = IPL_PSW_MASK;
s390_add_running_cpu(env);
}
static int s390_ipl_init(SysBusDevice *dev)
{
S390IPLState *ipl = S390_IPL(dev);
ram_addr_t kernel_size = 0;
if (!ipl->kernel) {
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_targphys(bios_filename, ZIPL_IMAGE_START, 4096);
g_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");
}
return 0;
} else {
kernel_size = load_elf(ipl->kernel, NULL, NULL, NULL, NULL,
NULL, 1, ELF_MACHINE, 0);
if (kernel_size == -1UL) {
kernel_size = load_image_targphys(ipl->kernel, 0, ram_size);
}
if (kernel_size == -1UL) {
fprintf(stderr, "could not load kernel '%s'\n", ipl->kernel);
return -1;
}
/* we have to overwrite values in the kernel image, which are "rom" */
strcpy(rom_ptr(KERN_PARM_AREA), ipl->cmdline);
}
if (ipl->initrd) {
ram_addr_t initrd_offset, initrd_size;
initrd_offset = INITRD_START;
while (kernel_size + 0x100000 > initrd_offset) {
initrd_offset += 0x100000;
}
initrd_size = load_image_targphys(ipl->initrd, initrd_offset,
ram_size - initrd_offset);
if (initrd_size == -1UL) {
fprintf(stderr, "qemu: could not load initrd '%s'\n", ipl->initrd);
exit(1);
}
/* we have to overwrite values in the kernel image, which are "rom" */
stq_p(rom_ptr(INITRD_PARM_START), initrd_offset);
stq_p(rom_ptr(INITRD_PARM_SIZE), initrd_size);
}
return 0;
}
static Property s390_ipl_properties[] = {
DEFINE_PROP_STRING("kernel", S390IPLState, kernel),
DEFINE_PROP_STRING("initrd", S390IPLState, initrd),
DEFINE_PROP_STRING("cmdline", S390IPLState, cmdline),
DEFINE_PROP_END_OF_LIST(),
};
static void s390_ipl_reset(DeviceState *dev)
{
S390IPLState *ipl = S390_IPL(dev);
if (ipl->kernel) {
/*
* 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.
*/
return s390_ipl_cpu(KERN_IMAGE_START);
} else {
return s390_ipl_cpu(ZIPL_IMAGE_START);
}
}
static void s390_ipl_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
k->init = s390_ipl_init;
dc->props = s390_ipl_properties;
dc->reset = s390_ipl_reset;
dc->no_user = 1;
}
static TypeInfo s390_ipl_info = {
.class_init = s390_ipl_class_init,
.parent = TYPE_SYS_BUS_DEVICE,
.name = "s390-ipl",
.instance_size = sizeof(S390IPLState),
};
static void s390_ipl_register_types(void)
{
type_register_static(&s390_ipl_info);
}
type_init(s390_ipl_register_types)

View File

@ -0,0 +1,36 @@
/*
* Support for virtio hypercalls on s390
*
* Copyright 2012 IBM Corp.
* Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at
* your option) any later version. See the COPYING file in the top-level
* directory.
*/
#include "cpu.h"
#include "hw/s390-virtio.h"
#define MAX_DIAG_SUBCODES 255
static s390_virtio_fn s390_diag500_table[MAX_DIAG_SUBCODES];
void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn)
{
assert(code < MAX_DIAG_SUBCODES);
assert(!s390_diag500_table[code]);
s390_diag500_table[code] = fn;
}
int s390_virtio_hypercall(CPUS390XState *env)
{
s390_virtio_fn fn = s390_diag500_table[env->regs[1]];
if (!fn) {
return -EINVAL;
}
return fn(&env->regs[2]);
}

View File

@ -4,6 +4,7 @@
* Copyright (c) 2009 Ulrich Hecht * Copyright (c) 2009 Ulrich Hecht
* Copyright (c) 2011 Alexander Graf * Copyright (c) 2011 Alexander Graf
* Copyright (c) 2012 SUSE LINUX Products GmbH * Copyright (c) 2012 SUSE LINUX Products GmbH
* Copyright (c) 2012 IBM Corp.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -18,12 +19,44 @@
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see * License along with this library; if not, see
* <http://www.gnu.org/licenses/lgpl-2.1.html> * <http://www.gnu.org/licenses/lgpl-2.1.html>
* Contributions after 2012-12-11 are licensed under the terms of the
* GNU GPL, version 2 or (at your option) any later version.
*/ */
#include "cpu.h" #include "cpu.h"
#include "qemu-common.h" #include "qemu-common.h"
#include "qemu/timer.h" #include "qemu/timer.h"
#ifndef CONFIG_USER_ONLY
#include "hw/hw.h"
#include "sysemu/arch_init.h"
#endif
#define CR0_RESET 0xE0UL
#define CR14_RESET 0xC2000000UL;
/* generate CPU information for cpu -? */
void s390_cpu_list(FILE *f, fprintf_function cpu_fprintf)
{
#ifdef CONFIG_KVM
(*cpu_fprintf)(f, "s390 %16s\n", "host");
#endif
}
#ifndef CONFIG_USER_ONLY
CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
{
CpuDefinitionInfoList *entry;
CpuDefinitionInfo *info;
info = g_malloc0(sizeof(*info));
info->name = g_strdup("host");
entry = g_malloc0(sizeof(*entry));
entry->value = info;
return entry;
}
#endif
/* CPUClass::reset() */ /* CPUClass::reset() */
static void s390_cpu_reset(CPUState *s) static void s390_cpu_reset(CPUState *s)
@ -37,14 +70,33 @@ static void s390_cpu_reset(CPUState *s)
log_cpu_state(env, 0); log_cpu_state(env, 0);
} }
s390_del_running_cpu(env);
scc->parent_reset(s); scc->parent_reset(s);
memset(env, 0, offsetof(CPUS390XState, breakpoints)); memset(env, 0, offsetof(CPUS390XState, breakpoints));
/* FIXME: reset vector? */
/* architectured initial values for CR 0 and 14 */
env->cregs[0] = CR0_RESET;
env->cregs[14] = CR14_RESET;
/* set halted to 1 to make sure we can add the cpu in
* s390_ipl_cpu code, where env->halted is set back to 0
* after incrementing the cpu counter */
#if !defined(CONFIG_USER_ONLY)
env->halted = 1;
#endif
tlb_flush(env, 1); tlb_flush(env, 1);
s390_add_running_cpu(env);
} }
#if !defined(CONFIG_USER_ONLY)
static void s390_cpu_machine_reset_cb(void *opaque)
{
S390CPU *cpu = opaque;
cpu_reset(CPU(cpu));
}
#endif
static void s390_cpu_initfn(Object *obj) static void s390_cpu_initfn(Object *obj)
{ {
S390CPU *cpu = S390_CPU(obj); S390CPU *cpu = S390_CPU(obj);
@ -56,12 +108,17 @@ static void s390_cpu_initfn(Object *obj)
cpu_exec_init(env); cpu_exec_init(env);
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
qemu_register_reset(s390_cpu_machine_reset_cb, cpu);
qemu_get_timedate(&tm, 0); qemu_get_timedate(&tm, 0);
env->tod_offset = TOD_UNIX_EPOCH + env->tod_offset = TOD_UNIX_EPOCH +
(time2tod(mktimegm(&tm)) * 1000000000ULL); (time2tod(mktimegm(&tm)) * 1000000000ULL);
env->tod_basetime = 0; env->tod_basetime = 0;
env->tod_timer = qemu_new_timer_ns(vm_clock, s390x_tod_timer, cpu); env->tod_timer = qemu_new_timer_ns(vm_clock, s390x_tod_timer, cpu);
env->cpu_timer = qemu_new_timer_ns(vm_clock, s390x_cpu_timer, cpu); env->cpu_timer = qemu_new_timer_ns(vm_clock, s390x_cpu_timer, cpu);
/* set env->halted state to 1 to avoid decrementing the running
* cpu counter in s390_cpu_reset to a negative number at
* initial ipl */
env->halted = 1;
#endif #endif
env->cpu_num = cpu_num++; env->cpu_num = cpu_num++;
env->ext_index = -1; env->ext_index = -1;
@ -69,6 +126,15 @@ static void s390_cpu_initfn(Object *obj)
cpu_reset(CPU(cpu)); cpu_reset(CPU(cpu));
} }
static void s390_cpu_finalize(Object *obj)
{
#if !defined(CONFIG_USER_ONLY)
S390CPU *cpu = S390_CPU(obj);
qemu_unregister_reset(s390_cpu_machine_reset_cb, cpu);
#endif
}
static void s390_cpu_class_init(ObjectClass *oc, void *data) static void s390_cpu_class_init(ObjectClass *oc, void *data)
{ {
S390CPUClass *scc = S390_CPU_CLASS(oc); S390CPUClass *scc = S390_CPU_CLASS(oc);
@ -83,6 +149,7 @@ static const TypeInfo s390_cpu_type_info = {
.parent = TYPE_CPU, .parent = TYPE_CPU,
.instance_size = sizeof(S390CPU), .instance_size = sizeof(S390CPU),
.instance_init = s390_cpu_initfn, .instance_init = s390_cpu_initfn,
.instance_finalize = s390_cpu_finalize,
.abstract = false, .abstract = false,
.class_size = sizeof(S390CPUClass), .class_size = sizeof(S390CPUClass),
.class_init = s390_cpu_class_init, .class_init = s390_cpu_class_init,

View File

@ -13,7 +13,10 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * Contributions after 2012-10-29 are licensed under the terms of the
* GNU GPL, version 2 or (at your option) any later version.
*
* You should have received a copy of the GNU (Lesser) General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef CPU_S390X_H #ifndef CPU_S390X_H
@ -302,7 +305,7 @@ int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong address, int rw
void s390x_tod_timer(void *opaque); void s390x_tod_timer(void *opaque);
void s390x_cpu_timer(void *opaque); void s390x_cpu_timer(void *opaque);
int s390_virtio_hypercall(CPUS390XState *env, uint64_t mem, uint64_t hypercall); int s390_virtio_hypercall(CPUS390XState *env);
#ifdef CONFIG_KVM #ifdef CONFIG_KVM
void kvm_s390_interrupt(S390CPU *cpu, int type, uint32_t code); void kvm_s390_interrupt(S390CPU *cpu, int type, uint32_t code);
@ -359,6 +362,9 @@ static inline void cpu_set_tls(CPUS390XState *env, target_ulong newtls)
#define cpu_gen_code cpu_s390x_gen_code #define cpu_gen_code cpu_s390x_gen_code
#define cpu_signal_handler cpu_s390x_signal_handler #define cpu_signal_handler cpu_s390x_signal_handler
void s390_cpu_list(FILE *f, fprintf_function cpu_fprintf);
#define cpu_list s390_cpu_list
#include "exec/exec-all.h" #include "exec/exec-all.h"
#define EXCP_EXT 1 /* external interrupt */ #define EXCP_EXT 1 /* external interrupt */
@ -769,87 +775,6 @@ struct sysib_322 {
#define SK_F (0x1 << 3) #define SK_F (0x1 << 3)
#define SK_ACC_MASK (0xf << 4) #define SK_ACC_MASK (0xf << 4)
/* EBCDIC handling */
static const uint8_t ebcdic2ascii[] = {
0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21,
0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07,
0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07,
};
static const uint8_t ascii2ebcdic [] = {
0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,
0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
};
static inline void ebcdic_put(uint8_t *p, const char *ascii, int len)
{
int i;
for (i = 0; i < len; i++) {
p[i] = ascii2ebcdic[(int)ascii[i]];
}
}
#define SIGP_SENSE 0x01 #define SIGP_SENSE 0x01
#define SIGP_EXTERNAL_CALL 0x02 #define SIGP_EXTERNAL_CALL 0x02
#define SIGP_EMERGENCY 0x03 #define SIGP_EMERGENCY 0x03

View File

@ -2,6 +2,7 @@
* QEMU S390x KVM implementation * QEMU S390x KVM implementation
* *
* Copyright (c) 2009 Alexander Graf <agraf@suse.de> * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
* Copyright IBM Corp. 2012
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -13,7 +14,10 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * Contributions after 2012-10-29 are licensed under the terms of the
* GNU GPL, version 2 or (at your option) any later version.
*
* You should have received a copy of the GNU (Lesser) General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>. * License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/ */
@ -85,7 +89,14 @@ int kvm_arch_init_vcpu(CPUState *cpu)
void kvm_arch_reset_vcpu(CPUState *cpu) void kvm_arch_reset_vcpu(CPUState *cpu)
{ {
/* FIXME: add code to reset vcpu. */ /* The initial reset call is needed here to reset in-kernel
* vcpu data that we can't access directly from QEMU
* (i.e. with older kernels which don't support sync_regs/ONE_REG).
* Before this ioctl cpu_synchronize_state() is called in common kvm
* code (kvm-all) */
if (kvm_vcpu_ioctl(cpu, KVM_S390_INITIAL_RESET, NULL)) {
perror("Can't reset vcpu\n");
}
} }
int kvm_arch_put_registers(CPUState *cs, int level) int kvm_arch_put_registers(CPUState *cs, int level)
@ -386,7 +397,7 @@ static int handle_priv(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
static int handle_hypercall(CPUS390XState *env, struct kvm_run *run) static int handle_hypercall(CPUS390XState *env, struct kvm_run *run)
{ {
cpu_synchronize_state(env); cpu_synchronize_state(env);
env->regs[2] = s390_virtio_hypercall(env, env->regs[2], env->regs[1]); env->regs[2] = s390_virtio_hypercall(env);
return 0; return 0;
} }

View File

@ -70,6 +70,87 @@ void HELPER(exception)(CPUS390XState *env, uint32_t excp)
} }
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
/* EBCDIC handling */
static const uint8_t ebcdic2ascii[] = {
0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21,
0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07,
0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07,
};
static const uint8_t ascii2ebcdic[] = {
0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,
0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
};
static inline void ebcdic_put(uint8_t *p, const char *ascii, int len)
{
int i;
for (i = 0; i < len; i++) {
p[i] = ascii2ebcdic[(uint8_t)ascii[i]];
}
}
void program_interrupt(CPUS390XState *env, uint32_t code, int ilen) void program_interrupt(CPUS390XState *env, uint32_t code, int ilen)
{ {
qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n", qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
@ -107,7 +188,7 @@ uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem,
switch (num) { switch (num) {
case 0x500: case 0x500:
/* KVM hypercall */ /* KVM hypercall */
r = s390_virtio_hypercall(env, mem, code); r = s390_virtio_hypercall(env);
break; break;
case 0x44: case 0x44:
/* yield */ /* yield */