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:
commit
67c4f2d0e1
198
hw/s390-virtio.c
198
hw/s390-virtio.c
@ -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
22
hw/s390-virtio.h
Normal 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
|
@ -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
174
hw/s390x/ipl.c
Normal 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)
|
36
hw/s390x/s390-virtio-hcall.c
Normal file
36
hw/s390x/s390-virtio-hcall.c
Normal 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]);
|
||||||
|
}
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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 */
|
||||||
|
Loading…
Reference in New Issue
Block a user