Merge systemz to the latest uc2 codebase
This commit is contained in:
commit
faa689c0f0
@ -17,7 +17,7 @@ option(UNICORN_BUILD_SHARED "Build shared instead of static library" ON)
|
||||
|
||||
if (NOT UNICORN_ARCH)
|
||||
# build all architectures
|
||||
set(UNICORN_ARCH "x86 arm aarch64 riscv mips sparc m68k ppc")
|
||||
set(UNICORN_ARCH "x86 arm aarch64 riscv mips sparc m68k ppc s390x")
|
||||
endif()
|
||||
|
||||
string(TOUPPER ${UNICORN_ARCH} UNICORN_ARCH)
|
||||
@ -198,6 +198,9 @@ else()
|
||||
if (UNICORN_HAS_RISCV)
|
||||
set (EXTRA_CFLAGS "${EXTRA_CFLAGS}-DUNICORN_HAS_RISCV ")
|
||||
endif()
|
||||
if (UNICORN_HAS_S390X)
|
||||
set (EXTRA_CFLAGS "${EXTRA_CFLAGS}-DUNICORN_HAS_S390X ")
|
||||
endif()
|
||||
|
||||
set (EXTRA_CFLAGS "${EXTRA_CFLAGS}-fPIC")
|
||||
if(ANDROID_ABI)
|
||||
@ -233,6 +236,9 @@ else()
|
||||
if (UNICORN_HAS_RISCV)
|
||||
set (TARGET_LIST "${TARGET_LIST}riscv32-softmmu, riscv64-softmmu, ")
|
||||
endif()
|
||||
if (UNICORN_HAS_S390X)
|
||||
set (TARGET_LIST "${TARGET_LIST}s390x-softmmu, ")
|
||||
endif()
|
||||
set (TARGET_LIST "${TARGET_LIST} ")
|
||||
|
||||
# GEN config-host.mak & target directories
|
||||
@ -326,6 +332,12 @@ else()
|
||||
OUTPUT_FILE ${CMAKE_BINARY_DIR}/riscv64-softmmu/config-target.h
|
||||
)
|
||||
endif()
|
||||
if (UNICORN_HAS_S390X)
|
||||
execute_process(COMMAND sh ${CMAKE_CURRENT_SOURCE_DIR}/qemu/scripts/create_config
|
||||
INPUT_FILE ${CMAKE_BINARY_DIR}/s390x-softmmu/config-target.mak
|
||||
OUTPUT_FILE ${CMAKE_BINARY_DIR}/s390x-softmmu/config-target.h
|
||||
)
|
||||
endif()
|
||||
add_compile_options(
|
||||
${UNICORN_CFLAGS}
|
||||
-I${CMAKE_CURRENT_SOURCE_DIR}/qemu/tcg/${UNICORN_TARGET_ARCH}
|
||||
@ -951,6 +963,54 @@ else()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (UNICORN_HAS_S390X)
|
||||
add_library(s390x-softmmu
|
||||
${UNICORN_ARCH_COMMON}
|
||||
|
||||
qemu/hw/s390x/s390-skeys.c
|
||||
|
||||
qemu/target/s390x/cc_helper.c
|
||||
qemu/target/s390x/cpu.c
|
||||
qemu/target/s390x/cpu_features.c
|
||||
qemu/target/s390x/cpu_models.c
|
||||
qemu/target/s390x/crypto_helper.c
|
||||
qemu/target/s390x/excp_helper.c
|
||||
qemu/target/s390x/fpu_helper.c
|
||||
qemu/target/s390x/helper.c
|
||||
qemu/target/s390x/interrupt.c
|
||||
qemu/target/s390x/int_helper.c
|
||||
qemu/target/s390x/ioinst.c
|
||||
qemu/target/s390x/mem_helper.c
|
||||
qemu/target/s390x/misc_helper.c
|
||||
qemu/target/s390x/mmu_helper.c
|
||||
qemu/target/s390x/sigp.c
|
||||
qemu/target/s390x/tcg-stub.c
|
||||
qemu/target/s390x/translate.c
|
||||
# qemu/target/s390x/translate_vx.inc.c
|
||||
qemu/target/s390x/vec_fpu_helper.c
|
||||
qemu/target/s390x/vec_helper.c
|
||||
qemu/target/s390x/vec_int_helper.c
|
||||
qemu/target/s390x/vec_string_helper.c
|
||||
qemu/target/s390x/unicorn.c
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
target_compile_options(s390x-softmmu PRIVATE
|
||||
-DNEED_CPU_H
|
||||
/FIs390x.h
|
||||
/I${CMAKE_CURRENT_SOURCE_DIR}/msvc/s390x-softmmu
|
||||
/I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/s390x
|
||||
)
|
||||
else()
|
||||
target_compile_options(s390x-softmmu PRIVATE
|
||||
-DNEED_CPU_H
|
||||
-include s390x.h
|
||||
-I${CMAKE_BINARY_DIR}/s390x-softmmu
|
||||
-I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/s390x
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
set(UNICORN_SRCS
|
||||
uc.c
|
||||
@ -1107,6 +1167,13 @@ if (UNICORN_HAS_RISCV)
|
||||
target_link_libraries(riscv64-softmmu unicorn-common)
|
||||
set(UNICORN_TEST_FILE ${UNICORN_TEST_FILE} test_riscv)
|
||||
endif()
|
||||
if (UNICORN_HAS_S390X)
|
||||
set(UNICORN_COMPILE_OPTIONS ${UNICORN_COMPILE_OPTIONS} -DUNICORN_HAS_S390X)
|
||||
set(UNICORN_LINK_LIBRARIES ${UNICORN_LINK_LIBRARIES} s390x-softmmu)
|
||||
set(UNICORN_SAMPLE_FILE ${UNICORN_SAMPLE_FILE} sample_s390x)
|
||||
target_link_libraries(s390x-softmmu unicorn-common)
|
||||
set(UNICORN_TEST_FILE ${UNICORN_TEST_FILE} test_s390x)
|
||||
endif()
|
||||
|
||||
# Extra tests
|
||||
set(UNICORN_TEST_FILE ${UNICORN_TEST_FILE} test_mem)
|
||||
@ -1167,7 +1234,7 @@ endif()
|
||||
|
||||
|
||||
if(UNICORN_FUZZ)
|
||||
set(UNICORN_FUZZ_SUFFIX "arm_arm;arm_armbe;arm_thumb;arm64_arm;arm64_armbe;m68k_be;mips_32be;mips_32le;sparc_32be;x86_16;x86_32;x86_64")
|
||||
set(UNICORN_FUZZ_SUFFIX "arm_arm;arm_armbe;arm_thumb;arm64_arm;arm64_armbe;m68k_be;mips_32be;mips_32le;sparc_32be;x86_16;x86_32;x86_64;s390x")
|
||||
set(SAMPLES_LIB ${SAMPLES_LIB} rt)
|
||||
foreach(SUFFIX ${UNICORN_FUZZ_SUFFIX})
|
||||
add_executable(fuzz_emu_${SUFFIX}
|
||||
|
@ -13,7 +13,7 @@ Unicorn is a lightweight, multi-platform, multi-architecture CPU emulator framew
|
||||
|
||||
Unicorn offers some unparalleled features:
|
||||
|
||||
- Multi-architecture: ARM, ARM64 (ARMv8), M68K, MIPS, PowerPC, RISCV, SPARC, and X86 (16, 32, 64-bit)
|
||||
- Multi-architecture: ARM, ARM64 (ARMv8), M68K, MIPS, PowerPC, RISCV, SPARC, S390X and X86 (16, 32, 64-bit)
|
||||
- Clean/simple/lightweight/intuitive architecture-neutral API
|
||||
- Implemented in pure C language, with bindings for Crystal, Clojure, Visual Basic, Perl, Rust, Ruby, Python, Java, .NET, Go, Delphi/Free Pascal, Haskell, Pharo, and Lua.
|
||||
- Native support for Windows & *nix (with Mac OSX, Linux, Android, *BSD & Solaris confirmed)
|
||||
|
13
TODO-s390
Normal file
13
TODO-s390
Normal file
@ -0,0 +1,13 @@
|
||||
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
|
||||
- support more registers in qemu/target/s390x/unicorn.c
|
||||
- storage-keys needed?
|
||||
- find & fix potential memory leaking with valgrind
|
||||
- sync with "dev" branch of github unicorn
|
@ -31,6 +31,7 @@
|
||||
#define UC_MODE_M68K_MASK (UC_MODE_BIG_ENDIAN)
|
||||
#define UC_MODE_RISCV_MASK \
|
||||
(UC_MODE_RISCV32 | UC_MODE_RISCV64 | UC_MODE_LITTLE_ENDIAN)
|
||||
#define UC_MODE_S390X_MASK (UC_MODE_BIG_ENDIAN)
|
||||
|
||||
#define ARR_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
||||
|
||||
|
99
include/unicorn/s390x.h
Normal file
99
include/unicorn/s390x.h
Normal 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
|
@ -34,6 +34,7 @@ typedef size_t uc_hook;
|
||||
#include "sparc.h"
|
||||
#include "ppc.h"
|
||||
#include "riscv.h"
|
||||
#include "s390x.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define DEFAULT_VISIBILITY __attribute__((visibility("default")))
|
||||
@ -101,6 +102,7 @@ typedef enum uc_arch {
|
||||
UC_ARCH_SPARC, // Sparc architecture
|
||||
UC_ARCH_M68K, // M68K architecture
|
||||
UC_ARCH_RISCV, // RISCV architecture
|
||||
UC_ARCH_S390X, // S390X architecture
|
||||
UC_ARCH_MAX,
|
||||
} uc_arch;
|
||||
|
||||
|
8
msvc/s390x-softmmu/config-target.h
Normal file
8
msvc/s390x-softmmu/config-target.h
Normal 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
|
2
qemu/configure
vendored
2
qemu/configure
vendored
@ -852,7 +852,7 @@ QEMU_CFLAGS="$CPU_CFLAGS $QEMU_CFLAGS"
|
||||
default_target_list="aarch64eb-softmmu aarch64-softmmu armeb-softmmu \
|
||||
arm-softmmu m68k-softmmu mips64el-softmmu mips64-softmmu mipsel-softmmu \
|
||||
mips-softmmu ppc64-softmmu ppc-softmmu sparc64-softmmu sparc-softmmu \
|
||||
x86_64-softmmu riscv32-softmmu riscv64-softmmu"
|
||||
x86_64-softmmu riscv32-softmmu riscv64-softmmu s390x-softmmu"
|
||||
|
||||
if test x"$show_help" = x"yes" ; then
|
||||
cat << EOF
|
||||
|
282
qemu/hw/s390x/s390-skeys.c
Normal file
282
qemu/hw/s390x/s390-skeys.c
Normal 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
|
104
qemu/include/hw/s390x/ebcdic.h
Normal file
104
qemu/include/hw/s390x/ebcdic.h
Normal 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 */
|
248
qemu/include/hw/s390x/ioinst.h
Normal file
248
qemu/include/hw/s390x/ioinst.h
Normal 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
|
221
qemu/include/hw/s390x/sclp.h
Normal file
221
qemu/include/hw/s390x/sclp.h
Normal 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
|
66
qemu/include/hw/s390x/storage-keys.h
Normal file
66
qemu/include/hw/s390x/storage-keys.h
Normal 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 */
|
@ -78,4 +78,6 @@ void os_setup_early_signal_handling(void);
|
||||
|
||||
void page_size_init(struct uc_struct *uc);
|
||||
|
||||
CPUState *qemu_get_cpu(struct uc_struct *uc, int index);
|
||||
|
||||
#endif
|
||||
|
@ -794,6 +794,19 @@ struct TCGContext {
|
||||
|
||||
// Used to store the start of current instrution.
|
||||
uint64_t pc_start;
|
||||
|
||||
// target/s390x/translate.c
|
||||
TCGv_i64 psw_addr;
|
||||
TCGv_i64 psw_mask;
|
||||
TCGv_i64 gbea;
|
||||
|
||||
TCGv_i32 cc_op;
|
||||
TCGv_i64 cc_src;
|
||||
TCGv_i64 cc_dst;
|
||||
TCGv_i64 cc_vr;
|
||||
|
||||
char s390x_cpu_reg_names[16][4]; // renamed from original cpu_reg_names[][] to avoid name clash with m68k
|
||||
TCGv_i64 regs[16];
|
||||
};
|
||||
|
||||
static inline size_t temp_idx(TCGContext *tcg_ctx, TCGTemp *ts)
|
||||
|
1277
qemu/s390x.h
Normal file
1277
qemu/s390x.h
Normal file
File diff suppressed because it is too large
Load Diff
595
qemu/target/s390x/cc_helper.c
Normal file
595
qemu/target/s390x/cc_helper.c
Normal 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
|
17
qemu/target/s390x/cpu-param.h
Normal file
17
qemu/target/s390x/cpu-param.h
Normal 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
|
64
qemu/target/s390x/cpu-qom.h
Normal file
64
qemu/target/s390x/cpu-qom.h
Normal 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
301
qemu/target/s390x/cpu.c
Normal 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
840
qemu/target/s390x/cpu.h
Normal 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
|
210
qemu/target/s390x/cpu_features.c
Normal file
210
qemu/target/s390x/cpu_features.c
Normal 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);
|
||||
}
|
||||
}
|
91
qemu/target/s390x/cpu_features.h
Normal file
91
qemu/target/s390x/cpu_features.h
Normal 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 */
|
25
qemu/target/s390x/cpu_features_def.h
Normal file
25
qemu/target/s390x/cpu_features_def.h
Normal 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 */
|
370
qemu/target/s390x/cpu_features_def.inc.h
Normal file
370
qemu/target/s390x/cpu_features_def.inc.h
Normal 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")
|
579
qemu/target/s390x/cpu_models.c
Normal file
579
qemu/target/s390x/cpu_models.c
Normal 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
|
||||
}
|
109
qemu/target/s390x/cpu_models.h
Normal file
109
qemu/target/s390x/cpu_models.h
Normal 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 */
|
60
qemu/target/s390x/crypto_helper.c
Normal file
60
qemu/target/s390x/crypto_helper.c
Normal 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;
|
||||
}
|
600
qemu/target/s390x/excp_helper.c
Normal file
600
qemu/target/s390x/excp_helper.c
Normal 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);
|
||||
}
|
888
qemu/target/s390x/fpu_helper.c
Normal file
888
qemu/target/s390x/fpu_helper.c
Normal 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);
|
||||
}
|
986
qemu/target/s390x/gen-features.c
Normal file
986
qemu/target/s390x/gen-features.c
Normal 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;
|
||||
}
|
135
qemu/target/s390x/gen-features.h
Normal file
135
qemu/target/s390x/gen-features.h
Normal 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
358
qemu/target/s390x/helper.c
Normal 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
358
qemu/target/s390x/helper.h
Normal 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
|
1371
qemu/target/s390x/insn-data.def
Normal file
1371
qemu/target/s390x/insn-data.def
Normal file
File diff suppressed because it is too large
Load Diff
81
qemu/target/s390x/insn-format.def
Normal file
81
qemu/target/s390x/insn-format.def
Normal 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))
|
148
qemu/target/s390x/int_helper.c
Normal file
148
qemu/target/s390x/int_helper.c
Normal 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;
|
||||
}
|
366
qemu/target/s390x/internal.h
Normal file
366
qemu/target/s390x/internal.h
Normal 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 */
|
233
qemu/target/s390x/interrupt.c
Normal file
233
qemu/target/s390x/interrupt.c
Normal 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
788
qemu/target/s390x/ioinst.c
Normal 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);
|
||||
}
|
||||
}
|
2892
qemu/target/s390x/mem_helper.c
Normal file
2892
qemu/target/s390x/mem_helper.c
Normal file
File diff suppressed because it is too large
Load Diff
815
qemu/target/s390x/misc_helper.c
Normal file
815
qemu/target/s390x/misc_helper.c
Normal 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
|
||||
}
|
554
qemu/target/s390x/mmu_helper.c
Normal file
554
qemu/target/s390x/mmu_helper.c
Normal 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;
|
||||
}
|
29
qemu/target/s390x/s390-tod.h
Normal file
29
qemu/target/s390x/s390-tod.h
Normal 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
466
qemu/target/s390x/sigp.c
Normal 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)
|
||||
{
|
||||
}
|
30
qemu/target/s390x/tcg-stub.c
Normal file
30
qemu/target/s390x/tcg-stub.c
Normal 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();
|
||||
}
|
24
qemu/target/s390x/tcg_s390x.h
Normal file
24
qemu/target/s390x/tcg_s390x.h
Normal 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 */
|
6932
qemu/target/s390x/translate.c
Normal file
6932
qemu/target/s390x/translate.c
Normal file
File diff suppressed because it is too large
Load Diff
2882
qemu/target/s390x/translate_vx.inc.c
Normal file
2882
qemu/target/s390x/translate_vx.inc.c
Normal file
File diff suppressed because it is too large
Load Diff
179
qemu/target/s390x/unicorn.c
Normal file
179
qemu/target/s390x/unicorn.c
Normal file
@ -0,0 +1,179 @@
|
||||
/* 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);
|
||||
}
|
19
qemu/target/s390x/unicorn.h
Normal file
19
qemu/target/s390x/unicorn.h
Normal file
@ -0,0 +1,19 @@
|
||||
/* 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
141
qemu/target/s390x/vec.h
Normal 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 */
|
625
qemu/target/s390x/vec_fpu_helper.c
Normal file
625
qemu/target/s390x/vec_fpu_helper.c
Normal 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));
|
||||
}
|
192
qemu/target/s390x/vec_helper.c
Normal file
192
qemu/target/s390x/vec_helper.c
Normal 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;
|
||||
}
|
||||
}
|
618
qemu/target/s390x/vec_int_helper.c
Normal file
618
qemu/target/s390x/vec_int_helper.c
Normal 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;
|
||||
}
|
||||
}
|
473
qemu/target/s390x/vec_string_helper.c
Normal file
473
qemu/target/s390x/vec_string_helper.c
Normal 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)
|
87
samples/sample_s390x.c
Normal file
87
samples/sample_s390x.c
Normal file
@ -0,0 +1,87 @@
|
||||
/* 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;
|
||||
}
|
@ -6271,7 +6271,7 @@ ppc_irq_reset \
|
||||
|
||||
ppc64_SYMBOLS=${ppc_SYMBOLS}
|
||||
|
||||
ARCHS="x86_64 arm armeb aarch64 aarch64eb riscv32 riscv64 mips mipsel mips64 mips64el sparc sparc64 m68k ppc ppc64"
|
||||
ARCHS="x86_64 arm armeb aarch64 aarch64eb riscv32 riscv64 mips mipsel mips64 mips64el sparc sparc64 m68k ppc ppc64 s390x"
|
||||
|
||||
for arch in $ARCHS; do
|
||||
|
||||
|
6
tests/unit/test_s390x.c
Normal file
6
tests/unit/test_s390x.c
Normal file
@ -0,0 +1,6 @@
|
||||
#include "unicorn_test.h"
|
||||
|
||||
const uint64_t code_start = 0x1000;
|
||||
const uint64_t code_len = 0x4000;
|
||||
|
||||
TEST_LIST = {{NULL, NULL}};
|
25
uc.c
25
uc.c
@ -23,6 +23,7 @@
|
||||
#include "qemu/target/sparc/unicorn.h"
|
||||
#include "qemu/target/ppc/unicorn.h"
|
||||
#include "qemu/target/riscv/unicorn.h"
|
||||
#include "qemu/target/s390x/unicorn.h"
|
||||
|
||||
#include "qemu/include/qemu/queue.h"
|
||||
#include "qemu-common.h"
|
||||
@ -131,6 +132,10 @@ bool uc_arch_supported(uc_arch arch)
|
||||
#ifdef UNICORN_HAS_RISCV
|
||||
case UC_ARCH_RISCV:
|
||||
return true;
|
||||
#endif
|
||||
#ifdef UNICORN_HAS_S390X
|
||||
case UC_ARCH_S390X:
|
||||
return true;
|
||||
#endif
|
||||
/* Invalid or disabled arch */
|
||||
default:
|
||||
@ -341,6 +346,15 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result)
|
||||
return UC_ERR_MODE;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef UNICORN_HAS_S390X
|
||||
case UC_ARCH_S390X:
|
||||
if ((mode & ~UC_MODE_S390X_MASK) || !(mode & UC_MODE_BIG_ENDIAN)) {
|
||||
free(uc);
|
||||
return UC_ERR_MODE;
|
||||
}
|
||||
uc->init_arch = s390_uc_init;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -763,6 +777,11 @@ uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until,
|
||||
case UC_ARCH_RISCV:
|
||||
uc_reg_write(uc, UC_RISCV_REG_PC, &begin);
|
||||
break;
|
||||
#endif
|
||||
#ifdef UNICORN_HAS_S390X
|
||||
case UC_ARCH_S390X:
|
||||
uc_reg_write(uc, UC_S390X_REG_PC, &begin);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -1922,6 +1941,12 @@ static void find_context_reg_rw_function(uc_arch arch, uc_mode mode,
|
||||
rw->context_reg_write = riscv64_context_reg_write;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef UNICORN_HAS_S390X
|
||||
case UC_ARCH_S390X:
|
||||
rw->context_reg_read = s390_context_reg_read;
|
||||
rw->context_reg_write = s390_context_reg_write;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user