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>
master
Peter Maydell 2018-07-02 14:57:43 +01:00
commit 7320bb2cb0
30 changed files with 543 additions and 166 deletions

View File

@ -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);

View File

@ -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++;

View File

@ -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

View File

@ -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);

View File

@ -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)

64
hw/s390x/tod-kvm.c Normal file
View File

@ -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);

87
hw/s390x/tod-qemu.c Normal file
View File

@ -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);

130
hw/s390x/tod.c Normal file
View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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) \

65
include/hw/s390x/tod.h Normal file
View File

@ -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

View File

@ -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;

View File

@ -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.

View File

@ -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)/

View File

@ -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()) {

View File

@ -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);

View File

@ -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

View File

@ -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)

View File

@ -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 */

View File

@ -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)
{

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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;
}

View File

@ -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 */

20
target/s390x/tcg-stub.c Normal file
View File

@ -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)
{
}

18
target/s390x/tcg_s390x.h Normal file
View File

@ -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 */

View File

@ -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
View File

@ -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;