mirror of https://gitee.com/openkylin/qemu.git
s390x updates:
- add bpb/ppa15 features to default cpu model for z196 and later - rework TOD handling and fix cpu hotplug under tcg - various fixes -----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEEw9DWbcNiT/aowBjO3s9rk8bwL68FAls6B/QSHGNvaHVja0By ZWRoYXQuY29tAAoJEN7Pa5PG8C+vqCIQAII2fFuPicarkERO8DBbn/nzPWMNp20f UUkhmS5w7Bng3Fq2hL3aihmRijMM7K4+6M4m0/mEf6Z07dQmC5M/FGNsV22/ToFb wjGUZM/SaqJF+gosEvA/pzhc8GmgPCDF3z2Phbdqsa4Ck33sMKyZIGveH8jF9lDf 8HoljDQ06ckXhaIsX1DZ9I6o6u5CpoCOSLrwuLpVfzFK1fimD04B44GINZg/oJQ0 e++ac2OwyV7OgjdLiNlVJOI5UV7iVrgZRvtGLqLzRCWLJVDl85I2JwhQwx0mHv4Y Of0SyiY3SF5jiV/FCLdd/k9CxMUzBXhZvq5vi7qtejakiVbVA+W5E1hugUUl794a gjlsrkKnpFFAW6QU8/4bq88I9e0F4LXLfaK1dCnOsJX3kGIruUjLGfOTM/T2Cuz9 0oJPYgZs0NAxTh+9wsFOlhS0EBr8jczn+DRRQjUPrzWk2INLtl8kKyjh71UW9yl5 vYCZevK9KUuZXNGBsqVn2pS1rKbryoJVm3IZudJXBvyj5EPo4q3Tdxm7NZKGPIlu e6VXHinhMtk7BZt5J2HNKGFIo5IPCcYQJCgs6+M1wRTHK6VtquVvas0y5aW5Wvl8 0lHI0fmflDoHbPiyRH9xvOS3r/y9xNYoUUG2GxjQqteW7tJAuhYy/rQIvBbVKufL 0xFKC4vdhV7c =GF+m -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20180702' into staging s390x updates: - add bpb/ppa15 features to default cpu model for z196 and later - rework TOD handling and fix cpu hotplug under tcg - various fixes # gpg: Signature made Mon 02 Jul 2018 12:09:40 BST # gpg: using RSA key DECF6B93C6F02FAF # gpg: Good signature from "Cornelia Huck <conny@cornelia-huck.de>" # gpg: aka "Cornelia Huck <huckc@linux.vnet.ibm.com>" # gpg: aka "Cornelia Huck <cornelia.huck@de.ibm.com>" # gpg: aka "Cornelia Huck <cohuck@kernel.org>" # gpg: aka "Cornelia Huck <cohuck@redhat.com>" # Primary key fingerprint: C3D0 D66D C362 4FF6 A8C0 18CE DECF 6B93 C6F0 2FAF * remotes/cohuck/tags/s390x-20180702: s390x/tcg: fix locking problem with tcg_s390_tod_updated s390x/kvm: indicate alignment in legacy_s390_alloc() s390x/kvm: legacy_s390_alloc() only supports one allocation s390x/tcg: fix CPU hotplug with single-threaded TCG s390x/tcg: rearm the CKC timer during migration s390x/tcg: implement SET CLOCK s390x/tcg: SET CLOCK COMPARATOR can clear CKC interrupts s390x/tcg: properly implement the TOD s390x/tcg: drop tod_basetime s390x/tod: factor out TOD into separate device s390x/kvm: pass values instead of pointers to kvm_s390_set_clock_*() s390x/tcg: avoid overflows in time2tod/tod2time s390x/cpumodel: default enable bpb and ppa15 for z196 and later loader: Check access size when calling rom_ptr() to avoid crashes s390/ipl: fix ipl with -no-reboot Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
7320bb2cb0
|
@ -191,7 +191,7 @@ void pstrcpy_targphys(const char *name, hwaddr dest, int buf_size,
|
|||
rom_add_blob_fixed(name, source, (nulp - source) + 1, dest);
|
||||
} else {
|
||||
rom_add_blob_fixed(name, source, buf_size, dest);
|
||||
ptr = rom_ptr(dest + buf_size - 1);
|
||||
ptr = rom_ptr(dest + buf_size - 1, sizeof(*ptr));
|
||||
*ptr = 0;
|
||||
}
|
||||
}
|
||||
|
@ -1165,7 +1165,7 @@ void rom_reset_order_override(void)
|
|||
fw_cfg_reset_order_override(fw_cfg);
|
||||
}
|
||||
|
||||
static Rom *find_rom(hwaddr addr)
|
||||
static Rom *find_rom(hwaddr addr, size_t size)
|
||||
{
|
||||
Rom *rom;
|
||||
|
||||
|
@ -1179,7 +1179,7 @@ static Rom *find_rom(hwaddr addr)
|
|||
if (rom->addr > addr) {
|
||||
continue;
|
||||
}
|
||||
if (rom->addr + rom->romsize < addr) {
|
||||
if (rom->addr + rom->romsize < addr + size) {
|
||||
continue;
|
||||
}
|
||||
return rom;
|
||||
|
@ -1249,11 +1249,11 @@ int rom_copy(uint8_t *dest, hwaddr addr, size_t size)
|
|||
return (d + l) - dest;
|
||||
}
|
||||
|
||||
void *rom_ptr(hwaddr addr)
|
||||
void *rom_ptr(hwaddr addr, size_t size)
|
||||
{
|
||||
Rom *rom;
|
||||
|
||||
rom = find_rom(addr);
|
||||
rom = find_rom(addr, size);
|
||||
if (!rom || !rom->data)
|
||||
return NULL;
|
||||
return rom->data + (addr - rom->addr);
|
||||
|
|
|
@ -1133,11 +1133,13 @@ void mips_malta_init(MachineState *machine)
|
|||
a neat trick which allows bi-endian firmware. */
|
||||
#ifndef TARGET_WORDS_BIGENDIAN
|
||||
{
|
||||
uint32_t *end, *addr = rom_ptr(FLASH_ADDRESS);
|
||||
uint32_t *end, *addr;
|
||||
const size_t swapsize = MIN(bios_size, 0x3e0000);
|
||||
addr = rom_ptr(FLASH_ADDRESS, swapsize);
|
||||
if (!addr) {
|
||||
addr = memory_region_get_ram_ptr(bios);
|
||||
}
|
||||
end = (void *)addr + MIN(bios_size, 0x3e0000);
|
||||
end = (void *)addr + swapsize;
|
||||
while (addr < end) {
|
||||
bswap32s(addr);
|
||||
addr++;
|
||||
|
|
|
@ -14,6 +14,9 @@ obj-$(CONFIG_PCI) += s390-pci-bus.o s390-pci-inst.o
|
|||
obj-$(call lnot,$(CONFIG_PCI)) += s390-pci-stub.o
|
||||
obj-y += s390-skeys.o
|
||||
obj-y += s390-stattrib.o
|
||||
obj-y += tod.o
|
||||
obj-$(CONFIG_KVM) += tod-kvm.o
|
||||
obj-$(CONFIG_TCG) += tod-qemu.o
|
||||
obj-$(CONFIG_KVM) += s390-skeys-kvm.o
|
||||
obj-$(CONFIG_KVM) += s390-stattrib-kvm.o
|
||||
obj-y += s390-ccw.o
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
#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_IMAGE_START 0x009000UL
|
||||
#define IPL_PSW_MASK (PSW_MASK_32 | PSW_MASK_64)
|
||||
|
@ -165,12 +164,12 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
|
|||
goto error;
|
||||
}
|
||||
/* if this is Linux use KERN_IMAGE_START */
|
||||
magic = rom_ptr(LINUX_MAGIC_ADDR);
|
||||
magic = rom_ptr(LINUX_MAGIC_ADDR, 6);
|
||||
if (magic && !memcmp(magic, "S390EP", 6)) {
|
||||
pentry = KERN_IMAGE_START;
|
||||
} else {
|
||||
/* if not Linux load the address of the (short) IPL PSW */
|
||||
ipl_psw = rom_ptr(4);
|
||||
ipl_psw = rom_ptr(4, 4);
|
||||
if (ipl_psw) {
|
||||
pentry = be32_to_cpu(*ipl_psw) & 0x7fffffffUL;
|
||||
} else {
|
||||
|
@ -186,9 +185,12 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
|
|||
* loader) and it won't work. For this case we force it to 0x10000, too.
|
||||
*/
|
||||
if (pentry == KERN_IMAGE_START || pentry == 0x800) {
|
||||
char *parm_area = rom_ptr(KERN_PARM_AREA, strlen(ipl->cmdline) + 1);
|
||||
ipl->start_addr = KERN_IMAGE_START;
|
||||
/* Overwrite parameters in the kernel image, which are "rom" */
|
||||
strcpy(rom_ptr(KERN_PARM_AREA), ipl->cmdline);
|
||||
if (parm_area) {
|
||||
strcpy(parm_area, ipl->cmdline);
|
||||
}
|
||||
} else {
|
||||
ipl->start_addr = pentry;
|
||||
}
|
||||
|
@ -196,6 +198,7 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
|
|||
if (ipl->initrd) {
|
||||
ram_addr_t initrd_offset;
|
||||
int initrd_size;
|
||||
uint64_t *romptr;
|
||||
|
||||
initrd_offset = INITRD_START;
|
||||
while (kernel_size + 0x100000 > initrd_offset) {
|
||||
|
@ -212,8 +215,11 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
|
|||
* 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);
|
||||
romptr = rom_ptr(INITRD_PARM_START, 16);
|
||||
if (romptr) {
|
||||
stq_p(romptr, initrd_offset);
|
||||
stq_p(romptr + 1, initrd_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
@ -535,7 +541,13 @@ void s390_ipl_reset_request(CPUState *cs, enum s390_reset reset_type)
|
|||
ipl->iplb_valid = s390_gen_initial_iplb(ipl);
|
||||
}
|
||||
}
|
||||
qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
|
||||
if (reset_type == S390_RESET_MODIFIED_CLEAR ||
|
||||
reset_type == S390_RESET_LOAD_NORMAL) {
|
||||
/* ignore -no-reboot, send no event */
|
||||
qemu_system_reset_request(SHUTDOWN_CAUSE_SUBSYSTEM_RESET);
|
||||
} else {
|
||||
qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
|
||||
}
|
||||
/* as this is triggered by a CPU, make sure to exit the loop */
|
||||
if (tcg_enabled()) {
|
||||
cpu_loop_exit(cs);
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "migration/register.h"
|
||||
#include "cpu_models.h"
|
||||
#include "hw/nmi.h"
|
||||
#include "hw/s390x/tod.h"
|
||||
|
||||
S390CPU *s390_cpu_addr2state(uint16_t cpu_addr)
|
||||
{
|
||||
|
@ -187,58 +188,6 @@ static void s390_memory_init(ram_addr_t mem_size)
|
|||
s390_stattrib_init();
|
||||
}
|
||||
|
||||
#define S390_TOD_CLOCK_VALUE_MISSING 0x00
|
||||
#define S390_TOD_CLOCK_VALUE_PRESENT 0x01
|
||||
|
||||
static void gtod_save(QEMUFile *f, void *opaque)
|
||||
{
|
||||
uint64_t tod_low;
|
||||
uint8_t tod_high;
|
||||
int r;
|
||||
|
||||
r = s390_get_clock(&tod_high, &tod_low);
|
||||
if (r) {
|
||||
warn_report("Unable to get guest clock for migration: %s",
|
||||
strerror(-r));
|
||||
error_printf("Guest clock will not be migrated "
|
||||
"which could cause the guest to hang.");
|
||||
qemu_put_byte(f, S390_TOD_CLOCK_VALUE_MISSING);
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_put_byte(f, S390_TOD_CLOCK_VALUE_PRESENT);
|
||||
qemu_put_byte(f, tod_high);
|
||||
qemu_put_be64(f, tod_low);
|
||||
}
|
||||
|
||||
static int gtod_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
uint64_t tod_low;
|
||||
uint8_t tod_high;
|
||||
int r;
|
||||
|
||||
if (qemu_get_byte(f) == S390_TOD_CLOCK_VALUE_MISSING) {
|
||||
warn_report("Guest clock was not migrated. This could "
|
||||
"cause the guest to hang.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
tod_high = qemu_get_byte(f);
|
||||
tod_low = qemu_get_be64(f);
|
||||
|
||||
r = s390_set_clock(&tod_high, &tod_low);
|
||||
if (r) {
|
||||
error_report("Unable to set KVM guest TOD clock: %s", strerror(-r));
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static SaveVMHandlers savevm_gtod = {
|
||||
.save_state = gtod_save,
|
||||
.load_state = gtod_load,
|
||||
};
|
||||
|
||||
static void s390_init_ipl_dev(const char *kernel_filename,
|
||||
const char *kernel_cmdline,
|
||||
const char *initrd_filename, const char *firmware,
|
||||
|
@ -363,8 +312,8 @@ static void ccw_init(MachineState *machine)
|
|||
s390_create_sclpconsole("sclplmconsole", serial_hd(1));
|
||||
}
|
||||
|
||||
/* Register savevm handler for guest TOD clock */
|
||||
register_savevm_live(NULL, "todclock", 0, 1, &savevm_gtod, NULL);
|
||||
/* init the TOD clock */
|
||||
s390_init_tod();
|
||||
}
|
||||
|
||||
static void s390_cpu_plug(HotplugHandler *hotplug_dev,
|
||||
|
@ -824,6 +773,8 @@ DEFINE_CCW_MACHINE(3_0, "3.0", true);
|
|||
static void ccw_machine_2_12_instance_options(MachineState *machine)
|
||||
{
|
||||
ccw_machine_3_0_instance_options(machine);
|
||||
s390_cpudef_featoff_greater(11, 1, S390_FEAT_PPA15);
|
||||
s390_cpudef_featoff_greater(11, 1, S390_FEAT_BPB);
|
||||
}
|
||||
|
||||
static void ccw_machine_2_12_class_options(MachineClass *mc)
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* TOD (Time Of Day) clock - KVM implementation
|
||||
*
|
||||
* Copyright 2018 Red Hat, Inc.
|
||||
* Author(s): David Hildenbrand <david@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/s390x/tod.h"
|
||||
#include "kvm_s390x.h"
|
||||
|
||||
static void kvm_s390_tod_get(const S390TODState *td, S390TOD *tod, Error **errp)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = kvm_s390_get_clock_ext(&tod->high, &tod->low);
|
||||
if (r == -ENXIO) {
|
||||
r = kvm_s390_get_clock(&tod->high, &tod->low);
|
||||
}
|
||||
if (r) {
|
||||
error_setg(errp, "Unable to get KVM guest TOD clock: %s",
|
||||
strerror(-r));
|
||||
}
|
||||
}
|
||||
|
||||
static void kvm_s390_tod_set(S390TODState *td, const S390TOD *tod, Error **errp)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = kvm_s390_set_clock_ext(tod->high, tod->low);
|
||||
if (r == -ENXIO) {
|
||||
r = kvm_s390_set_clock(tod->high, tod->low);
|
||||
}
|
||||
if (r) {
|
||||
error_setg(errp, "Unable to set KVM guest TOD clock: %s",
|
||||
strerror(-r));
|
||||
}
|
||||
}
|
||||
|
||||
static void kvm_s390_tod_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
S390TODClass *tdc = S390_TOD_CLASS(oc);
|
||||
|
||||
tdc->get = kvm_s390_tod_get;
|
||||
tdc->set = kvm_s390_tod_set;
|
||||
}
|
||||
|
||||
static TypeInfo kvm_s390_tod_info = {
|
||||
.name = TYPE_KVM_S390_TOD,
|
||||
.parent = TYPE_S390_TOD,
|
||||
.instance_size = sizeof(S390TODState),
|
||||
.class_init = kvm_s390_tod_class_init,
|
||||
.class_size = sizeof(S390TODClass),
|
||||
};
|
||||
|
||||
static void register_types(void)
|
||||
{
|
||||
type_register_static(&kvm_s390_tod_info);
|
||||
}
|
||||
type_init(register_types);
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* TOD (Time Of Day) clock - QEMU implementation
|
||||
*
|
||||
* Copyright 2018 Red Hat, Inc.
|
||||
* Author(s): David Hildenbrand <david@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/s390x/tod.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "cpu.h"
|
||||
#include "tcg_s390x.h"
|
||||
|
||||
static void qemu_s390_tod_get(const S390TODState *td, S390TOD *tod,
|
||||
Error **errp)
|
||||
{
|
||||
*tod = td->base;
|
||||
|
||||
tod->low += time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
|
||||
if (tod->low < td->base.low) {
|
||||
tod->high++;
|
||||
}
|
||||
}
|
||||
|
||||
static void qemu_s390_tod_set(S390TODState *td, const S390TOD *tod,
|
||||
Error **errp)
|
||||
{
|
||||
CPUState *cpu;
|
||||
|
||||
td->base = *tod;
|
||||
|
||||
td->base.low -= time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
|
||||
if (td->base.low > tod->low) {
|
||||
td->base.high--;
|
||||
}
|
||||
|
||||
/*
|
||||
* The TOD has been changed and we have to recalculate the CKC values
|
||||
* for all CPUs. We do this asynchronously, as "SET CLOCK should be
|
||||
* issued only while all other activity on all CPUs .. has been
|
||||
* suspended".
|
||||
*/
|
||||
CPU_FOREACH(cpu) {
|
||||
async_run_on_cpu(cpu, tcg_s390_tod_updated, RUN_ON_CPU_NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void qemu_s390_tod_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
S390TODClass *tdc = S390_TOD_CLASS(oc);
|
||||
|
||||
tdc->get = qemu_s390_tod_get;
|
||||
tdc->set = qemu_s390_tod_set;
|
||||
}
|
||||
|
||||
static void qemu_s390_tod_init(Object *obj)
|
||||
{
|
||||
S390TODState *td = S390_TOD(obj);
|
||||
struct tm tm;
|
||||
|
||||
qemu_get_timedate(&tm, 0);
|
||||
td->base.high = 0;
|
||||
td->base.low = TOD_UNIX_EPOCH + (time2tod(mktimegm(&tm)) * 1000000000ULL);
|
||||
if (td->base.low < TOD_UNIX_EPOCH) {
|
||||
td->base.high += 1;
|
||||
}
|
||||
}
|
||||
|
||||
static TypeInfo qemu_s390_tod_info = {
|
||||
.name = TYPE_QEMU_S390_TOD,
|
||||
.parent = TYPE_S390_TOD,
|
||||
.instance_size = sizeof(S390TODState),
|
||||
.instance_init = qemu_s390_tod_init,
|
||||
.class_init = qemu_s390_tod_class_init,
|
||||
.class_size = sizeof(S390TODClass),
|
||||
};
|
||||
|
||||
static void register_types(void)
|
||||
{
|
||||
type_register_static(&qemu_s390_tod_info);
|
||||
}
|
||||
type_init(register_types);
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* TOD (Time Of Day) clock
|
||||
*
|
||||
* Copyright 2018 Red Hat, Inc.
|
||||
* Author(s): David Hildenbrand <david@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/s390x/tod.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "migration/register.h"
|
||||
|
||||
void s390_init_tod(void)
|
||||
{
|
||||
Object *obj;
|
||||
|
||||
if (kvm_enabled()) {
|
||||
obj = object_new(TYPE_KVM_S390_TOD);
|
||||
} else {
|
||||
obj = object_new(TYPE_QEMU_S390_TOD);
|
||||
}
|
||||
object_property_add_child(qdev_get_machine(), TYPE_S390_TOD, obj, NULL);
|
||||
object_unref(obj);
|
||||
|
||||
qdev_init_nofail(DEVICE(obj));
|
||||
}
|
||||
|
||||
S390TODState *s390_get_todstate(void)
|
||||
{
|
||||
static S390TODState *ts;
|
||||
|
||||
if (!ts) {
|
||||
ts = S390_TOD(object_resolve_path_type("", TYPE_S390_TOD, NULL));
|
||||
}
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
#define S390_TOD_CLOCK_VALUE_MISSING 0x00
|
||||
#define S390_TOD_CLOCK_VALUE_PRESENT 0x01
|
||||
|
||||
static void s390_tod_save(QEMUFile *f, void *opaque)
|
||||
{
|
||||
S390TODState *td = opaque;
|
||||
S390TODClass *tdc = S390_TOD_GET_CLASS(td);
|
||||
Error *err = NULL;
|
||||
S390TOD tod;
|
||||
|
||||
tdc->get(td, &tod, &err);
|
||||
if (err) {
|
||||
warn_report_err(err);
|
||||
error_printf("Guest clock will not be migrated "
|
||||
"which could cause the guest to hang.");
|
||||
qemu_put_byte(f, S390_TOD_CLOCK_VALUE_MISSING);
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_put_byte(f, S390_TOD_CLOCK_VALUE_PRESENT);
|
||||
qemu_put_byte(f, tod.high);
|
||||
qemu_put_be64(f, tod.low);
|
||||
}
|
||||
|
||||
static int s390_tod_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
S390TODState *td = opaque;
|
||||
S390TODClass *tdc = S390_TOD_GET_CLASS(td);
|
||||
Error *err = NULL;
|
||||
S390TOD tod;
|
||||
|
||||
if (qemu_get_byte(f) == S390_TOD_CLOCK_VALUE_MISSING) {
|
||||
warn_report("Guest clock was not migrated. This could "
|
||||
"cause the guest to hang.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
tod.high = qemu_get_byte(f);
|
||||
tod.low = qemu_get_be64(f);
|
||||
|
||||
tdc->set(td, &tod, &err);
|
||||
if (err) {
|
||||
error_report_err(err);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SaveVMHandlers savevm_tod = {
|
||||
.save_state = s390_tod_save,
|
||||
.load_state = s390_tod_load,
|
||||
};
|
||||
|
||||
static void s390_tod_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
S390TODState *td = S390_TOD(dev);
|
||||
|
||||
/* Legacy migration interface */
|
||||
register_savevm_live(NULL, "todclock", 0, 1, &savevm_tod, td);
|
||||
}
|
||||
|
||||
static void s390_tod_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->desc = "TOD (Time Of Day) Clock";
|
||||
dc->realize = s390_tod_realize;
|
||||
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||
|
||||
/* We only have one TOD clock in the system attached to the machine */
|
||||
dc->user_creatable = false;
|
||||
}
|
||||
|
||||
static TypeInfo s390_tod_info = {
|
||||
.name = TYPE_S390_TOD,
|
||||
.parent = TYPE_DEVICE,
|
||||
.instance_size = sizeof(S390TODState),
|
||||
.class_init = s390_tod_class_init,
|
||||
.class_size = sizeof(S390TODClass),
|
||||
.abstract = true,
|
||||
};
|
||||
|
||||
static void register_types(void)
|
||||
{
|
||||
type_register_static(&s390_tod_info);
|
||||
}
|
||||
type_init(register_types);
|
|
@ -272,8 +272,8 @@ static unsigned long sun4m_load_kernel(const char *kernel_filename,
|
|||
}
|
||||
if (initrd_size > 0) {
|
||||
for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
|
||||
ptr = rom_ptr(KERNEL_LOAD_ADDR + i);
|
||||
if (ldl_p(ptr) == 0x48647253) { // HdrS
|
||||
ptr = rom_ptr(KERNEL_LOAD_ADDR + i, 24);
|
||||
if (ptr && ldl_p(ptr) == 0x48647253) { /* HdrS */
|
||||
stl_p(ptr + 16, INITRD_LOAD_ADDR);
|
||||
stl_p(ptr + 20, initrd_size);
|
||||
break;
|
||||
|
|
|
@ -186,8 +186,8 @@ static uint64_t sun4u_load_kernel(const char *kernel_filename,
|
|||
}
|
||||
if (*initrd_size > 0) {
|
||||
for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
|
||||
ptr = rom_ptr(*kernel_addr + i);
|
||||
if (ldl_p(ptr + 8) == 0x48647253) { /* HdrS */
|
||||
ptr = rom_ptr(*kernel_addr + i, 32);
|
||||
if (ptr && ldl_p(ptr + 8) == 0x48647253) { /* HdrS */
|
||||
stl_p(ptr + 24, *initrd_addr + *kernel_addr);
|
||||
stl_p(ptr + 28, *initrd_size);
|
||||
break;
|
||||
|
|
|
@ -226,7 +226,7 @@ void rom_set_fw(FWCfgState *f);
|
|||
void rom_set_order_override(int order);
|
||||
void rom_reset_order_override(void);
|
||||
int rom_copy(uint8_t *dest, hwaddr addr, size_t size);
|
||||
void *rom_ptr(hwaddr addr);
|
||||
void *rom_ptr(hwaddr addr, size_t size);
|
||||
void hmp_info_roms(Monitor *mon, const QDict *qdict);
|
||||
|
||||
#define rom_add_file_fixed(_f, _a, _i) \
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* TOD (Time Of Day) clock
|
||||
*
|
||||
* Copyright 2018 Red Hat, Inc.
|
||||
* Author(s): David Hildenbrand <david@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef HW_S390_TOD_H
|
||||
#define HW_S390_TOD_H
|
||||
|
||||
#include "hw/qdev.h"
|
||||
|
||||
typedef struct S390TOD {
|
||||
uint8_t high;
|
||||
uint64_t low;
|
||||
} S390TOD;
|
||||
|
||||
#define TYPE_S390_TOD "s390-tod"
|
||||
#define S390_TOD(obj) OBJECT_CHECK(S390TODState, (obj), TYPE_S390_TOD)
|
||||
#define S390_TOD_CLASS(oc) OBJECT_CLASS_CHECK(S390TODClass, (oc), \
|
||||
TYPE_S390_TOD)
|
||||
#define S390_TOD_GET_CLASS(obj) OBJECT_GET_CLASS(S390TODClass, (obj), \
|
||||
TYPE_S390_TOD)
|
||||
#define TYPE_KVM_S390_TOD TYPE_S390_TOD "-kvm"
|
||||
#define TYPE_QEMU_S390_TOD TYPE_S390_TOD "-qemu"
|
||||
|
||||
typedef struct S390TODState {
|
||||
/* private */
|
||||
DeviceState parent_obj;
|
||||
|
||||
/* unused by KVM implementation */
|
||||
S390TOD base;
|
||||
} S390TODState;
|
||||
|
||||
typedef struct S390TODClass {
|
||||
/* private */
|
||||
DeviceClass parent_class;
|
||||
|
||||
/* public */
|
||||
void (*get)(const S390TODState *td, S390TOD *tod, Error **errp);
|
||||
void (*set)(S390TODState *td, const S390TOD *tod, Error **errp);
|
||||
} S390TODClass;
|
||||
|
||||
/* The value of the TOD clock for 1.1.1970. */
|
||||
#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL
|
||||
|
||||
/* Converts ns to s390's clock format */
|
||||
static inline uint64_t time2tod(uint64_t ns)
|
||||
{
|
||||
return (ns << 9) / 125 + (((ns & 0xff10000000000000ull) / 125) << 9);
|
||||
}
|
||||
|
||||
/* Converts s390's clock format to ns */
|
||||
static inline uint64_t tod2time(uint64_t t)
|
||||
{
|
||||
return ((t >> 9) * 125) + (((t & 0x1ff) * 125) >> 9);
|
||||
}
|
||||
|
||||
void s390_init_tod(void);
|
||||
S390TODState *s390_get_todstate(void);
|
||||
|
||||
#endif
|
|
@ -44,6 +44,10 @@ typedef enum ShutdownCause {
|
|||
turns that into a shutdown */
|
||||
SHUTDOWN_CAUSE_GUEST_PANIC, /* Guest panicked, and command line turns
|
||||
that into a shutdown */
|
||||
SHUTDOWN_CAUSE_SUBSYSTEM_RESET,/* Partial guest reset that does not trigger
|
||||
QMP events and ignores --no-reboot. This
|
||||
is useful for sanitize hypercalls on s390
|
||||
that are used during kexec/kdump/boot */
|
||||
SHUTDOWN_CAUSE__MAX,
|
||||
} ShutdownCause;
|
||||
|
||||
|
|
|
@ -239,7 +239,7 @@ static void arm_cpu_reset(CPUState *s)
|
|||
|
||||
/* Load the initial SP and PC from offset 0 and 4 in the vector table */
|
||||
vecbase = env->v7m.vecbase[env->v7m.secure];
|
||||
rom = rom_ptr(vecbase);
|
||||
rom = rom_ptr(vecbase, 8);
|
||||
if (rom) {
|
||||
/* Address zero is covered by ROM which hasn't yet been
|
||||
* copied into physical memory.
|
||||
|
|
|
@ -5,6 +5,7 @@ obj-$(CONFIG_SOFTMMU) += machine.o ioinst.o arch_dump.o mmu_helper.o diag.o
|
|||
obj-$(CONFIG_SOFTMMU) += sigp.o
|
||||
obj-$(CONFIG_KVM) += kvm.o
|
||||
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
|
||||
obj-$(call lnot,$(CONFIG_TCG)) += tcg-stub.o
|
||||
|
||||
# build and run feature list generator
|
||||
feat-src = $(SRC_PATH)/target/$(TARGET_BASE_ARCH)/
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
#include "kvm_s390x.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "trace.h"
|
||||
|
@ -219,11 +218,18 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp)
|
|||
#endif
|
||||
s390_cpu_gdb_init(cs);
|
||||
qemu_init_vcpu(cs);
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
run_on_cpu(cs, s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
|
||||
#else
|
||||
cpu_reset(cs);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* KVM requires the initial CPU reset ioctl to be executed on the target
|
||||
* CPU thread. CPU hotplug under single-threaded TCG will not work with
|
||||
* run_on_cpu(), as run_on_cpu() will not work properly if called while
|
||||
* the main thread is already running but the CPU hasn't been realized.
|
||||
*/
|
||||
if (kvm_enabled()) {
|
||||
run_on_cpu(cs, s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
|
||||
} else {
|
||||
cpu_reset(cs);
|
||||
}
|
||||
|
||||
scc->parent_realize(dev, &err);
|
||||
out:
|
||||
|
@ -275,9 +281,6 @@ static void s390_cpu_initfn(Object *obj)
|
|||
CPUState *cs = CPU(obj);
|
||||
S390CPU *cpu = S390_CPU(obj);
|
||||
CPUS390XState *env = &cpu->env;
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
struct tm tm;
|
||||
#endif
|
||||
|
||||
cs->env_ptr = env;
|
||||
cs->halted = 1;
|
||||
|
@ -286,10 +289,6 @@ static void s390_cpu_initfn(Object *obj)
|
|||
s390_cpu_get_crash_info_qom, NULL, NULL, NULL, NULL);
|
||||
s390_cpu_model_register_props(obj);
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
qemu_get_timedate(&tm, 0);
|
||||
env->tod_offset = TOD_UNIX_EPOCH +
|
||||
(time2tod(mktimegm(&tm)) * 1000000000ULL);
|
||||
env->tod_basetime = 0;
|
||||
env->tod_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_tod_timer, cpu);
|
||||
env->cpu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_cpu_timer, cpu);
|
||||
s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu);
|
||||
|
@ -390,38 +389,6 @@ unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu)
|
|||
return s390_count_running_cpus();
|
||||
}
|
||||
|
||||
int s390_get_clock(uint8_t *tod_high, uint64_t *tod_low)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
if (kvm_enabled()) {
|
||||
r = kvm_s390_get_clock_ext(tod_high, tod_low);
|
||||
if (r == -ENXIO) {
|
||||
return kvm_s390_get_clock(tod_high, tod_low);
|
||||
}
|
||||
} else {
|
||||
/* Fixme TCG */
|
||||
*tod_high = 0;
|
||||
*tod_low = 0;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int s390_set_clock(uint8_t *tod_high, uint64_t *tod_low)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
if (kvm_enabled()) {
|
||||
r = kvm_s390_set_clock_ext(tod_high, tod_low);
|
||||
if (r == -ENXIO) {
|
||||
return kvm_s390_set_clock(tod_high, tod_low);
|
||||
}
|
||||
}
|
||||
/* Fixme TCG */
|
||||
return r;
|
||||
}
|
||||
|
||||
int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit)
|
||||
{
|
||||
if (kvm_enabled()) {
|
||||
|
|
|
@ -130,8 +130,6 @@ struct CPUS390XState {
|
|||
uint64_t cpuid;
|
||||
#endif
|
||||
|
||||
uint64_t tod_offset;
|
||||
uint64_t tod_basetime;
|
||||
QEMUTimer *tod_timer;
|
||||
|
||||
QEMUTimer *cpu_timer;
|
||||
|
@ -714,8 +712,6 @@ static inline void s390_do_cpu_load_normal(CPUState *cs, run_on_cpu_data arg)
|
|||
|
||||
|
||||
/* cpu.c */
|
||||
int s390_get_clock(uint8_t *tod_high, uint64_t *tod_low);
|
||||
int s390_set_clock(uint8_t *tod_high, uint64_t *tod_low);
|
||||
void s390_crypto_reset(void);
|
||||
bool s390_get_squash_mcss(void);
|
||||
int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit);
|
||||
|
|
|
@ -512,6 +512,8 @@ static uint16_t default_GEN11_GA1[] = {
|
|||
S390_FEAT_IPTE_RANGE,
|
||||
S390_FEAT_ACCESS_EXCEPTION_FS_INDICATION,
|
||||
S390_FEAT_GROUP_MSA_EXT_4,
|
||||
S390_FEAT_PPA15,
|
||||
S390_FEAT_BPB,
|
||||
};
|
||||
|
||||
#define default_GEN11_GA2 EmptyFeat
|
||||
|
|
|
@ -127,6 +127,7 @@ DEF_HELPER_4(diag, void, env, i32, i32, i32)
|
|||
DEF_HELPER_3(load_psw, noreturn, env, i64, i64)
|
||||
DEF_HELPER_FLAGS_2(spx, TCG_CALL_NO_RWG, void, env, i64)
|
||||
DEF_HELPER_FLAGS_1(stck, TCG_CALL_NO_RWG_SE, i64, env)
|
||||
DEF_HELPER_FLAGS_2(sck, TCG_CALL_NO_RWG, i32, env, i64)
|
||||
DEF_HELPER_FLAGS_2(sckc, TCG_CALL_NO_RWG, void, env, i64)
|
||||
DEF_HELPER_FLAGS_2(sckpf, TCG_CALL_NO_RWG, void, env, i64)
|
||||
DEF_HELPER_FLAGS_1(stckc, TCG_CALL_NO_RWG, i64, env)
|
||||
|
|
|
@ -997,8 +997,7 @@
|
|||
/* SET ADDRESS SPACE CONTROL FAST */
|
||||
C(0xb279, SACF, S, Z, 0, a2, 0, 0, sacf, 0)
|
||||
/* SET CLOCK */
|
||||
/* ??? Not implemented - is it necessary? */
|
||||
C(0xb204, SCK, S, Z, 0, 0, 0, 0, 0, 0)
|
||||
C(0xb204, SCK, S, Z, la2, 0, 0, 0, sck, 0)
|
||||
/* SET CLOCK COMPARATOR */
|
||||
C(0xb206, SCKC, S, Z, 0, m2_64a, 0, 0, sckc, 0)
|
||||
/* SET CLOCK PROGRAMMABLE FIELD */
|
||||
|
|
|
@ -237,21 +237,6 @@ enum cc_op {
|
|||
CC_OP_MAX
|
||||
};
|
||||
|
||||
/* The value of the TOD clock for 1.1.1970. */
|
||||
#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL
|
||||
|
||||
/* Converts ns to s390's clock format */
|
||||
static inline uint64_t time2tod(uint64_t ns)
|
||||
{
|
||||
return (ns << 9) / 125;
|
||||
}
|
||||
|
||||
/* Converts s390's clock format to ns */
|
||||
static inline uint64_t tod2time(uint64_t t)
|
||||
{
|
||||
return (t * 125) >> 9;
|
||||
}
|
||||
|
||||
static inline hwaddr decode_basedisp_s(CPUS390XState *env, uint32_t ipb,
|
||||
uint8_t *ar)
|
||||
{
|
||||
|
|
|
@ -60,12 +60,12 @@ int kvm_s390_get_clock_ext(uint8_t *tod_high, uint64_t *tod_low)
|
|||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int kvm_s390_set_clock(uint8_t *tod_high, uint64_t *tod_low)
|
||||
int kvm_s390_set_clock(uint8_t tod_high, uint64_t tod_low)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
int kvm_s390_set_clock_ext(uint8_t *tod_high, uint64_t *tod_low)
|
||||
int kvm_s390_set_clock_ext(uint8_t tod_high, uint64_t tod_low)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
|
|
@ -666,13 +666,13 @@ int kvm_s390_get_clock_ext(uint8_t *tod_high, uint64_t *tod_low)
|
|||
return r;
|
||||
}
|
||||
|
||||
int kvm_s390_set_clock(uint8_t *tod_high, uint64_t *tod_low)
|
||||
int kvm_s390_set_clock(uint8_t tod_high, uint64_t tod_low)
|
||||
{
|
||||
int r;
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_S390_VM_TOD,
|
||||
.attr = KVM_S390_VM_TOD_LOW,
|
||||
.addr = (uint64_t)tod_low,
|
||||
.addr = (uint64_t)&tod_low,
|
||||
};
|
||||
|
||||
r = kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
|
||||
|
@ -681,15 +681,15 @@ int kvm_s390_set_clock(uint8_t *tod_high, uint64_t *tod_low)
|
|||
}
|
||||
|
||||
attr.attr = KVM_S390_VM_TOD_HIGH;
|
||||
attr.addr = (uint64_t)tod_high;
|
||||
attr.addr = (uint64_t)&tod_high;
|
||||
return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
|
||||
}
|
||||
|
||||
int kvm_s390_set_clock_ext(uint8_t *tod_high, uint64_t *tod_low)
|
||||
int kvm_s390_set_clock_ext(uint8_t tod_high, uint64_t tod_low)
|
||||
{
|
||||
struct kvm_s390_vm_tod_clock gtod = {
|
||||
.epoch_idx = *tod_high,
|
||||
.tod = *tod_low,
|
||||
.epoch_idx = tod_high,
|
||||
.tod = tod_low,
|
||||
};
|
||||
struct kvm_device_attr attr = {
|
||||
.group = KVM_S390_VM_TOD,
|
||||
|
@ -752,12 +752,23 @@ int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, uint8_t ar, void *hostbuf,
|
|||
*/
|
||||
static void *legacy_s390_alloc(size_t size, uint64_t *align, bool shared)
|
||||
{
|
||||
void *mem;
|
||||
static void *mem;
|
||||
|
||||
if (mem) {
|
||||
/* we only support one allocation, which is enough for initial ram */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mem = mmap((void *) 0x800000000ULL, size,
|
||||
PROT_EXEC|PROT_READ|PROT_WRITE,
|
||||
MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
|
||||
return mem == MAP_FAILED ? NULL : mem;
|
||||
if (mem == MAP_FAILED) {
|
||||
mem = NULL;
|
||||
}
|
||||
if (mem && align) {
|
||||
*align = QEMU_VMALLOC_ALIGN;
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
static uint8_t const *sw_bp_inst;
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#ifndef KVM_S390X_H
|
||||
#define KVM_S390X_H
|
||||
|
||||
#include "cpu-qom.h"
|
||||
|
||||
struct kvm_s390_irq;
|
||||
|
||||
void kvm_s390_floating_interrupt_legacy(struct kvm_s390_irq *irq);
|
||||
|
@ -25,8 +27,8 @@ int kvm_s390_get_ri(void);
|
|||
int kvm_s390_get_gs(void);
|
||||
int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_clock);
|
||||
int kvm_s390_get_clock_ext(uint8_t *tod_high, uint64_t *tod_clock);
|
||||
int kvm_s390_set_clock(uint8_t *tod_high, uint64_t *tod_clock);
|
||||
int kvm_s390_set_clock_ext(uint8_t *tod_high, uint64_t *tod_clock);
|
||||
int kvm_s390_set_clock(uint8_t tod_high, uint64_t tod_clock);
|
||||
int kvm_s390_set_clock_ext(uint8_t tod_high, uint64_t tod_clock);
|
||||
void kvm_s390_enable_css_support(S390CPU *cpu);
|
||||
int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch,
|
||||
int vq, bool assign);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "cpu.h"
|
||||
#include "internal.h"
|
||||
#include "kvm_s390x.h"
|
||||
#include "tcg_s390x.h"
|
||||
#include "sysemu/kvm.h"
|
||||
|
||||
static int cpu_post_load(void *opaque, int version_id)
|
||||
|
@ -34,6 +35,11 @@ static int cpu_post_load(void *opaque, int version_id)
|
|||
return kvm_s390_vcpu_interrupt_post_load(cpu);
|
||||
}
|
||||
|
||||
if (tcg_enabled()) {
|
||||
/* Rearm the CKC timer if necessary */
|
||||
tcg_s390_tod_updated(CPU(cpu), RUN_ON_CPU_NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#include "qemu/timer.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "qapi/error.h"
|
||||
#include "tcg_s390x.h"
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
#include "sysemu/cpus.h"
|
||||
|
@ -39,6 +41,7 @@
|
|||
#include "hw/s390x/ioinst.h"
|
||||
#include "hw/s390x/s390-pci-inst.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/s390x/tod.h"
|
||||
#endif
|
||||
|
||||
/* #define DEBUG_HELPER */
|
||||
|
@ -138,30 +141,69 @@ void HELPER(spx)(CPUS390XState *env, uint64_t a1)
|
|||
/* Store Clock */
|
||||
uint64_t HELPER(stck)(CPUS390XState *env)
|
||||
{
|
||||
uint64_t time;
|
||||
S390TODState *td = s390_get_todstate();
|
||||
S390TODClass *tdc = S390_TOD_GET_CLASS(td);
|
||||
S390TOD tod;
|
||||
|
||||
time = env->tod_offset +
|
||||
time2tod(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - env->tod_basetime);
|
||||
|
||||
return time;
|
||||
tdc->get(td, &tod, &error_abort);
|
||||
return tod.low;
|
||||
}
|
||||
|
||||
/* Set Clock Comparator */
|
||||
void HELPER(sckc)(CPUS390XState *env, uint64_t time)
|
||||
static void update_ckc_timer(CPUS390XState *env)
|
||||
{
|
||||
if (time == -1ULL) {
|
||||
S390TODState *td = s390_get_todstate();
|
||||
uint64_t time;
|
||||
|
||||
/* stop the timer and remove pending CKC IRQs */
|
||||
timer_del(env->tod_timer);
|
||||
g_assert(qemu_mutex_iothread_locked());
|
||||
env->pending_int &= ~INTERRUPT_EXT_CLOCK_COMPARATOR;
|
||||
|
||||
/* the tod has to exceed the ckc, this can never happen if ckc is all 1's */
|
||||
if (env->ckc == -1ULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
env->ckc = time;
|
||||
|
||||
/* difference between origins */
|
||||
time -= env->tod_offset;
|
||||
time = env->ckc - td->base.low;
|
||||
|
||||
/* nanoseconds */
|
||||
time = tod2time(time);
|
||||
|
||||
timer_mod(env->tod_timer, env->tod_basetime + time);
|
||||
timer_mod(env->tod_timer, time);
|
||||
}
|
||||
|
||||
/* Set Clock Comparator */
|
||||
void HELPER(sckc)(CPUS390XState *env, uint64_t ckc)
|
||||
{
|
||||
env->ckc = ckc;
|
||||
|
||||
qemu_mutex_lock_iothread();
|
||||
update_ckc_timer(env);
|
||||
qemu_mutex_unlock_iothread();
|
||||
}
|
||||
|
||||
void tcg_s390_tod_updated(CPUState *cs, run_on_cpu_data opaque)
|
||||
{
|
||||
S390CPU *cpu = S390_CPU(cs);
|
||||
|
||||
update_ckc_timer(&cpu->env);
|
||||
}
|
||||
|
||||
/* Set Clock */
|
||||
uint32_t HELPER(sck)(CPUS390XState *env, uint64_t tod_low)
|
||||
{
|
||||
S390TODState *td = s390_get_todstate();
|
||||
S390TODClass *tdc = S390_TOD_GET_CLASS(td);
|
||||
S390TOD tod = {
|
||||
.high = 0,
|
||||
.low = tod_low,
|
||||
};
|
||||
|
||||
qemu_mutex_lock_iothread();
|
||||
tdc->set(td, &tod, &error_abort);
|
||||
qemu_mutex_unlock_iothread();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set Tod Programmable Field */
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* QEMU TCG support -- s390x specific function stubs.
|
||||
*
|
||||
* Copyright (C) 2018 Red Hat Inc
|
||||
*
|
||||
* Authors:
|
||||
* David Hildenbrand <david@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "cpu.h"
|
||||
#include "tcg_s390x.h"
|
||||
|
||||
void tcg_s390_tod_updated(CPUState *cs, run_on_cpu_data opaque)
|
||||
{
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* QEMU TCG support -- s390x specific functions.
|
||||
*
|
||||
* Copyright 2018 Red Hat, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* David Hildenbrand <david@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef TCG_S390X_H
|
||||
#define TCG_S390X_H
|
||||
|
||||
void tcg_s390_tod_updated(CPUState *cs, run_on_cpu_data opaque);
|
||||
|
||||
#endif /* TCG_S390X_H */
|
|
@ -4016,6 +4016,15 @@ static DisasJumpType op_stcke(DisasContext *s, DisasOps *o)
|
|||
return DISAS_NEXT;
|
||||
}
|
||||
|
||||
static DisasJumpType op_sck(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
check_privileged(s);
|
||||
tcg_gen_qemu_ld_i64(o->in1, o->addr1, get_mem_index(s), MO_TEQ | MO_ALIGN);
|
||||
gen_helper_sck(cc_op, cpu_env, o->in1);
|
||||
set_cc_static(s);
|
||||
return DISAS_NEXT;
|
||||
}
|
||||
|
||||
static DisasJumpType op_sckc(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
check_privileged(s);
|
||||
|
|
4
vl.c
4
vl.c
|
@ -1645,7 +1645,7 @@ void qemu_system_reset(ShutdownCause reason)
|
|||
} else {
|
||||
qemu_devices_reset();
|
||||
}
|
||||
if (reason) {
|
||||
if (reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) {
|
||||
qapi_event_send_reset(shutdown_caused_by_guest(reason),
|
||||
&error_abort);
|
||||
}
|
||||
|
@ -1691,7 +1691,7 @@ void qemu_system_guest_panicked(GuestPanicInformation *info)
|
|||
|
||||
void qemu_system_reset_request(ShutdownCause reason)
|
||||
{
|
||||
if (no_reboot) {
|
||||
if (no_reboot && reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) {
|
||||
shutdown_requested = reason;
|
||||
} else {
|
||||
reset_requested = reason;
|
||||
|
|
Loading…
Reference in New Issue