提交 7320bb2c 编写于 作者: P Peter Maydell

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: NPeter Maydell <peter.maydell@linaro.org>
...@@ -191,7 +191,7 @@ void pstrcpy_targphys(const char *name, hwaddr dest, int buf_size, ...@@ -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); rom_add_blob_fixed(name, source, (nulp - source) + 1, dest);
} else { } else {
rom_add_blob_fixed(name, source, buf_size, dest); 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; *ptr = 0;
} }
} }
...@@ -1165,7 +1165,7 @@ void rom_reset_order_override(void) ...@@ -1165,7 +1165,7 @@ void rom_reset_order_override(void)
fw_cfg_reset_order_override(fw_cfg); fw_cfg_reset_order_override(fw_cfg);
} }
static Rom *find_rom(hwaddr addr) static Rom *find_rom(hwaddr addr, size_t size)
{ {
Rom *rom; Rom *rom;
...@@ -1179,7 +1179,7 @@ static Rom *find_rom(hwaddr addr) ...@@ -1179,7 +1179,7 @@ static Rom *find_rom(hwaddr addr)
if (rom->addr > addr) { if (rom->addr > addr) {
continue; continue;
} }
if (rom->addr + rom->romsize < addr) { if (rom->addr + rom->romsize < addr + size) {
continue; continue;
} }
return rom; return rom;
...@@ -1249,11 +1249,11 @@ int rom_copy(uint8_t *dest, hwaddr addr, size_t size) ...@@ -1249,11 +1249,11 @@ int rom_copy(uint8_t *dest, hwaddr addr, size_t size)
return (d + l) - dest; return (d + l) - dest;
} }
void *rom_ptr(hwaddr addr) void *rom_ptr(hwaddr addr, size_t size)
{ {
Rom *rom; Rom *rom;
rom = find_rom(addr); rom = find_rom(addr, size);
if (!rom || !rom->data) if (!rom || !rom->data)
return NULL; return NULL;
return rom->data + (addr - rom->addr); return rom->data + (addr - rom->addr);
......
...@@ -1133,11 +1133,13 @@ void mips_malta_init(MachineState *machine) ...@@ -1133,11 +1133,13 @@ void mips_malta_init(MachineState *machine)
a neat trick which allows bi-endian firmware. */ a neat trick which allows bi-endian firmware. */
#ifndef TARGET_WORDS_BIGENDIAN #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) { if (!addr) {
addr = memory_region_get_ram_ptr(bios); addr = memory_region_get_ram_ptr(bios);
} }
end = (void *)addr + MIN(bios_size, 0x3e0000); end = (void *)addr + swapsize;
while (addr < end) { while (addr < end) {
bswap32s(addr); bswap32s(addr);
addr++; addr++;
......
...@@ -14,6 +14,9 @@ obj-$(CONFIG_PCI) += s390-pci-bus.o s390-pci-inst.o ...@@ -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-$(call lnot,$(CONFIG_PCI)) += s390-pci-stub.o
obj-y += s390-skeys.o obj-y += s390-skeys.o
obj-y += s390-stattrib.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-skeys-kvm.o
obj-$(CONFIG_KVM) += s390-stattrib-kvm.o obj-$(CONFIG_KVM) += s390-stattrib-kvm.o
obj-y += s390-ccw.o obj-y += s390-ccw.o
...@@ -33,7 +33,6 @@ ...@@ -33,7 +33,6 @@
#define KERN_PARM_AREA 0x010480UL #define KERN_PARM_AREA 0x010480UL
#define INITRD_START 0x800000UL #define INITRD_START 0x800000UL
#define INITRD_PARM_START 0x010408UL #define INITRD_PARM_START 0x010408UL
#define INITRD_PARM_SIZE 0x010410UL
#define PARMFILE_START 0x001000UL #define PARMFILE_START 0x001000UL
#define ZIPL_IMAGE_START 0x009000UL #define ZIPL_IMAGE_START 0x009000UL
#define IPL_PSW_MASK (PSW_MASK_32 | PSW_MASK_64) #define IPL_PSW_MASK (PSW_MASK_32 | PSW_MASK_64)
...@@ -165,12 +164,12 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp) ...@@ -165,12 +164,12 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
goto error; goto error;
} }
/* if this is Linux use KERN_IMAGE_START */ /* 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)) { if (magic && !memcmp(magic, "S390EP", 6)) {
pentry = KERN_IMAGE_START; pentry = KERN_IMAGE_START;
} else { } else {
/* if not Linux load the address of the (short) IPL PSW */ /* 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) { if (ipl_psw) {
pentry = be32_to_cpu(*ipl_psw) & 0x7fffffffUL; pentry = be32_to_cpu(*ipl_psw) & 0x7fffffffUL;
} else { } else {
...@@ -186,9 +185,12 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp) ...@@ -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. * loader) and it won't work. For this case we force it to 0x10000, too.
*/ */
if (pentry == KERN_IMAGE_START || pentry == 0x800) { 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; ipl->start_addr = KERN_IMAGE_START;
/* Overwrite parameters in the kernel image, which are "rom" */ /* 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 { } else {
ipl->start_addr = pentry; ipl->start_addr = pentry;
} }
...@@ -196,6 +198,7 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp) ...@@ -196,6 +198,7 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
if (ipl->initrd) { if (ipl->initrd) {
ram_addr_t initrd_offset; ram_addr_t initrd_offset;
int initrd_size; int initrd_size;
uint64_t *romptr;
initrd_offset = INITRD_START; initrd_offset = INITRD_START;
while (kernel_size + 0x100000 > initrd_offset) { while (kernel_size + 0x100000 > initrd_offset) {
...@@ -212,8 +215,11 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp) ...@@ -212,8 +215,11 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
* we have to overwrite values in the kernel image, * we have to overwrite values in the kernel image,
* which are "rom" * which are "rom"
*/ */
stq_p(rom_ptr(INITRD_PARM_START), initrd_offset); romptr = rom_ptr(INITRD_PARM_START, 16);
stq_p(rom_ptr(INITRD_PARM_SIZE), initrd_size); 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) ...@@ -535,7 +541,13 @@ void s390_ipl_reset_request(CPUState *cs, enum s390_reset reset_type)
ipl->iplb_valid = s390_gen_initial_iplb(ipl); 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 */ /* as this is triggered by a CPU, make sure to exit the loop */
if (tcg_enabled()) { if (tcg_enabled()) {
cpu_loop_exit(cs); cpu_loop_exit(cs);
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include "migration/register.h" #include "migration/register.h"
#include "cpu_models.h" #include "cpu_models.h"
#include "hw/nmi.h" #include "hw/nmi.h"
#include "hw/s390x/tod.h"
S390CPU *s390_cpu_addr2state(uint16_t cpu_addr) S390CPU *s390_cpu_addr2state(uint16_t cpu_addr)
{ {
...@@ -187,58 +188,6 @@ static void s390_memory_init(ram_addr_t mem_size) ...@@ -187,58 +188,6 @@ static void s390_memory_init(ram_addr_t mem_size)
s390_stattrib_init(); 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, static void s390_init_ipl_dev(const char *kernel_filename,
const char *kernel_cmdline, const char *kernel_cmdline,
const char *initrd_filename, const char *firmware, const char *initrd_filename, const char *firmware,
...@@ -363,8 +312,8 @@ static void ccw_init(MachineState *machine) ...@@ -363,8 +312,8 @@ static void ccw_init(MachineState *machine)
s390_create_sclpconsole("sclplmconsole", serial_hd(1)); s390_create_sclpconsole("sclplmconsole", serial_hd(1));
} }
/* Register savevm handler for guest TOD clock */ /* init the TOD clock */
register_savevm_live(NULL, "todclock", 0, 1, &savevm_gtod, NULL); s390_init_tod();
} }
static void s390_cpu_plug(HotplugHandler *hotplug_dev, static void s390_cpu_plug(HotplugHandler *hotplug_dev,
...@@ -824,6 +773,8 @@ DEFINE_CCW_MACHINE(3_0, "3.0", true); ...@@ -824,6 +773,8 @@ DEFINE_CCW_MACHINE(3_0, "3.0", true);
static void ccw_machine_2_12_instance_options(MachineState *machine) static void ccw_machine_2_12_instance_options(MachineState *machine)
{ {
ccw_machine_3_0_instance_options(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) static void ccw_machine_2_12_class_options(MachineClass *mc)
......
/*
* 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);
/*
* 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);
/*
* 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, ...@@ -272,8 +272,8 @@ static unsigned long sun4m_load_kernel(const char *kernel_filename,
} }
if (initrd_size > 0) { if (initrd_size > 0) {
for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) { for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
ptr = rom_ptr(KERNEL_LOAD_ADDR + i); ptr = rom_ptr(KERNEL_LOAD_ADDR + i, 24);
if (ldl_p(ptr) == 0x48647253) { // HdrS if (ptr && ldl_p(ptr) == 0x48647253) { /* HdrS */
stl_p(ptr + 16, INITRD_LOAD_ADDR); stl_p(ptr + 16, INITRD_LOAD_ADDR);
stl_p(ptr + 20, initrd_size); stl_p(ptr + 20, initrd_size);
break; break;
......
...@@ -186,8 +186,8 @@ static uint64_t sun4u_load_kernel(const char *kernel_filename, ...@@ -186,8 +186,8 @@ static uint64_t sun4u_load_kernel(const char *kernel_filename,
} }
if (*initrd_size > 0) { if (*initrd_size > 0) {
for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) { for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
ptr = rom_ptr(*kernel_addr + i); ptr = rom_ptr(*kernel_addr + i, 32);
if (ldl_p(ptr + 8) == 0x48647253) { /* HdrS */ if (ptr && ldl_p(ptr + 8) == 0x48647253) { /* HdrS */
stl_p(ptr + 24, *initrd_addr + *kernel_addr); stl_p(ptr + 24, *initrd_addr + *kernel_addr);
stl_p(ptr + 28, *initrd_size); stl_p(ptr + 28, *initrd_size);
break; break;
......
...@@ -226,7 +226,7 @@ void rom_set_fw(FWCfgState *f); ...@@ -226,7 +226,7 @@ void rom_set_fw(FWCfgState *f);
void rom_set_order_override(int order); void rom_set_order_override(int order);
void rom_reset_order_override(void); void rom_reset_order_override(void);
int rom_copy(uint8_t *dest, hwaddr addr, size_t size); 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); void hmp_info_roms(Monitor *mon, const QDict *qdict);
#define rom_add_file_fixed(_f, _a, _i) \ #define rom_add_file_fixed(_f, _a, _i) \
......
/*
* 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 { ...@@ -44,6 +44,10 @@ typedef enum ShutdownCause {
turns that into a shutdown */ turns that into a shutdown */
SHUTDOWN_CAUSE_GUEST_PANIC, /* Guest panicked, and command line turns SHUTDOWN_CAUSE_GUEST_PANIC, /* Guest panicked, and command line turns
that into a shutdown */ 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, SHUTDOWN_CAUSE__MAX,
} ShutdownCause; } ShutdownCause;
......
...@@ -239,7 +239,7 @@ static void arm_cpu_reset(CPUState *s) ...@@ -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 */ /* Load the initial SP and PC from offset 0 and 4 in the vector table */
vecbase = env->v7m.vecbase[env->v7m.secure]; vecbase = env->v7m.vecbase[env->v7m.secure];
rom = rom_ptr(vecbase); rom = rom_ptr(vecbase, 8);
if (rom) { if (rom) {
/* Address zero is covered by ROM which hasn't yet been /* Address zero is covered by ROM which hasn't yet been
* copied into physical memory. * copied into physical memory.
......
...@@ -5,6 +5,7 @@ obj-$(CONFIG_SOFTMMU) += machine.o ioinst.o arch_dump.o mmu_helper.o diag.o ...@@ -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_SOFTMMU) += sigp.o
obj-$(CONFIG_KVM) += kvm.o obj-$(CONFIG_KVM) += kvm.o
obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o
obj-$(call lnot,$(CONFIG_TCG)) += tcg-stub.o
# build and run feature list generator # build and run feature list generator
feat-src = $(SRC_PATH)/target/$(TARGET_BASE_ARCH)/ feat-src = $(SRC_PATH)/target/$(TARGET_BASE_ARCH)/
......
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
#include "kvm_s390x.h" #include "kvm_s390x.h"
#include "sysemu/kvm.h" #include "sysemu/kvm.h"
#include "qemu-common.h" #include "qemu-common.h"
#include "qemu/cutils.h"
#include "qemu/timer.h" #include "qemu/timer.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "trace.h" #include "trace.h"
...@@ -219,11 +218,18 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp) ...@@ -219,11 +218,18 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp)
#endif #endif
s390_cpu_gdb_init(cs); s390_cpu_gdb_init(cs);
qemu_init_vcpu(cs); qemu_init_vcpu(cs);
#if !defined(CONFIG_USER_ONLY)
run_on_cpu(cs, s390_do_cpu_full_reset, RUN_ON_CPU_NULL); /*
#else * KVM requires the initial CPU reset ioctl to be executed on the target
cpu_reset(cs); * CPU thread. CPU hotplug under single-threaded TCG will not work with
#endif * 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); scc->parent_realize(dev, &err);
out: out:
...@@ -275,9 +281,6 @@ static void s390_cpu_initfn(Object *obj) ...@@ -275,9 +281,6 @@ static void s390_cpu_initfn(Object *obj)
CPUState *cs = CPU(obj); CPUState *cs = CPU(obj);
S390CPU *cpu = S390_CPU(obj); S390CPU *cpu = S390_CPU(obj);
CPUS390XState *env = &cpu->env; CPUS390XState *env = &cpu->env;
#if !defined(CONFIG_USER_ONLY)
struct tm tm;
#endif
cs->env_ptr = env; cs->env_ptr = env;
cs->halted = 1; cs->halted = 1;
...@@ -286,10 +289,6 @@ static void s390_cpu_initfn(Object *obj) ...@@ -286,10 +289,6 @@ static void s390_cpu_initfn(Object *obj)
s390_cpu_get_crash_info_qom, NULL, NULL, NULL, NULL); s390_cpu_get_crash_info_qom, NULL, NULL, NULL, NULL);
s390_cpu_model_register_props(obj); s390_cpu_model_register_props(obj);
#if !defined(CONFIG_USER_ONLY) #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->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); env->cpu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_cpu_timer, cpu);
s390_cpu_set_state(S390_CPU_STATE_STOPPED, 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) ...@@ -390,38 +389,6 @@ unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu)
return s390_count_running_cpus(); 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) int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit)
{ {
if (kvm_enabled()) { if (kvm_enabled()) {
......
...@@ -130,8 +130,6 @@ struct CPUS390XState { ...@@ -130,8 +130,6 @@ struct CPUS390XState {
uint64_t cpuid; uint64_t cpuid;
#endif #endif
uint64_t tod_offset;
uint64_t tod_basetime;
QEMUTimer *tod_timer; QEMUTimer *tod_timer;
QEMUTimer *cpu_timer; QEMUTimer *cpu_timer;
...@@ -714,8 +712,6 @@ static inline void s390_do_cpu_load_normal(CPUState *cs, run_on_cpu_data arg) ...@@ -714,8 +712,6 @@ static inline void s390_do_cpu_load_normal(CPUState *cs, run_on_cpu_data arg)
/* cpu.c */ /* 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); void s390_crypto_reset(void);
bool s390_get_squash_mcss(void); bool s390_get_squash_mcss(void);
int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit); int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit);
......
...@@ -512,6 +512,8 @@ static uint16_t default_GEN11_GA1[] = { ...@@ -512,6 +512,8 @@ static uint16_t default_GEN11_GA1[] = {
S390_FEAT_IPTE_RANGE, S390_FEAT_IPTE_RANGE,
S390_FEAT_ACCESS_EXCEPTION_FS_INDICATION, S390_FEAT_ACCESS_EXCEPTION_FS_INDICATION,
S390_FEAT_GROUP_MSA_EXT_4, S390_FEAT_GROUP_MSA_EXT_4,
S390_FEAT_PPA15,
S390_FEAT_BPB,
}; };
#define default_GEN11_GA2 EmptyFeat #define default_GEN11_GA2 EmptyFeat
......
...@@ -127,6 +127,7 @@ DEF_HELPER_4(diag, void, env, i32, i32, i32) ...@@ -127,6 +127,7 @@ DEF_HELPER_4(diag, void, env, i32, i32, i32)
DEF_HELPER_3(load_psw, noreturn, env, i64, i64) DEF_HELPER_3(load_psw, noreturn, env, i64, i64)
DEF_HELPER_FLAGS_2(spx, TCG_CALL_NO_RWG, void, env, 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_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(sckc, TCG_CALL_NO_RWG, void, env, i64)
DEF_HELPER_FLAGS_2(sckpf, 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) DEF_HELPER_FLAGS_1(stckc, TCG_CALL_NO_RWG, i64, env)
......
...@@ -997,8 +997,7 @@ ...@@ -997,8 +997,7 @@
/* SET ADDRESS SPACE CONTROL FAST */ /* SET ADDRESS SPACE CONTROL FAST */
C(0xb279, SACF, S, Z, 0, a2, 0, 0, sacf, 0) C(0xb279, SACF, S, Z, 0, a2, 0, 0, sacf, 0)
/* SET CLOCK */ /* SET CLOCK */
/* ??? Not implemented - is it necessary? */ C(0xb204, SCK, S, Z, la2, 0, 0, 0, sck, 0)
C(0xb204, SCK, S, Z, 0, 0, 0, 0, 0, 0)
/* SET CLOCK COMPARATOR */ /* SET CLOCK COMPARATOR */
C(0xb206, SCKC, S, Z, 0, m2_64a, 0, 0, sckc, 0) C(0xb206, SCKC, S, Z, 0, m2_64a, 0, 0, sckc, 0)
/* SET CLOCK PROGRAMMABLE FIELD */ /* SET CLOCK PROGRAMMABLE FIELD */
......
...@@ -237,21 +237,6 @@ enum cc_op { ...@@ -237,21 +237,6 @@ enum cc_op {
CC_OP_MAX 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, static inline hwaddr decode_basedisp_s(CPUS390XState *env, uint32_t ipb,
uint8_t *ar) uint8_t *ar)
{ {
......
...@@ -60,12 +60,12 @@ int kvm_s390_get_clock_ext(uint8_t *tod_high, uint64_t *tod_low) ...@@ -60,12 +60,12 @@ int kvm_s390_get_clock_ext(uint8_t *tod_high, uint64_t *tod_low)
return -ENOSYS; 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; 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; return -ENOSYS;
} }
......
...@@ -666,13 +666,13 @@ int kvm_s390_get_clock_ext(uint8_t *tod_high, uint64_t *tod_low) ...@@ -666,13 +666,13 @@ int kvm_s390_get_clock_ext(uint8_t *tod_high, uint64_t *tod_low)
return r; 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; int r;
struct kvm_device_attr attr = { struct kvm_device_attr attr = {
.group = KVM_S390_VM_TOD, .group = KVM_S390_VM_TOD,
.attr = KVM_S390_VM_TOD_LOW, .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); 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) ...@@ -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.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); 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 = { struct kvm_s390_vm_tod_clock gtod = {
.epoch_idx = *tod_high, .epoch_idx = tod_high,
.tod = *tod_low, .tod = tod_low,
}; };
struct kvm_device_attr attr = { struct kvm_device_attr attr = {
.group = KVM_S390_VM_TOD, .group = KVM_S390_VM_TOD,
...@@ -752,12 +752,23 @@ int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, uint8_t ar, void *hostbuf, ...@@ -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) 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, mem = mmap((void *) 0x800000000ULL, size,
PROT_EXEC|PROT_READ|PROT_WRITE, PROT_EXEC|PROT_READ|PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0); 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; static uint8_t const *sw_bp_inst;
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
#ifndef KVM_S390X_H #ifndef KVM_S390X_H
#define KVM_S390X_H #define KVM_S390X_H
#include "cpu-qom.h"
struct kvm_s390_irq; struct kvm_s390_irq;
void kvm_s390_floating_interrupt_legacy(struct kvm_s390_irq *irq); void kvm_s390_floating_interrupt_legacy(struct kvm_s390_irq *irq);
...@@ -25,8 +27,8 @@ int kvm_s390_get_ri(void); ...@@ -25,8 +27,8 @@ int kvm_s390_get_ri(void);
int kvm_s390_get_gs(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(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_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(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_ext(uint8_t tod_high, uint64_t tod_clock);
void kvm_s390_enable_css_support(S390CPU *cpu); void kvm_s390_enable_css_support(S390CPU *cpu);
int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch, int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch,
int vq, bool assign); int vq, bool assign);
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "cpu.h" #include "cpu.h"
#include "internal.h" #include "internal.h"
#include "kvm_s390x.h" #include "kvm_s390x.h"
#include "tcg_s390x.h"
#include "sysemu/kvm.h" #include "sysemu/kvm.h"
static int cpu_post_load(void *opaque, int version_id) static int cpu_post_load(void *opaque, int version_id)
...@@ -34,6 +35,11 @@ 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); 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; return 0;
} }
......
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
#include "qemu/timer.h" #include "qemu/timer.h"
#include "exec/exec-all.h" #include "exec/exec-all.h"
#include "exec/cpu_ldst.h" #include "exec/cpu_ldst.h"
#include "qapi/error.h"
#include "tcg_s390x.h"
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
#include "sysemu/cpus.h" #include "sysemu/cpus.h"
...@@ -39,6 +41,7 @@ ...@@ -39,6 +41,7 @@
#include "hw/s390x/ioinst.h" #include "hw/s390x/ioinst.h"
#include "hw/s390x/s390-pci-inst.h" #include "hw/s390x/s390-pci-inst.h"
#include "hw/boards.h" #include "hw/boards.h"
#include "hw/s390x/tod.h"
#endif #endif
/* #define DEBUG_HELPER */ /* #define DEBUG_HELPER */
...@@ -138,30 +141,69 @@ void HELPER(spx)(CPUS390XState *env, uint64_t a1) ...@@ -138,30 +141,69 @@ void HELPER(spx)(CPUS390XState *env, uint64_t a1)
/* Store Clock */ /* Store Clock */
uint64_t HELPER(stck)(CPUS390XState *env) uint64_t HELPER(stck)(CPUS390XState *env)
{ {
uint64_t time; S390TODState *td = s390_get_todstate();
S390TODClass *tdc = S390_TOD_GET_CLASS(td);
time = env->tod_offset + S390TOD tod;
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 */ static void update_ckc_timer(CPUS390XState *env)
void HELPER(sckc)(CPUS390XState *env, uint64_t time)
{ {
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; return;
} }
env->ckc = time;
/* difference between origins */ /* difference between origins */
time -= env->tod_offset; time = env->ckc - td->base.low;
/* nanoseconds */ /* nanoseconds */
time = tod2time(time); 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 */ /* Set Tod Programmable Field */
......
/*
* 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)
{
}
/*
* 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) ...@@ -4016,6 +4016,15 @@ static DisasJumpType op_stcke(DisasContext *s, DisasOps *o)
return DISAS_NEXT; 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) static DisasJumpType op_sckc(DisasContext *s, DisasOps *o)
{ {
check_privileged(s); check_privileged(s);
......
...@@ -1645,7 +1645,7 @@ void qemu_system_reset(ShutdownCause reason) ...@@ -1645,7 +1645,7 @@ void qemu_system_reset(ShutdownCause reason)
} else { } else {
qemu_devices_reset(); qemu_devices_reset();
} }
if (reason) { if (reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) {
qapi_event_send_reset(shutdown_caused_by_guest(reason), qapi_event_send_reset(shutdown_caused_by_guest(reason),
&error_abort); &error_abort);
} }
...@@ -1691,7 +1691,7 @@ void qemu_system_guest_panicked(GuestPanicInformation *info) ...@@ -1691,7 +1691,7 @@ void qemu_system_guest_panicked(GuestPanicInformation *info)
void qemu_system_reset_request(ShutdownCause reason) void qemu_system_reset_request(ShutdownCause reason)
{ {
if (no_reboot) { if (no_reboot && reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) {
shutdown_requested = reason; shutdown_requested = reason;
} else { } else {
reset_requested = reason; reset_requested = reason;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册