add missing files

This commit is contained in:
Nguyen Anh Quynh 2021-12-06 04:28:13 +08:00
parent 97b92d8861
commit b042a6a01d
51 changed files with 28849 additions and 0 deletions

12
TODO-s390 Normal file
View File

@ -0,0 +1,12 @@
current status:
- only build s390x arch (see CMakeLists.txt)
- sample_s390x crash, due to qemu/target/s390x/cpu.c :: cpu_s390_init() still has bugs
Todo:
- fix qemu/target/s390x/cpu.c, so sample_s390x works
- enable building all arch to fix conflicts
- remove all static vars in qemu/target/s390x/translate.c
- support more registers in qemu/target/s390x/unicorn.c
- find & fix potential memory leaking with valgrind

99
include/unicorn/s390x.h Normal file
View File

@ -0,0 +1,99 @@
/* Unicorn Engine */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015-2021 */
#ifndef UNICORN_S390X_H
#define UNICORN_S390X_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _MSC_VER
#pragma warning(disable:4201)
#endif
//> S390X registers
typedef enum uc_s390x_reg {
UC_S390X_REG_INVALID = 0,
//> General purpose registers
UC_S390X_REG_R0,
UC_S390X_REG_R1,
UC_S390X_REG_R2,
UC_S390X_REG_R3,
UC_S390X_REG_R4,
UC_S390X_REG_R5,
UC_S390X_REG_R6,
UC_S390X_REG_R7,
UC_S390X_REG_R8,
UC_S390X_REG_R9,
UC_S390X_REG_R10,
UC_S390X_REG_R11,
UC_S390X_REG_R12,
UC_S390X_REG_R13,
UC_S390X_REG_R14,
UC_S390X_REG_R15,
//> Floating point registers
UC_S390X_REG_F0,
UC_S390X_REG_F1,
UC_S390X_REG_F2,
UC_S390X_REG_F3,
UC_S390X_REG_F4,
UC_S390X_REG_F5,
UC_S390X_REG_F6,
UC_S390X_REG_F7,
UC_S390X_REG_F8,
UC_S390X_REG_F9,
UC_S390X_REG_F10,
UC_S390X_REG_F11,
UC_S390X_REG_F12,
UC_S390X_REG_F13,
UC_S390X_REG_F14,
UC_S390X_REG_F15,
UC_S390X_REG_F16,
UC_S390X_REG_F17,
UC_S390X_REG_F18,
UC_S390X_REG_F19,
UC_S390X_REG_F20,
UC_S390X_REG_F21,
UC_S390X_REG_F22,
UC_S390X_REG_F23,
UC_S390X_REG_F24,
UC_S390X_REG_F25,
UC_S390X_REG_F26,
UC_S390X_REG_F27,
UC_S390X_REG_F28,
UC_S390X_REG_F29,
UC_S390X_REG_F30,
UC_S390X_REG_F31,
//> Access registers
UC_S390X_REG_A0,
UC_S390X_REG_A1,
UC_S390X_REG_A2,
UC_S390X_REG_A3,
UC_S390X_REG_A4,
UC_S390X_REG_A5,
UC_S390X_REG_A6,
UC_S390X_REG_A7,
UC_S390X_REG_A8,
UC_S390X_REG_A9,
UC_S390X_REG_A10,
UC_S390X_REG_A11,
UC_S390X_REG_A12,
UC_S390X_REG_A13,
UC_S390X_REG_A14,
UC_S390X_REG_A15,
UC_S390X_REG_PC, // PC register
UC_S390X_REG_ENDING, // <-- mark the end of the list or registers
//> Alias registers
} uc_s390x_reg;
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,8 @@
/* Automatically generated by create_config - do not modify */
#define TARGET_S390X 1
#define TARGET_NAME "s390x"
#define TARGET_S390X 1
#define TARGET_SYSTBL_ABI common,64
#define TARGET_WORDS_BIGENDIAN 1
#define CONFIG_SOFTMMU 1
#define TARGET_SUPPORTS_MTTCG 1

282
qemu/hw/s390x/s390-skeys.c Normal file
View File

@ -0,0 +1,282 @@
/*
* s390 storage key device
*
* Copyright 2015 IBM Corp.
* Author(s): Jason J. Herne <jjherne@linux.vnet.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at
* your option) any later version. See the COPYING file in the top-level
* directory.
*/
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "target/s390x/cpu.h"
#include "hw/s390x/storage-keys.h"
#define S390_SKEYS_BUFFER_SIZE (128 * KiB) /* Room for 128k storage keys */
#define S390_SKEYS_SAVE_FLAG_EOS 0x01
#define S390_SKEYS_SAVE_FLAG_SKEYS 0x02
#define S390_SKEYS_SAVE_FLAG_ERROR 0x04
#if 0
S390SKeysState *s390_get_skeys_device(void)
{
S390SKeysState *ss;
ss = S390_SKEYS(object_resolve_path_type("", TYPE_S390_SKEYS, NULL));
assert(ss);
return ss;
}
void s390_skeys_init(void)
{
Object *obj;
obj = object_new(TYPE_QEMU_S390_SKEYS);
object_property_add_child(qdev_get_machine(), TYPE_S390_SKEYS,
obj, NULL);
object_unref(obj);
qdev_init_nofail(DEVICE(obj));
}
static void qemu_s390_skeys_init(Object *obj)
{
QEMUS390SKeysState *skeys = QEMU_S390_SKEYS(obj);
MachineState *machine = MACHINE(qdev_get_machine());
skeys->key_count = machine->ram_size / TARGET_PAGE_SIZE;
skeys->keydata = g_malloc0(skeys->key_count);
}
static int qemu_s390_skeys_enabled(S390SKeysState *ss)
{
return 1;
}
/*
* TODO: for memory hotplug support qemu_s390_skeys_set and qemu_s390_skeys_get
* will have to make sure that the given gfn belongs to a memory region and not
* a memory hole.
*/
static int qemu_s390_skeys_set(S390SKeysState *ss, uint64_t start_gfn,
uint64_t count, uint8_t *keys)
{
QEMUS390SKeysState *skeydev = QEMU_S390_SKEYS(ss);
int i;
/* Check for uint64 overflow and access beyond end of key data */
if (start_gfn + count > skeydev->key_count || start_gfn + count < count) {
error_report("Error: Setting storage keys for page beyond the end "
"of memory: gfn=%" PRIx64 " count=%" PRId64,
start_gfn, count);
return -EINVAL;
}
for (i = 0; i < count; i++) {
skeydev->keydata[start_gfn + i] = keys[i];
}
return 0;
}
static int qemu_s390_skeys_get(S390SKeysState *ss, uint64_t start_gfn,
uint64_t count, uint8_t *keys)
{
QEMUS390SKeysState *skeydev = QEMU_S390_SKEYS(ss);
int i;
/* Check for uint64 overflow and access beyond end of key data */
if (start_gfn + count > skeydev->key_count || start_gfn + count < count) {
error_report("Error: Getting storage keys for page beyond the end "
"of memory: gfn=%" PRIx64 " count=%" PRId64,
start_gfn, count);
return -EINVAL;
}
for (i = 0; i < count; i++) {
keys[i] = skeydev->keydata[start_gfn + i];
}
return 0;
}
static void qemu_s390_skeys_class_init(ObjectClass *oc, void *data)
{
S390SKeysClass *skeyclass = S390_SKEYS_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
skeyclass->skeys_enabled = qemu_s390_skeys_enabled;
skeyclass->get_skeys = qemu_s390_skeys_get;
skeyclass->set_skeys = qemu_s390_skeys_set;
/* Reason: Internal device (only one skeys device for the whole memory) */
dc->user_creatable = false;
}
static const TypeInfo qemu_s390_skeys_info = {
.name = TYPE_QEMU_S390_SKEYS,
.parent = TYPE_S390_SKEYS,
.instance_init = qemu_s390_skeys_init,
.instance_size = sizeof(QEMUS390SKeysState),
.class_init = qemu_s390_skeys_class_init,
.class_size = sizeof(S390SKeysClass),
};
static void write_keys(FILE *f, uint8_t *keys, uint64_t startgfn,
uint64_t count, Error **errp)
{
uint64_t curpage = startgfn;
uint64_t maxpage = curpage + count - 1;
for (; curpage <= maxpage; curpage++) {
uint8_t acc = (*keys & 0xF0) >> 4;
int fp = (*keys & 0x08);
int ref = (*keys & 0x04);
int ch = (*keys & 0x02);
int res = (*keys & 0x01);
fprintf(f, "page=%03" PRIx64 ": key(%d) => ACC=%X, FP=%d, REF=%d,"
" ch=%d, reserved=%d\n",
curpage, *keys, acc, fp, ref, ch, res);
keys++;
}
}
static void s390_storage_keys_save(QEMUFile *f, void *opaque)
{
S390SKeysState *ss = S390_SKEYS(opaque);
S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss);
uint64_t pages_left = ram_size / TARGET_PAGE_SIZE;
uint64_t read_count, eos = S390_SKEYS_SAVE_FLAG_EOS;
vaddr cur_gfn = 0;
int error = 0;
uint8_t *buf;
if (!skeyclass->skeys_enabled(ss)) {
goto end_stream;
}
buf = g_try_malloc(S390_SKEYS_BUFFER_SIZE);
if (!buf) {
error_report("storage key save could not allocate memory");
goto end_stream;
}
/* We only support initial memory. Standby memory is not handled yet. */
qemu_put_be64(f, (cur_gfn * TARGET_PAGE_SIZE) | S390_SKEYS_SAVE_FLAG_SKEYS);
qemu_put_be64(f, pages_left);
while (pages_left) {
read_count = MIN(pages_left, S390_SKEYS_BUFFER_SIZE);
if (!error) {
error = skeyclass->get_skeys(ss, cur_gfn, read_count, buf);
if (error) {
/*
* If error: we want to fill the stream with valid data instead
* of stopping early so we pad the stream with 0x00 values and
* use S390_SKEYS_SAVE_FLAG_ERROR to indicate failure to the
* reading side.
*/
error_report("S390_GET_KEYS error %d", error);
memset(buf, 0, S390_SKEYS_BUFFER_SIZE);
eos = S390_SKEYS_SAVE_FLAG_ERROR;
}
}
qemu_put_buffer(f, buf, read_count);
cur_gfn += read_count;
pages_left -= read_count;
}
g_free(buf);
end_stream:
qemu_put_be64(f, eos);
}
static int s390_storage_keys_load(QEMUFile *f, void *opaque, int version_id)
{
S390SKeysState *ss = S390_SKEYS(opaque);
S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss);
int ret = 0;
while (!ret) {
ram_addr_t addr;
int flags;
addr = qemu_get_be64(f);
flags = addr & ~TARGET_PAGE_MASK;
addr &= TARGET_PAGE_MASK;
switch (flags) {
case S390_SKEYS_SAVE_FLAG_SKEYS: {
const uint64_t total_count = qemu_get_be64(f);
uint64_t handled_count = 0, cur_count;
uint64_t cur_gfn = addr / TARGET_PAGE_SIZE;
uint8_t *buf = g_try_malloc(S390_SKEYS_BUFFER_SIZE);
if (!buf) {
error_report("storage key load could not allocate memory");
ret = -ENOMEM;
break;
}
while (handled_count < total_count) {
cur_count = MIN(total_count - handled_count,
S390_SKEYS_BUFFER_SIZE);
qemu_get_buffer(f, buf, cur_count);
ret = skeyclass->set_skeys(ss, cur_gfn, cur_count, buf);
if (ret < 0) {
error_report("S390_SET_KEYS error %d", ret);
break;
}
handled_count += cur_count;
cur_gfn += cur_count;
}
g_free(buf);
break;
}
case S390_SKEYS_SAVE_FLAG_ERROR: {
error_report("Storage key data is incomplete");
ret = -EINVAL;
break;
}
case S390_SKEYS_SAVE_FLAG_EOS:
/* normal exit */
return 0;
default:
error_report("Unexpected storage key flag data: %#x", flags);
ret = -EINVAL;
}
}
return ret;
}
static void s390_skeys_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->hotpluggable = false;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
}
static const TypeInfo s390_skeys_info = {
.name = TYPE_S390_SKEYS,
.parent = TYPE_DEVICE,
.instance_init = NULL,
.instance_size = sizeof(S390SKeysState),
.class_init = s390_skeys_class_init,
.class_size = sizeof(S390SKeysClass),
.abstract = true,
};
static void qemu_s390_skeys_register_types(void)
{
type_register_static(&s390_skeys_info);
type_register_static(&qemu_s390_skeys_info);
}
type_init(qemu_s390_skeys_register_types)
#endif

View File

@ -0,0 +1,104 @@
/*
* EBCDIC/ASCII conversion Support
*
* Copyright (c) 2011 Alexander Graf
* Copyright IBM, Corp. 2013
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at your
* option) any later version. See the COPYING file in the top-level directory.
*
*/
#ifndef EBCDIC_H
#define EBCDIC_H
/* EBCDIC handling */
static const uint8_t ebcdic2ascii[] = {
0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21,
0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07,
0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07,
};
static const uint8_t ascii2ebcdic[] = {
0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,
0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
};
static inline void ebcdic_put(uint8_t *p, const char *ascii, int len)
{
int i;
for (i = 0; i < len; i++) {
p[i] = ascii2ebcdic[(uint8_t)ascii[i]];
}
}
static inline void ascii_put(uint8_t *p, const char *ebcdic, int len)
{
int i;
for (i = 0; i < len; i++) {
p[i] = ebcdic2ascii[(uint8_t)ebcdic[i]];
}
}
#endif /* EBCDIC_H */

View File

@ -0,0 +1,248 @@
/*
* S/390 channel I/O instructions
*
* Copyright 2012 IBM Corp.
* Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at
* your option) any later version. See the COPYING file in the top-level
* directory.
*/
#ifndef S390X_IOINST_H
#define S390X_IOINST_H
/*
* Channel I/O related definitions, as defined in the Principles
* Of Operation (and taken from the Linux implementation).
*/
/* subchannel status word (command mode only) */
typedef struct SCSW {
uint16_t flags;
uint16_t ctrl;
uint32_t cpa;
uint8_t dstat;
uint8_t cstat;
uint16_t count;
} 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
#define SCSW_FLAGS_MASK_ESWF 0x0400
#define SCSW_FLAGS_MASK_CC 0x0300
#define SCSW_FLAGS_MASK_FMT 0x0080
#define SCSW_FLAGS_MASK_PFCH 0x0040
#define SCSW_FLAGS_MASK_ISIC 0x0020
#define SCSW_FLAGS_MASK_ALCC 0x0010
#define SCSW_FLAGS_MASK_SSI 0x0008
#define SCSW_FLAGS_MASK_ZCC 0x0004
#define SCSW_FLAGS_MASK_ECTL 0x0002
#define SCSW_FLAGS_MASK_PNO 0x0001
#define SCSW_CTRL_MASK_FCTL 0x7000
#define SCSW_CTRL_MASK_ACTL 0x0fe0
#define SCSW_CTRL_MASK_STCTL 0x001f
#define SCSW_FCTL_CLEAR_FUNC 0x1000
#define SCSW_FCTL_HALT_FUNC 0x2000
#define SCSW_FCTL_START_FUNC 0x4000
#define SCSW_ACTL_SUSP 0x0020
#define SCSW_ACTL_DEVICE_ACTIVE 0x0040
#define SCSW_ACTL_SUBCH_ACTIVE 0x0080
#define SCSW_ACTL_CLEAR_PEND 0x0100
#define SCSW_ACTL_HALT_PEND 0x0200
#define SCSW_ACTL_START_PEND 0x0400
#define SCSW_ACTL_RESUME_PEND 0x0800
#define SCSW_STCTL_STATUS_PEND 0x0001
#define SCSW_STCTL_SECONDARY 0x0002
#define SCSW_STCTL_PRIMARY 0x0004
#define SCSW_STCTL_INTERMEDIATE 0x0008
#define SCSW_STCTL_ALERT 0x0010
#define SCSW_DSTAT_ATTENTION 0x80
#define SCSW_DSTAT_STAT_MOD 0x40
#define SCSW_DSTAT_CU_END 0x20
#define SCSW_DSTAT_BUSY 0x10
#define SCSW_DSTAT_CHANNEL_END 0x08
#define SCSW_DSTAT_DEVICE_END 0x04
#define SCSW_DSTAT_UNIT_CHECK 0x02
#define SCSW_DSTAT_UNIT_EXCEP 0x01
#define SCSW_CSTAT_PCI 0x80
#define SCSW_CSTAT_INCORR_LEN 0x40
#define SCSW_CSTAT_PROG_CHECK 0x20
#define SCSW_CSTAT_PROT_CHECK 0x10
#define SCSW_CSTAT_DATA_CHECK 0x08
#define SCSW_CSTAT_CHN_CTRL_CHK 0x04
#define SCSW_CSTAT_INTF_CTRL_CHK 0x02
#define SCSW_CSTAT_CHAIN_CHECK 0x01
/* path management control word */
typedef struct PMCW {
uint32_t intparm;
uint16_t flags;
uint16_t devno;
uint8_t lpm;
uint8_t pnom;
uint8_t lpum;
uint8_t pim;
uint16_t mbi;
uint8_t pom;
uint8_t pam;
uint8_t chpid[8];
uint32_t chars;
} 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
#define PMCW_FLAGS_MASK_ISC 0x3800
#define PMCW_FLAGS_MASK_ENA 0x0080
#define PMCW_FLAGS_MASK_LM 0x0060
#define PMCW_FLAGS_MASK_MME 0x0018
#define PMCW_FLAGS_MASK_MP 0x0004
#define PMCW_FLAGS_MASK_TF 0x0002
#define PMCW_FLAGS_MASK_DNV 0x0001
#define PMCW_FLAGS_MASK_INVALID 0x0700
#define PMCW_CHARS_MASK_ST 0x00e00000
#define PMCW_CHARS_MASK_MBFC 0x00000004
#define PMCW_CHARS_MASK_XMWME 0x00000002
#define PMCW_CHARS_MASK_CSENSE 0x00000001
#define PMCW_CHARS_MASK_INVALID 0xff1ffff8
/* subchannel information block */
typedef struct SCHIB {
PMCW pmcw;
SCSW scsw;
uint64_t mba;
uint8_t mda[4];
} QEMU_PACKED SCHIB;
/* interruption response block */
typedef struct IRB {
SCSW scsw;
uint32_t esw[5];
uint32_t ecw[8];
uint32_t emw[8];
} IRB;
QEMU_BUILD_BUG_MSG(sizeof(IRB) != 96, "size of IRB is wrong");
/* operation request block */
typedef struct ORB {
uint32_t intparm;
uint16_t ctrl0;
uint8_t lpm;
uint8_t ctrl1;
uint32_t cpa;
} 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
#define ORB_CTRL0_MASK_STR 0x0400
#define ORB_CTRL0_MASK_MOD 0x0200
#define ORB_CTRL0_MASK_SYNC 0x0100
#define ORB_CTRL0_MASK_FMT 0x0080
#define ORB_CTRL0_MASK_PFCH 0x0040
#define ORB_CTRL0_MASK_ISIC 0x0020
#define ORB_CTRL0_MASK_ALCC 0x0010
#define ORB_CTRL0_MASK_SSIC 0x0008
#define ORB_CTRL0_MASK_C64 0x0002
#define ORB_CTRL0_MASK_I2K 0x0001
#define ORB_CTRL0_MASK_INVALID 0x0004
#define ORB_CTRL1_MASK_ILS 0x80
#define ORB_CTRL1_MASK_MIDAW 0x40
#define ORB_CTRL1_MASK_ORBX 0x01
#define ORB_CTRL1_MASK_INVALID 0x3e
/* channel command word (type 0) */
typedef struct CCW0 {
uint8_t cmd_code;
uint8_t cda0;
uint16_t cda1;
uint8_t flags;
uint8_t reserved;
uint16_t count;
} CCW0;
QEMU_BUILD_BUG_MSG(sizeof(CCW0) != 8, "size of CCW0 is wrong");
/* channel command word (type 1) */
typedef struct CCW1 {
uint8_t cmd_code;
uint8_t flags;
uint16_t count;
uint32_t cda;
} CCW1;
QEMU_BUILD_BUG_MSG(sizeof(CCW1) != 8, "size of CCW1 is wrong");
#define CCW_FLAG_DC 0x80
#define CCW_FLAG_CC 0x40
#define CCW_FLAG_SLI 0x20
#define CCW_FLAG_SKIP 0x10
#define CCW_FLAG_PCI 0x08
#define CCW_FLAG_IDA 0x04
#define CCW_FLAG_SUSPEND 0x02
#define CCW_FLAG_MIDA 0x01
#define CCW_CMD_NOOP 0x03
#define CCW_CMD_BASIC_SENSE 0x04
#define CCW_CMD_TIC 0x08
#define CCW_CMD_SENSE_ID 0xe4
typedef struct CRW {
uint16_t flags;
uint16_t rsid;
} 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
#define CRW_FLAGS_MASK_C 0x1000
#define CRW_FLAGS_MASK_RSC 0x0f00
#define CRW_FLAGS_MASK_A 0x0080
#define CRW_FLAGS_MASK_ERC 0x003f
#define CRW_ERC_EVENT 0x00 /* event information pending */
#define CRW_ERC_AVAIL 0x01 /* available */
#define CRW_ERC_INIT 0x02 /* initialized */
#define CRW_ERC_TERROR 0x03 /* temporary error */
#define CRW_ERC_IPI 0x04 /* installed parm initialized */
#define CRW_ERC_TERM 0x05 /* terminal */
#define CRW_ERC_PERRN 0x06 /* perm. error, facility not init */
#define CRW_ERC_PERRI 0x07 /* perm. error, facility init */
#define CRW_ERC_PMOD 0x08 /* installed parameters modified */
#define CRW_ERC_IPR 0x0A /* installed parameters restored */
#define CRW_RSC_SUBCH 0x3
#define CRW_RSC_CHP 0x4
#define CRW_RSC_CSS 0xb
/* I/O interruption code */
typedef struct IOIntCode {
uint32_t subsys_id;
uint32_t intparm;
uint32_t interrupt_id;
} QEMU_PACKED IOIntCode;
/* schid disintegration */
#define IOINST_SCHID_ONE(_schid) ((_schid & 0x00010000) >> 16)
#define IOINST_SCHID_M(_schid) ((_schid & 0x00080000) >> 19)
#define IOINST_SCHID_CSSID(_schid) ((_schid & 0xff000000) >> 24)
#define IOINST_SCHID_SSID(_schid) ((_schid & 0x00060000) >> 17)
#define IOINST_SCHID_NR(_schid) (_schid & 0x0000ffff)
#define IO_INT_WORD_ISC(_int_word) ((_int_word & 0x38000000) >> 27)
#define ISC_TO_ISC_BITS(_isc) ((0x80 >> _isc) << 24)
#define IO_INT_WORD_AI 0x80000000
int ioinst_disassemble_sch_ident(uint32_t value, int *m, int *cssid, int *ssid,
int *schid);
#endif

View File

@ -0,0 +1,221 @@
/*
* SCLP Support
*
* Copyright IBM, Corp. 2012
*
* Authors:
* Christian Borntraeger <borntraeger@de.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at your
* option) any later version. See the COPYING file in the top-level directory.
*
*/
#ifndef HW_S390_SCLP_H
#define HW_S390_SCLP_H
//#include "hw/sysbus.h"
#include "target/s390x/cpu-qom.h"
#define SCLP_CMD_CODE_MASK 0xffff00ff
/* SCLP command codes */
#define SCLP_CMDW_READ_SCP_INFO 0x00020001
#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
#define SCLP_READ_STORAGE_ELEMENT_INFO 0x00040001
#define SCLP_ATTACH_STORAGE_ELEMENT 0x00080001
#define SCLP_ASSIGN_STORAGE 0x000D0001
#define SCLP_UNASSIGN_STORAGE 0x000C0001
#define SCLP_CMD_READ_EVENT_DATA 0x00770005
#define SCLP_CMD_WRITE_EVENT_DATA 0x00760005
#define SCLP_CMD_WRITE_EVENT_MASK 0x00780005
/* SCLP Memory hotplug codes */
#define SCLP_FC_ASSIGN_ATTACH_READ_STOR 0xE00000000000ULL
#define SCLP_STARTING_SUBINCREMENT_ID 0x10001
#define SCLP_INCREMENT_UNIT 0x10000
#define MAX_STORAGE_INCREMENTS 1020
/* CPU hotplug SCLP codes */
#define SCLP_HAS_CPU_INFO 0x0C00000000000000ULL
#define SCLP_CMDW_READ_CPU_INFO 0x00010001
#define SCLP_CMDW_CONFIGURE_CPU 0x00110001
#define SCLP_CMDW_DECONFIGURE_CPU 0x00100001
/* SCLP PCI codes */
#define SCLP_HAS_IOA_RECONFIG 0x0000000040000000ULL
#define SCLP_CMDW_CONFIGURE_IOA 0x001a0001
#define SCLP_CMDW_DECONFIGURE_IOA 0x001b0001
#define SCLP_RECONFIG_PCI_ATYPE 2
/* SCLP response codes */
#define SCLP_RC_NORMAL_READ_COMPLETION 0x0010
#define SCLP_RC_NORMAL_COMPLETION 0x0020
#define SCLP_RC_SCCB_BOUNDARY_VIOLATION 0x0100
#define SCLP_RC_NO_ACTION_REQUIRED 0x0120
#define SCLP_RC_INVALID_SCLP_COMMAND 0x01f0
#define SCLP_RC_CONTAINED_EQUIPMENT_CHECK 0x0340
#define SCLP_RC_INSUFFICIENT_SCCB_LENGTH 0x0300
#define SCLP_RC_STANDBY_READ_COMPLETION 0x0410
#define SCLP_RC_ADAPTER_IN_RESERVED_STATE 0x05f0
#define SCLP_RC_ADAPTER_TYPE_NOT_RECOGNIZED 0x06f0
#define SCLP_RC_ADAPTER_ID_NOT_RECOGNIZED 0x09f0
#define SCLP_RC_INVALID_FUNCTION 0x40f0
#define SCLP_RC_NO_EVENT_BUFFERS_STORED 0x60f0
#define SCLP_RC_INVALID_SELECTION_MASK 0x70f0
#define SCLP_RC_INCONSISTENT_LENGTHS 0x72f0
#define SCLP_RC_EVENT_BUFFER_SYNTAX_ERROR 0x73f0
#define SCLP_RC_INVALID_MASK_LENGTH 0x74f0
/* Service Call Control Block (SCCB) and its elements */
#define SCCB_SIZE 4096
#define SCLP_VARIABLE_LENGTH_RESPONSE 0x80
#define SCLP_EVENT_BUFFER_ACCEPTED 0x80
#define SCLP_FC_NORMAL_WRITE 0
/*
* Normally packed structures are not the right thing to do, since all code
* must take care of endianness. We cannot use ldl_phys and friends for two
* reasons, though:
* - some of the embedded structures below the SCCB can appear multiple times
* at different locations, so there is no fixed offset
* - we work on a private copy of the SCCB, since there are several length
* fields, that would cause a security nightmare if we allow the guest to
* alter the structure while we parse it. We cannot use ldl_p and friends
* either without doing pointer arithmetics
* So we have to double check that all users of sclp data structures use the
* right endianness wrappers.
*/
typedef struct SCCBHeader {
uint16_t length;
uint8_t function_code;
uint8_t control_mask[3];
uint16_t response_code;
} QEMU_PACKED SCCBHeader;
#define SCCB_DATA_LEN (SCCB_SIZE - sizeof(SCCBHeader))
#define SCCB_CPU_FEATURE_LEN 6
/* CPU information */
typedef struct CPUEntry {
uint8_t address;
uint8_t reserved0;
uint8_t features[SCCB_CPU_FEATURE_LEN];
uint8_t reserved2[6];
uint8_t type;
uint8_t reserved1;
} QEMU_PACKED CPUEntry;
typedef struct ReadInfo {
SCCBHeader h;
uint16_t rnmax;
uint8_t rnsize;
uint8_t _reserved1[16 - 11]; /* 11-15 */
uint16_t entries_cpu; /* 16-17 */
uint16_t offset_cpu; /* 18-19 */
uint8_t _reserved2[24 - 20]; /* 20-23 */
uint8_t loadparm[8]; /* 24-31 */
uint8_t _reserved3[48 - 32]; /* 32-47 */
uint64_t facilities; /* 48-55 */
uint8_t _reserved0[76 - 56]; /* 56-75 */
uint32_t ibc_val;
uint8_t conf_char[99 - 80]; /* 80-98 */
uint8_t mha_pow;
uint32_t rnsize2;
uint64_t rnmax2;
uint8_t _reserved6[116 - 112]; /* 112-115 */
uint8_t conf_char_ext[120 - 116]; /* 116-119 */
uint16_t highest_cpu;
uint8_t _reserved5[124 - 122]; /* 122-123 */
uint32_t hmfai;
struct CPUEntry entries[];
} QEMU_PACKED ReadInfo;
typedef struct ReadCpuInfo {
SCCBHeader h;
uint16_t nr_configured; /* 8-9 */
uint16_t offset_configured; /* 10-11 */
uint16_t nr_standby; /* 12-13 */
uint16_t offset_standby; /* 14-15 */
uint8_t reserved0[24-16]; /* 16-23 */
struct CPUEntry entries[];
} QEMU_PACKED ReadCpuInfo;
typedef struct ReadStorageElementInfo {
SCCBHeader h;
uint16_t max_id;
uint16_t assigned;
uint16_t standby;
uint8_t _reserved0[16 - 14]; /* 14-15 */
uint32_t entries[];
} QEMU_PACKED ReadStorageElementInfo;
typedef struct AttachStorageElement {
SCCBHeader h;
uint8_t _reserved0[10 - 8]; /* 8-9 */
uint16_t assigned;
uint8_t _reserved1[16 - 12]; /* 12-15 */
uint32_t entries[];
} QEMU_PACKED AttachStorageElement;
typedef struct AssignStorage {
SCCBHeader h;
uint16_t rn;
} QEMU_PACKED AssignStorage;
typedef struct IoaCfgSccb {
SCCBHeader header;
uint8_t atype;
uint8_t reserved1;
uint16_t reserved2;
uint32_t aid;
} QEMU_PACKED IoaCfgSccb;
typedef struct SCCB {
SCCBHeader h;
char data[SCCB_DATA_LEN];
} QEMU_PACKED SCCB;
#define TYPE_SCLP "sclp"
#define SCLP(obj) OBJECT_CHECK(SCLPDevice, (obj), TYPE_SCLP)
#define SCLP_CLASS(oc) OBJECT_CLASS_CHECK(SCLPDeviceClass, (oc), TYPE_SCLP)
#define SCLP_GET_CLASS(obj) OBJECT_GET_CLASS(SCLPDeviceClass, (obj), TYPE_SCLP)
typedef struct SCLPEventFacility SCLPEventFacility;
typedef struct SCLPDevice {
/* private */
CPUState parent_obj;
SCLPEventFacility *event_facility;
int increment_size;
/* public */
} SCLPDevice;
typedef struct SCLPDeviceClass {
/* private */
DeviceClass parent_class;
void (*read_SCP_info)(SCLPDevice *sclp, SCCB *sccb);
void (*read_cpu_info)(SCLPDevice *sclp, SCCB *sccb);
/* public */
void (*execute)(SCLPDevice *sclp, SCCB *sccb, uint32_t code);
void (*service_interrupt)(SCLPDevice *sclp, uint32_t sccb);
} SCLPDeviceClass;
static inline int sccb_data_len(SCCB *sccb)
{
return be16_to_cpu(sccb->h.length) - sizeof(sccb->h);
}
void s390_sclp_init(void);
void sclp_service_interrupt(uint32_t sccb);
void raise_irq_cpu_hotplug(void);
int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code);
#endif

View File

@ -0,0 +1,66 @@
/*
* s390 storage key device
*
* Copyright 2015 IBM Corp.
* Author(s): Jason J. Herne <jjherne@linux.vnet.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at
* your option) any later version. See the COPYING file in the top-level
* directory.
*/
#ifndef S390_STORAGE_KEYS_H
#define S390_STORAGE_KEYS_H
/*
#define TYPE_S390_SKEYS "s390-skeys"
#define S390_SKEYS(obj) \
OBJECT_CHECK(S390SKeysState, (obj), TYPE_S390_SKEYS)
#define S390_CPU(obj) \
OBJECT_CHECK(S390CPU, (obj), TYPE_S390_CPU)
#define S390_CPU(obj) ((S390CPU *)obj)
*/
typedef struct S390SKeysState {
CPUState parent_obj;
} S390SKeysState;
/*
#define S390_SKEYS_CLASS(klass) \
OBJECT_CLASS_CHECK(S390SKeysClass, (klass), TYPE_S390_SKEYS)
*/
#define S390_SKEYS_CLASS(klass) ((S390SKeysClass *)klass)
/*
#define S390_SKEYS_GET_CLASS(obj) \
OBJECT_GET_CLASS(S390SKeysClass, (obj), TYPE_S390_SKEYS)
*/
#define S390_SKEYS_GET_CLASS(obj) (&((S390CPU *)obj)->skey)
typedef struct S390SKeysClass {
CPUClass parent_class;
int (*skeys_enabled)(S390SKeysState *ks);
int (*get_skeys)(S390SKeysState *ks, uint64_t start_gfn, uint64_t count,
uint8_t *keys);
int (*set_skeys)(S390SKeysState *ks, uint64_t start_gfn, uint64_t count,
uint8_t *keys);
} S390SKeysClass;
#define TYPE_KVM_S390_SKEYS "s390-skeys-kvm"
#define TYPE_QEMU_S390_SKEYS "s390-skeys-qemu"
#define QEMU_S390_SKEYS(obj) \
OBJECT_CHECK(QEMUS390SKeysState, (obj), TYPE_QEMU_S390_SKEYS)
typedef struct QEMUS390SKeysState {
S390SKeysState parent_obj;
uint8_t *keydata;
uint32_t key_count;
} QEMUS390SKeysState;
void s390_skeys_init(void);
S390SKeysState *s390_get_skeys_device(void);
#endif /* S390_STORAGE_KEYS_H */

1277
qemu/s390x.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,595 @@
/*
* S/390 condition code helper routines
*
* Copyright (c) 2009 Ulrich Hecht
* Copyright (c) 2009 Alexander Graf
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
#include "tcg_s390x.h"
#include "exec/exec-all.h"
#include "exec/helper-proto.h"
#include "qemu/host-utils.h"
/* #define DEBUG_HELPER */
#ifdef DEBUG_HELPER
#define HELPER_LOG(x...) qemu_log(x)
#else
#define HELPER_LOG(x...)
#endif
static uint32_t cc_calc_ltgt_32(int32_t src, int32_t dst)
{
if (src == dst) {
return 0;
} else if (src < dst) {
return 1;
} else {
return 2;
}
}
static uint32_t cc_calc_ltgt0_32(int32_t dst)
{
return cc_calc_ltgt_32(dst, 0);
}
static uint32_t cc_calc_ltgt_64(int64_t src, int64_t dst)
{
if (src == dst) {
return 0;
} else if (src < dst) {
return 1;
} else {
return 2;
}
}
static uint32_t cc_calc_ltgt0_64(int64_t dst)
{
return cc_calc_ltgt_64(dst, 0);
}
static uint32_t cc_calc_ltugtu_32(uint32_t src, uint32_t dst)
{
if (src == dst) {
return 0;
} else if (src < dst) {
return 1;
} else {
return 2;
}
}
static uint32_t cc_calc_ltugtu_64(uint64_t src, uint64_t dst)
{
if (src == dst) {
return 0;
} else if (src < dst) {
return 1;
} else {
return 2;
}
}
static uint32_t cc_calc_tm_32(uint32_t val, uint32_t mask)
{
uint32_t r = val & mask;
if (r == 0) {
return 0;
} else if (r == mask) {
return 3;
} else {
return 1;
}
}
static uint32_t cc_calc_tm_64(uint64_t val, uint64_t mask)
{
uint64_t r = val & mask;
if (r == 0) {
return 0;
} else if (r == mask) {
return 3;
} else {
int top = clz64(mask);
if ((int64_t)(val << top) < 0) {
return 2;
} else {
return 1;
}
}
}
static uint32_t cc_calc_nz(uint64_t dst)
{
return !!dst;
}
static uint32_t cc_calc_add_64(int64_t a1, int64_t a2, int64_t ar)
{
if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
return 3; /* overflow */
} else {
if (ar < 0) {
return 1;
} else if (ar > 0) {
return 2;
} else {
return 0;
}
}
}
static uint32_t cc_calc_addu_64(uint64_t a1, uint64_t a2, uint64_t ar)
{
return (ar != 0) + 2 * (ar < a1);
}
static uint32_t cc_calc_addc_64(uint64_t a1, uint64_t a2, uint64_t ar)
{
/* Recover a2 + carry_in. */
uint64_t a2c = ar - a1;
/* Check for a2+carry_in overflow, then a1+a2c overflow. */
int carry_out = (a2c < a2) || (ar < a1);
return (ar != 0) + 2 * carry_out;
}
static uint32_t cc_calc_sub_64(int64_t a1, int64_t a2, int64_t ar)
{
if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
return 3; /* overflow */
} else {
if (ar < 0) {
return 1;
} else if (ar > 0) {
return 2;
} else {
return 0;
}
}
}
static uint32_t cc_calc_subu_64(uint64_t a1, uint64_t a2, uint64_t ar)
{
if (ar == 0) {
return 2;
} else {
if (a2 > a1) {
return 1;
} else {
return 3;
}
}
}
static uint32_t cc_calc_subb_64(uint64_t a1, uint64_t a2, uint64_t ar)
{
int borrow_out;
if (ar != a1 - a2) { /* difference means borrow-in */
borrow_out = (a2 >= a1);
} else {
borrow_out = (a2 > a1);
}
return (ar != 0) + 2 * !borrow_out;
}
static uint32_t cc_calc_abs_64(int64_t dst)
{
if ((uint64_t)dst == 0x8000000000000000ULL) {
return 3;
} else if (dst) {
return 2;
} else {
return 0;
}
}
static uint32_t cc_calc_nabs_64(int64_t dst)
{
return !!dst;
}
static uint32_t cc_calc_comp_64(int64_t dst)
{
if ((uint64_t)dst == 0x8000000000000000ULL) {
return 3;
} else if (dst < 0) {
return 1;
} else if (dst > 0) {
return 2;
} else {
return 0;
}
}
static uint32_t cc_calc_add_32(int32_t a1, int32_t a2, int32_t ar)
{
if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
return 3; /* overflow */
} else {
if (ar < 0) {
return 1;
} else if (ar > 0) {
return 2;
} else {
return 0;
}
}
}
static uint32_t cc_calc_addu_32(uint32_t a1, uint32_t a2, uint32_t ar)
{
return (ar != 0) + 2 * (ar < a1);
}
static uint32_t cc_calc_addc_32(uint32_t a1, uint32_t a2, uint32_t ar)
{
/* Recover a2 + carry_in. */
uint32_t a2c = ar - a1;
/* Check for a2+carry_in overflow, then a1+a2c overflow. */
int carry_out = (a2c < a2) || (ar < a1);
return (ar != 0) + 2 * carry_out;
}
static uint32_t cc_calc_sub_32(int32_t a1, int32_t a2, int32_t ar)
{
if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
return 3; /* overflow */
} else {
if (ar < 0) {
return 1;
} else if (ar > 0) {
return 2;
} else {
return 0;
}
}
}
static uint32_t cc_calc_subu_32(uint32_t a1, uint32_t a2, uint32_t ar)
{
if (ar == 0) {
return 2;
} else {
if (a2 > a1) {
return 1;
} else {
return 3;
}
}
}
static uint32_t cc_calc_subb_32(uint32_t a1, uint32_t a2, uint32_t ar)
{
int borrow_out;
if (ar != a1 - a2) { /* difference means borrow-in */
borrow_out = (a2 >= a1);
} else {
borrow_out = (a2 > a1);
}
return (ar != 0) + 2 * !borrow_out;
}
static uint32_t cc_calc_abs_32(int32_t dst)
{
if ((uint32_t)dst == 0x80000000UL) {
return 3;
} else if (dst) {
return 2;
} else {
return 0;
}
}
static uint32_t cc_calc_nabs_32(int32_t dst)
{
return !!dst;
}
static uint32_t cc_calc_comp_32(int32_t dst)
{
if ((uint32_t)dst == 0x80000000UL) {
return 3;
} else if (dst < 0) {
return 1;
} else if (dst > 0) {
return 2;
} else {
return 0;
}
}
/* calculate condition code for insert character under mask insn */
static uint32_t cc_calc_icm(uint64_t mask, uint64_t val)
{
if ((val & mask) == 0) {
return 0;
} else {
int top = clz64(mask);
if ((int64_t)(val << top) < 0) {
return 1;
} else {
return 2;
}
}
}
static uint32_t cc_calc_sla_32(uint32_t src, int shift)
{
uint32_t mask = ((1U << shift) - 1U) << (32 - shift);
uint32_t sign = 1U << 31;
uint32_t match;
int32_t r;
/* Check if the sign bit stays the same. */
if (src & sign) {
match = mask;
} else {
match = 0;
}
if ((src & mask) != match) {
/* Overflow. */
return 3;
}
r = ((src << shift) & ~sign) | (src & sign);
if (r == 0) {
return 0;
} else if (r < 0) {
return 1;
}
return 2;
}
static uint32_t cc_calc_sla_64(uint64_t src, int shift)
{
uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift);
uint64_t sign = 1ULL << 63;
uint64_t match;
int64_t r;
/* Check if the sign bit stays the same. */
if (src & sign) {
match = mask;
} else {
match = 0;
}
if ((src & mask) != match) {
/* Overflow. */
return 3;
}
r = ((src << shift) & ~sign) | (src & sign);
if (r == 0) {
return 0;
} else if (r < 0) {
return 1;
}
return 2;
}
static uint32_t cc_calc_flogr(uint64_t dst)
{
return dst ? 2 : 0;
}
static uint32_t cc_calc_lcbb(uint64_t dst)
{
return dst == 16 ? 0 : 3;
}
static uint32_t cc_calc_vc(uint64_t low, uint64_t high)
{
if (high == -1ull && low == -1ull) {
/* all elements match */
return 0;
} else if (high == 0 && low == 0) {
/* no elements match */
return 3;
} else {
/* some elements but not all match */
return 1;
}
}
static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op,
uint64_t src, uint64_t dst, uint64_t vr)
{
uint32_t r = 0;
switch (cc_op) {
case CC_OP_CONST0:
case CC_OP_CONST1:
case CC_OP_CONST2:
case CC_OP_CONST3:
/* cc_op value _is_ cc */
r = cc_op;
break;
case CC_OP_LTGT0_32:
r = cc_calc_ltgt0_32(dst);
break;
case CC_OP_LTGT0_64:
r = cc_calc_ltgt0_64(dst);
break;
case CC_OP_LTGT_32:
r = cc_calc_ltgt_32(src, dst);
break;
case CC_OP_LTGT_64:
r = cc_calc_ltgt_64(src, dst);
break;
case CC_OP_LTUGTU_32:
r = cc_calc_ltugtu_32(src, dst);
break;
case CC_OP_LTUGTU_64:
r = cc_calc_ltugtu_64(src, dst);
break;
case CC_OP_TM_32:
r = cc_calc_tm_32(src, dst);
break;
case CC_OP_TM_64:
r = cc_calc_tm_64(src, dst);
break;
case CC_OP_NZ:
r = cc_calc_nz(dst);
break;
case CC_OP_ADD_64:
r = cc_calc_add_64(src, dst, vr);
break;
case CC_OP_ADDU_64:
r = cc_calc_addu_64(src, dst, vr);
break;
case CC_OP_ADDC_64:
r = cc_calc_addc_64(src, dst, vr);
break;
case CC_OP_SUB_64:
r = cc_calc_sub_64(src, dst, vr);
break;
case CC_OP_SUBU_64:
r = cc_calc_subu_64(src, dst, vr);
break;
case CC_OP_SUBB_64:
r = cc_calc_subb_64(src, dst, vr);
break;
case CC_OP_ABS_64:
r = cc_calc_abs_64(dst);
break;
case CC_OP_NABS_64:
r = cc_calc_nabs_64(dst);
break;
case CC_OP_COMP_64:
r = cc_calc_comp_64(dst);
break;
case CC_OP_ADD_32:
r = cc_calc_add_32(src, dst, vr);
break;
case CC_OP_ADDU_32:
r = cc_calc_addu_32(src, dst, vr);
break;
case CC_OP_ADDC_32:
r = cc_calc_addc_32(src, dst, vr);
break;
case CC_OP_SUB_32:
r = cc_calc_sub_32(src, dst, vr);
break;
case CC_OP_SUBU_32:
r = cc_calc_subu_32(src, dst, vr);
break;
case CC_OP_SUBB_32:
r = cc_calc_subb_32(src, dst, vr);
break;
case CC_OP_ABS_32:
r = cc_calc_abs_32(dst);
break;
case CC_OP_NABS_32:
r = cc_calc_nabs_32(dst);
break;
case CC_OP_COMP_32:
r = cc_calc_comp_32(dst);
break;
case CC_OP_ICM:
r = cc_calc_icm(src, dst);
break;
case CC_OP_SLA_32:
r = cc_calc_sla_32(src, dst);
break;
case CC_OP_SLA_64:
r = cc_calc_sla_64(src, dst);
break;
case CC_OP_FLOGR:
r = cc_calc_flogr(dst);
break;
case CC_OP_LCBB:
r = cc_calc_lcbb(dst);
break;
case CC_OP_VC:
r = cc_calc_vc(src, dst);
break;
case CC_OP_NZ_F32:
r = set_cc_nz_f32(dst);
break;
case CC_OP_NZ_F64:
r = set_cc_nz_f64(dst);
break;
case CC_OP_NZ_F128:
r = set_cc_nz_f128(make_float128(src, dst));
break;
default:
cpu_abort(env_cpu(env), "Unknown CC operation: %s\n", cc_name(cc_op));
}
HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __func__,
cc_name(cc_op), src, dst, vr, r);
return r;
}
uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
uint64_t vr)
{
return do_calc_cc(env, cc_op, src, dst, vr);
}
uint32_t HELPER(calc_cc)(CPUS390XState *env, uint32_t cc_op, uint64_t src,
uint64_t dst, uint64_t vr)
{
return do_calc_cc(env, cc_op, src, dst, vr);
}
#ifndef CONFIG_USER_ONLY
void HELPER(load_psw)(CPUS390XState *env, uint64_t mask, uint64_t addr)
{
load_psw(env, mask, addr);
cpu_loop_exit(env_cpu(env));
}
void HELPER(sacf)(CPUS390XState *env, uint64_t a1)
{
HELPER_LOG("%s: %16" PRIx64 "\n", __func__, a1);
switch (a1 & 0xf00) {
case 0x000:
env->psw.mask &= ~PSW_MASK_ASC;
env->psw.mask |= PSW_ASC_PRIMARY;
break;
case 0x100:
env->psw.mask &= ~PSW_MASK_ASC;
env->psw.mask |= PSW_ASC_SECONDARY;
break;
case 0x300:
env->psw.mask &= ~PSW_MASK_ASC;
env->psw.mask |= PSW_ASC_HOME;
break;
default:
HELPER_LOG("unknown sacf mode: %" PRIx64 "\n", a1);
tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
}
}
#endif

View File

@ -0,0 +1,17 @@
/*
* S/390 cpu parameters for qemu.
*
* Copyright (c) 2009 Ulrich Hecht
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef S390_CPU_PARAM_H
#define S390_CPU_PARAM_H 1
#define TARGET_LONG_BITS 64
#define TARGET_PAGE_BITS 12
#define TARGET_PHYS_ADDR_SPACE_BITS 64
#define TARGET_VIRT_ADDR_SPACE_BITS 64
#define NB_MMU_MODES 4
#endif

View File

@ -0,0 +1,64 @@
/*
* QEMU S/390 CPU
*
* Copyright (c) 2012 SUSE LINUX Products GmbH
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see
* <http://www.gnu.org/licenses/lgpl-2.1.html>
*/
#ifndef QEMU_S390_CPU_QOM_H
#define QEMU_S390_CPU_QOM_H
#include "hw/core/cpu.h"
#define S390_CPU(obj) ((S390CPU *)obj)
#define S390_CPU_CLASS(klass) ((S390CPUClass *)klass)
#define S390_CPU_GET_CLASS(obj) (&((S390CPU *)obj)->cc)
typedef struct S390CPUModel S390CPUModel;
typedef struct S390CPUDef S390CPUDef;
typedef enum cpu_reset_type {
S390_CPU_RESET_NORMAL,
S390_CPU_RESET_INITIAL,
S390_CPU_RESET_CLEAR,
} cpu_reset_type;
/**
* S390CPUClass:
* @parent_realize: The parent class' realize handler.
* @parent_reset: The parent class' reset handler.
* @load_normal: Performs a load normal.
* @cpu_reset: Performs a CPU reset.
* @initial_cpu_reset: Performs an initial CPU reset.
*
* An S/390 CPU model.
*/
typedef struct S390CPUClass {
/*< private >*/
CPUClass parent_class;
/*< public >*/
const S390CPUDef *cpu_def;
bool is_static;
// const char *desc; qq
void (*load_normal)(CPUState *cpu);
void (*reset)(CPUState *cpu, cpu_reset_type type);
void (*parent_reset)(CPUState *cpu);
} S390CPUClass;
typedef struct S390CPU S390CPU;
typedef struct CPUS390XState CPUS390XState;
#endif

301
qemu/target/s390x/cpu.c Normal file
View File

@ -0,0 +1,301 @@
/*
* QEMU S/390 CPU
*
* Copyright (c) 2009 Ulrich Hecht
* Copyright (c) 2011 Alexander Graf
* Copyright (c) 2012 SUSE LINUX Products GmbH
* Copyright (c) 2012 IBM Corp.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
#include "sysemu/tcg.h"
#include "fpu/softfloat-helpers.h"
#define CR0_RESET 0xE0UL
#define CR14_RESET 0xC2000000UL;
static void s390_cpu_set_pc(CPUState *cs, vaddr value)
{
S390CPU *cpu = S390_CPU(cs);
cpu->env.psw.addr = value;
}
static bool s390_cpu_has_work(CPUState *cs)
{
S390CPU *cpu = S390_CPU(cs);
#if 0
/* STOPPED cpus can never wake up */
if (s390_cpu_get_state(cpu) != S390_CPU_STATE_LOAD &&
s390_cpu_get_state(cpu) != S390_CPU_STATE_OPERATING) {
return false;
}
#endif
if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) {
return false;
}
return s390_cpu_has_int(cpu);
}
/* S390CPUClass::reset() */
static void s390_cpu_reset(CPUState *dev, cpu_reset_type type)
{
CPUState *s = CPU(dev);
S390CPU *cpu = S390_CPU(s);
S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
CPUS390XState *env = &cpu->env;
scc->parent_reset(dev);
cpu->env.sigp_order = 0;
s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu);
switch (type) {
case S390_CPU_RESET_CLEAR:
memset(env, 0, offsetof(CPUS390XState, start_initial_reset_fields));
/* fall through */
case S390_CPU_RESET_INITIAL:
/* initial reset does not clear everything! */
memset(&env->start_initial_reset_fields, 0,
offsetof(CPUS390XState, start_normal_reset_fields) -
offsetof(CPUS390XState, start_initial_reset_fields));
/* architectured initial value for Breaking-Event-Address register */
env->gbea = 1;
/* architectured initial values for CR 0 and 14 */
env->cregs[0] = CR0_RESET;
env->cregs[14] = CR14_RESET;
/* tininess for underflow is detected before rounding */
set_float_detect_tininess(float_tininess_before_rounding,
&env->fpu_status);
/* fall through */
case S390_CPU_RESET_NORMAL:
env->psw.mask &= ~PSW_MASK_RI;
memset(&env->start_normal_reset_fields, 0,
offsetof(CPUS390XState, end_reset_fields) -
offsetof(CPUS390XState, start_normal_reset_fields));
env->pfault_token = -1UL;
env->bpbc = false;
break;
default:
g_assert_not_reached();
}
}
static void s390_cpu_realizefn(struct uc_struct *uc, CPUState *dev)
{
CPUState *cs = CPU(dev);
S390CPU *cpu = S390_CPU(dev);
/* the model has to be realized before qemu_init_vcpu() due to kvm */
// s390_realize_cpu_model(cs);
/* sync cs->cpu_index and env->core_id. The latter is needed for TCG. */
cs->cpu_index = cpu->env.core_id;
cpu_exec_realizefn(cs);
qemu_init_vcpu(cs);
cpu_reset(cs);
}
static void s390_cpu_initfn(struct uc_struct *uc, CPUState *obj)
{
CPUState *cs = CPU(obj);
S390CPU *cpu = S390_CPU(obj);
cpu_set_cpustate_pointers(cpu);
cs->halted = 1;
cs->exception_index = EXCP_HLT;
// s390_cpu_model_register_props(obj);
// cpu->env.tod_timer =
// timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_tod_timer, cpu);
// cpu->env.cpu_timer =
// timer_new_ns(QEMU_CLOCK_VIRTUAL, s390x_cpu_timer, cpu);
s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu);
}
static unsigned s390_count_running_cpus(void)
{
return 1;
}
unsigned int s390_cpu_halt(S390CPU *cpu)
{
CPUState *cs = CPU(cpu);
if (!cs->halted) {
cs->halted = 1;
cs->exception_index = EXCP_HLT;
}
return s390_count_running_cpus();
}
void s390_cpu_unhalt(S390CPU *cpu)
{
CPUState *cs = CPU(cpu);
if (cs->halted) {
cs->halted = 0;
cs->exception_index = -1;
}
}
unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu)
{
switch (cpu_state) {
case S390_CPU_STATE_STOPPED:
case S390_CPU_STATE_CHECK_STOP:
/* halt the cpu for common infrastructure */
s390_cpu_halt(cpu);
break;
case S390_CPU_STATE_OPERATING:
case S390_CPU_STATE_LOAD:
/*
* Starting a CPU with a PSW WAIT bit set:
* KVM: handles this internally and triggers another WAIT exit.
* TCG: will actually try to continue to run. Don't unhalt, will
* be done when the CPU actually has work (an interrupt).
*/
if (!(cpu->env.psw.mask & PSW_MASK_WAIT)) {
s390_cpu_unhalt(cpu);
}
break;
default:
//error_report("Requested CPU state is not a valid S390 CPU state: %u",
// cpu_state);
exit(1);
}
cpu->env.cpu_state = cpu_state;
return s390_count_running_cpus();
}
int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit)
{
return 0;
}
void s390_set_max_pagesize(uint64_t pagesize)
{
}
void s390_cmma_reset(void)
{
}
void s390_crypto_reset(void)
{
}
void s390_enable_css_support(S390CPU *cpu)
{
}
#if 0
static void s390_cpu_reset_full(CPUState *dev)
{
return s390_cpu_reset(dev, S390_CPU_RESET_CLEAR);
}
#endif
static void s390_cpu_class_init(struct uc_struct *uc, CPUClass *oc)
{
S390CPUClass *scc = S390_CPU_CLASS(oc);
CPUClass *cc = CPU_CLASS(scc);
scc->reset = s390_cpu_reset;
cc->has_work = s390_cpu_has_work;
// cc->do_interrupt = s390_cpu_do_interrupt;
cc->set_pc = s390_cpu_set_pc;
cc->get_phys_page_debug = s390_cpu_get_phys_page_debug;
cc->cpu_exec_interrupt = s390_cpu_exec_interrupt;
cc->debug_excp_handler = s390x_cpu_debug_excp_handler;
cc->do_unaligned_access = s390x_cpu_do_unaligned_access;
cc->tcg_initialize = s390x_translate_init;
cc->tlb_fill = s390_cpu_tlb_fill;
// s390_cpu_model_class_register_props(oc);
}
S390CPU *cpu_s390_init(struct uc_struct *uc, const char *cpu_model)
{
S390CPU *cpu;
CPUState *cs;
CPUClass *cc;
// int i;
cpu = calloc(1, sizeof(*cpu));
if (cpu == NULL) {
return NULL;
}
cs = (CPUState *)cpu;
cc = (CPUClass *)&cpu->cc;
cs->cc = cc;
cs->uc = uc;
uc->cpu = (CPUState *)cpu;
/* init CPUClass */
cpu_class_init(uc, cc);
/* init CPUClass */
s390_cpu_class_init(uc, cc);
/* init CPUState */
cpu_common_initfn(uc, cs);
/* init CPU */
s390_cpu_initfn(uc, cs);
/* init specific CPU model */
/*
for (i = 0; i < ARRAY_SIZE(cpu_models); i++) {
if (strcmp(cpu_model, cpu_models[i].name) == 0) {
cpu_models[i].initfn(cs);
if (arm_cpus[i].class_init) {
arm_cpus[i].class_init(uc, cc, uc);
}
if (arm_cpus[i].initfn) {
arm_cpus[i].initfn(uc, cs);
}
break;
}
}
*/
/* realize CPU */
s390_cpu_realizefn(uc, cs);
// init addresss space
cpu_address_space_init(cs, 0, cs->memory);
qemu_init_vcpu(cs);
return cpu;
}

840
qemu/target/s390x/cpu.h Normal file
View File

@ -0,0 +1,840 @@
/*
* S/390 virtual CPU header
*
* For details on the s390x architecture and used definitions (e.g.,
* PSW, PER and DAT (Dynamic Address Translation)), please refer to
* the "z/Architecture Principles of Operations" - a.k.a. PoP.
*
* Copyright (c) 2009 Ulrich Hecht
* Copyright IBM Corp. 2012, 2018
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef S390X_CPU_H
#define S390X_CPU_H
#include "cpu-qom.h"
#include "cpu_models.h"
#include "exec/cpu-defs.h"
#include "hw/s390x/storage-keys.h"
#define ELF_MACHINE_UNAME "S390X"
/* The z/Architecture has a strong memory model with some store-after-load re-ordering */
#define TCG_GUEST_DEFAULT_MO (TCG_MO_ALL & ~TCG_MO_ST_LD)
#define TARGET_INSN_START_EXTRA_WORDS 2
#define MMU_USER_IDX 0
#define S390_MAX_CPUS 248
typedef struct PSW {
uint64_t mask;
uint64_t addr;
} PSW;
struct CPUS390XState {
uint64_t regs[16]; /* GP registers */
/*
* The floating point registers are part of the vector registers.
* vregs[0][0] -> vregs[15][0] are 16 floating point registers
*/
uint64_t vregs[32][2] QEMU_ALIGNED(16); /* vector registers */
uint32_t aregs[16]; /* access registers */
uint64_t gscb[4]; /* guarded storage control */
uint64_t etoken; /* etoken */
uint64_t etoken_extension; /* etoken extension */
/* Fields up to this point are not cleared by initial CPU reset */
int start_initial_reset_fields;
uint32_t fpc; /* floating-point control register */
uint32_t cc_op;
bool bpbc; /* branch prediction blocking */
float_status fpu_status; /* passed to softfloat lib */
/* The low part of a 128-bit return, or remainder of a divide. */
uint64_t retxl;
PSW psw;
// S390CrashReason crash_reason;
uint64_t cc_src;
uint64_t cc_dst;
uint64_t cc_vr;
uint64_t ex_value;
uint64_t __excp_addr;
uint64_t psa;
uint32_t int_pgm_code;
uint32_t int_pgm_ilen;
uint32_t int_svc_code;
uint32_t int_svc_ilen;
uint64_t per_address;
uint16_t per_perc_atmid;
uint64_t cregs[16]; /* control registers */
uint64_t ckc;
uint64_t cputm;
uint32_t todpr;
uint64_t pfault_token;
uint64_t pfault_compare;
uint64_t pfault_select;
uint64_t gbea;
uint64_t pp;
/* Fields up to this point are not cleared by normal CPU reset */
int start_normal_reset_fields;
uint8_t riccb[64]; /* runtime instrumentation control */
int pending_int;
uint16_t external_call_addr;
DECLARE_BITMAP(emergency_signals, S390_MAX_CPUS);
/* Fields up to this point are cleared by a CPU reset */
int end_reset_fields;
uint32_t core_id; /* PoP "CPU address", same as cpu_index */
uint64_t cpuid;
// QEMUTimer *tod_timer;
// QEMUTimer *cpu_timer;
/*
* The cpu state represents the logical state of a cpu. In contrast to other
* architectures, there is a difference between a halt and a stop on s390.
* If all cpus are either stopped (including check stop) or in the disabled
* wait state, the vm can be shut down.
* The acceptable cpu_state values are defined in the CpuInfoS390State
* enum.
*/
uint8_t cpu_state;
/* currently processed sigp order */
uint8_t sigp_order;
// Unicorn engine
struct uc_struct *uc;
};
static inline uint64_t *get_freg(CPUS390XState *cs, int nr)
{
return &cs->vregs[nr][0];
}
/**
* S390CPU:
* @env: #CPUS390XState.
*
* An S/390 CPU.
*/
struct S390CPU {
/*< private >*/
CPUState parent_obj;
/*< public >*/
CPUNegativeOffsetState neg;
CPUS390XState env;
S390CPUModel *model;
/* needed for live migration */
void *irqstate;
uint32_t irqstate_saved_size;
// unicorn
struct S390CPUClass cc;
struct S390SKeysClass skey;
};
/* distinguish between 24 bit and 31 bit addressing */
#define HIGH_ORDER_BIT 0x80000000
/* Interrupt Codes */
/* Program Interrupts */
#define PGM_OPERATION 0x0001
#define PGM_PRIVILEGED 0x0002
#define PGM_EXECUTE 0x0003
#define PGM_PROTECTION 0x0004
#define PGM_ADDRESSING 0x0005
#define PGM_SPECIFICATION 0x0006
#define PGM_DATA 0x0007
#define PGM_FIXPT_OVERFLOW 0x0008
#define PGM_FIXPT_DIVIDE 0x0009
#define PGM_DEC_OVERFLOW 0x000a
#define PGM_DEC_DIVIDE 0x000b
#define PGM_HFP_EXP_OVERFLOW 0x000c
#define PGM_HFP_EXP_UNDERFLOW 0x000d
#define PGM_HFP_SIGNIFICANCE 0x000e
#define PGM_HFP_DIVIDE 0x000f
#define PGM_SEGMENT_TRANS 0x0010
#define PGM_PAGE_TRANS 0x0011
#define PGM_TRANS_SPEC 0x0012
#define PGM_SPECIAL_OP 0x0013
#define PGM_OPERAND 0x0015
#define PGM_TRACE_TABLE 0x0016
#define PGM_VECTOR_PROCESSING 0x001b
#define PGM_SPACE_SWITCH 0x001c
#define PGM_HFP_SQRT 0x001d
#define PGM_PC_TRANS_SPEC 0x001f
#define PGM_AFX_TRANS 0x0020
#define PGM_ASX_TRANS 0x0021
#define PGM_LX_TRANS 0x0022
#define PGM_EX_TRANS 0x0023
#define PGM_PRIM_AUTH 0x0024
#define PGM_SEC_AUTH 0x0025
#define PGM_ALET_SPEC 0x0028
#define PGM_ALEN_SPEC 0x0029
#define PGM_ALE_SEQ 0x002a
#define PGM_ASTE_VALID 0x002b
#define PGM_ASTE_SEQ 0x002c
#define PGM_EXT_AUTH 0x002d
#define PGM_STACK_FULL 0x0030
#define PGM_STACK_EMPTY 0x0031
#define PGM_STACK_SPEC 0x0032
#define PGM_STACK_TYPE 0x0033
#define PGM_STACK_OP 0x0034
#define PGM_ASCE_TYPE 0x0038
#define PGM_REG_FIRST_TRANS 0x0039
#define PGM_REG_SEC_TRANS 0x003a
#define PGM_REG_THIRD_TRANS 0x003b
#define PGM_MONITOR 0x0040
#define PGM_PER 0x0080
#define PGM_CRYPTO 0x0119
/* External Interrupts */
#define EXT_INTERRUPT_KEY 0x0040
#define EXT_CLOCK_COMP 0x1004
#define EXT_CPU_TIMER 0x1005
#define EXT_MALFUNCTION 0x1200
#define EXT_EMERGENCY 0x1201
#define EXT_EXTERNAL_CALL 0x1202
#define EXT_ETR 0x1406
#define EXT_SERVICE 0x2401
#define EXT_VIRTIO 0x2603
/* PSW defines */
#undef PSW_MASK_PER
#undef PSW_MASK_UNUSED_2
#undef PSW_MASK_UNUSED_3
#undef PSW_MASK_DAT
#undef PSW_MASK_IO
#undef PSW_MASK_EXT
#undef PSW_MASK_KEY
#undef PSW_SHIFT_KEY
#undef PSW_MASK_MCHECK
#undef PSW_MASK_WAIT
#undef PSW_MASK_PSTATE
#undef PSW_MASK_ASC
#undef PSW_SHIFT_ASC
#undef PSW_MASK_CC
#undef PSW_MASK_PM
#undef PSW_MASK_RI
#undef PSW_SHIFT_MASK_PM
#undef PSW_MASK_64
#undef PSW_MASK_32
#undef PSW_MASK_ESA_ADDR
#define PSW_MASK_PER 0x4000000000000000ULL
#define PSW_MASK_UNUSED_2 0x2000000000000000ULL
#define PSW_MASK_UNUSED_3 0x1000000000000000ULL
#define PSW_MASK_DAT 0x0400000000000000ULL
#define PSW_MASK_IO 0x0200000000000000ULL
#define PSW_MASK_EXT 0x0100000000000000ULL
#define PSW_MASK_KEY 0x00F0000000000000ULL
#define PSW_SHIFT_KEY 52
#define PSW_MASK_SHORTPSW 0x0008000000000000ULL
#define PSW_MASK_MCHECK 0x0004000000000000ULL
#define PSW_MASK_WAIT 0x0002000000000000ULL
#define PSW_MASK_PSTATE 0x0001000000000000ULL
#define PSW_MASK_ASC 0x0000C00000000000ULL
#define PSW_SHIFT_ASC 46
#define PSW_MASK_CC 0x0000300000000000ULL
#define PSW_MASK_PM 0x00000F0000000000ULL
#define PSW_SHIFT_MASK_PM 40
#define PSW_MASK_RI 0x0000008000000000ULL
#define PSW_MASK_64 0x0000000100000000ULL
#define PSW_MASK_32 0x0000000080000000ULL
#define PSW_MASK_SHORT_ADDR 0x000000007fffffffULL
#define PSW_MASK_SHORT_CTRL 0xffffffff80000000ULL
#undef PSW_ASC_PRIMARY
#undef PSW_ASC_ACCREG
#undef PSW_ASC_SECONDARY
#undef PSW_ASC_HOME
#define PSW_ASC_PRIMARY 0x0000000000000000ULL
#define PSW_ASC_ACCREG 0x0000400000000000ULL
#define PSW_ASC_SECONDARY 0x0000800000000000ULL
#define PSW_ASC_HOME 0x0000C00000000000ULL
/* the address space values shifted */
#define AS_PRIMARY 0
#define AS_ACCREG 1
#define AS_SECONDARY 2
#define AS_HOME 3
/* tb flags */
#define FLAG_MASK_PSW_SHIFT 31
#define FLAG_MASK_PER (PSW_MASK_PER >> FLAG_MASK_PSW_SHIFT)
#define FLAG_MASK_DAT (PSW_MASK_DAT >> FLAG_MASK_PSW_SHIFT)
#define FLAG_MASK_PSTATE (PSW_MASK_PSTATE >> FLAG_MASK_PSW_SHIFT)
#define FLAG_MASK_ASC (PSW_MASK_ASC >> FLAG_MASK_PSW_SHIFT)
#define FLAG_MASK_64 (PSW_MASK_64 >> FLAG_MASK_PSW_SHIFT)
#define FLAG_MASK_32 (PSW_MASK_32 >> FLAG_MASK_PSW_SHIFT)
#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)
#define FLAG_MASK_VECTOR (PSW_MASK_UNUSED_3 >> 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_VECTOR 0x0000000000020000ULL
#define CR0_IEP 0x0000000000100000ULL
#define CR0_EMERGENCY_SIGNAL_SC 0x0000000000004000ULL
#define CR0_EXTERNAL_CALL_SC 0x0000000000002000ULL
#define CR0_CKC_SC 0x0000000000000800ULL
#define CR0_CPU_TIMER_SC 0x0000000000000400ULL
#define CR0_SERVICE_SC 0x0000000000000200ULL
/* Control register 14 bits */
#define CR14_CHANNEL_REPORT_SC 0x0000000010000000ULL
/* MMU */
#define MMU_PRIMARY_IDX 0
#define MMU_SECONDARY_IDX 1
#define MMU_HOME_IDX 2
#define MMU_REAL_IDX 3
static inline int cpu_mmu_index(CPUS390XState *env, bool ifetch)
{
if (!(env->psw.mask & PSW_MASK_DAT)) {
return MMU_REAL_IDX;
}
if (ifetch) {
if ((env->psw.mask & PSW_MASK_ASC) == PSW_ASC_HOME) {
return MMU_HOME_IDX;
}
return MMU_PRIMARY_IDX;
}
switch (env->psw.mask & PSW_MASK_ASC) {
case PSW_ASC_PRIMARY:
return MMU_PRIMARY_IDX;
case PSW_ASC_SECONDARY:
return MMU_SECONDARY_IDX;
case PSW_ASC_HOME:
return MMU_HOME_IDX;
case PSW_ASC_ACCREG:
/* Fallthrough: access register mode is not yet supported */
default:
abort();
}
}
static inline void cpu_get_tb_cpu_state(CPUS390XState* env, target_ulong *pc,
target_ulong *cs_base, uint32_t *flags)
{
*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;
}
if (env->cregs[0] & CR0_VECTOR) {
*flags |= FLAG_MASK_VECTOR;
}
}
/* PER bits from control register 9 */
#define PER_CR9_EVENT_BRANCH 0x80000000
#define PER_CR9_EVENT_IFETCH 0x40000000
#define PER_CR9_EVENT_STORE 0x20000000
#define PER_CR9_EVENT_STORE_REAL 0x08000000
#define PER_CR9_EVENT_NULLIFICATION 0x01000000
#define PER_CR9_CONTROL_BRANCH_ADDRESS 0x00800000
#define PER_CR9_CONTROL_ALTERATION 0x00200000
/* PER bits from the PER CODE/ATMID/AI in lowcore */
#define PER_CODE_EVENT_BRANCH 0x8000
#define PER_CODE_EVENT_IFETCH 0x4000
#define PER_CODE_EVENT_STORE 0x2000
#define PER_CODE_EVENT_STORE_REAL 0x0800
#define PER_CODE_EVENT_NULLIFICATION 0x0100
#define EXCP_EXT 1 /* external interrupt */
#define EXCP_SVC 2 /* supervisor call (syscall) */
#define EXCP_PGM 3 /* program interruption */
#define EXCP_RESTART 4 /* restart interrupt */
#define EXCP_STOP 5 /* stop interrupt */
#define EXCP_IO 7 /* I/O interrupt */
#define EXCP_MCHK 8 /* machine check */
#define INTERRUPT_EXT_CPU_TIMER (1 << 3)
#define INTERRUPT_EXT_CLOCK_COMPARATOR (1 << 4)
#define INTERRUPT_EXTERNAL_CALL (1 << 5)
#define INTERRUPT_EMERGENCY_SIGNAL (1 << 6)
#define INTERRUPT_RESTART (1 << 7)
#define INTERRUPT_STOP (1 << 8)
/* Program Status Word. */
#define S390_PSWM_REGNUM 0
#define S390_PSWA_REGNUM 1
/* General Purpose Registers. */
#define S390_R0_REGNUM 2
#define S390_R1_REGNUM 3
#define S390_R2_REGNUM 4
#define S390_R3_REGNUM 5
#define S390_R4_REGNUM 6
#define S390_R5_REGNUM 7
#define S390_R6_REGNUM 8
#define S390_R7_REGNUM 9
#define S390_R8_REGNUM 10
#define S390_R9_REGNUM 11
#define S390_R10_REGNUM 12
#define S390_R11_REGNUM 13
#define S390_R12_REGNUM 14
#define S390_R13_REGNUM 15
#define S390_R14_REGNUM 16
#define S390_R15_REGNUM 17
/* Total Core Registers. */
#define S390_NUM_CORE_REGS 18
static inline void setcc(S390CPU *cpu, uint64_t cc)
{
CPUS390XState *env = &cpu->env;
env->psw.mask &= ~(3ull << 44);
env->psw.mask |= (cc & 3) << 44;
env->cc_op = cc;
}
/* STSI */
#define STSI_R0_FC_MASK 0x00000000f0000000ULL
#define STSI_R0_FC_CURRENT 0x0000000000000000ULL
#define STSI_R0_FC_LEVEL_1 0x0000000010000000ULL
#define STSI_R0_FC_LEVEL_2 0x0000000020000000ULL
#define STSI_R0_FC_LEVEL_3 0x0000000030000000ULL
#define STSI_R0_RESERVED_MASK 0x000000000fffff00ULL
#define STSI_R0_SEL1_MASK 0x00000000000000ffULL
#define STSI_R1_RESERVED_MASK 0x00000000ffff0000ULL
#define STSI_R1_SEL2_MASK 0x000000000000ffffULL
/* Basic Machine Configuration */
typedef struct SysIB_111 {
uint8_t res1[32];
uint8_t manuf[16];
uint8_t type[4];
uint8_t res2[12];
uint8_t model[16];
uint8_t sequence[16];
uint8_t plant[4];
uint8_t res3[3996];
} SysIB_111;
QEMU_BUILD_BUG_ON(sizeof(SysIB_111) != 4096);
/* Basic Machine CPU */
typedef struct SysIB_121 {
uint8_t res1[80];
uint8_t sequence[16];
uint8_t plant[4];
uint8_t res2[2];
uint16_t cpu_addr;
uint8_t res3[3992];
} SysIB_121;
QEMU_BUILD_BUG_ON(sizeof(SysIB_121) != 4096);
/* Basic Machine CPUs */
typedef struct SysIB_122 {
uint8_t res1[32];
uint32_t capability;
uint16_t total_cpus;
uint16_t conf_cpus;
uint16_t standby_cpus;
uint16_t reserved_cpus;
uint16_t adjustments[2026];
} SysIB_122;
QEMU_BUILD_BUG_ON(sizeof(SysIB_122) != 4096);
/* LPAR CPU */
typedef struct SysIB_221 {
uint8_t res1[80];
uint8_t sequence[16];
uint8_t plant[4];
uint16_t cpu_id;
uint16_t cpu_addr;
uint8_t res3[3992];
} SysIB_221;
QEMU_BUILD_BUG_ON(sizeof(SysIB_221) != 4096);
/* LPAR CPUs */
typedef struct SysIB_222 {
uint8_t res1[32];
uint16_t lpar_num;
uint8_t res2;
uint8_t lcpuc;
uint16_t total_cpus;
uint16_t conf_cpus;
uint16_t standby_cpus;
uint16_t reserved_cpus;
uint8_t name[8];
uint32_t caf;
uint8_t res3[16];
uint16_t dedicated_cpus;
uint16_t shared_cpus;
uint8_t res4[4020];
} SysIB_222;
QEMU_BUILD_BUG_ON(sizeof(SysIB_222) != 4096);
/* VM CPUs */
typedef struct SysIB_322 {
uint8_t res1[31];
uint8_t count;
struct {
uint8_t res2[4];
uint16_t total_cpus;
uint16_t conf_cpus;
uint16_t standby_cpus;
uint16_t reserved_cpus;
uint8_t name[8];
uint32_t caf;
uint8_t cpi[16];
uint8_t res5[3];
uint8_t ext_name_encoding;
uint32_t res3;
uint8_t uuid[16];
} vm[8];
uint8_t res4[1504];
uint8_t ext_names[8][256];
} SysIB_322;
QEMU_BUILD_BUG_ON(sizeof(SysIB_322) != 4096);
typedef union SysIB {
SysIB_111 sysib_111;
SysIB_121 sysib_121;
SysIB_122 sysib_122;
SysIB_221 sysib_221;
SysIB_222 sysib_222;
SysIB_322 sysib_322;
} SysIB;
QEMU_BUILD_BUG_ON(sizeof(SysIB) != 4096);
/* MMU defines */
#define ASCE_ORIGIN (~0xfffULL) /* segment table origin */
#define ASCE_SUBSPACE 0x200 /* subspace group control */
#define ASCE_PRIVATE_SPACE 0x100 /* private space control */
#define ASCE_ALT_EVENT 0x80 /* storage alteration event control */
#define ASCE_SPACE_SWITCH 0x40 /* space switch event */
#define ASCE_REAL_SPACE 0x20 /* real space control */
#define ASCE_TYPE_MASK 0x0c /* asce table type mask */
#define ASCE_TYPE_REGION1 0x0c /* region first table type */
#define ASCE_TYPE_REGION2 0x08 /* region second table type */
#define ASCE_TYPE_REGION3 0x04 /* region third table type */
#define ASCE_TYPE_SEGMENT 0x00 /* segment table type */
#define ASCE_TABLE_LENGTH 0x03 /* region table length */
#define REGION_ENTRY_ORIGIN 0xfffffffffffff000ULL
#define REGION_ENTRY_P 0x0000000000000200ULL
#define REGION_ENTRY_TF 0x00000000000000c0ULL
#define REGION_ENTRY_I 0x0000000000000020ULL
#define REGION_ENTRY_TT 0x000000000000000cULL
#define REGION_ENTRY_TL 0x0000000000000003ULL
#define REGION_ENTRY_TT_REGION1 0x000000000000000cULL
#define REGION_ENTRY_TT_REGION2 0x0000000000000008ULL
#define REGION_ENTRY_TT_REGION3 0x0000000000000004ULL
#define REGION3_ENTRY_RFAA 0xffffffff80000000ULL
#define REGION3_ENTRY_AV 0x0000000000010000ULL
#define REGION3_ENTRY_ACC 0x000000000000f000ULL
#define REGION3_ENTRY_F 0x0000000000000800ULL
#define REGION3_ENTRY_FC 0x0000000000000400ULL
#define REGION3_ENTRY_IEP 0x0000000000000100ULL
#define REGION3_ENTRY_CR 0x0000000000000010ULL
#define SEGMENT_ENTRY_ORIGIN 0xfffffffffffff800ULL
#define SEGMENT_ENTRY_SFAA 0xfffffffffff00000ULL
#define SEGMENT_ENTRY_AV 0x0000000000010000ULL
#define SEGMENT_ENTRY_ACC 0x000000000000f000ULL
#define SEGMENT_ENTRY_F 0x0000000000000800ULL
#define SEGMENT_ENTRY_FC 0x0000000000000400ULL
#define SEGMENT_ENTRY_P 0x0000000000000200ULL
#define SEGMENT_ENTRY_IEP 0x0000000000000100ULL
#define SEGMENT_ENTRY_I 0x0000000000000020ULL
#define SEGMENT_ENTRY_CS 0x0000000000000010ULL
#define SEGMENT_ENTRY_TT 0x000000000000000cULL
#define SEGMENT_ENTRY_TT_SEGMENT 0x0000000000000000ULL
#define PAGE_ENTRY_0 0x0000000000000800ULL
#define PAGE_ENTRY_I 0x0000000000000400ULL
#define PAGE_ENTRY_P 0x0000000000000200ULL
#define PAGE_ENTRY_IEP 0x0000000000000100ULL
#define VADDR_REGION1_TX_MASK 0xffe0000000000000ULL
#define VADDR_REGION2_TX_MASK 0x001ffc0000000000ULL
#define VADDR_REGION3_TX_MASK 0x000003ff80000000ULL
#define VADDR_SEGMENT_TX_MASK 0x000000007ff00000ULL
#define VADDR_PAGE_TX_MASK 0x00000000000ff000ULL
#define VADDR_REGION1_TX(vaddr) (((vaddr) & VADDR_REGION1_TX_MASK) >> 53)
#define VADDR_REGION2_TX(vaddr) (((vaddr) & VADDR_REGION2_TX_MASK) >> 42)
#define VADDR_REGION3_TX(vaddr) (((vaddr) & VADDR_REGION3_TX_MASK) >> 31)
#define VADDR_SEGMENT_TX(vaddr) (((vaddr) & VADDR_SEGMENT_TX_MASK) >> 20)
#define VADDR_PAGE_TX(vaddr) (((vaddr) & VADDR_PAGE_TX_MASK) >> 12)
#define VADDR_REGION1_TL(vaddr) (((vaddr) & 0xc000000000000000ULL) >> 62)
#define VADDR_REGION2_TL(vaddr) (((vaddr) & 0x0018000000000000ULL) >> 51)
#define VADDR_REGION3_TL(vaddr) (((vaddr) & 0x0000030000000000ULL) >> 40)
#define VADDR_SEGMENT_TL(vaddr) (((vaddr) & 0x0000000060000000ULL) >> 29)
#define SK_C (0x1 << 1)
#define SK_R (0x1 << 2)
#define SK_F (0x1 << 3)
#define SK_ACC_MASK (0xf << 4)
/* SIGP order codes */
#define SIGP_SENSE 0x01
#define SIGP_EXTERNAL_CALL 0x02
#define SIGP_EMERGENCY 0x03
#define SIGP_START 0x04
#define SIGP_STOP 0x05
#define SIGP_RESTART 0x06
#define SIGP_STOP_STORE_STATUS 0x09
#define SIGP_INITIAL_CPU_RESET 0x0b
#define SIGP_CPU_RESET 0x0c
#define SIGP_SET_PREFIX 0x0d
#define SIGP_STORE_STATUS_ADDR 0x0e
#define SIGP_SET_ARCH 0x12
#define SIGP_COND_EMERGENCY 0x13
#define SIGP_SENSE_RUNNING 0x15
#define SIGP_STORE_ADTL_STATUS 0x17
/* SIGP condition codes */
#define SIGP_CC_ORDER_CODE_ACCEPTED 0
#define SIGP_CC_STATUS_STORED 1
#define SIGP_CC_BUSY 2
#define SIGP_CC_NOT_OPERATIONAL 3
/* SIGP status bits */
#define SIGP_STAT_EQUIPMENT_CHECK 0x80000000UL
#define SIGP_STAT_NOT_RUNNING 0x00000400UL
#define SIGP_STAT_INCORRECT_STATE 0x00000200UL
#define SIGP_STAT_INVALID_PARAMETER 0x00000100UL
#define SIGP_STAT_EXT_CALL_PENDING 0x00000080UL
#define SIGP_STAT_STOPPED 0x00000040UL
#define SIGP_STAT_OPERATOR_INTERV 0x00000020UL
#define SIGP_STAT_CHECK_STOP 0x00000010UL
#define SIGP_STAT_INOPERATIVE 0x00000004UL
#define SIGP_STAT_INVALID_ORDER 0x00000002UL
#define SIGP_STAT_RECEIVER_CHECK 0x00000001UL
/* SIGP SET ARCHITECTURE modes */
#define SIGP_MODE_ESA_S390 0
#define SIGP_MODE_Z_ARCH_TRANS_ALL_PSW 1
#define SIGP_MODE_Z_ARCH_TRANS_CUR_PSW 2
/* SIGP order code mask corresponding to bit positions 56-63 */
#define SIGP_ORDER_MASK 0x000000ff
/* machine check interruption code */
/* subclasses */
#define MCIC_SC_SD 0x8000000000000000ULL
#define MCIC_SC_PD 0x4000000000000000ULL
#define MCIC_SC_SR 0x2000000000000000ULL
#define MCIC_SC_CD 0x0800000000000000ULL
#define MCIC_SC_ED 0x0400000000000000ULL
#define MCIC_SC_DG 0x0100000000000000ULL
#define MCIC_SC_W 0x0080000000000000ULL
#define MCIC_SC_CP 0x0040000000000000ULL
#define MCIC_SC_SP 0x0020000000000000ULL
#define MCIC_SC_CK 0x0010000000000000ULL
/* subclass modifiers */
#define MCIC_SCM_B 0x0002000000000000ULL
#define MCIC_SCM_DA 0x0000000020000000ULL
#define MCIC_SCM_AP 0x0000000000080000ULL
/* storage errors */
#define MCIC_SE_SE 0x0000800000000000ULL
#define MCIC_SE_SC 0x0000400000000000ULL
#define MCIC_SE_KE 0x0000200000000000ULL
#define MCIC_SE_DS 0x0000100000000000ULL
#define MCIC_SE_IE 0x0000000080000000ULL
/* validity bits */
#define MCIC_VB_WP 0x0000080000000000ULL
#define MCIC_VB_MS 0x0000040000000000ULL
#define MCIC_VB_PM 0x0000020000000000ULL
#define MCIC_VB_IA 0x0000010000000000ULL
#define MCIC_VB_FA 0x0000008000000000ULL
#define MCIC_VB_VR 0x0000004000000000ULL
#define MCIC_VB_EC 0x0000002000000000ULL
#define MCIC_VB_FP 0x0000001000000000ULL
#define MCIC_VB_GR 0x0000000800000000ULL
#define MCIC_VB_CR 0x0000000400000000ULL
#define MCIC_VB_ST 0x0000000100000000ULL
#define MCIC_VB_AR 0x0000000040000000ULL
#define MCIC_VB_GS 0x0000000008000000ULL
#define MCIC_VB_PR 0x0000000000200000ULL
#define MCIC_VB_FC 0x0000000000100000ULL
#define MCIC_VB_CT 0x0000000000020000ULL
#define MCIC_VB_CC 0x0000000000010000ULL
static inline uint64_t s390_build_validity_mcic(struct uc_struct *uc)
{
uint64_t mcic;
/*
* Indicate all validity bits (no damage) only. Other bits have to be
* added by the caller. (storage errors, subclasses and subclass modifiers)
*/
mcic = MCIC_VB_WP | MCIC_VB_MS | MCIC_VB_PM | MCIC_VB_IA | MCIC_VB_FP |
MCIC_VB_GR | MCIC_VB_CR | MCIC_VB_ST | MCIC_VB_AR | MCIC_VB_PR |
MCIC_VB_FC | MCIC_VB_CT | MCIC_VB_CC;
if (s390_has_feat(uc, S390_FEAT_VECTOR)) {
mcic |= MCIC_VB_VR;
}
if (s390_has_feat(uc, S390_FEAT_GUARDED_STORAGE)) {
mcic |= MCIC_VB_GS;
}
return mcic;
}
static inline void s390_do_cpu_full_reset(CPUState *cs, run_on_cpu_data arg)
{
cpu_reset(cs);
}
static inline void s390_do_cpu_reset(CPUState *cs, run_on_cpu_data arg)
{
S390CPUClass *scc = S390_CPU_GET_CLASS(cs);
scc->reset(cs, S390_CPU_RESET_NORMAL);
}
static inline void s390_do_cpu_initial_reset(CPUState *cs, run_on_cpu_data arg)
{
S390CPUClass *scc = S390_CPU_GET_CLASS(cs);
scc->reset(cs, S390_CPU_RESET_INITIAL);
}
static inline void s390_do_cpu_load_normal(CPUState *cs, run_on_cpu_data arg)
{
S390CPUClass *scc = S390_CPU_GET_CLASS(cs);
scc->load_normal(cs);
}
/* cpu.c */
void s390_crypto_reset(void);
int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit);
void s390_set_max_pagesize(uint64_t pagesize);
void s390_cmma_reset(void);
void s390_enable_css_support(S390CPU *cpu);
unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu);
static inline uint8_t s390_cpu_get_state(S390CPU *cpu)
{
return cpu->env.cpu_state;
}
/* cpu_models.c */
void s390_cpu_list(void);
#define cpu_list s390_cpu_list
void s390_set_qemu_cpu_model(uint16_t type, uint8_t gen, uint8_t ec_ga,
const S390FeatInit feat_init);
/* helper.c */
#define S390_CPU_TYPE_SUFFIX "-" TYPE_S390_CPU
#define S390_CPU_TYPE_NAME(name) (name S390_CPU_TYPE_SUFFIX)
#define CPU_RESOLVING_TYPE TYPE_S390_CPU
/* you can call this signal handler from your SIGBUS and SIGSEGV
signal handlers to inform the virtual CPU of exceptions. non zero
is returned if the signal was handled by the virtual CPU. */
int cpu_s390x_signal_handler(int host_signum, void *pinfo, void *puc);
#define cpu_signal_handler cpu_s390x_signal_handler
/* interrupt.c */
void s390_crw_mchk(void);
void s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr,
uint32_t io_int_parm, uint32_t io_int_word);
#define RA_IGNORED 0
void s390_program_interrupt(CPUS390XState *env, uint32_t code, uintptr_t ra);
/* service interrupts are floating therefore we must not pass an cpustate */
void s390_sclp_extint(uint32_t parm);
/* mmu_helper.c */
int s390_cpu_virt_mem_rw(S390CPU *cpu, vaddr laddr, uint8_t ar, void *hostbuf,
int len, bool is_write);
#define s390_cpu_virt_mem_read(cpu, laddr, ar, dest, len) \
s390_cpu_virt_mem_rw(cpu, laddr, ar, dest, len, false)
#define s390_cpu_virt_mem_write(cpu, laddr, ar, dest, len) \
s390_cpu_virt_mem_rw(cpu, laddr, ar, dest, len, true)
#define s390_cpu_virt_mem_check_read(cpu, laddr, ar, len) \
s390_cpu_virt_mem_rw(cpu, laddr, ar, NULL, len, false)
#define s390_cpu_virt_mem_check_write(cpu, laddr, ar, len) \
s390_cpu_virt_mem_rw(cpu, laddr, ar, NULL, len, true)
void s390_cpu_virt_mem_handle_exc(S390CPU *cpu, uintptr_t ra);
/* sigp.c */
int s390_cpu_restart(S390CPU *cpu);
void s390_init_sigp(void);
/* outside of target/s390x/ */
S390CPU *s390_cpu_addr2state(uint16_t cpu_addr);
typedef CPUS390XState CPUArchState;
typedef S390CPU ArchCPU;
#include "exec/cpu-all.h"
typedef enum CpuS390State {
S390_CPU_STATE_UNINITIALIZED,
S390_CPU_STATE_STOPPED,
S390_CPU_STATE_CHECK_STOP,
S390_CPU_STATE_OPERATING,
S390_CPU_STATE_LOAD,
S390_CPU_STATE__MAX,
} CpuS390State;
#endif

View File

@ -0,0 +1,210 @@
/*
* CPU features/facilities for s390x
*
* Copyright IBM Corp. 2016, 2018
* Copyright Red Hat, Inc. 2019
*
* Author(s): David Hildenbrand <david@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at
* your option) any later version. See the COPYING file in the top-level
* directory.
*/
#include "qemu/osdep.h"
#include "cpu_features.h"
#define DEF_FEAT(_FEAT, _NAME, _TYPE, _BIT, _DESC) \
[S390_FEAT_##_FEAT] = { \
.name = _NAME, \
.type = S390_FEAT_TYPE_##_TYPE, \
.bit = _BIT, \
.desc = _DESC, \
},
static const S390FeatDef s390_features[S390_FEAT_MAX] = {
#include "cpu_features_def.inc.h"
};
#undef DEF_FEAT
const S390FeatDef *s390_feat_def(S390Feat feat)
{
return &s390_features[feat];
}
S390Feat s390_feat_by_type_and_bit(S390FeatType type, int bit)
{
S390Feat feat;
for (feat = 0; feat < ARRAY_SIZE(s390_features); feat++) {
if (s390_features[feat].type == type &&
s390_features[feat].bit == bit) {
return feat;
}
}
return S390_FEAT_MAX;
}
void s390_init_feat_bitmap(const S390FeatInit init, S390FeatBitmap bitmap)
{
int i, j;
for (i = 0; i < (S390_FEAT_MAX / 64 + 1); i++) {
if (init[i]) {
for (j = 0; j < 64; j++) {
if (init[i] & 1ULL << j) {
set_bit(i * 64 + j, bitmap);
}
}
}
}
}
void s390_fill_feat_block(const S390FeatBitmap features, S390FeatType type,
uint8_t *data)
{
S390Feat feat;
int bit_nr;
switch (type) {
case S390_FEAT_TYPE_STFL:
if (test_bit(S390_FEAT_ZARCH, features)) {
/* Features that are always active */
set_be_bit(2, data); /* z/Architecture */
set_be_bit(138, data); /* Configuration-z-architectural-mode */
}
break;
case S390_FEAT_TYPE_PTFF:
case S390_FEAT_TYPE_KMAC:
case S390_FEAT_TYPE_KMC:
case S390_FEAT_TYPE_KM:
case S390_FEAT_TYPE_KIMD:
case S390_FEAT_TYPE_KLMD:
case S390_FEAT_TYPE_PCKMO:
case S390_FEAT_TYPE_KMCTR:
case S390_FEAT_TYPE_KMF:
case S390_FEAT_TYPE_KMO:
case S390_FEAT_TYPE_PCC:
case S390_FEAT_TYPE_PPNO:
case S390_FEAT_TYPE_KMA:
case S390_FEAT_TYPE_KDSA:
case S390_FEAT_TYPE_SORTL:
case S390_FEAT_TYPE_DFLTCC:
set_be_bit(0, data); /* query is always available */
break;
default:
break;
};
feat = find_first_bit(features, S390_FEAT_MAX);
while (feat < S390_FEAT_MAX) {
if (s390_features[feat].type == type) {
bit_nr = s390_features[feat].bit;
/* big endian on uint8_t array */
set_be_bit(bit_nr, data);
}
feat = find_next_bit(features, S390_FEAT_MAX, feat + 1);
}
}
void s390_add_from_feat_block(S390FeatBitmap features, S390FeatType type,
uint8_t *data)
{
int nr_bits, le_bit;
switch (type) {
case S390_FEAT_TYPE_STFL:
nr_bits = 16384;
break;
case S390_FEAT_TYPE_PLO:
case S390_FEAT_TYPE_SORTL:
case S390_FEAT_TYPE_DFLTCC:
nr_bits = 256;
break;
default:
/* all cpu subfunctions have 128 bit */
nr_bits = 128;
};
le_bit = find_first_bit((unsigned long *) data, nr_bits);
while (le_bit < nr_bits) {
/* convert the bit number to a big endian bit nr */
S390Feat feat = s390_feat_by_type_and_bit(type, BE_BIT_NR(le_bit));
/* ignore unknown bits */
if (feat < S390_FEAT_MAX) {
set_bit(feat, features);
}
le_bit = find_next_bit((unsigned long *) data, nr_bits, le_bit + 1);
}
}
void s390_feat_bitmap_to_ascii(const S390FeatBitmap features, void *opaque,
void (*fn)(const char *name, void *opaque))
{
S390FeatBitmap bitmap, tmp;
S390FeatGroup group;
S390Feat feat;
bitmap_copy(bitmap, features, S390_FEAT_MAX);
/* process whole groups first */
for (group = 0; group < S390_FEAT_GROUP_MAX; group++) {
const S390FeatGroupDef *def = s390_feat_group_def(group);
bitmap_and(tmp, bitmap, def->feat, S390_FEAT_MAX);
if (bitmap_equal(tmp, def->feat, S390_FEAT_MAX)) {
bitmap_andnot(bitmap, bitmap, def->feat, S390_FEAT_MAX);
fn(def->name, opaque);
}
}
/* report leftovers as separate features */
feat = find_first_bit(bitmap, S390_FEAT_MAX);
while (feat < S390_FEAT_MAX) {
fn(s390_feat_def(feat)->name, opaque);
feat = find_next_bit(bitmap, S390_FEAT_MAX, feat + 1);
};
}
#define FEAT_GROUP_INIT(_name, _group, _desc) \
{ \
.name = _name, \
.desc = _desc, \
.init = { S390_FEAT_GROUP_LIST_ ## _group }, \
}
/* indexed by feature group number for easy lookup */
static S390FeatGroupDef s390_feature_groups[] = {
FEAT_GROUP_INIT("plo", PLO, "Perform-locked-operation facility"),
FEAT_GROUP_INIT("tods", TOD_CLOCK_STEERING, "Tod-clock-steering facility"),
FEAT_GROUP_INIT("gen13ptff", GEN13_PTFF, "PTFF enhancements introduced with z13"),
FEAT_GROUP_INIT("msa", MSA, "Message-security-assist facility"),
FEAT_GROUP_INIT("msa1", MSA_EXT_1, "Message-security-assist-extension 1 facility"),
FEAT_GROUP_INIT("msa2", MSA_EXT_2, "Message-security-assist-extension 2 facility"),
FEAT_GROUP_INIT("msa3", MSA_EXT_3, "Message-security-assist-extension 3 facility"),
FEAT_GROUP_INIT("msa4", MSA_EXT_4, "Message-security-assist-extension 4 facility"),
FEAT_GROUP_INIT("msa5", MSA_EXT_5, "Message-security-assist-extension 5 facility"),
FEAT_GROUP_INIT("msa6", MSA_EXT_6, "Message-security-assist-extension 6 facility"),
FEAT_GROUP_INIT("msa7", MSA_EXT_7, "Message-security-assist-extension 7 facility"),
FEAT_GROUP_INIT("msa8", MSA_EXT_8, "Message-security-assist-extension 8 facility"),
FEAT_GROUP_INIT("msa9", MSA_EXT_9, "Message-security-assist-extension 9 facility"),
FEAT_GROUP_INIT("msa9_pckmo", MSA_EXT_9_PCKMO, "Message-security-assist-extension 9 PCKMO subfunctions"),
FEAT_GROUP_INIT("mepochptff", MULTIPLE_EPOCH_PTFF, "PTFF enhancements introduced with Multiple-epoch facility"),
FEAT_GROUP_INIT("esort", ENH_SORT, "Enhanced-sort facility"),
FEAT_GROUP_INIT("deflate", DEFLATE_CONVERSION, "Deflate-conversion facility"),
};
const S390FeatGroupDef *s390_feat_group_def(S390FeatGroup group)
{
return &s390_feature_groups[group];
}
void init_groups(void)
{
int i;
/* init all bitmaps from gnerated data initially */
for (i = 0; i < ARRAY_SIZE(s390_feature_groups); i++) {
s390_init_feat_bitmap(s390_feature_groups[i].init,
s390_feature_groups[i].feat);
}
}

View File

@ -0,0 +1,91 @@
/*
* CPU features/facilities helper structs and utility functions for s390
*
* Copyright 2016 IBM Corp.
*
* Author(s): Michael Mueller <mimu@linux.vnet.ibm.com>
* David Hildenbrand <dahi@linux.vnet.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at
* your option) any later version. See the COPYING file in the top-level
* directory.
*/
#ifndef TARGET_S390X_CPU_FEATURES_H
#define TARGET_S390X_CPU_FEATURES_H
#include "qemu/bitmap.h"
#include "cpu_features_def.h"
#include "gen-features.h"
/* CPU features are announced via different ways */
typedef enum {
S390_FEAT_TYPE_STFL,
S390_FEAT_TYPE_SCLP_CONF_CHAR,
S390_FEAT_TYPE_SCLP_CONF_CHAR_EXT,
S390_FEAT_TYPE_SCLP_CPU,
S390_FEAT_TYPE_MISC,
S390_FEAT_TYPE_PLO,
S390_FEAT_TYPE_PTFF,
S390_FEAT_TYPE_KMAC,
S390_FEAT_TYPE_KMC,
S390_FEAT_TYPE_KM,
S390_FEAT_TYPE_KIMD,
S390_FEAT_TYPE_KLMD,
S390_FEAT_TYPE_PCKMO,
S390_FEAT_TYPE_KMCTR,
S390_FEAT_TYPE_KMF,
S390_FEAT_TYPE_KMO,
S390_FEAT_TYPE_PCC,
S390_FEAT_TYPE_PPNO,
S390_FEAT_TYPE_KMA,
S390_FEAT_TYPE_KDSA,
S390_FEAT_TYPE_SORTL,
S390_FEAT_TYPE_DFLTCC,
} S390FeatType;
/* Definition of a CPU feature */
typedef struct {
const char *name; /* name exposed to the user */
const char *desc; /* description exposed to the user */
S390FeatType type; /* feature type (way of indication)*/
int bit; /* bit within the feature type area (fixed) */
} S390FeatDef;
/* use ordinary bitmap operations to work with features */
typedef unsigned long S390FeatBitmap[BITS_TO_LONGS(S390_FEAT_MAX)];
/* 64bit based bitmap used to init S390FeatBitmap from generated data */
typedef uint64_t S390FeatInit[S390_FEAT_MAX / 64 + 1];
const S390FeatDef *s390_feat_def(S390Feat feat);
S390Feat s390_feat_by_type_and_bit(S390FeatType type, int bit);
void s390_init_feat_bitmap(const S390FeatInit init, S390FeatBitmap bitmap);
void s390_fill_feat_block(const S390FeatBitmap features, S390FeatType type,
uint8_t *data);
void s390_add_from_feat_block(S390FeatBitmap features, S390FeatType type,
uint8_t *data);
void s390_feat_bitmap_to_ascii(const S390FeatBitmap features, void *opaque,
void (*fn)(const char *name, void *opaque));
/* Definition of a CPU feature group */
typedef struct {
const char *name; /* name exposed to the user */
const char *desc; /* description exposed to the user */
S390FeatBitmap feat; /* features contained in the group */
S390FeatInit init; /* used to init feat from generated data */
} S390FeatGroupDef;
const S390FeatGroupDef *s390_feat_group_def(S390FeatGroup group);
#define BE_BIT_NR(BIT) (BIT ^ (BITS_PER_LONG - 1))
static inline void set_be_bit(unsigned int bit_nr, uint8_t *array)
{
array[bit_nr / 8] |= 0x80 >> (bit_nr % 8);
}
static inline bool test_be_bit(unsigned int bit_nr, const uint8_t *array)
{
return array[bit_nr / 8] & (0x80 >> (bit_nr % 8));
}
#endif /* TARGET_S390X_CPU_FEATURES_H */

View File

@ -0,0 +1,25 @@
/*
* CPU features/facilities for s390
*
* Copyright IBM Corp. 2016, 2018
* Copyright Red Hat, Inc. 2019
*
* Author(s): Michael Mueller <mimu@linux.vnet.ibm.com>
* David Hildenbrand <david@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at
* your option) any later version. See the COPYING file in the top-level
* directory.
*/
#ifndef TARGET_S390X_CPU_FEATURES_DEF_H
#define TARGET_S390X_CPU_FEATURES_DEF_H
#define DEF_FEAT(_FEAT, ...) S390_FEAT_##_FEAT,
typedef enum {
#include "cpu_features_def.inc.h"
S390_FEAT_MAX,
} S390Feat;
#undef DEF_FEAT
#endif /* TARGET_S390X_CPU_FEATURES_DEF_H */

View File

@ -0,0 +1,370 @@
/*
* RAW s390x CPU feature definitions:
*
* DEF_FEAT(_FEAT, _NAME, _TYPE, _BIT, _DESC):
* - _FEAT: Feature (enum) name used internally (S390_FEAT_##_FEAT)
* - _NAME: Feature name exposed to the user.
* - _TYPE: Feature type (S390_FEAT_TYPE_##_TYPE).
* - _BIT: Feature bit number within feature type block (unused for MISC).
* - _DESC: Feature description, exposed to the user.
*
* Copyright IBM Corp. 2016, 2018
* Copyright Red Hat, Inc. 2019
*
* Author(s): Michael Mueller <mimu@linux.vnet.ibm.com>
* David Hildenbrand <david@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at
* your option) any later version. See the COPYING file in the top-level
* directory.
*/
/* Features exposed via the STFL(E) instruction. */
DEF_FEAT(ESAN3, "esan3", STFL, 0, "Instructions marked as n3")
DEF_FEAT(ZARCH, "zarch", STFL, 1, "z/Architecture architectural mode")
DEF_FEAT(DAT_ENH, "dateh", STFL, 3, "DAT-enhancement facility")
DEF_FEAT(IDTE_SEGMENT, "idtes", STFL, 4, "IDTE selective TLB segment-table clearing")
DEF_FEAT(IDTE_REGION, "idter", STFL, 5, "IDTE selective TLB region-table clearing")
DEF_FEAT(ASN_LX_REUSE, "asnlxr", STFL, 6, "ASN-and-LX reuse facility")
DEF_FEAT(STFLE, "stfle", STFL, 7, "Store-facility-list-extended facility")
DEF_FEAT(EDAT, "edat", STFL, 8, "Enhanced-DAT facility")
DEF_FEAT(SENSE_RUNNING_STATUS, "srs", STFL, 9, "Sense-running-status facility")
DEF_FEAT(CONDITIONAL_SSKE, "csske", STFL, 10, "Conditional-SSKE facility")
DEF_FEAT(CONFIGURATION_TOPOLOGY, "ctop", STFL, 11, "Configuration-topology facility")
DEF_FEAT(AP_QUERY_CONFIG_INFO, "apqci", STFL, 12, "Query AP Configuration Information facility")
DEF_FEAT(IPTE_RANGE, "ipter", STFL, 13, "IPTE-range facility")
DEF_FEAT(NONQ_KEY_SETTING, "nonqks", STFL, 14, "Nonquiescing key-setting facility")
DEF_FEAT(AP_FACILITIES_TEST, "apft", STFL, 15, "AP Facilities Test facility")
DEF_FEAT(EXTENDED_TRANSLATION_2, "etf2", STFL, 16, "Extended-translation facility 2")
DEF_FEAT(MSA, "msa-base", STFL, 17, "Message-security-assist facility (excluding subfunctions)")
DEF_FEAT(LONG_DISPLACEMENT, "ldisp", STFL, 18, "Long-displacement facility")
DEF_FEAT(LONG_DISPLACEMENT_FAST, "ldisphp", STFL, 19, "Long-displacement facility has high performance")
DEF_FEAT(HFP_MADDSUB, "hfpm", STFL, 20, "HFP-multiply-add/subtract facility")
DEF_FEAT(EXTENDED_IMMEDIATE, "eimm", STFL, 21, "Extended-immediate facility")
DEF_FEAT(EXTENDED_TRANSLATION_3, "etf3", STFL, 22, "Extended-translation facility 3")
DEF_FEAT(HFP_UNNORMALIZED_EXT, "hfpue", STFL, 23, "HFP-unnormalized-extension facility")
DEF_FEAT(ETF2_ENH, "etf2eh", STFL, 24, "ETF2-enhancement facility")
DEF_FEAT(STORE_CLOCK_FAST, "stckf", STFL, 25, "Store-clock-fast facility")
DEF_FEAT(PARSING_ENH, "parseh", STFL, 26, "Parsing-enhancement facility")
DEF_FEAT(MOVE_WITH_OPTIONAL_SPEC, "mvcos", STFL, 27, "Move-with-optional-specification facility")
DEF_FEAT(TOD_CLOCK_STEERING, "tods-base", STFL, 28, "TOD-clock-steering facility (excluding subfunctions)")
DEF_FEAT(ETF3_ENH, "etf3eh", STFL, 30, "ETF3-enhancement facility")
DEF_FEAT(EXTRACT_CPU_TIME, "ectg", STFL, 31, "Extract-CPU-time facility")
DEF_FEAT(COMPARE_AND_SWAP_AND_STORE, "csst", STFL, 32, "Compare-and-swap-and-store facility")
DEF_FEAT(COMPARE_AND_SWAP_AND_STORE_2, "csst2", STFL, 33, "Compare-and-swap-and-store facility 2")
DEF_FEAT(GENERAL_INSTRUCTIONS_EXT, "ginste", STFL, 34, "General-instructions-extension facility")
DEF_FEAT(EXECUTE_EXT, "exrl", STFL, 35, "Execute-extensions facility")
DEF_FEAT(ENHANCED_MONITOR, "emon", STFL, 36, "Enhanced-monitor facility")
DEF_FEAT(FLOATING_POINT_EXT, "fpe", STFL, 37, "Floating-point extension facility")
DEF_FEAT(ORDER_PRESERVING_COMPRESSION, "opc", STFL, 38, "Order Preserving Compression facility")
DEF_FEAT(SET_PROGRAM_PARAMETERS, "sprogp", STFL, 40, "Set-program-parameters facility")
DEF_FEAT(FLOATING_POINT_SUPPPORT_ENH, "fpseh", STFL, 41, "Floating-point-support-enhancement facilities")
DEF_FEAT(DFP, "dfp", STFL, 42, "DFP (decimal-floating-point) facility")
DEF_FEAT(DFP_FAST, "dfphp", STFL, 43, "DFP (decimal-floating-point) facility has high performance")
DEF_FEAT(PFPO, "pfpo", STFL, 44, "PFPO instruction")
DEF_FEAT(STFLE_45, "stfle45", STFL, 45, "Various facilities introduced with z196")
DEF_FEAT(CMPSC_ENH, "cmpsceh", STFL, 47, "CMPSC-enhancement facility")
DEF_FEAT(DFP_ZONED_CONVERSION, "dfpzc", STFL, 48, "Decimal-floating-point zoned-conversion facility")
DEF_FEAT(STFLE_49, "stfle49", STFL, 49, "Various facilities introduced with zEC12")
DEF_FEAT(CONSTRAINT_TRANSACTIONAL_EXE, "cte", STFL, 50, "Constrained transactional-execution facility")
DEF_FEAT(LOCAL_TLB_CLEARING, "ltlbc", STFL, 51, "Local-TLB-clearing facility")
DEF_FEAT(INTERLOCKED_ACCESS_2, "iacc2", STFL, 52, "Interlocked-access facility 2")
DEF_FEAT(STFLE_53, "stfle53", STFL, 53, "Various facilities introduced with z13")
DEF_FEAT(ENTROPY_ENC_COMP, "eec", STFL, 54, "Entropy encoding compression facility")
DEF_FEAT(MSA_EXT_5, "msa5-base", STFL, 57, "Message-security-assist-extension-5 facility (excluding subfunctions)")
DEF_FEAT(MISC_INSTRUCTION_EXT, "minste2", STFL, 58, "Miscellaneous-instruction-extensions facility 2")
DEF_FEAT(SEMAPHORE_ASSIST, "sema", STFL, 59, "Semaphore-assist facility")
DEF_FEAT(TIME_SLICE_INSTRUMENTATION, "tsi", STFL, 60, "Time-slice Instrumentation facility")
DEF_FEAT(MISC_INSTRUCTION_EXT3, "minste3", STFL, 61, "Miscellaneous-Instruction-Extensions Facility 3")
DEF_FEAT(RUNTIME_INSTRUMENTATION, "ri", STFL, 64, "CPU runtime-instrumentation facility")
DEF_FEAT(AP_QUEUE_INTERRUPT_CONTROL, "apqi", STFL, 65, "AP-Queue interruption facility")
DEF_FEAT(ZPCI, "zpci", STFL, 69, "z/PCI facility")
DEF_FEAT(ADAPTER_EVENT_NOTIFICATION, "aen", STFL, 71, "General-purpose-adapter-event-notification facility")
DEF_FEAT(ADAPTER_INT_SUPPRESSION, "ais", STFL, 72, "General-purpose-adapter-interruption-suppression facility")
DEF_FEAT(TRANSACTIONAL_EXE, "te", STFL, 73, "Transactional-execution facility")
DEF_FEAT(STORE_HYPERVISOR_INFO, "sthyi", STFL, 74, "Store-hypervisor-information facility")
DEF_FEAT(ACCESS_EXCEPTION_FS_INDICATION, "aefsi", STFL, 75, "Access-exception-fetch/store-indication facility")
DEF_FEAT(MSA_EXT_3, "msa3-base", STFL, 76, "Message-security-assist-extension-3 facility (excluding subfunctions)")
DEF_FEAT(MSA_EXT_4, "msa4-base", STFL, 77, "Message-security-assist-extension-4 facility (excluding subfunctions)")
DEF_FEAT(EDAT_2, "edat2", STFL, 78, "Enhanced-DAT facility 2")
DEF_FEAT(DFP_PACKED_CONVERSION, "dfppc", STFL, 80, "Decimal-floating-point packed-conversion facility")
DEF_FEAT(PPA15, "ppa15", STFL, 81, "PPA15 is installed")
DEF_FEAT(BPB, "bpb", STFL, 82, "Branch prediction blocking")
DEF_FEAT(VECTOR, "vx", STFL, 129, "Vector facility")
DEF_FEAT(INSTRUCTION_EXEC_PROT, "iep", STFL, 130, "Instruction-execution-protection facility")
DEF_FEAT(SIDE_EFFECT_ACCESS_ESOP2, "sea_esop2", STFL, 131, "Side-effect-access facility and Enhanced-suppression-on-protection facility 2")
DEF_FEAT(GUARDED_STORAGE, "gs", STFL, 133, "Guarded-storage facility")
DEF_FEAT(VECTOR_PACKED_DECIMAL, "vxpd", STFL, 134, "Vector packed decimal facility")
DEF_FEAT(VECTOR_ENH, "vxeh", STFL, 135, "Vector enhancements facility")
DEF_FEAT(MULTIPLE_EPOCH, "mepoch", STFL, 139, "Multiple-epoch facility")
DEF_FEAT(TEST_PENDING_EXT_INTERRUPTION, "tpei", STFL, 144, "Test-pending-external-interruption facility")
DEF_FEAT(INSERT_REFERENCE_BITS_MULT, "irbm", STFL, 145, "Insert-reference-bits-multiple facility")
DEF_FEAT(MSA_EXT_8, "msa8-base", STFL, 146, "Message-security-assist-extension-8 facility (excluding subfunctions)")
DEF_FEAT(CMM_NT, "cmmnt", STFL, 147, "CMM: ESSA-enhancement (no translate) facility")
DEF_FEAT(VECTOR_ENH2, "vxeh2", STFL, 148, "Vector Enhancements facility 2")
DEF_FEAT(ESORT_BASE, "esort-base", STFL, 150, "Enhanced-sort facility (excluding subfunctions)")
DEF_FEAT(DEFLATE_BASE, "deflate-base", STFL, 151, "Deflate-conversion facility (excluding subfunctions)")
DEF_FEAT(VECTOR_PACKED_DECIMAL_ENH, "vxpdeh", STFL, 152, "Vector-Packed-Decimal-Enhancement Facility")
DEF_FEAT(MSA_EXT_9, "msa9-base", STFL, 155, "Message-security-assist-extension-9 facility (excluding subfunctions)")
DEF_FEAT(ETOKEN, "etoken", STFL, 156, "Etoken facility")
/* Features exposed via SCLP SCCB Byte 80 - 98 (bit numbers relative to byte-80) */
DEF_FEAT(SIE_GSLS, "gsls", SCLP_CONF_CHAR, 40, "SIE: Guest-storage-limit-suppression facility")
DEF_FEAT(ESOP, "esop", SCLP_CONF_CHAR, 46, "Enhanced-suppression-on-protection facility")
DEF_FEAT(HPMA2, "hpma2", SCLP_CONF_CHAR, 90, "Host page management assist 2 Facility") /* 91-2 */
DEF_FEAT(SIE_KSS, "kss", SCLP_CONF_CHAR, 151, "SIE: Keyless-subset facility") /* 98-7 */
/* Features exposed via SCLP SCCB Byte 116 - 119 (bit numbers relative to byte-116) */
DEF_FEAT(SIE_64BSCAO, "64bscao", SCLP_CONF_CHAR_EXT, 0, "SIE: 64-bit-SCAO facility")
DEF_FEAT(SIE_CMMA, "cmma", SCLP_CONF_CHAR_EXT, 1, "SIE: Collaborative-memory-management assist")
DEF_FEAT(SIE_PFMFI, "pfmfi", SCLP_CONF_CHAR_EXT, 9, "SIE: PFMF interpretation facility")
DEF_FEAT(SIE_IBS, "ibs", SCLP_CONF_CHAR_EXT, 10, "SIE: Interlock-and-broadcast-suppression facility")
/* Features exposed via SCLP CPU info. */
DEF_FEAT(SIE_F2, "sief2", SCLP_CPU, 4, "SIE: interception format 2 (Virtual SIE)")
DEF_FEAT(SIE_SKEY, "skey", SCLP_CPU, 5, "SIE: Storage-key facility")
DEF_FEAT(SIE_GPERE, "gpereh", SCLP_CPU, 10, "SIE: Guest-PER enhancement facility")
DEF_FEAT(SIE_SIIF, "siif", SCLP_CPU, 11, "SIE: Shared IPTE-interlock facility")
DEF_FEAT(SIE_SIGPIF, "sigpif", SCLP_CPU, 12, "SIE: SIGP interpretation facility")
DEF_FEAT(SIE_IB, "ib", SCLP_CPU, 42, "SIE: Intervention bypass facility")
DEF_FEAT(SIE_CEI, "cei", SCLP_CPU, 43, "SIE: Conditional-external-interception facility")
/*
* Features exposed via no feature bit (but e.g., instruction sensing)
* -> the feature bit number is irrelavant
*/
DEF_FEAT(DAT_ENH_2, "dateh2", MISC, 0, "DAT-enhancement facility 2")
DEF_FEAT(CMM, "cmm", MISC, 0, "Collaborative-memory-management facility")
DEF_FEAT(AP, "ap", MISC, 0, "AP instructions installed")
/* Features exposed via the PLO instruction. */
DEF_FEAT(PLO_CL, "plo-cl", PLO, 0, "PLO Compare and load (32 bit in general registers)")
DEF_FEAT(PLO_CLG, "plo-clg", PLO, 1, "PLO Compare and load (64 bit in parameter list)")
DEF_FEAT(PLO_CLGR, "plo-clgr", PLO, 2, "PLO Compare and load (32 bit in general registers)")
DEF_FEAT(PLO_CLX, "plo-clx", PLO, 3, "PLO Compare and load (128 bit in parameter list)")
DEF_FEAT(PLO_CS, "plo-cs", PLO, 4, "PLO Compare and swap (32 bit in general registers)")
DEF_FEAT(PLO_CSG, "plo-csg", PLO, 5, "PLO Compare and swap (64 bit in parameter list)")
DEF_FEAT(PLO_CSGR, "plo-csgr", PLO, 6, "PLO Compare and swap (32 bit in general registers)")
DEF_FEAT(PLO_CSX, "plo-csx", PLO, 7, "PLO Compare and swap (128 bit in parameter list)")
DEF_FEAT(PLO_DCS, "plo-dcs", PLO, 8, "PLO Double compare and swap (32 bit in general registers)")
DEF_FEAT(PLO_DCSG, "plo-dcsg", PLO, 9, "PLO Double compare and swap (64 bit in parameter list)")
DEF_FEAT(PLO_DCSGR, "plo-dcsgr", PLO, 10, "PLO Double compare and swap (32 bit in general registers)")
DEF_FEAT(PLO_DCSX, "plo-dcsx", PLO, 11, "PLO Double compare and swap (128 bit in parameter list)")
DEF_FEAT(PLO_CSST, "plo-csst", PLO, 12, "PLO Compare and swap and store (32 bit in general registers)")
DEF_FEAT(PLO_CSSTG, "plo-csstg", PLO, 13, "PLO Compare and swap and store (64 bit in parameter list)")
DEF_FEAT(PLO_CSSTGR, "plo-csstgr", PLO, 14, "PLO Compare and swap and store (32 bit in general registers)")
DEF_FEAT(PLO_CSSTX, "plo-csstx", PLO, 15, "PLO Compare and swap and store (128 bit in parameter list)")
DEF_FEAT(PLO_CSDST, "plo-csdst", PLO, 16, "PLO Compare and swap and double store (32 bit in general registers)")
DEF_FEAT(PLO_CSDSTG, "plo-csdstg", PLO, 17, "PLO Compare and swap and double store (64 bit in parameter list)")
DEF_FEAT(PLO_CSDSTGR, "plo-csdstgr", PLO, 18, "PLO Compare and swap and double store (32 bit in general registers)")
DEF_FEAT(PLO_CSDSTX, "plo-csdstx", PLO, 19, "PLO Compare and swap and double store (128 bit in parameter list)")
DEF_FEAT(PLO_CSTST, "plo-cstst", PLO, 20, "PLO Compare and swap and triple store (32 bit in general registers)")
DEF_FEAT(PLO_CSTSTG, "plo-cststg", PLO, 21, "PLO Compare and swap and triple store (64 bit in parameter list)")
DEF_FEAT(PLO_CSTSTGR, "plo-cststgr", PLO, 22, "PLO Compare and swap and triple store (32 bit in general registers)")
DEF_FEAT(PLO_CSTSTX, "plo-cststx", PLO, 23, "PLO Compare and swap and triple store (128 bit in parameter list)")
/* Features exposed via the PTFF instruction. */
DEF_FEAT(PTFF_QTO, "ptff-qto", PTFF, 1, "PTFF Query TOD Offset")
DEF_FEAT(PTFF_QSI, "ptff-qsi", PTFF, 2, "PTFF Query Steering Information")
DEF_FEAT(PTFF_QPT, "ptff-qpc", PTFF, 3, "PTFF Query Physical Clock")
DEF_FEAT(PTFF_QUI, "ptff-qui", PTFF, 4, "PTFF Query UTC Information")
DEF_FEAT(PTFF_QTOU, "ptff-qtou", PTFF, 5, "PTFF Query TOD Offset User")
DEF_FEAT(PTFF_QSIE, "ptff-qsie", PTFF, 10, "PTFF Query Steering Information Extended")
DEF_FEAT(PTFF_QTOUE, "ptff-qtoue", PTFF, 13, "PTFF Query TOD Offset User Extended")
DEF_FEAT(PTFF_STO, "ptff-sto", PTFF, 65, "PTFF Set TOD Offset")
DEF_FEAT(PTFF_STOU, "ptff-stou", PTFF, 69, "PTFF Set TOD Offset User")
DEF_FEAT(PTFF_STOE, "ptff-stoe", PTFF, 73, "PTFF Set TOD Offset Extended")
DEF_FEAT(PTFF_STOUE, "ptff-stoue", PTFF, 77, "PTFF Set TOD Offset User Extended")
/* Features exposed via the KMAC instruction. */
DEF_FEAT(KMAC_DEA, "kmac-dea", KMAC, 1, "KMAC DEA")
DEF_FEAT(KMAC_TDEA_128, "kmac-tdea-128", KMAC, 2, "KMAC TDEA-128")
DEF_FEAT(KMAC_TDEA_192, "kmac-tdea-192", KMAC, 3, "KMAC TDEA-192")
DEF_FEAT(KMAC_EDEA, "kmac-edea", KMAC, 9, "KMAC Encrypted-DEA")
DEF_FEAT(KMAC_ETDEA_128, "kmac-etdea-128", KMAC, 10, "KMAC Encrypted-TDEA-128")
DEF_FEAT(KMAC_ETDEA_192, "kmac-etdea-192", KMAC, 11, "KMAC Encrypted-TDEA-192")
DEF_FEAT(KMAC_AES_128, "kmac-aes-128", KMAC, 18, "KMAC AES-128")
DEF_FEAT(KMAC_AES_192, "kmac-aes-192", KMAC, 19, "KMAC AES-192")
DEF_FEAT(KMAC_AES_256, "kmac-aes-256", KMAC, 20, "KMAC AES-256")
DEF_FEAT(KMAC_EAES_128, "kmac-eaes-128", KMAC, 26, "KMAC Encrypted-AES-128")
DEF_FEAT(KMAC_EAES_192, "kmac-eaes-192", KMAC, 27, "KMAC Encrypted-AES-192")
DEF_FEAT(KMAC_EAES_256, "kmac-eaes-256", KMAC, 28, "KMAC Encrypted-AES-256")
/* Features exposed via the KMC instruction. */
DEF_FEAT(KMC_DEA, "kmc-dea", KMC, 1, "KMC DEA")
DEF_FEAT(KMC_TDEA_128, "kmc-tdea-128", KMC, 2, "KMC TDEA-128")
DEF_FEAT(KMC_TDEA_192, "kmc-tdea-192", KMC, 3, "KMC TDEA-192")
DEF_FEAT(KMC_EDEA, "kmc-edea", KMC, 9, "KMC Encrypted-DEA")
DEF_FEAT(KMC_ETDEA_128, "kmc-etdea-128", KMC, 10, "KMC Encrypted-TDEA-128")
DEF_FEAT(KMC_ETDEA_192, "kmc-etdea-192", KMC, 11, "KMC Encrypted-TDEA-192")
DEF_FEAT(KMC_AES_128, "kmc-aes-128", KMC, 18, "KMC AES-128")
DEF_FEAT(KMC_AES_192, "kmc-aes-192", KMC, 19, "KMC AES-192")
DEF_FEAT(KMC_AES_256, "kmc-aes-256", KMC, 20, "KMC AES-256")
DEF_FEAT(KMC_EAES_128, "kmc-eaes-128", KMC, 26, "KMC Encrypted-AES-128")
DEF_FEAT(KMC_EAES_192, "kmc-eaes-192", KMC, 27, "KMC Encrypted-AES-192")
DEF_FEAT(KMC_EAES_256, "kmc-eaes-256", KMC, 28, "KMC Encrypted-AES-256")
DEF_FEAT(KMC_PRNG, "kmc-prng", KMC, 67, "KMC PRNG")
/* Features exposed via the KM instruction. */
DEF_FEAT(KM_DEA, "km-dea", KM, 1, "KM DEA")
DEF_FEAT(KM_TDEA_128, "km-tdea-128", KM, 2, "KM TDEA-128")
DEF_FEAT(KM_TDEA_192, "km-tdea-192", KM, 3, "KM TDEA-192")
DEF_FEAT(KM_EDEA, "km-edea", KM, 9, "KM Encrypted-DEA")
DEF_FEAT(KM_ETDEA_128, "km-etdea-128", KM, 10, "KM Encrypted-TDEA-128")
DEF_FEAT(KM_ETDEA_192, "km-etdea-192", KM, 11, "KM Encrypted-TDEA-192")
DEF_FEAT(KM_AES_128, "km-aes-128", KM, 18, "KM AES-128")
DEF_FEAT(KM_AES_192, "km-aes-192", KM, 19, "KM AES-192")
DEF_FEAT(KM_AES_256, "km-aes-256", KM, 20, "KM AES-256")
DEF_FEAT(KM_EAES_128, "km-eaes-128", KM, 26, "KM Encrypted-AES-128")
DEF_FEAT(KM_EAES_192, "km-eaes-192", KM, 27, "KM Encrypted-AES-192")
DEF_FEAT(KM_EAES_256, "km-eaes-256", KM, 28, "KM Encrypted-AES-256")
DEF_FEAT(KM_XTS_AES_128, "km-xts-aes-128", KM, 50, "KM XTS-AES-128")
DEF_FEAT(KM_XTS_AES_256, "km-xts-aes-256", KM, 52, "KM XTS-AES-256")
DEF_FEAT(KM_XTS_EAES_128, "km-xts-eaes-128", KM, 58, "KM XTS-Encrypted-AES-128")
DEF_FEAT(KM_XTS_EAES_256, "km-xts-eaes-256", KM, 60, "KM XTS-Encrypted-AES-256")
/* Features exposed via the KIMD instruction. */
DEF_FEAT(KIMD_SHA_1, "kimd-sha-1", KIMD, 1, "KIMD SHA-1")
DEF_FEAT(KIMD_SHA_256, "kimd-sha-256", KIMD, 2, "KIMD SHA-256")
DEF_FEAT(KIMD_SHA_512, "kimd-sha-512", KIMD, 3, "KIMD SHA-512")
DEF_FEAT(KIMD_SHA3_224, "kimd-sha3-224", KIMD, 32, "KIMD SHA3-224")
DEF_FEAT(KIMD_SHA3_256, "kimd-sha3-256", KIMD, 33, "KIMD SHA3-256")
DEF_FEAT(KIMD_SHA3_384, "kimd-sha3-384", KIMD, 34, "KIMD SHA3-384")
DEF_FEAT(KIMD_SHA3_512, "kimd-sha3-512", KIMD, 35, "KIMD SHA3-512")
DEF_FEAT(KIMD_SHAKE_128, "kimd-shake-128", KIMD, 36, "KIMD SHAKE-128")
DEF_FEAT(KIMD_SHAKE_256, "kimd-shake-256", KIMD, 37, "KIMD SHAKE-256")
DEF_FEAT(KIMD_GHASH, "kimd-ghash", KIMD, 65, "KIMD GHASH")
/* Features exposed via the KLMD instruction. */
DEF_FEAT(KLMD_SHA_1, "klmd-sha-1", KLMD, 1, "KLMD SHA-1")
DEF_FEAT(KLMD_SHA_256, "klmd-sha-256", KLMD, 2, "KLMD SHA-256")
DEF_FEAT(KLMD_SHA_512, "klmd-sha-512", KLMD, 3, "KLMD SHA-512")
DEF_FEAT(KLMD_SHA3_224, "klmd-sha3-224", KLMD, 32, "KLMD SHA3-224")
DEF_FEAT(KLMD_SHA3_256, "klmd-sha3-256", KLMD, 33, "KLMD SHA3-256")
DEF_FEAT(KLMD_SHA3_384, "klmd-sha3-384", KLMD, 34, "KLMD SHA3-384")
DEF_FEAT(KLMD_SHA3_512, "klmd-sha3-512", KLMD, 35, "KLMD SHA3-512")
DEF_FEAT(KLMD_SHAKE_128, "klmd-shake-128", KLMD, 36, "KLMD SHAKE-128")
DEF_FEAT(KLMD_SHAKE_256, "klmd-shake-256", KLMD, 37, "KLMD SHAKE-256")
/* Features exposed via the PCKMO instruction. */
DEF_FEAT(PCKMO_EDEA, "pckmo-edea", PCKMO, 1, "PCKMO Encrypted-DEA-Key")
DEF_FEAT(PCKMO_ETDEA_128, "pckmo-etdea-128", PCKMO, 2, "PCKMO Encrypted-TDEA-128-Key")
DEF_FEAT(PCKMO_ETDEA_256, "pckmo-etdea-192", PCKMO, 3, "PCKMO Encrypted-TDEA-192-Key")
DEF_FEAT(PCKMO_AES_128, "pckmo-aes-128", PCKMO, 18, "PCKMO Encrypted-AES-128-Key")
DEF_FEAT(PCKMO_AES_192, "pckmo-aes-192", PCKMO, 19, "PCKMO Encrypted-AES-192-Key")
DEF_FEAT(PCKMO_AES_256, "pckmo-aes-256", PCKMO, 20, "PCKMO Encrypted-AES-256-Key")
DEF_FEAT(PCKMO_ECC_P256, "pckmo-ecc-p256", PCKMO, 32, "PCKMO Encrypt-ECC-P256-Key")
DEF_FEAT(PCKMO_ECC_P384, "pckmo-ecc-p384", PCKMO, 33, "PCKMO Encrypt-ECC-P384-Key")
DEF_FEAT(PCKMO_ECC_P521, "pckmo-ecc-p521", PCKMO, 34, "PCKMO Encrypt-ECC-P521-Key")
DEF_FEAT(PCKMO_ECC_ED25519, "pckmo-ecc-ed25519", PCKMO, 40 , "PCKMO Encrypt-ECC-Ed25519-Key")
DEF_FEAT(PCKMO_ECC_ED448, "pckmo-ecc-ed448", PCKMO, 41 , "PCKMO Encrypt-ECC-Ed448-Key")
/* Features exposed via the KMCTR instruction. */
DEF_FEAT(KMCTR_DEA, "kmctr-dea", KMCTR, 1, "KMCTR DEA")
DEF_FEAT(KMCTR_TDEA_128, "kmctr-tdea-128", KMCTR, 2, "KMCTR TDEA-128")
DEF_FEAT(KMCTR_TDEA_192, "kmctr-tdea-192", KMCTR, 3, "KMCTR TDEA-192")
DEF_FEAT(KMCTR_EDEA, "kmctr-edea", KMCTR, 9, "KMCTR Encrypted-DEA")
DEF_FEAT(KMCTR_ETDEA_128, "kmctr-etdea-128", KMCTR, 10, "KMCTR Encrypted-TDEA-128")
DEF_FEAT(KMCTR_ETDEA_192, "kmctr-etdea-192", KMCTR, 11, "KMCTR Encrypted-TDEA-192")
DEF_FEAT(KMCTR_AES_128, "kmctr-aes-128", KMCTR, 18, "KMCTR AES-128")
DEF_FEAT(KMCTR_AES_192, "kmctr-aes-192", KMCTR, 19, "KMCTR AES-192")
DEF_FEAT(KMCTR_AES_256, "kmctr-aes-256", KMCTR, 20, "KMCTR AES-256")
DEF_FEAT(KMCTR_EAES_128, "kmctr-eaes-128", KMCTR, 26, "KMCTR Encrypted-AES-128")
DEF_FEAT(KMCTR_EAES_192, "kmctr-eaes-192", KMCTR, 27, "KMCTR Encrypted-AES-192")
DEF_FEAT(KMCTR_EAES_256, "kmctr-eaes-256", KMCTR, 28, "KMCTR Encrypted-AES-256")
/* Features exposed via the KMF instruction. */
DEF_FEAT(KMF_DEA, "kmf-dea", KMF, 1, "KMF DEA")
DEF_FEAT(KMF_TDEA_128, "kmf-tdea-128", KMF, 2, "KMF TDEA-128")
DEF_FEAT(KMF_TDEA_192, "kmf-tdea-192", KMF, 3, "KMF TDEA-192")
DEF_FEAT(KMF_EDEA, "kmf-edea", KMF, 9, "KMF Encrypted-DEA")
DEF_FEAT(KMF_ETDEA_128, "kmf-etdea-128", KMF, 10, "KMF Encrypted-TDEA-128")
DEF_FEAT(KMF_ETDEA_192, "kmf-etdea-192", KMF, 11, "KMF Encrypted-TDEA-192")
DEF_FEAT(KMF_AES_128, "kmf-aes-128", KMF, 18, "KMF AES-128")
DEF_FEAT(KMF_AES_192, "kmf-aes-192", KMF, 19, "KMF AES-192")
DEF_FEAT(KMF_AES_256, "kmf-aes-256", KMF, 20, "KMF AES-256")
DEF_FEAT(KMF_EAES_128, "kmf-eaes-128", KMF, 26, "KMF Encrypted-AES-128")
DEF_FEAT(KMF_EAES_192, "kmf-eaes-192", KMF, 27, "KMF Encrypted-AES-192")
DEF_FEAT(KMF_EAES_256, "kmf-eaes-256", KMF, 28, "KMF Encrypted-AES-256")
/* Features exposed via the KMO instruction. */
DEF_FEAT(KMO_DEA, "kmo-dea", KMO, 1, "KMO DEA")
DEF_FEAT(KMO_TDEA_128, "kmo-tdea-128", KMO, 2, "KMO TDEA-128")
DEF_FEAT(KMO_TDEA_192, "kmo-tdea-192", KMO, 3, "KMO TDEA-192")
DEF_FEAT(KMO_EDEA, "kmo-edea", KMO, 9, "KMO Encrypted-DEA")
DEF_FEAT(KMO_ETDEA_128, "kmo-etdea-128", KMO, 10, "KMO Encrypted-TDEA-128")
DEF_FEAT(KMO_ETDEA_192, "kmo-etdea-192", KMO, 11, "KMO Encrypted-TDEA-192")
DEF_FEAT(KMO_AES_128, "kmo-aes-128", KMO, 18, "KMO AES-128")
DEF_FEAT(KMO_AES_192, "kmo-aes-192", KMO, 19, "KMO AES-192")
DEF_FEAT(KMO_AES_256, "kmo-aes-256", KMO, 20, "KMO AES-256")
DEF_FEAT(KMO_EAES_128, "kmo-eaes-128", KMO, 26, "KMO Encrypted-AES-128")
DEF_FEAT(KMO_EAES_192, "kmo-eaes-192", KMO, 27, "KMO Encrypted-AES-192")
DEF_FEAT(KMO_EAES_256, "kmo-eaes-256", KMO, 28, "KMO Encrypted-AES-256")
/* Features exposed via the PCC instruction. */
DEF_FEAT(PCC_CMAC_DEA, "pcc-cmac-dea", PCC, 1, "PCC Compute-Last-Block-CMAC-Using-DEA")
DEF_FEAT(PCC_CMAC_TDEA_128, "pcc-cmac-tdea-128", PCC, 2, "PCC Compute-Last-Block-CMAC-Using-TDEA-128")
DEF_FEAT(PCC_CMAC_TDEA_192, "pcc-cmac-tdea-192", PCC, 3, "PCC Compute-Last-Block-CMAC-Using-TDEA-192")
DEF_FEAT(PCC_CMAC_ETDEA_128, "pcc-cmac-edea", PCC, 9, "PCC Compute-Last-Block-CMAC-Using-Encrypted-DEA")
DEF_FEAT(PCC_CMAC_ETDEA_192, "pcc-cmac-etdea-128", PCC, 10, "PCC Compute-Last-Block-CMAC-Using-Encrypted-TDEA-128")
DEF_FEAT(PCC_CMAC_TDEA, "pcc-cmac-etdea-192", PCC, 11, "PCC Compute-Last-Block-CMAC-Using-EncryptedTDEA-192")
DEF_FEAT(PCC_CMAC_AES_128, "pcc-cmac-aes-128", PCC, 18, "PCC Compute-Last-Block-CMAC-Using-AES-128")
DEF_FEAT(PCC_CMAC_AES_192, "pcc-cmac-aes-192", PCC, 19, "PCC Compute-Last-Block-CMAC-Using-AES-192")
DEF_FEAT(PCC_CMAC_AES_256, "pcc-cmac-eaes-256", PCC, 20, "PCC Compute-Last-Block-CMAC-Using-AES-256")
DEF_FEAT(PCC_CMAC_EAES_128, "pcc-cmac-eaes-128", PCC, 26, "PCC Compute-Last-Block-CMAC-Using-Encrypted-AES-128")
DEF_FEAT(PCC_CMAC_EAES_192, "pcc-cmac-eaes-192", PCC, 27, "PCC Compute-Last-Block-CMAC-Using-Encrypted-AES-192")
DEF_FEAT(PCC_CMAC_EAES_256, "pcc-cmac-eaes-256", PCC, 28, "PCC Compute-Last-Block-CMAC-Using-Encrypted-AES-256")
DEF_FEAT(PCC_XTS_AES_128, "pcc-xts-aes-128", PCC, 50, "PCC Compute-XTS-Parameter-Using-AES-128")
DEF_FEAT(PCC_XTS_AES_256, "pcc-xts-aes-256", PCC, 52, "PCC Compute-XTS-Parameter-Using-AES-256")
DEF_FEAT(PCC_XTS_EAES_128, "pcc-xts-eaes-128", PCC, 58, "PCC Compute-XTS-Parameter-Using-Encrypted-AES-128")
DEF_FEAT(PCC_XTS_EAES_256, "pcc-xts-eaes-256", PCC, 60, "PCC Compute-XTS-Parameter-Using-Encrypted-AES-256")
DEF_FEAT(PCC_SCALAR_MULT_P256, "pcc-scalar-mult-p256", PCC, 64, "PCC Scalar-Multiply-P256")
DEF_FEAT(PCC_SCALAR_MULT_P384, "pcc-scalar-mult-p384", PCC, 65, "PCC Scalar-Multiply-P384")
DEF_FEAT(PCC_SCALAR_MULT_P512, "pcc-scalar-mult-p521", PCC, 66, "PCC Scalar-Multiply-P521")
DEF_FEAT(PCC_SCALAR_MULT_ED25519, "pcc-scalar-mult-ed25519", PCC, 72, "PCC Scalar-Multiply-Ed25519")
DEF_FEAT(PCC_SCALAR_MULT_ED448, "pcc-scalar-mult-ed448", PCC, 73, "PCC Scalar-Multiply-Ed448")
DEF_FEAT(PCC_SCALAR_MULT_X25519, "pcc-scalar-mult-x25519", PCC, 80, "PCC Scalar-Multiply-X25519")
DEF_FEAT(PCC_SCALAR_MULT_X448, "pcc-scalar-mult-x448", PCC, 81, "PCC Scalar-Multiply-X448")
/* Features exposed via the PPNO/PRNO instruction. */
DEF_FEAT(PPNO_SHA_512_DRNG, "ppno-sha-512-drng", PPNO, 3, "PPNO SHA-512-DRNG")
DEF_FEAT(PRNO_TRNG_QRTCR, "prno-trng-qrtcr", PPNO, 112, "PRNO TRNG-Query-Raw-to-Conditioned-Ratio")
DEF_FEAT(PRNO_TRNG, "prno-trng", PPNO, 114, "PRNO TRNG")
/* Features exposed via the KMA instruction. */
DEF_FEAT(KMA_GCM_AES_128, "kma-gcm-aes-128", KMA, 18, "KMA GCM-AES-128")
DEF_FEAT(KMA_GCM_AES_192, "kma-gcm-aes-192", KMA, 19, "KMA GCM-AES-192")
DEF_FEAT(KMA_GCM_AES_256, "kma-gcm-aes-256", KMA, 20, "KMA GCM-AES-256")
DEF_FEAT(KMA_GCM_EAES_128, "kma-gcm-eaes-128", KMA, 26, "KMA GCM-Encrypted-AES-128")
DEF_FEAT(KMA_GCM_EAES_192, "kma-gcm-eaes-192", KMA, 27, "KMA GCM-Encrypted-AES-192")
DEF_FEAT(KMA_GCM_EAES_256, "kma-gcm-eaes-256", KMA, 28, "KMA GCM-Encrypted-AES-256")
/* Features exposed via the KDSA instruction. */
DEF_FEAT(KDSA_ECDSA_VERIFY_P256, "kdsa-ecdsa-verify-p256", KDSA, 1, "KDSA ECDSA-Verify-P256")
DEF_FEAT(KDSA_ECDSA_VERIFY_P384, "kdsa-ecdsa-verify-p384", KDSA, 2, "KDSA ECDSA-Verify-P384")
DEF_FEAT(KDSA_ECDSA_VERIFY_P512, "kdsa-ecdsa-verify-p521", KDSA, 3, "KDSA ECDSA-Verify-P521")
DEF_FEAT(KDSA_ECDSA_SIGN_P256, "kdsa-ecdsa-sign-p256", KDSA, 9, "KDSA ECDSA-Sign-P256")
DEF_FEAT(KDSA_ECDSA_SIGN_P384, "kdsa-ecdsa-sign-p384", KDSA, 10, "KDSA ECDSA-Sign-P384")
DEF_FEAT(KDSA_ECDSA_SIGN_P512, "kdsa-ecdsa-sign-p521", KDSA, 11, "KDSA ECDSA-Sign-P521")
DEF_FEAT(KDSA_EECDSA_SIGN_P256, "kdsa-eecdsa-sign-p256", KDSA, 17, "KDSA Encrypted-ECDSA-Sign-P256")
DEF_FEAT(KDSA_EECDSA_SIGN_P384, "kdsa-eecdsa-sign-p384", KDSA, 18, "KDSA Encrypted-ECDSA-Sign-P384")
DEF_FEAT(KDSA_EECDSA_SIGN_P512, "kdsa-eecdsa-sign-p521", KDSA, 19, "KDSA Encrypted-ECDSA-Sign-P521")
DEF_FEAT(KDSA_EDDSA_VERIFY_ED25519, "kdsa-eddsa-verify-ed25519", KDSA, 32, "KDSA EdDSA-Verify-Ed25519")
DEF_FEAT(KDSA_EDDSA_VERIFY_ED448, "kdsa-eddsa-verify-ed448", KDSA, 36, "KDSA EdDSA-Verify-Ed448")
DEF_FEAT(KDSA_EDDSA_SIGN_ED25519, "kdsa-eddsa-sign-ed25519", KDSA, 40, "KDSA EdDSA-Sign-Ed25519")
DEF_FEAT(KDSA_EDDSA_SIGN_ED448, "kdsa-eddsa-sign-ed448", KDSA, 44, "KDSA EdDSA-Sign-Ed448")
DEF_FEAT(KDSA_EEDDSA_SIGN_ED25519, "kdsa-eeddsa-sign-ed25519", KDSA, 48, "KDSA Encrypted-EdDSA-Sign-Ed25519")
DEF_FEAT(KDSA_EEDDSA_SIGN_ED448, "kdsa-eeddsa-sign-ed448", KDSA, 52, "KDSA Encrypted-EdDSA-Sign-Ed448")
/* Features exposed via the SORTL instruction. */
DEF_FEAT(SORTL_SFLR, "sortl-sflr", SORTL, 1, "SORTL SFLR")
DEF_FEAT(SORTL_SVLR, "sortl-svlr", SORTL, 2, "SORTL SVLR")
DEF_FEAT(SORTL_32, "sortl-32", SORTL, 130, "SORTL 32 input lists")
DEF_FEAT(SORTL_128, "sortl-128", SORTL, 132, "SORTL 128 input lists")
DEF_FEAT(SORTL_F0, "sortl-f0", SORTL, 192, "SORTL format 0 parameter-block")
/* Features exposed via the DEFLATE instruction. */
DEF_FEAT(DEFLATE_GHDT, "dfltcc-gdht", DFLTCC, 1, "DFLTCC GDHT")
DEF_FEAT(DEFLATE_CMPR, "dfltcc-cmpr", DFLTCC, 2, "DFLTCC CMPR")
DEF_FEAT(DEFLATE_XPND, "dfltcc-xpnd", DFLTCC, 4, "DFLTCC XPND")
DEF_FEAT(DEFLATE_F0, "dfltcc-f0", DFLTCC, 192, "DFLTCC format 0 parameter-block")

View File

@ -0,0 +1,579 @@
/*
* CPU models for s390x
*
* Copyright 2016 IBM Corp.
*
* Author(s): David Hildenbrand <dahi@linux.vnet.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at
* your option) any later version. See the COPYING file in the top-level
* directory.
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
#include "sysemu/tcg.h"
#include "qemu-common.h"
//#include "hw/pci/pci.h"
#define CPUDEF_INIT(_type, _gen, _ec_ga, _mha_pow, _hmfai, _name, _desc) \
{ \
.name = _name, \
.type = _type, \
.gen = _gen, \
.ec_ga = _ec_ga, \
.mha_pow = _mha_pow, \
.hmfai = _hmfai, \
.desc = _desc, \
.base_init = { S390_FEAT_LIST_GEN ## _gen ## _GA ## _ec_ga ## _BASE }, \
.default_init = { S390_FEAT_LIST_GEN ## _gen ## _GA ## _ec_ga ## _DEFAULT }, \
.full_init = { S390_FEAT_LIST_GEN ## _gen ## _GA ## _ec_ga ## _FULL }, \
}
/*
* CPU definition list in order of release. Up to generation 14 base features
* of a following release have been a superset of the previous release. With
* generation 15 one base feature and one optional feature have been deprecated.
*/
static S390CPUDef s390_cpu_defs[] = {
CPUDEF_INIT(0x2064, 7, 1, 38, 0x00000000U, "z900", "IBM zSeries 900 GA1"),
CPUDEF_INIT(0x2064, 7, 2, 38, 0x00000000U, "z900.2", "IBM zSeries 900 GA2"),
CPUDEF_INIT(0x2064, 7, 3, 38, 0x00000000U, "z900.3", "IBM zSeries 900 GA3"),
CPUDEF_INIT(0x2066, 7, 3, 38, 0x00000000U, "z800", "IBM zSeries 800 GA1"),
CPUDEF_INIT(0x2084, 8, 1, 38, 0x00000000U, "z990", "IBM zSeries 990 GA1"),
CPUDEF_INIT(0x2084, 8, 2, 38, 0x00000000U, "z990.2", "IBM zSeries 990 GA2"),
CPUDEF_INIT(0x2084, 8, 3, 38, 0x00000000U, "z990.3", "IBM zSeries 990 GA3"),
CPUDEF_INIT(0x2086, 8, 3, 38, 0x00000000U, "z890", "IBM zSeries 880 GA1"),
CPUDEF_INIT(0x2084, 8, 4, 38, 0x00000000U, "z990.4", "IBM zSeries 990 GA4"),
CPUDEF_INIT(0x2086, 8, 4, 38, 0x00000000U, "z890.2", "IBM zSeries 880 GA2"),
CPUDEF_INIT(0x2084, 8, 5, 38, 0x00000000U, "z990.5", "IBM zSeries 990 GA5"),
CPUDEF_INIT(0x2086, 8, 5, 38, 0x00000000U, "z890.3", "IBM zSeries 880 GA3"),
CPUDEF_INIT(0x2094, 9, 1, 40, 0x00000000U, "z9EC", "IBM System z9 EC GA1"),
CPUDEF_INIT(0x2094, 9, 2, 40, 0x00000000U, "z9EC.2", "IBM System z9 EC GA2"),
CPUDEF_INIT(0x2096, 9, 2, 40, 0x00000000U, "z9BC", "IBM System z9 BC GA1"),
CPUDEF_INIT(0x2094, 9, 3, 40, 0x00000000U, "z9EC.3", "IBM System z9 EC GA3"),
CPUDEF_INIT(0x2096, 9, 3, 40, 0x00000000U, "z9BC.2", "IBM System z9 BC GA2"),
CPUDEF_INIT(0x2097, 10, 1, 43, 0x00000000U, "z10EC", "IBM System z10 EC GA1"),
CPUDEF_INIT(0x2097, 10, 2, 43, 0x00000000U, "z10EC.2", "IBM System z10 EC GA2"),
CPUDEF_INIT(0x2098, 10, 2, 43, 0x00000000U, "z10BC", "IBM System z10 BC GA1"),
CPUDEF_INIT(0x2097, 10, 3, 43, 0x00000000U, "z10EC.3", "IBM System z10 EC GA3"),
CPUDEF_INIT(0x2098, 10, 3, 43, 0x00000000U, "z10BC.2", "IBM System z10 BC GA2"),
CPUDEF_INIT(0x2817, 11, 1, 44, 0x08000000U, "z196", "IBM zEnterprise 196 GA1"),
CPUDEF_INIT(0x2817, 11, 2, 44, 0x08000000U, "z196.2", "IBM zEnterprise 196 GA2"),
CPUDEF_INIT(0x2818, 11, 2, 44, 0x08000000U, "z114", "IBM zEnterprise 114 GA1"),
CPUDEF_INIT(0x2827, 12, 1, 44, 0x08000000U, "zEC12", "IBM zEnterprise EC12 GA1"),
CPUDEF_INIT(0x2827, 12, 2, 44, 0x08000000U, "zEC12.2", "IBM zEnterprise EC12 GA2"),
CPUDEF_INIT(0x2828, 12, 2, 44, 0x08000000U, "zBC12", "IBM zEnterprise BC12 GA1"),
CPUDEF_INIT(0x2964, 13, 1, 47, 0x08000000U, "z13", "IBM z13 GA1"),
CPUDEF_INIT(0x2964, 13, 2, 47, 0x08000000U, "z13.2", "IBM z13 GA2"),
CPUDEF_INIT(0x2965, 13, 2, 47, 0x08000000U, "z13s", "IBM z13s GA1"),
CPUDEF_INIT(0x3906, 14, 1, 47, 0x08000000U, "z14", "IBM z14 GA1"),
CPUDEF_INIT(0x3906, 14, 2, 47, 0x08000000U, "z14.2", "IBM z14 GA2"),
CPUDEF_INIT(0x3907, 14, 1, 47, 0x08000000U, "z14ZR1", "IBM z14 Model ZR1 GA1"),
CPUDEF_INIT(0x8561, 15, 1, 47, 0x08000000U, "gen15a", "IBM z15 GA1"),
CPUDEF_INIT(0x8562, 15, 1, 47, 0x08000000U, "gen15b", "IBM 8562 GA1"),
};
#define QEMU_MAX_CPU_TYPE 0x2964
#define QEMU_MAX_CPU_GEN 13
#define QEMU_MAX_CPU_EC_GA 2
static const S390FeatInit qemu_max_cpu_feat_init = { S390_FEAT_LIST_QEMU_MAX };
static S390FeatBitmap qemu_max_cpu_feat;
/* features part of a base model but not relevant for finding a base model */
S390FeatBitmap ignored_base_feat;
void s390_cpudef_featoff(uint8_t gen, uint8_t ec_ga, S390Feat feat)
{
const S390CPUDef *def;
def = s390_find_cpu_def(0, gen, ec_ga, NULL);
clear_bit(feat, (unsigned long *)&def->default_feat);
}
void s390_cpudef_featoff_greater(uint8_t gen, uint8_t ec_ga, S390Feat feat)
{
int i;
for (i = 0; i < ARRAY_SIZE(s390_cpu_defs); i++) {
const S390CPUDef *def = &s390_cpu_defs[i];
if (def->gen < gen) {
continue;
}
if (def->gen == gen && def->ec_ga < ec_ga) {
continue;
}
clear_bit(feat, (unsigned long *)&def->default_feat);
}
}
void s390_cpudef_group_featoff_greater(uint8_t gen, uint8_t ec_ga,
S390FeatGroup group)
{
const S390FeatGroupDef *group_def = s390_feat_group_def(group);
S390FeatBitmap group_def_off;
int i;
bitmap_complement(group_def_off, group_def->feat, S390_FEAT_MAX);
for (i = 0; i < ARRAY_SIZE(s390_cpu_defs); i++) {
const S390CPUDef *cpu_def = &s390_cpu_defs[i];
if (cpu_def->gen < gen) {
continue;
}
if (cpu_def->gen == gen && cpu_def->ec_ga < ec_ga) {
continue;
}
bitmap_and((unsigned long *)&cpu_def->default_feat,
cpu_def->default_feat, group_def_off, S390_FEAT_MAX);
}
}
uint32_t s390_get_hmfai(void)
{
static S390CPU *cpu;
if (!cpu) {
cpu = S390_CPU(qemu_get_cpu(NULL, 0));
}
if (!cpu || !cpu->model) {
return 0;
}
return cpu->model->def->hmfai;
}
uint8_t s390_get_mha_pow(void)
{
static S390CPU *cpu;
if (!cpu) {
cpu = S390_CPU(qemu_get_cpu(NULL, 0));
}
if (!cpu || !cpu->model) {
return 0;
}
return cpu->model->def->mha_pow;
}
uint32_t s390_get_ibc_val(void)
{
uint16_t unblocked_ibc, lowest_ibc;
static S390CPU *cpu;
if (!cpu) {
cpu = S390_CPU(qemu_get_cpu(NULL, 0));
}
if (!cpu || !cpu->model) {
return 0;
}
unblocked_ibc = s390_ibc_from_cpu_model(cpu->model);
lowest_ibc = cpu->model->lowest_ibc;
/* the lowest_ibc always has to be <= unblocked_ibc */
if (!lowest_ibc || lowest_ibc > unblocked_ibc) {
return 0;
}
return ((uint32_t) lowest_ibc << 16) | unblocked_ibc;
}
void s390_get_feat_block(struct uc_struct *uc, S390FeatType type, uint8_t *data)
{
S390CPU *cpu = S390_CPU(qemu_get_cpu(uc, 0));
s390_fill_feat_block(cpu->model->features, type, data);
}
bool s390_has_feat(struct uc_struct *uc, S390Feat feat)
{
S390CPU *cpu = S390_CPU(qemu_get_cpu(uc, 0));
if (!cpu->model) {
if (feat == S390_FEAT_ZPCI) {
return true;
}
return false;
}
return test_bit(feat, cpu->model->features);
}
uint8_t s390_get_gen_for_cpu_type(uint16_t type)
{
int i;
for (i = 0; i < ARRAY_SIZE(s390_cpu_defs); i++) {
if (s390_cpu_defs[i].type == type) {
return s390_cpu_defs[i].gen;
}
}
return 0;
}
const S390CPUDef *s390_find_cpu_def(uint16_t type, uint8_t gen, uint8_t ec_ga,
S390FeatBitmap features)
{
const S390CPUDef *last_compatible = NULL;
const S390CPUDef *matching_cpu_type = NULL;
int i;
if (!gen) {
ec_ga = 0;
}
if (!gen && type) {
gen = s390_get_gen_for_cpu_type(type);
}
for (i = 0; i < ARRAY_SIZE(s390_cpu_defs); i++) {
const S390CPUDef *def = &s390_cpu_defs[i];
S390FeatBitmap missing;
/* don't even try newer generations if we know the generation */
if (gen) {
if (def->gen > gen) {
break;
} else if (def->gen == gen && ec_ga && def->ec_ga > ec_ga) {
break;
}
}
if (features) {
/* see if the model satisfies the minimum features */
bitmap_andnot(missing, def->base_feat, features, S390_FEAT_MAX);
/*
* Ignore certain features that are in the base model, but not
* relevant for the search (esp. MSA subfunctions).
*/
bitmap_andnot(missing, missing, ignored_base_feat, S390_FEAT_MAX);
if (!bitmap_empty(missing, S390_FEAT_MAX)) {
break;
}
}
/* stop the search if we found the exact model */
if (def->type == type && def->ec_ga == ec_ga) {
return def;
}
/* remember if we've at least seen one with the same cpu type */
if (def->type == type) {
matching_cpu_type = def;
}
last_compatible = def;
}
/* prefer the model with the same cpu type, esp. don't take the BC for EC */
if (matching_cpu_type) {
return matching_cpu_type;
}
return last_compatible;
}
static S390CPUModel *get_max_cpu_model(void);
static S390CPUModel *get_max_cpu_model(void)
{
static S390CPUModel max_model;
static bool cached;
if (cached) {
return &max_model;
}
max_model.def = s390_find_cpu_def(QEMU_MAX_CPU_TYPE, QEMU_MAX_CPU_GEN,
QEMU_MAX_CPU_EC_GA, NULL);
bitmap_copy(max_model.features, qemu_max_cpu_feat, S390_FEAT_MAX);
cached = true;
return &max_model;
}
static inline void apply_cpu_model(const S390CPUModel *model)
{
static S390CPUModel applied_model;
static bool applied;
/*
* We have the same model for all VCPUs. KVM can only be configured before
* any VCPUs are defined in KVM.
*/
if (applied) {
if (model && memcmp(&applied_model, model, sizeof(S390CPUModel))) {
// error_setg(errp, "Mixed CPU models are not supported on s390x.");
}
return;
}
applied = true;
if (model) {
applied_model = *model;
}
}
void s390_realize_cpu_model(CPUState *cs)
{
S390CPU *cpu = S390_CPU(cs);
const S390CPUModel *max_model;
if (!cpu->model) {
/* no host model support -> perform compatibility stuff */
apply_cpu_model(NULL);
return;
}
max_model = get_max_cpu_model();
if (!max_model) {
//error_prepend(errp, "CPU models are not available: ");
return;
}
/* copy over properties that can vary */
cpu->model->lowest_ibc = max_model->lowest_ibc;
cpu->model->cpu_id = max_model->cpu_id;
cpu->model->cpu_id_format = max_model->cpu_id_format;
cpu->model->cpu_ver = max_model->cpu_ver;
apply_cpu_model(cpu->model);
cpu->env.cpuid = s390_cpuid_from_cpu_model(cpu->model);
/* basic mode, write the cpu address into the first 4 bit of the ID */
cpu->env.cpuid = deposit64(cpu->env.cpuid, 54, 4, cpu->env.core_id);
}
static void s390_cpu_model_initfn(CPUState *obj)
{
S390CPU *cpu = S390_CPU(obj);
S390CPUClass *xcc = S390_CPU_GET_CLASS(cpu);
cpu->model = g_malloc0(sizeof(*cpu->model));
/* copy the model, so we can modify it */
cpu->model->def = xcc->cpu_def;
if (xcc->is_static) {
/* base model - features will never change */
bitmap_copy(cpu->model->features, cpu->model->def->base_feat,
S390_FEAT_MAX);
} else {
/* latest model - features can change */
bitmap_copy(cpu->model->features,
cpu->model->def->default_feat, S390_FEAT_MAX);
}
}
static S390CPUDef s390_qemu_cpu_def;
static S390CPUModel s390_qemu_cpu_model;
/* Set the qemu CPU model (on machine initialization). Must not be called
* once CPUs have been created.
*/
void s390_set_qemu_cpu_model(uint16_t type, uint8_t gen, uint8_t ec_ga,
const S390FeatInit feat_init)
{
const S390CPUDef *def = s390_find_cpu_def(type, gen, ec_ga, NULL);
g_assert(def);
//g_assert(QTAILQ_EMPTY_RCU(&cpus));
/* TCG emulates some features that can usually not be enabled with
* the emulated machine generation. Make sure they can be enabled
* when using the QEMU model by adding them to full_feat. We have
* to copy the definition to do that.
*/
memcpy(&s390_qemu_cpu_def, def, sizeof(s390_qemu_cpu_def));
bitmap_or(s390_qemu_cpu_def.full_feat, s390_qemu_cpu_def.full_feat,
qemu_max_cpu_feat, S390_FEAT_MAX);
/* build the CPU model */
s390_qemu_cpu_model.def = &s390_qemu_cpu_def;
bitmap_zero(s390_qemu_cpu_model.features, S390_FEAT_MAX);
s390_init_feat_bitmap(feat_init, s390_qemu_cpu_model.features);
}
static void s390_qemu_cpu_model_initfn(CPUState *obj)
{
S390CPU *cpu = S390_CPU(obj);
cpu->model = g_malloc0(sizeof(*cpu->model));
/* copy the CPU model so we can modify it */
memcpy(cpu->model, &s390_qemu_cpu_model, sizeof(*cpu->model));
}
static void s390_max_cpu_model_initfn(CPUState *obj)
{
const S390CPUModel *max_model;
S390CPU *cpu = S390_CPU(obj);
max_model = get_max_cpu_model();
cpu->model = g_new(S390CPUModel, 1);
/* copy the CPU model so we can modify it */
memcpy(cpu->model, max_model, sizeof(*cpu->model));
}
static void s390_cpu_model_finalize(CPUState *obj)
{
S390CPU *cpu = S390_CPU(obj);
g_free(cpu->model);
cpu->model = NULL;
}
static void s390_base_cpu_model_class_init(struct uc_struct *uc, CPUClass *oc, void *data)
{
S390CPUClass *xcc = S390_CPU_CLASS(oc);
/* all base models are migration safe */
xcc->cpu_def = (const S390CPUDef *) data;
xcc->is_static = true;
//xcc->desc = xcc->cpu_def->desc;
}
static void s390_cpu_model_class_init(struct uc_struct *uc, CPUClass *oc, void *data)
{
S390CPUClass *xcc = S390_CPU_CLASS(oc);
/* model that can change between QEMU versions */
xcc->cpu_def = (const S390CPUDef *) data;
//xcc->desc = xcc->cpu_def->desc;
}
static void s390_qemu_cpu_model_class_init(struct uc_struct *uc, CPUClass *oc, void *data)
{
//S390CPUClass *xcc = S390_CPU_CLASS(oc);
//xcc->desc = g_strdup_printf("QEMU Virtual CPU version %s",
// qemu_hw_version());
}
static void s390_max_cpu_model_class_init(struct uc_struct *uc, CPUClass *oc, void *data)
{
//S390CPUClass *xcc = S390_CPU_CLASS(oc);
/*
* The "max" model is neither static nor migration safe. Under KVM
* it represents the "host" model. Under TCG it represents some kind of
* "qemu" CPU model without compat handling and maybe with some additional
* CPU features that are not yet unlocked in the "qemu" model.
*/
//xcc->desc =
// "Enables all features supported by the accelerator in the current host";
}
#if 0
/* Generate type name for a cpu model. Caller has to free the string. */
static char *s390_cpu_type_name(const char *model_name)
{
return g_strdup_printf(S390_CPU_TYPE_NAME("%s"), model_name);
}
/* Generate type name for a base cpu model. Caller has to free the string. */
static char *s390_base_cpu_type_name(const char *model_name)
{
return g_strdup_printf(S390_CPU_TYPE_NAME("%s-base"), model_name);
}
CPUClass *s390_cpu_class_by_name(const char *name)
{
char *typename = s390_cpu_type_name(name);
CPUClass *oc;
oc = object_class_by_name(typename);
g_free(typename);
return oc;
}
static const TypeInfo qemu_s390_cpu_type_info = {
//.name = S390_CPU_TYPE_NAME("qemu"),
.parent = TYPE_S390_CPU,
.instance_init = s390_qemu_cpu_model_initfn,
.instance_finalize = s390_cpu_model_finalize,
.class_init = s390_qemu_cpu_model_class_init,
};
static const TypeInfo max_s390_cpu_type_info = {
//.name = S390_CPU_TYPE_NAME("max"),
.parent = TYPE_S390_CPU,
.instance_init = s390_max_cpu_model_initfn,
.instance_finalize = s390_cpu_model_finalize,
.class_init = s390_max_cpu_model_class_init,
};
#endif
static void init_ignored_base_feat(void)
{
static const int feats[] = {
/* MSA subfunctions that could not be available on certain machines */
S390_FEAT_KMAC_DEA,
S390_FEAT_KMAC_TDEA_128,
S390_FEAT_KMAC_TDEA_192,
S390_FEAT_KMC_DEA,
S390_FEAT_KMC_TDEA_128,
S390_FEAT_KMC_TDEA_192,
S390_FEAT_KM_DEA,
S390_FEAT_KM_TDEA_128,
S390_FEAT_KM_TDEA_192,
S390_FEAT_KIMD_SHA_1,
S390_FEAT_KLMD_SHA_1,
/* CSSKE is deprecated on newer generations */
S390_FEAT_CONDITIONAL_SSKE,
};
int i;
for (i = 0; i < ARRAY_SIZE(feats); i++) {
set_bit(feats[i], ignored_base_feat);
}
}
static void register_types(void)
{
#if 0
static const S390FeatInit qemu_latest_init = { S390_FEAT_LIST_QEMU_LATEST };
int i;
init_ignored_base_feat();
/* init all bitmaps from gnerated data initially */
s390_init_feat_bitmap(qemu_max_cpu_feat_init, qemu_max_cpu_feat);
for (i = 0; i < ARRAY_SIZE(s390_cpu_defs); i++) {
s390_init_feat_bitmap(s390_cpu_defs[i].base_init,
s390_cpu_defs[i].base_feat);
s390_init_feat_bitmap(s390_cpu_defs[i].default_init,
s390_cpu_defs[i].default_feat);
s390_init_feat_bitmap(s390_cpu_defs[i].full_init,
s390_cpu_defs[i].full_feat);
}
/* initialize the qemu model with latest definition */
s390_set_qemu_cpu_model(QEMU_MAX_CPU_TYPE, QEMU_MAX_CPU_GEN,
QEMU_MAX_CPU_EC_GA, qemu_latest_init);
for (i = 0; i < ARRAY_SIZE(s390_cpu_defs); i++) {
char *base_name = s390_base_cpu_type_name(s390_cpu_defs[i].name);
TypeInfo ti_base = {
.name = base_name,
.parent = TYPE_S390_CPU,
.instance_init = s390_cpu_model_initfn,
.instance_finalize = s390_cpu_model_finalize,
.class_init = s390_base_cpu_model_class_init,
.class_data = (void *) &s390_cpu_defs[i],
};
char *name = s390_cpu_type_name(s390_cpu_defs[i].name);
TypeInfo ti = {
.name = name,
.parent = TYPE_S390_CPU,
.instance_init = s390_cpu_model_initfn,
.instance_finalize = s390_cpu_model_finalize,
.class_init = s390_cpu_model_class_init,
.class_data = (void *) &s390_cpu_defs[i],
};
type_register_static(&ti_base);
type_register_static(&ti);
g_free(base_name);
g_free(name);
}
type_register_static(&qemu_s390_cpu_type_info);
type_register_static(&max_s390_cpu_type_info);
#endif
}

View File

@ -0,0 +1,109 @@
/*
* CPU models for s390x
*
* Copyright 2016 IBM Corp.
*
* Author(s): David Hildenbrand <dahi@linux.vnet.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at
* your option) any later version. See the COPYING file in the top-level
* directory.
*/
#ifndef TARGET_S390X_CPU_MODELS_H
#define TARGET_S390X_CPU_MODELS_H
#include "cpu_features.h"
#include "gen-features.h"
#include "hw/core/cpu.h"
/* static CPU definition */
struct S390CPUDef {
const char *name; /* name exposed to the user */
const char *desc; /* description exposed to the user */
uint8_t gen; /* hw generation identification */
uint16_t type; /* cpu type identification */
uint8_t ec_ga; /* EC GA version (on which also the BC is based) */
uint8_t mha_pow; /* Maximum Host Adress Power, mha = 2^pow-1 */
uint32_t hmfai; /* hypervisor-managed facilities */
/* base/min features, must never be changed between QEMU versions */
S390FeatBitmap base_feat;
/* used to init base_feat from generated data */
S390FeatInit base_init;
/* deafault features, QEMU version specific */
S390FeatBitmap default_feat;
/* used to init default_feat from generated data */
S390FeatInit default_init;
/* max allowed features, QEMU version specific */
S390FeatBitmap full_feat;
/* used to init full_feat from generated data */
S390FeatInit full_init;
};
/* CPU model based on a CPU definition */
struct S390CPUModel {
const S390CPUDef *def;
S390FeatBitmap features;
/* values copied from the "host" model, can change during migration */
uint16_t lowest_ibc; /* lowest IBC that the hardware supports */
uint32_t cpu_id; /* CPU id */
uint8_t cpu_id_format; /* CPU id format bit */
uint8_t cpu_ver; /* CPU version, usually "ff" for kvm */
};
/*
* CPU ID
*
* bits 0-7: Zeroes (ff for kvm)
* bits 8-31: CPU ID (serial number)
* bits 32-47: Machine type
* bit 48: CPU ID format
* bits 49-63: Zeroes
*/
#define cpuid_type(x) (((x) >> 16) & 0xffff)
#define cpuid_id(x) (((x) >> 32) & 0xffffff)
#define cpuid_ver(x) (((x) >> 56) & 0xff)
#define cpuid_format(x) (((x) >> 15) & 0x1)
#define lowest_ibc(x) (((uint32_t)(x) >> 16) & 0xfff)
#define unblocked_ibc(x) ((uint32_t)(x) & 0xfff)
#define has_ibc(x) (lowest_ibc(x) != 0)
#define S390_GEN_Z10 0xa
#define ibc_gen(x) (x == 0 ? 0 : ((x >> 4) + S390_GEN_Z10))
#define ibc_ec_ga(x) (x & 0xf)
void s390_cpudef_featoff(uint8_t gen, uint8_t ec_ga, S390Feat feat);
void s390_cpudef_featoff_greater(uint8_t gen, uint8_t ec_ga, S390Feat feat);
void s390_cpudef_group_featoff_greater(uint8_t gen, uint8_t ec_ga,
S390FeatGroup group);
uint32_t s390_get_hmfai(void);
uint8_t s390_get_mha_pow(void);
uint32_t s390_get_ibc_val(void);
static inline uint16_t s390_ibc_from_cpu_model(const S390CPUModel *model)
{
uint16_t ibc = 0;
if (model->def->gen >= S390_GEN_Z10) {
ibc = ((model->def->gen - S390_GEN_Z10) << 4) + model->def->ec_ga;
}
return ibc;
}
void s390_get_feat_block(struct uc_struct *uc, S390FeatType type, uint8_t *data);
bool s390_has_feat(struct uc_struct *uc, S390Feat feat);
uint8_t s390_get_gen_for_cpu_type(uint16_t type);
static inline bool s390_known_cpu_type(uint16_t type)
{
return s390_get_gen_for_cpu_type(type) != 0;
}
static inline uint64_t s390_cpuid_from_cpu_model(const S390CPUModel *model)
{
return ((uint64_t)model->cpu_ver << 56) |
((uint64_t)model->cpu_id << 32) |
((uint64_t)model->def->type << 16) |
(model->def->gen == 7 ? 0 : (uint64_t)model->cpu_id_format << 15);
}
S390CPUDef const *s390_find_cpu_def(uint16_t type, uint8_t gen, uint8_t ec_ga,
S390FeatBitmap features);
#endif /* TARGET_S390X_CPU_MODELS_H */

View File

@ -0,0 +1,60 @@
/*
* s390x crypto helpers
*
* Copyright (c) 2017 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 "internal.h"
#include "tcg_s390x.h"
#include "exec/helper-proto.h"
#include "exec/exec-all.h"
#include "exec/cpu_ldst.h"
uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3,
uint32_t type)
{
const uintptr_t ra = GETPC();
const uint8_t mod = env->regs[0] & 0x80ULL;
const uint8_t fc = env->regs[0] & 0x7fULL;
uint8_t subfunc[16] = { 0 };
uint64_t param_addr;
int i;
switch (type) {
case S390_FEAT_TYPE_KMAC:
case S390_FEAT_TYPE_KIMD:
case S390_FEAT_TYPE_KLMD:
case S390_FEAT_TYPE_PCKMO:
case S390_FEAT_TYPE_PCC:
if (mod) {
tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
}
break;
}
s390_get_feat_block(env->uc, type, subfunc);
if (!test_be_bit(fc, subfunc)) {
tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
}
switch (fc) {
case 0: /* query subfunction */
for (i = 0; i < 16; i++) {
param_addr = wrap_address(env, env->regs[1] + i);
cpu_stb_data_ra(env, param_addr, subfunc[i], ra);
}
break;
default:
/* we don't implement any other subfunction yet */
g_assert_not_reached();
}
return 0;
}

View File

@ -0,0 +1,600 @@
/*
* s390x exception / interrupt helpers
*
* Copyright (c) 2009 Ulrich Hecht
* Copyright (c) 2011 Alexander Graf
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#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"
#include "sysemu/sysemu.h"
//#include "hw/s390x/s390_flic.h"
void QEMU_NORETURN tcg_s390_program_interrupt(CPUS390XState *env,
uint32_t code, uintptr_t ra)
{
CPUState *cs = env_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);
cpu_loop_exit(cs);
}
void QEMU_NORETURN tcg_s390_data_exception(CPUS390XState *env, uint32_t dxc,
uintptr_t ra)
{
g_assert(dxc <= 0xff);
/* Store the DXC into the lowcore */
#ifdef UNICORN_ARCH_POSTFIX
glue(stl_phys, UNICORN_ARCH_POSTFIX)(env->uc, env_cpu(env)->as,
env->psa + offsetof(LowCore, data_exc_code), dxc);
#else
stl_phys(env->uc, env_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, ra);
}
void QEMU_NORETURN tcg_s390_vector_exception(CPUS390XState *env, uint32_t vxc,
uintptr_t ra)
{
g_assert(vxc <= 0xff);
/* Always store the VXC into the lowcore, without AFP it is undefined */
#ifdef UNICORN_ARCH_POSTFIX
glue(stl_phys, UNICORN_ARCH_POSTFIX)(env->uc, env_cpu(env)->as,
env->psa + offsetof(LowCore, data_exc_code), vxc);
#else
stl_phys(env->uc, env_cpu(env)->as,
env->psa + offsetof(LowCore, data_exc_code), vxc);
#endif
/* Always store the VXC into the FPC, without AFP it is undefined */
env->fpc = deposit32(env->fpc, 8, 8, vxc);
tcg_s390_program_interrupt(env, PGM_VECTOR_PROCESSING, ra);
}
void HELPER(data_exception)(CPUS390XState *env, uint32_t dxc)
{
tcg_s390_data_exception(env, dxc, GETPC());
}
static inline uint64_t cpu_mmu_idx_to_asc(int mmu_idx)
{
switch (mmu_idx) {
case MMU_PRIMARY_IDX:
return PSW_ASC_PRIMARY;
case MMU_SECONDARY_IDX:
return PSW_ASC_SECONDARY;
case MMU_HOME_IDX:
return PSW_ASC_HOME;
default:
abort();
}
}
bool s390_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
MMUAccessType access_type, int mmu_idx,
bool probe, uintptr_t retaddr)
{
S390CPU *cpu = S390_CPU(cs);
CPUS390XState *env = &cpu->env;
target_ulong vaddr, raddr;
uint64_t asc, tec;
int prot, excp;
//qemu_log_mask(CPU_LOG_MMU, "%s: addr 0x%" VADDR_PRIx " rw %d mmu_idx %d\n",
// __func__, address, access_type, mmu_idx);
vaddr = address;
if (mmu_idx < MMU_REAL_IDX) {
asc = cpu_mmu_idx_to_asc(mmu_idx);
/* 31-Bit mode */
if (!(env->psw.mask & PSW_MASK_64)) {
vaddr &= 0x7fffffff;
}
excp = mmu_translate(env, vaddr, access_type, asc, &raddr, &prot, &tec);
} else if (mmu_idx == MMU_REAL_IDX) {
/* 31-Bit mode */
if (!(env->psw.mask & PSW_MASK_64)) {
vaddr &= 0x7fffffff;
}
excp = mmu_translate_real(env, vaddr, access_type, &raddr, &prot, &tec);
} else {
g_assert_not_reached();
}
/* check out of RAM access */
if (!excp &&
!address_space_access_valid(env_cpu(env)->as, raddr,
TARGET_PAGE_SIZE, access_type,
MEMTXATTRS_UNSPECIFIED)) {
//qemu_log_mask(CPU_LOG_MMU,
// "%s: raddr %" PRIx64 " > ram_size %" PRIx64 "\n",
// __func__, (uint64_t)raddr, (uint64_t)ram_size);
excp = PGM_ADDRESSING;
tec = 0; /* unused */
}
if (!excp) {
//qemu_log_mask(CPU_LOG_MMU,
// "%s: set tlb %" PRIx64 " -> %" PRIx64 " (%x)\n",
// __func__, (uint64_t)vaddr, (uint64_t)raddr, prot);
tlb_set_page(cs, address & TARGET_PAGE_MASK, raddr, prot,
mmu_idx, TARGET_PAGE_SIZE);
return true;
}
if (probe) {
return false;
}
if (excp != PGM_ADDRESSING) {
#ifdef UNICORN_ARCH_POSTFIX
glue(stq_phys, UNICORN_ARCH_POSTFIX)(cs->uc, env_cpu(env)->as,
env->psa + offsetof(LowCore, trans_exc_code), tec);
#else
stq_phys(cs->uc, env_cpu(env)->as,
env->psa + offsetof(LowCore, trans_exc_code), tec);
#endif
}
/*
* For data accesses, ILEN will be filled in from the unwind info,
* within cpu_loop_exit_restore. For code accesses, retaddr == 0,
* and so unwinding will not occur. However, ILEN is also undefined
* for that case -- we choose to set ILEN = 2.
*/
env->int_pgm_ilen = 2;
trigger_pgm_exception(env, excp);
cpu_loop_exit_restore(cs, retaddr);
}
#if 0
static void do_program_interrupt(CPUS390XState *env)
{
uint64_t mask, addr;
LowCore *lowcore;
int ilen = env->int_pgm_ilen;
assert(ilen == 2 || ilen == 4 || ilen == 6);
switch (env->int_pgm_code) {
case PGM_PER:
if (env->per_perc_atmid & PER_CODE_EVENT_NULLIFICATION) {
break;
}
/* FALL THROUGH */
case PGM_OPERATION:
case PGM_PRIVILEGED:
case PGM_EXECUTE:
case PGM_PROTECTION:
case PGM_ADDRESSING:
case PGM_SPECIFICATION:
case PGM_DATA:
case PGM_FIXPT_OVERFLOW:
case PGM_FIXPT_DIVIDE:
case PGM_DEC_OVERFLOW:
case PGM_DEC_DIVIDE:
case PGM_HFP_EXP_OVERFLOW:
case PGM_HFP_EXP_UNDERFLOW:
case PGM_HFP_SIGNIFICANCE:
case PGM_HFP_DIVIDE:
case PGM_TRANS_SPEC:
case PGM_SPECIAL_OP:
case PGM_OPERAND:
case PGM_HFP_SQRT:
case PGM_PC_TRANS_SPEC:
case PGM_ALET_SPEC:
case PGM_MONITOR:
/* advance the PSW if our exception is not nullifying */
env->psw.addr += ilen;
break;
}
//qemu_log_mask(CPU_LOG_INT,
// "%s: code=0x%x ilen=%d psw: %" PRIx64 " %" PRIx64 "\n",
// __func__, env->int_pgm_code, ilen, env->psw.mask,
// env->psw.addr);
lowcore = cpu_map_lowcore(env);
/* Signal PER events with the exception. */
if (env->per_perc_atmid) {
env->int_pgm_code |= PGM_PER;
lowcore->per_address = cpu_to_be64(env->per_address);
lowcore->per_perc_atmid = cpu_to_be16(env->per_perc_atmid);
env->per_perc_atmid = 0;
}
lowcore->pgm_ilen = cpu_to_be16(ilen);
lowcore->pgm_code = cpu_to_be16(env->int_pgm_code);
lowcore->program_old_psw.mask = cpu_to_be64(get_psw_mask(env));
lowcore->program_old_psw.addr = cpu_to_be64(env->psw.addr);
mask = be64_to_cpu(lowcore->program_new_psw.mask);
addr = be64_to_cpu(lowcore->program_new_psw.addr);
lowcore->per_breaking_event_addr = cpu_to_be64(env->gbea);
cpu_unmap_lowcore(lowcore);
load_psw(env, mask, addr);
}
static void do_svc_interrupt(CPUS390XState *env)
{
uint64_t mask, addr;
LowCore *lowcore;
lowcore = cpu_map_lowcore(env);
lowcore->svc_code = cpu_to_be16(env->int_svc_code);
lowcore->svc_ilen = cpu_to_be16(env->int_svc_ilen);
lowcore->svc_old_psw.mask = cpu_to_be64(get_psw_mask(env));
lowcore->svc_old_psw.addr = cpu_to_be64(env->psw.addr + env->int_svc_ilen);
mask = be64_to_cpu(lowcore->svc_new_psw.mask);
addr = be64_to_cpu(lowcore->svc_new_psw.addr);
cpu_unmap_lowcore(lowcore);
load_psw(env, mask, addr);
/* When a PER event is pending, the PER exception has to happen
immediately after the SERVICE CALL one. */
if (env->per_perc_atmid) {
env->int_pgm_code = PGM_PER;
env->int_pgm_ilen = env->int_svc_ilen;
do_program_interrupt(env);
}
}
#define VIRTIO_SUBCODE_64 0x0D00
static void do_ext_interrupt(CPUS390XState *env)
{
QEMUS390FLICState *flic = QEMU_S390_FLIC(s390_get_flic());
S390CPU *cpu = env_archcpu(env);
uint64_t mask, addr;
uint16_t cpu_addr;
LowCore *lowcore;
if (!(env->psw.mask & PSW_MASK_EXT)) {
cpu_abort(CPU(cpu), "Ext int w/o ext mask\n");
}
lowcore = cpu_map_lowcore(env);
if ((env->pending_int & INTERRUPT_EMERGENCY_SIGNAL) &&
(env->cregs[0] & CR0_EMERGENCY_SIGNAL_SC)) {
MachineState *ms = MACHINE(qdev_get_machine());
unsigned int max_cpus = ms->smp.max_cpus;
lowcore->ext_int_code = cpu_to_be16(EXT_EMERGENCY);
cpu_addr = find_first_bit(env->emergency_signals, S390_MAX_CPUS);
g_assert(cpu_addr < S390_MAX_CPUS);
lowcore->cpu_addr = cpu_to_be16(cpu_addr);
clear_bit(cpu_addr, env->emergency_signals);
if (bitmap_empty(env->emergency_signals, max_cpus)) {
env->pending_int &= ~INTERRUPT_EMERGENCY_SIGNAL;
}
} else if ((env->pending_int & INTERRUPT_EXTERNAL_CALL) &&
(env->cregs[0] & CR0_EXTERNAL_CALL_SC)) {
lowcore->ext_int_code = cpu_to_be16(EXT_EXTERNAL_CALL);
lowcore->cpu_addr = cpu_to_be16(env->external_call_addr);
env->pending_int &= ~INTERRUPT_EXTERNAL_CALL;
} else if ((env->pending_int & INTERRUPT_EXT_CLOCK_COMPARATOR) &&
(env->cregs[0] & CR0_CKC_SC)) {
lowcore->ext_int_code = cpu_to_be16(EXT_CLOCK_COMP);
lowcore->cpu_addr = 0;
env->pending_int &= ~INTERRUPT_EXT_CLOCK_COMPARATOR;
} else if ((env->pending_int & INTERRUPT_EXT_CPU_TIMER) &&
(env->cregs[0] & CR0_CPU_TIMER_SC)) {
lowcore->ext_int_code = cpu_to_be16(EXT_CPU_TIMER);
lowcore->cpu_addr = 0;
env->pending_int &= ~INTERRUPT_EXT_CPU_TIMER;
} else if (qemu_s390_flic_has_service(flic) &&
(env->cregs[0] & CR0_SERVICE_SC)) {
uint32_t param;
param = qemu_s390_flic_dequeue_service(flic);
lowcore->ext_int_code = cpu_to_be16(EXT_SERVICE);
lowcore->ext_params = cpu_to_be32(param);
lowcore->cpu_addr = 0;
} else {
g_assert_not_reached();
}
mask = be64_to_cpu(lowcore->external_new_psw.mask);
addr = be64_to_cpu(lowcore->external_new_psw.addr);
lowcore->external_old_psw.mask = cpu_to_be64(get_psw_mask(env));
lowcore->external_old_psw.addr = cpu_to_be64(env->psw.addr);
cpu_unmap_lowcore(lowcore);
load_psw(env, mask, addr);
}
static void do_io_interrupt(CPUS390XState *env)
{
QEMUS390FLICState *flic = QEMU_S390_FLIC(s390_get_flic());
uint64_t mask, addr;
QEMUS390FlicIO *io;
LowCore *lowcore;
g_assert(env->psw.mask & PSW_MASK_IO);
io = qemu_s390_flic_dequeue_io(flic, env->cregs[6]);
g_assert(io);
lowcore = cpu_map_lowcore(env);
lowcore->subchannel_id = cpu_to_be16(io->id);
lowcore->subchannel_nr = cpu_to_be16(io->nr);
lowcore->io_int_parm = cpu_to_be32(io->parm);
lowcore->io_int_word = cpu_to_be32(io->word);
lowcore->io_old_psw.mask = cpu_to_be64(get_psw_mask(env));
lowcore->io_old_psw.addr = cpu_to_be64(env->psw.addr);
mask = be64_to_cpu(lowcore->io_new_psw.mask);
addr = be64_to_cpu(lowcore->io_new_psw.addr);
cpu_unmap_lowcore(lowcore);
g_free(io);
load_psw(env, mask, addr);
}
typedef struct MchkExtSaveArea {
uint64_t vregs[32][2]; /* 0x0000 */
uint8_t pad_0x0200[0x0400 - 0x0200]; /* 0x0200 */
} MchkExtSaveArea;
QEMU_BUILD_BUG_ON(sizeof(MchkExtSaveArea) != 1024);
static int mchk_store_vregs(CPUS390XState *env, uint64_t mcesao)
{
hwaddr len = sizeof(MchkExtSaveArea);
MchkExtSaveArea *sa;
int i;
sa = cpu_physical_memory_map(env_cpu(env)->as, mcesao, &len, true);
if (!sa) {
return -EFAULT;
}
if (len != sizeof(MchkExtSaveArea)) {
cpu_physical_memory_unmap(env_cpu(env)->as, sa, len, 1, 0);
return -EFAULT;
}
for (i = 0; i < 32; i++) {
sa->vregs[i][0] = cpu_to_be64(env->vregs[i][0]);
sa->vregs[i][1] = cpu_to_be64(env->vregs[i][1]);
}
cpu_physical_memory_unmap(env_cpu(env)->as, sa, len, 1, len);
return 0;
}
static void do_mchk_interrupt(CPUS390XState *env)
{
QEMUS390FLICState *flic = QEMU_S390_FLIC(s390_get_flic());
uint64_t mcic = s390_build_validity_mcic() | MCIC_SC_CP;
uint64_t mask, addr, mcesao = 0;
LowCore *lowcore;
int i;
/* for now we only support channel report machine checks (floating) */
g_assert(env->psw.mask & PSW_MASK_MCHECK);
g_assert(env->cregs[14] & CR14_CHANNEL_REPORT_SC);
qemu_s390_flic_dequeue_crw_mchk(flic);
lowcore = cpu_map_lowcore(env);
/* extended save area */
if (mcic & MCIC_VB_VR) {
/* length and alignment is 1024 bytes */
mcesao = be64_to_cpu(lowcore->mcesad) & ~0x3ffull;
}
/* try to store vector registers */
if (!mcesao || mchk_store_vregs(env, mcesao)) {
mcic &= ~MCIC_VB_VR;
}
/* we are always in z/Architecture mode */
lowcore->ar_access_id = 1;
for (i = 0; i < 16; i++) {
lowcore->floating_pt_save_area[i] = cpu_to_be64(*get_freg(env, i));
lowcore->gpregs_save_area[i] = cpu_to_be64(env->regs[i]);
lowcore->access_regs_save_area[i] = cpu_to_be32(env->aregs[i]);
lowcore->cregs_save_area[i] = cpu_to_be64(env->cregs[i]);
}
lowcore->prefixreg_save_area = cpu_to_be32(env->psa);
lowcore->fpt_creg_save_area = cpu_to_be32(env->fpc);
lowcore->tod_progreg_save_area = cpu_to_be32(env->todpr);
lowcore->cpu_timer_save_area = cpu_to_be64(env->cputm);
lowcore->clock_comp_save_area = cpu_to_be64(env->ckc >> 8);
lowcore->mcic = cpu_to_be64(mcic);
lowcore->mcck_old_psw.mask = cpu_to_be64(get_psw_mask(env));
lowcore->mcck_old_psw.addr = cpu_to_be64(env->psw.addr);
mask = be64_to_cpu(lowcore->mcck_new_psw.mask);
addr = be64_to_cpu(lowcore->mcck_new_psw.addr);
cpu_unmap_lowcore(lowcore);
load_psw(env, mask, addr);
}
void s390_cpu_do_interrupt(CPUState *cs)
{
QEMUS390FLICState *flic = QEMU_S390_FLIC(s390_get_flic());
S390CPU *cpu = S390_CPU(cs);
CPUS390XState *env = &cpu->env;
bool stopped = false;
//qemu_log_mask(CPU_LOG_INT, "%s: %d at psw=%" PRIx64 ":%" PRIx64 "\n",
// __func__, cs->exception_index, env->psw.mask, env->psw.addr);
try_deliver:
/* handle machine checks */
if (cs->exception_index == -1 && s390_cpu_has_mcck_int(cpu)) {
cs->exception_index = EXCP_MCHK;
}
/* handle external interrupts */
if (cs->exception_index == -1 && s390_cpu_has_ext_int(cpu)) {
cs->exception_index = EXCP_EXT;
}
/* handle I/O interrupts */
if (cs->exception_index == -1 && s390_cpu_has_io_int(cpu)) {
cs->exception_index = EXCP_IO;
}
/* RESTART interrupt */
if (cs->exception_index == -1 && s390_cpu_has_restart_int(cpu)) {
cs->exception_index = EXCP_RESTART;
}
/* STOP interrupt has least priority */
if (cs->exception_index == -1 && s390_cpu_has_stop_int(cpu)) {
cs->exception_index = EXCP_STOP;
}
switch (cs->exception_index) {
case EXCP_PGM:
do_program_interrupt(env);
break;
case EXCP_SVC:
do_svc_interrupt(env);
break;
case EXCP_EXT:
do_ext_interrupt(env);
break;
case EXCP_IO:
do_io_interrupt(env);
break;
case EXCP_MCHK:
do_mchk_interrupt(env);
break;
case EXCP_RESTART:
do_restart_interrupt(env);
break;
case EXCP_STOP:
do_stop_interrupt(env);
stopped = true;
break;
}
if (cs->exception_index != -1 && !stopped) {
/* check if there are more pending interrupts to deliver */
cs->exception_index = -1;
goto try_deliver;
}
cs->exception_index = -1;
/* we might still have pending interrupts, but not deliverable */
if (!env->pending_int && !qemu_s390_flic_has_any(flic)) {
cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
}
/* WAIT PSW during interrupt injection or STOP interrupt */
if ((env->psw.mask & PSW_MASK_WAIT) || stopped) {
/* don't trigger a cpu_loop_exit(), use an interrupt instead */
cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HALT);
} else if (cs->halted) {
/* unhalt if we had a WAIT PSW somehwere in our injection chain */
s390_cpu_unhalt(cpu);
}
}
#endif
bool s390_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
{
if (interrupt_request & CPU_INTERRUPT_HARD) {
S390CPU *cpu = S390_CPU(cs);
CPUS390XState *env = &cpu->env;
if (env->ex_value) {
/* Execution of the target insn is indivisible from
the parent EXECUTE insn. */
return false;
}
if (s390_cpu_has_int(cpu)) {
//s390_cpu_do_interrupt(cs);
return true;
}
if (env->psw.mask & PSW_MASK_WAIT) {
/* Woken up because of a floating interrupt but it has already
* been delivered. Go back to sleep. */
cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HALT);
}
}
return false;
}
void s390x_cpu_debug_excp_handler(CPUState *cs)
{
S390CPU *cpu = S390_CPU(cs);
CPUS390XState *env = &cpu->env;
CPUWatchpoint *wp_hit = cs->watchpoint_hit;
if (wp_hit && wp_hit->flags & BP_CPU) {
/* FIXME: When the storage-alteration-space control bit is set,
the exception should only be triggered if the memory access
is done using an address space with the storage-alteration-event
bit set. We have no way to detect that with the current
watchpoint code. */
cs->watchpoint_hit = NULL;
env->per_address = env->psw.addr;
env->per_perc_atmid |= PER_CODE_EVENT_STORE | get_per_atmid(env);
/* FIXME: We currently no way to detect the address space used
to trigger the watchpoint. For now just consider it is the
current default ASC. This turn to be true except when MVCP
and MVCS instrutions are not used. */
env->per_perc_atmid |= env->psw.mask & (PSW_MASK_ASC) >> 46;
/* Remove all watchpoints to re-execute the code. A PER exception
will be triggered, it will call load_psw which will recompute
the watchpoints. */
cpu_watchpoint_remove_all(cs, BP_CPU);
cpu_loop_exit_noexc(cs);
}
}
/* Unaligned accesses are only diagnosed with MO_ALIGN. At the moment,
this is only for the atomic operations, for which we want to raise a
specification exception. */
void s390x_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
MMUAccessType access_type,
int mmu_idx, uintptr_t retaddr)
{
S390CPU *cpu = S390_CPU(cs);
CPUS390XState *env = &cpu->env;
tcg_s390_program_interrupt(env, PGM_SPECIFICATION, retaddr);
}

View File

@ -0,0 +1,888 @@
/*
* S/390 FPU helper routines
*
* Copyright (c) 2009 Ulrich Hecht
* Copyright (c) 2009 Alexander Graf
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#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"
#include "fpu/softfloat.h"
/* #define DEBUG_HELPER */
#ifdef DEBUG_HELPER
#define HELPER_LOG(x...) qemu_log(x)
#else
#define HELPER_LOG(x...)
#endif
#define RET128(F) (env->retxl = F.low, F.high)
uint8_t s390_softfloat_exc_to_ieee(unsigned int exc)
{
uint8_t s390_exc = 0;
s390_exc |= (exc & float_flag_invalid) ? S390_IEEE_MASK_INVALID : 0;
s390_exc |= (exc & float_flag_divbyzero) ? S390_IEEE_MASK_DIVBYZERO : 0;
s390_exc |= (exc & float_flag_overflow) ? S390_IEEE_MASK_OVERFLOW : 0;
s390_exc |= (exc & float_flag_underflow) ? S390_IEEE_MASK_UNDERFLOW : 0;
s390_exc |= (exc & float_flag_inexact) ? S390_IEEE_MASK_INEXACT : 0;
return s390_exc;
}
/* Should be called after any operation that may raise IEEE exceptions. */
static void handle_exceptions(CPUS390XState *env, bool XxC, uintptr_t retaddr)
{
unsigned s390_exc, qemu_exc;
/* Get the exceptions raised by the current operation. Reset the
fpu_status contents so that the next operation has a clean slate. */
qemu_exc = env->fpu_status.float_exception_flags;
if (qemu_exc == 0) {
return;
}
env->fpu_status.float_exception_flags = 0;
s390_exc = s390_softfloat_exc_to_ieee(qemu_exc);
/*
* IEEE-Underflow exception recognition exists if a tininess condition
* (underflow) exists and
* - The mask bit in the FPC is zero and the result is inexact
* - The mask bit in the FPC is one
* So tininess conditions that are not inexact don't trigger any
* underflow action in case the mask bit is not one.
*/
if (!(s390_exc & S390_IEEE_MASK_INEXACT) &&
!((env->fpc >> 24) & S390_IEEE_MASK_UNDERFLOW)) {
s390_exc &= ~S390_IEEE_MASK_UNDERFLOW;
}
/*
* FIXME:
* 1. Right now, all inexact conditions are inidicated as
* "truncated" (0) and never as "incremented" (1) in the DXC.
* 2. Only traps due to invalid/divbyzero are suppressing. Other traps
* are completing, meaning the target register has to be written!
* This, however will mean that we have to write the register before
* triggering the trap - impossible right now.
*/
/*
* invalid/divbyzero cannot coexist with other conditions.
* overflow/underflow however can coexist with inexact, we have to
* handle it separatly.
*/
if (s390_exc & ~S390_IEEE_MASK_INEXACT) {
if (s390_exc & ~S390_IEEE_MASK_INEXACT & env->fpc >> 24) {
/* trap condition - inexact reported along */
tcg_s390_data_exception(env, s390_exc, retaddr);
}
/* nontrap condition - inexact handled differently */
env->fpc |= (s390_exc & ~S390_IEEE_MASK_INEXACT) << 16;
}
/* inexact handling */
if (s390_exc & S390_IEEE_MASK_INEXACT && !XxC) {
/* trap condition - overflow/underflow _not_ reported along */
if (s390_exc & S390_IEEE_MASK_INEXACT & env->fpc >> 24) {
tcg_s390_data_exception(env, s390_exc & S390_IEEE_MASK_INEXACT,
retaddr);
}
/* nontrap condition */
env->fpc |= (s390_exc & S390_IEEE_MASK_INEXACT) << 16;
}
}
int float_comp_to_cc(CPUS390XState *env, int float_compare)
{
switch (float_compare) {
case float_relation_equal:
return 0;
case float_relation_less:
return 1;
case float_relation_greater:
return 2;
case float_relation_unordered:
return 3;
default:
cpu_abort(env_cpu(env), "unknown return value for float compare\n");
}
}
/* condition codes for unary FP ops */
uint32_t set_cc_nz_f32(float32 v)
{
if (float32_is_any_nan(v)) {
return 3;
} else if (float32_is_zero(v)) {
return 0;
} else if (float32_is_neg(v)) {
return 1;
} else {
return 2;
}
}
uint32_t set_cc_nz_f64(float64 v)
{
if (float64_is_any_nan(v)) {
return 3;
} else if (float64_is_zero(v)) {
return 0;
} else if (float64_is_neg(v)) {
return 1;
} else {
return 2;
}
}
uint32_t set_cc_nz_f128(float128 v)
{
if (float128_is_any_nan(v)) {
return 3;
} else if (float128_is_zero(v)) {
return 0;
} else if (float128_is_neg(v)) {
return 1;
} else {
return 2;
}
}
static inline uint8_t round_from_m34(uint32_t m34)
{
return extract32(m34, 0, 4);
}
static inline bool xxc_from_m34(uint32_t m34)
{
/* XxC is bit 1 of m4 */
return extract32(m34, 4 + 3 - 1, 1);
}
/* 32-bit FP addition */
uint64_t HELPER(aeb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
{
float32 ret = float32_add(f1, f2, &env->fpu_status);
handle_exceptions(env, false, GETPC());
return ret;
}
/* 64-bit FP addition */
uint64_t HELPER(adb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
{
float64 ret = float64_add(f1, f2, &env->fpu_status);
handle_exceptions(env, false, GETPC());
return ret;
}
/* 128-bit FP addition */
uint64_t HELPER(axb)(CPUS390XState *env, uint64_t ah, uint64_t al,
uint64_t bh, uint64_t bl)
{
float128 ret = float128_add(make_float128(ah, al),
make_float128(bh, bl),
&env->fpu_status);
handle_exceptions(env, false, GETPC());
return RET128(ret);
}
/* 32-bit FP subtraction */
uint64_t HELPER(seb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
{
float32 ret = float32_sub(f1, f2, &env->fpu_status);
handle_exceptions(env, false, GETPC());
return ret;
}
/* 64-bit FP subtraction */
uint64_t HELPER(sdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
{
float64 ret = float64_sub(f1, f2, &env->fpu_status);
handle_exceptions(env, false, GETPC());
return ret;
}
/* 128-bit FP subtraction */
uint64_t HELPER(sxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
uint64_t bh, uint64_t bl)
{
float128 ret = float128_sub(make_float128(ah, al),
make_float128(bh, bl),
&env->fpu_status);
handle_exceptions(env, false, GETPC());
return RET128(ret);
}
/* 32-bit FP division */
uint64_t HELPER(deb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
{
float32 ret = float32_div(f1, f2, &env->fpu_status);
handle_exceptions(env, false, GETPC());
return ret;
}
/* 64-bit FP division */
uint64_t HELPER(ddb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
{
float64 ret = float64_div(f1, f2, &env->fpu_status);
handle_exceptions(env, false, GETPC());
return ret;
}
/* 128-bit FP division */
uint64_t HELPER(dxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
uint64_t bh, uint64_t bl)
{
float128 ret = float128_div(make_float128(ah, al),
make_float128(bh, bl),
&env->fpu_status);
handle_exceptions(env, false, GETPC());
return RET128(ret);
}
/* 32-bit FP multiplication */
uint64_t HELPER(meeb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
{
float32 ret = float32_mul(f1, f2, &env->fpu_status);
handle_exceptions(env, false, GETPC());
return ret;
}
/* 64-bit FP multiplication */
uint64_t HELPER(mdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
{
float64 ret = float64_mul(f1, f2, &env->fpu_status);
handle_exceptions(env, false, GETPC());
return ret;
}
/* 64/32-bit FP multiplication */
uint64_t HELPER(mdeb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
{
float64 ret = float32_to_float64(f2, &env->fpu_status);
ret = float64_mul(f1, ret, &env->fpu_status);
handle_exceptions(env, false, GETPC());
return ret;
}
/* 128-bit FP multiplication */
uint64_t HELPER(mxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
uint64_t bh, uint64_t bl)
{
float128 ret = float128_mul(make_float128(ah, al),
make_float128(bh, bl),
&env->fpu_status);
handle_exceptions(env, false, GETPC());
return RET128(ret);
}
/* 128/64-bit FP multiplication */
uint64_t HELPER(mxdb)(CPUS390XState *env, uint64_t ah, uint64_t al,
uint64_t f2)
{
float128 ret = float64_to_float128(f2, &env->fpu_status);
ret = float128_mul(make_float128(ah, al), ret, &env->fpu_status);
handle_exceptions(env, false, GETPC());
return RET128(ret);
}
/* convert 32-bit float to 64-bit float */
uint64_t HELPER(ldeb)(CPUS390XState *env, uint64_t f2)
{
float64 ret = float32_to_float64(f2, &env->fpu_status);
handle_exceptions(env, false, GETPC());
return ret;
}
/* convert 128-bit float to 64-bit float */
uint64_t HELPER(ldxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
float64 ret = float128_to_float64(make_float128(ah, al), &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
return ret;
}
/* convert 64-bit float to 128-bit float */
uint64_t HELPER(lxdb)(CPUS390XState *env, uint64_t f2)
{
float128 ret = float64_to_float128(f2, &env->fpu_status);
handle_exceptions(env, false, GETPC());
return RET128(ret);
}
/* convert 32-bit float to 128-bit float */
uint64_t HELPER(lxeb)(CPUS390XState *env, uint64_t f2)
{
float128 ret = float32_to_float128(f2, &env->fpu_status);
handle_exceptions(env, false, GETPC());
return RET128(ret);
}
/* convert 64-bit float to 32-bit float */
uint64_t HELPER(ledb)(CPUS390XState *env, uint64_t f2, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
float32 ret = float64_to_float32(f2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
return ret;
}
/* convert 128-bit float to 32-bit float */
uint64_t HELPER(lexb)(CPUS390XState *env, uint64_t ah, uint64_t al,
uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
float32 ret = float128_to_float32(make_float128(ah, al), &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
return ret;
}
/* 32-bit FP compare */
uint32_t HELPER(ceb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
{
int cmp = float32_compare_quiet(f1, f2, &env->fpu_status);
handle_exceptions(env, false, GETPC());
return float_comp_to_cc(env, cmp);
}
/* 64-bit FP compare */
uint32_t HELPER(cdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
{
int cmp = float64_compare_quiet(f1, f2, &env->fpu_status);
handle_exceptions(env, false, GETPC());
return float_comp_to_cc(env, cmp);
}
/* 128-bit FP compare */
uint32_t HELPER(cxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
uint64_t bh, uint64_t bl)
{
int cmp = float128_compare_quiet(make_float128(ah, al),
make_float128(bh, bl),
&env->fpu_status);
handle_exceptions(env, false, GETPC());
return float_comp_to_cc(env, cmp);
}
int s390_swap_bfp_rounding_mode(CPUS390XState *env, int m3)
{
int ret = env->fpu_status.float_rounding_mode;
switch (m3) {
case 0:
/* current mode */
break;
case 1:
/* round to nearest with ties away from 0 */
set_float_rounding_mode(float_round_ties_away, &env->fpu_status);
break;
case 3:
/* round to prepare for shorter precision */
set_float_rounding_mode(float_round_to_odd, &env->fpu_status);
break;
case 4:
/* round to nearest with ties to even */
set_float_rounding_mode(float_round_nearest_even, &env->fpu_status);
break;
case 5:
/* round to zero */
set_float_rounding_mode(float_round_to_zero, &env->fpu_status);
break;
case 6:
/* round to +inf */
set_float_rounding_mode(float_round_up, &env->fpu_status);
break;
case 7:
/* round to -inf */
set_float_rounding_mode(float_round_down, &env->fpu_status);
break;
default:
g_assert_not_reached();
}
return ret;
}
void s390_restore_bfp_rounding_mode(CPUS390XState *env, int old_mode)
{
set_float_rounding_mode(old_mode, &env->fpu_status);
}
/* convert 64-bit int to 32-bit float */
uint64_t HELPER(cegb)(CPUS390XState *env, int64_t v2, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
float32 ret = int64_to_float32(v2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
return ret;
}
/* convert 64-bit int to 64-bit float */
uint64_t HELPER(cdgb)(CPUS390XState *env, int64_t v2, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
float64 ret = int64_to_float64(v2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
return ret;
}
/* convert 64-bit int to 128-bit float */
uint64_t HELPER(cxgb)(CPUS390XState *env, int64_t v2, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
float128 ret = int64_to_float128(v2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
return RET128(ret);
}
/* convert 64-bit uint to 32-bit float */
uint64_t HELPER(celgb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
float32 ret = uint64_to_float32(v2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
return ret;
}
/* convert 64-bit uint to 64-bit float */
uint64_t HELPER(cdlgb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
float64 ret = uint64_to_float64(v2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
return ret;
}
/* convert 64-bit uint to 128-bit float */
uint64_t HELPER(cxlgb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
float128 ret = uint64_to_float128(v2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
return RET128(ret);
}
/* convert 32-bit float to 64-bit int */
uint64_t HELPER(cgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
int64_t ret = float32_to_int64(v2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
return ret;
}
/* convert 64-bit float to 64-bit int */
uint64_t HELPER(cgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
int64_t ret = float64_to_int64(v2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
return ret;
}
/* convert 128-bit float to 64-bit int */
uint64_t HELPER(cgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
float128 v2 = make_float128(h, l);
int64_t ret = float128_to_int64(v2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
return ret;
}
/* convert 32-bit float to 32-bit int */
uint64_t HELPER(cfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
int32_t ret = float32_to_int32(v2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
return ret;
}
/* convert 64-bit float to 32-bit int */
uint64_t HELPER(cfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
int32_t ret = float64_to_int32(v2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
return ret;
}
/* convert 128-bit float to 32-bit int */
uint64_t HELPER(cfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
float128 v2 = make_float128(h, l);
int32_t ret = float128_to_int32(v2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
return ret;
}
/* convert 32-bit float to 64-bit uint */
uint64_t HELPER(clgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
uint64_t ret;
v2 = float32_to_float64(v2, &env->fpu_status);
ret = float64_to_uint64(v2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
return ret;
}
/* convert 64-bit float to 64-bit uint */
uint64_t HELPER(clgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
uint64_t ret = float64_to_uint64(v2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
return ret;
}
/* convert 128-bit float to 64-bit uint */
uint64_t HELPER(clgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
uint64_t ret = float128_to_uint64(make_float128(h, l), &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
return ret;
}
/* convert 32-bit float to 32-bit uint */
uint64_t HELPER(clfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
uint32_t ret = float32_to_uint32(v2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
return ret;
}
/* convert 64-bit float to 32-bit uint */
uint64_t HELPER(clfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
uint32_t ret = float64_to_uint32(v2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
return ret;
}
/* convert 128-bit float to 32-bit uint */
uint64_t HELPER(clfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
uint32_t ret = float128_to_uint32(make_float128(h, l), &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
return ret;
}
/* round to integer 32-bit */
uint64_t HELPER(fieb)(CPUS390XState *env, uint64_t f2, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
float32 ret = float32_round_to_int(f2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
return ret;
}
/* round to integer 64-bit */
uint64_t HELPER(fidb)(CPUS390XState *env, uint64_t f2, uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
float64 ret = float64_round_to_int(f2, &env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
return ret;
}
/* round to integer 128-bit */
uint64_t HELPER(fixb)(CPUS390XState *env, uint64_t ah, uint64_t al,
uint32_t m34)
{
int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34));
float128 ret = float128_round_to_int(make_float128(ah, al),
&env->fpu_status);
s390_restore_bfp_rounding_mode(env, old_mode);
handle_exceptions(env, xxc_from_m34(m34), GETPC());
return RET128(ret);
}
/* 32-bit FP compare and signal */
uint32_t HELPER(keb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
{
int cmp = float32_compare(f1, f2, &env->fpu_status);
handle_exceptions(env, false, GETPC());
return float_comp_to_cc(env, cmp);
}
/* 64-bit FP compare and signal */
uint32_t HELPER(kdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
{
int cmp = float64_compare(f1, f2, &env->fpu_status);
handle_exceptions(env, false, GETPC());
return float_comp_to_cc(env, cmp);
}
/* 128-bit FP compare and signal */
uint32_t HELPER(kxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
uint64_t bh, uint64_t bl)
{
int cmp = float128_compare(make_float128(ah, al),
make_float128(bh, bl),
&env->fpu_status);
handle_exceptions(env, false, GETPC());
return float_comp_to_cc(env, cmp);
}
/* 32-bit FP multiply and add */
uint64_t HELPER(maeb)(CPUS390XState *env, uint64_t f1,
uint64_t f2, uint64_t f3)
{
float32 ret = float32_muladd(f2, f3, f1, 0, &env->fpu_status);
handle_exceptions(env, false, GETPC());
return ret;
}
/* 64-bit FP multiply and add */
uint64_t HELPER(madb)(CPUS390XState *env, uint64_t f1,
uint64_t f2, uint64_t f3)
{
float64 ret = float64_muladd(f2, f3, f1, 0, &env->fpu_status);
handle_exceptions(env, false, GETPC());
return ret;
}
/* 32-bit FP multiply and subtract */
uint64_t HELPER(mseb)(CPUS390XState *env, uint64_t f1,
uint64_t f2, uint64_t f3)
{
float32 ret = float32_muladd(f2, f3, f1, float_muladd_negate_c,
&env->fpu_status);
handle_exceptions(env, false, GETPC());
return ret;
}
/* 64-bit FP multiply and subtract */
uint64_t HELPER(msdb)(CPUS390XState *env, uint64_t f1,
uint64_t f2, uint64_t f3)
{
float64 ret = float64_muladd(f2, f3, f1, float_muladd_negate_c,
&env->fpu_status);
handle_exceptions(env, false, GETPC());
return ret;
}
/* The rightmost bit has the number 11. */
static inline uint16_t dcmask(int bit, bool neg)
{
return 1 << (11 - bit - neg);
}
#define DEF_FLOAT_DCMASK(_TYPE) \
uint16_t _TYPE##_dcmask(CPUS390XState *env, _TYPE f1) \
{ \
const bool neg = _TYPE##_is_neg(f1); \
\
/* Sorted by most common cases - only one class is possible */ \
if (_TYPE##_is_normal(f1)) { \
return dcmask(2, neg); \
} else if (_TYPE##_is_zero(f1)) { \
return dcmask(0, neg); \
} else if (_TYPE##_is_denormal(f1)) { \
return dcmask(4, neg); \
} else if (_TYPE##_is_infinity(f1)) { \
return dcmask(6, neg); \
} else if (_TYPE##_is_quiet_nan(f1, &env->fpu_status)) { \
return dcmask(8, neg); \
} \
/* signaling nan, as last remaining case */ \
return dcmask(10, neg); \
}
DEF_FLOAT_DCMASK(float32)
DEF_FLOAT_DCMASK(float64)
DEF_FLOAT_DCMASK(float128)
/* test data class 32-bit */
uint32_t HELPER(tceb)(CPUS390XState *env, uint64_t f1, uint64_t m2)
{
return (m2 & float32_dcmask(env, f1)) != 0;
}
/* test data class 64-bit */
uint32_t HELPER(tcdb)(CPUS390XState *env, uint64_t v1, uint64_t m2)
{
return (m2 & float64_dcmask(env, v1)) != 0;
}
/* test data class 128-bit */
uint32_t HELPER(tcxb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t m2)
{
return (m2 & float128_dcmask(env, make_float128(ah, al))) != 0;
}
/* square root 32-bit */
uint64_t HELPER(sqeb)(CPUS390XState *env, uint64_t f2)
{
float32 ret = float32_sqrt(f2, &env->fpu_status);
handle_exceptions(env, false, GETPC());
return ret;
}
/* square root 64-bit */
uint64_t HELPER(sqdb)(CPUS390XState *env, uint64_t f2)
{
float64 ret = float64_sqrt(f2, &env->fpu_status);
handle_exceptions(env, false, GETPC());
return ret;
}
/* square root 128-bit */
uint64_t HELPER(sqxb)(CPUS390XState *env, uint64_t ah, uint64_t al)
{
float128 ret = float128_sqrt(make_float128(ah, al), &env->fpu_status);
handle_exceptions(env, false, GETPC());
return RET128(ret);
}
static const int fpc_to_rnd[8] = {
float_round_nearest_even,
float_round_to_zero,
float_round_up,
float_round_down,
-1,
-1,
-1,
float_round_to_odd,
};
/* set fpc */
void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc)
{
if (fpc_to_rnd[fpc & 0x7] == -1 || fpc & 0x03030088u ||
(!s390_has_feat(env->uc, S390_FEAT_FLOATING_POINT_EXT) && fpc & 0x4)) {
tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
}
/* Install everything in the main FPC. */
env->fpc = fpc;
/* Install the rounding mode in the shadow fpu_status. */
set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status);
}
/* set fpc and signal */
void HELPER(sfas)(CPUS390XState *env, uint64_t fpc)
{
uint32_t signalling = env->fpc;
uint32_t s390_exc;
if (fpc_to_rnd[fpc & 0x7] == -1 || fpc & 0x03030088u ||
(!s390_has_feat(env->uc, S390_FEAT_FLOATING_POINT_EXT) && fpc & 0x4)) {
tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
}
/*
* FPC is set to the FPC operand with a bitwise OR of the signalling
* flags.
*/
env->fpc = fpc | (signalling & 0x00ff0000);
set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status);
/*
* If any signaling flag is enabled in the new FPC mask, a
* simulated-iee-exception exception occurs.
*/
s390_exc = (signalling >> 16) & (fpc >> 24);
if (s390_exc) {
if (s390_exc & S390_IEEE_MASK_INVALID) {
s390_exc = S390_IEEE_MASK_INVALID;
} else if (s390_exc & S390_IEEE_MASK_DIVBYZERO) {
s390_exc = S390_IEEE_MASK_DIVBYZERO;
} else if (s390_exc & S390_IEEE_MASK_OVERFLOW) {
s390_exc &= (S390_IEEE_MASK_OVERFLOW | S390_IEEE_MASK_INEXACT);
} else if (s390_exc & S390_IEEE_MASK_UNDERFLOW) {
s390_exc &= (S390_IEEE_MASK_UNDERFLOW | S390_IEEE_MASK_INEXACT);
} else if (s390_exc & S390_IEEE_MASK_INEXACT) {
s390_exc = S390_IEEE_MASK_INEXACT;
} else if (s390_exc & S390_IEEE_MASK_QUANTUM) {
s390_exc = S390_IEEE_MASK_QUANTUM;
}
tcg_s390_data_exception(env, s390_exc | 3, GETPC());
}
}
/* set bfp rounding mode */
void HELPER(srnm)(CPUS390XState *env, uint64_t rnd)
{
if (rnd > 0x7 || fpc_to_rnd[rnd & 0x7] == -1) {
tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
}
env->fpc = deposit32(env->fpc, 0, 3, rnd);
set_float_rounding_mode(fpc_to_rnd[rnd & 0x7], &env->fpu_status);
}

View File

@ -0,0 +1,986 @@
/*
* S390 feature list generator
*
* Copyright IBM Corp. 2016, 2018
*
* Author(s): Michael Mueller <mimu@linux.vnet.ibm.com>
* David Hildenbrand <dahi@linux.vnet.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at
* your option) any later version. See the COPYING file in the top-level
* directory.
*/
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include "cpu_features_def.h"
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
/***** BEGIN FEATURE DEFS *****/
#define S390_FEAT_GROUP_PLO \
S390_FEAT_PLO_CL, \
S390_FEAT_PLO_CLG, \
S390_FEAT_PLO_CLGR, \
S390_FEAT_PLO_CLX, \
S390_FEAT_PLO_CS, \
S390_FEAT_PLO_CSG, \
S390_FEAT_PLO_CSGR, \
S390_FEAT_PLO_CSX, \
S390_FEAT_PLO_DCS, \
S390_FEAT_PLO_DCSG, \
S390_FEAT_PLO_DCSGR, \
S390_FEAT_PLO_DCSX, \
S390_FEAT_PLO_CSST, \
S390_FEAT_PLO_CSSTG, \
S390_FEAT_PLO_CSSTGR, \
S390_FEAT_PLO_CSSTX, \
S390_FEAT_PLO_CSDST, \
S390_FEAT_PLO_CSDSTG, \
S390_FEAT_PLO_CSDSTGR, \
S390_FEAT_PLO_CSDSTX, \
S390_FEAT_PLO_CSTST, \
S390_FEAT_PLO_CSTSTG, \
S390_FEAT_PLO_CSTSTGR, \
S390_FEAT_PLO_CSTSTX
#define S390_FEAT_GROUP_TOD_CLOCK_STEERING \
S390_FEAT_TOD_CLOCK_STEERING, \
S390_FEAT_PTFF_QTO, \
S390_FEAT_PTFF_QSI, \
S390_FEAT_PTFF_QPT, \
S390_FEAT_PTFF_STO
#define S390_FEAT_GROUP_GEN13_PTFF \
S390_FEAT_PTFF_QUI, \
S390_FEAT_PTFF_QTOU, \
S390_FEAT_PTFF_STOU
#define S390_FEAT_GROUP_MULTIPLE_EPOCH_PTFF \
S390_FEAT_PTFF_QSIE, \
S390_FEAT_PTFF_QTOUE, \
S390_FEAT_PTFF_STOE, \
S390_FEAT_PTFF_STOUE
#define S390_FEAT_GROUP_MSA \
S390_FEAT_MSA, \
S390_FEAT_KMAC_DEA, \
S390_FEAT_KMAC_TDEA_128, \
S390_FEAT_KMAC_TDEA_192, \
S390_FEAT_KMC_DEA, \
S390_FEAT_KMC_TDEA_128, \
S390_FEAT_KMC_TDEA_192, \
S390_FEAT_KM_DEA, \
S390_FEAT_KM_TDEA_128, \
S390_FEAT_KM_TDEA_192, \
S390_FEAT_KIMD_SHA_1, \
S390_FEAT_KLMD_SHA_1
#define S390_FEAT_GROUP_MSA_EXT_1 \
S390_FEAT_KMC_AES_128, \
S390_FEAT_KM_AES_128, \
S390_FEAT_KIMD_SHA_256, \
S390_FEAT_KLMD_SHA_256
#define S390_FEAT_GROUP_MSA_EXT_2 \
S390_FEAT_KMC_AES_192, \
S390_FEAT_KMC_AES_256, \
S390_FEAT_KMC_PRNG, \
S390_FEAT_KM_AES_192, \
S390_FEAT_KM_AES_256, \
S390_FEAT_KIMD_SHA_512, \
S390_FEAT_KLMD_SHA_512
#define S390_FEAT_GROUP_MSA_EXT_3 \
S390_FEAT_MSA_EXT_3, \
S390_FEAT_KMAC_EDEA, \
S390_FEAT_KMAC_ETDEA_128, \
S390_FEAT_KMAC_ETDEA_192, \
S390_FEAT_KMC_EAES_128, \
S390_FEAT_KMC_EAES_192, \
S390_FEAT_KMC_EAES_256, \
S390_FEAT_KMC_EDEA, \
S390_FEAT_KMC_ETDEA_128, \
S390_FEAT_KMC_ETDEA_192, \
S390_FEAT_KM_EDEA, \
S390_FEAT_KM_ETDEA_128, \
S390_FEAT_KM_ETDEA_192, \
S390_FEAT_KM_EAES_128, \
S390_FEAT_KM_EAES_192, \
S390_FEAT_KM_EAES_256, \
S390_FEAT_PCKMO_EDEA, \
S390_FEAT_PCKMO_ETDEA_128, \
S390_FEAT_PCKMO_ETDEA_256, \
S390_FEAT_PCKMO_AES_128, \
S390_FEAT_PCKMO_AES_192, \
S390_FEAT_PCKMO_AES_256
#define S390_FEAT_GROUP_MSA_EXT_4 \
S390_FEAT_MSA_EXT_4, \
S390_FEAT_KMAC_AES_128, \
S390_FEAT_KMAC_AES_192, \
S390_FEAT_KMAC_AES_256, \
S390_FEAT_KMAC_EAES_128, \
S390_FEAT_KMAC_EAES_192, \
S390_FEAT_KMAC_EAES_256, \
S390_FEAT_KM_XTS_AES_128, \
S390_FEAT_KM_XTS_AES_256, \
S390_FEAT_KM_XTS_EAES_128, \
S390_FEAT_KM_XTS_EAES_256, \
S390_FEAT_KIMD_GHASH, \
S390_FEAT_KMCTR_DEA, \
S390_FEAT_KMCTR_TDEA_128, \
S390_FEAT_KMCTR_TDEA_192, \
S390_FEAT_KMCTR_EDEA, \
S390_FEAT_KMCTR_ETDEA_128, \
S390_FEAT_KMCTR_ETDEA_192, \
S390_FEAT_KMCTR_AES_128, \
S390_FEAT_KMCTR_AES_192, \
S390_FEAT_KMCTR_AES_256, \
S390_FEAT_KMCTR_EAES_128, \
S390_FEAT_KMCTR_EAES_192, \
S390_FEAT_KMCTR_EAES_256, \
S390_FEAT_KMF_DEA, \
S390_FEAT_KMF_TDEA_128, \
S390_FEAT_KMF_TDEA_192, \
S390_FEAT_KMF_EDEA, \
S390_FEAT_KMF_ETDEA_128, \
S390_FEAT_KMF_ETDEA_192, \
S390_FEAT_KMF_AES_128, \
S390_FEAT_KMF_AES_192, \
S390_FEAT_KMF_AES_256, \
S390_FEAT_KMF_EAES_128, \
S390_FEAT_KMF_EAES_192, \
S390_FEAT_KMF_EAES_256, \
S390_FEAT_KMO_DEA, \
S390_FEAT_KMO_TDEA_128, \
S390_FEAT_KMO_TDEA_192, \
S390_FEAT_KMO_EDEA, \
S390_FEAT_KMO_ETDEA_128, \
S390_FEAT_KMO_ETDEA_192, \
S390_FEAT_KMO_AES_128, \
S390_FEAT_KMO_AES_192, \
S390_FEAT_KMO_AES_256, \
S390_FEAT_KMO_EAES_128, \
S390_FEAT_KMO_EAES_192, \
S390_FEAT_KMO_EAES_256, \
S390_FEAT_PCC_CMAC_DEA, \
S390_FEAT_PCC_CMAC_TDEA_128, \
S390_FEAT_PCC_CMAC_TDEA_192, \
S390_FEAT_PCC_CMAC_ETDEA_128, \
S390_FEAT_PCC_CMAC_ETDEA_192, \
S390_FEAT_PCC_CMAC_TDEA, \
S390_FEAT_PCC_CMAC_AES_128, \
S390_FEAT_PCC_CMAC_AES_192, \
S390_FEAT_PCC_CMAC_AES_256, \
S390_FEAT_PCC_CMAC_EAES_128, \
S390_FEAT_PCC_CMAC_EAES_192, \
S390_FEAT_PCC_CMAC_EAES_256, \
S390_FEAT_PCC_XTS_AES_128, \
S390_FEAT_PCC_XTS_AES_256, \
S390_FEAT_PCC_XTS_EAES_128, \
S390_FEAT_PCC_XTS_EAES_256
#define S390_FEAT_GROUP_MSA_EXT_5 \
S390_FEAT_MSA_EXT_5, \
S390_FEAT_PPNO_SHA_512_DRNG
#define S390_FEAT_GROUP_MSA_EXT_6 \
S390_FEAT_KIMD_SHA3_224, \
S390_FEAT_KIMD_SHA3_256, \
S390_FEAT_KIMD_SHA3_384, \
S390_FEAT_KIMD_SHA3_512, \
S390_FEAT_KIMD_SHAKE_128, \
S390_FEAT_KIMD_SHAKE_256, \
S390_FEAT_KLMD_SHA3_224, \
S390_FEAT_KLMD_SHA3_256, \
S390_FEAT_KLMD_SHA3_384, \
S390_FEAT_KLMD_SHA3_512, \
S390_FEAT_KLMD_SHAKE_128, \
S390_FEAT_KLMD_SHAKE_256
#define S390_FEAT_GROUP_MSA_EXT_7 \
S390_FEAT_PRNO_TRNG_QRTCR, \
S390_FEAT_PRNO_TRNG
#define S390_FEAT_GROUP_MSA_EXT_8 \
S390_FEAT_MSA_EXT_8, \
S390_FEAT_KMA_GCM_AES_128, \
S390_FEAT_KMA_GCM_AES_192, \
S390_FEAT_KMA_GCM_AES_256 , \
S390_FEAT_KMA_GCM_EAES_128, \
S390_FEAT_KMA_GCM_EAES_192, \
S390_FEAT_KMA_GCM_EAES_256
#define S390_FEAT_GROUP_MSA_EXT_9 \
S390_FEAT_MSA_EXT_9, \
S390_FEAT_KDSA_ECDSA_VERIFY_P256, \
S390_FEAT_KDSA_ECDSA_VERIFY_P384, \
S390_FEAT_KDSA_ECDSA_VERIFY_P512, \
S390_FEAT_KDSA_ECDSA_SIGN_P256, \
S390_FEAT_KDSA_ECDSA_SIGN_P384, \
S390_FEAT_KDSA_ECDSA_SIGN_P512, \
S390_FEAT_KDSA_EECDSA_SIGN_P256, \
S390_FEAT_KDSA_EECDSA_SIGN_P384, \
S390_FEAT_KDSA_EECDSA_SIGN_P512, \
S390_FEAT_KDSA_EDDSA_VERIFY_ED25519, \
S390_FEAT_KDSA_EDDSA_VERIFY_ED448, \
S390_FEAT_KDSA_EDDSA_SIGN_ED25519, \
S390_FEAT_KDSA_EDDSA_SIGN_ED448, \
S390_FEAT_KDSA_EEDDSA_SIGN_ED25519, \
S390_FEAT_KDSA_EEDDSA_SIGN_ED448, \
S390_FEAT_PCC_SCALAR_MULT_P256, \
S390_FEAT_PCC_SCALAR_MULT_P384, \
S390_FEAT_PCC_SCALAR_MULT_P512, \
S390_FEAT_PCC_SCALAR_MULT_ED25519, \
S390_FEAT_PCC_SCALAR_MULT_ED448, \
S390_FEAT_PCC_SCALAR_MULT_X25519, \
S390_FEAT_PCC_SCALAR_MULT_X448
#define S390_FEAT_GROUP_MSA_EXT_9_PCKMO \
S390_FEAT_PCKMO_ECC_P256, \
S390_FEAT_PCKMO_ECC_P384, \
S390_FEAT_PCKMO_ECC_P521, \
S390_FEAT_PCKMO_ECC_ED25519, \
S390_FEAT_PCKMO_ECC_ED448
#define S390_FEAT_GROUP_ENH_SORT \
S390_FEAT_ESORT_BASE, \
S390_FEAT_SORTL_SFLR, \
S390_FEAT_SORTL_SVLR, \
S390_FEAT_SORTL_32, \
S390_FEAT_SORTL_128, \
S390_FEAT_SORTL_F0
#define S390_FEAT_GROUP_DEFLATE_CONVERSION \
S390_FEAT_DEFLATE_BASE, \
S390_FEAT_DEFLATE_GHDT, \
S390_FEAT_DEFLATE_CMPR, \
S390_FEAT_DEFLATE_XPND, \
S390_FEAT_DEFLATE_F0
/* cpu feature groups */
static uint16_t group_PLO[] = {
S390_FEAT_GROUP_PLO,
};
static uint16_t group_TOD_CLOCK_STEERING[] = {
S390_FEAT_GROUP_TOD_CLOCK_STEERING,
};
static uint16_t group_GEN13_PTFF[] = {
S390_FEAT_GROUP_GEN13_PTFF,
};
static uint16_t group_MULTIPLE_EPOCH_PTFF[] = {
S390_FEAT_GROUP_MULTIPLE_EPOCH_PTFF,
};
static uint16_t group_MSA[] = {
S390_FEAT_GROUP_MSA,
};
static uint16_t group_MSA_EXT_1[] = {
S390_FEAT_GROUP_MSA_EXT_1,
};
static uint16_t group_MSA_EXT_2[] = {
S390_FEAT_GROUP_MSA_EXT_2,
};
static uint16_t group_MSA_EXT_3[] = {
S390_FEAT_GROUP_MSA_EXT_3,
};
static uint16_t group_MSA_EXT_4[] = {
S390_FEAT_GROUP_MSA_EXT_4,
};
static uint16_t group_MSA_EXT_5[] = {
S390_FEAT_GROUP_MSA_EXT_5,
};
static uint16_t group_MSA_EXT_6[] = {
S390_FEAT_GROUP_MSA_EXT_6,
};
static uint16_t group_MSA_EXT_7[] = {
S390_FEAT_GROUP_MSA_EXT_7,
};
static uint16_t group_MSA_EXT_8[] = {
S390_FEAT_GROUP_MSA_EXT_8,
};
static uint16_t group_MSA_EXT_9[] = {
S390_FEAT_GROUP_MSA_EXT_9,
};
static uint16_t group_MSA_EXT_9_PCKMO[] = {
S390_FEAT_GROUP_MSA_EXT_9_PCKMO,
};
static uint16_t group_ENH_SORT[] = {
S390_FEAT_GROUP_ENH_SORT,
};
static uint16_t group_DEFLATE_CONVERSION[] = {
S390_FEAT_GROUP_DEFLATE_CONVERSION,
};
/* Base features (in order of release)
* Only non-hypervisor managed features belong here.
* Base feature sets are static meaning they do not change in future QEMU
* releases.
*/
static uint16_t base_GEN7_GA1[] = {
S390_FEAT_GROUP_PLO,
S390_FEAT_ESAN3,
S390_FEAT_ZARCH,
};
#define base_GEN7_GA2 EmptyFeat
#define base_GEN7_GA3 EmptyFeat
static uint16_t base_GEN8_GA1[] = {
S390_FEAT_DAT_ENH,
S390_FEAT_EXTENDED_TRANSLATION_2,
S390_FEAT_GROUP_MSA,
S390_FEAT_LONG_DISPLACEMENT,
S390_FEAT_LONG_DISPLACEMENT_FAST,
S390_FEAT_HFP_MADDSUB,
};
#define base_GEN8_GA2 EmptyFeat
#define base_GEN8_GA3 EmptyFeat
#define base_GEN8_GA4 EmptyFeat
#define base_GEN8_GA5 EmptyFeat
static uint16_t base_GEN9_GA1[] = {
S390_FEAT_IDTE_SEGMENT,
S390_FEAT_ASN_LX_REUSE,
S390_FEAT_STFLE,
S390_FEAT_SENSE_RUNNING_STATUS,
S390_FEAT_EXTENDED_IMMEDIATE,
S390_FEAT_EXTENDED_TRANSLATION_3,
S390_FEAT_HFP_UNNORMALIZED_EXT,
S390_FEAT_ETF2_ENH,
S390_FEAT_STORE_CLOCK_FAST,
S390_FEAT_GROUP_TOD_CLOCK_STEERING,
S390_FEAT_ETF3_ENH,
S390_FEAT_DAT_ENH_2,
};
#define base_GEN9_GA2 EmptyFeat
#define base_GEN9_GA3 EmptyFeat
static uint16_t base_GEN10_GA1[] = {
S390_FEAT_CONDITIONAL_SSKE,
S390_FEAT_PARSING_ENH,
S390_FEAT_MOVE_WITH_OPTIONAL_SPEC,
S390_FEAT_EXTRACT_CPU_TIME,
S390_FEAT_COMPARE_AND_SWAP_AND_STORE,
S390_FEAT_COMPARE_AND_SWAP_AND_STORE_2,
S390_FEAT_GENERAL_INSTRUCTIONS_EXT,
S390_FEAT_EXECUTE_EXT,
S390_FEAT_FLOATING_POINT_SUPPPORT_ENH,
S390_FEAT_DFP,
S390_FEAT_DFP_FAST,
S390_FEAT_PFPO,
};
#define base_GEN10_GA2 EmptyFeat
#define base_GEN10_GA3 EmptyFeat
static uint16_t base_GEN11_GA1[] = {
S390_FEAT_NONQ_KEY_SETTING,
S390_FEAT_ENHANCED_MONITOR,
S390_FEAT_FLOATING_POINT_EXT,
S390_FEAT_SET_PROGRAM_PARAMETERS,
S390_FEAT_STFLE_45,
S390_FEAT_CMPSC_ENH,
S390_FEAT_INTERLOCKED_ACCESS_2,
};
#define base_GEN11_GA2 EmptyFeat
static uint16_t base_GEN12_GA1[] = {
S390_FEAT_DFP_ZONED_CONVERSION,
S390_FEAT_STFLE_49,
S390_FEAT_LOCAL_TLB_CLEARING,
};
#define base_GEN12_GA2 EmptyFeat
static uint16_t base_GEN13_GA1[] = {
S390_FEAT_STFLE_53,
S390_FEAT_DFP_PACKED_CONVERSION,
S390_FEAT_GROUP_GEN13_PTFF,
};
#define base_GEN13_GA2 EmptyFeat
static uint16_t base_GEN14_GA1[] = {
S390_FEAT_ENTROPY_ENC_COMP,
S390_FEAT_MISC_INSTRUCTION_EXT,
S390_FEAT_SEMAPHORE_ASSIST,
S390_FEAT_TIME_SLICE_INSTRUMENTATION,
S390_FEAT_ORDER_PRESERVING_COMPRESSION,
};
#define base_GEN14_GA2 EmptyFeat
static uint16_t base_GEN15_GA1[] = {
S390_FEAT_MISC_INSTRUCTION_EXT3,
};
/* Full features (in order of release)
* Automatically includes corresponding base features.
* Full features are all features this hardware supports even if kvm/QEMU do not
* support these features yet.
*/
static uint16_t full_GEN7_GA1[] = {
S390_FEAT_PPA15,
S390_FEAT_BPB,
S390_FEAT_SIE_F2,
S390_FEAT_SIE_SKEY,
S390_FEAT_SIE_GPERE,
S390_FEAT_SIE_IB,
S390_FEAT_SIE_CEI,
};
static uint16_t full_GEN7_GA2[] = {
S390_FEAT_EXTENDED_TRANSLATION_2,
};
static uint16_t full_GEN7_GA3[] = {
S390_FEAT_LONG_DISPLACEMENT,
S390_FEAT_SIE_SIIF,
};
static uint16_t full_GEN8_GA1[] = {
S390_FEAT_SIE_GSLS,
S390_FEAT_SIE_64BSCAO,
};
#define full_GEN8_GA2 EmptyFeat
static uint16_t full_GEN8_GA3[] = {
S390_FEAT_ASN_LX_REUSE,
S390_FEAT_EXTENDED_TRANSLATION_3,
};
#define full_GEN8_GA4 EmptyFeat
#define full_GEN8_GA5 EmptyFeat
static uint16_t full_GEN9_GA1[] = {
S390_FEAT_STORE_HYPERVISOR_INFO,
S390_FEAT_GROUP_MSA_EXT_1,
S390_FEAT_CMM,
S390_FEAT_SIE_CMMA,
};
static uint16_t full_GEN9_GA2[] = {
S390_FEAT_MOVE_WITH_OPTIONAL_SPEC,
S390_FEAT_EXTRACT_CPU_TIME,
S390_FEAT_COMPARE_AND_SWAP_AND_STORE,
S390_FEAT_FLOATING_POINT_SUPPPORT_ENH,
S390_FEAT_DFP,
};
static uint16_t full_GEN9_GA3[] = {
S390_FEAT_CONDITIONAL_SSKE,
S390_FEAT_PFPO,
};
static uint16_t full_GEN10_GA1[] = {
S390_FEAT_EDAT,
S390_FEAT_CONFIGURATION_TOPOLOGY,
S390_FEAT_GROUP_MSA_EXT_2,
S390_FEAT_ESOP,
S390_FEAT_SIE_PFMFI,
S390_FEAT_SIE_SIGPIF,
};
static uint16_t full_GEN10_GA2[] = {
S390_FEAT_SET_PROGRAM_PARAMETERS,
S390_FEAT_SIE_IBS,
};
static uint16_t full_GEN10_GA3[] = {
S390_FEAT_GROUP_MSA_EXT_3,
};
static uint16_t full_GEN11_GA1[] = {
S390_FEAT_IPTE_RANGE,
S390_FEAT_ACCESS_EXCEPTION_FS_INDICATION,
S390_FEAT_GROUP_MSA_EXT_4,
};
#define full_GEN11_GA2 EmptyFeat
static uint16_t full_GEN12_GA1[] = {
S390_FEAT_CONSTRAINT_TRANSACTIONAL_EXE,
S390_FEAT_TRANSACTIONAL_EXE,
S390_FEAT_RUNTIME_INSTRUMENTATION,
S390_FEAT_ZPCI,
S390_FEAT_ADAPTER_EVENT_NOTIFICATION,
S390_FEAT_ADAPTER_INT_SUPPRESSION,
S390_FEAT_EDAT_2,
S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2,
S390_FEAT_AP_QUERY_CONFIG_INFO,
S390_FEAT_AP_QUEUE_INTERRUPT_CONTROL,
S390_FEAT_AP_FACILITIES_TEST,
S390_FEAT_AP,
};
static uint16_t full_GEN12_GA2[] = {
S390_FEAT_GROUP_MSA_EXT_5,
};
static uint16_t full_GEN13_GA1[] = {
S390_FEAT_VECTOR,
};
#define full_GEN13_GA2 EmptyFeat
static uint16_t full_GEN14_GA1[] = {
S390_FEAT_INSTRUCTION_EXEC_PROT,
S390_FEAT_GUARDED_STORAGE,
S390_FEAT_VECTOR_PACKED_DECIMAL,
S390_FEAT_VECTOR_ENH,
S390_FEAT_MULTIPLE_EPOCH,
S390_FEAT_TEST_PENDING_EXT_INTERRUPTION,
S390_FEAT_INSERT_REFERENCE_BITS_MULT,
S390_FEAT_GROUP_MSA_EXT_6,
S390_FEAT_GROUP_MSA_EXT_7,
S390_FEAT_GROUP_MSA_EXT_8,
S390_FEAT_CMM_NT,
S390_FEAT_ETOKEN,
S390_FEAT_HPMA2,
S390_FEAT_SIE_KSS,
S390_FEAT_GROUP_MULTIPLE_EPOCH_PTFF,
};
#define full_GEN14_GA2 EmptyFeat
static uint16_t full_GEN15_GA1[] = {
S390_FEAT_VECTOR_ENH2,
S390_FEAT_GROUP_ENH_SORT,
S390_FEAT_GROUP_DEFLATE_CONVERSION,
S390_FEAT_VECTOR_PACKED_DECIMAL_ENH,
S390_FEAT_GROUP_MSA_EXT_9,
S390_FEAT_GROUP_MSA_EXT_9_PCKMO,
S390_FEAT_ETOKEN,
};
/* Default features (in order of release)
* Automatically includes corresponding base features.
* Default features are all features this version of QEMU supports for this
* hardware model. Default feature sets can grow with new QEMU releases.
*/
#define default_GEN7_GA1 EmptyFeat
#define default_GEN7_GA2 EmptyFeat
#define default_GEN7_GA3 EmptyFeat
#define default_GEN8_GA1 EmptyFeat
#define default_GEN8_GA2 EmptyFeat
#define default_GEN8_GA3 EmptyFeat
#define default_GEN8_GA4 EmptyFeat
#define default_GEN8_GA5 EmptyFeat
static uint16_t default_GEN9_GA1[] = {
S390_FEAT_STORE_HYPERVISOR_INFO,
S390_FEAT_GROUP_MSA_EXT_1,
S390_FEAT_CMM,
};
#define default_GEN9_GA2 EmptyFeat
#define default_GEN9_GA3 EmptyFeat
static uint16_t default_GEN10_GA1[] = {
S390_FEAT_EDAT,
S390_FEAT_GROUP_MSA_EXT_2,
};
#define default_GEN10_GA2 EmptyFeat
#define default_GEN10_GA3 EmptyFeat
static uint16_t default_GEN11_GA1[] = {
S390_FEAT_GROUP_MSA_EXT_3,
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
static uint16_t default_GEN12_GA1[] = {
S390_FEAT_CONSTRAINT_TRANSACTIONAL_EXE,
S390_FEAT_TRANSACTIONAL_EXE,
S390_FEAT_RUNTIME_INSTRUMENTATION,
S390_FEAT_ZPCI,
S390_FEAT_ADAPTER_EVENT_NOTIFICATION,
S390_FEAT_EDAT_2,
S390_FEAT_ESOP,
S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2,
};
#define default_GEN12_GA2 EmptyFeat
static uint16_t default_GEN13_GA1[] = {
S390_FEAT_GROUP_MSA_EXT_5,
S390_FEAT_VECTOR,
};
#define default_GEN13_GA2 EmptyFeat
static uint16_t default_GEN14_GA1[] = {
S390_FEAT_INSTRUCTION_EXEC_PROT,
S390_FEAT_GUARDED_STORAGE,
S390_FEAT_VECTOR_PACKED_DECIMAL,
S390_FEAT_VECTOR_ENH,
S390_FEAT_GROUP_MSA_EXT_6,
S390_FEAT_GROUP_MSA_EXT_7,
S390_FEAT_GROUP_MSA_EXT_8,
S390_FEAT_MULTIPLE_EPOCH,
S390_FEAT_GROUP_MULTIPLE_EPOCH_PTFF,
};
#define default_GEN14_GA2 EmptyFeat
static uint16_t default_GEN15_GA1[] = {
S390_FEAT_VECTOR_ENH2,
S390_FEAT_GROUP_DEFLATE_CONVERSION,
S390_FEAT_VECTOR_PACKED_DECIMAL_ENH,
S390_FEAT_GROUP_MSA_EXT_9,
S390_FEAT_GROUP_MSA_EXT_9_PCKMO,
S390_FEAT_ETOKEN,
};
/* QEMU (CPU model) features */
static uint16_t qemu_V2_11[] = {
S390_FEAT_GROUP_PLO,
S390_FEAT_ESAN3,
S390_FEAT_ZARCH,
};
static uint16_t qemu_V3_1[] = {
S390_FEAT_DAT_ENH,
S390_FEAT_IDTE_SEGMENT,
S390_FEAT_STFLE,
S390_FEAT_SENSE_RUNNING_STATUS,
S390_FEAT_EXTENDED_TRANSLATION_2,
S390_FEAT_MSA,
S390_FEAT_LONG_DISPLACEMENT,
S390_FEAT_LONG_DISPLACEMENT_FAST,
S390_FEAT_EXTENDED_IMMEDIATE,
S390_FEAT_EXTENDED_TRANSLATION_3,
S390_FEAT_ETF2_ENH,
S390_FEAT_STORE_CLOCK_FAST,
S390_FEAT_MOVE_WITH_OPTIONAL_SPEC,
S390_FEAT_ETF3_ENH,
S390_FEAT_EXTRACT_CPU_TIME,
S390_FEAT_COMPARE_AND_SWAP_AND_STORE,
S390_FEAT_COMPARE_AND_SWAP_AND_STORE_2,
S390_FEAT_GENERAL_INSTRUCTIONS_EXT,
S390_FEAT_EXECUTE_EXT,
S390_FEAT_SET_PROGRAM_PARAMETERS,
S390_FEAT_FLOATING_POINT_SUPPPORT_ENH,
S390_FEAT_STFLE_45,
S390_FEAT_STFLE_49,
S390_FEAT_LOCAL_TLB_CLEARING,
S390_FEAT_INTERLOCKED_ACCESS_2,
S390_FEAT_ADAPTER_EVENT_NOTIFICATION,
S390_FEAT_ADAPTER_INT_SUPPRESSION,
S390_FEAT_MSA_EXT_3,
S390_FEAT_MSA_EXT_4,
};
static uint16_t qemu_V4_0[] = {
/*
* Only BFP bits are implemented (HFP, DFP, PFPO and DIVIDE TO INTEGER not
* implemented yet).
*/
S390_FEAT_FLOATING_POINT_EXT,
S390_FEAT_ZPCI,
};
static uint16_t qemu_V4_1[] = {
S390_FEAT_STFLE_53,
S390_FEAT_VECTOR,
};
static uint16_t qemu_LATEST[] = {
S390_FEAT_ACCESS_EXCEPTION_FS_INDICATION,
S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2,
S390_FEAT_ESOP,
};
/* add all new definitions before this point */
static uint16_t qemu_MAX[] = {
/* generates a dependency warning, leave it out for now */
S390_FEAT_MSA_EXT_5,
/* features introduced after the z13 */
S390_FEAT_INSTRUCTION_EXEC_PROT,
};
/****** END FEATURE DEFS ******/
#define _YEARS "2016"
#define _NAME_H "TARGET_S390X_GEN_FEATURES_H"
#define CPU_FEAT_INITIALIZER(_name) \
{ \
.name = "S390_FEAT_LIST_" #_name, \
.base_bits = \
{ .data = base_##_name, \
.len = ARRAY_SIZE(base_##_name) }, \
.default_bits = \
{ .data = default_##_name, \
.len = ARRAY_SIZE(default_##_name) }, \
.full_bits = \
{ .data = full_##_name, \
.len = ARRAY_SIZE(full_##_name) }, \
}
typedef struct BitSpec {
uint16_t *data;
uint32_t len;
} BitSpec;
typedef struct {
const char *name;
BitSpec base_bits;
BitSpec default_bits;
BitSpec full_bits;
} CpuFeatDefSpec;
static uint16_t EmptyFeat[] = {};
/*******************************
* processor GA series
*******************************/
static CpuFeatDefSpec CpuFeatDef[] = {
CPU_FEAT_INITIALIZER(GEN7_GA1),
CPU_FEAT_INITIALIZER(GEN7_GA2),
CPU_FEAT_INITIALIZER(GEN7_GA3),
CPU_FEAT_INITIALIZER(GEN8_GA1),
CPU_FEAT_INITIALIZER(GEN8_GA2),
CPU_FEAT_INITIALIZER(GEN8_GA3),
CPU_FEAT_INITIALIZER(GEN8_GA4),
CPU_FEAT_INITIALIZER(GEN8_GA5),
CPU_FEAT_INITIALIZER(GEN9_GA1),
CPU_FEAT_INITIALIZER(GEN9_GA2),
CPU_FEAT_INITIALIZER(GEN9_GA3),
CPU_FEAT_INITIALIZER(GEN10_GA1),
CPU_FEAT_INITIALIZER(GEN10_GA2),
CPU_FEAT_INITIALIZER(GEN10_GA3),
CPU_FEAT_INITIALIZER(GEN11_GA1),
CPU_FEAT_INITIALIZER(GEN11_GA2),
CPU_FEAT_INITIALIZER(GEN12_GA1),
CPU_FEAT_INITIALIZER(GEN12_GA2),
CPU_FEAT_INITIALIZER(GEN13_GA1),
CPU_FEAT_INITIALIZER(GEN13_GA2),
CPU_FEAT_INITIALIZER(GEN14_GA1),
CPU_FEAT_INITIALIZER(GEN14_GA2),
CPU_FEAT_INITIALIZER(GEN15_GA1),
};
#define FEAT_GROUP_INITIALIZER(_name) \
{ \
.name = "S390_FEAT_GROUP_LIST_" #_name, \
.enum_name = "S390_FEAT_GROUP_" #_name, \
.bits = \
{ .data = group_##_name, \
.len = ARRAY_SIZE(group_##_name) }, \
}
typedef struct {
const char *name;
const char *enum_name;
BitSpec bits;
} FeatGroupDefSpec;
/*******************************
* feature groups
*******************************/
static FeatGroupDefSpec FeatGroupDef[] = {
FEAT_GROUP_INITIALIZER(PLO),
FEAT_GROUP_INITIALIZER(TOD_CLOCK_STEERING),
FEAT_GROUP_INITIALIZER(GEN13_PTFF),
FEAT_GROUP_INITIALIZER(MSA),
FEAT_GROUP_INITIALIZER(MSA_EXT_1),
FEAT_GROUP_INITIALIZER(MSA_EXT_2),
FEAT_GROUP_INITIALIZER(MSA_EXT_3),
FEAT_GROUP_INITIALIZER(MSA_EXT_4),
FEAT_GROUP_INITIALIZER(MSA_EXT_5),
FEAT_GROUP_INITIALIZER(MSA_EXT_6),
FEAT_GROUP_INITIALIZER(MSA_EXT_7),
FEAT_GROUP_INITIALIZER(MSA_EXT_8),
FEAT_GROUP_INITIALIZER(MSA_EXT_9),
FEAT_GROUP_INITIALIZER(MSA_EXT_9_PCKMO),
FEAT_GROUP_INITIALIZER(MULTIPLE_EPOCH_PTFF),
FEAT_GROUP_INITIALIZER(ENH_SORT),
FEAT_GROUP_INITIALIZER(DEFLATE_CONVERSION),
};
#define QEMU_FEAT_INITIALIZER(_name) \
{ \
.name = "S390_FEAT_LIST_QEMU_" #_name, \
.bits = \
{ .data = qemu_##_name, \
.len = ARRAY_SIZE(qemu_##_name) }, \
}
/*******************************
* QEMU (CPU model) features
*******************************/
static FeatGroupDefSpec QemuFeatDef[] = {
QEMU_FEAT_INITIALIZER(V2_11),
QEMU_FEAT_INITIALIZER(V3_1),
QEMU_FEAT_INITIALIZER(V4_0),
QEMU_FEAT_INITIALIZER(V4_1),
QEMU_FEAT_INITIALIZER(LATEST),
QEMU_FEAT_INITIALIZER(MAX),
};
static void set_bits(uint64_t list[], BitSpec bits)
{
uint32_t i;
for (i = 0; i < bits.len; i++) {
list[bits.data[i] / 64] |= 1ULL << (bits.data[i] % 64);
}
}
static inline void clear_bit(uint64_t list[], unsigned long nr)
{
list[nr / 64] &= ~(1ULL << (nr % 64));
}
static void print_feature_defs(void)
{
uint64_t base_feat[S390_FEAT_MAX / 64 + 1] = {};
uint64_t default_feat[S390_FEAT_MAX / 64 + 1] = {};
uint64_t full_feat[S390_FEAT_MAX / 64 + 1] = {};
int i, j;
printf("\n/* CPU model feature list data */\n");
for (i = 0; i < ARRAY_SIZE(CpuFeatDef); i++) {
/* With gen15 CSSKE and BPB are deprecated */
if (strcmp(CpuFeatDef[i].name, "S390_FEAT_LIST_GEN15_GA1") == 0) {
clear_bit(base_feat, S390_FEAT_CONDITIONAL_SSKE);
clear_bit(default_feat, S390_FEAT_CONDITIONAL_SSKE);
clear_bit(default_feat, S390_FEAT_BPB);
}
set_bits(base_feat, CpuFeatDef[i].base_bits);
/* add the base to the default features */
set_bits(default_feat, CpuFeatDef[i].base_bits);
set_bits(default_feat, CpuFeatDef[i].default_bits);
/* add the base to the full features */
set_bits(full_feat, CpuFeatDef[i].base_bits);
set_bits(full_feat, CpuFeatDef[i].full_bits);
printf("#define %s_BASE\t", CpuFeatDef[i].name);
for (j = 0; j < ARRAY_SIZE(base_feat); j++) {
printf("0x%016"PRIx64"ULL", base_feat[j]);
if (j < ARRAY_SIZE(base_feat) - 1) {
printf(",");
} else {
printf("\n");
}
}
printf("#define %s_DEFAULT\t", CpuFeatDef[i].name);
for (j = 0; j < ARRAY_SIZE(default_feat); j++) {
printf("0x%016"PRIx64"ULL", default_feat[j]);
if (j < ARRAY_SIZE(default_feat) - 1) {
printf(",");
} else {
printf("\n");
}
}
printf("#define %s_FULL\t\t", CpuFeatDef[i].name);
for (j = 0; j < ARRAY_SIZE(full_feat); j++) {
printf("0x%016"PRIx64"ULL", full_feat[j]);
if (j < ARRAY_SIZE(full_feat) - 1) {
printf(",");
} else {
printf("\n");
}
}
}
}
static void print_qemu_feature_defs(void)
{
uint64_t feat[S390_FEAT_MAX / 64 + 1] = {};
int i, j;
printf("\n/* QEMU (CPU model) feature list data */\n");
/* for now we assume that we only add new features */
for (i = 0; i < ARRAY_SIZE(QemuFeatDef); i++) {
set_bits(feat, QemuFeatDef[i].bits);
printf("#define %s\t", QemuFeatDef[i].name);
for (j = 0; j < ARRAY_SIZE(feat); j++) {
printf("0x%016"PRIx64"ULL", feat[j]);
if (j < ARRAY_SIZE(feat) - 1) {
printf(",");
} else {
printf("\n");
}
}
}
}
static void print_feature_group_defs(void)
{
int i, j;
printf("\n/* CPU feature group list data */\n");
for (i = 0; i < ARRAY_SIZE(FeatGroupDef); i++) {
uint64_t feat[S390_FEAT_MAX / 64 + 1] = {};
set_bits(feat, FeatGroupDef[i].bits);
printf("#define %s\t", FeatGroupDef[i].name);
for (j = 0; j < ARRAY_SIZE(feat); j++) {
printf("0x%016"PRIx64"ULL", feat[j]);
if (j < ARRAY_SIZE(feat) - 1) {
printf(",");
} else {
printf("\n");
}
}
}
}
static void print_feature_group_enum_type(void)
{
int i;
printf("\n/* CPU feature group enum type */\n"
"typedef enum {\n");
for (i = 0; i < ARRAY_SIZE(FeatGroupDef); i++) {
printf("\t%s,\n", FeatGroupDef[i].enum_name);
}
printf("\tS390_FEAT_GROUP_MAX,\n"
"} S390FeatGroup;\n");
}
int main(int argc, char *argv[])
{
printf("/*\n"
" * AUTOMATICALLY GENERATED, DO NOT MODIFY HERE, EDIT\n"
" * SOURCE FILE \"%s\" INSTEAD.\n"
" *\n"
" * Copyright %s IBM Corp.\n"
" *\n"
" * This work is licensed under the terms of the GNU GPL, "
"version 2 or (at\n * your option) any later version. See "
"the COPYING file in the top-level\n * directory.\n"
" */\n\n"
"#ifndef %s\n#define %s\n", __FILE__, _YEARS, _NAME_H, _NAME_H);
print_feature_defs();
print_feature_group_defs();
print_qemu_feature_defs();
print_feature_group_enum_type();
printf("\n#endif\n");
return 0;
}

View File

@ -0,0 +1,135 @@
/*
* AUTOMATICALLY GENERATED, DO NOT MODIFY HERE, EDIT
* SOURCE FILE "/home/me/projects/qemu/qemu-5.0.1/target/s390x/gen-features.c" INSTEAD.
*
* Copyright 2016 IBM Corp.
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at
* your option) any later version. See the COPYING file in the top-level
* directory.
*/
#ifndef TARGET_S390X_GEN_FEATURES_H
#define TARGET_S390X_GEN_FEATURES_H
/* CPU model feature list data */
#define S390_FEAT_LIST_GEN7_GA1_BASE 0x0000000000000003ULL,0xfffffe0000000000ULL,0x0000000000000001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN7_GA1_DEFAULT 0x0000000000000003ULL,0xfffffe0000000000ULL,0x0000000000000001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN7_GA1_FULL 0x0000000000000003ULL,0xfffffe3380000030ULL,0x0000000000000001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN7_GA2_BASE 0x0000000000000003ULL,0xfffffe0000000000ULL,0x0000000000000001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN7_GA2_DEFAULT 0x0000000000000003ULL,0xfffffe0000000000ULL,0x0000000000000001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN7_GA2_FULL 0x0000000000008003ULL,0xfffffe3380000030ULL,0x0000000000000001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN7_GA3_BASE 0x0000000000000003ULL,0xfffffe0000000000ULL,0x0000000000000001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN7_GA3_DEFAULT 0x0000000000000003ULL,0xfffffe0000000000ULL,0x0000000000000001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN7_GA3_FULL 0x0000000000028003ULL,0xfffffe3780000030ULL,0x0000000000000001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN8_GA1_BASE 0x00000000000f8007ULL,0xfffffe0000000000ULL,0x802000e007007001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN8_GA1_DEFAULT 0x00000000000f8007ULL,0xfffffe0000000000ULL,0x802000e007007001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN8_GA1_FULL 0x00000000000f8007ULL,0xfffffe3788800030ULL,0x802000e007007001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN8_GA2_BASE 0x00000000000f8007ULL,0xfffffe0000000000ULL,0x802000e007007001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN8_GA2_DEFAULT 0x00000000000f8007ULL,0xfffffe0000000000ULL,0x802000e007007001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN8_GA2_FULL 0x00000000000f8007ULL,0xfffffe3788800030ULL,0x802000e007007001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN8_GA3_BASE 0x00000000000f8007ULL,0xfffffe0000000000ULL,0x802000e007007001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN8_GA3_DEFAULT 0x00000000000f8007ULL,0xfffffe0000000000ULL,0x802000e007007001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN8_GA3_FULL 0x00000000002f8027ULL,0xfffffe3788800030ULL,0x802000e007007001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN8_GA4_BASE 0x00000000000f8007ULL,0xfffffe0000000000ULL,0x802000e007007001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN8_GA4_DEFAULT 0x00000000000f8007ULL,0xfffffe0000000000ULL,0x802000e007007001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN8_GA4_FULL 0x00000000002f8027ULL,0xfffffe3788800030ULL,0x802000e007007001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN8_GA5_BASE 0x00000000000f8007ULL,0xfffffe0000000000ULL,0x802000e007007001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN8_GA5_DEFAULT 0x00000000000f8007ULL,0xfffffe0000000000ULL,0x802000e007007001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN8_GA5_FULL 0x00000000002f8027ULL,0xfffffe3788800030ULL,0x802000e007007001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN9_GA1_BASE 0x0000000019ff816fULL,0xfffffe4000000000ULL,0x802000e00700710fULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN9_GA1_DEFAULT 0x4000000019ff816fULL,0xfffffec000000000ULL,0x806008e04700710fULL,0x0000000000000001ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN9_GA1_FULL 0x4000000019ff816fULL,0xfffffef798800030ULL,0x806008e04700710fULL,0x0000000000000001ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN9_GA2_BASE 0x0000000019ff816fULL,0xfffffe4000000000ULL,0x802000e00700710fULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN9_GA2_DEFAULT 0x4000000019ff816fULL,0xfffffec000000000ULL,0x806008e04700710fULL,0x0000000000000001ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN9_GA2_FULL 0x400000c07dff816fULL,0xfffffef798800030ULL,0x806008e04700710fULL,0x0000000000000001ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN9_GA3_BASE 0x0000000019ff816fULL,0xfffffe4000000000ULL,0x802000e00700710fULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN9_GA3_DEFAULT 0x4000000019ff816fULL,0xfffffec000000000ULL,0x806008e04700710fULL,0x0000000000000001ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN9_GA3_FULL 0x400002c07dff836fULL,0xfffffef798800030ULL,0x806008e04700710fULL,0x0000000000000001ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN10_GA1_BASE 0x000003c3ffff836fULL,0xfffffe4000000000ULL,0x802000e00700710fULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN10_GA1_DEFAULT 0x400003c3ffff83efULL,0xfffffec000000000ULL,0x80e038f1c700710fULL,0x0000000000000003ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN10_GA1_FULL 0x400003c3ffff87efULL,0xfffffeffb9800030ULL,0x80e038f1c700710fULL,0x0000000000000003ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN10_GA2_BASE 0x000003c3ffff836fULL,0xfffffe4000000000ULL,0x802000e00700710fULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN10_GA2_DEFAULT 0x400003c3ffff83efULL,0xfffffec000000000ULL,0x80e038f1c700710fULL,0x0000000000000003ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN10_GA2_FULL 0x400003e3ffff87efULL,0xfffffefff9800030ULL,0x80e038f1c700710fULL,0x0000000000000003ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN10_GA3_BASE 0x000003c3ffff836fULL,0xfffffe4000000000ULL,0x802000e00700710fULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN10_GA3_DEFAULT 0x400003c3ffff83efULL,0xfffffec000000000ULL,0x80e038f1c700710fULL,0x0000000000000003ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN10_GA3_FULL 0x400003e3ffff87efULL,0xfffffefff9800031ULL,0x80e1ffffff03f10fULL,0x0000000000003f03ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN11_GA1_BASE 0x00010fefffffa36fULL,0xfffffe4000000000ULL,0x802000e00700710fULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN11_GA1_DEFAULT 0xc0010fefffffb3efULL,0xfffffec000000033ULL,0xc0fffffffffff10fULL,0xfffffffffff83f03ULL,0x000000000000007fULL
#define S390_FEAT_LIST_GEN11_GA1_FULL 0xc0010fefffffb7efULL,0xfffffefff9800033ULL,0xc0fffffffffff10fULL,0xfffffffffff83f03ULL,0x000000000000007fULL
#define S390_FEAT_LIST_GEN11_GA2_BASE 0x00010fefffffa36fULL,0xfffffe4000000000ULL,0x802000e00700710fULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN11_GA2_DEFAULT 0xc0010fefffffb3efULL,0xfffffec000000033ULL,0xc0fffffffffff10fULL,0xfffffffffff83f03ULL,0x000000000000007fULL
#define S390_FEAT_LIST_GEN11_GA2_FULL 0xc0010fefffffb7efULL,0xfffffefff9800033ULL,0xc0fffffffffff10fULL,0xfffffffffff83f03ULL,0x000000000000007fULL
#define S390_FEAT_LIST_GEN12_GA1_BASE 0x0001bfefffffa36fULL,0xfffffe4000000000ULL,0x802000e00700710fULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN12_GA1_DEFAULT 0xed01ffefffffb3efULL,0xfffffec001000137ULL,0xc0fffffffffff10fULL,0xfffffffffff83f03ULL,0x000000000000007fULL
#define S390_FEAT_LIST_GEN12_GA1_FULL 0xff01ffefffffffefULL,0xfffffffff9800137ULL,0xc0fffffffffff10fULL,0xfffffffffff83f03ULL,0x000000000000007fULL
#define S390_FEAT_LIST_GEN12_GA2_BASE 0x0001bfefffffa36fULL,0xfffffe4000000000ULL,0x802000e00700710fULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN12_GA2_DEFAULT 0xed01ffefffffb3efULL,0xfffffec001000137ULL,0xc0fffffffffff10fULL,0xfffffffffff83f03ULL,0x000000000000007fULL
#define S390_FEAT_LIST_GEN12_GA2_FULL 0xff09ffefffffffefULL,0xfffffffff9800137ULL,0xc0fffffffffff10fULL,0xfffffffffff83f03ULL,0x000000000000407fULL
#define S390_FEAT_LIST_GEN13_GA1_BASE 0x0003bfefffffa36fULL,0xfffffe4000000008ULL,0x802000e00700733fULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN13_GA1_DEFAULT 0xed0bffefffffb3efULL,0xfffffec00100017fULL,0xc0fffffffffff33fULL,0xfffffffffff83f03ULL,0x000000000000407fULL
#define S390_FEAT_LIST_GEN13_GA1_FULL 0xff0bffefffffffefULL,0xfffffffff980017fULL,0xc0fffffffffff33fULL,0xfffffffffff83f03ULL,0x000000000000407fULL
#define S390_FEAT_LIST_GEN13_GA2_BASE 0x0003bfefffffa36fULL,0xfffffe4000000008ULL,0x802000e00700733fULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN13_GA2_DEFAULT 0xed0bffefffffb3efULL,0xfffffec00100017fULL,0xc0fffffffffff33fULL,0xfffffffffff83f03ULL,0x000000000000407fULL
#define S390_FEAT_LIST_GEN13_GA2_FULL 0xff0bffefffffffefULL,0xfffffffff980017fULL,0xc0fffffffffff33fULL,0xfffffffffff83f03ULL,0x000000000000407fULL
#define S390_FEAT_LIST_GEN14_GA1_BASE 0x0077bfffffffa36fULL,0xfffffe4000000008ULL,0x802000e00700733fULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN14_GA1_DEFAULT 0xed7fffffffffb3efULL,0xfffffec001009fffULL,0xffffffffffffffffULL,0xfffffffffff83fffULL,0x00000000007fc07fULL
#define S390_FEAT_LIST_GEN14_GA1_FULL 0xff7fffffffffffefULL,0xffffffffffc1ffffULL,0xffffffffffffffffULL,0xfffffffffff83fffULL,0x00000000007fc07fULL
#define S390_FEAT_LIST_GEN14_GA2_BASE 0x0077bfffffffa36fULL,0xfffffe4000000008ULL,0x802000e00700733fULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN14_GA2_DEFAULT 0xed7fffffffffb3efULL,0xfffffec001009fffULL,0xffffffffffffffffULL,0xfffffffffff83fffULL,0x00000000007fc07fULL
#define S390_FEAT_LIST_GEN14_GA2_FULL 0xff7fffffffffffefULL,0xffffffffffc1ffffULL,0xffffffffffffffffULL,0xfffffffffff83fffULL,0x00000000007fc07fULL
#define S390_FEAT_LIST_GEN15_GA1_BASE 0x00f7bfffffffa16fULL,0xfffffe4000000008ULL,0x802000e00700733fULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_GEN15_GA1_DEFAULT 0xedffffffffffb1efULL,0xfffffec0017a9fdfULL,0xffffffffffffffffULL,0xffffffffffffffffULL,0x0000783fffffffffULL
#define S390_FEAT_LIST_GEN15_GA1_FULL 0xffffffffffffffefULL,0xffffffffffffffffULL,0xffffffffffffffffULL,0xffffffffffffffffULL,0x00007fffffffffffULL
/* CPU feature group list data */
#define S390_FEAT_GROUP_LIST_PLO 0x0000000000000000ULL,0xfffffe0000000000ULL,0x0000000000000001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_GROUP_LIST_TOD_CLOCK_STEERING 0x0000000008000000ULL,0x0000000000000000ULL,0x000000000000010eULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_GROUP_LIST_GEN13_PTFF 0x0000000000000000ULL,0x0000000000000000ULL,0x0000000000000230ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_GROUP_LIST_MSA 0x0000000000010000ULL,0x0000000000000000ULL,0x802000e007007000ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_GROUP_LIST_MSA_EXT_1 0x0000000000000000ULL,0x0000000000000000ULL,0x0040080040000000ULL,0x0000000000000001ULL,0x0000000000000000ULL
#define S390_FEAT_GROUP_LIST_MSA_EXT_2 0x0000000000000000ULL,0x0000000000000000ULL,0x0080301180000000ULL,0x0000000000000002ULL,0x0000000000000000ULL
#define S390_FEAT_GROUP_LIST_MSA_EXT_3 0x0000000000000000ULL,0x0000000000000001ULL,0x0001c70e38038000ULL,0x0000000000003f00ULL,0x0000000000000000ULL
#define S390_FEAT_GROUP_LIST_MSA_EXT_4 0x0000000000000000ULL,0x0000000000000002ULL,0x401e000000fc0000ULL,0xfffffffffff80000ULL,0x000000000000007fULL
#define S390_FEAT_GROUP_LIST_MSA_EXT_5 0x0008000000000000ULL,0x0000000000000000ULL,0x0000000000000000ULL,0x0000000000000000ULL,0x0000000000004000ULL
#define S390_FEAT_GROUP_LIST_MSA_EXT_6 0x0000000000000000ULL,0x0000000000000000ULL,0x3f00000000000000ULL,0x00000000000000fcULL,0x0000000000000000ULL
#define S390_FEAT_GROUP_LIST_MSA_EXT_7 0x0000000000000000ULL,0x0000000000000000ULL,0x0000000000000000ULL,0x0000000000000000ULL,0x0000000000018000ULL
#define S390_FEAT_GROUP_LIST_MSA_EXT_8 0x0000000000000000ULL,0x0000000000008000ULL,0x0000000000000000ULL,0x0000000000000000ULL,0x00000000007e0000ULL
#define S390_FEAT_GROUP_LIST_MSA_EXT_9 0x0000000000000000ULL,0x0000000000200000ULL,0x0000000000000000ULL,0x0000000000000000ULL,0x0000003fff803f80ULL
#define S390_FEAT_GROUP_LIST_MSA_EXT_9_PCKMO 0x0000000000000000ULL,0x0000000000000000ULL,0x0000000000000000ULL,0x000000000007c000ULL,0x0000000000000000ULL
#define S390_FEAT_GROUP_LIST_MULTIPLE_EPOCH_PTFF 0x0000000000000000ULL,0x0000000000000000ULL,0x0000000000000cc0ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_GROUP_LIST_ENH_SORT 0x0000000000000000ULL,0x0000000000040000ULL,0x0000000000000000ULL,0x0000000000000000ULL,0x000007c000000000ULL
#define S390_FEAT_GROUP_LIST_DEFLATE_CONVERSION 0x0000000000000000ULL,0x0000000000080000ULL,0x0000000000000000ULL,0x0000000000000000ULL,0x0000780000000000ULL
/* QEMU (CPU model) feature list data */
#define S390_FEAT_LIST_QEMU_V2_11 0x0000000000000003ULL,0xfffffe0000000000ULL,0x0000000000000001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_QEMU_V3_1 0x1801a463f5b7814fULL,0xfffffe0000000003ULL,0x0000000000000001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_QEMU_V4_0 0x1c01a46bf5b7814fULL,0xfffffe0000000003ULL,0x0000000000000001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_QEMU_V4_1 0x1c03a46bf5b7814fULL,0xfffffe0000000043ULL,0x0000000000000001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_QEMU_LATEST 0x9c03a46bf5b7814fULL,0xfffffe0001000143ULL,0x0000000000000001ULL,0x0000000000000000ULL,0x0000000000000000ULL
#define S390_FEAT_LIST_QEMU_MAX 0x9c0ba46bf5b7814fULL,0xfffffe00010001c3ULL,0x0000000000000001ULL,0x0000000000000000ULL,0x0000000000000000ULL
/* CPU feature group enum type */
typedef enum {
S390_FEAT_GROUP_PLO,
S390_FEAT_GROUP_TOD_CLOCK_STEERING,
S390_FEAT_GROUP_GEN13_PTFF,
S390_FEAT_GROUP_MSA,
S390_FEAT_GROUP_MSA_EXT_1,
S390_FEAT_GROUP_MSA_EXT_2,
S390_FEAT_GROUP_MSA_EXT_3,
S390_FEAT_GROUP_MSA_EXT_4,
S390_FEAT_GROUP_MSA_EXT_5,
S390_FEAT_GROUP_MSA_EXT_6,
S390_FEAT_GROUP_MSA_EXT_7,
S390_FEAT_GROUP_MSA_EXT_8,
S390_FEAT_GROUP_MSA_EXT_9,
S390_FEAT_GROUP_MSA_EXT_9_PCKMO,
S390_FEAT_GROUP_MULTIPLE_EPOCH_PTFF,
S390_FEAT_GROUP_ENH_SORT,
S390_FEAT_GROUP_DEFLATE_CONVERSION,
S390_FEAT_GROUP_MAX,
} S390FeatGroup;
#endif

358
qemu/target/s390x/helper.c Normal file
View File

@ -0,0 +1,358 @@
/*
* S/390 helpers
*
* Copyright (c) 2009 Ulrich Hecht
* Copyright (c) 2011 Alexander Graf
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
#include "qemu/timer.h"
#include "hw/s390x/ioinst.h"
#include "sysemu/tcg.h"
void s390x_tod_timer(void *opaque)
{
cpu_inject_clock_comparator((S390CPU *) opaque);
}
void s390x_cpu_timer(void *opaque)
{
cpu_inject_cpu_timer((S390CPU *) opaque);
}
hwaddr s390_cpu_get_phys_page_debug(CPUState *cs, vaddr vaddr)
{
S390CPU *cpu = S390_CPU(cs);
CPUS390XState *env = &cpu->env;
target_ulong raddr;
int prot;
uint64_t asc = env->psw.mask & PSW_MASK_ASC;
uint64_t tec;
/* 31-Bit mode */
if (!(env->psw.mask & PSW_MASK_64)) {
vaddr &= 0x7fffffff;
}
/* We want to read the code (e.g., see what we are single-stepping).*/
if (asc != PSW_ASC_HOME) {
asc = PSW_ASC_PRIMARY;
}
/*
* We want to read code even if IEP is active. Use MMU_DATA_LOAD instead
* of MMU_INST_FETCH.
*/
if (mmu_translate(env, vaddr, MMU_DATA_LOAD, asc, &raddr, &prot, &tec)) {
return -1;
}
return raddr;
}
hwaddr s390_cpu_get_phys_addr_debug(CPUState *cs, vaddr vaddr)
{
hwaddr phys_addr;
target_ulong page;
page = vaddr & TARGET_PAGE_MASK;
phys_addr = cpu_get_phys_page_debug(cs, page);
phys_addr += (vaddr & ~TARGET_PAGE_MASK);
return phys_addr;
}
static inline bool is_special_wait_psw(uint64_t psw_addr)
{
/* signal quiesce */
return (psw_addr & 0xfffUL) == 0xfffUL;
}
void s390_handle_wait(S390CPU *cpu)
{
#if 0
CPUState *cs = CPU(cpu);
if (s390_cpu_halt(cpu) == 0) {
if (is_special_wait_psw(cpu->env.psw.addr)) {
// qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
} else {
cpu->env.crash_reason = S390_CRASH_REASON_DISABLED_WAIT;
qemu_system_guest_panicked(cpu_get_crash_info(cs));
}
}
#endif
}
void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr)
{
uint64_t old_mask = env->psw.mask;
env->psw.addr = addr;
env->psw.mask = mask;
env->cc_op = (mask >> 44) & 3;
if ((old_mask ^ mask) & PSW_MASK_PER) {
s390_cpu_recompute_watchpoints(env_cpu(env));
}
if (mask & PSW_MASK_WAIT) {
s390_handle_wait(env_archcpu(env));
}
}
uint64_t get_psw_mask(CPUS390XState *env)
{
uint64_t r = env->psw.mask;
env->cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst,
env->cc_vr);
r &= ~PSW_MASK_CC;
assert(!(env->cc_op & ~3));
r |= (uint64_t)env->cc_op << 44;
return r;
}
LowCore *cpu_map_lowcore(CPUS390XState *env)
{
LowCore *lowcore;
hwaddr len = sizeof(LowCore);
lowcore = cpu_physical_memory_map(env_cpu(env)->as, env->psa, &len, true);
if (len < sizeof(LowCore)) {
cpu_abort(env_cpu(env), "Could not map lowcore\n");
}
return lowcore;
}
void cpu_unmap_lowcore(CPUS390XState *env, LowCore *lowcore)
{
cpu_physical_memory_unmap(env_cpu(env)->as, lowcore, sizeof(LowCore), 1, sizeof(LowCore));
}
void do_restart_interrupt(CPUS390XState *env)
{
uint64_t mask, addr;
LowCore *lowcore;
lowcore = cpu_map_lowcore(env);
lowcore->restart_old_psw.mask = cpu_to_be64(get_psw_mask(env));
lowcore->restart_old_psw.addr = cpu_to_be64(env->psw.addr);
mask = be64_to_cpu(lowcore->restart_new_psw.mask);
addr = be64_to_cpu(lowcore->restart_new_psw.addr);
cpu_unmap_lowcore(env, lowcore);
env->pending_int &= ~INTERRUPT_RESTART;
load_psw(env, mask, addr);
}
void s390_cpu_recompute_watchpoints(CPUState *cs)
{
const int wp_flags = BP_CPU | BP_MEM_WRITE | BP_STOP_BEFORE_ACCESS;
S390CPU *cpu = S390_CPU(cs);
CPUS390XState *env = &cpu->env;
/* We are called when the watchpoints have changed. First
remove them all. */
cpu_watchpoint_remove_all(cs, BP_CPU);
/* Return if PER is not enabled */
if (!(env->psw.mask & PSW_MASK_PER)) {
return;
}
/* Return if storage-alteration event is not enabled. */
if (!(env->cregs[9] & PER_CR9_EVENT_STORE)) {
return;
}
if (env->cregs[10] == 0 && env->cregs[11] == -1LL) {
/* We can't create a watchoint spanning the whole memory range, so
split it in two parts. */
cpu_watchpoint_insert(cs, 0, 1ULL << 63, wp_flags, NULL);
cpu_watchpoint_insert(cs, 1ULL << 63, 1ULL << 63, wp_flags, NULL);
} else if (env->cregs[10] > env->cregs[11]) {
/* The address range loops, create two watchpoints. */
cpu_watchpoint_insert(cs, env->cregs[10], -env->cregs[10],
wp_flags, NULL);
cpu_watchpoint_insert(cs, 0, env->cregs[11] + 1, wp_flags, NULL);
} else {
/* Default case, create a single watchpoint. */
cpu_watchpoint_insert(cs, env->cregs[10],
env->cregs[11] - env->cregs[10] + 1,
wp_flags, NULL);
}
}
typedef struct SigpSaveArea {
uint64_t fprs[16]; /* 0x0000 */
uint64_t grs[16]; /* 0x0080 */
PSW psw; /* 0x0100 */
uint8_t pad_0x0110[0x0118 - 0x0110]; /* 0x0110 */
uint32_t prefix; /* 0x0118 */
uint32_t fpc; /* 0x011c */
uint8_t pad_0x0120[0x0124 - 0x0120]; /* 0x0120 */
uint32_t todpr; /* 0x0124 */
uint64_t cputm; /* 0x0128 */
uint64_t ckc; /* 0x0130 */
uint8_t pad_0x0138[0x0140 - 0x0138]; /* 0x0138 */
uint32_t ars[16]; /* 0x0140 */
uint64_t crs[16]; /* 0x0384 */
} SigpSaveArea;
QEMU_BUILD_BUG_ON(sizeof(SigpSaveArea) != 512);
int s390_store_status(S390CPU *cpu, hwaddr addr, bool store_arch)
{
static const uint8_t ar_id = 1;
SigpSaveArea *sa;
hwaddr len = sizeof(*sa);
int i;
sa = cpu_physical_memory_map(CPU(cpu)->as, addr, &len, true);
if (!sa) {
return -EFAULT;
}
if (len != sizeof(*sa)) {
cpu_physical_memory_unmap(CPU(cpu)->as, sa, len, 1, 0);
return -EFAULT;
}
if (store_arch) {
cpu_physical_memory_write(CPU(cpu)->as, offsetof(LowCore, ar_access_id), &ar_id, 1);
}
for (i = 0; i < 16; ++i) {
sa->fprs[i] = cpu_to_be64(*get_freg(&cpu->env, i));
}
for (i = 0; i < 16; ++i) {
sa->grs[i] = cpu_to_be64(cpu->env.regs[i]);
}
sa->psw.addr = cpu_to_be64(cpu->env.psw.addr);
sa->psw.mask = cpu_to_be64(get_psw_mask(&cpu->env));
sa->prefix = cpu_to_be32(cpu->env.psa);
sa->fpc = cpu_to_be32(cpu->env.fpc);
sa->todpr = cpu_to_be32(cpu->env.todpr);
sa->cputm = cpu_to_be64(cpu->env.cputm);
sa->ckc = cpu_to_be64(cpu->env.ckc >> 8);
for (i = 0; i < 16; ++i) {
sa->ars[i] = cpu_to_be32(cpu->env.aregs[i]);
}
for (i = 0; i < 16; ++i) {
sa->crs[i] = cpu_to_be64(cpu->env.cregs[i]);
}
cpu_physical_memory_unmap(CPU(cpu)->as, sa, len, 1, len);
return 0;
}
typedef struct SigpAdtlSaveArea {
uint64_t vregs[32][2]; /* 0x0000 */
uint8_t pad_0x0200[0x0400 - 0x0200]; /* 0x0200 */
uint64_t gscb[4]; /* 0x0400 */
uint8_t pad_0x0420[0x1000 - 0x0420]; /* 0x0420 */
} SigpAdtlSaveArea;
QEMU_BUILD_BUG_ON(sizeof(SigpAdtlSaveArea) != 4096);
#define ADTL_GS_MIN_SIZE 2048 /* minimal size of adtl save area for GS */
int s390_store_adtl_status(S390CPU *cpu, hwaddr addr, hwaddr len)
{
SigpAdtlSaveArea *sa;
hwaddr save = len;
int i;
sa = cpu_physical_memory_map(CPU(cpu)->as, addr, &save, true);
if (!sa) {
return -EFAULT;
}
if (save != len) {
cpu_physical_memory_unmap(CPU(cpu)->as, sa, len, 1, 0);
return -EFAULT;
}
if (s390_has_feat(cpu->env.uc, S390_FEAT_VECTOR)) {
for (i = 0; i < 32; i++) {
sa->vregs[i][0] = cpu_to_be64(cpu->env.vregs[i][0]);
sa->vregs[i][1] = cpu_to_be64(cpu->env.vregs[i][1]);
}
}
if (s390_has_feat(cpu->env.uc, S390_FEAT_GUARDED_STORAGE) && len >= ADTL_GS_MIN_SIZE) {
for (i = 0; i < 4; i++) {
sa->gscb[i] = cpu_to_be64(cpu->env.gscb[i]);
}
}
cpu_physical_memory_unmap(CPU(cpu)->as, sa, len, 1, len);
return 0;
}
const char *cc_name(enum cc_op cc_op)
{
static const char * const cc_names[] = {
[CC_OP_CONST0] = "CC_OP_CONST0",
[CC_OP_CONST1] = "CC_OP_CONST1",
[CC_OP_CONST2] = "CC_OP_CONST2",
[CC_OP_CONST3] = "CC_OP_CONST3",
[CC_OP_DYNAMIC] = "CC_OP_DYNAMIC",
[CC_OP_STATIC] = "CC_OP_STATIC",
[CC_OP_NZ] = "CC_OP_NZ",
[CC_OP_LTGT_32] = "CC_OP_LTGT_32",
[CC_OP_LTGT_64] = "CC_OP_LTGT_64",
[CC_OP_LTUGTU_32] = "CC_OP_LTUGTU_32",
[CC_OP_LTUGTU_64] = "CC_OP_LTUGTU_64",
[CC_OP_LTGT0_32] = "CC_OP_LTGT0_32",
[CC_OP_LTGT0_64] = "CC_OP_LTGT0_64",
[CC_OP_ADD_64] = "CC_OP_ADD_64",
[CC_OP_ADDU_64] = "CC_OP_ADDU_64",
[CC_OP_ADDC_64] = "CC_OP_ADDC_64",
[CC_OP_SUB_64] = "CC_OP_SUB_64",
[CC_OP_SUBU_64] = "CC_OP_SUBU_64",
[CC_OP_SUBB_64] = "CC_OP_SUBB_64",
[CC_OP_ABS_64] = "CC_OP_ABS_64",
[CC_OP_NABS_64] = "CC_OP_NABS_64",
[CC_OP_ADD_32] = "CC_OP_ADD_32",
[CC_OP_ADDU_32] = "CC_OP_ADDU_32",
[CC_OP_ADDC_32] = "CC_OP_ADDC_32",
[CC_OP_SUB_32] = "CC_OP_SUB_32",
[CC_OP_SUBU_32] = "CC_OP_SUBU_32",
[CC_OP_SUBB_32] = "CC_OP_SUBB_32",
[CC_OP_ABS_32] = "CC_OP_ABS_32",
[CC_OP_NABS_32] = "CC_OP_NABS_32",
[CC_OP_COMP_32] = "CC_OP_COMP_32",
[CC_OP_COMP_64] = "CC_OP_COMP_64",
[CC_OP_TM_32] = "CC_OP_TM_32",
[CC_OP_TM_64] = "CC_OP_TM_64",
[CC_OP_NZ_F32] = "CC_OP_NZ_F32",
[CC_OP_NZ_F64] = "CC_OP_NZ_F64",
[CC_OP_NZ_F128] = "CC_OP_NZ_F128",
[CC_OP_ICM] = "CC_OP_ICM",
[CC_OP_SLA_32] = "CC_OP_SLA_32",
[CC_OP_SLA_64] = "CC_OP_SLA_64",
[CC_OP_FLOGR] = "CC_OP_FLOGR",
[CC_OP_LCBB] = "CC_OP_LCBB",
[CC_OP_VC] = "CC_OP_VC",
};
return cc_names[cc_op];
}

358
qemu/target/s390x/helper.h Normal file
View File

@ -0,0 +1,358 @@
DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64)
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)
DEF_HELPER_FLAGS_4(mvc, TCG_CALL_NO_WG, void, env, i32, i64, i64)
DEF_HELPER_FLAGS_4(mvcin, TCG_CALL_NO_WG, void, env, i32, i64, i64)
DEF_HELPER_FLAGS_4(clc, TCG_CALL_NO_WG, i32, env, i32, i64, i64)
DEF_HELPER_3(mvcl, i32, env, i32, i32)
DEF_HELPER_3(clcl, i32, env, i32, i32)
DEF_HELPER_FLAGS_4(clm, TCG_CALL_NO_WG, i32, env, i32, i32, i64)
DEF_HELPER_FLAGS_3(divs32, TCG_CALL_NO_WG, s64, env, s64, s64)
DEF_HELPER_FLAGS_3(divu32, TCG_CALL_NO_WG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(divs64, TCG_CALL_NO_WG, s64, env, s64, s64)
DEF_HELPER_FLAGS_4(divu64, TCG_CALL_NO_WG, i64, env, i64, i64, i64)
DEF_HELPER_3(srst, void, env, i32, i32)
DEF_HELPER_3(srstu, void, env, i32, i32)
DEF_HELPER_4(clst, i64, env, i64, i64, i64)
DEF_HELPER_FLAGS_4(mvn, TCG_CALL_NO_WG, void, env, i32, i64, i64)
DEF_HELPER_FLAGS_4(mvo, TCG_CALL_NO_WG, void, env, i32, i64, i64)
DEF_HELPER_FLAGS_4(mvpg, TCG_CALL_NO_WG, i32, env, i64, i64, i64)
DEF_HELPER_FLAGS_4(mvz, TCG_CALL_NO_WG, void, env, i32, i64, i64)
DEF_HELPER_3(mvst, i32, env, i32, i32)
DEF_HELPER_4(ex, void, env, i32, i64, i64)
DEF_HELPER_FLAGS_4(stam, TCG_CALL_NO_WG, void, env, i32, i64, i32)
DEF_HELPER_FLAGS_4(lam, TCG_CALL_NO_WG, void, env, i32, i64, i32)
DEF_HELPER_4(mvcle, i32, env, i32, i64, i32)
DEF_HELPER_4(mvclu, i32, env, i32, i64, i32)
DEF_HELPER_4(clcle, i32, env, i32, i64, i32)
DEF_HELPER_4(clclu, i32, env, i32, i64, i32)
DEF_HELPER_3(cegb, i64, env, s64, i32)
DEF_HELPER_3(cdgb, i64, env, s64, i32)
DEF_HELPER_3(cxgb, i64, env, s64, i32)
DEF_HELPER_3(celgb, i64, env, i64, i32)
DEF_HELPER_3(cdlgb, i64, env, i64, i32)
DEF_HELPER_3(cxlgb, i64, env, i64, i32)
DEF_HELPER_4(cdsg, void, env, i64, i32, i32)
DEF_HELPER_4(cdsg_parallel, void, env, i64, i32, i32)
DEF_HELPER_4(csst, i32, env, i32, i64, i64)
DEF_HELPER_4(csst_parallel, i32, env, i32, i64, i64)
DEF_HELPER_FLAGS_3(aeb, TCG_CALL_NO_WG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(adb, TCG_CALL_NO_WG, i64, env, i64, i64)
DEF_HELPER_FLAGS_5(axb, TCG_CALL_NO_WG, i64, env, i64, i64, i64, i64)
DEF_HELPER_FLAGS_3(seb, TCG_CALL_NO_WG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(sdb, TCG_CALL_NO_WG, i64, env, i64, i64)
DEF_HELPER_FLAGS_5(sxb, TCG_CALL_NO_WG, i64, env, i64, i64, i64, i64)
DEF_HELPER_FLAGS_3(deb, TCG_CALL_NO_WG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(ddb, TCG_CALL_NO_WG, i64, env, i64, i64)
DEF_HELPER_FLAGS_5(dxb, TCG_CALL_NO_WG, i64, env, i64, i64, i64, i64)
DEF_HELPER_FLAGS_3(meeb, TCG_CALL_NO_WG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(mdeb, TCG_CALL_NO_WG, i64, env, i64, i64)
DEF_HELPER_FLAGS_3(mdb, TCG_CALL_NO_WG, i64, env, i64, i64)
DEF_HELPER_FLAGS_5(mxb, TCG_CALL_NO_WG, i64, env, i64, i64, i64, i64)
DEF_HELPER_FLAGS_4(mxdb, TCG_CALL_NO_WG, i64, env, i64, i64, i64)
DEF_HELPER_FLAGS_2(ldeb, TCG_CALL_NO_WG, i64, env, i64)
DEF_HELPER_FLAGS_4(ldxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32)
DEF_HELPER_FLAGS_2(lxdb, TCG_CALL_NO_WG, i64, env, i64)
DEF_HELPER_FLAGS_2(lxeb, TCG_CALL_NO_WG, i64, env, i64)
DEF_HELPER_FLAGS_3(ledb, TCG_CALL_NO_WG, i64, env, i64, i32)
DEF_HELPER_FLAGS_4(lexb, TCG_CALL_NO_WG, i64, env, i64, i64, i32)
DEF_HELPER_FLAGS_3(ceb, TCG_CALL_NO_WG_SE, i32, env, i64, i64)
DEF_HELPER_FLAGS_3(cdb, TCG_CALL_NO_WG_SE, i32, env, i64, i64)
DEF_HELPER_FLAGS_5(cxb, TCG_CALL_NO_WG_SE, i32, env, i64, i64, i64, i64)
DEF_HELPER_FLAGS_3(keb, TCG_CALL_NO_WG, i32, env, i64, i64)
DEF_HELPER_FLAGS_3(kdb, TCG_CALL_NO_WG, i32, env, i64, i64)
DEF_HELPER_FLAGS_5(kxb, TCG_CALL_NO_WG, i32, env, i64, i64, i64, i64)
DEF_HELPER_FLAGS_3(cgeb, TCG_CALL_NO_WG, i64, env, i64, i32)
DEF_HELPER_FLAGS_3(cgdb, TCG_CALL_NO_WG, i64, env, i64, i32)
DEF_HELPER_FLAGS_4(cgxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32)
DEF_HELPER_FLAGS_3(cfeb, TCG_CALL_NO_WG, i64, env, i64, i32)
DEF_HELPER_FLAGS_3(cfdb, TCG_CALL_NO_WG, i64, env, i64, i32)
DEF_HELPER_FLAGS_4(cfxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32)
DEF_HELPER_FLAGS_3(clgeb, TCG_CALL_NO_WG, i64, env, i64, i32)
DEF_HELPER_FLAGS_3(clgdb, TCG_CALL_NO_WG, i64, env, i64, i32)
DEF_HELPER_FLAGS_4(clgxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32)
DEF_HELPER_FLAGS_3(clfeb, TCG_CALL_NO_WG, i64, env, i64, i32)
DEF_HELPER_FLAGS_3(clfdb, TCG_CALL_NO_WG, i64, env, i64, i32)
DEF_HELPER_FLAGS_4(clfxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32)
DEF_HELPER_FLAGS_3(fieb, TCG_CALL_NO_WG, i64, env, i64, i32)
DEF_HELPER_FLAGS_3(fidb, TCG_CALL_NO_WG, i64, env, i64, i32)
DEF_HELPER_FLAGS_4(fixb, TCG_CALL_NO_WG, i64, env, i64, i64, i32)
DEF_HELPER_FLAGS_4(maeb, TCG_CALL_NO_WG, i64, env, i64, i64, i64)
DEF_HELPER_FLAGS_4(madb, TCG_CALL_NO_WG, i64, env, i64, i64, i64)
DEF_HELPER_FLAGS_4(mseb, TCG_CALL_NO_WG, i64, env, i64, i64, i64)
DEF_HELPER_FLAGS_4(msdb, TCG_CALL_NO_WG, i64, env, i64, i64, i64)
DEF_HELPER_FLAGS_3(tceb, TCG_CALL_NO_RWG_SE, i32, env, i64, i64)
DEF_HELPER_FLAGS_3(tcdb, TCG_CALL_NO_RWG_SE, i32, env, i64, i64)
DEF_HELPER_FLAGS_4(tcxb, TCG_CALL_NO_RWG_SE, i32, env, i64, i64, i64)
DEF_HELPER_FLAGS_2(sqeb, TCG_CALL_NO_WG, i64, env, i64)
DEF_HELPER_FLAGS_2(sqdb, TCG_CALL_NO_WG, i64, env, i64)
DEF_HELPER_FLAGS_3(sqxb, TCG_CALL_NO_WG, i64, env, i64, i64)
DEF_HELPER_FLAGS_1(cvd, TCG_CALL_NO_RWG_SE, i64, s32)
DEF_HELPER_FLAGS_4(pack, TCG_CALL_NO_WG, void, env, i32, i64, i64)
DEF_HELPER_FLAGS_4(pka, TCG_CALL_NO_WG, void, env, i64, i64, i32)
DEF_HELPER_FLAGS_4(pku, TCG_CALL_NO_WG, void, env, i64, i64, i32)
DEF_HELPER_FLAGS_4(unpk, TCG_CALL_NO_WG, void, env, i32, i64, i64)
DEF_HELPER_FLAGS_4(unpka, TCG_CALL_NO_WG, i32, env, i64, i32, i64)
DEF_HELPER_FLAGS_4(unpku, TCG_CALL_NO_WG, i32, env, i64, i32, i64)
DEF_HELPER_FLAGS_3(tp, TCG_CALL_NO_WG, i32, env, i64, i32)
DEF_HELPER_FLAGS_4(tr, TCG_CALL_NO_WG, void, env, i32, i64, i64)
DEF_HELPER_4(tre, i64, env, i64, i64, i64)
DEF_HELPER_4(trt, i32, env, i32, i64, i64)
DEF_HELPER_4(trtr, i32, env, i32, i64, i64)
DEF_HELPER_5(trXX, i32, env, i32, i32, i32, i32)
DEF_HELPER_4(cksm, i64, env, i64, i64, i64)
DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, i32, env, i32, i64, i64, i64)
DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_NO_WG, void, env, i64)
DEF_HELPER_FLAGS_2(sfas, TCG_CALL_NO_WG, void, env, i64)
DEF_HELPER_FLAGS_2(srnm, TCG_CALL_NO_WG, void, env, i64)
DEF_HELPER_FLAGS_1(popcnt, TCG_CALL_NO_RWG_SE, i64, i64)
DEF_HELPER_2(stfle, i32, env, i64)
DEF_HELPER_FLAGS_2(lpq, TCG_CALL_NO_WG, i64, env, i64)
DEF_HELPER_FLAGS_2(lpq_parallel, TCG_CALL_NO_WG, i64, env, i64)
DEF_HELPER_FLAGS_4(stpq, TCG_CALL_NO_WG, void, env, i64, i64, i64)
DEF_HELPER_FLAGS_4(stpq_parallel, TCG_CALL_NO_WG, void, env, i64, i64, i64)
DEF_HELPER_4(mvcos, i32, env, i64, i64, i64)
DEF_HELPER_4(cu12, i32, env, i32, i32, i32)
DEF_HELPER_4(cu14, i32, env, i32, i32, i32)
DEF_HELPER_4(cu21, i32, env, i32, i32, i32)
DEF_HELPER_4(cu24, i32, env, i32, i32, i32)
DEF_HELPER_4(cu41, i32, env, i32, i32, i32)
DEF_HELPER_4(cu42, i32, env, i32, i32, i32)
DEF_HELPER_5(msa, i32, env, i32, i32, i32, i32)
DEF_HELPER_FLAGS_1(stpt, TCG_CALL_NO_RWG, i64, env)
DEF_HELPER_FLAGS_1(stck, TCG_CALL_NO_RWG_SE, i64, env)
DEF_HELPER_FLAGS_3(probe_write_access, TCG_CALL_NO_WG, void, env, i64, i64)
/* === Vector Support Instructions === */
DEF_HELPER_FLAGS_4(vll, TCG_CALL_NO_WG, void, env, ptr, i64, i64)
DEF_HELPER_FLAGS_4(gvec_vpk16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vpk32, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vpk64, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vpks16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vpks32, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vpks64, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_5(gvec_vpks_cc16, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_5(gvec_vpks_cc32, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_5(gvec_vpks_cc64, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vpkls16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vpkls32, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vpkls64, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_5(gvec_vpkls_cc16, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_5(gvec_vpkls_cc32, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_5(gvec_vpkls_cc64, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vperm, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(vstl, TCG_CALL_NO_WG, void, env, cptr, i64, i64)
/* === Vector Integer Instructions === */
DEF_HELPER_FLAGS_4(gvec_vavg8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vavg16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vavgl8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vavgl16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_3(gvec_vclz8, TCG_CALL_NO_RWG, void, ptr, cptr, i32)
DEF_HELPER_FLAGS_3(gvec_vclz16, TCG_CALL_NO_RWG, void, ptr, cptr, i32)
DEF_HELPER_FLAGS_3(gvec_vctz8, TCG_CALL_NO_RWG, void, ptr, cptr, i32)
DEF_HELPER_FLAGS_3(gvec_vctz16, TCG_CALL_NO_RWG, void, ptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vgfm8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vgfm16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vgfm32, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vgfm64, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_5(gvec_vgfma8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_5(gvec_vgfma16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_5(gvec_vgfma32, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_5(gvec_vgfma64, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_5(gvec_vmal8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_5(gvec_vmal16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_5(gvec_vmah8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_5(gvec_vmah16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_5(gvec_vmalh8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_5(gvec_vmalh16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_5(gvec_vmae8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_5(gvec_vmae16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_5(gvec_vmae32, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_5(gvec_vmale8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_5(gvec_vmale16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_5(gvec_vmale32, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_5(gvec_vmao8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_5(gvec_vmao16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_5(gvec_vmao32, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_5(gvec_vmalo8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_5(gvec_vmalo16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_5(gvec_vmalo32, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vmh8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vmh16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vmlh8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vmlh16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vme8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vme16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vme32, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vmle8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vmle16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vmle32, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vmo8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vmo16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vmo32, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vmlo8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vmlo16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vmlo32, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_3(gvec_vpopct8, TCG_CALL_NO_RWG, void, ptr, cptr, i32)
DEF_HELPER_FLAGS_3(gvec_vpopct16, TCG_CALL_NO_RWG, void, ptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_verllv8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_verllv16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_verll8, TCG_CALL_NO_RWG, void, ptr, cptr, i64, i32)
DEF_HELPER_FLAGS_4(gvec_verll16, TCG_CALL_NO_RWG, void, ptr, cptr, i64, i32)
DEF_HELPER_FLAGS_4(gvec_verim8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_verim16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vsl, TCG_CALL_NO_RWG, void, ptr, cptr, i64, i32)
DEF_HELPER_FLAGS_4(gvec_vsra, TCG_CALL_NO_RWG, void, ptr, cptr, i64, i32)
DEF_HELPER_FLAGS_4(gvec_vsrl, TCG_CALL_NO_RWG, void, ptr, cptr, i64, i32)
DEF_HELPER_FLAGS_4(gvec_vscbi8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vscbi16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_4(gvec_vtm, void, ptr, cptr, env, i32)
/* === Vector String Instructions === */
DEF_HELPER_FLAGS_4(gvec_vfae8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vfae16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vfae32, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_5(gvec_vfae_cc8, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_5(gvec_vfae_cc16, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_5(gvec_vfae_cc32, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vfee8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vfee16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vfee32, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_5(gvec_vfee_cc8, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_5(gvec_vfee_cc16, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_5(gvec_vfee_cc32, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vfene8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vfene16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_4(gvec_vfene32, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, i32)
DEF_HELPER_5(gvec_vfene_cc8, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_5(gvec_vfene_cc16, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_5(gvec_vfene_cc32, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_3(gvec_vistr8, TCG_CALL_NO_RWG, void, ptr, cptr, i32)
DEF_HELPER_FLAGS_3(gvec_vistr16, TCG_CALL_NO_RWG, void, ptr, cptr, i32)
DEF_HELPER_FLAGS_3(gvec_vistr32, TCG_CALL_NO_RWG, void, ptr, cptr, i32)
DEF_HELPER_4(gvec_vistr_cc8, void, ptr, cptr, env, i32)
DEF_HELPER_4(gvec_vistr_cc16, void, ptr, cptr, env, i32)
DEF_HELPER_4(gvec_vistr_cc32, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vstrc8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_5(gvec_vstrc16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_5(gvec_vstrc32, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_5(gvec_vstrc_rt8, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_5(gvec_vstrc_rt16, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, cptr, i32)
DEF_HELPER_FLAGS_5(gvec_vstrc_rt32, TCG_CALL_NO_RWG, void, ptr, cptr, cptr, cptr, i32)
DEF_HELPER_6(gvec_vstrc_cc8, void, ptr, cptr, cptr, cptr, env, i32)
DEF_HELPER_6(gvec_vstrc_cc16, void, ptr, cptr, cptr, cptr, env, i32)
DEF_HELPER_6(gvec_vstrc_cc32, void, ptr, cptr, cptr, cptr, env, i32)
DEF_HELPER_6(gvec_vstrc_cc_rt8, void, ptr, cptr, cptr, cptr, env, i32)
DEF_HELPER_6(gvec_vstrc_cc_rt16, void, ptr, cptr, cptr, cptr, env, i32)
DEF_HELPER_6(gvec_vstrc_cc_rt32, void, ptr, cptr, cptr, cptr, env, i32)
/* === Vector Floating-Point Instructions */
DEF_HELPER_FLAGS_5(gvec_vfa64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfa64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_4(gvec_wfc64, void, cptr, cptr, env, i32)
DEF_HELPER_4(gvec_wfk64, void, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfce64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfce64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_5(gvec_vfce64_cc, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_5(gvec_vfce64s_cc, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfch64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfch64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_5(gvec_vfch64_cc, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_5(gvec_vfch64s_cc, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfche64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfche64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_5(gvec_vfche64_cc, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_5(gvec_vfche64s_cc, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vcdg64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vcdg64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vcdlg64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vcdlg64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vcgd64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vcgd64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vclgd64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vclgd64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfd64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfd64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vfi64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vfi64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vfll32, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vfll32s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vflr64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vflr64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfm64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfm64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_6(gvec_vfma64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_6(gvec_vfma64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_6(gvec_vfms64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_6(gvec_vfms64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vfsq64, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_4(gvec_vfsq64s, TCG_CALL_NO_WG, void, ptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfs64, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_FLAGS_5(gvec_vfs64s, TCG_CALL_NO_WG, void, ptr, cptr, cptr, env, i32)
DEF_HELPER_4(gvec_vftci64, void, ptr, cptr, env, i32)
DEF_HELPER_4(gvec_vftci64s, void, ptr, cptr, env, i32)
#ifndef CONFIG_USER_ONLY
DEF_HELPER_3(servc, i32, env, i64, i64)
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_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)
DEF_HELPER_FLAGS_2(spt, TCG_CALL_NO_RWG, void, env, i64)
DEF_HELPER_4(stsi, i32, env, i64, i64, i64)
DEF_HELPER_FLAGS_4(lctl, TCG_CALL_NO_WG, void, env, i32, i64, i32)
DEF_HELPER_FLAGS_4(lctlg, TCG_CALL_NO_WG, void, env, i32, i64, i32)
DEF_HELPER_FLAGS_4(stctl, TCG_CALL_NO_WG, void, env, i32, i64, i32)
DEF_HELPER_FLAGS_4(stctg, TCG_CALL_NO_WG, void, env, i32, i64, i32)
DEF_HELPER_FLAGS_2(testblock, TCG_CALL_NO_WG, i32, env, i64)
DEF_HELPER_FLAGS_3(tprot, TCG_CALL_NO_WG, i32, env, i64, i64)
DEF_HELPER_FLAGS_2(iske, TCG_CALL_NO_RWG_SE, i64, env, i64)
DEF_HELPER_FLAGS_3(sske, TCG_CALL_NO_RWG, void, env, i64, i64)
DEF_HELPER_FLAGS_2(rrbe, TCG_CALL_NO_RWG, i32, env, i64)
DEF_HELPER_4(mvcs, i32, env, i64, i64, i64)
DEF_HELPER_4(mvcp, i32, env, i64, i64, i64)
DEF_HELPER_4(sigp, i32, env, i64, i32, i32)
DEF_HELPER_FLAGS_2(sacf, TCG_CALL_NO_WG, void, env, i64)
DEF_HELPER_FLAGS_4(idte, TCG_CALL_NO_RWG, void, env, i64, i64, i32)
DEF_HELPER_FLAGS_4(ipte, TCG_CALL_NO_RWG, void, env, i64, i64, i32)
DEF_HELPER_FLAGS_1(ptlb, TCG_CALL_NO_RWG, void, env)
DEF_HELPER_FLAGS_1(purge, TCG_CALL_NO_RWG, void, env)
DEF_HELPER_2(lra, i64, env, i64)
DEF_HELPER_1(per_check_exception, void, env)
DEF_HELPER_FLAGS_3(per_branch, TCG_CALL_NO_RWG, void, env, i64, i64)
DEF_HELPER_FLAGS_2(per_ifetch, TCG_CALL_NO_RWG, void, env, i64)
DEF_HELPER_FLAGS_1(per_store_real, TCG_CALL_NO_RWG, void, env)
DEF_HELPER_FLAGS_1(stfl, TCG_CALL_NO_RWG, void, env)
DEF_HELPER_2(xsch, void, env, i64)
DEF_HELPER_2(csch, void, env, i64)
DEF_HELPER_2(hsch, void, env, i64)
DEF_HELPER_3(msch, void, env, i64, i64)
DEF_HELPER_2(rchp, void, env, i64)
DEF_HELPER_2(rsch, void, env, i64)
DEF_HELPER_2(sal, void, env, i64)
DEF_HELPER_4(schm, void, env, i64, i64, i64)
DEF_HELPER_3(ssch, void, env, i64, i64)
DEF_HELPER_2(stcrw, void, env, i64)
DEF_HELPER_3(stsch, void, env, i64, i64)
DEF_HELPER_2(tpi, i32, env, i64)
DEF_HELPER_3(tsch, void, env, i64, i64)
DEF_HELPER_2(chsc, void, env, i64)
DEF_HELPER_2(clp, void, env, i32)
DEF_HELPER_3(pcilg, void, env, i32, i32)
DEF_HELPER_3(pcistg, void, env, i32, i32)
DEF_HELPER_4(stpcifc, void, env, i32, i64, i32)
DEF_HELPER_3(sic, void, env, i64, i64)
DEF_HELPER_3(rpcit, void, env, i32, i32)
DEF_HELPER_5(pcistb, void, env, i32, i32, i64, i32)
DEF_HELPER_4(mpcifc, void, env, i32, i64, i32)
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,81 @@
/* Description of s390 insn formats. */
/* NAME F1, F2... */
F0(E)
F1(I, I(1, 8, 8))
F2(RI_a, R(1, 8), I(2,16,16))
F2(RI_b, R(1, 8), I(2,16,16))
F2(RI_c, M(1, 8), I(2,16,16))
F3(RIE_a, R(1, 8), I(2,16,16), M(3,32))
F4(RIE_b, R(1, 8), R(2,12), M(3,32), I(4,16,16))
F4(RIE_c, R(1, 8), I(2,32, 8), M(3,12), I(4,16,16))
F3(RIE_d, R(1, 8), I(2,16,16), R(3,12))
F3(RIE_e, R(1, 8), I(2,16,16), R(3,12))
F5(RIE_f, R(1, 8), R(2,12), I(3,16,8), I(4,24,8), I(5,32,8))
F3(RIE_g, R(1, 8), I(2,16,16), M(3,12))
F2(RIL_a, R(1, 8), I(2,16,32))
F2(RIL_b, R(1, 8), I(2,16,32))
F2(RIL_c, M(1, 8), I(2,16,32))
F4(RIS, R(1, 8), I(2,32, 8), M(3,12), BD(4,16,20))
/* ??? The PoO does not call out subtypes _a and _b for RR, as it does
for e.g. RX. Our checking requires this for e.g. BCR. */
F2(RR_a, R(1, 8), R(2,12))
F2(RR_b, M(1, 8), R(2,12))
F2(RRE, R(1,24), R(2,28))
F3(RRD, R(1,16), R(2,28), R(3,24))
F4(RRF_a, R(1,24), R(2,28), R(3,16), M(4,20))
F4(RRF_b, R(1,24), R(2,28), R(3,16), M(4,20))
F4(RRF_c, R(1,24), R(2,28), M(3,16), M(4,20))
F4(RRF_d, R(1,24), R(2,28), M(3,16), M(4,20))
F4(RRF_e, R(1,24), R(2,28), M(3,16), M(4,20))
F4(RRS, R(1, 8), R(2,12), M(3,32), BD(4,16,20))
F3(RS_a, R(1, 8), BD(2,16,20), R(3,12))
F3(RS_b, R(1, 8), BD(2,16,20), M(3,12))
F3(RSI, R(1, 8), I(2,16,16), R(3,12))
F2(RSL, L(1, 8, 4), BD(1,16,20))
F3(RSY_a, R(1, 8), BDL(2), R(3,12))
F3(RSY_b, R(1, 8), BDL(2), M(3,12))
F2(RX_a, R(1, 8), BXD(2))
F2(RX_b, M(1, 8), BXD(2))
F3(RXE, R(1, 8), BXD(2), M(3,32))
F3(RXF, R(1,32), BXD(2), R(3, 8))
F2(RXY_a, R(1, 8), BXDL(2))
F2(RXY_b, M(1, 8), BXDL(2))
F1(S, BD(2,16,20))
F2(SI, BD(1,16,20), I(2,8,8))
F2(SIL, BD(1,16,20), I(2,32,16))
F2(SIY, BDL(1), I(2, 8, 8))
F3(SS_a, L(1, 8, 8), BD(1,16,20), BD(2,32,36))
F4(SS_b, L(1, 8, 4), BD(1,16,20), L(2,12,4), BD(2,32,36))
F4(SS_c, L(1, 8, 4), BD(1,16,20), BD(2,32,36), I(3,12, 4))
/* ??? Odd man out. The L1 field here is really a register, but the
easy way to compress the fields has R1 and B1 overlap. */
F4(SS_d, L(1, 8, 4), BD(1,16,20), BD(2,32,36), R(3,12))
F4(SS_e, R(1, 8), BD(2,16,20), R(3,12), BD(4,32,36))
F3(SS_f, BD(1,16,20), L(2,8,8), BD(2,32,36))
F2(SSE, BD(1,16,20), BD(2,32,36))
F3(SSF, BD(1,16,20), BD(2,32,36), R(3,8))
F3(VRI_a, V(1,8), I(2,16,16), M(3,32))
F4(VRI_b, V(1,8), I(2,16,8), I(3,24,8), M(4,32))
F4(VRI_c, V(1,8), V(3,12), I(2,16,16), M(4,32))
F5(VRI_d, V(1,8), V(2,12), V(3,16), I(4,24,8), M(5,32))
F5(VRI_e, V(1,8), V(2,12), I(3,16,12), M(5,28), M(4,32))
F5(VRI_f, V(1,8), V(2,12), V(3,16), M(5,24), I(4,28,8))
F5(VRI_g, V(1,8), V(2,12), I(4,16,8), M(5,24), I(3,28,8))
F3(VRI_h, V(1,8), I(2,16,16), I(3,32,4))
F4(VRI_i, V(1,8), R(2,12), M(4,24), I(3,28,8))
F5(VRR_a, V(1,8), V(2,12), M(5,24), M(4,28), M(3,32))
F5(VRR_b, V(1,8), V(2,12), V(3,16), M(5,24), M(4,32))
F6(VRR_c, V(1,8), V(2,12), V(3,16), M(6,24), M(5,28), M(4,32))
F6(VRR_d, V(1,8), V(2,12), V(3,16), M(5,20), M(6,24), V(4,32))
F6(VRR_e, V(1,8), V(2,12), V(3,16), M(6,20), M(5,28), V(4,32))
F3(VRR_f, V(1,8), R(2,12), R(3,16))
F1(VRR_g, V(1,12))
F3(VRR_h, V(1,12), V(2,16), M(3,24))
F3(VRR_i, R(1,8), V(2,12), M(3,24))
F4(VRS_a, V(1,8), V(3,12), BD(2,16,20), M(4,32))
F4(VRS_b, V(1,8), R(3,12), BD(2,16,20), M(4,32))
F4(VRS_c, R(1,8), V(3,12), BD(2,16,20), M(4,32))
F3(VRS_d, R(3,12), BD(2,16,20), V(1,32))
F4(VRV, V(1,8), V(2,12), BD(2,16,20), M(3,32))
F3(VRX, V(1,8), BXD(2), M(3,32))
F3(VSI, I(3,8,8), BD(2,16,20), V(1,32))

View File

@ -0,0 +1,148 @@
/*
* S/390 integer helper routines
*
* Copyright (c) 2009 Ulrich Hecht
* Copyright (c) 2009 Alexander Graf
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
#include "tcg_s390x.h"
#include "exec/exec-all.h"
#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
/* #define DEBUG_HELPER */
#ifdef DEBUG_HELPER
#define HELPER_LOG(x...) qemu_log(x)
#else
#define HELPER_LOG(x...)
#endif
/* 64/32 -> 32 signed division */
int64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b64)
{
int32_t ret, b = b64;
int64_t q;
if (b == 0) {
tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
}
ret = q = a / b;
env->retxl = a % b;
/* Catch non-representable quotient. */
if (ret != q) {
tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
}
return ret;
}
/* 64/32 -> 32 unsigned division */
uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b64)
{
uint32_t ret, b = b64;
uint64_t q;
if (b == 0) {
tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
}
ret = q = a / b;
env->retxl = a % b;
/* Catch non-representable quotient. */
if (ret != q) {
tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
}
return ret;
}
/* 64/64 -> 64 signed division */
int64_t HELPER(divs64)(CPUS390XState *env, int64_t a, int64_t b)
{
/* Catch divide by zero, and non-representable quotient (MIN / -1). */
if (b == 0 || (b == -1 && a == (1ll << 63))) {
tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
}
env->retxl = a % b;
return a / b;
}
/* 128 -> 64/64 unsigned division */
uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al,
uint64_t b)
{
uint64_t ret;
/* Signal divide by zero. */
if (b == 0) {
tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
}
if (ah == 0) {
/* 64 -> 64/64 case */
env->retxl = al % b;
ret = al / b;
} else {
/* ??? Move i386 idivq helper to host-utils. */
#ifdef CONFIG_INT128
__uint128_t a = ((__uint128_t)ah << 64) | al;
__uint128_t q = a / b;
env->retxl = a % b;
ret = q;
if (ret != q) {
tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
}
#else
/* 32-bit hosts would need special wrapper functionality - just abort if
we encounter such a case; it's very unlikely anyways. */
cpu_abort(env_cpu(env), "128 -> 64/64 division not implemented\n");
#endif
}
return ret;
}
uint64_t HELPER(cvd)(int32_t reg)
{
/* positive 0 */
uint64_t dec = 0x0c;
int64_t bin = reg;
int shift;
if (bin < 0) {
bin = -bin;
dec = 0x0d;
}
for (shift = 4; (shift < 64) && bin; shift += 4) {
dec |= (bin % 10) << shift;
bin /= 10;
}
return dec;
}
uint64_t HELPER(popcnt)(uint64_t val)
{
/* Note that we don't fold past bytes. */
val = (val & 0x5555555555555555ULL) + ((val >> 1) & 0x5555555555555555ULL);
val = (val & 0x3333333333333333ULL) + ((val >> 2) & 0x3333333333333333ULL);
val = (val + (val >> 4)) & 0x0f0f0f0f0f0f0f0fULL;
return val;
}

View File

@ -0,0 +1,366 @@
/*
* s390x internal definitions and helpers
*
* Copyright (c) 2009 Ulrich Hecht
*
* 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 S390X_INTERNAL_H
#define S390X_INTERNAL_H
#include "cpu.h"
#ifndef CONFIG_USER_ONLY
typedef struct LowCore {
/* prefix area: defined by architecture */
uint32_t ccw1[2]; /* 0x000 */
uint32_t ccw2[4]; /* 0x008 */
uint8_t pad1[0x80 - 0x18]; /* 0x018 */
uint32_t ext_params; /* 0x080 */
uint16_t cpu_addr; /* 0x084 */
uint16_t ext_int_code; /* 0x086 */
uint16_t svc_ilen; /* 0x088 */
uint16_t svc_code; /* 0x08a */
uint16_t pgm_ilen; /* 0x08c */
uint16_t pgm_code; /* 0x08e */
uint32_t data_exc_code; /* 0x090 */
uint16_t mon_class_num; /* 0x094 */
uint16_t per_perc_atmid; /* 0x096 */
uint64_t per_address; /* 0x098 */
uint8_t exc_access_id; /* 0x0a0 */
uint8_t per_access_id; /* 0x0a1 */
uint8_t op_access_id; /* 0x0a2 */
uint8_t ar_access_id; /* 0x0a3 */
uint8_t pad2[0xA8 - 0xA4]; /* 0x0a4 */
uint64_t trans_exc_code; /* 0x0a8 */
uint64_t monitor_code; /* 0x0b0 */
uint16_t subchannel_id; /* 0x0b8 */
uint16_t subchannel_nr; /* 0x0ba */
uint32_t io_int_parm; /* 0x0bc */
uint32_t io_int_word; /* 0x0c0 */
uint8_t pad3[0xc8 - 0xc4]; /* 0x0c4 */
uint32_t stfl_fac_list; /* 0x0c8 */
uint8_t pad4[0xe8 - 0xcc]; /* 0x0cc */
uint64_t mcic; /* 0x0e8 */
uint8_t pad5[0xf4 - 0xf0]; /* 0x0f0 */
uint32_t external_damage_code; /* 0x0f4 */
uint64_t failing_storage_address; /* 0x0f8 */
uint8_t pad6[0x110 - 0x100]; /* 0x100 */
uint64_t per_breaking_event_addr; /* 0x110 */
uint8_t pad7[0x120 - 0x118]; /* 0x118 */
PSW restart_old_psw; /* 0x120 */
PSW external_old_psw; /* 0x130 */
PSW svc_old_psw; /* 0x140 */
PSW program_old_psw; /* 0x150 */
PSW mcck_old_psw; /* 0x160 */
PSW io_old_psw; /* 0x170 */
uint8_t pad8[0x1a0 - 0x180]; /* 0x180 */
PSW restart_new_psw; /* 0x1a0 */
PSW external_new_psw; /* 0x1b0 */
PSW svc_new_psw; /* 0x1c0 */
PSW program_new_psw; /* 0x1d0 */
PSW mcck_new_psw; /* 0x1e0 */
PSW io_new_psw; /* 0x1f0 */
uint8_t pad13[0x11b0 - 0x200]; /* 0x200 */
uint64_t mcesad; /* 0x11B0 */
/* 64 bit extparam used for pfault, diag 250 etc */
uint64_t ext_params2; /* 0x11B8 */
uint8_t pad14[0x1200 - 0x11C0]; /* 0x11C0 */
/* System info area */
uint64_t floating_pt_save_area[16]; /* 0x1200 */
uint64_t gpregs_save_area[16]; /* 0x1280 */
uint32_t st_status_fixed_logout[4]; /* 0x1300 */
uint8_t pad15[0x1318 - 0x1310]; /* 0x1310 */
uint32_t prefixreg_save_area; /* 0x1318 */
uint32_t fpt_creg_save_area; /* 0x131c */
uint8_t pad16[0x1324 - 0x1320]; /* 0x1320 */
uint32_t tod_progreg_save_area; /* 0x1324 */
uint64_t cpu_timer_save_area; /* 0x1328 */
uint64_t clock_comp_save_area; /* 0x1330 */
uint8_t pad17[0x1340 - 0x1338]; /* 0x1338 */
uint32_t access_regs_save_area[16]; /* 0x1340 */
uint64_t cregs_save_area[16]; /* 0x1380 */
/* align to the top of the prefix area */
uint8_t pad18[0x2000 - 0x1400]; /* 0x1400 */
} QEMU_PACKED LowCore;
QEMU_BUILD_BUG_ON(sizeof(LowCore) != 8192);
#endif /* CONFIG_USER_ONLY */
#define MAX_ILEN 6
/* While the PoO talks about ILC (a number between 1-3) what is actually
stored in LowCore is shifted left one bit (an even between 2-6). As
this is the actual length of the insn and therefore more useful, that
is what we want to pass around and manipulate. To make sure that we
have applied this distinction universally, rename the "ILC" to "ILEN". */
static inline int get_ilen(uint8_t opc)
{
switch (opc >> 6) {
case 0:
return 2;
case 1:
case 2:
return 4;
default:
return 6;
}
}
/* Compute the ATMID field that is stored in the per_perc_atmid lowcore
entry when a PER exception is triggered. */
static inline uint8_t get_per_atmid(CPUS390XState *env)
{
return ((env->psw.mask & PSW_MASK_64) ? (1 << 7) : 0) |
(1 << 6) |
((env->psw.mask & PSW_MASK_32) ? (1 << 5) : 0) |
((env->psw.mask & PSW_MASK_DAT) ? (1 << 4) : 0) |
((env->psw.mask & PSW_ASC_SECONDARY) ? (1 << 3) : 0) |
((env->psw.mask & PSW_ASC_ACCREG) ? (1 << 2) : 0);
}
static inline uint64_t wrap_address(CPUS390XState *env, uint64_t a)
{
if (!(env->psw.mask & PSW_MASK_64)) {
if (!(env->psw.mask & PSW_MASK_32)) {
/* 24-Bit mode */
a &= 0x00ffffff;
} else {
/* 31-Bit mode */
a &= 0x7fffffff;
}
}
return a;
}
/* CC optimization */
/* Instead of computing the condition codes after each x86 instruction,
* QEMU just stores the result (called CC_DST), the type of operation
* (called CC_OP) and whatever operands are needed (CC_SRC and possibly
* CC_VR). When the condition codes are needed, the condition codes can
* be calculated using this information. Condition codes are not generated
* if they are only needed for conditional branches.
*/
enum cc_op {
CC_OP_CONST0 = 0, /* CC is 0 */
CC_OP_CONST1, /* CC is 1 */
CC_OP_CONST2, /* CC is 2 */
CC_OP_CONST3, /* CC is 3 */
CC_OP_DYNAMIC, /* CC calculation defined by env->cc_op */
CC_OP_STATIC, /* CC value is env->cc_op */
CC_OP_NZ, /* env->cc_dst != 0 */
CC_OP_LTGT_32, /* signed less/greater than (32bit) */
CC_OP_LTGT_64, /* signed less/greater than (64bit) */
CC_OP_LTUGTU_32, /* unsigned less/greater than (32bit) */
CC_OP_LTUGTU_64, /* unsigned less/greater than (64bit) */
CC_OP_LTGT0_32, /* signed less/greater than 0 (32bit) */
CC_OP_LTGT0_64, /* signed less/greater than 0 (64bit) */
CC_OP_ADD_64, /* overflow on add (64bit) */
CC_OP_ADDU_64, /* overflow on unsigned add (64bit) */
CC_OP_ADDC_64, /* overflow on unsigned add-carry (64bit) */
CC_OP_SUB_64, /* overflow on subtraction (64bit) */
CC_OP_SUBU_64, /* overflow on unsigned subtraction (64bit) */
CC_OP_SUBB_64, /* overflow on unsigned sub-borrow (64bit) */
CC_OP_ABS_64, /* sign eval on abs (64bit) */
CC_OP_NABS_64, /* sign eval on nabs (64bit) */
CC_OP_ADD_32, /* overflow on add (32bit) */
CC_OP_ADDU_32, /* overflow on unsigned add (32bit) */
CC_OP_ADDC_32, /* overflow on unsigned add-carry (32bit) */
CC_OP_SUB_32, /* overflow on subtraction (32bit) */
CC_OP_SUBU_32, /* overflow on unsigned subtraction (32bit) */
CC_OP_SUBB_32, /* overflow on unsigned sub-borrow (32bit) */
CC_OP_ABS_32, /* sign eval on abs (64bit) */
CC_OP_NABS_32, /* sign eval on nabs (64bit) */
CC_OP_COMP_32, /* complement */
CC_OP_COMP_64, /* complement */
CC_OP_TM_32, /* test under mask (32bit) */
CC_OP_TM_64, /* test under mask (64bit) */
CC_OP_NZ_F32, /* FP dst != 0 (32bit) */
CC_OP_NZ_F64, /* FP dst != 0 (64bit) */
CC_OP_NZ_F128, /* FP dst != 0 (128bit) */
CC_OP_ICM, /* insert characters under mask */
CC_OP_SLA_32, /* Calculate shift left signed (32bit) */
CC_OP_SLA_64, /* Calculate shift left signed (64bit) */
CC_OP_FLOGR, /* find leftmost one */
CC_OP_LCBB, /* load count to block boundary */
CC_OP_VC, /* vector compare result */
CC_OP_MAX
};
static inline hwaddr decode_basedisp_s(CPUS390XState *env, uint32_t ipb,
uint8_t *ar)
{
hwaddr addr = 0;
uint8_t reg;
reg = ipb >> 28;
if (reg > 0) {
addr = env->regs[reg];
}
addr += (ipb >> 16) & 0xfff;
if (ar) {
*ar = reg;
}
return addr;
}
/* Base/displacement are at the same locations. */
#define decode_basedisp_rs decode_basedisp_s
/* cc_helper.c */
const char *cc_name(enum cc_op cc_op);
void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr);
uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
uint64_t vr);
/* cpu.c */
unsigned int s390_cpu_halt(S390CPU *cpu);
void s390_cpu_unhalt(S390CPU *cpu);
/* cpu_models.c */
void s390_cpu_model_register_props(CPUState *obj);
void s390_cpu_model_class_register_props(CPUClass *oc);
void s390_realize_cpu_model(CPUState *cs);
CPUClass *s390_cpu_class_by_name(const char *name);
/* excp_helper.c */
void s390x_cpu_debug_excp_handler(CPUState *cs);
void s390_cpu_do_interrupt(CPUState *cpu);
bool s390_cpu_exec_interrupt(CPUState *cpu, int int_req);
bool s390_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
MMUAccessType access_type, int mmu_idx,
bool probe, uintptr_t retaddr);
void s390x_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
MMUAccessType access_type,
int mmu_idx, uintptr_t retaddr);
/* fpu_helper.c */
uint32_t set_cc_nz_f32(float32 v);
uint32_t set_cc_nz_f64(float64 v);
uint32_t set_cc_nz_f128(float128 v);
#define S390_IEEE_MASK_INVALID 0x80
#define S390_IEEE_MASK_DIVBYZERO 0x40
#define S390_IEEE_MASK_OVERFLOW 0x20
#define S390_IEEE_MASK_UNDERFLOW 0x10
#define S390_IEEE_MASK_INEXACT 0x08
#define S390_IEEE_MASK_QUANTUM 0x04
uint8_t s390_softfloat_exc_to_ieee(unsigned int exc);
int s390_swap_bfp_rounding_mode(CPUS390XState *env, int m3);
void s390_restore_bfp_rounding_mode(CPUS390XState *env, int old_mode);
int float_comp_to_cc(CPUS390XState *env, int float_compare);
uint16_t float32_dcmask(CPUS390XState *env, float32 f1);
uint16_t float64_dcmask(CPUS390XState *env, float64 f1);
uint16_t float128_dcmask(CPUS390XState *env, float128 f1);
/* gdbstub.c */
int s390_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int s390_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void s390_cpu_gdb_init(CPUState *cs);
/* helper.c */
void s390_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
hwaddr s390_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
hwaddr s390_cpu_get_phys_addr_debug(CPUState *cpu, vaddr addr);
uint64_t get_psw_mask(CPUS390XState *env);
void s390_cpu_recompute_watchpoints(CPUState *cs);
void s390x_tod_timer(void *opaque);
void s390x_cpu_timer(void *opaque);
void do_restart_interrupt(CPUS390XState *env);
void s390_handle_wait(S390CPU *cpu);
#define S390_STORE_STATUS_DEF_ADDR offsetof(LowCore, floating_pt_save_area)
int s390_store_status(S390CPU *cpu, hwaddr addr, bool store_arch);
int s390_store_adtl_status(S390CPU *cpu, hwaddr addr, hwaddr len);
#ifndef CONFIG_USER_ONLY
LowCore *cpu_map_lowcore(CPUS390XState *env);
void cpu_unmap_lowcore(CPUS390XState *env, LowCore *lowcore);
#endif /* CONFIG_USER_ONLY */
/* interrupt.c */
void trigger_pgm_exception(CPUS390XState *env, uint32_t code);
void cpu_inject_clock_comparator(S390CPU *cpu);
void cpu_inject_cpu_timer(S390CPU *cpu);
void cpu_inject_emergency_signal(S390CPU *cpu, uint16_t src_cpu_addr);
int cpu_inject_external_call(S390CPU *cpu, uint16_t src_cpu_addr);
bool s390_cpu_has_io_int(S390CPU *cpu);
bool s390_cpu_has_ext_int(S390CPU *cpu);
bool s390_cpu_has_mcck_int(S390CPU *cpu);
bool s390_cpu_has_int(S390CPU *cpu);
bool s390_cpu_has_restart_int(S390CPU *cpu);
bool s390_cpu_has_stop_int(S390CPU *cpu);
void cpu_inject_restart(S390CPU *cpu);
void cpu_inject_stop(S390CPU *cpu);
/* ioinst.c */
void ioinst_handle_xsch(S390CPU *cpu, uint64_t reg1, uintptr_t ra);
void ioinst_handle_csch(S390CPU *cpu, uint64_t reg1, uintptr_t ra);
void ioinst_handle_hsch(S390CPU *cpu, uint64_t reg1, uintptr_t ra);
void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb,
uintptr_t ra);
void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb,
uintptr_t ra);
void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb, uintptr_t ra);
void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb,
uintptr_t ra);
int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra);
void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb, uintptr_t ra);
void ioinst_handle_schm(S390CPU *cpu, uint64_t reg1, uint64_t reg2,
uint32_t ipb, uintptr_t ra);
void ioinst_handle_rsch(S390CPU *cpu, uint64_t reg1, uintptr_t ra);
void ioinst_handle_rchp(S390CPU *cpu, uint64_t reg1, uintptr_t ra);
void ioinst_handle_sal(S390CPU *cpu, uint64_t reg1, uintptr_t ra);
/* mem_helper.c */
target_ulong mmu_real2abs(CPUS390XState *env, target_ulong raddr);
void probe_write_access(CPUS390XState *env, uint64_t addr, uint64_t len,
uintptr_t ra);
/* mmu_helper.c */
int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
target_ulong *raddr, int *flags, uint64_t *tec);
int mmu_translate_real(CPUS390XState *env, target_ulong raddr, int rw,
target_ulong *addr, int *flags, uint64_t *tec);
/* misc_helper.c */
int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3);
void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3,
uintptr_t ra);
/* translate.c */
void s390x_translate_init(struct uc_struct *uc);
/* sigp.c */
int handle_sigp(CPUS390XState *env, uint8_t order, uint64_t r1, uint64_t r3);
void do_stop_interrupt(CPUS390XState *env);
#endif /* S390X_INTERNAL_H */

View File

@ -0,0 +1,233 @@
/*
* QEMU S/390 Interrupt support
*
* Copyright IBM Corp. 2012, 2014
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at your
* option) any later version. See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "cpu.h"
#include "internal.h"
#include "exec/exec-all.h"
#include "sysemu/tcg.h"
#include "hw/s390x/ioinst.h"
#include "tcg_s390x.h"
//#include "hw/s390x/s390_flic.h"
/* Ensure to exit the TB after this call! */
void trigger_pgm_exception(CPUS390XState *env, uint32_t code)
{
CPUState *cs = env_cpu(env);
cs->exception_index = EXCP_PGM;
env->int_pgm_code = code;
/* env->int_pgm_ilen is already set, or will be set during unwinding */
}
void s390_program_interrupt(CPUS390XState *env, uint32_t code, uintptr_t ra)
{
tcg_s390_program_interrupt(env, code, ra);
}
void cpu_inject_clock_comparator(S390CPU *cpu)
{
CPUS390XState *env = &cpu->env;
env->pending_int |= INTERRUPT_EXT_CLOCK_COMPARATOR;
cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
}
void cpu_inject_cpu_timer(S390CPU *cpu)
{
CPUS390XState *env = &cpu->env;
env->pending_int |= INTERRUPT_EXT_CPU_TIMER;
cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
}
void cpu_inject_emergency_signal(S390CPU *cpu, uint16_t src_cpu_addr)
{
CPUS390XState *env = &cpu->env;
g_assert(src_cpu_addr < S390_MAX_CPUS);
set_bit(src_cpu_addr, env->emergency_signals);
env->pending_int |= INTERRUPT_EMERGENCY_SIGNAL;
cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
}
int cpu_inject_external_call(S390CPU *cpu, uint16_t src_cpu_addr)
{
CPUS390XState *env = &cpu->env;
g_assert(src_cpu_addr < S390_MAX_CPUS);
if (env->pending_int & INTERRUPT_EXTERNAL_CALL) {
return -EBUSY;
}
env->external_call_addr = src_cpu_addr;
env->pending_int |= INTERRUPT_EXTERNAL_CALL;
cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
return 0;
}
void cpu_inject_restart(S390CPU *cpu)
{
CPUS390XState *env = &cpu->env;
env->pending_int |= INTERRUPT_RESTART;
cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
}
void cpu_inject_stop(S390CPU *cpu)
{
CPUS390XState *env = &cpu->env;
env->pending_int |= INTERRUPT_STOP;
cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
}
/*
* All of the following interrupts are floating, i.e. not per-vcpu.
* We just need a dummy cpustate in order to be able to inject in the
* non-kvm case.
*/
void s390_sclp_extint(uint32_t parm)
{
#if 0
S390FLICState *fs = s390_get_flic();
S390FLICStateClass *fsc = s390_get_flic_class(fs);
fsc->inject_service(fs, parm);
#endif
}
void s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr,
uint32_t io_int_parm, uint32_t io_int_word)
{
#if 0
S390FLICState *fs = s390_get_flic();
S390FLICStateClass *fsc = s390_get_flic_class(fs);
fsc->inject_io(fs, subchannel_id, subchannel_nr, io_int_parm, io_int_word);
#endif
}
void s390_crw_mchk(void)
{
#if 0
S390FLICState *fs = s390_get_flic();
S390FLICStateClass *fsc = s390_get_flic_class(fs);
fsc->inject_crw_mchk(fs);
#endif
}
bool s390_cpu_has_mcck_int(S390CPU *cpu)
{
#if 0
QEMUS390FLICState *flic = s390_get_qemu_flic(s390_get_flic());
CPUS390XState *env = &cpu->env;
if (!(env->psw.mask & PSW_MASK_MCHECK)) {
return false;
}
/* for now we only support channel report machine checks (floating) */
if (qemu_s390_flic_has_crw_mchk(flic) &&
(env->cregs[14] & CR14_CHANNEL_REPORT_SC)) {
return true;
}
#endif
return false;
}
bool s390_cpu_has_ext_int(S390CPU *cpu)
{
#if 0
QEMUS390FLICState *flic = s390_get_qemu_flic(s390_get_flic());
CPUS390XState *env = &cpu->env;
if (!(env->psw.mask & PSW_MASK_EXT)) {
return false;
}
if ((env->pending_int & INTERRUPT_EMERGENCY_SIGNAL) &&
(env->cregs[0] & CR0_EMERGENCY_SIGNAL_SC)) {
return true;
}
if ((env->pending_int & INTERRUPT_EXTERNAL_CALL) &&
(env->cregs[0] & CR0_EXTERNAL_CALL_SC)) {
return true;
}
if ((env->pending_int & INTERRUPT_EXTERNAL_CALL) &&
(env->cregs[0] & CR0_EXTERNAL_CALL_SC)) {
return true;
}
if ((env->pending_int & INTERRUPT_EXT_CLOCK_COMPARATOR) &&
(env->cregs[0] & CR0_CKC_SC)) {
return true;
}
if ((env->pending_int & INTERRUPT_EXT_CPU_TIMER) &&
(env->cregs[0] & CR0_CPU_TIMER_SC)) {
return true;
}
if (qemu_s390_flic_has_service(flic) &&
(env->cregs[0] & CR0_SERVICE_SC)) {
return true;
}
#endif
return false;
}
bool s390_cpu_has_io_int(S390CPU *cpu)
{
#if 0
QEMUS390FLICState *flic = s390_get_qemu_flic(s390_get_flic());
CPUS390XState *env = &cpu->env;
if (!(env->psw.mask & PSW_MASK_IO)) {
return false;
}
return qemu_s390_flic_has_io(flic, env->cregs[6]);
#endif
return false;
}
bool s390_cpu_has_restart_int(S390CPU *cpu)
{
return false;
#if 0
CPUS390XState *env = &cpu->env;
return env->pending_int & INTERRUPT_RESTART;
#endif
}
bool s390_cpu_has_stop_int(S390CPU *cpu)
{
CPUS390XState *env = &cpu->env;
return env->pending_int & INTERRUPT_STOP;
}
bool s390_cpu_has_int(S390CPU *cpu)
{
return s390_cpu_has_mcck_int(cpu) ||
s390_cpu_has_ext_int(cpu) ||
s390_cpu_has_io_int(cpu) ||
s390_cpu_has_restart_int(cpu) ||
s390_cpu_has_stop_int(cpu);
}

788
qemu/target/s390x/ioinst.c Normal file
View File

@ -0,0 +1,788 @@
/*
* I/O instructions for S/390
*
* Copyright 2012, 2015 IBM Corp.
* Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at
* your option) any later version. See the COPYING file in the top-level
* directory.
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
#include "hw/s390x/ioinst.h"
//#include "hw/s390x/s390-pci-bus.h"
int ioinst_disassemble_sch_ident(uint32_t value, int *m, int *cssid, int *ssid,
int *schid)
{
if (!IOINST_SCHID_ONE(value)) {
return -EINVAL;
}
if (!IOINST_SCHID_M(value)) {
if (IOINST_SCHID_CSSID(value)) {
return -EINVAL;
}
*cssid = 0;
*m = 0;
} else {
*cssid = IOINST_SCHID_CSSID(value);
*m = 1;
}
*ssid = IOINST_SCHID_SSID(value);
*schid = IOINST_SCHID_NR(value);
return 0;
}
void ioinst_handle_xsch(S390CPU *cpu, uint64_t reg1, uintptr_t ra)
{
#if 0
int cssid, ssid, schid, m;
SubchDev *sch;
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
s390_program_interrupt(&cpu->env, PGM_OPERAND, ra);
return;
}
trace_ioinst_sch_id("xsch", cssid, ssid, schid);
sch = css_find_subch(m, cssid, ssid, schid);
if (!sch || !css_subch_visible(sch)) {
setcc(cpu, 3);
return;
}
setcc(cpu, css_do_xsch(sch));
#endif
}
void ioinst_handle_csch(S390CPU *cpu, uint64_t reg1, uintptr_t ra)
{
#if 0
int cssid, ssid, schid, m;
SubchDev *sch;
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
s390_program_interrupt(&cpu->env, PGM_OPERAND, ra);
return;
}
trace_ioinst_sch_id("csch", cssid, ssid, schid);
sch = css_find_subch(m, cssid, ssid, schid);
if (!sch || !css_subch_visible(sch)) {
setcc(cpu, 3);
return;
}
setcc(cpu, css_do_csch(sch));
#endif
}
void ioinst_handle_hsch(S390CPU *cpu, uint64_t reg1, uintptr_t ra)
{
#if 0
int cssid, ssid, schid, m;
SubchDev *sch;
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
s390_program_interrupt(&cpu->env, PGM_OPERAND, ra);
return;
}
trace_ioinst_sch_id("hsch", cssid, ssid, schid);
sch = css_find_subch(m, cssid, ssid, schid);
if (!sch || !css_subch_visible(sch)) {
setcc(cpu, 3);
return;
}
setcc(cpu, css_do_hsch(sch));
#endif
}
static int ioinst_schib_valid(SCHIB *schib)
{
if ((be16_to_cpu(schib->pmcw.flags) & PMCW_FLAGS_MASK_INVALID) ||
(be32_to_cpu(schib->pmcw.chars) & PMCW_CHARS_MASK_INVALID)) {
return 0;
}
/* Disallow extended measurements for now. */
if (be32_to_cpu(schib->pmcw.chars) & PMCW_CHARS_MASK_XMWME) {
return 0;
}
return 1;
}
void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra)
{
#if 0
int cssid, ssid, schid, m;
SubchDev *sch;
SCHIB schib;
uint64_t addr;
CPUS390XState *env = &cpu->env;
uint8_t ar;
addr = decode_basedisp_s(env, ipb, &ar);
if (addr & 3) {
s390_program_interrupt(env, PGM_SPECIFICATION, ra);
return;
}
if (s390_cpu_virt_mem_read(cpu, addr, ar, &schib, sizeof(schib))) {
s390_cpu_virt_mem_handle_exc(cpu, ra);
return;
}
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) ||
!ioinst_schib_valid(&schib)) {
s390_program_interrupt(env, PGM_OPERAND, ra);
return;
}
trace_ioinst_sch_id("msch", cssid, ssid, schid);
sch = css_find_subch(m, cssid, ssid, schid);
if (!sch || !css_subch_visible(sch)) {
setcc(cpu, 3);
return;
}
setcc(cpu, css_do_msch(sch, &schib));
#endif
}
static void copy_orb_from_guest(ORB *dest, const ORB *src)
{
dest->intparm = be32_to_cpu(src->intparm);
dest->ctrl0 = be16_to_cpu(src->ctrl0);
dest->lpm = src->lpm;
dest->ctrl1 = src->ctrl1;
dest->cpa = be32_to_cpu(src->cpa);
}
static int ioinst_orb_valid(ORB *orb)
{
if ((orb->ctrl0 & ORB_CTRL0_MASK_INVALID) ||
(orb->ctrl1 & ORB_CTRL1_MASK_INVALID)) {
return 0;
}
/* We don't support MIDA. */
if (orb->ctrl1 & ORB_CTRL1_MASK_MIDAW) {
return 0;
}
if ((orb->cpa & HIGH_ORDER_BIT) != 0) {
return 0;
}
return 1;
}
void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra)
{
#if 0
int cssid, ssid, schid, m;
SubchDev *sch;
ORB orig_orb, orb;
uint64_t addr;
CPUS390XState *env = &cpu->env;
uint8_t ar;
addr = decode_basedisp_s(env, ipb, &ar);
if (addr & 3) {
s390_program_interrupt(env, PGM_SPECIFICATION, ra);
return;
}
if (s390_cpu_virt_mem_read(cpu, addr, ar, &orig_orb, sizeof(orb))) {
s390_cpu_virt_mem_handle_exc(cpu, ra);
return;
}
copy_orb_from_guest(&orb, &orig_orb);
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) ||
!ioinst_orb_valid(&orb)) {
s390_program_interrupt(env, PGM_OPERAND, ra);
return;
}
trace_ioinst_sch_id("ssch", cssid, ssid, schid);
sch = css_find_subch(m, cssid, ssid, schid);
if (!sch || !css_subch_visible(sch)) {
setcc(cpu, 3);
return;
}
setcc(cpu, css_do_ssch(sch, &orb));
#endif
}
void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb, uintptr_t ra)
{
#if 0
CRW crw;
uint64_t addr;
int cc;
CPUS390XState *env = &cpu->env;
uint8_t ar;
addr = decode_basedisp_s(env, ipb, &ar);
if (addr & 3) {
s390_program_interrupt(env, PGM_SPECIFICATION, ra);
return;
}
cc = css_do_stcrw(&crw);
/* 0 - crw stored, 1 - zeroes stored */
if (s390_cpu_virt_mem_write(cpu, addr, ar, &crw, sizeof(crw)) == 0) {
setcc(cpu, cc);
} else {
if (cc == 0) {
/* Write failed: requeue CRW since STCRW is suppressing */
css_undo_stcrw(&crw);
}
s390_cpu_virt_mem_handle_exc(cpu, ra);
}
#endif
}
void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb,
uintptr_t ra)
{
#if 0
int cssid, ssid, schid, m;
SubchDev *sch;
uint64_t addr;
int cc;
SCHIB schib;
CPUS390XState *env = &cpu->env;
uint8_t ar;
addr = decode_basedisp_s(env, ipb, &ar);
if (addr & 3) {
s390_program_interrupt(env, PGM_SPECIFICATION, ra);
return;
}
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
/*
* As operand exceptions have a lower priority than access exceptions,
* we check whether the memory area is writeable (injecting the
* access execption if it is not) first.
*/
if (!s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib))) {
s390_program_interrupt(env, PGM_OPERAND, ra);
} else {
s390_cpu_virt_mem_handle_exc(cpu, ra);
}
return;
}
trace_ioinst_sch_id("stsch", cssid, ssid, schid);
sch = css_find_subch(m, cssid, ssid, schid);
if (sch) {
if (css_subch_visible(sch)) {
css_do_stsch(sch, &schib);
cc = 0;
} else {
/* Indicate no more subchannels in this css/ss */
cc = 3;
}
} else {
if (css_schid_final(m, cssid, ssid, schid)) {
cc = 3; /* No more subchannels in this css/ss */
} else {
/* Store an empty schib. */
memset(&schib, 0, sizeof(schib));
cc = 0;
}
}
if (cc != 3) {
if (s390_cpu_virt_mem_write(cpu, addr, ar, &schib,
sizeof(schib)) != 0) {
s390_cpu_virt_mem_handle_exc(cpu, ra);
return;
}
} else {
/* Access exceptions have a higher priority than cc3 */
if (s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib)) != 0) {
s390_cpu_virt_mem_handle_exc(cpu, ra);
return;
}
}
setcc(cpu, cc);
#endif
}
int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra)
{
#if 0
CPUS390XState *env = &cpu->env;
int cssid, ssid, schid, m;
SubchDev *sch;
IRB irb;
uint64_t addr;
int cc, irb_len;
uint8_t ar;
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
s390_program_interrupt(env, PGM_OPERAND, ra);
return -EIO;
}
trace_ioinst_sch_id("tsch", cssid, ssid, schid);
addr = decode_basedisp_s(env, ipb, &ar);
if (addr & 3) {
s390_program_interrupt(env, PGM_SPECIFICATION, ra);
return -EIO;
}
sch = css_find_subch(m, cssid, ssid, schid);
if (sch && css_subch_visible(sch)) {
cc = css_do_tsch_get_irb(sch, &irb, &irb_len);
} else {
cc = 3;
}
/* 0 - status pending, 1 - not status pending, 3 - not operational */
if (cc != 3) {
if (s390_cpu_virt_mem_write(cpu, addr, ar, &irb, irb_len) != 0) {
s390_cpu_virt_mem_handle_exc(cpu, ra);
return -EFAULT;
}
css_do_tsch_update_subch(sch);
} else {
irb_len = sizeof(irb) - sizeof(irb.emw);
/* Access exceptions have a higher priority than cc3 */
if (s390_cpu_virt_mem_check_write(cpu, addr, ar, irb_len) != 0) {
s390_cpu_virt_mem_handle_exc(cpu, ra);
return -EFAULT;
}
}
setcc(cpu, cc);
#endif
return 0;
}
typedef struct ChscReq {
uint16_t len;
uint16_t command;
uint32_t param0;
uint32_t param1;
uint32_t param2;
} QEMU_PACKED ChscReq;
typedef struct ChscResp {
uint16_t len;
uint16_t code;
uint32_t param;
char data[];
} QEMU_PACKED ChscResp;
#define CHSC_MIN_RESP_LEN 0x0008
#define CHSC_SCPD 0x0002
#define CHSC_SCSC 0x0010
#define CHSC_SDA 0x0031
#define CHSC_SEI 0x000e
#define CHSC_SCPD_0_M 0x20000000
#define CHSC_SCPD_0_C 0x10000000
#define CHSC_SCPD_0_FMT 0x0f000000
#define CHSC_SCPD_0_CSSID 0x00ff0000
#define CHSC_SCPD_0_RFMT 0x00000f00
#define CHSC_SCPD_0_RES 0xc000f000
#define CHSC_SCPD_1_RES 0xffffff00
#define CHSC_SCPD_01_CHPID 0x000000ff
static void ioinst_handle_chsc_scpd(ChscReq *req, ChscResp *res)
{
#if 0
uint16_t len = be16_to_cpu(req->len);
uint32_t param0 = be32_to_cpu(req->param0);
uint32_t param1 = be32_to_cpu(req->param1);
uint16_t resp_code;
int rfmt;
uint16_t cssid;
uint8_t f_chpid, l_chpid;
int desc_size;
int m;
rfmt = (param0 & CHSC_SCPD_0_RFMT) >> 8;
if ((rfmt == 0) || (rfmt == 1)) {
rfmt = !!(param0 & CHSC_SCPD_0_C);
}
if ((len != 0x0010) || (param0 & CHSC_SCPD_0_RES) ||
(param1 & CHSC_SCPD_1_RES) || req->param2) {
resp_code = 0x0003;
goto out_err;
}
if (param0 & CHSC_SCPD_0_FMT) {
resp_code = 0x0007;
goto out_err;
}
cssid = (param0 & CHSC_SCPD_0_CSSID) >> 16;
m = param0 & CHSC_SCPD_0_M;
if (cssid != 0) {
if (!m || !css_present(cssid)) {
resp_code = 0x0008;
goto out_err;
}
}
f_chpid = param0 & CHSC_SCPD_01_CHPID;
l_chpid = param1 & CHSC_SCPD_01_CHPID;
if (l_chpid < f_chpid) {
resp_code = 0x0003;
goto out_err;
}
/* css_collect_chp_desc() is endian-aware */
desc_size = css_collect_chp_desc(m, cssid, f_chpid, l_chpid, rfmt,
&res->data);
res->code = cpu_to_be16(0x0001);
res->len = cpu_to_be16(8 + desc_size);
res->param = cpu_to_be32(rfmt);
return;
out_err:
res->code = cpu_to_be16(resp_code);
res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
res->param = cpu_to_be32(rfmt);
#endif
}
#define CHSC_SCSC_0_M 0x20000000
#define CHSC_SCSC_0_FMT 0x000f0000
#define CHSC_SCSC_0_CSSID 0x0000ff00
#define CHSC_SCSC_0_RES 0xdff000ff
static void ioinst_handle_chsc_scsc(ChscReq *req, ChscResp *res)
{
#if 0
uint16_t len = be16_to_cpu(req->len);
uint32_t param0 = be32_to_cpu(req->param0);
uint8_t cssid;
uint16_t resp_code;
uint32_t general_chars[510];
uint32_t chsc_chars[508];
if (len != 0x0010) {
resp_code = 0x0003;
goto out_err;
}
if (param0 & CHSC_SCSC_0_FMT) {
resp_code = 0x0007;
goto out_err;
}
cssid = (param0 & CHSC_SCSC_0_CSSID) >> 8;
if (cssid != 0) {
if (!(param0 & CHSC_SCSC_0_M) || !css_present(cssid)) {
resp_code = 0x0008;
goto out_err;
}
}
if ((param0 & CHSC_SCSC_0_RES) || req->param1 || req->param2) {
resp_code = 0x0003;
goto out_err;
}
res->code = cpu_to_be16(0x0001);
res->len = cpu_to_be16(4080);
res->param = 0;
memset(general_chars, 0, sizeof(general_chars));
memset(chsc_chars, 0, sizeof(chsc_chars));
general_chars[0] = cpu_to_be32(0x03000000);
general_chars[1] = cpu_to_be32(0x00079000);
general_chars[3] = cpu_to_be32(0x00080000);
chsc_chars[0] = cpu_to_be32(0x40000000);
chsc_chars[3] = cpu_to_be32(0x00040000);
memcpy(res->data, general_chars, sizeof(general_chars));
memcpy(res->data + sizeof(general_chars), chsc_chars, sizeof(chsc_chars));
return;
out_err:
res->code = cpu_to_be16(resp_code);
res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
res->param = 0;
#endif
}
#define CHSC_SDA_0_FMT 0x0f000000
#define CHSC_SDA_0_OC 0x0000ffff
#define CHSC_SDA_0_RES 0xf0ff0000
#define CHSC_SDA_OC_MCSSE 0x0
#define CHSC_SDA_OC_MSS 0x2
static void ioinst_handle_chsc_sda(ChscReq *req, ChscResp *res)
{
#if 0
uint16_t resp_code = 0x0001;
uint16_t len = be16_to_cpu(req->len);
uint32_t param0 = be32_to_cpu(req->param0);
uint16_t oc;
int ret;
if ((len != 0x0400) || (param0 & CHSC_SDA_0_RES)) {
resp_code = 0x0003;
goto out;
}
if (param0 & CHSC_SDA_0_FMT) {
resp_code = 0x0007;
goto out;
}
oc = param0 & CHSC_SDA_0_OC;
switch (oc) {
case CHSC_SDA_OC_MCSSE:
ret = css_enable_mcsse();
if (ret == -EINVAL) {
resp_code = 0x0101;
goto out;
}
break;
case CHSC_SDA_OC_MSS:
ret = css_enable_mss();
if (ret == -EINVAL) {
resp_code = 0x0101;
goto out;
}
break;
default:
resp_code = 0x0003;
goto out;
}
out:
res->code = cpu_to_be16(resp_code);
res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
res->param = 0;
#endif
}
static int chsc_sei_nt0_get_event(void *res)
{
/* no events yet */
return 1;
}
static int chsc_sei_nt0_have_event(void)
{
/* no events yet */
return 0;
}
#if 0
static int chsc_sei_nt2_get_event(void *res)
{
if (s390_has_feat(uc, S390_FEAT_ZPCI)) {
// return pci_chsc_sei_nt2_get_event(res);
}
return 1;
}
static int chsc_sei_nt2_have_event(void)
{
if (s390_has_feat(uc, S390_FEAT_ZPCI)) {
// return pci_chsc_sei_nt2_have_event();
}
return 0;
}
#endif
#define CHSC_SEI_NT0 (1ULL << 63)
#define CHSC_SEI_NT2 (1ULL << 61)
static void ioinst_handle_chsc_sei(ChscReq *req, ChscResp *res)
{
#if 0
uint64_t selection_mask = ldq_p(&req->param1);
uint8_t *res_flags = (uint8_t *)res->data;
int have_event = 0;
int have_more = 0;
/* regarding architecture nt0 can not be masked */
have_event = !chsc_sei_nt0_get_event(res);
have_more = chsc_sei_nt0_have_event();
if (selection_mask & CHSC_SEI_NT2) {
if (!have_event) {
have_event = !chsc_sei_nt2_get_event(res);
}
if (!have_more) {
have_more = chsc_sei_nt2_have_event();
}
}
if (have_event) {
res->code = cpu_to_be16(0x0001);
if (have_more) {
(*res_flags) |= 0x80;
} else {
(*res_flags) &= ~0x80;
css_clear_sei_pending();
}
} else {
res->code = cpu_to_be16(0x0005);
res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
}
#endif
}
static void ioinst_handle_chsc_unimplemented(ChscResp *res)
{
res->len = cpu_to_be16(CHSC_MIN_RESP_LEN);
res->code = cpu_to_be16(0x0004);
res->param = 0;
}
void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb, uintptr_t ra)
{
ChscReq *req;
ChscResp *res;
uint64_t addr;
int reg;
uint16_t len;
uint16_t command;
CPUS390XState *env = &cpu->env;
uint8_t buf[TARGET_PAGE_SIZE];
reg = (ipb >> 20) & 0x00f;
addr = env->regs[reg];
/* Page boundary? */
if (addr & 0xfff) {
s390_program_interrupt(env, PGM_SPECIFICATION, ra);
return;
}
/*
* Reading sizeof(ChscReq) bytes is currently enough for all of our
* present CHSC sub-handlers ... if we ever need more, we should take
* care of req->len here first.
*/
if (s390_cpu_virt_mem_read(cpu, addr, reg, buf, sizeof(ChscReq))) {
s390_cpu_virt_mem_handle_exc(cpu, ra);
return;
}
req = (ChscReq *)buf;
len = be16_to_cpu(req->len);
/* Length field valid? */
if ((len < 16) || (len > 4088) || (len & 7)) {
s390_program_interrupt(env, PGM_OPERAND, ra);
return;
}
memset((char *)req + len, 0, TARGET_PAGE_SIZE - len);
res = (void *)((char *)req + len);
command = be16_to_cpu(req->command);
switch (command) {
case CHSC_SCSC:
ioinst_handle_chsc_scsc(req, res);
break;
case CHSC_SCPD:
ioinst_handle_chsc_scpd(req, res);
break;
case CHSC_SDA:
ioinst_handle_chsc_sda(req, res);
break;
case CHSC_SEI:
ioinst_handle_chsc_sei(req, res);
break;
default:
ioinst_handle_chsc_unimplemented(res);
break;
}
if (!s390_cpu_virt_mem_write(cpu, addr + len, reg, res,
be16_to_cpu(res->len))) {
setcc(cpu, 0); /* Command execution complete */
} else {
s390_cpu_virt_mem_handle_exc(cpu, ra);
}
}
#define SCHM_REG1_RES(_reg) (_reg & 0x000000000ffffffc)
#define SCHM_REG1_MBK(_reg) ((_reg & 0x00000000f0000000) >> 28)
#define SCHM_REG1_UPD(_reg) ((_reg & 0x0000000000000002) >> 1)
#define SCHM_REG1_DCT(_reg) (_reg & 0x0000000000000001)
void ioinst_handle_schm(S390CPU *cpu, uint64_t reg1, uint64_t reg2,
uint32_t ipb, uintptr_t ra)
{
#if 0
uint8_t mbk;
int update;
int dct;
CPUS390XState *env = &cpu->env;
if (SCHM_REG1_RES(reg1)) {
s390_program_interrupt(env, PGM_OPERAND, ra);
return;
}
mbk = SCHM_REG1_MBK(reg1);
update = SCHM_REG1_UPD(reg1);
dct = SCHM_REG1_DCT(reg1);
if (update && (reg2 & 0x000000000000001f)) {
s390_program_interrupt(env, PGM_OPERAND, ra);
return;
}
css_do_schm(mbk, update, dct, update ? reg2 : 0);
#endif
}
void ioinst_handle_rsch(S390CPU *cpu, uint64_t reg1, uintptr_t ra)
{
#if 0
int cssid, ssid, schid, m;
SubchDev *sch;
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
s390_program_interrupt(&cpu->env, PGM_OPERAND, ra);
return;
}
trace_ioinst_sch_id("rsch", cssid, ssid, schid);
sch = css_find_subch(m, cssid, ssid, schid);
if (!sch || !css_subch_visible(sch)) {
setcc(cpu, 3);
return;
}
setcc(cpu, css_do_rsch(sch));
#endif
}
#define RCHP_REG1_RES(_reg) (_reg & 0x00000000ff00ff00)
#define RCHP_REG1_CSSID(_reg) ((_reg & 0x0000000000ff0000) >> 16)
#define RCHP_REG1_CHPID(_reg) (_reg & 0x00000000000000ff)
void ioinst_handle_rchp(S390CPU *cpu, uint64_t reg1, uintptr_t ra)
{
#if 0
int cc;
uint8_t cssid;
uint8_t chpid;
int ret;
CPUS390XState *env = &cpu->env;
if (RCHP_REG1_RES(reg1)) {
s390_program_interrupt(env, PGM_OPERAND, ra);
return;
}
cssid = RCHP_REG1_CSSID(reg1);
chpid = RCHP_REG1_CHPID(reg1);
ret = css_do_rchp(cssid, chpid);
switch (ret) {
case -ENODEV:
cc = 3;
break;
case -EBUSY:
cc = 2;
break;
case 0:
cc = 0;
break;
default:
/* Invalid channel subsystem. */
s390_program_interrupt(env, PGM_OPERAND, ra);
return;
}
setcc(cpu, cc);
#endif
}
#define SAL_REG1_INVALID(_reg) (_reg & 0x0000000080000000)
void ioinst_handle_sal(S390CPU *cpu, uint64_t reg1, uintptr_t ra)
{
/* We do not provide address limit checking, so let's suppress it. */
if (SAL_REG1_INVALID(reg1) || reg1 & 0x000000000000ffff) {
s390_program_interrupt(&cpu->env, PGM_OPERAND, ra);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,815 @@
/*
* S/390 misc helper routines
*
* Copyright (c) 2009 Ulrich Hecht
* Copyright (c) 2009 Alexander Graf
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
#include "exec/memory.h"
#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
#include "qemu/timer.h"
#include "exec/exec-all.h"
#include "exec/cpu_ldst.h"
#include "tcg_s390x.h"
#include "s390-tod.h"
#include "sysemu/cpus.h"
#include "sysemu/sysemu.h"
#include "hw/s390x/ebcdic.h"
//#include "hw/s390x/sclp.h"
//#include "hw/s390x/s390_flic.h"
#include "hw/s390x/ioinst.h"
//#include "hw/s390x/s390-pci-inst.h"
//#include "hw/s390x/tod.h"
/* #define DEBUG_HELPER */
#ifdef DEBUG_HELPER
#define HELPER_LOG(x...) qemu_log(x)
#else
#define HELPER_LOG(x...)
#endif
/* Raise an exception statically from a TB. */
void HELPER(exception)(CPUS390XState *env, uint32_t excp)
{
CPUState *cs = env_cpu(env);
HELPER_LOG("%s: exception %d\n", __func__, excp);
cs->exception_index = excp;
cpu_loop_exit(cs);
}
/* Store CPU Timer (also used for EXTRACT CPU TIME) */
uint64_t HELPER(stpt)(CPUS390XState *env)
{
return time2tod(env->cputm - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
}
/* Store Clock */
uint64_t HELPER(stck)(CPUS390XState *env)
{
#if 0
S390TODState *td = s390_get_todstate();
S390TODClass *tdc = S390_TOD_GET_CLASS(td);
S390TOD tod;
tdc->get(td, &tod, &error_abort);
return tod.low;
#endif
return 0;
}
/* SCLP service call */
uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2)
{
#if 0
qemu_mutex_lock_iothread();
int r = sclp_service_call(env, r1, r2);
qemu_mutex_unlock_iothread();
if (r < 0) {
tcg_s390_program_interrupt(env, -r, GETPC());
}
return r;
#endif
return 0;
}
void HELPER(diag)(CPUS390XState *env, uint32_t r1, uint32_t r3, uint32_t num)
{
#if 0
uint64_t r;
switch (num) {
case 0x500:
/* KVM hypercall */
qemu_mutex_lock_iothread();
r = s390_virtio_hypercall(env);
qemu_mutex_unlock_iothread();
break;
case 0x44:
/* yield */
r = 0;
break;
case 0x308:
/* ipl */
qemu_mutex_lock_iothread();
handle_diag_308(env, r1, r3, GETPC());
qemu_mutex_unlock_iothread();
r = 0;
break;
case 0x288:
/* time bomb (watchdog) */
r = handle_diag_288(env, r1, r3);
break;
default:
r = -1;
break;
}
if (r) {
tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
}
#endif
}
/* Set Prefix */
void HELPER(spx)(CPUS390XState *env, uint64_t a1)
{
CPUState *cs = env_cpu(env);
uint32_t prefix = a1 & 0x7fffe000;
env->psa = prefix;
HELPER_LOG("prefix: %#x\n", prefix);
tlb_flush_page(cs, 0);
tlb_flush_page(cs, TARGET_PAGE_SIZE);
}
static void update_ckc_timer(CPUS390XState *env)
{
#if 0
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;
}
/* difference between origins */
time = env->ckc - td->base.low;
/* nanoseconds */
time = tod2time(time);
timer_mod(env->tod_timer, time);
#endif
}
/* Set Clock Comparator */
void HELPER(sckc)(CPUS390XState *env, uint64_t ckc)
{
#if 0
env->ckc = ckc;
qemu_mutex_lock_iothread();
update_ckc_timer(env);
qemu_mutex_unlock_iothread();
#endif
}
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)
{
#if 0
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();
#endif
return 0;
}
/* Set Tod Programmable Field */
void HELPER(sckpf)(CPUS390XState *env, uint64_t r0)
{
uint32_t val = r0;
if (val & 0xffff0000) {
tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
}
env->todpr = val;
}
/* Store Clock Comparator */
uint64_t HELPER(stckc)(CPUS390XState *env)
{
return env->ckc;
}
/* Set CPU Timer */
void HELPER(spt)(CPUS390XState *env, uint64_t time)
{
if (time == -1ULL) {
return;
}
/* nanoseconds */
time = tod2time(time);
env->cputm = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time;
// timer_mod(env->cpu_timer, env->cputm);
}
/* Store System Information */
uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, uint64_t r0, uint64_t r1)
{
#if 0
const uintptr_t ra = GETPC();
const uint32_t sel1 = r0 & STSI_R0_SEL1_MASK;
const uint32_t sel2 = r1 & STSI_R1_SEL2_MASK;
const MachineState *ms = MACHINE(qdev_get_machine());
uint16_t total_cpus = 0, conf_cpus = 0, reserved_cpus = 0;
S390CPU *cpu = env_archcpu(env);
SysIB sysib = { };
int i, cc = 0;
if ((r0 & STSI_R0_FC_MASK) > STSI_R0_FC_LEVEL_3) {
/* invalid function code: no other checks are performed */
return 3;
}
if ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK)) {
tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
}
if ((r0 & STSI_R0_FC_MASK) == STSI_R0_FC_CURRENT) {
/* query the current level: no further checks are performed */
env->regs[0] = STSI_R0_FC_LEVEL_3;
return 0;
}
if (a0 & ~TARGET_PAGE_MASK) {
tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
}
/* count the cpus and split them into configured and reserved ones */
for (i = 0; i < ms->possible_cpus->len; i++) {
total_cpus++;
if (ms->possible_cpus->cpus[i].cpu) {
conf_cpus++;
} else {
reserved_cpus++;
}
}
/*
* In theory, we could report Level 1 / Level 2 as current. However,
* the Linux kernel will detect this as running under LPAR and assume
* that we have a sclp linemode console (which is always present on
* LPAR, but not the default for QEMU), therefore not displaying boot
* messages and making booting a Linux kernel under TCG harder.
*
* For now we fake the same SMP configuration on all levels.
*
* TODO: We could later make the level configurable via the machine
* and change defaults (linemode console) based on machine type
* and accelerator.
*/
switch (r0 & STSI_R0_FC_MASK) {
case STSI_R0_FC_LEVEL_1:
if ((sel1 == 1) && (sel2 == 1)) {
/* Basic Machine Configuration */
char type[5] = {};
ebcdic_put(sysib.sysib_111.manuf, "QEMU ", 16);
/* same as machine type number in STORE CPU ID, but in EBCDIC */
snprintf(type, ARRAY_SIZE(type), "%X", cpu->model->def->type);
ebcdic_put(sysib.sysib_111.type, type, 4);
/* model number (not stored in STORE CPU ID for z/Architecure) */
ebcdic_put(sysib.sysib_111.model, "QEMU ", 16);
ebcdic_put(sysib.sysib_111.sequence, "QEMU ", 16);
ebcdic_put(sysib.sysib_111.plant, "QEMU", 4);
} else if ((sel1 == 2) && (sel2 == 1)) {
/* Basic Machine CPU */
ebcdic_put(sysib.sysib_121.sequence, "QEMUQEMUQEMUQEMU", 16);
ebcdic_put(sysib.sysib_121.plant, "QEMU", 4);
sysib.sysib_121.cpu_addr = cpu_to_be16(env->core_id);
} else if ((sel1 == 2) && (sel2 == 2)) {
/* Basic Machine CPUs */
sysib.sysib_122.capability = cpu_to_be32(0x443afc29);
sysib.sysib_122.total_cpus = cpu_to_be16(total_cpus);
sysib.sysib_122.conf_cpus = cpu_to_be16(conf_cpus);
sysib.sysib_122.reserved_cpus = cpu_to_be16(reserved_cpus);
} else {
cc = 3;
}
break;
case STSI_R0_FC_LEVEL_2:
if ((sel1 == 2) && (sel2 == 1)) {
/* LPAR CPU */
ebcdic_put(sysib.sysib_221.sequence, "QEMUQEMUQEMUQEMU", 16);
ebcdic_put(sysib.sysib_221.plant, "QEMU", 4);
sysib.sysib_221.cpu_addr = cpu_to_be16(env->core_id);
} else if ((sel1 == 2) && (sel2 == 2)) {
/* LPAR CPUs */
sysib.sysib_222.lcpuc = 0x80; /* dedicated */
sysib.sysib_222.total_cpus = cpu_to_be16(total_cpus);
sysib.sysib_222.conf_cpus = cpu_to_be16(conf_cpus);
sysib.sysib_222.reserved_cpus = cpu_to_be16(reserved_cpus);
ebcdic_put(sysib.sysib_222.name, "QEMU ", 8);
sysib.sysib_222.caf = cpu_to_be32(1000);
sysib.sysib_222.dedicated_cpus = cpu_to_be16(conf_cpus);
} else {
cc = 3;
}
break;
case STSI_R0_FC_LEVEL_3:
if ((sel1 == 2) && (sel2 == 2)) {
/* VM CPUs */
sysib.sysib_322.count = 1;
sysib.sysib_322.vm[0].total_cpus = cpu_to_be16(total_cpus);
sysib.sysib_322.vm[0].conf_cpus = cpu_to_be16(conf_cpus);
sysib.sysib_322.vm[0].reserved_cpus = cpu_to_be16(reserved_cpus);
sysib.sysib_322.vm[0].caf = cpu_to_be32(1000);
/* Linux kernel uses this to distinguish us from z/VM */
ebcdic_put(sysib.sysib_322.vm[0].cpi, "KVM/Linux ", 16);
sysib.sysib_322.vm[0].ext_name_encoding = 2; /* UTF-8 */
/* If our VM has a name, use the real name */
if (qemu_name) {
memset(sysib.sysib_322.vm[0].name, 0x40,
sizeof(sysib.sysib_322.vm[0].name));
ebcdic_put(sysib.sysib_322.vm[0].name, qemu_name,
MIN(sizeof(sysib.sysib_322.vm[0].name),
strlen(qemu_name)));
strncpy((char *)sysib.sysib_322.ext_names[0], qemu_name,
sizeof(sysib.sysib_322.ext_names[0]));
} else {
ebcdic_put(sysib.sysib_322.vm[0].name, "TCGguest", 8);
strcpy((char *)sysib.sysib_322.ext_names[0], "TCGguest");
}
/* add the uuid */
memcpy(sysib.sysib_322.vm[0].uuid, &qemu_uuid,
sizeof(sysib.sysib_322.vm[0].uuid));
} else {
cc = 3;
}
break;
}
if (cc == 0) {
if (s390_cpu_virt_mem_write(cpu, a0, 0, &sysib, sizeof(sysib))) {
s390_cpu_virt_mem_handle_exc(cpu, ra);
}
}
return cc;
#endif
return 0;
}
uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
uint32_t r3)
{
#if 0
int cc;
/* TODO: needed to inject interrupts - push further down */
qemu_mutex_lock_iothread();
cc = handle_sigp(env, order_code & SIGP_ORDER_MASK, r1, r3);
qemu_mutex_unlock_iothread();
return cc;
#endif
return 0;
}
void HELPER(xsch)(CPUS390XState *env, uint64_t r1)
{
#if 0
S390CPU *cpu = env_archcpu(env);
qemu_mutex_lock_iothread();
ioinst_handle_xsch(cpu, r1, GETPC());
qemu_mutex_unlock_iothread();
#endif
}
void HELPER(csch)(CPUS390XState *env, uint64_t r1)
{
#if 0
S390CPU *cpu = env_archcpu(env);
qemu_mutex_lock_iothread();
ioinst_handle_csch(cpu, r1, GETPC());
qemu_mutex_unlock_iothread();
#endif
}
void HELPER(hsch)(CPUS390XState *env, uint64_t r1)
{
#if 0
S390CPU *cpu = env_archcpu(env);
qemu_mutex_lock_iothread();
ioinst_handle_hsch(cpu, r1, GETPC());
qemu_mutex_unlock_iothread();
#endif
}
void HELPER(msch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
{
#if 0
S390CPU *cpu = env_archcpu(env);
qemu_mutex_lock_iothread();
ioinst_handle_msch(cpu, r1, inst >> 16, GETPC());
qemu_mutex_unlock_iothread();
#endif
}
void HELPER(rchp)(CPUS390XState *env, uint64_t r1)
{
#if 0
S390CPU *cpu = env_archcpu(env);
qemu_mutex_lock_iothread();
ioinst_handle_rchp(cpu, r1, GETPC());
qemu_mutex_unlock_iothread();
#endif
}
void HELPER(rsch)(CPUS390XState *env, uint64_t r1)
{
#if 0
S390CPU *cpu = env_archcpu(env);
qemu_mutex_lock_iothread();
ioinst_handle_rsch(cpu, r1, GETPC());
qemu_mutex_unlock_iothread();
#endif
}
void HELPER(sal)(CPUS390XState *env, uint64_t r1)
{
#if 0
S390CPU *cpu = env_archcpu(env);
qemu_mutex_lock_iothread();
ioinst_handle_sal(cpu, r1, GETPC());
qemu_mutex_unlock_iothread();
#endif
}
void HELPER(schm)(CPUS390XState *env, uint64_t r1, uint64_t r2, uint64_t inst)
{
#if 0
S390CPU *cpu = env_archcpu(env);
qemu_mutex_lock_iothread();
ioinst_handle_schm(cpu, r1, r2, inst >> 16, GETPC());
qemu_mutex_unlock_iothread();
#endif
}
void HELPER(ssch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
{
#if 0
S390CPU *cpu = env_archcpu(env);
qemu_mutex_lock_iothread();
ioinst_handle_ssch(cpu, r1, inst >> 16, GETPC());
qemu_mutex_unlock_iothread();
#endif
}
void HELPER(stcrw)(CPUS390XState *env, uint64_t inst)
{
#if 0
S390CPU *cpu = env_archcpu(env);
qemu_mutex_lock_iothread();
ioinst_handle_stcrw(cpu, inst >> 16, GETPC());
qemu_mutex_unlock_iothread();
#endif
}
void HELPER(stsch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
{
#if 0
S390CPU *cpu = env_archcpu(env);
qemu_mutex_lock_iothread();
ioinst_handle_stsch(cpu, r1, inst >> 16, GETPC());
qemu_mutex_unlock_iothread();
#endif
}
uint32_t HELPER(tpi)(CPUS390XState *env, uint64_t addr)
{
#if 0
const uintptr_t ra = GETPC();
S390CPU *cpu = env_archcpu(env);
QEMUS390FLICState *flic = s390_get_qemu_flic(s390_get_flic());
QEMUS390FlicIO *io = NULL;
LowCore *lowcore;
if (addr & 0x3) {
tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
}
qemu_mutex_lock_iothread();
io = qemu_s390_flic_dequeue_io(flic, env->cregs[6]);
if (!io) {
qemu_mutex_unlock_iothread();
return 0;
}
if (addr) {
struct {
uint16_t id;
uint16_t nr;
uint32_t parm;
} intc = {
.id = cpu_to_be16(io->id),
.nr = cpu_to_be16(io->nr),
.parm = cpu_to_be32(io->parm),
};
if (s390_cpu_virt_mem_write(cpu, addr, 0, &intc, sizeof(intc))) {
/* writing failed, reinject and properly clean up */
s390_io_interrupt(io->id, io->nr, io->parm, io->word);
qemu_mutex_unlock_iothread();
g_free(io);
s390_cpu_virt_mem_handle_exc(cpu, ra);
return 0;
}
} else {
/* no protection applies */
lowcore = cpu_map_lowcore(env);
lowcore->subchannel_id = cpu_to_be16(io->id);
lowcore->subchannel_nr = cpu_to_be16(io->nr);
lowcore->io_int_parm = cpu_to_be32(io->parm);
lowcore->io_int_word = cpu_to_be32(io->word);
cpu_unmap_lowcore(env, lowcore);
}
g_free(io);
qemu_mutex_unlock_iothread();
#endif
return 1;
}
void HELPER(tsch)(CPUS390XState *env, uint64_t r1, uint64_t inst)
{
#if 0
S390CPU *cpu = env_archcpu(env);
qemu_mutex_lock_iothread();
ioinst_handle_tsch(cpu, r1, inst >> 16, GETPC());
qemu_mutex_unlock_iothread();
#endif
}
void HELPER(chsc)(CPUS390XState *env, uint64_t inst)
{
#if 0
S390CPU *cpu = env_archcpu(env);
qemu_mutex_lock_iothread();
ioinst_handle_chsc(cpu, inst >> 16, GETPC());
qemu_mutex_unlock_iothread();
#endif
}
void HELPER(per_check_exception)(CPUS390XState *env)
{
if (env->per_perc_atmid) {
tcg_s390_program_interrupt(env, PGM_PER, GETPC());
}
}
/* Check if an address is within the PER starting address and the PER
ending address. The address range might loop. */
static inline bool get_per_in_range(CPUS390XState *env, uint64_t addr)
{
if (env->cregs[10] <= env->cregs[11]) {
return env->cregs[10] <= addr && addr <= env->cregs[11];
} else {
return env->cregs[10] <= addr || addr <= env->cregs[11];
}
}
void HELPER(per_branch)(CPUS390XState *env, uint64_t from, uint64_t to)
{
if ((env->cregs[9] & PER_CR9_EVENT_BRANCH)) {
if (!(env->cregs[9] & PER_CR9_CONTROL_BRANCH_ADDRESS)
|| get_per_in_range(env, to)) {
env->per_address = from;
env->per_perc_atmid = PER_CODE_EVENT_BRANCH | get_per_atmid(env);
}
}
}
void HELPER(per_ifetch)(CPUS390XState *env, uint64_t addr)
{
if ((env->cregs[9] & PER_CR9_EVENT_IFETCH) && get_per_in_range(env, addr)) {
env->per_address = addr;
env->per_perc_atmid = PER_CODE_EVENT_IFETCH | get_per_atmid(env);
/* If the instruction has to be nullified, trigger the
exception immediately. */
if (env->cregs[9] & PER_CR9_EVENT_NULLIFICATION) {
CPUState *cs = env_cpu(env);
env->per_perc_atmid |= PER_CODE_EVENT_NULLIFICATION;
env->int_pgm_code = PGM_PER;
env->int_pgm_ilen = get_ilen(cpu_ldub_code(env, addr));
cs->exception_index = EXCP_PGM;
cpu_loop_exit(cs);
}
}
}
void HELPER(per_store_real)(CPUS390XState *env)
{
if ((env->cregs[9] & PER_CR9_EVENT_STORE) &&
(env->cregs[9] & PER_CR9_EVENT_STORE_REAL)) {
/* PSW is saved just before calling the helper. */
env->per_address = env->psw.addr;
env->per_perc_atmid = PER_CODE_EVENT_STORE_REAL | get_per_atmid(env);
}
}
static uint8_t stfl_bytes[2048];
static unsigned int used_stfl_bytes;
static void prepare_stfl(void)
{
#if 0
static bool initialized;
int i;
/* racy, but we don't care, the same values are always written */
if (initialized) {
return;
}
s390_get_feat_block(S390_FEAT_TYPE_STFL, stfl_bytes);
for (i = 0; i < sizeof(stfl_bytes); i++) {
if (stfl_bytes[i]) {
used_stfl_bytes = i + 1;
}
}
initialized = true;
#endif
}
void HELPER(stfl)(CPUS390XState *env)
{
LowCore *lowcore;
lowcore = cpu_map_lowcore(env);
prepare_stfl();
memcpy(&lowcore->stfl_fac_list, stfl_bytes, sizeof(lowcore->stfl_fac_list));
cpu_unmap_lowcore(env, lowcore);
}
uint32_t HELPER(stfle)(CPUS390XState *env, uint64_t addr)
{
const uintptr_t ra = GETPC();
const int count_bytes = ((env->regs[0] & 0xff) + 1) * 8;
int max_bytes;
int i;
if (addr & 0x7) {
tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
}
prepare_stfl();
max_bytes = ROUND_UP(used_stfl_bytes, 8);
/*
* The PoP says that doublewords beyond the highest-numbered facility
* bit may or may not be stored. However, existing hardware appears to
* not store the words, and existing software depend on that.
*/
for (i = 0; i < MIN(count_bytes, max_bytes); ++i) {
cpu_stb_data_ra(env, addr + i, stfl_bytes[i], ra);
}
env->regs[0] = deposit64(env->regs[0], 0, 8, (max_bytes / 8) - 1);
return count_bytes >= max_bytes ? 0 : 3;
}
/*
* Note: we ignore any return code of the functions called for the pci
* instructions, as the only time they return !0 is when the stub is
* called, and in that case we didn't even offer the zpci facility.
* The only exception is SIC, where program checks need to be handled
* by the caller.
*/
void HELPER(clp)(CPUS390XState *env, uint32_t r2)
{
#if 0
S390CPU *cpu = env_archcpu(env);
qemu_mutex_lock_iothread();
clp_service_call(cpu, r2, GETPC());
qemu_mutex_unlock_iothread();
#endif
}
void HELPER(pcilg)(CPUS390XState *env, uint32_t r1, uint32_t r2)
{
#if 0
S390CPU *cpu = env_archcpu(env);
qemu_mutex_lock_iothread();
pcilg_service_call(cpu, r1, r2, GETPC());
qemu_mutex_unlock_iothread();
#endif
}
void HELPER(pcistg)(CPUS390XState *env, uint32_t r1, uint32_t r2)
{
#if 0
S390CPU *cpu = env_archcpu(env);
qemu_mutex_lock_iothread();
pcistg_service_call(cpu, r1, r2, GETPC());
qemu_mutex_unlock_iothread();
#endif
}
void HELPER(stpcifc)(CPUS390XState *env, uint32_t r1, uint64_t fiba,
uint32_t ar)
{
#if 0
S390CPU *cpu = env_archcpu(env);
qemu_mutex_lock_iothread();
stpcifc_service_call(cpu, r1, fiba, ar, GETPC());
qemu_mutex_unlock_iothread();
#endif
}
void HELPER(sic)(CPUS390XState *env, uint64_t r1, uint64_t r3)
{
#if 0
int r;
qemu_mutex_lock_iothread();
r = css_do_sic(env, (r3 >> 27) & 0x7, r1 & 0xffff);
qemu_mutex_unlock_iothread();
/* css_do_sic() may actually return a PGM_xxx value to inject */
if (r) {
tcg_s390_program_interrupt(env, -r, GETPC());
}
#endif
}
void HELPER(rpcit)(CPUS390XState *env, uint32_t r1, uint32_t r2)
{
#if 0
S390CPU *cpu = env_archcpu(env);
qemu_mutex_lock_iothread();
rpcit_service_call(cpu, r1, r2, GETPC());
qemu_mutex_unlock_iothread();
#endif
}
void HELPER(pcistb)(CPUS390XState *env, uint32_t r1, uint32_t r3,
uint64_t gaddr, uint32_t ar)
{
#if 0
S390CPU *cpu = env_archcpu(env);
qemu_mutex_lock_iothread();
pcistb_service_call(cpu, r1, r3, gaddr, ar, GETPC());
qemu_mutex_unlock_iothread();
#endif
}
void HELPER(mpcifc)(CPUS390XState *env, uint32_t r1, uint64_t fiba,
uint32_t ar)
{
#if 0
S390CPU *cpu = env_archcpu(env);
qemu_mutex_lock_iothread();
mpcifc_service_call(cpu, r1, fiba, ar, GETPC());
qemu_mutex_unlock_iothread();
#endif
}

View File

@ -0,0 +1,554 @@
/*
* S390x MMU related functions
*
* Copyright (c) 2011 Alexander Graf
* Copyright (c) 2015 Thomas Huth, IBM Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "qemu/osdep.h"
//#include "exec/address-spaces.h"
#include "cpu.h"
#include "internal.h"
#include "sysemu/tcg.h"
#include "exec/exec-all.h"
//#include "hw/hw.h"
#include "hw/s390x/storage-keys.h"
/* Fetch/store bits in the translation exception code: */
#define FS_READ 0x800
#define FS_WRITE 0x400
static void trigger_access_exception(CPUS390XState *env, uint32_t type,
uint64_t tec)
{
CPUState *cs = env_cpu(env);
if (type != PGM_ADDRESSING) {
#ifdef UNICORN_ARCH_POSTFIX
glue(stq_phys, UNICORN_ARCH_POSTFIX)(env->uc, cs->as, env->psa + offsetof(LowCore, trans_exc_code), tec);
#else
stq_phys(env->uc, cs->as, env->psa + offsetof(LowCore, trans_exc_code), tec);
#endif
}
trigger_pgm_exception(env, type);
}
/* check whether the address would be proteted by Low-Address Protection */
static bool is_low_address(uint64_t addr)
{
return addr <= 511 || (addr >= 4096 && addr <= 4607);
}
/* check whether Low-Address Protection is enabled for mmu_translate() */
static bool lowprot_enabled(const CPUS390XState *env, uint64_t asc)
{
if (!(env->cregs[0] & CR0_LOWPROT)) {
return false;
}
if (!(env->psw.mask & PSW_MASK_DAT)) {
return true;
}
/* Check the private-space control bit */
switch (asc) {
case PSW_ASC_PRIMARY:
return !(env->cregs[1] & ASCE_PRIVATE_SPACE);
case PSW_ASC_SECONDARY:
return !(env->cregs[7] & ASCE_PRIVATE_SPACE);
case PSW_ASC_HOME:
return !(env->cregs[13] & ASCE_PRIVATE_SPACE);
default:
/* We don't support access register mode */
// error_report("unsupported addressing mode");
exit(1);
}
}
/**
* Translate real address to absolute (= physical)
* address by taking care of the prefix mapping.
*/
target_ulong mmu_real2abs(CPUS390XState *env, target_ulong raddr)
{
if (raddr < 0x2000) {
return raddr + env->psa; /* Map the lowcore. */
} else if (raddr >= env->psa && raddr < env->psa + 0x2000) {
return raddr - env->psa; /* Map the 0 page. */
}
return raddr;
}
static inline bool read_table_entry(CPUS390XState *env, hwaddr gaddr,
uint64_t *entry)
{
CPUState *cs = env_cpu(env);
/*
* According to the PoP, these table addresses are "unpredictably real
* or absolute". Also, "it is unpredictable whether the address wraps
* or an addressing exception is recognized".
*
* We treat them as absolute addresses and don't wrap them.
*/
if (unlikely(address_space_read(cs->as, gaddr, MEMTXATTRS_UNSPECIFIED,
entry, sizeof(*entry)) !=
MEMTX_OK)) {
return false;
}
*entry = be64_to_cpu(*entry);
return true;
}
static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr,
uint64_t asc, uint64_t asce, target_ulong *raddr,
int *flags, int rw)
{
const bool edat1 = (env->cregs[0] & CR0_EDAT) &&
s390_has_feat(env->uc, S390_FEAT_EDAT);
const bool edat2 = edat1 && s390_has_feat(env->uc, S390_FEAT_EDAT_2);
const bool iep = (env->cregs[0] & CR0_IEP) &&
s390_has_feat(env->uc, S390_FEAT_INSTRUCTION_EXEC_PROT);
const int asce_tl = asce & ASCE_TABLE_LENGTH;
const int asce_p = asce & ASCE_PRIVATE_SPACE;
hwaddr gaddr = asce & ASCE_ORIGIN;
uint64_t entry;
if (asce & ASCE_REAL_SPACE) {
/* direct mapping */
*raddr = vaddr;
return 0;
}
switch (asce & ASCE_TYPE_MASK) {
case ASCE_TYPE_REGION1:
if (VADDR_REGION1_TL(vaddr) > asce_tl) {
return PGM_REG_FIRST_TRANS;
}
gaddr += VADDR_REGION1_TX(vaddr) * 8;
break;
case ASCE_TYPE_REGION2:
if (VADDR_REGION1_TX(vaddr)) {
return PGM_ASCE_TYPE;
}
if (VADDR_REGION2_TL(vaddr) > asce_tl) {
return PGM_REG_SEC_TRANS;
}
gaddr += VADDR_REGION2_TX(vaddr) * 8;
break;
case ASCE_TYPE_REGION3:
if (VADDR_REGION1_TX(vaddr) || VADDR_REGION2_TX(vaddr)) {
return PGM_ASCE_TYPE;
}
if (VADDR_REGION3_TL(vaddr) > asce_tl) {
return PGM_REG_THIRD_TRANS;
}
gaddr += VADDR_REGION3_TX(vaddr) * 8;
break;
case ASCE_TYPE_SEGMENT:
if (VADDR_REGION1_TX(vaddr) || VADDR_REGION2_TX(vaddr) ||
VADDR_REGION3_TX(vaddr)) {
return PGM_ASCE_TYPE;
}
if (VADDR_SEGMENT_TL(vaddr) > asce_tl) {
return PGM_SEGMENT_TRANS;
}
gaddr += VADDR_SEGMENT_TX(vaddr) * 8;
break;
}
switch (asce & ASCE_TYPE_MASK) {
case ASCE_TYPE_REGION1:
if (!read_table_entry(env, gaddr, &entry)) {
return PGM_ADDRESSING;
}
if (entry & REGION_ENTRY_I) {
return PGM_REG_FIRST_TRANS;
}
if ((entry & REGION_ENTRY_TT) != REGION_ENTRY_TT_REGION1) {
return PGM_TRANS_SPEC;
}
if (VADDR_REGION2_TL(vaddr) < (entry & REGION_ENTRY_TF) >> 6 ||
VADDR_REGION2_TL(vaddr) > (entry & REGION_ENTRY_TL)) {
return PGM_REG_SEC_TRANS;
}
if (edat1 && (entry & REGION_ENTRY_P)) {
*flags &= ~PAGE_WRITE;
}
gaddr = (entry & REGION_ENTRY_ORIGIN) + VADDR_REGION2_TX(vaddr) * 8;
/* fall through */
case ASCE_TYPE_REGION2:
if (!read_table_entry(env, gaddr, &entry)) {
return PGM_ADDRESSING;
}
if (entry & REGION_ENTRY_I) {
return PGM_REG_SEC_TRANS;
}
if ((entry & REGION_ENTRY_TT) != REGION_ENTRY_TT_REGION2) {
return PGM_TRANS_SPEC;
}
if (VADDR_REGION3_TL(vaddr) < (entry & REGION_ENTRY_TF) >> 6 ||
VADDR_REGION3_TL(vaddr) > (entry & REGION_ENTRY_TL)) {
return PGM_REG_THIRD_TRANS;
}
if (edat1 && (entry & REGION_ENTRY_P)) {
*flags &= ~PAGE_WRITE;
}
gaddr = (entry & REGION_ENTRY_ORIGIN) + VADDR_REGION3_TX(vaddr) * 8;
/* fall through */
case ASCE_TYPE_REGION3:
if (!read_table_entry(env, gaddr, &entry)) {
return PGM_ADDRESSING;
}
if (entry & REGION_ENTRY_I) {
return PGM_REG_THIRD_TRANS;
}
if ((entry & REGION_ENTRY_TT) != REGION_ENTRY_TT_REGION3) {
return PGM_TRANS_SPEC;
}
if (edat2 && (entry & REGION3_ENTRY_CR) && asce_p) {
return PGM_TRANS_SPEC;
}
if (edat1 && (entry & REGION_ENTRY_P)) {
*flags &= ~PAGE_WRITE;
}
if (edat2 && (entry & REGION3_ENTRY_FC)) {
if (iep && (entry & REGION3_ENTRY_IEP)) {
*flags &= ~PAGE_EXEC;
}
*raddr = (entry & REGION3_ENTRY_RFAA) |
(vaddr & ~REGION3_ENTRY_RFAA);
return 0;
}
if (VADDR_SEGMENT_TL(vaddr) < (entry & REGION_ENTRY_TF) >> 6 ||
VADDR_SEGMENT_TL(vaddr) > (entry & REGION_ENTRY_TL)) {
return PGM_SEGMENT_TRANS;
}
gaddr = (entry & REGION_ENTRY_ORIGIN) + VADDR_SEGMENT_TX(vaddr) * 8;
/* fall through */
case ASCE_TYPE_SEGMENT:
if (!read_table_entry(env, gaddr, &entry)) {
return PGM_ADDRESSING;
}
if (entry & SEGMENT_ENTRY_I) {
return PGM_SEGMENT_TRANS;
}
if ((entry & SEGMENT_ENTRY_TT) != SEGMENT_ENTRY_TT_SEGMENT) {
return PGM_TRANS_SPEC;
}
if ((entry & SEGMENT_ENTRY_CS) && asce_p) {
return PGM_TRANS_SPEC;
}
if (entry & SEGMENT_ENTRY_P) {
*flags &= ~PAGE_WRITE;
}
if (edat1 && (entry & SEGMENT_ENTRY_FC)) {
if (iep && (entry & SEGMENT_ENTRY_IEP)) {
*flags &= ~PAGE_EXEC;
}
*raddr = (entry & SEGMENT_ENTRY_SFAA) |
(vaddr & ~SEGMENT_ENTRY_SFAA);
return 0;
}
gaddr = (entry & SEGMENT_ENTRY_ORIGIN) + VADDR_PAGE_TX(vaddr) * 8;
break;
}
if (!read_table_entry(env, gaddr, &entry)) {
return PGM_ADDRESSING;
}
if (entry & PAGE_ENTRY_I) {
return PGM_PAGE_TRANS;
}
if (entry & PAGE_ENTRY_0) {
return PGM_TRANS_SPEC;
}
if (entry & PAGE_ENTRY_P) {
*flags &= ~PAGE_WRITE;
}
if (iep && (entry & PAGE_ENTRY_IEP)) {
*flags &= ~PAGE_EXEC;
}
*raddr = entry & TARGET_PAGE_MASK;
return 0;
}
static void mmu_handle_skey(target_ulong addr, int rw, int *flags)
{
static S390SKeysClass *skeyclass;
static S390SKeysState *ss;
uint8_t key;
int rc;
#if 0
if (unlikely(addr >= ram_size)) {
return;
}
#endif
if (unlikely(!ss)) {
// ss = s390_get_skeys_device();
// skeyclass = S390_SKEYS_GET_CLASS(ss);
}
/*
* Whenever we create a new TLB entry, we set the storage key reference
* bit. In case we allow write accesses, we set the storage key change
* bit. Whenever the guest changes the storage key, we have to flush the
* TLBs of all CPUs (the whole TLB or all affected entries), so that the
* next reference/change will result in an MMU fault and make us properly
* update the storage key here.
*
* Note 1: "record of references ... is not necessarily accurate",
* "change bit may be set in case no storing has occurred".
* -> We can set reference/change bits even on exceptions.
* Note 2: certain accesses seem to ignore storage keys. For example,
* DAT translation does not set reference bits for table accesses.
*
* TODO: key-controlled protection. Only CPU accesses make use of the
* PSW key. CSS accesses are different - we have to pass in the key.
*
* TODO: we have races between getting and setting the key.
*/
rc = skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
if (rc) {
// trace_get_skeys_nonzero(rc);
return;
}
switch (rw) {
case MMU_DATA_LOAD:
case MMU_INST_FETCH:
/*
* The TLB entry has to remain write-protected on read-faults if
* the storage key does not indicate a change already. Otherwise
* we might miss setting the change bit on write accesses.
*/
if (!(key & SK_C)) {
*flags &= ~PAGE_WRITE;
}
break;
case MMU_DATA_STORE:
key |= SK_C;
break;
default:
g_assert_not_reached();
}
/* Any store/fetch sets the reference bit */
key |= SK_R;
rc = skeyclass->set_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key);
if (rc) {
// trace_set_skeys_nonzero(rc);
}
}
/**
* Translate a virtual (logical) address into a physical (absolute) address.
* @param vaddr the virtual address
* @param rw 0 = read, 1 = write, 2 = code fetch
* @param asc address space control (one of the PSW_ASC_* modes)
* @param raddr the translated address is stored to this pointer
* @param flags the PAGE_READ/WRITE/EXEC flags are stored to this pointer
* @param exc true = inject a program check if a fault occurred
* @return 0 = success, != 0, the exception to raise
*/
int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
target_ulong *raddr, int *flags, uint64_t *tec)
{
uint64_t asce;
int r;
*tec = (vaddr & TARGET_PAGE_MASK) | (asc >> 46) |
(rw == MMU_DATA_STORE ? FS_WRITE : FS_READ);
*flags = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
if (is_low_address(vaddr & TARGET_PAGE_MASK) && lowprot_enabled(env, asc)) {
/*
* If any part of this page is currently protected, make sure the
* TLB entry will not be reused.
*
* As the protected range is always the first 512 bytes of the
* two first pages, we are able to catch all writes to these areas
* just by looking at the start address (triggering the tlb miss).
*/
*flags |= PAGE_WRITE_INV;
if (is_low_address(vaddr) && rw == MMU_DATA_STORE) {
/* LAP sets bit 56 */
*tec |= 0x80;
return PGM_PROTECTION;
}
}
vaddr &= TARGET_PAGE_MASK;
if (!(env->psw.mask & PSW_MASK_DAT)) {
*raddr = vaddr;
goto nodat;
}
switch (asc) {
case PSW_ASC_PRIMARY:
asce = env->cregs[1];
break;
case PSW_ASC_HOME:
asce = env->cregs[13];
break;
case PSW_ASC_SECONDARY:
asce = env->cregs[7];
break;
case PSW_ASC_ACCREG:
default:
// hw_error("guest switched to unknown asc mode\n");
break;
}
/* perform the DAT translation */
r = mmu_translate_asce(env, vaddr, asc, asce, raddr, flags, rw);
if (unlikely(r)) {
return r;
}
/* check for DAT protection */
if (unlikely(rw == MMU_DATA_STORE && !(*flags & PAGE_WRITE))) {
/* DAT sets bit 61 only */
*tec |= 0x4;
return PGM_PROTECTION;
}
/* check for Instruction-Execution-Protection */
if (unlikely(rw == MMU_INST_FETCH && !(*flags & PAGE_EXEC))) {
/* IEP sets bit 56 and 61 */
*tec |= 0x84;
return PGM_PROTECTION;
}
nodat:
/* Convert real address -> absolute address */
*raddr = mmu_real2abs(env, *raddr);
mmu_handle_skey(*raddr, rw, flags);
return 0;
}
/**
* translate_pages: Translate a set of consecutive logical page addresses
* to absolute addresses. This function is used for TCG and old KVM without
* the MEMOP interface.
*/
static int translate_pages(S390CPU *cpu, vaddr addr, int nr_pages,
target_ulong *pages, bool is_write, uint64_t *tec)
{
uint64_t asc = cpu->env.psw.mask & PSW_MASK_ASC;
CPUS390XState *env = &cpu->env;
int ret, i, pflags;
for (i = 0; i < nr_pages; i++) {
ret = mmu_translate(env, addr, is_write, asc, &pages[i], &pflags, tec);
if (ret) {
return ret;
}
if (!address_space_access_valid(env_cpu(env)->as, pages[i],
TARGET_PAGE_SIZE, is_write,
MEMTXATTRS_UNSPECIFIED)) {
*tec = 0; /* unused */
return PGM_ADDRESSING;
}
addr += TARGET_PAGE_SIZE;
}
return 0;
}
/**
* s390_cpu_virt_mem_rw:
* @laddr: the logical start address
* @ar: the access register number
* @hostbuf: buffer in host memory. NULL = do only checks w/o copying
* @len: length that should be transferred
* @is_write: true = write, false = read
* Returns: 0 on success, non-zero if an exception occurred
*
* Copy from/to guest memory using logical addresses. Note that we inject a
* program interrupt in case there is an error while accessing the memory.
*
* This function will always return (also for TCG), make sure to call
* s390_cpu_virt_mem_handle_exc() to properly exit the CPU loop.
*/
int s390_cpu_virt_mem_rw(S390CPU *cpu, vaddr laddr, uint8_t ar, void *hostbuf,
int len, bool is_write)
{
int currlen, nr_pages, i;
target_ulong *pages;
uint64_t tec;
int ret;
CPUS390XState *env = &cpu->env;
nr_pages = (((laddr & ~TARGET_PAGE_MASK) + len - 1) >> TARGET_PAGE_BITS)
+ 1;
pages = g_malloc(nr_pages * sizeof(*pages));
ret = translate_pages(cpu, laddr, nr_pages, pages, is_write, &tec);
if (ret) {
trigger_access_exception(&cpu->env, ret, tec);
} else if (hostbuf != NULL) {
/* Copy data by stepping through the area page by page */
for (i = 0; i < nr_pages; i++) {
currlen = MIN(len, TARGET_PAGE_SIZE - (laddr % TARGET_PAGE_SIZE));
cpu_physical_memory_rw(env_cpu(env)->as, pages[i] | (laddr & ~TARGET_PAGE_MASK),
hostbuf, currlen, is_write);
laddr += currlen;
hostbuf += currlen;
len -= currlen;
}
}
g_free(pages);
return ret;
}
void s390_cpu_virt_mem_handle_exc(S390CPU *cpu, uintptr_t ra)
{
/* KVM will handle the interrupt automatically, TCG has to exit the TB */
cpu_loop_exit_restore(CPU(cpu), ra);
}
/**
* Translate a real address into a physical (absolute) address.
* @param raddr the real address
* @param rw 0 = read, 1 = write, 2 = code fetch
* @param addr the translated address is stored to this pointer
* @param flags the PAGE_READ/WRITE/EXEC flags are stored to this pointer
* @return 0 = success, != 0, the exception to raise
*/
int mmu_translate_real(CPUS390XState *env, target_ulong raddr, int rw,
target_ulong *addr, int *flags, uint64_t *tec)
{
const bool lowprot_enabled = env->cregs[0] & CR0_LOWPROT;
*flags = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
if (is_low_address(raddr & TARGET_PAGE_MASK) && lowprot_enabled) {
/* see comment in mmu_translate() how this works */
*flags |= PAGE_WRITE_INV;
if (is_low_address(raddr) && rw == MMU_DATA_STORE) {
/* LAP sets bit 56 */
*tec = (raddr & TARGET_PAGE_MASK) | FS_WRITE | 0x80;
return PGM_PROTECTION;
}
}
*addr = mmu_real2abs(env, raddr & TARGET_PAGE_MASK);
mmu_handle_skey(*addr, rw, flags);
return 0;
}

View File

@ -0,0 +1,29 @@
/*
* 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 TARGET_S390_TOD_H
#define TARGET_S390_TOD_H
/* 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 & 0xff80000000000000ull) / 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);
}
#endif

466
qemu/target/s390x/sigp.c Normal file
View File

@ -0,0 +1,466 @@
/*
* s390x SIGP instruction handling
*
* Copyright (c) 2009 Alexander Graf <agraf@suse.de>
* Copyright IBM Corp. 2012
*
* 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 "cpu.h"
#include "internal.h"
//#include "exec/address-spaces.h"
#include "exec/exec-all.h"
#include "sysemu/tcg.h"
typedef struct SigpInfo {
uint64_t param;
int cc;
uint64_t *status_reg;
} SigpInfo;
static void set_sigp_status(SigpInfo *si, uint64_t status)
{
*si->status_reg &= 0xffffffff00000000ULL;
*si->status_reg |= status;
si->cc = SIGP_CC_STATUS_STORED;
}
static void sigp_sense(S390CPU *dst_cpu, SigpInfo *si)
{
uint8_t state = s390_cpu_get_state(dst_cpu);
bool ext_call = dst_cpu->env.pending_int & INTERRUPT_EXTERNAL_CALL;
uint64_t status = 0;
/* sensing without locks is racy, but it's the same for real hw */
if (state != S390_CPU_STATE_STOPPED && !ext_call) {
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
} else {
if (ext_call) {
status |= SIGP_STAT_EXT_CALL_PENDING;
}
if (state == S390_CPU_STATE_STOPPED) {
status |= SIGP_STAT_STOPPED;
}
set_sigp_status(si, status);
}
}
static void sigp_external_call(S390CPU *src_cpu, S390CPU *dst_cpu, SigpInfo *si)
{
int ret;
ret = cpu_inject_external_call(dst_cpu, src_cpu->env.core_id);
if (!ret) {
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
} else {
set_sigp_status(si, SIGP_STAT_EXT_CALL_PENDING);
}
}
static void sigp_emergency(S390CPU *src_cpu, S390CPU *dst_cpu, SigpInfo *si)
{
cpu_inject_emergency_signal(dst_cpu, src_cpu->env.core_id);
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
}
#if 0
static void sigp_start(CPUState *cs, run_on_cpu_data arg)
{
S390CPU *cpu = S390_CPU(cs);
SigpInfo *si = arg.host_ptr;
if (s390_cpu_get_state(cpu) != S390_CPU_STATE_STOPPED) {
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
return;
}
s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
}
static void sigp_stop(CPUState *cs, run_on_cpu_data arg)
{
S390CPU *cpu = S390_CPU(cs);
SigpInfo *si = arg.host_ptr;
if (s390_cpu_get_state(cpu) != S390_CPU_STATE_OPERATING) {
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
return;
}
/* disabled wait - sleeping in user space */
if (cs->halted) {
s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu);
} else {
/* execute the stop function */
cpu->env.sigp_order = SIGP_STOP;
cpu_inject_stop(cpu);
}
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
}
static void sigp_stop_and_store_status(CPUState *cs, run_on_cpu_data arg)
{
S390CPU *cpu = S390_CPU(cs);
SigpInfo *si = arg.host_ptr;
/* disabled wait - sleeping in user space */
if (s390_cpu_get_state(cpu) == S390_CPU_STATE_OPERATING && cs->halted) {
s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu);
}
switch (s390_cpu_get_state(cpu)) {
case S390_CPU_STATE_OPERATING:
cpu->env.sigp_order = SIGP_STOP_STORE_STATUS;
cpu_inject_stop(cpu);
/* store will be performed in do_stop_interrup() */
break;
case S390_CPU_STATE_STOPPED:
/* already stopped, just store the status */
// cpu_synchronize_state(cs);
s390_store_status(cpu, S390_STORE_STATUS_DEF_ADDR, true);
break;
}
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
}
static void sigp_store_status_at_address(CPUState *cs, run_on_cpu_data arg)
{
S390CPU *cpu = S390_CPU(cs);
SigpInfo *si = arg.host_ptr;
uint32_t address = si->param & 0x7ffffe00u;
/* cpu has to be stopped */
if (s390_cpu_get_state(cpu) != S390_CPU_STATE_STOPPED) {
set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
return;
}
// cpu_synchronize_state(cs);
if (s390_store_status(cpu, address, false)) {
set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
return;
}
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
}
#define ADTL_SAVE_LC_MASK 0xfUL
static void sigp_store_adtl_status(CPUState *cs, run_on_cpu_data arg)
{
S390CPU *cpu = S390_CPU(cs);
SigpInfo *si = arg.host_ptr;
uint8_t lc = si->param & ADTL_SAVE_LC_MASK;
hwaddr addr = si->param & ~ADTL_SAVE_LC_MASK;
hwaddr len = 1UL << (lc ? lc : 10);
if (!s390_has_feat(S390_FEAT_VECTOR) &&
!s390_has_feat(S390_FEAT_GUARDED_STORAGE)) {
set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
return;
}
/* cpu has to be stopped */
if (s390_cpu_get_state(cpu) != S390_CPU_STATE_STOPPED) {
set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
return;
}
/* address must be aligned to length */
if (addr & (len - 1)) {
set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
return;
}
/* no GS: only lc == 0 is valid */
if (!s390_has_feat(S390_FEAT_GUARDED_STORAGE) &&
lc != 0) {
set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
return;
}
/* GS: 0, 10, 11, 12 are valid */
if (s390_has_feat(S390_FEAT_GUARDED_STORAGE) &&
lc != 0 &&
lc != 10 &&
lc != 11 &&
lc != 12) {
set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
return;
}
// cpu_synchronize_state(cs);
if (s390_store_adtl_status(cpu, addr, len)) {
set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
return;
}
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
}
static void sigp_restart(CPUState *cs, run_on_cpu_data arg)
{
S390CPU *cpu = S390_CPU(cs);
SigpInfo *si = arg.host_ptr;
switch (s390_cpu_get_state(cpu)) {
case S390_CPU_STATE_STOPPED:
/* the restart irq has to be delivered prior to any other pending irq */
// cpu_synchronize_state(cs);
/*
* Set OPERATING (and unhalting) before loading the restart PSW.
* load_psw() will then properly halt the CPU again if necessary (TCG).
*/
s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
do_restart_interrupt(&cpu->env);
break;
case S390_CPU_STATE_OPERATING:
cpu_inject_restart(cpu);
break;
}
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
}
static void sigp_initial_cpu_reset(CPUState *cs, run_on_cpu_data arg)
{
S390CPU *cpu = S390_CPU(cs);
S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
SigpInfo *si = arg.host_ptr;
// cpu_synchronize_state(cs);
scc->reset(cs, S390_CPU_RESET_INITIAL);
// cpu_synchronize_post_reset(cs);
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
}
static void sigp_cpu_reset(CPUState *cs, run_on_cpu_data arg)
{
S390CPU *cpu = S390_CPU(cs);
S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
SigpInfo *si = arg.host_ptr;
// cpu_synchronize_state(cs);
scc->reset(cs, S390_CPU_RESET_NORMAL);
// cpu_synchronize_post_reset(cs);
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
}
static void sigp_set_prefix(CPUState *cs, run_on_cpu_data arg)
{
S390CPU *cpu = S390_CPU(cs);
CPUS390XState *env = &cpu->env;
SigpInfo *si = arg.host_ptr;
uint32_t addr = si->param & 0x7fffe000u;
// cpu_synchronize_state(cs);
if (!address_space_access_valid(env_cpu(env)->as, addr,
sizeof(struct LowCore), false,
MEMTXATTRS_UNSPECIFIED)) {
set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
return;
}
/* cpu has to be stopped */
if (s390_cpu_get_state(cpu) != S390_CPU_STATE_STOPPED) {
set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
return;
}
cpu->env.psa = addr;
tlb_flush(cs);
// cpu_synchronize_post_init(cs);
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
}
#endif
static void sigp_cond_emergency(S390CPU *src_cpu, S390CPU *dst_cpu,
SigpInfo *si)
{
const uint64_t psw_int_mask = PSW_MASK_IO | PSW_MASK_EXT;
uint16_t p_asn, s_asn, asn;
uint64_t psw_addr, psw_mask;
bool idle;
/* this looks racy, but these values are only used when STOPPED */
idle = CPU(dst_cpu)->halted;
psw_addr = dst_cpu->env.psw.addr;
psw_mask = dst_cpu->env.psw.mask;
asn = si->param;
p_asn = dst_cpu->env.cregs[4] & 0xffff; /* Primary ASN */
s_asn = dst_cpu->env.cregs[3] & 0xffff; /* Secondary ASN */
if (s390_cpu_get_state(dst_cpu) != S390_CPU_STATE_STOPPED ||
(psw_mask & psw_int_mask) != psw_int_mask ||
(idle && psw_addr != 0) ||
(!idle && (asn == p_asn || asn == s_asn))) {
cpu_inject_emergency_signal(dst_cpu, src_cpu->env.core_id);
} else {
set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
}
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
}
static void sigp_sense_running(S390CPU *dst_cpu, SigpInfo *si)
{
/* sensing without locks is racy, but it's the same for real hw */
//if (!s390_has_feat(S390_FEAT_SENSE_RUNNING_STATUS)) {
// set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
// return;
//}
/* If halted (which includes also STOPPED), it is not running */
if (CPU(dst_cpu)->halted) {
set_sigp_status(si, SIGP_STAT_NOT_RUNNING);
} else {
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
}
}
static int handle_sigp_single_dst(S390CPU *cpu, S390CPU *dst_cpu, uint8_t order,
uint64_t param, uint64_t *status_reg)
{
SigpInfo si = {
.param = param,
.status_reg = status_reg,
};
/* cpu available? */
if (dst_cpu == NULL) {
return SIGP_CC_NOT_OPERATIONAL;
}
/* only resets can break pending orders */
if (dst_cpu->env.sigp_order != 0 &&
order != SIGP_CPU_RESET &&
order != SIGP_INITIAL_CPU_RESET) {
return SIGP_CC_BUSY;
}
switch (order) {
case SIGP_SENSE:
sigp_sense(dst_cpu, &si);
break;
case SIGP_EXTERNAL_CALL:
sigp_external_call(cpu, dst_cpu, &si);
break;
case SIGP_EMERGENCY:
sigp_emergency(cpu, dst_cpu, &si);
break;
case SIGP_START:
//run_on_cpu(CPU(dst_cpu), sigp_start, RUN_ON_CPU_HOST_PTR(&si));
break;
case SIGP_STOP:
//run_on_cpu(CPU(dst_cpu), sigp_stop, RUN_ON_CPU_HOST_PTR(&si));
break;
case SIGP_RESTART:
//run_on_cpu(CPU(dst_cpu), sigp_restart, RUN_ON_CPU_HOST_PTR(&si));
break;
case SIGP_STOP_STORE_STATUS:
//run_on_cpu(CPU(dst_cpu), sigp_stop_and_store_status, RUN_ON_CPU_HOST_PTR(&si));
break;
case SIGP_STORE_STATUS_ADDR:
//run_on_cpu(CPU(dst_cpu), sigp_store_status_at_address, RUN_ON_CPU_HOST_PTR(&si));
break;
case SIGP_STORE_ADTL_STATUS:
//run_on_cpu(CPU(dst_cpu), sigp_store_adtl_status, RUN_ON_CPU_HOST_PTR(&si));
break;
case SIGP_SET_PREFIX:
//run_on_cpu(CPU(dst_cpu), sigp_set_prefix, RUN_ON_CPU_HOST_PTR(&si));
break;
case SIGP_INITIAL_CPU_RESET:
//run_on_cpu(CPU(dst_cpu), sigp_initial_cpu_reset, RUN_ON_CPU_HOST_PTR(&si));
break;
case SIGP_CPU_RESET:
//run_on_cpu(CPU(dst_cpu), sigp_cpu_reset, RUN_ON_CPU_HOST_PTR(&si));
break;
case SIGP_COND_EMERGENCY:
sigp_cond_emergency(cpu, dst_cpu, &si);
break;
case SIGP_SENSE_RUNNING:
sigp_sense_running(dst_cpu, &si);
break;
default:
set_sigp_status(&si, SIGP_STAT_INVALID_ORDER);
}
return si.cc;
}
static int sigp_set_architecture(S390CPU *cpu, uint32_t param,
uint64_t *status_reg)
{
bool all_stopped = true;
#if 0
CPU_FOREACH(cur_cs) {
cur_cpu = S390_CPU(cur_cs);
if (cur_cpu == cpu) {
continue;
}
if (s390_cpu_get_state(cur_cpu) != S390_CPU_STATE_STOPPED) {
all_stopped = false;
}
}
#endif
all_stopped = false;
*status_reg &= 0xffffffff00000000ULL;
/* Reject set arch order, with czam we're always in z/Arch mode. */
*status_reg |= (all_stopped ? SIGP_STAT_INVALID_PARAMETER :
SIGP_STAT_INCORRECT_STATE);
return SIGP_CC_STATUS_STORED;
}
int handle_sigp(CPUS390XState *env, uint8_t order, uint64_t r1, uint64_t r3)
{
uint64_t *status_reg = &env->regs[r1];
uint64_t param = (r1 % 2) ? env->regs[r1] : env->regs[r1 + 1];
S390CPU *cpu = env_archcpu(env);
S390CPU *dst_cpu = NULL;
int ret;
switch (order) {
case SIGP_SET_ARCH:
ret = sigp_set_architecture(cpu, param, status_reg);
break;
default:
/* all other sigp orders target a single vcpu */
dst_cpu = s390_cpu_addr2state(env->regs[r3]);
ret = handle_sigp_single_dst(cpu, dst_cpu, order, param, status_reg);
}
return ret;
}
int s390_cpu_restart(S390CPU *cpu)
{
//SigpInfo si = {};
//run_on_cpu(CPU(cpu), sigp_restart, RUN_ON_CPU_HOST_PTR(&si));
return 0;
}
void do_stop_interrupt(CPUS390XState *env)
{
S390CPU *cpu = env_archcpu(env);
if (s390_cpu_set_state(S390_CPU_STATE_STOPPED, cpu) == 0) {
// qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
}
if (cpu->env.sigp_order == SIGP_STOP_STORE_STATUS) {
s390_store_status(cpu, S390_STORE_STATUS_DEF_ADDR, true);
}
env->sigp_order = 0;
env->pending_int &= ~INTERRUPT_STOP;
}
void s390_init_sigp(void)
{
}

View File

@ -0,0 +1,30 @@
/*
* 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)
{
}
void QEMU_NORETURN tcg_s390_program_interrupt(CPUS390XState *env,
uint32_t code, 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();
}

View File

@ -0,0 +1,24 @@
/*
* 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);
void QEMU_NORETURN tcg_s390_program_interrupt(CPUS390XState *env,
uint32_t code, uintptr_t ra);
void QEMU_NORETURN tcg_s390_data_exception(CPUS390XState *env, uint32_t dxc,
uintptr_t ra);
void QEMU_NORETURN tcg_s390_vector_exception(CPUS390XState *env, uint32_t vxc,
uintptr_t ra);
#endif /* TCG_S390X_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

173
qemu/target/s390x/unicorn.c Normal file
View File

@ -0,0 +1,173 @@
/* Unicorn Emulator Engine */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015-2021 */
#include "sysemu/cpus.h"
#include "cpu.h"
#include "unicorn_common.h"
#include "uc_priv.h"
#include "unicorn.h"
S390CPU *cpu_s390_init(struct uc_struct *uc, const char *cpu_model);
static void s390_set_pc(struct uc_struct *uc, uint64_t address)
{
// ((CPUS390XState *)uc->cpu->env_ptr)->pc = address;
}
static void s390_release(void* ctx)
{
#if 0
int i;
TCGContext *tcg_ctx = (TCGContext *)ctx;
S390XCPU *cpu = (S390XCPU *)tcg_ctx->uc->cpu;
CPUTLBDesc *d = cpu->neg.tlb.d;
CPUTLBDescFast *f = cpu->neg.tlb.f;
CPUTLBDesc *desc;
CPUTLBDescFast *fast;
release_common(ctx);
for (i = 0; i < NB_MMU_MODES; i++) {
desc = &(d[i]);
fast = &(f[i]);
g_free(desc->iotlb);
g_free(fast->table);
}
#endif
}
void s390_reg_reset(struct uc_struct *uc)
{
CPUArchState *env = uc->cpu->env_ptr;
memset(env->regs, 0, sizeof(env->regs));
memset(env->aregs, 0, sizeof(env->aregs));
env->psw.addr = 0;
}
static void reg_read(CPUS390XState *env, unsigned int regid, void *value)
{
if (regid >= UC_S390X_REG_R0 && regid <= UC_S390X_REG_R15) {
*(uint64_t *)value = env->regs[regid - UC_S390X_REG_R0];
return;
}
if (regid >= UC_S390X_REG_A0 && regid <= UC_S390X_REG_A15) {
*(uint32_t *)value = env->regs[regid - UC_S390X_REG_A0];
return;
}
switch(regid) {
default: break;
case UC_S390X_REG_PC:
*(uint64_t *)value = env->psw.addr;
break;
}
}
static void reg_write(CPUS390XState *env, unsigned int regid, const void *value)
{
if (regid >= UC_S390X_REG_R0 && regid <= UC_S390X_REG_R15) {
env->regs[regid - UC_S390X_REG_R0] = *(uint64_t *)value;
return;
}
if (regid >= UC_S390X_REG_A0 && regid <= UC_S390X_REG_A15) {
env->regs[regid - UC_S390X_REG_A0] = *(uint32_t *)value;
return;
}
switch(regid) {
default: break;
case UC_S390X_REG_PC:
env->psw.addr = *(uint64_t *)value;
break;
}
}
static int s390_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count)
{
CPUS390XState* env = &(S390_CPU(uc->cpu)->env);
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
void *value = vals[i];
reg_read(env, regid, value);
}
return 0;
}
static int s390_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count)
{
CPUS390XState* env = &(S390_CPU(uc->cpu)->env);
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
const void *value = vals[i];
reg_write(env, regid, value);
if (regid == UC_S390X_REG_PC){
// force to quit execution and flush TB
uc->quit_request = true;
uc_emu_stop(uc);
}
}
return 0;
}
DEFAULT_VISIBILITY
int s390_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count)
{
CPUS390XState* env = (CPUS390XState* )ctx->data;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
void *value = vals[i];
reg_read(env, regid, value);
}
return 0;
}
DEFAULT_VISIBILITY
int s390_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count)
{
CPUS390XState* env = (CPUS390XState* )ctx->data;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
const void *value = vals[i];
reg_write(env, regid, value);
}
return 0;
}
static int s390_cpus_init(struct uc_struct *uc, const char *cpu_model)
{
S390CPU *cpu;
cpu = cpu_s390_init(uc, cpu_model);
if (cpu == NULL) {
return -1;
}
return 0;
}
DEFAULT_VISIBILITY
void s390_uc_init(struct uc_struct* uc)
{
uc->release = s390_release;
uc->reg_read = s390_reg_read;
uc->reg_write = s390_reg_write;
uc->reg_reset = s390_reg_reset;
uc->set_pc = s390_set_pc;
uc->cpus_init = s390_cpus_init;
uc->cpu_context_size = offsetof(CPUS390XState, end_reset_fields);
uc_common_init(uc);
}

View File

@ -0,0 +1,16 @@
/* Unicorn Emulator Engine */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015-2021 */
#ifndef UC_QEMU_TARGET_S390X_H
#define UC_QEMU_TARGET_S390X_H
// functions to read & write registers
//int s390_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
//int s390_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
int s390_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count);
int s390_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count);
void s390_reg_reset(struct uc_struct *uc);
void s390_uc_init(struct uc_struct* uc);
#endif

141
qemu/target/s390x/vec.h Normal file
View File

@ -0,0 +1,141 @@
/*
* QEMU TCG support -- s390x vector utilitites
*
* Copyright (C) 2019 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 S390X_VEC_H
#define S390X_VEC_H
#include "tcg/tcg.h"
typedef union S390Vector {
uint64_t doubleword[2];
uint32_t word[4];
uint16_t halfword[8];
uint8_t byte[16];
} S390Vector;
/*
* Each vector is stored as two 64bit host values. So when talking about
* byte/halfword/word numbers, we have to take care of proper translation
* between element numbers.
*
* Big Endian (target/possible host)
* B: [ 0][ 1][ 2][ 3][ 4][ 5][ 6][ 7] - [ 8][ 9][10][11][12][13][14][15]
* HW: [ 0][ 1][ 2][ 3] - [ 4][ 5][ 6][ 7]
* W: [ 0][ 1] - [ 2][ 3]
* DW: [ 0] - [ 1]
*
* Little Endian (possible host)
* B: [ 7][ 6][ 5][ 4][ 3][ 2][ 1][ 0] - [15][14][13][12][11][10][ 9][ 8]
* HW: [ 3][ 2][ 1][ 0] - [ 7][ 6][ 5][ 4]
* W: [ 1][ 0] - [ 3][ 2]
* DW: [ 0] - [ 1]
*/
#ifndef HOST_WORDS_BIGENDIAN
#define H1(x) ((x) ^ 7)
#define H2(x) ((x) ^ 3)
#define H4(x) ((x) ^ 1)
#else
#define H1(x) (x)
#define H2(x) (x)
#define H4(x) (x)
#endif
static inline uint8_t s390_vec_read_element8(const S390Vector *v, uint8_t enr)
{
g_assert(enr < 16);
return v->byte[H1(enr)];
}
static inline uint16_t s390_vec_read_element16(const S390Vector *v, uint8_t enr)
{
g_assert(enr < 8);
return v->halfword[H2(enr)];
}
static inline uint32_t s390_vec_read_element32(const S390Vector *v, uint8_t enr)
{
g_assert(enr < 4);
return v->word[H4(enr)];
}
static inline uint64_t s390_vec_read_element64(const S390Vector *v, uint8_t enr)
{
g_assert(enr < 2);
return v->doubleword[enr];
}
static inline uint64_t s390_vec_read_element(const S390Vector *v, uint8_t enr,
uint8_t es)
{
switch (es) {
case MO_8:
return s390_vec_read_element8(v, enr);
case MO_16:
return s390_vec_read_element16(v, enr);
case MO_32:
return s390_vec_read_element32(v, enr);
case MO_64:
return s390_vec_read_element64(v, enr);
default:
g_assert_not_reached();
}
}
static inline void s390_vec_write_element8(S390Vector *v, uint8_t enr,
uint8_t data)
{
g_assert(enr < 16);
v->byte[H1(enr)] = data;
}
static inline void s390_vec_write_element16(S390Vector *v, uint8_t enr,
uint16_t data)
{
g_assert(enr < 8);
v->halfword[H2(enr)] = data;
}
static inline void s390_vec_write_element32(S390Vector *v, uint8_t enr,
uint32_t data)
{
g_assert(enr < 4);
v->word[H4(enr)] = data;
}
static inline void s390_vec_write_element64(S390Vector *v, uint8_t enr,
uint64_t data)
{
g_assert(enr < 2);
v->doubleword[enr] = data;
}
static inline void s390_vec_write_element(S390Vector *v, uint8_t enr,
uint8_t es, uint64_t data)
{
switch (es) {
case MO_8:
s390_vec_write_element8(v, enr, data);
break;
case MO_16:
s390_vec_write_element16(v, enr, data);
break;
case MO_32:
s390_vec_write_element32(v, enr, data);
break;
case MO_64:
s390_vec_write_element64(v, enr, data);
break;
default:
g_assert_not_reached();
}
}
#endif /* S390X_VEC_H */

View File

@ -0,0 +1,625 @@
/*
* QEMU TCG support -- s390x vector floating point instruction support
*
* Copyright (C) 2019 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 "internal.h"
#include "vec.h"
#include "tcg_s390x.h"
#include "tcg/tcg-gvec-desc.h"
#include "exec/exec-all.h"
#include "exec/helper-proto.h"
#include "fpu/softfloat.h"
#define VIC_INVALID 0x1
#define VIC_DIVBYZERO 0x2
#define VIC_OVERFLOW 0x3
#define VIC_UNDERFLOW 0x4
#define VIC_INEXACT 0x5
/* returns the VEX. If the VEX is 0, there is no trap */
static uint8_t check_ieee_exc(CPUS390XState *env, uint8_t enr, bool XxC,
uint8_t *vec_exc)
{
uint8_t vece_exc = 0, trap_exc;
unsigned qemu_exc;
/* Retrieve and clear the softfloat exceptions */
qemu_exc = env->fpu_status.float_exception_flags;
if (qemu_exc == 0) {
return 0;
}
env->fpu_status.float_exception_flags = 0;
vece_exc = s390_softfloat_exc_to_ieee(qemu_exc);
/* Add them to the vector-wide s390x exception bits */
*vec_exc |= vece_exc;
/* Check for traps and construct the VXC */
trap_exc = vece_exc & env->fpc >> 24;
if (trap_exc) {
if (trap_exc & S390_IEEE_MASK_INVALID) {
return enr << 4 | VIC_INVALID;
} else if (trap_exc & S390_IEEE_MASK_DIVBYZERO) {
return enr << 4 | VIC_DIVBYZERO;
} else if (trap_exc & S390_IEEE_MASK_OVERFLOW) {
return enr << 4 | VIC_OVERFLOW;
} else if (trap_exc & S390_IEEE_MASK_UNDERFLOW) {
return enr << 4 | VIC_UNDERFLOW;
} else if (!XxC) {
g_assert(trap_exc & S390_IEEE_MASK_INEXACT);
/* inexact has lowest priority on traps */
return enr << 4 | VIC_INEXACT;
}
}
return 0;
}
static void handle_ieee_exc(CPUS390XState *env, uint8_t vxc, uint8_t vec_exc,
uintptr_t retaddr)
{
if (vxc) {
/* on traps, the fpc flags are not updated, instruction is suppressed */
tcg_s390_vector_exception(env, vxc, retaddr);
}
if (vec_exc) {
/* indicate exceptions for all elements combined */
env->fpc |= vec_exc << 16;
}
}
typedef uint64_t (*vop64_2_fn)(uint64_t a, float_status *s);
static void vop64_2(S390Vector *v1, const S390Vector *v2, CPUS390XState *env,
bool s, bool XxC, uint8_t erm, vop64_2_fn fn,
uintptr_t retaddr)
{
uint8_t vxc, vec_exc = 0;
S390Vector tmp = {};
int i, old_mode;
old_mode = s390_swap_bfp_rounding_mode(env, erm);
for (i = 0; i < 2; i++) {
const uint64_t a = s390_vec_read_element64(v2, i);
s390_vec_write_element64(&tmp, i, fn(a, &env->fpu_status));
vxc = check_ieee_exc(env, i, XxC, &vec_exc);
if (s || vxc) {
break;
}
}
s390_restore_bfp_rounding_mode(env, old_mode);
handle_ieee_exc(env, vxc, vec_exc, retaddr);
*v1 = tmp;
}
typedef uint64_t (*vop64_3_fn)(uint64_t a, uint64_t b, float_status *s);
static void vop64_3(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
CPUS390XState *env, bool s, vop64_3_fn fn,
uintptr_t retaddr)
{
uint8_t vxc, vec_exc = 0;
S390Vector tmp = {};
int i;
for (i = 0; i < 2; i++) {
const uint64_t a = s390_vec_read_element64(v2, i);
const uint64_t b = s390_vec_read_element64(v3, i);
s390_vec_write_element64(&tmp, i, fn(a, b, &env->fpu_status));
vxc = check_ieee_exc(env, i, false, &vec_exc);
if (s || vxc) {
break;
}
}
handle_ieee_exc(env, vxc, vec_exc, retaddr);
*v1 = tmp;
}
static uint64_t vfa64(uint64_t a, uint64_t b, float_status *s)
{
return float64_add(a, b, s);
}
void HELPER(gvec_vfa64)(void *v1, const void *v2, const void *v3,
CPUS390XState *env, uint32_t desc)
{
vop64_3(v1, v2, v3, env, false, vfa64, GETPC());
}
void HELPER(gvec_vfa64s)(void *v1, const void *v2, const void *v3,
CPUS390XState *env, uint32_t desc)
{
vop64_3(v1, v2, v3, env, true, vfa64, GETPC());
}
static int wfc64(const S390Vector *v1, const S390Vector *v2,
CPUS390XState *env, bool signal, uintptr_t retaddr)
{
/* only the zero-indexed elements are compared */
const float64 a = s390_vec_read_element64(v1, 0);
const float64 b = s390_vec_read_element64(v2, 0);
uint8_t vxc, vec_exc = 0;
int cmp;
if (signal) {
cmp = float64_compare(a, b, &env->fpu_status);
} else {
cmp = float64_compare_quiet(a, b, &env->fpu_status);
}
vxc = check_ieee_exc(env, 0, false, &vec_exc);
handle_ieee_exc(env, vxc, vec_exc, retaddr);
return float_comp_to_cc(env, cmp);
}
void HELPER(gvec_wfc64)(const void *v1, const void *v2, CPUS390XState *env,
uint32_t desc)
{
env->cc_op = wfc64(v1, v2, env, false, GETPC());
}
void HELPER(gvec_wfk64)(const void *v1, const void *v2, CPUS390XState *env,
uint32_t desc)
{
env->cc_op = wfc64(v1, v2, env, true, GETPC());
}
typedef int (*vfc64_fn)(float64 a, float64 b, float_status *status);
static int vfc64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
CPUS390XState *env, bool s, vfc64_fn fn, uintptr_t retaddr)
{
uint8_t vxc, vec_exc = 0;
S390Vector tmp = {};
int match = 0;
int i;
for (i = 0; i < 2; i++) {
const float64 a = s390_vec_read_element64(v2, i);
const float64 b = s390_vec_read_element64(v3, i);
/* swap the order of the parameters, so we can use existing functions */
if (fn(b, a, &env->fpu_status)) {
match++;
s390_vec_write_element64(&tmp, i, -1ull);
}
vxc = check_ieee_exc(env, i, false, &vec_exc);
if (s || vxc) {
break;
}
}
handle_ieee_exc(env, vxc, vec_exc, retaddr);
*v1 = tmp;
if (match) {
return s || match == 2 ? 0 : 1;
}
return 3;
}
void HELPER(gvec_vfce64)(void *v1, const void *v2, const void *v3,
CPUS390XState *env, uint32_t desc)
{
vfc64(v1, v2, v3, env, false, float64_eq_quiet, GETPC());
}
void HELPER(gvec_vfce64s)(void *v1, const void *v2, const void *v3,
CPUS390XState *env, uint32_t desc)
{
vfc64(v1, v2, v3, env, true, float64_eq_quiet, GETPC());
}
void HELPER(gvec_vfce64_cc)(void *v1, const void *v2, const void *v3,
CPUS390XState *env, uint32_t desc)
{
env->cc_op = vfc64(v1, v2, v3, env, false, float64_eq_quiet, GETPC());
}
void HELPER(gvec_vfce64s_cc)(void *v1, const void *v2, const void *v3,
CPUS390XState *env, uint32_t desc)
{
env->cc_op = vfc64(v1, v2, v3, env, true, float64_eq_quiet, GETPC());
}
void HELPER(gvec_vfch64)(void *v1, const void *v2, const void *v3,
CPUS390XState *env, uint32_t desc)
{
vfc64(v1, v2, v3, env, false, float64_lt_quiet, GETPC());
}
void HELPER(gvec_vfch64s)(void *v1, const void *v2, const void *v3,
CPUS390XState *env, uint32_t desc)
{
vfc64(v1, v2, v3, env, true, float64_lt_quiet, GETPC());
}
void HELPER(gvec_vfch64_cc)(void *v1, const void *v2, const void *v3,
CPUS390XState *env, uint32_t desc)
{
env->cc_op = vfc64(v1, v2, v3, env, false, float64_lt_quiet, GETPC());
}
void HELPER(gvec_vfch64s_cc)(void *v1, const void *v2, const void *v3,
CPUS390XState *env, uint32_t desc)
{
env->cc_op = vfc64(v1, v2, v3, env, true, float64_lt_quiet, GETPC());
}
void HELPER(gvec_vfche64)(void *v1, const void *v2, const void *v3,
CPUS390XState *env, uint32_t desc)
{
vfc64(v1, v2, v3, env, false, float64_le_quiet, GETPC());
}
void HELPER(gvec_vfche64s)(void *v1, const void *v2, const void *v3,
CPUS390XState *env, uint32_t desc)
{
vfc64(v1, v2, v3, env, true, float64_le_quiet, GETPC());
}
void HELPER(gvec_vfche64_cc)(void *v1, const void *v2, const void *v3,
CPUS390XState *env, uint32_t desc)
{
env->cc_op = vfc64(v1, v2, v3, env, false, float64_le_quiet, GETPC());
}
void HELPER(gvec_vfche64s_cc)(void *v1, const void *v2, const void *v3,
CPUS390XState *env, uint32_t desc)
{
env->cc_op = vfc64(v1, v2, v3, env, true, float64_le_quiet, GETPC());
}
static uint64_t vcdg64(uint64_t a, float_status *s)
{
return int64_to_float64(a, s);
}
void HELPER(gvec_vcdg64)(void *v1, const void *v2, CPUS390XState *env,
uint32_t desc)
{
const uint8_t erm = extract32(simd_data(desc), 4, 4);
const bool XxC = extract32(simd_data(desc), 2, 1);
vop64_2(v1, v2, env, false, XxC, erm, vcdg64, GETPC());
}
void HELPER(gvec_vcdg64s)(void *v1, const void *v2, CPUS390XState *env,
uint32_t desc)
{
const uint8_t erm = extract32(simd_data(desc), 4, 4);
const bool XxC = extract32(simd_data(desc), 2, 1);
vop64_2(v1, v2, env, true, XxC, erm, vcdg64, GETPC());
}
static uint64_t vcdlg64(uint64_t a, float_status *s)
{
return uint64_to_float64(a, s);
}
void HELPER(gvec_vcdlg64)(void *v1, const void *v2, CPUS390XState *env,
uint32_t desc)
{
const uint8_t erm = extract32(simd_data(desc), 4, 4);
const bool XxC = extract32(simd_data(desc), 2, 1);
vop64_2(v1, v2, env, false, XxC, erm, vcdlg64, GETPC());
}
void HELPER(gvec_vcdlg64s)(void *v1, const void *v2, CPUS390XState *env,
uint32_t desc)
{
const uint8_t erm = extract32(simd_data(desc), 4, 4);
const bool XxC = extract32(simd_data(desc), 2, 1);
vop64_2(v1, v2, env, true, XxC, erm, vcdlg64, GETPC());
}
static uint64_t vcgd64(uint64_t a, float_status *s)
{
return float64_to_int64(a, s);
}
void HELPER(gvec_vcgd64)(void *v1, const void *v2, CPUS390XState *env,
uint32_t desc)
{
const uint8_t erm = extract32(simd_data(desc), 4, 4);
const bool XxC = extract32(simd_data(desc), 2, 1);
vop64_2(v1, v2, env, false, XxC, erm, vcgd64, GETPC());
}
void HELPER(gvec_vcgd64s)(void *v1, const void *v2, CPUS390XState *env,
uint32_t desc)
{
const uint8_t erm = extract32(simd_data(desc), 4, 4);
const bool XxC = extract32(simd_data(desc), 2, 1);
vop64_2(v1, v2, env, true, XxC, erm, vcgd64, GETPC());
}
static uint64_t vclgd64(uint64_t a, float_status *s)
{
return float64_to_uint64(a, s);
}
void HELPER(gvec_vclgd64)(void *v1, const void *v2, CPUS390XState *env,
uint32_t desc)
{
const uint8_t erm = extract32(simd_data(desc), 4, 4);
const bool XxC = extract32(simd_data(desc), 2, 1);
vop64_2(v1, v2, env, false, XxC, erm, vclgd64, GETPC());
}
void HELPER(gvec_vclgd64s)(void *v1, const void *v2, CPUS390XState *env,
uint32_t desc)
{
const uint8_t erm = extract32(simd_data(desc), 4, 4);
const bool XxC = extract32(simd_data(desc), 2, 1);
vop64_2(v1, v2, env, true, XxC, erm, vclgd64, GETPC());
}
static uint64_t vfd64(uint64_t a, uint64_t b, float_status *s)
{
return float64_div(a, b, s);
}
void HELPER(gvec_vfd64)(void *v1, const void *v2, const void *v3,
CPUS390XState *env, uint32_t desc)
{
vop64_3(v1, v2, v3, env, false, vfd64, GETPC());
}
void HELPER(gvec_vfd64s)(void *v1, const void *v2, const void *v3,
CPUS390XState *env, uint32_t desc)
{
vop64_3(v1, v2, v3, env, true, vfd64, GETPC());
}
static uint64_t vfi64(uint64_t a, float_status *s)
{
return float64_round_to_int(a, s);
}
void HELPER(gvec_vfi64)(void *v1, const void *v2, CPUS390XState *env,
uint32_t desc)
{
const uint8_t erm = extract32(simd_data(desc), 4, 4);
const bool XxC = extract32(simd_data(desc), 2, 1);
vop64_2(v1, v2, env, false, XxC, erm, vfi64, GETPC());
}
void HELPER(gvec_vfi64s)(void *v1, const void *v2, CPUS390XState *env,
uint32_t desc)
{
const uint8_t erm = extract32(simd_data(desc), 4, 4);
const bool XxC = extract32(simd_data(desc), 2, 1);
vop64_2(v1, v2, env, true, XxC, erm, vfi64, GETPC());
}
static void vfll32(S390Vector *v1, const S390Vector *v2, CPUS390XState *env,
bool s, uintptr_t retaddr)
{
uint8_t vxc, vec_exc = 0;
S390Vector tmp = {};
int i;
for (i = 0; i < 2; i++) {
/* load from even element */
const float32 a = s390_vec_read_element32(v2, i * 2);
const uint64_t ret = float32_to_float64(a, &env->fpu_status);
s390_vec_write_element64(&tmp, i, ret);
/* indicate the source element */
vxc = check_ieee_exc(env, i * 2, false, &vec_exc);
if (s || vxc) {
break;
}
}
handle_ieee_exc(env, vxc, vec_exc, retaddr);
*v1 = tmp;
}
void HELPER(gvec_vfll32)(void *v1, const void *v2, CPUS390XState *env,
uint32_t desc)
{
vfll32(v1, v2, env, false, GETPC());
}
void HELPER(gvec_vfll32s)(void *v1, const void *v2, CPUS390XState *env,
uint32_t desc)
{
vfll32(v1, v2, env, true, GETPC());
}
static void vflr64(S390Vector *v1, const S390Vector *v2, CPUS390XState *env,
bool s, bool XxC, uint8_t erm, uintptr_t retaddr)
{
uint8_t vxc, vec_exc = 0;
S390Vector tmp = {};
int i, old_mode;
old_mode = s390_swap_bfp_rounding_mode(env, erm);
for (i = 0; i < 2; i++) {
float64 a = s390_vec_read_element64(v2, i);
uint32_t ret = float64_to_float32(a, &env->fpu_status);
/* place at even element */
s390_vec_write_element32(&tmp, i * 2, ret);
/* indicate the source element */
vxc = check_ieee_exc(env, i, XxC, &vec_exc);
if (s || vxc) {
break;
}
}
s390_restore_bfp_rounding_mode(env, old_mode);
handle_ieee_exc(env, vxc, vec_exc, retaddr);
*v1 = tmp;
}
void HELPER(gvec_vflr64)(void *v1, const void *v2, CPUS390XState *env,
uint32_t desc)
{
const uint8_t erm = extract32(simd_data(desc), 4, 4);
const bool XxC = extract32(simd_data(desc), 2, 1);
vflr64(v1, v2, env, false, XxC, erm, GETPC());
}
void HELPER(gvec_vflr64s)(void *v1, const void *v2, CPUS390XState *env,
uint32_t desc)
{
const uint8_t erm = extract32(simd_data(desc), 4, 4);
const bool XxC = extract32(simd_data(desc), 2, 1);
vflr64(v1, v2, env, true, XxC, erm, GETPC());
}
static uint64_t vfm64(uint64_t a, uint64_t b, float_status *s)
{
return float64_mul(a, b, s);
}
void HELPER(gvec_vfm64)(void *v1, const void *v2, const void *v3,
CPUS390XState *env, uint32_t desc)
{
vop64_3(v1, v2, v3, env, false, vfm64, GETPC());
}
void HELPER(gvec_vfm64s)(void *v1, const void *v2, const void *v3,
CPUS390XState *env, uint32_t desc)
{
vop64_3(v1, v2, v3, env, true, vfm64, GETPC());
}
static void vfma64(S390Vector *v1, const S390Vector *v2, const S390Vector *v3,
const S390Vector *v4, CPUS390XState *env, bool s, int flags,
uintptr_t retaddr)
{
uint8_t vxc, vec_exc = 0;
S390Vector tmp = {};
int i;
for (i = 0; i < 2; i++) {
const uint64_t a = s390_vec_read_element64(v2, i);
const uint64_t b = s390_vec_read_element64(v3, i);
const uint64_t c = s390_vec_read_element64(v4, i);
uint64_t ret = float64_muladd(a, b, c, flags, &env->fpu_status);
s390_vec_write_element64(&tmp, i, ret);
vxc = check_ieee_exc(env, i, false, &vec_exc);
if (s || vxc) {
break;
}
}
handle_ieee_exc(env, vxc, vec_exc, retaddr);
*v1 = tmp;
}
void HELPER(gvec_vfma64)(void *v1, const void *v2, const void *v3,
const void *v4, CPUS390XState *env, uint32_t desc)
{
vfma64(v1, v2, v3, v4, env, false, 0, GETPC());
}
void HELPER(gvec_vfma64s)(void *v1, const void *v2, const void *v3,
const void *v4, CPUS390XState *env, uint32_t desc)
{
vfma64(v1, v2, v3, v4, env, true, 0, GETPC());
}
void HELPER(gvec_vfms64)(void *v1, const void *v2, const void *v3,
const void *v4, CPUS390XState *env, uint32_t desc)
{
vfma64(v1, v2, v3, v4, env, false, float_muladd_negate_c, GETPC());
}
void HELPER(gvec_vfms64s)(void *v1, const void *v2, const void *v3,
const void *v4, CPUS390XState *env, uint32_t desc)
{
vfma64(v1, v2, v3, v4, env, true, float_muladd_negate_c, GETPC());
}
static uint64_t vfsq64(uint64_t a, float_status *s)
{
return float64_sqrt(a, s);
}
void HELPER(gvec_vfsq64)(void *v1, const void *v2, CPUS390XState *env,
uint32_t desc)
{
vop64_2(v1, v2, env, false, false, 0, vfsq64, GETPC());
}
void HELPER(gvec_vfsq64s)(void *v1, const void *v2, CPUS390XState *env,
uint32_t desc)
{
vop64_2(v1, v2, env, true, false, 0, vfsq64, GETPC());
}
static uint64_t vfs64(uint64_t a, uint64_t b, float_status *s)
{
return float64_sub(a, b, s);
}
void HELPER(gvec_vfs64)(void *v1, const void *v2, const void *v3,
CPUS390XState *env, uint32_t desc)
{
vop64_3(v1, v2, v3, env, false, vfs64, GETPC());
}
void HELPER(gvec_vfs64s)(void *v1, const void *v2, const void *v3,
CPUS390XState *env, uint32_t desc)
{
vop64_3(v1, v2, v3, env, true, vfs64, GETPC());
}
static int vftci64(S390Vector *v1, const S390Vector *v2, CPUS390XState *env,
bool s, uint16_t i3)
{
int i, match = 0;
for (i = 0; i < 2; i++) {
float64 a = s390_vec_read_element64(v2, i);
if (float64_dcmask(env, a) & i3) {
match++;
s390_vec_write_element64(v1, i, -1ull);
} else {
s390_vec_write_element64(v1, i, 0);
}
if (s) {
break;
}
}
if (match) {
return s || match == 2 ? 0 : 1;
}
return 3;
}
void HELPER(gvec_vftci64)(void *v1, const void *v2, CPUS390XState *env,
uint32_t desc)
{
env->cc_op = vftci64(v1, v2, env, false, simd_data(desc));
}
void HELPER(gvec_vftci64s)(void *v1, const void *v2, CPUS390XState *env,
uint32_t desc)
{
env->cc_op = vftci64(v1, v2, env, true, simd_data(desc));
}

View File

@ -0,0 +1,192 @@
/*
* QEMU TCG support -- s390x vector support instructions
*
* Copyright (C) 2019 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 "cpu.h"
#include "internal.h"
#include "vec.h"
#include "tcg/tcg.h"
#include "tcg/tcg-gvec-desc.h"
#include "exec/helper-proto.h"
#include "exec/cpu_ldst.h"
#include "exec/exec-all.h"
void HELPER(vll)(CPUS390XState *env, void *v1, uint64_t addr, uint64_t bytes)
{
if (likely(bytes >= 16)) {
uint64_t t0, t1;
t0 = cpu_ldq_data_ra(env, addr, GETPC());
addr = wrap_address(env, addr + 8);
t1 = cpu_ldq_data_ra(env, addr, GETPC());
s390_vec_write_element64(v1, 0, t0);
s390_vec_write_element64(v1, 1, t1);
} else {
S390Vector tmp = {};
int i;
for (i = 0; i < bytes; i++) {
uint8_t byte = cpu_ldub_data_ra(env, addr, GETPC());
s390_vec_write_element8(&tmp, i, byte);
addr = wrap_address(env, addr + 1);
}
*(S390Vector *)v1 = tmp;
}
}
#define DEF_VPK_HFN(BITS, TBITS) \
typedef uint##TBITS##_t (*vpk##BITS##_fn)(uint##BITS##_t, int *); \
static int vpk##BITS##_hfn(S390Vector *v1, const S390Vector *v2, \
const S390Vector *v3, vpk##BITS##_fn fn) \
{ \
int i, saturated = 0; \
S390Vector tmp; \
\
for (i = 0; i < (128 / TBITS); i++) { \
uint##BITS##_t src; \
\
if (i < (128 / BITS)) { \
src = s390_vec_read_element##BITS(v2, i); \
} else { \
src = s390_vec_read_element##BITS(v3, i - (128 / BITS)); \
} \
s390_vec_write_element##TBITS(&tmp, i, fn(src, &saturated)); \
} \
*v1 = tmp; \
return saturated; \
}
DEF_VPK_HFN(64, 32)
DEF_VPK_HFN(32, 16)
DEF_VPK_HFN(16, 8)
#define DEF_VPK(BITS, TBITS) \
static uint##TBITS##_t vpk##BITS##e(uint##BITS##_t src, int *saturated) \
{ \
return src; \
} \
void HELPER(gvec_vpk##BITS)(void *v1, const void *v2, const void *v3, \
uint32_t desc) \
{ \
vpk##BITS##_hfn(v1, v2, v3, vpk##BITS##e); \
}
DEF_VPK(64, 32)
DEF_VPK(32, 16)
DEF_VPK(16, 8)
#define DEF_VPKS(BITS, TBITS) \
static uint##TBITS##_t vpks##BITS##e(uint##BITS##_t src, int *saturated) \
{ \
if ((int##BITS##_t)src > INT##TBITS##_MAX) { \
(*saturated)++; \
return INT##TBITS##_MAX; \
} else if ((int##BITS##_t)src < INT##TBITS##_MIN) { \
(*saturated)++; \
return INT##TBITS##_MIN; \
} \
return src; \
} \
void HELPER(gvec_vpks##BITS)(void *v1, const void *v2, const void *v3, \
uint32_t desc) \
{ \
vpk##BITS##_hfn(v1, v2, v3, vpks##BITS##e); \
} \
void HELPER(gvec_vpks_cc##BITS)(void *v1, const void *v2, const void *v3, \
CPUS390XState *env, uint32_t desc) \
{ \
int saturated = vpk##BITS##_hfn(v1, v2, v3, vpks##BITS##e); \
\
if (saturated == (128 / TBITS)) { \
env->cc_op = 3; \
} else if (saturated) { \
env->cc_op = 1; \
} else { \
env->cc_op = 0; \
} \
}
DEF_VPKS(64, 32)
DEF_VPKS(32, 16)
DEF_VPKS(16, 8)
#define DEF_VPKLS(BITS, TBITS) \
static uint##TBITS##_t vpkls##BITS##e(uint##BITS##_t src, int *saturated) \
{ \
if (src > UINT##TBITS##_MAX) { \
(*saturated)++; \
return UINT##TBITS##_MAX; \
} \
return src; \
} \
void HELPER(gvec_vpkls##BITS)(void *v1, const void *v2, const void *v3, \
uint32_t desc) \
{ \
vpk##BITS##_hfn(v1, v2, v3, vpkls##BITS##e); \
} \
void HELPER(gvec_vpkls_cc##BITS)(void *v1, const void *v2, const void *v3, \
CPUS390XState *env, uint32_t desc) \
{ \
int saturated = vpk##BITS##_hfn(v1, v2, v3, vpkls##BITS##e); \
\
if (saturated == (128 / TBITS)) { \
env->cc_op = 3; \
} else if (saturated) { \
env->cc_op = 1; \
} else { \
env->cc_op = 0; \
} \
}
DEF_VPKLS(64, 32)
DEF_VPKLS(32, 16)
DEF_VPKLS(16, 8)
void HELPER(gvec_vperm)(void *v1, const void *v2, const void *v3,
const void *v4, uint32_t desc)
{
S390Vector tmp;
int i;
for (i = 0; i < 16; i++) {
const uint8_t selector = s390_vec_read_element8(v4, i) & 0x1f;
uint8_t byte;
if (selector < 16) {
byte = s390_vec_read_element8(v2, selector);
} else {
byte = s390_vec_read_element8(v3, selector - 16);
}
s390_vec_write_element8(&tmp, i, byte);
}
*(S390Vector *)v1 = tmp;
}
void HELPER(vstl)(CPUS390XState *env, const void *v1, uint64_t addr,
uint64_t bytes)
{
/* Probe write access before actually modifying memory */
probe_write_access(env, addr, bytes, GETPC());
if (likely(bytes >= 16)) {
cpu_stq_data_ra(env, addr, s390_vec_read_element64(v1, 0), GETPC());
addr = wrap_address(env, addr + 8);
cpu_stq_data_ra(env, addr, s390_vec_read_element64(v1, 1), GETPC());
} else {
S390Vector tmp = {};
int i;
for (i = 0; i < bytes; i++) {
uint8_t byte = s390_vec_read_element8(v1, i);
cpu_stb_data_ra(env, addr, byte, GETPC());
addr = wrap_address(env, addr + 1);
}
*(S390Vector *)v1 = tmp;
}
}

View File

@ -0,0 +1,618 @@
/*
* QEMU TCG support -- s390x vector integer instruction support
*
* Copyright (C) 2019 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 "vec.h"
#include "exec/helper-proto.h"
#include "tcg/tcg-gvec-desc.h"
static bool s390_vec_is_zero(const S390Vector *v)
{
return !v->doubleword[0] && !v->doubleword[1];
}
static void s390_vec_xor(S390Vector *res, const S390Vector *a,
const S390Vector *b)
{
res->doubleword[0] = a->doubleword[0] ^ b->doubleword[0];
res->doubleword[1] = a->doubleword[1] ^ b->doubleword[1];
}
static void s390_vec_and(S390Vector *res, const S390Vector *a,
const S390Vector *b)
{
res->doubleword[0] = a->doubleword[0] & b->doubleword[0];
res->doubleword[1] = a->doubleword[1] & b->doubleword[1];
}
static bool s390_vec_equal(const S390Vector *a, const S390Vector *b)
{
return a->doubleword[0] == b->doubleword[0] &&
a->doubleword[1] == b->doubleword[1];
}
static void s390_vec_shl(S390Vector *d, const S390Vector *a, uint64_t count)
{
uint64_t tmp;
g_assert(count < 128);
if (count == 0) {
d->doubleword[0] = a->doubleword[0];
d->doubleword[1] = a->doubleword[1];
} else if (count == 64) {
d->doubleword[0] = a->doubleword[1];
d->doubleword[1] = 0;
} else if (count < 64) {
tmp = extract64(a->doubleword[1], 64 - count, count);
d->doubleword[1] = a->doubleword[1] << count;
d->doubleword[0] = (a->doubleword[0] << count) | tmp;
} else {
d->doubleword[0] = a->doubleword[1] << (count - 64);
d->doubleword[1] = 0;
}
}
static void s390_vec_sar(S390Vector *d, const S390Vector *a, uint64_t count)
{
uint64_t tmp;
if (count == 0) {
d->doubleword[0] = a->doubleword[0];
d->doubleword[1] = a->doubleword[1];
} else if (count == 64) {
tmp = (int64_t)a->doubleword[0] >> 63;
d->doubleword[1] = a->doubleword[0];
d->doubleword[0] = tmp;
} else if (count < 64) {
tmp = a->doubleword[1] >> count;
d->doubleword[1] = deposit64(tmp, 64 - count, count, a->doubleword[0]);
d->doubleword[0] = (int64_t)a->doubleword[0] >> count;
} else {
tmp = (int64_t)a->doubleword[0] >> 63;
d->doubleword[1] = (int64_t)a->doubleword[0] >> (count - 64);
d->doubleword[0] = tmp;
}
}
static void s390_vec_shr(S390Vector *d, const S390Vector *a, uint64_t count)
{
uint64_t tmp;
g_assert(count < 128);
if (count == 0) {
d->doubleword[0] = a->doubleword[0];
d->doubleword[1] = a->doubleword[1];
} else if (count == 64) {
d->doubleword[1] = a->doubleword[0];
d->doubleword[0] = 0;
} else if (count < 64) {
tmp = a->doubleword[1] >> count;
d->doubleword[1] = deposit64(tmp, 64 - count, count, a->doubleword[0]);
d->doubleword[0] = a->doubleword[0] >> count;
} else {
d->doubleword[1] = a->doubleword[0] >> (count - 64);
d->doubleword[0] = 0;
}
}
#define DEF_VAVG(BITS) \
void HELPER(gvec_vavg##BITS)(void *v1, const void *v2, const void *v3, \
uint32_t desc) \
{ \
int i; \
\
for (i = 0; i < (128 / BITS); i++) { \
const int32_t a = (int##BITS##_t)s390_vec_read_element##BITS(v2, i); \
const int32_t b = (int##BITS##_t)s390_vec_read_element##BITS(v3, i); \
\
s390_vec_write_element##BITS(v1, i, (a + b + 1) >> 1); \
} \
}
DEF_VAVG(8)
DEF_VAVG(16)
#define DEF_VAVGL(BITS) \
void HELPER(gvec_vavgl##BITS)(void *v1, const void *v2, const void *v3, \
uint32_t desc) \
{ \
int i; \
\
for (i = 0; i < (128 / BITS); i++) { \
const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i); \
const uint##BITS##_t b = s390_vec_read_element##BITS(v3, i); \
\
s390_vec_write_element##BITS(v1, i, (a + b + 1) >> 1); \
} \
}
DEF_VAVGL(8)
DEF_VAVGL(16)
#define DEF_VCLZ(BITS) \
void HELPER(gvec_vclz##BITS)(void *v1, const void *v2, uint32_t desc) \
{ \
int i; \
\
for (i = 0; i < (128 / BITS); i++) { \
const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i); \
\
s390_vec_write_element##BITS(v1, i, clz32(a) - 32 + BITS); \
} \
}
DEF_VCLZ(8)
DEF_VCLZ(16)
#define DEF_VCTZ(BITS) \
void HELPER(gvec_vctz##BITS)(void *v1, const void *v2, uint32_t desc) \
{ \
int i; \
\
for (i = 0; i < (128 / BITS); i++) { \
const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i); \
\
s390_vec_write_element##BITS(v1, i, a ? ctz32(a) : BITS); \
} \
}
DEF_VCTZ(8)
DEF_VCTZ(16)
/* like binary multiplication, but XOR instead of addition */
#define DEF_GALOIS_MULTIPLY(BITS, TBITS) \
static uint##TBITS##_t galois_multiply##BITS(uint##TBITS##_t a, \
uint##TBITS##_t b) \
{ \
uint##TBITS##_t res = 0; \
\
while (b) { \
if (b & 0x1) { \
res = res ^ a; \
} \
a = a << 1; \
b = b >> 1; \
} \
return res; \
}
DEF_GALOIS_MULTIPLY(8, 16)
DEF_GALOIS_MULTIPLY(16, 32)
DEF_GALOIS_MULTIPLY(32, 64)
static S390Vector galois_multiply64(uint64_t a, uint64_t b)
{
S390Vector res = {};
S390Vector va = {
.doubleword[1] = a,
};
S390Vector vb = {
.doubleword[1] = b,
};
while (!s390_vec_is_zero(&vb)) {
if (vb.doubleword[1] & 0x1) {
s390_vec_xor(&res, &res, &va);
}
s390_vec_shl(&va, &va, 1);
s390_vec_shr(&vb, &vb, 1);
}
return res;
}
#define DEF_VGFM(BITS, TBITS) \
void HELPER(gvec_vgfm##BITS)(void *v1, const void *v2, const void *v3, \
uint32_t desc) \
{ \
int i; \
\
for (i = 0; i < (128 / TBITS); i++) { \
uint##BITS##_t a = s390_vec_read_element##BITS(v2, i * 2); \
uint##BITS##_t b = s390_vec_read_element##BITS(v3, i * 2); \
uint##TBITS##_t d = galois_multiply##BITS(a, b); \
\
a = s390_vec_read_element##BITS(v2, i * 2 + 1); \
b = s390_vec_read_element##BITS(v3, i * 2 + 1); \
d = d ^ galois_multiply32(a, b); \
s390_vec_write_element##TBITS(v1, i, d); \
} \
}
DEF_VGFM(8, 16)
DEF_VGFM(16, 32)
DEF_VGFM(32, 64)
void HELPER(gvec_vgfm64)(void *v1, const void *v2, const void *v3,
uint32_t desc)
{
S390Vector tmp1, tmp2;
uint64_t a, b;
a = s390_vec_read_element64(v2, 0);
b = s390_vec_read_element64(v3, 0);
tmp1 = galois_multiply64(a, b);
a = s390_vec_read_element64(v2, 1);
b = s390_vec_read_element64(v3, 1);
tmp2 = galois_multiply64(a, b);
s390_vec_xor(v1, &tmp1, &tmp2);
}
#define DEF_VGFMA(BITS, TBITS) \
void HELPER(gvec_vgfma##BITS)(void *v1, const void *v2, const void *v3, \
const void *v4, uint32_t desc) \
{ \
int i; \
\
for (i = 0; i < (128 / TBITS); i++) { \
uint##BITS##_t a = s390_vec_read_element##BITS(v2, i * 2); \
uint##BITS##_t b = s390_vec_read_element##BITS(v3, i * 2); \
uint##TBITS##_t d = galois_multiply##BITS(a, b); \
\
a = s390_vec_read_element##BITS(v2, i * 2 + 1); \
b = s390_vec_read_element##BITS(v3, i * 2 + 1); \
d = d ^ galois_multiply32(a, b); \
d = d ^ s390_vec_read_element##TBITS(v4, i); \
s390_vec_write_element##TBITS(v1, i, d); \
} \
}
DEF_VGFMA(8, 16)
DEF_VGFMA(16, 32)
DEF_VGFMA(32, 64)
void HELPER(gvec_vgfma64)(void *v1, const void *v2, const void *v3,
const void *v4, uint32_t desc)
{
S390Vector tmp1, tmp2;
uint64_t a, b;
a = s390_vec_read_element64(v2, 0);
b = s390_vec_read_element64(v3, 0);
tmp1 = galois_multiply64(a, b);
a = s390_vec_read_element64(v2, 1);
b = s390_vec_read_element64(v3, 1);
tmp2 = galois_multiply64(a, b);
s390_vec_xor(&tmp1, &tmp1, &tmp2);
s390_vec_xor(v1, &tmp1, v4);
}
#define DEF_VMAL(BITS) \
void HELPER(gvec_vmal##BITS)(void *v1, const void *v2, const void *v3, \
const void *v4, uint32_t desc) \
{ \
int i; \
\
for (i = 0; i < (128 / BITS); i++) { \
const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i); \
const uint##BITS##_t b = s390_vec_read_element##BITS(v3, i); \
const uint##BITS##_t c = s390_vec_read_element##BITS(v4, i); \
\
s390_vec_write_element##BITS(v1, i, a * b + c); \
} \
}
DEF_VMAL(8)
DEF_VMAL(16)
#define DEF_VMAH(BITS) \
void HELPER(gvec_vmah##BITS)(void *v1, const void *v2, const void *v3, \
const void *v4, uint32_t desc) \
{ \
int i; \
\
for (i = 0; i < (128 / BITS); i++) { \
const int32_t a = (int##BITS##_t)s390_vec_read_element##BITS(v2, i); \
const int32_t b = (int##BITS##_t)s390_vec_read_element##BITS(v3, i); \
const int32_t c = (int##BITS##_t)s390_vec_read_element##BITS(v4, i); \
\
s390_vec_write_element##BITS(v1, i, (a * b + c) >> BITS); \
} \
}
DEF_VMAH(8)
DEF_VMAH(16)
#define DEF_VMALH(BITS) \
void HELPER(gvec_vmalh##BITS)(void *v1, const void *v2, const void *v3, \
const void *v4, uint32_t desc) \
{ \
int i; \
\
for (i = 0; i < (128 / BITS); i++) { \
const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i); \
const uint##BITS##_t b = s390_vec_read_element##BITS(v3, i); \
const uint##BITS##_t c = s390_vec_read_element##BITS(v4, i); \
\
s390_vec_write_element##BITS(v1, i, (a * b + c) >> BITS); \
} \
}
DEF_VMALH(8)
DEF_VMALH(16)
#define DEF_VMAE(BITS, TBITS) \
void HELPER(gvec_vmae##BITS)(void *v1, const void *v2, const void *v3, \
const void *v4, uint32_t desc) \
{ \
int i, j; \
\
for (i = 0, j = 0; i < (128 / TBITS); i++, j += 2) { \
int##TBITS##_t a = (int##BITS##_t)s390_vec_read_element##BITS(v2, j); \
int##TBITS##_t b = (int##BITS##_t)s390_vec_read_element##BITS(v3, j); \
int##TBITS##_t c = s390_vec_read_element##TBITS(v4, i); \
\
s390_vec_write_element##TBITS(v1, i, a * b + c); \
} \
}
DEF_VMAE(8, 16)
DEF_VMAE(16, 32)
DEF_VMAE(32, 64)
#define DEF_VMALE(BITS, TBITS) \
void HELPER(gvec_vmale##BITS)(void *v1, const void *v2, const void *v3, \
const void *v4, uint32_t desc) \
{ \
int i, j; \
\
for (i = 0, j = 0; i < (128 / TBITS); i++, j += 2) { \
uint##TBITS##_t a = s390_vec_read_element##BITS(v2, j); \
uint##TBITS##_t b = s390_vec_read_element##BITS(v3, j); \
uint##TBITS##_t c = s390_vec_read_element##TBITS(v4, i); \
\
s390_vec_write_element##TBITS(v1, i, a * b + c); \
} \
}
DEF_VMALE(8, 16)
DEF_VMALE(16, 32)
DEF_VMALE(32, 64)
#define DEF_VMAO(BITS, TBITS) \
void HELPER(gvec_vmao##BITS)(void *v1, const void *v2, const void *v3, \
const void *v4, uint32_t desc) \
{ \
int i, j; \
\
for (i = 0, j = 1; i < (128 / TBITS); i++, j += 2) { \
int##TBITS##_t a = (int##BITS##_t)s390_vec_read_element##BITS(v2, j); \
int##TBITS##_t b = (int##BITS##_t)s390_vec_read_element##BITS(v3, j); \
int##TBITS##_t c = s390_vec_read_element##TBITS(v4, i); \
\
s390_vec_write_element##TBITS(v1, i, a * b + c); \
} \
}
DEF_VMAO(8, 16)
DEF_VMAO(16, 32)
DEF_VMAO(32, 64)
#define DEF_VMALO(BITS, TBITS) \
void HELPER(gvec_vmalo##BITS)(void *v1, const void *v2, const void *v3, \
const void *v4, uint32_t desc) \
{ \
int i, j; \
\
for (i = 0, j = 1; i < (128 / TBITS); i++, j += 2) { \
uint##TBITS##_t a = s390_vec_read_element##BITS(v2, j); \
uint##TBITS##_t b = s390_vec_read_element##BITS(v3, j); \
uint##TBITS##_t c = s390_vec_read_element##TBITS(v4, i); \
\
s390_vec_write_element##TBITS(v1, i, a * b + c); \
} \
}
DEF_VMALO(8, 16)
DEF_VMALO(16, 32)
DEF_VMALO(32, 64)
#define DEF_VMH(BITS) \
void HELPER(gvec_vmh##BITS)(void *v1, const void *v2, const void *v3, \
uint32_t desc) \
{ \
int i; \
\
for (i = 0; i < (128 / BITS); i++) { \
const int32_t a = (int##BITS##_t)s390_vec_read_element##BITS(v2, i); \
const int32_t b = (int##BITS##_t)s390_vec_read_element##BITS(v3, i); \
\
s390_vec_write_element##BITS(v1, i, (a * b) >> BITS); \
} \
}
DEF_VMH(8)
DEF_VMH(16)
#define DEF_VMLH(BITS) \
void HELPER(gvec_vmlh##BITS)(void *v1, const void *v2, const void *v3, \
uint32_t desc) \
{ \
int i; \
\
for (i = 0; i < (128 / BITS); i++) { \
const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i); \
const uint##BITS##_t b = s390_vec_read_element##BITS(v3, i); \
\
s390_vec_write_element##BITS(v1, i, (a * b) >> BITS); \
} \
}
DEF_VMLH(8)
DEF_VMLH(16)
#define DEF_VME(BITS, TBITS) \
void HELPER(gvec_vme##BITS)(void *v1, const void *v2, const void *v3, \
uint32_t desc) \
{ \
int i, j; \
\
for (i = 0, j = 0; i < (128 / TBITS); i++, j += 2) { \
int##TBITS##_t a = (int##BITS##_t)s390_vec_read_element##BITS(v2, j); \
int##TBITS##_t b = (int##BITS##_t)s390_vec_read_element##BITS(v3, j); \
\
s390_vec_write_element##TBITS(v1, i, a * b); \
} \
}
DEF_VME(8, 16)
DEF_VME(16, 32)
DEF_VME(32, 64)
#define DEF_VMLE(BITS, TBITS) \
void HELPER(gvec_vmle##BITS)(void *v1, const void *v2, const void *v3, \
uint32_t desc) \
{ \
int i, j; \
\
for (i = 0, j = 0; i < (128 / TBITS); i++, j += 2) { \
const uint##TBITS##_t a = s390_vec_read_element##BITS(v2, j); \
const uint##TBITS##_t b = s390_vec_read_element##BITS(v3, j); \
\
s390_vec_write_element##TBITS(v1, i, a * b); \
} \
}
DEF_VMLE(8, 16)
DEF_VMLE(16, 32)
DEF_VMLE(32, 64)
#define DEF_VMO(BITS, TBITS) \
void HELPER(gvec_vmo##BITS)(void *v1, const void *v2, const void *v3, \
uint32_t desc) \
{ \
int i, j; \
\
for (i = 0, j = 1; i < (128 / TBITS); i++, j += 2) { \
int##TBITS##_t a = (int##BITS##_t)s390_vec_read_element##BITS(v2, j); \
int##TBITS##_t b = (int##BITS##_t)s390_vec_read_element##BITS(v3, j); \
\
s390_vec_write_element##TBITS(v1, i, a * b); \
} \
}
DEF_VMO(8, 16)
DEF_VMO(16, 32)
DEF_VMO(32, 64)
#define DEF_VMLO(BITS, TBITS) \
void HELPER(gvec_vmlo##BITS)(void *v1, const void *v2, const void *v3, \
uint32_t desc) \
{ \
int i, j; \
\
for (i = 0, j = 1; i < (128 / TBITS); i++, j += 2) { \
const uint##TBITS##_t a = s390_vec_read_element##BITS(v2, j); \
const uint##TBITS##_t b = s390_vec_read_element##BITS(v3, j); \
\
s390_vec_write_element##TBITS(v1, i, a * b); \
} \
}
DEF_VMLO(8, 16)
DEF_VMLO(16, 32)
DEF_VMLO(32, 64)
#define DEF_VPOPCT(BITS) \
void HELPER(gvec_vpopct##BITS)(void *v1, const void *v2, uint32_t desc) \
{ \
int i; \
\
for (i = 0; i < (128 / BITS); i++) { \
const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i); \
\
s390_vec_write_element##BITS(v1, i, ctpop32(a)); \
} \
}
DEF_VPOPCT(8)
DEF_VPOPCT(16)
#define DEF_VERLLV(BITS) \
void HELPER(gvec_verllv##BITS)(void *v1, const void *v2, const void *v3, \
uint32_t desc) \
{ \
int i; \
\
for (i = 0; i < (128 / BITS); i++) { \
const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i); \
const uint##BITS##_t b = s390_vec_read_element##BITS(v3, i); \
\
s390_vec_write_element##BITS(v1, i, rol##BITS(a, b)); \
} \
}
DEF_VERLLV(8)
DEF_VERLLV(16)
#define DEF_VERLL(BITS) \
void HELPER(gvec_verll##BITS)(void *v1, const void *v2, uint64_t count, \
uint32_t desc) \
{ \
int i; \
\
for (i = 0; i < (128 / BITS); i++) { \
const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i); \
\
s390_vec_write_element##BITS(v1, i, rol##BITS(a, count)); \
} \
}
DEF_VERLL(8)
DEF_VERLL(16)
#define DEF_VERIM(BITS) \
void HELPER(gvec_verim##BITS)(void *v1, const void *v2, const void *v3, \
uint32_t desc) \
{ \
const uint8_t count = simd_data(desc); \
int i; \
\
for (i = 0; i < (128 / BITS); i++) { \
const uint##BITS##_t a = s390_vec_read_element##BITS(v1, i); \
const uint##BITS##_t b = s390_vec_read_element##BITS(v2, i); \
const uint##BITS##_t mask = s390_vec_read_element##BITS(v3, i); \
const uint##BITS##_t d = (a & ~mask) | (rol##BITS(b, count) & mask); \
\
s390_vec_write_element##BITS(v1, i, d); \
} \
}
DEF_VERIM(8)
DEF_VERIM(16)
void HELPER(gvec_vsl)(void *v1, const void *v2, uint64_t count,
uint32_t desc)
{
s390_vec_shl(v1, v2, count);
}
void HELPER(gvec_vsra)(void *v1, const void *v2, uint64_t count,
uint32_t desc)
{
s390_vec_sar(v1, v2, count);
}
void HELPER(gvec_vsrl)(void *v1, const void *v2, uint64_t count,
uint32_t desc)
{
s390_vec_shr(v1, v2, count);
}
#define DEF_VSCBI(BITS) \
void HELPER(gvec_vscbi##BITS)(void *v1, const void *v2, const void *v3, \
uint32_t desc) \
{ \
int i; \
\
for (i = 0; i < (128 / BITS); i++) { \
const uint##BITS##_t a = s390_vec_read_element##BITS(v2, i); \
const uint##BITS##_t b = s390_vec_read_element##BITS(v3, i); \
\
s390_vec_write_element##BITS(v1, i, a >= b); \
} \
}
DEF_VSCBI(8)
DEF_VSCBI(16)
void HELPER(gvec_vtm)(void *v1, const void *v2, CPUS390XState *env,
uint32_t desc)
{
S390Vector tmp;
s390_vec_and(&tmp, v1, v2);
if (s390_vec_is_zero(&tmp)) {
/* Selected bits all zeros; or all mask bits zero */
env->cc_op = 0;
} else if (s390_vec_equal(&tmp, v2)) {
/* Selected bits all ones */
env->cc_op = 3;
} else {
/* Selected bits a mix of zeros and ones */
env->cc_op = 1;
}
}

View File

@ -0,0 +1,473 @@
/*
* QEMU TCG support -- s390x vector string instruction support
*
* Copyright (C) 2019 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 "internal.h"
#include "vec.h"
#include "tcg/tcg.h"
#include "tcg/tcg-gvec-desc.h"
#include "exec/helper-proto.h"
/*
* Returns a bit set in the MSB of each element that is zero,
* as defined by the mask.
*/
static inline uint64_t zero_search(uint64_t a, uint64_t mask)
{
return ~(((a & mask) + mask) | a | mask);
}
/*
* Returns a bit set in the MSB of each element that is not zero,
* as defined by the mask.
*/
static inline uint64_t nonzero_search(uint64_t a, uint64_t mask)
{
return (((a & mask) + mask) | a) & ~mask;
}
/*
* Returns the byte offset for the first match, or 16 for no match.
*/
static inline int match_index(uint64_t c0, uint64_t c1)
{
return (c0 ? clz64(c0) : clz64(c1) + 64) >> 3;
}
/*
* Returns the number of bits composing one element.
*/
static uint8_t get_element_bits(uint8_t es)
{
return (1 << es) * BITS_PER_BYTE;
}
/*
* Returns the bitmask for a single element.
*/
static uint64_t get_single_element_mask(uint8_t es)
{
return -1ull >> (64 - get_element_bits(es));
}
/*
* Returns the bitmask for a single element (excluding the MSB).
*/
static uint64_t get_single_element_lsbs_mask(uint8_t es)
{
return -1ull >> (65 - get_element_bits(es));
}
/*
* Returns the bitmasks for multiple elements (excluding the MSBs).
*/
static uint64_t get_element_lsbs_mask(uint8_t es)
{
return dup_const(es, get_single_element_lsbs_mask(es));
}
static int vfae(void *v1, const void *v2, const void *v3, bool in,
bool rt, bool zs, uint8_t es)
{
const uint64_t mask = get_element_lsbs_mask(es);
const int bits = get_element_bits(es);
uint64_t a0, a1, b0, b1, e0, e1, t0, t1, z0, z1;
uint64_t first_zero = 16;
uint64_t first_equal;
int i;
a0 = s390_vec_read_element64(v2, 0);
a1 = s390_vec_read_element64(v2, 1);
b0 = s390_vec_read_element64(v3, 0);
b1 = s390_vec_read_element64(v3, 1);
e0 = 0;
e1 = 0;
/* compare against equality with every other element */
for (i = 0; i < 64; i += bits) {
t0 = rol64(b0, i);
t1 = rol64(b1, i);
e0 |= zero_search(a0 ^ t0, mask);
e0 |= zero_search(a0 ^ t1, mask);
e1 |= zero_search(a1 ^ t0, mask);
e1 |= zero_search(a1 ^ t1, mask);
}
/* invert the result if requested - invert only the MSBs */
if (in) {
e0 = ~e0 & ~mask;
e1 = ~e1 & ~mask;
}
first_equal = match_index(e0, e1);
if (zs) {
z0 = zero_search(a0, mask);
z1 = zero_search(a1, mask);
first_zero = match_index(z0, z1);
}
if (rt) {
e0 = (e0 >> (bits - 1)) * get_single_element_mask(es);
e1 = (e1 >> (bits - 1)) * get_single_element_mask(es);
s390_vec_write_element64(v1, 0, e0);
s390_vec_write_element64(v1, 1, e1);
} else {
s390_vec_write_element64(v1, 0, MIN(first_equal, first_zero));
s390_vec_write_element64(v1, 1, 0);
}
if (first_zero == 16 && first_equal == 16) {
return 3; /* no match */
} else if (first_zero == 16) {
return 1; /* matching elements, no match for zero */
} else if (first_equal < first_zero) {
return 2; /* matching elements before match for zero */
}
return 0; /* match for zero */
}
#define DEF_VFAE_HELPER(BITS) \
void HELPER(gvec_vfae##BITS)(void *v1, const void *v2, const void *v3, \
uint32_t desc) \
{ \
const bool in = extract32(simd_data(desc), 3, 1); \
const bool rt = extract32(simd_data(desc), 2, 1); \
const bool zs = extract32(simd_data(desc), 1, 1); \
\
vfae(v1, v2, v3, in, rt, zs, MO_##BITS); \
}
DEF_VFAE_HELPER(8)
DEF_VFAE_HELPER(16)
DEF_VFAE_HELPER(32)
#define DEF_VFAE_CC_HELPER(BITS) \
void HELPER(gvec_vfae_cc##BITS)(void *v1, const void *v2, const void *v3, \
CPUS390XState *env, uint32_t desc) \
{ \
const bool in = extract32(simd_data(desc), 3, 1); \
const bool rt = extract32(simd_data(desc), 2, 1); \
const bool zs = extract32(simd_data(desc), 1, 1); \
\
env->cc_op = vfae(v1, v2, v3, in, rt, zs, MO_##BITS); \
}
DEF_VFAE_CC_HELPER(8)
DEF_VFAE_CC_HELPER(16)
DEF_VFAE_CC_HELPER(32)
static int vfee(void *v1, const void *v2, const void *v3, bool zs, uint8_t es)
{
const uint64_t mask = get_element_lsbs_mask(es);
uint64_t a0, a1, b0, b1, e0, e1, z0, z1;
uint64_t first_zero = 16;
uint64_t first_equal;
a0 = s390_vec_read_element64(v2, 0);
a1 = s390_vec_read_element64(v2, 1);
b0 = s390_vec_read_element64(v3, 0);
b1 = s390_vec_read_element64(v3, 1);
e0 = zero_search(a0 ^ b0, mask);
e1 = zero_search(a1 ^ b1, mask);
first_equal = match_index(e0, e1);
if (zs) {
z0 = zero_search(a0, mask);
z1 = zero_search(a1, mask);
first_zero = match_index(z0, z1);
}
s390_vec_write_element64(v1, 0, MIN(first_equal, first_zero));
s390_vec_write_element64(v1, 1, 0);
if (first_zero == 16 && first_equal == 16) {
return 3; /* no match */
} else if (first_zero == 16) {
return 1; /* matching elements, no match for zero */
} else if (first_equal < first_zero) {
return 2; /* matching elements before match for zero */
}
return 0; /* match for zero */
}
#define DEF_VFEE_HELPER(BITS) \
void HELPER(gvec_vfee##BITS)(void *v1, const void *v2, const void *v3, \
uint32_t desc) \
{ \
const bool zs = extract32(simd_data(desc), 1, 1); \
\
vfee(v1, v2, v3, zs, MO_##BITS); \
}
DEF_VFEE_HELPER(8)
DEF_VFEE_HELPER(16)
DEF_VFEE_HELPER(32)
#define DEF_VFEE_CC_HELPER(BITS) \
void HELPER(gvec_vfee_cc##BITS)(void *v1, const void *v2, const void *v3, \
CPUS390XState *env, uint32_t desc) \
{ \
const bool zs = extract32(simd_data(desc), 1, 1); \
\
env->cc_op = vfee(v1, v2, v3, zs, MO_##BITS); \
}
DEF_VFEE_CC_HELPER(8)
DEF_VFEE_CC_HELPER(16)
DEF_VFEE_CC_HELPER(32)
static int vfene(void *v1, const void *v2, const void *v3, bool zs, uint8_t es)
{
const uint64_t mask = get_element_lsbs_mask(es);
uint64_t a0, a1, b0, b1, e0, e1, z0, z1;
uint64_t first_zero = 16;
uint64_t first_inequal;
bool smaller = false;
a0 = s390_vec_read_element64(v2, 0);
a1 = s390_vec_read_element64(v2, 1);
b0 = s390_vec_read_element64(v3, 0);
b1 = s390_vec_read_element64(v3, 1);
e0 = nonzero_search(a0 ^ b0, mask);
e1 = nonzero_search(a1 ^ b1, mask);
first_inequal = match_index(e0, e1);
/* identify the smaller element */
if (first_inequal < 16) {
uint8_t enr = first_inequal / (1 << es);
uint32_t a = s390_vec_read_element(v2, enr, es);
uint32_t b = s390_vec_read_element(v3, enr, es);
smaller = a < b;
}
if (zs) {
z0 = zero_search(a0, mask);
z1 = zero_search(a1, mask);
first_zero = match_index(z0, z1);
}
s390_vec_write_element64(v1, 0, MIN(first_inequal, first_zero));
s390_vec_write_element64(v1, 1, 0);
if (first_zero == 16 && first_inequal == 16) {
return 3;
} else if (first_zero < first_inequal) {
return 0;
}
return smaller ? 1 : 2;
}
#define DEF_VFENE_HELPER(BITS) \
void HELPER(gvec_vfene##BITS)(void *v1, const void *v2, const void *v3, \
uint32_t desc) \
{ \
const bool zs = extract32(simd_data(desc), 1, 1); \
\
vfene(v1, v2, v3, zs, MO_##BITS); \
}
DEF_VFENE_HELPER(8)
DEF_VFENE_HELPER(16)
DEF_VFENE_HELPER(32)
#define DEF_VFENE_CC_HELPER(BITS) \
void HELPER(gvec_vfene_cc##BITS)(void *v1, const void *v2, const void *v3, \
CPUS390XState *env, uint32_t desc) \
{ \
const bool zs = extract32(simd_data(desc), 1, 1); \
\
env->cc_op = vfene(v1, v2, v3, zs, MO_##BITS); \
}
DEF_VFENE_CC_HELPER(8)
DEF_VFENE_CC_HELPER(16)
DEF_VFENE_CC_HELPER(32)
static int vistr(void *v1, const void *v2, uint8_t es)
{
const uint64_t mask = get_element_lsbs_mask(es);
uint64_t a0 = s390_vec_read_element64(v2, 0);
uint64_t a1 = s390_vec_read_element64(v2, 1);
uint64_t z;
int cc = 3;
z = zero_search(a0, mask);
if (z) {
a0 &= ~(-1ull >> clz64(z));
a1 = 0;
cc = 0;
} else {
z = zero_search(a1, mask);
if (z) {
a1 &= ~(-1ull >> clz64(z));
cc = 0;
}
}
s390_vec_write_element64(v1, 0, a0);
s390_vec_write_element64(v1, 1, a1);
return cc;
}
#define DEF_VISTR_HELPER(BITS) \
void HELPER(gvec_vistr##BITS)(void *v1, const void *v2, uint32_t desc) \
{ \
vistr(v1, v2, MO_##BITS); \
}
DEF_VISTR_HELPER(8)
DEF_VISTR_HELPER(16)
DEF_VISTR_HELPER(32)
#define DEF_VISTR_CC_HELPER(BITS) \
void HELPER(gvec_vistr_cc##BITS)(void *v1, const void *v2, CPUS390XState *env, \
uint32_t desc) \
{ \
env->cc_op = vistr(v1, v2, MO_##BITS); \
}
DEF_VISTR_CC_HELPER(8)
DEF_VISTR_CC_HELPER(16)
DEF_VISTR_CC_HELPER(32)
static bool element_compare(uint32_t data, uint32_t l, uint8_t c)
{
const bool equal = extract32(c, 7, 1);
const bool lower = extract32(c, 6, 1);
const bool higher = extract32(c, 5, 1);
if (data < l) {
return lower;
} else if (data > l) {
return higher;
}
return equal;
}
static int vstrc(void *v1, const void *v2, const void *v3, const void *v4,
bool in, bool rt, bool zs, uint8_t es)
{
const uint64_t mask = get_element_lsbs_mask(es);
uint64_t a0 = s390_vec_read_element64(v2, 0);
uint64_t a1 = s390_vec_read_element64(v2, 1);
int first_zero = 16, first_match = 16;
S390Vector rt_result = {};
uint64_t z0, z1;
int i, j;
if (zs) {
z0 = zero_search(a0, mask);
z1 = zero_search(a1, mask);
first_zero = match_index(z0, z1);
}
for (i = 0; i < 16 / (1 << es); i++) {
const uint32_t data = s390_vec_read_element(v2, i, es);
const int cur_byte = i * (1 << es);
bool any_match = false;
/* if we don't need a bit vector, we can stop early */
if (cur_byte == first_zero && !rt) {
break;
}
for (j = 0; j < 16 / (1 << es); j += 2) {
const uint32_t l1 = s390_vec_read_element(v3, j, es);
const uint32_t l2 = s390_vec_read_element(v3, j + 1, es);
/* we are only interested in the highest byte of each element */
const uint8_t c1 = s390_vec_read_element8(v4, j * (1 << es));
const uint8_t c2 = s390_vec_read_element8(v4, (j + 1) * (1 << es));
if (element_compare(data, l1, c1) &&
element_compare(data, l2, c2)) {
any_match = true;
break;
}
}
/* invert the result if requested */
any_match = in ^ any_match;
if (any_match) {
/* indicate bit vector if requested */
if (rt) {
const uint64_t val = -1ull;
first_match = MIN(cur_byte, first_match);
s390_vec_write_element(&rt_result, i, es, val);
} else {
/* stop on the first match */
first_match = cur_byte;
break;
}
}
}
if (rt) {
*(S390Vector *)v1 = rt_result;
} else {
s390_vec_write_element64(v1, 0, MIN(first_match, first_zero));
s390_vec_write_element64(v1, 1, 0);
}
if (first_zero == 16 && first_match == 16) {
return 3; /* no match */
} else if (first_zero == 16) {
return 1; /* matching elements, no match for zero */
} else if (first_match < first_zero) {
return 2; /* matching elements before match for zero */
}
return 0; /* match for zero */
}
#define DEF_VSTRC_HELPER(BITS) \
void HELPER(gvec_vstrc##BITS)(void *v1, const void *v2, const void *v3, \
const void *v4, uint32_t desc) \
{ \
const bool in = extract32(simd_data(desc), 3, 1); \
const bool zs = extract32(simd_data(desc), 1, 1); \
\
vstrc(v1, v2, v3, v4, in, 0, zs, MO_##BITS); \
}
DEF_VSTRC_HELPER(8)
DEF_VSTRC_HELPER(16)
DEF_VSTRC_HELPER(32)
#define DEF_VSTRC_RT_HELPER(BITS) \
void HELPER(gvec_vstrc_rt##BITS)(void *v1, const void *v2, const void *v3, \
const void *v4, uint32_t desc) \
{ \
const bool in = extract32(simd_data(desc), 3, 1); \
const bool zs = extract32(simd_data(desc), 1, 1); \
\
vstrc(v1, v2, v3, v4, in, 1, zs, MO_##BITS); \
}
DEF_VSTRC_RT_HELPER(8)
DEF_VSTRC_RT_HELPER(16)
DEF_VSTRC_RT_HELPER(32)
#define DEF_VSTRC_CC_HELPER(BITS) \
void HELPER(gvec_vstrc_cc##BITS)(void *v1, const void *v2, const void *v3, \
const void *v4, CPUS390XState *env, \
uint32_t desc) \
{ \
const bool in = extract32(simd_data(desc), 3, 1); \
const bool zs = extract32(simd_data(desc), 1, 1); \
\
env->cc_op = vstrc(v1, v2, v3, v4, in, 0, zs, MO_##BITS); \
}
DEF_VSTRC_CC_HELPER(8)
DEF_VSTRC_CC_HELPER(16)
DEF_VSTRC_CC_HELPER(32)
#define DEF_VSTRC_CC_RT_HELPER(BITS) \
void HELPER(gvec_vstrc_cc_rt##BITS)(void *v1, const void *v2, const void *v3, \
const void *v4, CPUS390XState *env, \
uint32_t desc) \
{ \
const bool in = extract32(simd_data(desc), 3, 1); \
const bool zs = extract32(simd_data(desc), 1, 1); \
\
env->cc_op = vstrc(v1, v2, v3, v4, in, 1, zs, MO_##BITS); \
}
DEF_VSTRC_CC_RT_HELPER(8)
DEF_VSTRC_CC_RT_HELPER(16)
DEF_VSTRC_CC_RT_HELPER(32)

83
samples/sample_s390x.c Normal file
View File

@ -0,0 +1,83 @@
/* Unicorn Emulator Engine */
/* By Nguyen Anh Quynh, 2021 */
/* Sample code to demonstrate how to emulate S390X code */
#include <unicorn/unicorn.h>
#include <string.h>
// code to be emulated
#define S390X_CODE "\x18\x23" // lr %r2, %r3
// memory address where emulation starts
#define ADDRESS 0x10000
static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
{
printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size);
}
static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
{
printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size);
}
static void test_s390x(void)
{
uc_engine *uc;
uc_hook trace1, trace2;
uc_err err;
uint64_t r2 = 2, r3 = 3;
printf("Emulate S390X code\n");
// Initialize emulator in S390X mode
err = uc_open(UC_ARCH_S390X, UC_MODE_BIG_ENDIAN, &uc);
if (err) {
printf("Failed on uc_open() with error returned: %u (%s)\n",
err, uc_strerror(err));
return;
}
// map 1MB memory for this emulation
uc_mem_map(uc, ADDRESS, 1024 * 1024, UC_PROT_ALL);
// write machine code to be emulated to memory
uc_mem_write(uc, ADDRESS, S390X_CODE, sizeof(S390X_CODE) - 1);
// initialize machine registers
uc_reg_write(uc, UC_S390X_REG_R2, &r2);
uc_reg_write(uc, UC_S390X_REG_R3, &r3);
// tracing all basic blocks with customized callback
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
// tracing all instruction
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0);
// emulate machine code in infinite time (last param = 0), or when
// finishing all the code.
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(S390X_CODE) - 1, 0, 0);
if (err) {
printf("Failed on uc_emu_start() with error returned: %u\n", err);
}
// now print out some registers
printf(">>> Emulation done. Below is the CPU context\n");
uc_reg_read(uc, UC_S390X_REG_R2, &r2);
uc_reg_read(uc, UC_S390X_REG_R3, &r3);
printf(">>> R2 = 0x%"PRIx64 "\t\t>>> R3 = 0x%"PRIx64 "\n", r2, r3);
uc_close(uc);
}
int main(int argc, char **argv, char **envp)
{
test_s390x();
return 0;
}

8
tests/unit/test_s390x.c Normal file
View File

@ -0,0 +1,8 @@
#include "unicorn_test.h"
const uint64_t code_start = 0x1000;
const uint64_t code_len = 0x4000;
TEST_LIST = {
{ NULL, NULL }
};