提交 ae7a4c0a 编写于 作者: P Peter Maydell

Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20181004' into staging

Various s390x updates:
- fix several struct definitions so that sparc hosts do not trip over
  unaligned accesses
- fence enabling huge pages for pre-3.1 machines
- sysbus init -> realize conversion
- fixes and improvements in tcg (instruction flags and AFP registers)

# gpg: Signature made Thu 04 Oct 2018 16:22:20 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-20181004:
  hw/s390x/s390-pci-bus: Convert sysbus init function to realize function
  s390x/tcg: refactor specification checking
  s390x/tcg: fix FP register pair checks
  s390x/tcg: handle privileged instructions via flags
  s390x/tcg: check for AFP-register, BFP and DFP data exceptions
  s390x/tcg: add instruction flags for floating point instructions
  s390x/tcg: support flags for instructions
  s390x/tcg: store in the TB flags if AFP is enabled
  s390x/tcg: factor out and fix DATA exception injection
  s390x: move tcg_s390_program_interrupt() into TCG code and mark it noreturn
  target/s390x: exception on non-aligned LPSW(E)
  s390x: Fence huge pages prior to 3.1
  hw/s390x/ioinst: Fix alignment problem in struct SubchDev
  hw/s390x/css: Remove QEMU_PACKED from struct SenseId
  hw/s390x/ipl: Fix alignment problems of S390IPLState members
Signed-off-by: NPeter Maydell <peter.maydell@linaro.org>
......@@ -750,20 +750,25 @@ static void sch_handle_halt_func(SubchDev *sch)
}
static void copy_sense_id_to_guest(SenseId *dest, SenseId *src)
/*
* As the SenseId struct cannot be packed (would cause unaligned accesses), we
* have to copy the individual fields to an unstructured area using the correct
* layout (see SA22-7204-01 "Common I/O-Device Commands").
*/
static void copy_sense_id_to_guest(uint8_t *dest, SenseId *src)
{
int i;
dest->reserved = src->reserved;
dest->cu_type = cpu_to_be16(src->cu_type);
dest->cu_model = src->cu_model;
dest->dev_type = cpu_to_be16(src->dev_type);
dest->dev_model = src->dev_model;
dest->unused = src->unused;
for (i = 0; i < ARRAY_SIZE(dest->ciw); i++) {
dest->ciw[i].type = src->ciw[i].type;
dest->ciw[i].command = src->ciw[i].command;
dest->ciw[i].count = cpu_to_be16(src->ciw[i].count);
dest[0] = src->reserved;
stw_be_p(dest + 1, src->cu_type);
dest[3] = src->cu_model;
stw_be_p(dest + 4, src->dev_type);
dest[6] = src->dev_model;
dest[7] = src->unused;
for (i = 0; i < ARRAY_SIZE(src->ciw); i++) {
dest[8 + i * 4] = src->ciw[i].type;
dest[9 + i * 4] = src->ciw[i].command;
stw_be_p(dest + 10 + i * 4, src->ciw[i].count);
}
}
......@@ -1044,9 +1049,10 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr,
break;
case CCW_CMD_SENSE_ID:
{
SenseId sense_id;
/* According to SA22-7204-01, Sense-ID can store up to 256 bytes */
uint8_t sense_id[256];
copy_sense_id_to_guest(&sense_id, &sch->id);
copy_sense_id_to_guest(sense_id, &sch->id);
/* Sense ID information is device specific. */
if (check_len) {
if (ccw.count != sizeof(sense_id)) {
......@@ -1060,11 +1066,11 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr,
* have enough place to store at least bytes 0-3.
*/
if (len >= 4) {
sense_id.reserved = 0xff;
sense_id[0] = 0xff;
} else {
sense_id.reserved = 0;
sense_id[0] = 0;
}
ccw_dstream_write_buf(&sch->cds, &sense_id, len);
ccw_dstream_write_buf(&sch->cds, sense_id, len);
sch->curr_status.scsw.count = ccw_dstream_residual_count(&sch->cds);
ret = 0;
break;
......
......@@ -132,15 +132,15 @@ typedef struct QemuIplParameters QemuIplParameters;
struct S390IPLState {
/*< private >*/
DeviceState parent_obj;
IplParameterBlock iplb;
QemuIplParameters qipl;
uint64_t start_addr;
uint64_t compat_start_addr;
uint64_t bios_start_addr;
uint64_t compat_bios_start_addr;
bool enforce_bios;
IplParameterBlock iplb;
bool iplb_valid;
bool netboot;
QemuIplParameters qipl;
/* reset related properties don't have to be migrated or reset */
enum s390_reset reset_type;
int reset_cpu_index;
......@@ -157,6 +157,7 @@ struct S390IPLState {
bool iplbext_migration;
};
typedef struct S390IPLState S390IPLState;
QEMU_BUILD_BUG_MSG(offsetof(S390IPLState, iplb) & 3, "alignment of iplb wrong");
#define S390_IPL_TYPE_FCP 0x00
#define S390_IPL_TYPE_CCW 0x02
......
......@@ -692,27 +692,35 @@ static void s390_pci_iommu_free(S390pciState *s, PCIBus *bus, int32_t devfn)
object_unref(OBJECT(iommu));
}
static int s390_pcihost_init(SysBusDevice *dev)
static void s390_pcihost_realize(DeviceState *dev, Error **errp)
{
PCIBus *b;
BusState *bus;
PCIHostState *phb = PCI_HOST_BRIDGE(dev);
S390pciState *s = S390_PCI_HOST_BRIDGE(dev);
Error *local_err = NULL;
DPRINTF("host_init\n");
b = pci_register_root_bus(DEVICE(dev), NULL,
s390_pci_set_irq, s390_pci_map_irq, NULL,
get_system_memory(), get_system_io(), 0, 64,
TYPE_PCI_BUS);
b = pci_register_root_bus(dev, NULL, s390_pci_set_irq, s390_pci_map_irq,
NULL, get_system_memory(), get_system_io(), 0,
64, TYPE_PCI_BUS);
pci_setup_iommu(b, s390_pci_dma_iommu, s);
bus = BUS(b);
qbus_set_hotplug_handler(bus, DEVICE(dev), NULL);
qbus_set_hotplug_handler(bus, dev, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
phb->bus = b;
s->bus = S390_PCI_BUS(qbus_create(TYPE_S390_PCI_BUS, DEVICE(s), NULL));
qbus_set_hotplug_handler(BUS(s->bus), DEVICE(s), NULL);
s->bus = S390_PCI_BUS(qbus_create(TYPE_S390_PCI_BUS, dev, NULL));
qbus_set_hotplug_handler(BUS(s->bus), dev, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
s->iommu_table = g_hash_table_new_full(g_int64_hash, g_int64_equal,
NULL, g_free);
......@@ -722,9 +730,10 @@ static int s390_pcihost_init(SysBusDevice *dev)
QTAILQ_INIT(&s->zpci_devs);
css_register_io_adapters(CSS_IO_ADAPTER_PCI, true, false,
S390_ADAPTER_SUPPRESSIBLE, &error_abort);
return 0;
S390_ADAPTER_SUPPRESSIBLE, &local_err);
if (local_err) {
error_propagate(errp, local_err);
}
}
static int s390_pci_msix_init(S390PCIBusDevice *pbdev)
......@@ -1018,12 +1027,11 @@ static void s390_pcihost_reset(DeviceState *dev)
static void s390_pcihost_class_init(ObjectClass *klass, void *data)
{
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
dc->reset = s390_pcihost_reset;
k->init = s390_pcihost_init;
dc->realize = s390_pcihost_realize;
hc->plug = s390_pcihost_hot_plug;
hc->unplug = s390_pcihost_hot_unplug;
msi_nonbroken = true;
......
......@@ -456,6 +456,7 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data)
s390mc->ri_allowed = true;
s390mc->cpu_model_allowed = true;
s390mc->css_migration_enabled = true;
s390mc->hpage_1m_allowed = true;
mc->init = ccw_init;
mc->reset = s390_machine_reset;
mc->hot_add_cpu = s390_hot_add_cpu;
......@@ -535,6 +536,12 @@ bool cpu_model_allowed(void)
return get_machine_class()->cpu_model_allowed;
}
bool hpage_1m_allowed(void)
{
/* for "none" machine this results in true */
return get_machine_class()->hpage_1m_allowed;
}
static char *machine_get_loadparm(Object *obj, Error **errp)
{
S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
......@@ -747,6 +754,9 @@ static void ccw_machine_3_0_instance_options(MachineState *machine)
static void ccw_machine_3_0_class_options(MachineClass *mc)
{
S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
s390mc->hpage_1m_allowed = false;
ccw_machine_3_1_class_options(mc);
SET_MACHINE_COMPAT(mc, CCW_COMPAT_3_0);
}
......
......@@ -48,7 +48,7 @@ typedef struct SenseId {
uint8_t unused; /* padding byte */
/* extended part */
CIW ciw[MAX_CIWS]; /* variable # of CIWs */
} QEMU_PACKED SenseId;
} SenseId; /* Note: No QEMU_PACKED due to unaligned members */
/* Channel measurements, from linux/drivers/s390/cio/cmf.c. */
typedef struct CMB {
......@@ -118,11 +118,12 @@ typedef enum IOInstEnding {
typedef struct SubchDev SubchDev;
struct SubchDev {
/* channel-subsystem related things: */
SCHIB curr_status; /* Needs alignment and thus must come first */
ORB orb;
uint8_t cssid;
uint8_t ssid;
uint16_t schid;
uint16_t devno;
SCHIB curr_status;
uint8_t sense_data[32];
hwaddr channel_prog;
CCW1 last_cmd;
......@@ -131,7 +132,6 @@ struct SubchDev {
bool thinint_active;
uint8_t ccw_no_data_cnt;
uint16_t migrated_schid; /* used for missmatch detection */
ORB orb;
CcwDataStream cds;
/* transport-provided data: */
int (*ccw_cb) (SubchDev *, CCW1);
......
......@@ -25,7 +25,8 @@ typedef struct SCSW {
uint8_t dstat;
uint8_t cstat;
uint16_t count;
} QEMU_PACKED SCSW;
} SCSW;
QEMU_BUILD_BUG_MSG(sizeof(SCSW) != 12, "size of SCSW is wrong");
#define SCSW_FLAGS_MASK_KEY 0xf000
#define SCSW_FLAGS_MASK_SCTL 0x0800
......@@ -94,7 +95,8 @@ typedef struct PMCW {
uint8_t pam;
uint8_t chpid[8];
uint32_t chars;
} QEMU_PACKED PMCW;
} PMCW;
QEMU_BUILD_BUG_MSG(sizeof(PMCW) != 28, "size of PMCW is wrong");
#define PMCW_FLAGS_MASK_QF 0x8000
#define PMCW_FLAGS_MASK_W 0x4000
......@@ -127,7 +129,8 @@ typedef struct IRB {
uint32_t esw[5];
uint32_t ecw[8];
uint32_t emw[8];
} QEMU_PACKED IRB;
} IRB;
QEMU_BUILD_BUG_MSG(sizeof(IRB) != 96, "size of IRB is wrong");
/* operation request block */
typedef struct ORB {
......@@ -136,7 +139,8 @@ typedef struct ORB {
uint8_t lpm;
uint8_t ctrl1;
uint32_t cpa;
} QEMU_PACKED ORB;
} ORB;
QEMU_BUILD_BUG_MSG(sizeof(ORB) != 12, "size of ORB is wrong");
#define ORB_CTRL0_MASK_KEY 0xf000
#define ORB_CTRL0_MASK_SPND 0x0800
......@@ -165,7 +169,8 @@ typedef struct CCW0 {
uint8_t flags;
uint8_t reserved;
uint16_t count;
} QEMU_PACKED CCW0;
} CCW0;
QEMU_BUILD_BUG_MSG(sizeof(CCW0) != 8, "size of CCW0 is wrong");
/* channel command word (type 1) */
typedef struct CCW1 {
......@@ -173,7 +178,8 @@ typedef struct CCW1 {
uint8_t flags;
uint16_t count;
uint32_t cda;
} QEMU_PACKED CCW1;
} CCW1;
QEMU_BUILD_BUG_MSG(sizeof(CCW1) != 8, "size of CCW1 is wrong");
#define CCW_FLAG_DC 0x80
#define CCW_FLAG_CC 0x40
......@@ -192,7 +198,8 @@ typedef struct CCW1 {
typedef struct CRW {
uint16_t flags;
uint16_t rsid;
} QEMU_PACKED CRW;
} CRW;
QEMU_BUILD_BUG_MSG(sizeof(CRW) != 4, "size of CRW is wrong");
#define CRW_FLAGS_MASK_S 0x4000
#define CRW_FLAGS_MASK_R 0x2000
......
......@@ -39,12 +39,15 @@ typedef struct S390CcwMachineClass {
bool ri_allowed;
bool cpu_model_allowed;
bool css_migration_enabled;
bool hpage_1m_allowed;
} S390CcwMachineClass;
/* runtime-instrumentation allowed by the machine */
bool ri_allowed(void);
/* cpu model allowed by the machine */
bool cpu_model_allowed(void);
/* 1M huge page mappings allowed by the machine */
bool hpage_1m_allowed(void);
/**
* Returns true if (vmstate based) migration of the channel subsystem
......
......@@ -255,6 +255,7 @@ extern const struct VMStateDescription vmstate_s390_cpu;
/* PSW defines */
#undef PSW_MASK_PER
#undef PSW_MASK_UNUSED_2
#undef PSW_MASK_DAT
#undef PSW_MASK_IO
#undef PSW_MASK_EXT
......@@ -273,6 +274,7 @@ extern const struct VMStateDescription vmstate_s390_cpu;
#undef PSW_MASK_ESA_ADDR
#define PSW_MASK_PER 0x4000000000000000ULL
#define PSW_MASK_UNUSED_2 0x2000000000000000ULL
#define PSW_MASK_DAT 0x0400000000000000ULL
#define PSW_MASK_IO 0x0200000000000000ULL
#define PSW_MASK_EXT 0x0100000000000000ULL
......@@ -318,10 +320,14 @@ extern const struct VMStateDescription vmstate_s390_cpu;
#define FLAG_MASK_PSW (FLAG_MASK_PER | FLAG_MASK_DAT | FLAG_MASK_PSTATE \
| FLAG_MASK_ASC | FLAG_MASK_64 | FLAG_MASK_32)
/* we'll use some unused PSW positions to store CR flags in tb flags */
#define FLAG_MASK_AFP (PSW_MASK_UNUSED_2 >> FLAG_MASK_PSW_SHIFT)
/* Control register 0 bits */
#define CR0_LOWPROT 0x0000000010000000ULL
#define CR0_SECONDARY 0x0000000004000000ULL
#define CR0_EDAT 0x0000000000800000ULL
#define CR0_AFP 0x0000000000040000ULL
#define CR0_EMERGENCY_SIGNAL_SC 0x0000000000004000ULL
#define CR0_EXTERNAL_CALL_SC 0x0000000000002000ULL
#define CR0_CKC_SC 0x0000000000000800ULL
......@@ -363,6 +369,9 @@ static inline void cpu_get_tb_cpu_state(CPUS390XState* env, target_ulong *pc,
*pc = env->psw.addr;
*cs_base = env->ex_value;
*flags = (env->psw.mask >> FLAG_MASK_PSW_SHIFT) & FLAG_MASK_PSW;
if (env->cregs[0] & CR0_AFP) {
*flags |= FLAG_MASK_AFP;
}
}
/* PER bits from control register 9 */
......
......@@ -21,11 +21,13 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
#include "exec/helper-proto.h"
#include "qemu/timer.h"
#include "exec/exec-all.h"
#include "exec/cpu_ldst.h"
#include "hw/s390x/ioinst.h"
#include "exec/address-spaces.h"
#include "tcg_s390x.h"
#ifndef CONFIG_USER_ONLY
#include "sysemu/sysemu.h"
#include "hw/s390x/s390_flic.h"
......@@ -48,6 +50,40 @@
do { } while (0)
#endif
void QEMU_NORETURN tcg_s390_program_interrupt(CPUS390XState *env, uint32_t code,
int ilen, uintptr_t ra)
{
CPUState *cs = CPU(s390_env_get_cpu(env));
cpu_restore_state(cs, ra, true);
qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
env->psw.addr);
trigger_pgm_exception(env, code, ilen);
cpu_loop_exit(cs);
}
void QEMU_NORETURN tcg_s390_data_exception(CPUS390XState *env, uint32_t dxc,
uintptr_t ra)
{
g_assert(dxc <= 0xff);
#if !defined(CONFIG_USER_ONLY)
/* Store the DXC into the lowcore */
stl_phys(CPU(s390_env_get_cpu(env))->as,
env->psa + offsetof(LowCore, data_exc_code), dxc);
#endif
/* Store the DXC into the FPC if AFP is enabled */
if (env->cregs[0] & CR0_AFP) {
env->fpc = deposit32(env->fpc, 8, 8, dxc);
}
tcg_s390_program_interrupt(env, PGM_DATA, ILEN_AUTO, ra);
}
void HELPER(data_exception)(CPUS390XState *env, uint32_t dxc)
{
tcg_s390_data_exception(env, dxc, GETPC());
}
#if defined(CONFIG_USER_ONLY)
void s390_cpu_do_interrupt(CPUState *cs)
......
......@@ -21,6 +21,7 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
#include "tcg_s390x.h"
#include "exec/exec-all.h"
#include "exec/cpu_ldst.h"
#include "exec/helper-proto.h"
......@@ -40,14 +41,6 @@
? (mask / (from / to)) & to \
: (mask & from) * (to / from))
static void ieee_exception(CPUS390XState *env, uint32_t dxc, uintptr_t retaddr)
{
/* Install the DXC code. */
env->fpc = (env->fpc & ~0xff00) | (dxc << 8);
/* Trap. */
s390_program_interrupt(env, PGM_DATA, ILEN_AUTO, retaddr);
}
/* Should be called after any operation that may raise IEEE exceptions. */
static void handle_exceptions(CPUS390XState *env, uintptr_t retaddr)
{
......@@ -75,7 +68,7 @@ static void handle_exceptions(CPUS390XState *env, uintptr_t retaddr)
/* Send signals for enabled exceptions. */
s390_exc &= env->fpc >> 24;
if (s390_exc) {
ieee_exception(env, s390_exc, retaddr);
tcg_s390_data_exception(env, s390_exc, retaddr);
}
}
......@@ -773,6 +766,6 @@ void HELPER(sfas)(CPUS390XState *env, uint64_t val)
is also 1, a simulated-iee-exception trap occurs. */
s390_exc = (signalling >> 16) & (source >> 24);
if (s390_exc) {
ieee_exception(env, s390_exc | 3, GETPC());
tcg_s390_data_exception(env, s390_exc | 3, GETPC());
}
}
DEF_HELPER_2(exception, noreturn, env, i32)
DEF_HELPER_2(data_exception, noreturn, env, i32)
DEF_HELPER_FLAGS_4(nc, TCG_CALL_NO_WG, i32, env, i32, i64, i64)
DEF_HELPER_FLAGS_4(oc, TCG_CALL_NO_WG, i32, env, i32, i64, i64)
DEF_HELPER_FLAGS_4(xc, TCG_CALL_NO_WG, i32, env, i32, i64, i64)
......
此差异已折叠。
......@@ -15,6 +15,7 @@
#include "exec/exec-all.h"
#include "sysemu/kvm.h"
#include "hw/s390x/ioinst.h"
#include "tcg_s390x.h"
#if !defined(CONFIG_USER_ONLY)
#include "hw/s390x/s390_flic.h"
#endif
......@@ -29,25 +30,11 @@ void trigger_pgm_exception(CPUS390XState *env, uint32_t code, uint32_t ilen)
env->int_pgm_ilen = ilen;
}
static void tcg_s390_program_interrupt(CPUS390XState *env, uint32_t code,
int ilen, uintptr_t ra)
{
#ifdef CONFIG_TCG
trigger_pgm_exception(env, code, ilen);
cpu_loop_exit_restore(CPU(s390_env_get_cpu(env)), ra);
#else
g_assert_not_reached();
#endif
}
void s390_program_interrupt(CPUS390XState *env, uint32_t code, int ilen,
uintptr_t ra)
{
S390CPU *cpu = s390_env_get_cpu(env);
qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
env->psw.addr);
if (kvm_enabled()) {
kvm_s390_program_interrupt(cpu, code);
} else if (tcg_enabled()) {
......
......@@ -36,6 +36,7 @@
#include "qemu/timer.h"
#include "qemu/units.h"
#include "qemu/mmap-alloc.h"
#include "qemu/log.h"
#include "sysemu/sysemu.h"
#include "sysemu/hw_accel.h"
#include "hw/hw.h"
......@@ -292,6 +293,12 @@ static int kvm_s390_configure_mempath_backing(KVMState *s)
return 0;
}
if (!hpage_1m_allowed()) {
error_report("This QEMU machine does not support huge page "
"mappings");
return -EINVAL;
}
if (path_psize != 1 * MiB) {
error_report("Memory backing with 2G pages was specified, "
"but KVM does not support this memory backing");
......@@ -1109,7 +1116,8 @@ void kvm_s390_program_interrupt(S390CPU *cpu, uint16_t code)
.type = KVM_S390_PROGRAM_INT,
.u.pgm.code = code,
};
qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
cpu->env.psw.addr);
kvm_s390_vcpu_interrupt(cpu, &irq);
}
......
......@@ -18,3 +18,13 @@
void tcg_s390_tod_updated(CPUState *cs, run_on_cpu_data opaque)
{
}
void QEMU_NORETURN tcg_s390_program_interrupt(CPUS390XState *env, uint32_t code,
int ilen, uintptr_t ra)
{
g_assert_not_reached();
}
void QEMU_NORETURN tcg_s390_data_exception(CPUS390XState *env, uint32_t dxc,
uintptr_t ra)
{
g_assert_not_reached();
}
......@@ -14,5 +14,9 @@
#define TCG_S390X_H
void tcg_s390_tod_updated(CPUState *cs, run_on_cpu_data opaque);
void QEMU_NORETURN tcg_s390_program_interrupt(CPUS390XState *env, uint32_t code,
int ilen, uintptr_t ra);
void QEMU_NORETURN tcg_s390_data_exception(CPUS390XState *env, uint32_t dxc,
uintptr_t ra);
#endif /* TCG_S390X_H */
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册