aboutsummaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
Diffstat (limited to 'target')
-rw-r--r--target/alpha/fpu_helper.c15
-rw-r--r--target/alpha/helper.c64
-rw-r--r--target/arm/arm-semi.c705
-rw-r--r--target/arm/cpu.c10
-rw-r--r--target/arm/helper.c115
-rw-r--r--target/arm/kvm.c22
-rw-r--r--target/arm/kvm_arm.h1
-rw-r--r--target/arm/m_helper.c18
-rw-r--r--target/arm/translate.c34
-rw-r--r--target/hppa/translate.c15
-rw-r--r--target/i386/cpu.c475
-rw-r--r--target/i386/cpu.h311
-rw-r--r--target/i386/helper.c5
-rw-r--r--target/i386/hvf/x86_cpuid.c2
-rw-r--r--target/i386/kvm.c203
-rw-r--r--target/i386/whpx-all.c1
-rw-r--r--target/m68k/fpu_helper.c8
-rw-r--r--target/mips/cpu.c2
-rw-r--r--target/mips/gdbstub.c3
-rw-r--r--target/mips/helper.h144
-rw-r--r--target/mips/internal.h68
-rw-r--r--target/mips/kvm_mips.h2
-rw-r--r--target/mips/mips-defs.h58
-rw-r--r--target/mips/msa_helper.c1957
-rw-r--r--target/mips/op_helper.c24
-rw-r--r--target/mips/translate.c421
-rw-r--r--target/ppc/cpu.h10
-rw-r--r--target/ppc/dfp_helper.c394
-rw-r--r--target/ppc/fpu_helper.c122
-rw-r--r--target/ppc/helper.h2
-rw-r--r--target/ppc/int_helper.c72
-rw-r--r--target/ppc/internal.h3
-rw-r--r--target/ppc/kvm.c5
-rw-r--r--target/ppc/translate/fp-impl.inc.c99
-rw-r--r--target/ppc/translate/fp-ops.inc.c6
-rw-r--r--target/ppc/translate_init.inc.c9
-rw-r--r--target/riscv/Makefile.objs7
-rw-r--r--target/riscv/cpu.c19
-rw-r--r--target/riscv/cpu.h6
-rw-r--r--target/riscv/cpu_bits.h35
-rw-r--r--target/riscv/cpu_helper.c20
-rw-r--r--target/riscv/csr.c22
-rw-r--r--target/riscv/gdbstub.c6
-rw-r--r--target/riscv/monitor.c229
-rw-r--r--target/riscv/pmp.c35
-rw-r--r--target/riscv/trace-events6
-rw-r--r--target/s390x/cc_helper.c4
-rw-r--r--target/s390x/cpu.h90
-rw-r--r--target/s390x/cpu_models.c3
-rw-r--r--target/s390x/crypto_helper.c7
-rw-r--r--target/s390x/diag.c14
-rw-r--r--target/s390x/excp_helper.c58
-rw-r--r--target/s390x/fpu_helper.c6
-rw-r--r--target/s390x/gen-features.c11
-rw-r--r--target/s390x/helper.c7
-rw-r--r--target/s390x/helper.h2
-rw-r--r--target/s390x/insn-data.def2
-rw-r--r--target/s390x/int_helper.c15
-rw-r--r--target/s390x/internal.h6
-rw-r--r--target/s390x/interrupt.c9
-rw-r--r--target/s390x/ioinst.c40
-rw-r--r--target/s390x/kvm.c27
-rw-r--r--target/s390x/mem_helper.c823
-rw-r--r--target/s390x/misc_helper.c27
-rw-r--r--target/s390x/mmu_helper.c427
-rw-r--r--target/s390x/tcg-stub.c4
-rw-r--r--target/s390x/tcg_s390x.h4
-rw-r--r--target/s390x/translate.c32
-rw-r--r--target/s390x/translate_vx.inc.c30
-rw-r--r--target/s390x/vec_int_helper.c18
-rw-r--r--target/sparc/cpu.c2
-rw-r--r--target/sparc/cpu.h8
-rw-r--r--target/sparc/ldst_helper.c317
-rw-r--r--target/sparc/mmu_helper.c57
74 files changed, 5696 insertions, 2144 deletions
diff --git a/target/alpha/fpu_helper.c b/target/alpha/fpu_helper.c
index 62a066d..df8b589 100644
--- a/target/alpha/fpu_helper.c
+++ b/target/alpha/fpu_helper.c
@@ -90,25 +90,18 @@ void helper_fp_exc_raise_s(CPUAlphaState *env, uint32_t ignore, uint32_t regno)
uint32_t exc = env->error_code & ~ignore;
if (exc) {
env->fpcr |= exc;
- exc &= ~ignore;
-#ifdef CONFIG_USER_ONLY
- /*
- * In user mode, the kernel's software handler only
- * delivers a signal if the exception is enabled.
- */
- if (!(exc & env->fpcr_exc_enable)) {
- return;
- }
-#else
+ exc &= env->fpcr_exc_enable;
/*
* In system mode, the software handler gets invoked
* for any non-ignored exception.
+ * In user mode, the kernel's software handler only
+ * delivers a signal if the exception is enabled.
*/
+#ifdef CONFIG_USER_ONLY
if (!exc) {
return;
}
#endif
- exc &= env->fpcr_exc_enable;
fp_exc_raise1(env, GETPC(), exc, regno, EXC_M_SWC);
}
}
diff --git a/target/alpha/helper.c b/target/alpha/helper.c
index 19cda0a..55d7274 100644
--- a/target/alpha/helper.c
+++ b/target/alpha/helper.c
@@ -36,53 +36,53 @@ uint64_t cpu_alpha_load_fpcr(CPUAlphaState *env)
void cpu_alpha_store_fpcr(CPUAlphaState *env, uint64_t val)
{
+ static const uint8_t rm_map[] = {
+ [FPCR_DYN_NORMAL >> FPCR_DYN_SHIFT] = float_round_nearest_even,
+ [FPCR_DYN_CHOPPED >> FPCR_DYN_SHIFT] = float_round_to_zero,
+ [FPCR_DYN_MINUS >> FPCR_DYN_SHIFT] = float_round_down,
+ [FPCR_DYN_PLUS >> FPCR_DYN_SHIFT] = float_round_up,
+ };
+
uint32_t fpcr = val >> 32;
uint32_t t = 0;
+ /* Record the raw value before adjusting for linux-user. */
+ env->fpcr = fpcr;
+
+#ifdef CONFIG_USER_ONLY
+ /*
+ * Override some of these bits with the contents of ENV->SWCR.
+ * In system mode, some of these would trap to the kernel, at
+ * which point the kernel's handler would emulate and apply
+ * the software exception mask.
+ */
+ uint32_t soft_fpcr = alpha_ieee_swcr_to_fpcr(env->swcr) >> 32;
+ fpcr |= soft_fpcr & (FPCR_STATUS_MASK | FPCR_DNZ);
+
+ /*
+ * The IOV exception is disabled by the kernel with SWCR_TRAP_ENABLE_INV,
+ * which got mapped by alpha_ieee_swcr_to_fpcr to FPCR_INVD.
+ * Add FPCR_IOV to fpcr_exc_enable so that it is handled identically.
+ */
+ t |= CONVERT_BIT(soft_fpcr, FPCR_INVD, FPCR_IOV);
+#endif
+
t |= CONVERT_BIT(fpcr, FPCR_INED, FPCR_INE);
t |= CONVERT_BIT(fpcr, FPCR_UNFD, FPCR_UNF);
t |= CONVERT_BIT(fpcr, FPCR_OVFD, FPCR_OVF);
t |= CONVERT_BIT(fpcr, FPCR_DZED, FPCR_DZE);
t |= CONVERT_BIT(fpcr, FPCR_INVD, FPCR_INV);
- env->fpcr = fpcr;
env->fpcr_exc_enable = ~t & FPCR_STATUS_MASK;
- switch (fpcr & FPCR_DYN_MASK) {
- case FPCR_DYN_NORMAL:
- default:
- t = float_round_nearest_even;
- break;
- case FPCR_DYN_CHOPPED:
- t = float_round_to_zero;
- break;
- case FPCR_DYN_MINUS:
- t = float_round_down;
- break;
- case FPCR_DYN_PLUS:
- t = float_round_up;
- break;
- }
- env->fpcr_dyn_round = t;
-
- env->fpcr_flush_to_zero = (fpcr & FPCR_UNFD) && (fpcr & FPCR_UNDZ);
+ env->fpcr_dyn_round = rm_map[(fpcr & FPCR_DYN_MASK) >> FPCR_DYN_SHIFT];
env->fp_status.flush_inputs_to_zero = (fpcr & FPCR_DNZ) != 0;
+ t = (fpcr & FPCR_UNFD) && (fpcr & FPCR_UNDZ);
#ifdef CONFIG_USER_ONLY
- /*
- * Override some of these bits with the contents of ENV->SWCR.
- * In system mode, some of these would trap to the kernel, at
- * which point the kernel's handler would emulate and apply
- * the software exception mask.
- */
- if (env->swcr & SWCR_MAP_DMZ) {
- env->fp_status.flush_inputs_to_zero = 1;
- }
- if (env->swcr & SWCR_MAP_UMZ) {
- env->fp_status.flush_to_zero = 1;
- }
- env->fpcr_exc_enable &= ~(alpha_ieee_swcr_to_fpcr(env->swcr) >> 32);
+ t |= (env->swcr & SWCR_MAP_UMZ) != 0;
#endif
+ env->fpcr_flush_to_zero = t;
}
uint64_t helper_load_fpcr(CPUAlphaState *env)
diff --git a/target/arm/arm-semi.c b/target/arm/arm-semi.c
index 90423a3..6f7b6d8 100644
--- a/target/arm/arm-semi.c
+++ b/target/arm/arm-semi.c
@@ -59,6 +59,7 @@
#define TARGET_SYS_HEAPINFO 0x16
#define TARGET_SYS_EXIT 0x18
#define TARGET_SYS_SYNCCACHE 0x19
+#define TARGET_SYS_EXIT_EXTENDED 0x20
/* ADP_Stopped_ApplicationExit is used for exit(0),
* anything else is implemented as exit(1) */
@@ -106,43 +107,169 @@ static int open_modeflags[12] = {
O_RDWR | O_CREAT | O_APPEND | O_BINARY
};
-#ifdef CONFIG_USER_ONLY
-static inline uint32_t set_swi_errno(TaskState *ts, uint32_t code)
+typedef enum GuestFDType {
+ GuestFDUnused = 0,
+ GuestFDHost = 1,
+ GuestFDGDB = 2,
+ GuestFDFeatureFile = 3,
+} GuestFDType;
+
+/*
+ * Guest file descriptors are integer indexes into an array of
+ * these structures (we will dynamically resize as necessary).
+ */
+typedef struct GuestFD {
+ GuestFDType type;
+ union {
+ int hostfd;
+ target_ulong featurefile_offset;
+ };
+} GuestFD;
+
+static GArray *guestfd_array;
+
+/*
+ * Allocate a new guest file descriptor and return it; if we
+ * couldn't allocate a new fd then return -1.
+ * This is a fairly simplistic implementation because we don't
+ * expect that most semihosting guest programs will make very
+ * heavy use of opening and closing fds.
+ */
+static int alloc_guestfd(void)
{
- if (code == (uint32_t)-1)
- ts->swi_errno = errno;
- return code;
+ guint i;
+
+ if (!guestfd_array) {
+ /* New entries zero-initialized, i.e. type GuestFDUnused */
+ guestfd_array = g_array_new(FALSE, TRUE, sizeof(GuestFD));
+ }
+
+ for (i = 0; i < guestfd_array->len; i++) {
+ GuestFD *gf = &g_array_index(guestfd_array, GuestFD, i);
+
+ if (gf->type == GuestFDUnused) {
+ return i;
+ }
+ }
+
+ /* All elements already in use: expand the array */
+ g_array_set_size(guestfd_array, i + 1);
+ return i;
}
-#else
-static inline uint32_t set_swi_errno(CPUARMState *env, uint32_t code)
+
+/*
+ * Look up the guestfd in the data structure; return NULL
+ * for out of bounds, but don't check whether the slot is unused.
+ * This is used internally by the other guestfd functions.
+ */
+static GuestFD *do_get_guestfd(int guestfd)
{
- return code;
+ if (!guestfd_array) {
+ return NULL;
+ }
+
+ if (guestfd < 0 || guestfd >= guestfd_array->len) {
+ return NULL;
+ }
+
+ return &g_array_index(guestfd_array, GuestFD, guestfd);
+}
+
+/*
+ * Associate the specified guest fd (which must have been
+ * allocated via alloc_fd() and not previously used) with
+ * the specified host/gdb fd.
+ */
+static void associate_guestfd(int guestfd, int hostfd)
+{
+ GuestFD *gf = do_get_guestfd(guestfd);
+
+ assert(gf);
+ gf->type = use_gdb_syscalls() ? GuestFDGDB : GuestFDHost;
+ gf->hostfd = hostfd;
+}
+
+/*
+ * Deallocate the specified guest file descriptor. This doesn't
+ * close the host fd, it merely undoes the work of alloc_fd().
+ */
+static void dealloc_guestfd(int guestfd)
+{
+ GuestFD *gf = do_get_guestfd(guestfd);
+
+ assert(gf);
+ gf->type = GuestFDUnused;
+}
+
+/*
+ * Given a guest file descriptor, get the associated struct.
+ * If the fd is not valid, return NULL. This is the function
+ * used by the various semihosting calls to validate a handle
+ * from the guest.
+ * Note: calling alloc_guestfd() or dealloc_guestfd() will
+ * invalidate any GuestFD* obtained by calling this function.
+ */
+static GuestFD *get_guestfd(int guestfd)
+{
+ GuestFD *gf = do_get_guestfd(guestfd);
+
+ if (!gf || gf->type == GuestFDUnused) {
+ return NULL;
+ }
+ return gf;
}
+/*
+ * The semihosting API has no concept of its errno being thread-safe,
+ * as the API design predates SMP CPUs and was intended as a simple
+ * real-hardware set of debug functionality. For QEMU, we make the
+ * errno be per-thread in linux-user mode; in softmmu it is a simple
+ * global, and we assume that the guest takes care of avoiding any races.
+ */
+#ifndef CONFIG_USER_ONLY
+static target_ulong syscall_err;
+
#include "exec/softmmu-semi.h"
#endif
-static target_ulong arm_semi_syscall_len;
+static inline uint32_t set_swi_errno(CPUARMState *env, uint32_t code)
+{
+ if (code == (uint32_t)-1) {
+#ifdef CONFIG_USER_ONLY
+ CPUState *cs = env_cpu(env);
+ TaskState *ts = cs->opaque;
-#if !defined(CONFIG_USER_ONLY)
-static target_ulong syscall_err;
+ ts->swi_errno = errno;
+#else
+ syscall_err = errno;
#endif
+ }
+ return code;
+}
-static void arm_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
+static inline uint32_t get_swi_errno(CPUARMState *env)
{
- ARMCPU *cpu = ARM_CPU(cs);
- CPUARMState *env = &cpu->env;
#ifdef CONFIG_USER_ONLY
+ CPUState *cs = env_cpu(env);
TaskState *ts = cs->opaque;
+
+ return ts->swi_errno;
+#else
+ return syscall_err;
#endif
+}
+
+static target_ulong arm_semi_syscall_len;
+
+static void arm_semi_cb(CPUState *cs, target_ulong ret, target_ulong err)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
target_ulong reg0 = is_a64(env) ? env->xregs[0] : env->regs[0];
if (ret == (target_ulong)-1) {
-#ifdef CONFIG_USER_ONLY
- ts->swi_errno = err;
-#else
- syscall_err = err;
-#endif
+ errno = err;
+ set_swi_errno(env, -1);
reg0 = ret;
} else {
/* Fixup syscalls that use nonstardard return conventions. */
@@ -199,11 +326,30 @@ static void arm_semi_flen_cb(CPUState *cs, target_ulong ret, target_ulong err)
} else {
env->regs[0] = size;
}
-#ifdef CONFIG_USER_ONLY
- ((TaskState *)cs->opaque)->swi_errno = err;
-#else
- syscall_err = err;
-#endif
+ errno = err;
+ set_swi_errno(env, -1);
+}
+
+static int arm_semi_open_guestfd;
+
+static void arm_semi_open_cb(CPUState *cs, target_ulong ret, target_ulong err)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ if (ret == (target_ulong)-1) {
+ errno = err;
+ set_swi_errno(env, -1);
+ dealloc_guestfd(arm_semi_open_guestfd);
+ } else {
+ associate_guestfd(arm_semi_open_guestfd, ret);
+ ret = arm_semi_open_guestfd;
+ }
+
+ if (is_a64(env)) {
+ env->xregs[0] = ret;
+ } else {
+ env->regs[0] = ret;
+ }
}
static target_ulong arm_gdb_syscall(ARMCPU *cpu, gdb_syscall_complete_cb cb,
@@ -216,26 +362,289 @@ static target_ulong arm_gdb_syscall(ARMCPU *cpu, gdb_syscall_complete_cb cb,
gdb_do_syscallv(cb, fmt, va);
va_end(va);
- /* FIXME: we are implicitly relying on the syscall completing
- * before this point, which is not guaranteed. We should
- * put in an explicit synchronization between this and
- * the callback function.
+ /*
+ * FIXME: in softmmu mode, the gdbstub will schedule our callback
+ * to occur, but will not actually call it to complete the syscall
+ * until after this function has returned and we are back in the
+ * CPU main loop. Therefore callers to this function must not
+ * do anything with its return value, because it is not necessarily
+ * the result of the syscall, but could just be the old value of X0.
+ * The only thing safe to do with this is that the callers of
+ * do_arm_semihosting() will write it straight back into X0.
+ * (In linux-user mode, the callback will have happened before
+ * gdb_do_syscallv() returns.)
+ *
+ * We should tidy this up so neither this function nor
+ * do_arm_semihosting() return a value, so the mistake of
+ * doing something with the return value is not possible to make.
*/
return is_a64(env) ? env->xregs[0] : env->regs[0];
}
+/*
+ * Types for functions implementing various semihosting calls
+ * for specific types of guest file descriptor. These must all
+ * do the work and return the required return value for the guest,
+ * setting the guest errno if appropriate.
+ */
+typedef uint32_t sys_closefn(ARMCPU *cpu, GuestFD *gf);
+typedef uint32_t sys_writefn(ARMCPU *cpu, GuestFD *gf,
+ target_ulong buf, uint32_t len);
+typedef uint32_t sys_readfn(ARMCPU *cpu, GuestFD *gf,
+ target_ulong buf, uint32_t len);
+typedef uint32_t sys_isattyfn(ARMCPU *cpu, GuestFD *gf);
+typedef uint32_t sys_seekfn(ARMCPU *cpu, GuestFD *gf,
+ target_ulong offset);
+typedef uint32_t sys_flenfn(ARMCPU *cpu, GuestFD *gf);
+
+static uint32_t host_closefn(ARMCPU *cpu, GuestFD *gf)
+{
+ CPUARMState *env = &cpu->env;
+
+ return set_swi_errno(env, close(gf->hostfd));
+}
+
+static uint32_t host_writefn(ARMCPU *cpu, GuestFD *gf,
+ target_ulong buf, uint32_t len)
+{
+ uint32_t ret;
+ CPUARMState *env = &cpu->env;
+ char *s = lock_user(VERIFY_READ, buf, len, 1);
+ if (!s) {
+ /* Return bytes not written on error */
+ return len;
+ }
+ ret = set_swi_errno(env, write(gf->hostfd, s, len));
+ unlock_user(s, buf, 0);
+ if (ret == (uint32_t)-1) {
+ ret = 0;
+ }
+ /* Return bytes not written */
+ return len - ret;
+}
+
+static uint32_t host_readfn(ARMCPU *cpu, GuestFD *gf,
+ target_ulong buf, uint32_t len)
+{
+ uint32_t ret;
+ CPUARMState *env = &cpu->env;
+ char *s = lock_user(VERIFY_WRITE, buf, len, 0);
+ if (!s) {
+ /* return bytes not read */
+ return len;
+ }
+ do {
+ ret = set_swi_errno(env, read(gf->hostfd, s, len));
+ } while (ret == -1 && errno == EINTR);
+ unlock_user(s, buf, len);
+ if (ret == (uint32_t)-1) {
+ ret = 0;
+ }
+ /* Return bytes not read */
+ return len - ret;
+}
+
+static uint32_t host_isattyfn(ARMCPU *cpu, GuestFD *gf)
+{
+ return isatty(gf->hostfd);
+}
+
+static uint32_t host_seekfn(ARMCPU *cpu, GuestFD *gf, target_ulong offset)
+{
+ CPUARMState *env = &cpu->env;
+ uint32_t ret = set_swi_errno(env, lseek(gf->hostfd, offset, SEEK_SET));
+ if (ret == (uint32_t)-1) {
+ return -1;
+ }
+ return 0;
+}
+
+static uint32_t host_flenfn(ARMCPU *cpu, GuestFD *gf)
+{
+ CPUARMState *env = &cpu->env;
+ struct stat buf;
+ uint32_t ret = set_swi_errno(env, fstat(gf->hostfd, &buf));
+ if (ret == (uint32_t)-1) {
+ return -1;
+ }
+ return buf.st_size;
+}
+
+static uint32_t gdb_closefn(ARMCPU *cpu, GuestFD *gf)
+{
+ return arm_gdb_syscall(cpu, arm_semi_cb, "close,%x", gf->hostfd);
+}
+
+static uint32_t gdb_writefn(ARMCPU *cpu, GuestFD *gf,
+ target_ulong buf, uint32_t len)
+{
+ arm_semi_syscall_len = len;
+ return arm_gdb_syscall(cpu, arm_semi_cb, "write,%x,%x,%x",
+ gf->hostfd, buf, len);
+}
+
+static uint32_t gdb_readfn(ARMCPU *cpu, GuestFD *gf,
+ target_ulong buf, uint32_t len)
+{
+ arm_semi_syscall_len = len;
+ return arm_gdb_syscall(cpu, arm_semi_cb, "read,%x,%x,%x",
+ gf->hostfd, buf, len);
+}
+
+static uint32_t gdb_isattyfn(ARMCPU *cpu, GuestFD *gf)
+{
+ return arm_gdb_syscall(cpu, arm_semi_cb, "isatty,%x", gf->hostfd);
+}
+
+static uint32_t gdb_seekfn(ARMCPU *cpu, GuestFD *gf, target_ulong offset)
+{
+ return arm_gdb_syscall(cpu, arm_semi_cb, "lseek,%x,%x,0",
+ gf->hostfd, offset);
+}
+
+static uint32_t gdb_flenfn(ARMCPU *cpu, GuestFD *gf)
+{
+ return arm_gdb_syscall(cpu, arm_semi_flen_cb, "fstat,%x,%x",
+ gf->hostfd, arm_flen_buf(cpu));
+}
+
+#define SHFB_MAGIC_0 0x53
+#define SHFB_MAGIC_1 0x48
+#define SHFB_MAGIC_2 0x46
+#define SHFB_MAGIC_3 0x42
+
+/* Feature bits reportable in feature byte 0 */
+#define SH_EXT_EXIT_EXTENDED (1 << 0)
+#define SH_EXT_STDOUT_STDERR (1 << 1)
+
+static const uint8_t featurefile_data[] = {
+ SHFB_MAGIC_0,
+ SHFB_MAGIC_1,
+ SHFB_MAGIC_2,
+ SHFB_MAGIC_3,
+ SH_EXT_EXIT_EXTENDED | SH_EXT_STDOUT_STDERR, /* Feature byte 0 */
+};
+
+static void init_featurefile_guestfd(int guestfd)
+{
+ GuestFD *gf = do_get_guestfd(guestfd);
+
+ assert(gf);
+ gf->type = GuestFDFeatureFile;
+ gf->featurefile_offset = 0;
+}
+
+static uint32_t featurefile_closefn(ARMCPU *cpu, GuestFD *gf)
+{
+ /* Nothing to do */
+ return 0;
+}
+
+static uint32_t featurefile_writefn(ARMCPU *cpu, GuestFD *gf,
+ target_ulong buf, uint32_t len)
+{
+ /* This fd can never be open for writing */
+ CPUARMState *env = &cpu->env;
+
+ errno = EBADF;
+ return set_swi_errno(env, -1);
+}
+
+static uint32_t featurefile_readfn(ARMCPU *cpu, GuestFD *gf,
+ target_ulong buf, uint32_t len)
+{
+ uint32_t i;
+#ifndef CONFIG_USER_ONLY
+ CPUARMState *env = &cpu->env;
+#endif
+ char *s;
+
+ s = lock_user(VERIFY_WRITE, buf, len, 0);
+ if (!s) {
+ return len;
+ }
+
+ for (i = 0; i < len; i++) {
+ if (gf->featurefile_offset >= sizeof(featurefile_data)) {
+ break;
+ }
+ s[i] = featurefile_data[gf->featurefile_offset];
+ gf->featurefile_offset++;
+ }
+
+ unlock_user(s, buf, len);
+
+ /* Return number of bytes not read */
+ return len - i;
+}
+
+static uint32_t featurefile_isattyfn(ARMCPU *cpu, GuestFD *gf)
+{
+ return 0;
+}
+
+static uint32_t featurefile_seekfn(ARMCPU *cpu, GuestFD *gf,
+ target_ulong offset)
+{
+ gf->featurefile_offset = offset;
+ return 0;
+}
+
+static uint32_t featurefile_flenfn(ARMCPU *cpu, GuestFD *gf)
+{
+ return sizeof(featurefile_data);
+}
+
+typedef struct GuestFDFunctions {
+ sys_closefn *closefn;
+ sys_writefn *writefn;
+ sys_readfn *readfn;
+ sys_isattyfn *isattyfn;
+ sys_seekfn *seekfn;
+ sys_flenfn *flenfn;
+} GuestFDFunctions;
+
+static const GuestFDFunctions guestfd_fns[] = {
+ [GuestFDHost] = {
+ .closefn = host_closefn,
+ .writefn = host_writefn,
+ .readfn = host_readfn,
+ .isattyfn = host_isattyfn,
+ .seekfn = host_seekfn,
+ .flenfn = host_flenfn,
+ },
+ [GuestFDGDB] = {
+ .closefn = gdb_closefn,
+ .writefn = gdb_writefn,
+ .readfn = gdb_readfn,
+ .isattyfn = gdb_isattyfn,
+ .seekfn = gdb_seekfn,
+ .flenfn = gdb_flenfn,
+ },
+ [GuestFDFeatureFile] = {
+ .closefn = featurefile_closefn,
+ .writefn = featurefile_writefn,
+ .readfn = featurefile_readfn,
+ .isattyfn = featurefile_isattyfn,
+ .seekfn = featurefile_seekfn,
+ .flenfn = featurefile_flenfn,
+ },
+};
+
/* Read the input value from the argument block; fail the semihosting
* call if the memory read fails.
*/
#define GET_ARG(n) do { \
if (is_a64(env)) { \
if (get_user_u64(arg ## n, args + (n) * 8)) { \
- return -1; \
+ errno = EFAULT; \
+ return set_swi_errno(env, -1); \
} \
} else { \
if (get_user_u32(arg ## n, args + (n) * 4)) { \
- return -1; \
+ errno = EFAULT; \
+ return set_swi_errno(env, -1); \
} \
} \
} while (0)
@@ -264,11 +673,7 @@ target_ulong do_arm_semihosting(CPUARMState *env)
int nr;
uint32_t ret;
uint32_t len;
-#ifdef CONFIG_USER_ONLY
- TaskState *ts = cs->opaque;
-#else
- CPUARMState *ts = env;
-#endif
+ GuestFD *gf;
if (is_a64(env)) {
/* Note that the syscall number is in W0, not X0 */
@@ -281,38 +686,90 @@ target_ulong do_arm_semihosting(CPUARMState *env)
switch (nr) {
case TARGET_SYS_OPEN:
+ {
+ int guestfd;
+
GET_ARG(0);
GET_ARG(1);
GET_ARG(2);
s = lock_user_string(arg0);
if (!s) {
- /* FIXME - should this error code be -TARGET_EFAULT ? */
- return (uint32_t)-1;
+ errno = EFAULT;
+ return set_swi_errno(env, -1);
}
if (arg1 >= 12) {
unlock_user(s, arg0, 0);
- return (uint32_t)-1;
+ errno = EINVAL;
+ return set_swi_errno(env, -1);
+ }
+
+ guestfd = alloc_guestfd();
+ if (guestfd < 0) {
+ unlock_user(s, arg0, 0);
+ errno = EMFILE;
+ return set_swi_errno(env, -1);
}
+
if (strcmp(s, ":tt") == 0) {
- int result_fileno = arg1 < 4 ? STDIN_FILENO : STDOUT_FILENO;
+ int result_fileno;
+
+ /*
+ * We implement SH_EXT_STDOUT_STDERR, so:
+ * open for read == stdin
+ * open for write == stdout
+ * open for append == stderr
+ */
+ if (arg1 < 4) {
+ result_fileno = STDIN_FILENO;
+ } else if (arg1 < 8) {
+ result_fileno = STDOUT_FILENO;
+ } else {
+ result_fileno = STDERR_FILENO;
+ }
+ associate_guestfd(guestfd, result_fileno);
unlock_user(s, arg0, 0);
- return result_fileno;
+ return guestfd;
}
+ if (strcmp(s, ":semihosting-features") == 0) {
+ unlock_user(s, arg0, 0);
+ /* We must fail opens for modes other than 0 ('r') or 1 ('rb') */
+ if (arg1 != 0 && arg1 != 1) {
+ dealloc_guestfd(guestfd);
+ errno = EACCES;
+ return set_swi_errno(env, -1);
+ }
+ init_featurefile_guestfd(guestfd);
+ return guestfd;
+ }
+
if (use_gdb_syscalls()) {
- ret = arm_gdb_syscall(cpu, arm_semi_cb, "open,%s,%x,1a4", arg0,
+ arm_semi_open_guestfd = guestfd;
+ ret = arm_gdb_syscall(cpu, arm_semi_open_cb, "open,%s,%x,1a4", arg0,
(int)arg2+1, gdb_open_modeflags[arg1]);
} else {
- ret = set_swi_errno(ts, open(s, open_modeflags[arg1], 0644));
+ ret = set_swi_errno(env, open(s, open_modeflags[arg1], 0644));
+ if (ret == (uint32_t)-1) {
+ dealloc_guestfd(guestfd);
+ } else {
+ associate_guestfd(guestfd, ret);
+ ret = guestfd;
+ }
}
unlock_user(s, arg0, 0);
return ret;
+ }
case TARGET_SYS_CLOSE:
GET_ARG(0);
- if (use_gdb_syscalls()) {
- return arm_gdb_syscall(cpu, arm_semi_cb, "close,%x", arg0);
- } else {
- return set_swi_errno(ts, close(arg0));
+
+ gf = get_guestfd(arg0);
+ if (!gf) {
+ errno = EBADF;
+ return set_swi_errno(env, -1);
}
+
+ ret = guestfd_fns[gf->type].closefn(cpu, gf);
+ dealloc_guestfd(arg0);
+ return ret;
case TARGET_SYS_WRITEC:
qemu_semihosting_console_outc(env, args);
return 0xdeadbeef;
@@ -323,83 +780,61 @@ target_ulong do_arm_semihosting(CPUARMState *env)
GET_ARG(1);
GET_ARG(2);
len = arg2;
- if (use_gdb_syscalls()) {
- arm_semi_syscall_len = len;
- return arm_gdb_syscall(cpu, arm_semi_cb, "write,%x,%x,%x",
- arg0, arg1, len);
- } else {
- s = lock_user(VERIFY_READ, arg1, len, 1);
- if (!s) {
- /* Return bytes not written on error */
- return len;
- }
- ret = set_swi_errno(ts, write(arg0, s, len));
- unlock_user(s, arg1, 0);
- if (ret == (uint32_t)-1) {
- ret = 0;
- }
- /* Return bytes not written */
- return len - ret;
+
+ gf = get_guestfd(arg0);
+ if (!gf) {
+ errno = EBADF;
+ return set_swi_errno(env, -1);
}
+
+ return guestfd_fns[gf->type].writefn(cpu, gf, arg1, len);
case TARGET_SYS_READ:
GET_ARG(0);
GET_ARG(1);
GET_ARG(2);
len = arg2;
- if (use_gdb_syscalls()) {
- arm_semi_syscall_len = len;
- return arm_gdb_syscall(cpu, arm_semi_cb, "read,%x,%x,%x",
- arg0, arg1, len);
- } else {
- s = lock_user(VERIFY_WRITE, arg1, len, 0);
- if (!s) {
- /* return bytes not read */
- return len;
- }
- do {
- ret = set_swi_errno(ts, read(arg0, s, len));
- } while (ret == -1 && errno == EINTR);
- unlock_user(s, arg1, len);
- if (ret == (uint32_t)-1) {
- ret = 0;
- }
- /* Return bytes not read */
- return len - ret;
+
+ gf = get_guestfd(arg0);
+ if (!gf) {
+ errno = EBADF;
+ return set_swi_errno(env, -1);
}
+
+ return guestfd_fns[gf->type].readfn(cpu, gf, arg1, len);
case TARGET_SYS_READC:
qemu_log_mask(LOG_UNIMP, "%s: SYS_READC not implemented", __func__);
return 0;
case TARGET_SYS_ISTTY:
GET_ARG(0);
- if (use_gdb_syscalls()) {
- return arm_gdb_syscall(cpu, arm_semi_cb, "isatty,%x", arg0);
- } else {
- return isatty(arg0);
+
+ gf = get_guestfd(arg0);
+ if (!gf) {
+ errno = EBADF;
+ return set_swi_errno(env, -1);
}
+
+ return guestfd_fns[gf->type].isattyfn(cpu, gf);
case TARGET_SYS_SEEK:
GET_ARG(0);
GET_ARG(1);
- if (use_gdb_syscalls()) {
- return arm_gdb_syscall(cpu, arm_semi_cb, "lseek,%x,%x,0",
- arg0, arg1);
- } else {
- ret = set_swi_errno(ts, lseek(arg0, arg1, SEEK_SET));
- if (ret == (uint32_t)-1)
- return -1;
- return 0;
+
+ gf = get_guestfd(arg0);
+ if (!gf) {
+ errno = EBADF;
+ return set_swi_errno(env, -1);
}
+
+ return guestfd_fns[gf->type].seekfn(cpu, gf, arg1);
case TARGET_SYS_FLEN:
GET_ARG(0);
- if (use_gdb_syscalls()) {
- return arm_gdb_syscall(cpu, arm_semi_flen_cb, "fstat,%x,%x",
- arg0, arm_flen_buf(cpu));
- } else {
- struct stat buf;
- ret = set_swi_errno(ts, fstat(arg0, &buf));
- if (ret == (uint32_t)-1)
- return -1;
- return buf.st_size;
+
+ gf = get_guestfd(arg0);
+ if (!gf) {
+ errno = EBADF;
+ return set_swi_errno(env, -1);
}
+
+ return guestfd_fns[gf->type].flenfn(cpu, gf);
case TARGET_SYS_TMPNAM:
qemu_log_mask(LOG_UNIMP, "%s: SYS_TMPNAM not implemented", __func__);
return -1;
@@ -412,10 +847,10 @@ target_ulong do_arm_semihosting(CPUARMState *env)
} else {
s = lock_user_string(arg0);
if (!s) {
- /* FIXME - should this error code be -TARGET_EFAULT ? */
- return (uint32_t)-1;
+ errno = EFAULT;
+ return set_swi_errno(env, -1);
}
- ret = set_swi_errno(ts, remove(s));
+ ret = set_swi_errno(env, remove(s));
unlock_user(s, arg0, 0);
}
return ret;
@@ -431,11 +866,12 @@ target_ulong do_arm_semihosting(CPUARMState *env)
char *s2;
s = lock_user_string(arg0);
s2 = lock_user_string(arg2);
- if (!s || !s2)
- /* FIXME - should this error code be -TARGET_EFAULT ? */
- ret = (uint32_t)-1;
- else
- ret = set_swi_errno(ts, rename(s, s2));
+ if (!s || !s2) {
+ errno = EFAULT;
+ ret = set_swi_errno(env, -1);
+ } else {
+ ret = set_swi_errno(env, rename(s, s2));
+ }
if (s2)
unlock_user(s2, arg2, 0);
if (s)
@@ -445,7 +881,7 @@ target_ulong do_arm_semihosting(CPUARMState *env)
case TARGET_SYS_CLOCK:
return clock() / (CLOCKS_PER_SEC / 100);
case TARGET_SYS_TIME:
- return set_swi_errno(ts, time(NULL));
+ return set_swi_errno(env, time(NULL));
case TARGET_SYS_SYSTEM:
GET_ARG(0);
GET_ARG(1);
@@ -455,19 +891,15 @@ target_ulong do_arm_semihosting(CPUARMState *env)
} else {
s = lock_user_string(arg0);
if (!s) {
- /* FIXME - should this error code be -TARGET_EFAULT ? */
- return (uint32_t)-1;
+ errno = EFAULT;
+ return set_swi_errno(env, -1);
}
- ret = set_swi_errno(ts, system(s));
+ ret = set_swi_errno(env, system(s));
unlock_user(s, arg0, 0);
return ret;
}
case TARGET_SYS_ERRNO:
-#ifdef CONFIG_USER_ONLY
- return ts->swi_errno;
-#else
- return syscall_err;
-#endif
+ return get_swi_errno(env);
case TARGET_SYS_GET_CMDLINE:
{
/* Build a command-line from the original argv.
@@ -490,6 +922,8 @@ target_ulong do_arm_semihosting(CPUARMState *env)
int status = 0;
#if !defined(CONFIG_USER_ONLY)
const char *cmdline;
+#else
+ TaskState *ts = cs->opaque;
#endif
GET_ARG(0);
GET_ARG(1);
@@ -516,19 +950,22 @@ target_ulong do_arm_semihosting(CPUARMState *env)
if (output_size > input_size) {
/* Not enough space to store command-line arguments. */
- return -1;
+ errno = E2BIG;
+ return set_swi_errno(env, -1);
}
/* Adjust the command-line length. */
if (SET_ARG(1, output_size - 1)) {
/* Couldn't write back to argument block */
- return -1;
+ errno = EFAULT;
+ return set_swi_errno(env, -1);
}
/* Lock the buffer on the ARM side. */
output_buffer = lock_user(VERIFY_WRITE, arg0, output_size, 0);
if (!output_buffer) {
- return -1;
+ errno = EFAULT;
+ return set_swi_errno(env, -1);
}
/* Copy the command-line arguments. */
@@ -543,7 +980,8 @@ target_ulong do_arm_semihosting(CPUARMState *env)
if (copy_from_user(output_buffer, ts->info->arg_start,
output_size)) {
- status = -1;
+ errno = EFAULT;
+ status = set_swi_errno(env, -1);
goto out;
}
@@ -565,6 +1003,9 @@ target_ulong do_arm_semihosting(CPUARMState *env)
target_ulong retvals[4];
target_ulong limit;
int i;
+#ifdef CONFIG_USER_ONLY
+ TaskState *ts = cs->opaque;
+#endif
GET_ARG(0);
@@ -613,17 +1054,21 @@ target_ulong do_arm_semihosting(CPUARMState *env)
if (fail) {
/* Couldn't write back to argument block */
- return -1;
+ errno = EFAULT;
+ return set_swi_errno(env, -1);
}
}
return 0;
}
case TARGET_SYS_EXIT:
- if (is_a64(env)) {
+ case TARGET_SYS_EXIT_EXTENDED:
+ if (nr == TARGET_SYS_EXIT_EXTENDED || is_a64(env)) {
/*
- * The A64 version of this call takes a parameter block,
+ * The A64 version of SYS_EXIT takes a parameter block,
* so the application-exit type can return a subcode which
* is the exit status code from the application.
+ * SYS_EXIT_EXTENDED is an a new-in-v2.0 optional function
+ * which allows A32/T32 guests to also provide a status code.
*/
GET_ARG(0);
GET_ARG(1);
@@ -635,8 +1080,10 @@ target_ulong do_arm_semihosting(CPUARMState *env)
}
} else {
/*
- * ARM specifies only Stopped_ApplicationExit as normal
- * exit, everything else is considered an error
+ * The A32/T32 version of SYS_EXIT specifies only
+ * Stopped_ApplicationExit as normal exit, but does not
+ * allow the guest to specify the exit status code.
+ * Everything else is considered an error.
*/
ret = (args == ADP_Stopped_ApplicationExit) ? 0 : 1;
}
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 2399c14..13813fb 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -576,16 +576,16 @@ static void arm_cpu_kvm_set_irq(void *opaque, int irq, int level)
ARMCPU *cpu = opaque;
CPUARMState *env = &cpu->env;
CPUState *cs = CPU(cpu);
- int kvm_irq = KVM_ARM_IRQ_TYPE_CPU << KVM_ARM_IRQ_TYPE_SHIFT;
uint32_t linestate_bit;
+ int irq_id;
switch (irq) {
case ARM_CPU_IRQ:
- kvm_irq |= KVM_ARM_IRQ_CPU_IRQ;
+ irq_id = KVM_ARM_IRQ_CPU_IRQ;
linestate_bit = CPU_INTERRUPT_HARD;
break;
case ARM_CPU_FIQ:
- kvm_irq |= KVM_ARM_IRQ_CPU_FIQ;
+ irq_id = KVM_ARM_IRQ_CPU_FIQ;
linestate_bit = CPU_INTERRUPT_FIQ;
break;
default:
@@ -597,9 +597,7 @@ static void arm_cpu_kvm_set_irq(void *opaque, int irq, int level)
} else {
env->irq_line_state &= ~linestate_bit;
}
-
- kvm_irq |= cs->cpu_index << KVM_ARM_IRQ_VCPU_SHIFT;
- kvm_set_irq(kvm_state, kvm_irq, level ? 1 : 0);
+ kvm_arm_set_irq(cs->cpu_index, KVM_ARM_IRQ_TYPE_CPU, irq_id, !!level);
#endif
}
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 507026c..0d9a2d2 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -6733,6 +6733,19 @@ void register_cp_regs_for_features(ARMCPU *cpu)
}
if (arm_feature(env, ARM_FEATURE_CBAR)) {
+ /*
+ * CBAR is IMPDEF, but common on Arm Cortex-A implementations.
+ * There are two flavours:
+ * (1) older 32-bit only cores have a simple 32-bit CBAR
+ * (2) 64-bit cores have a 64-bit CBAR visible to AArch64, plus a
+ * 32-bit register visible to AArch32 at a different encoding
+ * to the "flavour 1" register and with the bits rearranged to
+ * be able to squash a 64-bit address into the 32-bit view.
+ * We distinguish the two via the ARM_FEATURE_AARCH64 flag, but
+ * in future if we support AArch32-only configs of some of the
+ * AArch64 cores we might need to add a specific feature flag
+ * to indicate cores with "flavour 2" CBAR.
+ */
if (arm_feature(env, ARM_FEATURE_AARCH64)) {
/* 32 bit view is [31:18] 0...0 [43:32]. */
uint32_t cbar32 = (extract64(cpu->reset_cbar, 18, 14) << 18)
@@ -6740,12 +6753,12 @@ void register_cp_regs_for_features(ARMCPU *cpu)
ARMCPRegInfo cbar_reginfo[] = {
{ .name = "CBAR",
.type = ARM_CP_CONST,
- .cp = 15, .crn = 15, .crm = 0, .opc1 = 4, .opc2 = 0,
- .access = PL1_R, .resetvalue = cpu->reset_cbar },
+ .cp = 15, .crn = 15, .crm = 3, .opc1 = 1, .opc2 = 0,
+ .access = PL1_R, .resetvalue = cbar32 },
{ .name = "CBAR_EL1", .state = ARM_CP_STATE_AA64,
.type = ARM_CP_CONST,
.opc0 = 3, .opc1 = 1, .crn = 15, .crm = 3, .opc2 = 0,
- .access = PL1_R, .resetvalue = cbar32 },
+ .access = PL1_R, .resetvalue = cpu->reset_cbar },
REGINFO_SENTINEL
};
/* We don't implement a r/w 64 bit CBAR currently */
@@ -8339,88 +8352,32 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
new_el, env->pc, pstate_read(env));
}
-static inline bool check_for_semihosting(CPUState *cs)
-{
+/*
+ * Do semihosting call and set the appropriate return value. All the
+ * permission and validity checks have been done at translate time.
+ *
+ * We only see semihosting exceptions in TCG only as they are not
+ * trapped to the hypervisor in KVM.
+ */
#ifdef CONFIG_TCG
- /* Check whether this exception is a semihosting call; if so
- * then handle it and return true; otherwise return false.
- */
+static void handle_semihosting(CPUState *cs)
+{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
if (is_a64(env)) {
- if (cs->exception_index == EXCP_SEMIHOST) {
- /* This is always the 64-bit semihosting exception.
- * The "is this usermode" and "is semihosting enabled"
- * checks have been done at translate time.
- */
- qemu_log_mask(CPU_LOG_INT,
- "...handling as semihosting call 0x%" PRIx64 "\n",
- env->xregs[0]);
- env->xregs[0] = do_arm_semihosting(env);
- return true;
- }
- return false;
+ qemu_log_mask(CPU_LOG_INT,
+ "...handling as semihosting call 0x%" PRIx64 "\n",
+ env->xregs[0]);
+ env->xregs[0] = do_arm_semihosting(env);
} else {
- uint32_t imm;
-
- /* Only intercept calls from privileged modes, to provide some
- * semblance of security.
- */
- if (cs->exception_index != EXCP_SEMIHOST &&
- (!semihosting_enabled() ||
- ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR))) {
- return false;
- }
-
- switch (cs->exception_index) {
- case EXCP_SEMIHOST:
- /* This is always a semihosting call; the "is this usermode"
- * and "is semihosting enabled" checks have been done at
- * translate time.
- */
- break;
- case EXCP_SWI:
- /* Check for semihosting interrupt. */
- if (env->thumb) {
- imm = arm_lduw_code(env, env->regs[15] - 2, arm_sctlr_b(env))
- & 0xff;
- if (imm == 0xab) {
- break;
- }
- } else {
- imm = arm_ldl_code(env, env->regs[15] - 4, arm_sctlr_b(env))
- & 0xffffff;
- if (imm == 0x123456) {
- break;
- }
- }
- return false;
- case EXCP_BKPT:
- /* See if this is a semihosting syscall. */
- if (env->thumb) {
- imm = arm_lduw_code(env, env->regs[15], arm_sctlr_b(env))
- & 0xff;
- if (imm == 0xab) {
- env->regs[15] += 2;
- break;
- }
- }
- return false;
- default:
- return false;
- }
-
qemu_log_mask(CPU_LOG_INT,
"...handling as semihosting call 0x%x\n",
env->regs[0]);
env->regs[0] = do_arm_semihosting(env);
- return true;
}
-#else
- return false;
-#endif
}
+#endif
/* Handle a CPU exception for A and R profile CPUs.
* Do any appropriate logging, handle PSCI calls, and then hand off
@@ -8451,13 +8408,17 @@ void arm_cpu_do_interrupt(CPUState *cs)
return;
}
- /* Semihosting semantics depend on the register width of the
- * code that caused the exception, not the target exception level,
- * so must be handled here.
+ /*
+ * Semihosting semantics depend on the register width of the code
+ * that caused the exception, not the target exception level, so
+ * must be handled here.
*/
- if (check_for_semihosting(cs)) {
+#ifdef CONFIG_TCG
+ if (cs->exception_index == EXCP_SEMIHOST) {
+ handle_semihosting(cs);
return;
}
+#endif
/* Hooks may change global state so BQL should be held, also the
* BQL needs to be held for any modification of
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index b2eaa50..b473c63 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -182,6 +182,7 @@ int kvm_arm_get_max_vm_ipa_size(MachineState *ms)
int kvm_arch_init(MachineState *ms, KVMState *s)
{
+ int ret = 0;
/* For ARM interrupt delivery is always asynchronous,
* whether we are using an in-kernel VGIC or not.
*/
@@ -195,7 +196,14 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE);
- return 0;
+ if (ms->smp.cpus > 256 &&
+ !kvm_check_extension(s, KVM_CAP_ARM_IRQ_LINE_LAYOUT_2)) {
+ error_report("Using more than 256 vcpus requires a host kernel "
+ "with KVM_CAP_ARM_IRQ_LINE_LAYOUT_2");
+ ret = -EINVAL;
+ }
+
+ return ret;
}
unsigned long kvm_arch_vcpu_id(CPUState *cpu)
@@ -744,6 +752,18 @@ int kvm_arm_vgic_probe(void)
}
}
+int kvm_arm_set_irq(int cpu, int irqtype, int irq, int level)
+{
+ int kvm_irq = (irqtype << KVM_ARM_IRQ_TYPE_SHIFT) | irq;
+ int cpu_idx1 = cpu % 256;
+ int cpu_idx2 = cpu / 256;
+
+ kvm_irq |= (cpu_idx1 << KVM_ARM_IRQ_VCPU_SHIFT) |
+ (cpu_idx2 << KVM_ARM_IRQ_VCPU2_SHIFT);
+
+ return kvm_set_irq(kvm_state, kvm_irq, !!level);
+}
+
int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
uint64_t address, uint32_t data, PCIDevice *dev)
{
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index b3106c8..b4e1945 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -253,6 +253,7 @@ int kvm_arm_vgic_probe(void);
void kvm_arm_pmu_set_irq(CPUState *cs, int irq);
void kvm_arm_pmu_init(CPUState *cs);
+int kvm_arm_set_irq(int cpu, int irqtype, int irq, int level);
#else
diff --git a/target/arm/m_helper.c b/target/arm/m_helper.c
index 884d35d..27cd2f3 100644
--- a/target/arm/m_helper.c
+++ b/target/arm/m_helper.c
@@ -2114,19 +2114,13 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
break;
}
break;
+ case EXCP_SEMIHOST:
+ qemu_log_mask(CPU_LOG_INT,
+ "...handling as semihosting call 0x%x\n",
+ env->regs[0]);
+ env->regs[0] = do_arm_semihosting(env);
+ return;
case EXCP_BKPT:
- if (semihosting_enabled()) {
- int nr;
- nr = arm_lduw_code(env, env->regs[15], arm_sctlr_b(env)) & 0xff;
- if (nr == 0xab) {
- env->regs[15] += 2;
- qemu_log_mask(CPU_LOG_INT,
- "...handling as semihosting call 0x%x\n",
- env->regs[0]);
- env->regs[0] = do_arm_semihosting(env);
- return;
- }
- }
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_DEBUG, false);
break;
case EXCP_IRQ:
diff --git a/target/arm/translate.c b/target/arm/translate.c
index 34bb280..9634052 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -8045,7 +8045,9 @@ static bool op_smlaxxx(DisasContext *s, arg_rrrr *a,
case 2:
tl = load_reg(s, a->ra);
th = load_reg(s, a->rd);
- t1 = tcg_const_i32(0);
+ /* Sign-extend the 32-bit product to 64 bits. */
+ t1 = tcg_temp_new_i32();
+ tcg_gen_sari_i32(t1, t0, 31);
tcg_gen_add2_i32(tl, th, tl, th, t0, t1);
tcg_temp_free_i32(t0);
tcg_temp_free_i32(t1);
@@ -8424,7 +8426,16 @@ static bool trans_BKPT(DisasContext *s, arg_BKPT *a)
if (!ENABLE_ARCH_5) {
return false;
}
- gen_exception_bkpt_insn(s, syn_aa32_bkpt(a->imm, false));
+ if (arm_dc_feature(s, ARM_FEATURE_M) &&
+ semihosting_enabled() &&
+#ifndef CONFIG_USER_ONLY
+ !IS_USER(s) &&
+#endif
+ (a->imm == 0xab)) {
+ gen_exception_internal_insn(s, s->base.pc_next, EXCP_SEMIHOST);
+ } else {
+ gen_exception_bkpt_insn(s, syn_aa32_bkpt(a->imm, false));
+ }
return true;
}
@@ -10213,14 +10224,25 @@ static bool trans_CBZ(DisasContext *s, arg_CBZ *a)
}
/*
- * Supervisor call
+ * Supervisor call - both T32 & A32 come here so we need to check
+ * which mode we are in when checking for semihosting.
*/
static bool trans_SVC(DisasContext *s, arg_SVC *a)
{
- gen_set_pc_im(s, s->base.pc_next);
- s->svc_imm = a->imm;
- s->base.is_jmp = DISAS_SWI;
+ const uint32_t semihost_imm = s->thumb ? 0xab : 0x123456;
+
+ if (!arm_dc_feature(s, ARM_FEATURE_M) && semihosting_enabled() &&
+#ifndef CONFIG_USER_ONLY
+ !IS_USER(s) &&
+#endif
+ (a->imm == semihost_imm)) {
+ gen_exception_internal_insn(s, s->base.pc_next, EXCP_SEMIHOST);
+ } else {
+ gen_set_pc_im(s, s->base.pc_next);
+ s->svc_imm = a->imm;
+ s->base.is_jmp = DISAS_SWI;
+ }
return true;
}
diff --git a/target/hppa/translate.c b/target/hppa/translate.c
index 53e17d8..c1b2822 100644
--- a/target/hppa/translate.c
+++ b/target/hppa/translate.c
@@ -2214,10 +2214,11 @@ static bool trans_mtsp(DisasContext *ctx, arg_mtsp *a)
static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a)
{
unsigned ctl = a->t;
- TCGv_reg reg = load_gpr(ctx, a->r);
+ TCGv_reg reg;
TCGv_reg tmp;
if (ctl == CR_SAR) {
+ reg = load_gpr(ctx, a->r);
tmp = tcg_temp_new();
tcg_gen_andi_reg(tmp, reg, TARGET_REGISTER_BITS - 1);
save_or_nullify(ctx, cpu_sar, tmp);
@@ -2232,6 +2233,8 @@ static bool trans_mtctl(DisasContext *ctx, arg_mtctl *a)
#ifndef CONFIG_USER_ONLY
nullify_over(ctx);
+ reg = load_gpr(ctx, a->r);
+
switch (ctl) {
case CR_IT:
gen_helper_write_interval_timer(cpu_env, reg);
@@ -3401,10 +3404,6 @@ static bool do_depw_sar(DisasContext *ctx, unsigned rt, unsigned c,
TCGv_reg mask, tmp, shift, dest;
unsigned msb = 1U << (len - 1);
- if (c) {
- nullify_over(ctx);
- }
-
dest = dest_gpr(ctx, rt);
shift = tcg_temp_new();
tmp = tcg_temp_new();
@@ -3437,11 +3436,17 @@ static bool do_depw_sar(DisasContext *ctx, unsigned rt, unsigned c,
static bool trans_depw_sar(DisasContext *ctx, arg_depw_sar *a)
{
+ if (a->c) {
+ nullify_over(ctx);
+ }
return do_depw_sar(ctx, a->t, a->c, a->nz, a->clen, load_gpr(ctx, a->r));
}
static bool trans_depwi_sar(DisasContext *ctx, arg_depwi_sar *a)
{
+ if (a->c) {
+ nullify_over(ctx);
+ }
return do_depw_sar(ctx, a->t, a->c, a->nz, a->clen, load_const(ctx, a->i));
}
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 9e0bac3..47200b4 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -789,7 +789,7 @@ typedef struct FeatureWordInfo {
* In cases of disagreement between feature naming conventions,
* aliases may be added.
*/
- const char *feat_names[32];
+ const char *feat_names[64];
union {
/* If type==CPUID_FEATURE_WORD */
struct {
@@ -801,17 +801,13 @@ typedef struct FeatureWordInfo {
/* If type==MSR_FEATURE_WORD */
struct {
uint32_t index;
- struct { /*CPUID that enumerate this MSR*/
- FeatureWord cpuid_class;
- uint32_t cpuid_flag;
- } cpuid_dep;
} msr;
};
- uint32_t tcg_features; /* Feature flags supported by TCG */
- uint32_t unmigratable_flags; /* Feature flags known to be unmigratable */
- uint32_t migratable_flags; /* Feature flags known to be migratable */
+ uint64_t tcg_features; /* Feature flags supported by TCG */
+ uint64_t unmigratable_flags; /* Feature flags known to be unmigratable */
+ uint64_t migratable_flags; /* Feature flags known to be migratable */
/* Features that shouldn't be auto-enabled by "-cpu host" */
- uint32_t no_autoenable_flags;
+ uint64_t no_autoenable_flags;
} FeatureWordInfo;
static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
@@ -1134,7 +1130,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
[FEAT_8000_0008_EBX] = {
.type = CPUID_FEATURE_WORD,
.feat_names = {
- NULL, NULL, NULL, NULL,
+ "clzero", NULL, "xsaveerptr", NULL,
NULL, NULL, NULL, NULL,
NULL, "wbnoinvd", NULL, NULL,
"ibpb", NULL, NULL, NULL,
@@ -1218,10 +1214,6 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
},
.msr = {
.index = MSR_IA32_ARCH_CAPABILITIES,
- .cpuid_dep = {
- FEAT_7_0_EDX,
- CPUID_7_0_EDX_ARCH_CAPABILITIES
- }
},
},
[FEAT_CORE_CAPABILITY] = {
@@ -1238,12 +1230,253 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
},
.msr = {
.index = MSR_IA32_CORE_CAPABILITY,
- .cpuid_dep = {
- FEAT_7_0_EDX,
- CPUID_7_0_EDX_CORE_CAPABILITY,
- },
},
},
+
+ [FEAT_VMX_PROCBASED_CTLS] = {
+ .type = MSR_FEATURE_WORD,
+ .feat_names = {
+ NULL, NULL, "vmx-vintr-pending", "vmx-tsc-offset",
+ NULL, NULL, NULL, "vmx-hlt-exit",
+ NULL, "vmx-invlpg-exit", "vmx-mwait-exit", "vmx-rdpmc-exit",
+ "vmx-rdtsc-exit", NULL, NULL, "vmx-cr3-load-noexit",
+ "vmx-cr3-store-noexit", NULL, NULL, "vmx-cr8-load-exit",
+ "vmx-cr8-store-exit", "vmx-flexpriority", "vmx-vnmi-pending", "vmx-movdr-exit",
+ "vmx-io-exit", "vmx-io-bitmap", NULL, "vmx-mtf",
+ "vmx-msr-bitmap", "vmx-monitor-exit", "vmx-pause-exit", "vmx-secondary-ctls",
+ },
+ .msr = {
+ .index = MSR_IA32_VMX_TRUE_PROCBASED_CTLS,
+ }
+ },
+
+ [FEAT_VMX_SECONDARY_CTLS] = {
+ .type = MSR_FEATURE_WORD,
+ .feat_names = {
+ "vmx-apicv-xapic", "vmx-ept", "vmx-desc-exit", "vmx-rdtscp-exit",
+ "vmx-apicv-x2apic", "vmx-vpid", "vmx-wbinvd-exit", "vmx-unrestricted-guest",
+ "vmx-apicv-register", "vmx-apicv-vid", "vmx-ple", "vmx-rdrand-exit",
+ "vmx-invpcid-exit", "vmx-vmfunc", "vmx-shadow-vmcs", "vmx-encls-exit",
+ "vmx-rdseed-exit", "vmx-pml", NULL, NULL,
+ "vmx-xsaves", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ },
+ .msr = {
+ .index = MSR_IA32_VMX_PROCBASED_CTLS2,
+ }
+ },
+
+ [FEAT_VMX_PINBASED_CTLS] = {
+ .type = MSR_FEATURE_WORD,
+ .feat_names = {
+ "vmx-intr-exit", NULL, NULL, "vmx-nmi-exit",
+ NULL, "vmx-vnmi", "vmx-preemption-timer", "vmx-posted-intr",
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ },
+ .msr = {
+ .index = MSR_IA32_VMX_TRUE_PINBASED_CTLS,
+ }
+ },
+
+ [FEAT_VMX_EXIT_CTLS] = {
+ .type = MSR_FEATURE_WORD,
+ /*
+ * VMX_VM_EXIT_HOST_ADDR_SPACE_SIZE is copied from
+ * the LM CPUID bit.
+ */
+ .feat_names = {
+ NULL, NULL, "vmx-exit-nosave-debugctl", NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL /* vmx-exit-host-addr-space-size */, NULL, NULL,
+ "vmx-exit-load-perf-global-ctrl", NULL, NULL, "vmx-exit-ack-intr",
+ NULL, NULL, "vmx-exit-save-pat", "vmx-exit-load-pat",
+ "vmx-exit-save-efer", "vmx-exit-load-efer",
+ "vmx-exit-save-preemption-timer", "vmx-exit-clear-bndcfgs",
+ NULL, "vmx-exit-clear-rtit-ctl", NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ },
+ .msr = {
+ .index = MSR_IA32_VMX_TRUE_EXIT_CTLS,
+ }
+ },
+
+ [FEAT_VMX_ENTRY_CTLS] = {
+ .type = MSR_FEATURE_WORD,
+ .feat_names = {
+ NULL, NULL, "vmx-entry-noload-debugctl", NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, "vmx-entry-ia32e-mode", NULL, NULL,
+ NULL, "vmx-entry-load-perf-global-ctrl", "vmx-entry-load-pat", "vmx-entry-load-efer",
+ "vmx-entry-load-bndcfgs", NULL, "vmx-entry-load-rtit-ctl", NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ },
+ .msr = {
+ .index = MSR_IA32_VMX_TRUE_ENTRY_CTLS,
+ }
+ },
+
+ [FEAT_VMX_MISC] = {
+ .type = MSR_FEATURE_WORD,
+ .feat_names = {
+ NULL, NULL, NULL, NULL,
+ NULL, "vmx-store-lma", "vmx-activity-hlt", "vmx-activity-shutdown",
+ "vmx-activity-wait-sipi", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, "vmx-vmwrite-vmexit-fields", "vmx-zero-len-inject", NULL,
+ },
+ .msr = {
+ .index = MSR_IA32_VMX_MISC,
+ }
+ },
+
+ [FEAT_VMX_EPT_VPID_CAPS] = {
+ .type = MSR_FEATURE_WORD,
+ .feat_names = {
+ "vmx-ept-execonly", NULL, NULL, NULL,
+ NULL, NULL, "vmx-page-walk-4", "vmx-page-walk-5",
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ "vmx-ept-2mb", "vmx-ept-1gb", NULL, NULL,
+ "vmx-invept", "vmx-eptad", "vmx-ept-advanced-exitinfo", NULL,
+ NULL, "vmx-invept-single-context", "vmx-invept-all-context", NULL,
+ NULL, NULL, NULL, NULL,
+ "vmx-invvpid", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ "vmx-invvpid-single-addr", "vmx-invept-single-context",
+ "vmx-invvpid-all-context", "vmx-invept-single-context-noglobals",
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ },
+ .msr = {
+ .index = MSR_IA32_VMX_EPT_VPID_CAP,
+ }
+ },
+
+ [FEAT_VMX_BASIC] = {
+ .type = MSR_FEATURE_WORD,
+ .feat_names = {
+ [54] = "vmx-ins-outs",
+ [55] = "vmx-true-ctls",
+ },
+ .msr = {
+ .index = MSR_IA32_VMX_BASIC,
+ },
+ /* Just to be safe - we don't support setting the MSEG version field. */
+ .no_autoenable_flags = MSR_VMX_BASIC_DUAL_MONITOR,
+ },
+
+ [FEAT_VMX_VMFUNC] = {
+ .type = MSR_FEATURE_WORD,
+ .feat_names = {
+ [0] = "vmx-eptp-switching",
+ },
+ .msr = {
+ .index = MSR_IA32_VMX_VMFUNC,
+ }
+ },
+
+};
+
+typedef struct FeatureMask {
+ FeatureWord index;
+ uint64_t mask;
+} FeatureMask;
+
+typedef struct FeatureDep {
+ FeatureMask from, to;
+} FeatureDep;
+
+static FeatureDep feature_dependencies[] = {
+ {
+ .from = { FEAT_7_0_EDX, CPUID_7_0_EDX_ARCH_CAPABILITIES },
+ .to = { FEAT_ARCH_CAPABILITIES, ~0ull },
+ },
+ {
+ .from = { FEAT_7_0_EDX, CPUID_7_0_EDX_CORE_CAPABILITY },
+ .to = { FEAT_CORE_CAPABILITY, ~0ull },
+ },
+ {
+ .from = { FEAT_1_ECX, CPUID_EXT_VMX },
+ .to = { FEAT_VMX_PROCBASED_CTLS, ~0ull },
+ },
+ {
+ .from = { FEAT_1_ECX, CPUID_EXT_VMX },
+ .to = { FEAT_VMX_PINBASED_CTLS, ~0ull },
+ },
+ {
+ .from = { FEAT_1_ECX, CPUID_EXT_VMX },
+ .to = { FEAT_VMX_EXIT_CTLS, ~0ull },
+ },
+ {
+ .from = { FEAT_1_ECX, CPUID_EXT_VMX },
+ .to = { FEAT_VMX_ENTRY_CTLS, ~0ull },
+ },
+ {
+ .from = { FEAT_1_ECX, CPUID_EXT_VMX },
+ .to = { FEAT_VMX_MISC, ~0ull },
+ },
+ {
+ .from = { FEAT_1_ECX, CPUID_EXT_VMX },
+ .to = { FEAT_VMX_BASIC, ~0ull },
+ },
+ {
+ .from = { FEAT_8000_0001_EDX, CPUID_EXT2_LM },
+ .to = { FEAT_VMX_ENTRY_CTLS, VMX_VM_ENTRY_IA32E_MODE },
+ },
+ {
+ .from = { FEAT_VMX_PROCBASED_CTLS, VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS },
+ .to = { FEAT_VMX_SECONDARY_CTLS, ~0ull },
+ },
+ {
+ .from = { FEAT_XSAVE, CPUID_XSAVE_XSAVES },
+ .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_XSAVES },
+ },
+ {
+ .from = { FEAT_1_ECX, CPUID_EXT_RDRAND },
+ .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_RDRAND_EXITING },
+ },
+ {
+ .from = { FEAT_7_0_EBX, CPUID_7_0_EBX_INVPCID },
+ .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_ENABLE_INVPCID },
+ },
+ {
+ .from = { FEAT_7_0_EBX, CPUID_7_0_EBX_RDSEED },
+ .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_RDSEED_EXITING },
+ },
+ {
+ .from = { FEAT_8000_0001_EDX, CPUID_EXT2_RDTSCP },
+ .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_RDTSCP },
+ },
+ {
+ .from = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_ENABLE_EPT },
+ .to = { FEAT_VMX_EPT_VPID_CAPS, 0xffffffffull },
+ },
+ {
+ .from = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_ENABLE_EPT },
+ .to = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST },
+ },
+ {
+ .from = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_ENABLE_VPID },
+ .to = { FEAT_VMX_EPT_VPID_CAPS, 0xffffffffull << 32 },
+ },
+ {
+ .from = { FEAT_VMX_SECONDARY_CTLS, VMX_SECONDARY_EXEC_ENABLE_VMFUNC },
+ .to = { FEAT_VMX_VMFUNC, ~0ull },
+ },
};
typedef struct X86RegisterInfo32 {
@@ -1354,14 +1587,14 @@ const char *get_register_name_32(unsigned int reg)
* Returns the set of feature flags that are supported and migratable by
* QEMU, for a given FeatureWord.
*/
-static uint32_t x86_cpu_get_migratable_flags(FeatureWord w)
+static uint64_t x86_cpu_get_migratable_flags(FeatureWord w)
{
FeatureWordInfo *wi = &feature_word_info[w];
- uint32_t r = 0;
+ uint64_t r = 0;
int i;
- for (i = 0; i < 32; i++) {
- uint32_t f = 1U << i;
+ for (i = 0; i < 64; i++) {
+ uint64_t f = 1ULL << i;
/* If the feature name is known, it is implicitly considered migratable,
* unless it is explicitly set in unmigratable_flags */
@@ -2412,8 +2645,8 @@ static X86CPUDefinition builtin_x86_defs[] = {
CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
CPUID_7_0_EBX_SMAP,
.features[FEAT_7_0_ECX] =
- CPUID_7_0_ECX_VBMI | CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU |
- CPUID_7_0_ECX_VBMI2 | CPUID_7_0_ECX_GFNI |
+ CPUID_7_0_ECX_AVX512_VBMI | CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU |
+ CPUID_7_0_ECX_AVX512_VBMI2 | CPUID_7_0_ECX_GFNI |
CPUID_7_0_ECX_VAES | CPUID_7_0_ECX_VPCLMULQDQ |
CPUID_7_0_ECX_AVX512VNNI | CPUID_7_0_ECX_AVX512BITALG |
CPUID_7_0_ECX_AVX512_VPOPCNTDQ,
@@ -2470,8 +2703,8 @@ static X86CPUDefinition builtin_x86_defs[] = {
CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512CD |
CPUID_7_0_EBX_AVX512VL | CPUID_7_0_EBX_CLFLUSHOPT,
.features[FEAT_7_0_ECX] =
- CPUID_7_0_ECX_VBMI | CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU |
- CPUID_7_0_ECX_VBMI2 | CPUID_7_0_ECX_GFNI |
+ CPUID_7_0_ECX_AVX512_VBMI | CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU |
+ CPUID_7_0_ECX_AVX512_VBMI2 | CPUID_7_0_ECX_GFNI |
CPUID_7_0_ECX_VAES | CPUID_7_0_ECX_VPCLMULQDQ |
CPUID_7_0_ECX_AVX512VNNI | CPUID_7_0_ECX_AVX512BITALG |
CPUID_7_0_ECX_AVX512_VPOPCNTDQ | CPUID_7_0_ECX_LA57,
@@ -2560,6 +2793,18 @@ static X86CPUDefinition builtin_x86_defs[] = {
CPUID_6_EAX_ARAT,
.xlevel = 0x80000008,
.model_id = "Intel Atom Processor (SnowRidge)",
+ .versions = (X86CPUVersionDefinition[]) {
+ { .version = 1 },
+ {
+ .version = 2,
+ .props = (PropValue[]) {
+ { "mpx", "off" },
+ { "model-id", "Intel Atom Processor (Snowridge, no MPX)" },
+ { /* end of list */ },
+ },
+ },
+ { /* end of list */ },
+ },
},
{
.name = "KnightsMill",
@@ -2923,7 +3168,7 @@ void x86_cpu_change_kvm_default(const char *prop, const char *value)
assert(pv->prop);
}
-static uint32_t x86_cpu_get_supported_feature_word(FeatureWord w,
+static uint64_t x86_cpu_get_supported_feature_word(FeatureWord w,
bool migratable_only);
static bool lmce_supported(void)
@@ -3096,17 +3341,41 @@ static char *feature_word_description(FeatureWordInfo *f, uint32_t bit)
return NULL;
}
-static void report_unavailable_features(FeatureWord w, uint32_t mask)
+static bool x86_cpu_have_filtered_features(X86CPU *cpu)
{
+ FeatureWord w;
+
+ for (w = 0; w < FEATURE_WORDS; w++) {
+ if (cpu->filtered_features[w]) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void mark_unavailable_features(X86CPU *cpu, FeatureWord w, uint64_t mask,
+ const char *verbose_prefix)
+{
+ CPUX86State *env = &cpu->env;
FeatureWordInfo *f = &feature_word_info[w];
int i;
char *feat_word_str;
- for (i = 0; i < 32; ++i) {
- if ((1UL << i) & mask) {
+ if (!cpu->force_features) {
+ env->features[w] &= ~mask;
+ }
+ cpu->filtered_features[w] |= mask;
+
+ if (!verbose_prefix) {
+ return;
+ }
+
+ for (i = 0; i < 64; ++i) {
+ if ((1ULL << i) & mask) {
feat_word_str = feature_word_description(f, i);
- warn_report("%s doesn't support requested feature: %s%s%s [bit %d]",
- accel_uses_host_cpuid() ? "host" : "TCG",
+ warn_report("%s: %s%s%s [bit %d]",
+ verbose_prefix,
feat_word_str,
f->feat_names[i] ? "." : "",
f->feat_names[i] ? f->feat_names[i] : "", i);
@@ -3346,7 +3615,7 @@ static void x86_cpu_get_feature_words(Object *obj, Visitor *v,
const char *name, void *opaque,
Error **errp)
{
- uint32_t *array = (uint32_t *)opaque;
+ uint64_t *array = (uint64_t *)opaque;
FeatureWord w;
X86CPUFeatureWordInfo word_infos[FEATURE_WORDS] = { };
X86CPUFeatureWordInfoList list_entries[FEATURE_WORDS] = { };
@@ -3390,6 +3659,7 @@ static inline void feat2prop(char *s)
/* Return the feature property name for a feature flag bit */
static const char *x86_cpu_feature_name(FeatureWord w, int bitnr)
{
+ const char *name;
/* XSAVE components are automatically enabled by other features,
* so return the original feature name instead
*/
@@ -3403,9 +3673,11 @@ static const char *x86_cpu_feature_name(FeatureWord w, int bitnr)
}
}
- assert(bitnr < 32);
+ assert(bitnr < 64);
assert(w < FEATURE_WORDS);
- return feature_word_info[w].feat_names[bitnr];
+ name = feature_word_info[w].feat_names[bitnr];
+ assert(bitnr < 32 || !(name && feature_word_info[w].type == CPUID_FEATURE_WORD));
+ return name;
}
/* Compatibily hack to maintain legacy +-feat semantic,
@@ -3511,7 +3783,7 @@ static void x86_cpu_parse_featurestr(const char *typename, char *features,
}
static void x86_cpu_expand_features(X86CPU *cpu, Error **errp);
-static int x86_cpu_filter_features(X86CPU *cpu);
+static void x86_cpu_filter_features(X86CPU *cpu, bool verbose);
/* Build a list with the name of all features on a feature word array */
static void x86_cpu_list_feature_names(FeatureWordArray features,
@@ -3521,10 +3793,10 @@ static void x86_cpu_list_feature_names(FeatureWordArray features,
strList **next = feat_names;
for (w = 0; w < FEATURE_WORDS; w++) {
- uint32_t filtered = features[w];
+ uint64_t filtered = features[w];
int i;
- for (i = 0; i < 32; i++) {
- if (filtered & (1UL << i)) {
+ for (i = 0; i < 64; i++) {
+ if (filtered & (1ULL << i)) {
strList *new = g_new0(strList, 1);
new->value = g_strdup(x86_cpu_feature_name(w, i));
*next = new;
@@ -3576,7 +3848,7 @@ static void x86_cpu_class_check_missing_features(X86CPUClass *xcc,
next = &new->next;
}
- x86_cpu_filter_features(xc);
+ x86_cpu_filter_features(xc, false);
x86_cpu_list_feature_names(xc->filtered_features, next);
@@ -3693,7 +3965,7 @@ void x86_cpu_list(void)
names = NULL;
for (i = 0; i < ARRAY_SIZE(feature_word_info); i++) {
FeatureWordInfo *fw = &feature_word_info[i];
- for (j = 0; j < 32; j++) {
+ for (j = 0; j < 64; j++) {
if (fw->feat_names[j]) {
names = g_list_append(names, (gpointer)fw->feat_names[j]);
}
@@ -3748,11 +4020,11 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
return cpu_list;
}
-static uint32_t x86_cpu_get_supported_feature_word(FeatureWord w,
+static uint64_t x86_cpu_get_supported_feature_word(FeatureWord w,
bool migratable_only)
{
FeatureWordInfo *wi = &feature_word_info[w];
- uint32_t r = 0;
+ uint64_t r = 0;
if (kvm_enabled()) {
switch (wi->type) {
@@ -3784,15 +4056,6 @@ static uint32_t x86_cpu_get_supported_feature_word(FeatureWord w,
return r;
}
-static void x86_cpu_report_filtered_features(X86CPU *cpu)
-{
- FeatureWord w;
-
- for (w = 0; w < FEATURE_WORDS; w++) {
- report_unavailable_features(w, cpu->filtered_features[w]);
- }
-}
-
static void x86_cpu_apply_props(X86CPU *cpu, PropValue *props)
{
PropValue *pv;
@@ -3932,7 +4195,7 @@ static QDict *x86_cpu_static_props(void)
for (w = 0; w < FEATURE_WORDS; w++) {
FeatureWordInfo *fi = &feature_word_info[w];
int bit;
- for (bit = 0; bit < 32; bit++) {
+ for (bit = 0; bit < 64; bit++) {
if (!fi->feat_names[bit]) {
continue;
}
@@ -4442,7 +4705,13 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
*ecx = xsave_area_size(x86_cpu_xsave_components(cpu));
*eax = env->features[FEAT_XSAVE_COMP_LO];
*edx = env->features[FEAT_XSAVE_COMP_HI];
- *ebx = xsave_area_size(env->xcr0);
+ /*
+ * The initial value of xcr0 and ebx == 0, On host without kvm
+ * commit 412a3c41(e.g., CentOS 6), the ebx's value always == 0
+ * even through guest update xcr0, this will crash some legacy guest
+ * (e.g., CentOS 6), So set ebx == ecx to workaroud it.
+ */
+ *ebx = kvm_enabled() ? *ecx : xsave_area_size(env->xcr0);
} else if (count == 1) {
*eax = env->features[FEAT_XSAVE];
} else if (count < ARRAY_SIZE(x86_ext_save_areas)) {
@@ -5048,9 +5317,26 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp)
{
CPUX86State *env = &cpu->env;
FeatureWord w;
+ int i;
GList *l;
Error *local_err = NULL;
+ for (l = plus_features; l; l = l->next) {
+ const char *prop = l->data;
+ object_property_set_bool(OBJECT(cpu), true, prop, &local_err);
+ if (local_err) {
+ goto out;
+ }
+ }
+
+ for (l = minus_features; l; l = l->next) {
+ const char *prop = l->data;
+ object_property_set_bool(OBJECT(cpu), false, prop, &local_err);
+ if (local_err) {
+ goto out;
+ }
+ }
+
/*TODO: Now cpu->max_features doesn't overwrite features
* set using QOM properties, and we can convert
* plus_features & minus_features to global properties
@@ -5068,19 +5354,18 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp)
}
}
- for (l = plus_features; l; l = l->next) {
- const char *prop = l->data;
- object_property_set_bool(OBJECT(cpu), true, prop, &local_err);
- if (local_err) {
- goto out;
- }
- }
+ for (i = 0; i < ARRAY_SIZE(feature_dependencies); i++) {
+ FeatureDep *d = &feature_dependencies[i];
+ if (!(env->features[d->from.index] & d->from.mask)) {
+ uint64_t unavailable_features = env->features[d->to.index] & d->to.mask;
- for (l = minus_features; l; l = l->next) {
- const char *prop = l->data;
- object_property_set_bool(OBJECT(cpu), false, prop, &local_err);
- if (local_err) {
- goto out;
+ /* Not an error unless the dependent feature was added explicitly. */
+ mark_unavailable_features(cpu, d->to.index,
+ unavailable_features & env->user_features[d->to.index],
+ "This feature depends on other features that were not requested");
+
+ env->user_features[d->to.index] |= unavailable_features;
+ env->features[d->to.index] &= ~unavailable_features;
}
}
@@ -5154,24 +5439,24 @@ out:
*
* Returns: 0 if all flags are supported by the host, non-zero otherwise.
*/
-static int x86_cpu_filter_features(X86CPU *cpu)
+static void x86_cpu_filter_features(X86CPU *cpu, bool verbose)
{
CPUX86State *env = &cpu->env;
FeatureWord w;
- int rv = 0;
+ const char *prefix = NULL;
+
+ if (verbose) {
+ prefix = accel_uses_host_cpuid()
+ ? "host doesn't support requested feature"
+ : "TCG doesn't support requested feature";
+ }
for (w = 0; w < FEATURE_WORDS; w++) {
- uint32_t host_feat =
+ uint64_t host_feat =
x86_cpu_get_supported_feature_word(w, false);
- uint32_t requested_features = env->features[w];
- uint32_t available_features = requested_features & host_feat;
- if (!cpu->force_features) {
- env->features[w] = available_features;
- }
- cpu->filtered_features[w] = requested_features & ~available_features;
- if (cpu->filtered_features[w]) {
- rv = 1;
- }
+ uint64_t requested_features = env->features[w];
+ uint64_t unavailable_features = requested_features & ~host_feat;
+ mark_unavailable_features(cpu, w, unavailable_features, prefix);
}
if ((env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_INTEL_PT) &&
@@ -5197,13 +5482,9 @@ static int x86_cpu_filter_features(X86CPU *cpu)
* host can't emulate the capabilities we report on
* cpu_x86_cpuid(), intel-pt can't be enabled on the current host.
*/
- env->features[FEAT_7_0_EBX] &= ~CPUID_7_0_EBX_INTEL_PT;
- cpu->filtered_features[FEAT_7_0_EBX] |= CPUID_7_0_EBX_INTEL_PT;
- rv = 1;
+ mark_unavailable_features(cpu, FEAT_7_0_EBX, CPUID_7_0_EBX_INTEL_PT, prefix);
}
}
-
- return rv;
}
static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
@@ -5244,16 +5525,14 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
goto out;
}
- if (x86_cpu_filter_features(cpu) &&
- (cpu->check_cpuid || cpu->enforce_cpuid)) {
- x86_cpu_report_filtered_features(cpu);
- if (cpu->enforce_cpuid) {
- error_setg(&local_err,
- accel_uses_host_cpuid() ?
- "Host doesn't support requested features" :
- "TCG doesn't support requested features");
- goto out;
- }
+ x86_cpu_filter_features(cpu, cpu->check_cpuid || cpu->enforce_cpuid);
+
+ if (cpu->enforce_cpuid && x86_cpu_have_filtered_features(cpu)) {
+ error_setg(&local_err,
+ accel_uses_host_cpuid() ?
+ "Host doesn't support requested features" :
+ "TCG doesn't support requested features");
+ goto out;
}
/* On AMD CPUs, some CPUID[8000_0001].EDX bits must match the bits on
@@ -5473,7 +5752,7 @@ static void x86_cpu_unrealizefn(DeviceState *dev, Error **errp)
typedef struct BitProperty {
FeatureWord w;
- uint32_t mask;
+ uint64_t mask;
} BitProperty;
static void x86_cpu_get_bit_prop(Object *obj, Visitor *v, const char *name,
@@ -5481,7 +5760,7 @@ static void x86_cpu_get_bit_prop(Object *obj, Visitor *v, const char *name,
{
X86CPU *cpu = X86_CPU(obj);
BitProperty *fp = opaque;
- uint32_t f = cpu->env.features[fp->w];
+ uint64_t f = cpu->env.features[fp->w];
bool value = (f & fp->mask) == fp->mask;
visit_type_bool(v, name, &value, errp);
}
@@ -5534,7 +5813,7 @@ static void x86_cpu_register_bit_prop(X86CPU *cpu,
{
BitProperty *fp;
ObjectProperty *op;
- uint32_t mask = (1UL << bitnr);
+ uint64_t mask = (1ULL << bitnr);
op = object_property_find(OBJECT(cpu), prop_name, NULL);
if (op) {
@@ -5668,7 +5947,7 @@ static void x86_cpu_initfn(Object *obj)
for (w = 0; w < FEATURE_WORDS; w++) {
int bitnr;
- for (bitnr = 0; bitnr < 32; bitnr++) {
+ for (bitnr = 0; bitnr < 64; bitnr++) {
x86_cpu_register_feature_bit_props(cpu, w, bitnr);
}
}
@@ -5984,7 +6263,7 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
#ifndef CONFIG_USER_ONLY
cc->asidx_from_attrs = x86_asidx_from_attrs;
cc->get_memory_mapping = x86_cpu_get_memory_mapping;
- cc->get_phys_page_debug = x86_cpu_get_phys_page_debug;
+ cc->get_phys_page_attrs_debug = x86_cpu_get_phys_page_attrs_debug;
cc->write_elf64_note = x86_cpu_write_elf64_note;
cc->write_elf64_qemunote = x86_cpu_write_elf64_qemunote;
cc->write_elf32_note = x86_cpu_write_elf32_note;
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 5f6e3a0..cedb5bc 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -452,6 +452,25 @@ typedef enum X86Seg {
#define MSR_IA32_BNDCFGS 0x00000d90
#define MSR_IA32_XSS 0x00000da0
+#define MSR_IA32_VMX_BASIC 0x00000480
+#define MSR_IA32_VMX_PINBASED_CTLS 0x00000481
+#define MSR_IA32_VMX_PROCBASED_CTLS 0x00000482
+#define MSR_IA32_VMX_EXIT_CTLS 0x00000483
+#define MSR_IA32_VMX_ENTRY_CTLS 0x00000484
+#define MSR_IA32_VMX_MISC 0x00000485
+#define MSR_IA32_VMX_CR0_FIXED0 0x00000486
+#define MSR_IA32_VMX_CR0_FIXED1 0x00000487
+#define MSR_IA32_VMX_CR4_FIXED0 0x00000488
+#define MSR_IA32_VMX_CR4_FIXED1 0x00000489
+#define MSR_IA32_VMX_VMCS_ENUM 0x0000048a
+#define MSR_IA32_VMX_PROCBASED_CTLS2 0x0000048b
+#define MSR_IA32_VMX_EPT_VPID_CAP 0x0000048c
+#define MSR_IA32_VMX_TRUE_PINBASED_CTLS 0x0000048d
+#define MSR_IA32_VMX_TRUE_PROCBASED_CTLS 0x0000048e
+#define MSR_IA32_VMX_TRUE_EXIT_CTLS 0x0000048f
+#define MSR_IA32_VMX_TRUE_ENTRY_CTLS 0x00000490
+#define MSR_IA32_VMX_VMFUNC 0x00000491
+
#define XSTATE_FP_BIT 0
#define XSTATE_SSE_BIT 1
#define XSTATE_YMM_BIT 2
@@ -499,10 +518,19 @@ typedef enum FeatureWord {
FEAT_XSAVE_COMP_HI, /* CPUID[EAX=0xd,ECX=0].EDX */
FEAT_ARCH_CAPABILITIES,
FEAT_CORE_CAPABILITY,
+ FEAT_VMX_PROCBASED_CTLS,
+ FEAT_VMX_SECONDARY_CTLS,
+ FEAT_VMX_PINBASED_CTLS,
+ FEAT_VMX_EXIT_CTLS,
+ FEAT_VMX_ENTRY_CTLS,
+ FEAT_VMX_MISC,
+ FEAT_VMX_EPT_VPID_CAPS,
+ FEAT_VMX_BASIC,
+ FEAT_VMX_VMFUNC,
FEATURE_WORDS,
} FeatureWord;
-typedef uint32_t FeatureWordArray[FEATURE_WORDS];
+typedef uint64_t FeatureWordArray[FEATURE_WORDS];
/* cpuid_features bits */
#define CPUID_FP87 (1U << 0)
@@ -641,63 +669,116 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS];
#define CPUID_SVM_PAUSEFILTER (1U << 10)
#define CPUID_SVM_PFTHRESHOLD (1U << 12)
-#define CPUID_7_0_EBX_FSGSBASE (1U << 0)
-#define CPUID_7_0_EBX_BMI1 (1U << 3)
-#define CPUID_7_0_EBX_HLE (1U << 4)
-#define CPUID_7_0_EBX_AVX2 (1U << 5)
-#define CPUID_7_0_EBX_SMEP (1U << 7)
-#define CPUID_7_0_EBX_BMI2 (1U << 8)
-#define CPUID_7_0_EBX_ERMS (1U << 9)
-#define CPUID_7_0_EBX_INVPCID (1U << 10)
-#define CPUID_7_0_EBX_RTM (1U << 11)
-#define CPUID_7_0_EBX_MPX (1U << 14)
-#define CPUID_7_0_EBX_AVX512F (1U << 16) /* AVX-512 Foundation */
-#define CPUID_7_0_EBX_AVX512DQ (1U << 17) /* AVX-512 Doubleword & Quadword Instrs */
-#define CPUID_7_0_EBX_RDSEED (1U << 18)
-#define CPUID_7_0_EBX_ADX (1U << 19)
-#define CPUID_7_0_EBX_SMAP (1U << 20)
-#define CPUID_7_0_EBX_AVX512IFMA (1U << 21) /* AVX-512 Integer Fused Multiply Add */
-#define CPUID_7_0_EBX_PCOMMIT (1U << 22) /* Persistent Commit */
-#define CPUID_7_0_EBX_CLFLUSHOPT (1U << 23) /* Flush a Cache Line Optimized */
-#define CPUID_7_0_EBX_CLWB (1U << 24) /* Cache Line Write Back */
-#define CPUID_7_0_EBX_INTEL_PT (1U << 25) /* Intel Processor Trace */
-#define CPUID_7_0_EBX_AVX512PF (1U << 26) /* AVX-512 Prefetch */
-#define CPUID_7_0_EBX_AVX512ER (1U << 27) /* AVX-512 Exponential and Reciprocal */
-#define CPUID_7_0_EBX_AVX512CD (1U << 28) /* AVX-512 Conflict Detection */
-#define CPUID_7_0_EBX_SHA_NI (1U << 29) /* SHA1/SHA256 Instruction Extensions */
-#define CPUID_7_0_EBX_AVX512BW (1U << 30) /* AVX-512 Byte and Word Instructions */
-#define CPUID_7_0_EBX_AVX512VL (1U << 31) /* AVX-512 Vector Length Extensions */
-
-#define CPUID_7_0_ECX_AVX512BMI (1U << 1)
-#define CPUID_7_0_ECX_VBMI (1U << 1) /* AVX-512 Vector Byte Manipulation Instrs */
-#define CPUID_7_0_ECX_UMIP (1U << 2)
-#define CPUID_7_0_ECX_PKU (1U << 3)
-#define CPUID_7_0_ECX_OSPKE (1U << 4)
-#define CPUID_7_0_ECX_VBMI2 (1U << 6) /* Additional VBMI Instrs */
-#define CPUID_7_0_ECX_GFNI (1U << 8)
-#define CPUID_7_0_ECX_VAES (1U << 9)
-#define CPUID_7_0_ECX_VPCLMULQDQ (1U << 10)
-#define CPUID_7_0_ECX_AVX512VNNI (1U << 11)
-#define CPUID_7_0_ECX_AVX512BITALG (1U << 12)
-#define CPUID_7_0_ECX_AVX512_VPOPCNTDQ (1U << 14) /* POPCNT for vectors of DW/QW */
-#define CPUID_7_0_ECX_LA57 (1U << 16)
-#define CPUID_7_0_ECX_RDPID (1U << 22)
-#define CPUID_7_0_ECX_CLDEMOTE (1U << 25) /* CLDEMOTE Instruction */
-#define CPUID_7_0_ECX_MOVDIRI (1U << 27) /* MOVDIRI Instruction */
-#define CPUID_7_0_ECX_MOVDIR64B (1U << 28) /* MOVDIR64B Instruction */
-
-#define CPUID_7_0_EDX_AVX512_4VNNIW (1U << 2) /* AVX512 Neural Network Instructions */
-#define CPUID_7_0_EDX_AVX512_4FMAPS (1U << 3) /* AVX512 Multiply Accumulation Single Precision */
-#define CPUID_7_0_EDX_SPEC_CTRL (1U << 26) /* Speculation Control */
-#define CPUID_7_0_EDX_ARCH_CAPABILITIES (1U << 29) /*Arch Capabilities*/
-#define CPUID_7_0_EDX_CORE_CAPABILITY (1U << 30) /*Core Capability*/
-#define CPUID_7_0_EDX_SPEC_CTRL_SSBD (1U << 31) /* Speculative Store Bypass Disable */
-
-#define CPUID_7_1_EAX_AVX512_BF16 (1U << 5) /* AVX512 BFloat16 Instruction */
-
-#define CPUID_8000_0008_EBX_WBNOINVD (1U << 9) /* Write back and
- do not invalidate cache */
-#define CPUID_8000_0008_EBX_IBPB (1U << 12) /* Indirect Branch Prediction Barrier */
+/* Support RDFSBASE/RDGSBASE/WRFSBASE/WRGSBASE */
+#define CPUID_7_0_EBX_FSGSBASE (1U << 0)
+/* 1st Group of Advanced Bit Manipulation Extensions */
+#define CPUID_7_0_EBX_BMI1 (1U << 3)
+/* Hardware Lock Elision */
+#define CPUID_7_0_EBX_HLE (1U << 4)
+/* Intel Advanced Vector Extensions 2 */
+#define CPUID_7_0_EBX_AVX2 (1U << 5)
+/* Supervisor-mode Execution Prevention */
+#define CPUID_7_0_EBX_SMEP (1U << 7)
+/* 2nd Group of Advanced Bit Manipulation Extensions */
+#define CPUID_7_0_EBX_BMI2 (1U << 8)
+/* Enhanced REP MOVSB/STOSB */
+#define CPUID_7_0_EBX_ERMS (1U << 9)
+/* Invalidate Process-Context Identifier */
+#define CPUID_7_0_EBX_INVPCID (1U << 10)
+/* Restricted Transactional Memory */
+#define CPUID_7_0_EBX_RTM (1U << 11)
+/* Memory Protection Extension */
+#define CPUID_7_0_EBX_MPX (1U << 14)
+/* AVX-512 Foundation */
+#define CPUID_7_0_EBX_AVX512F (1U << 16)
+/* AVX-512 Doubleword & Quadword Instruction */
+#define CPUID_7_0_EBX_AVX512DQ (1U << 17)
+/* Read Random SEED */
+#define CPUID_7_0_EBX_RDSEED (1U << 18)
+/* ADCX and ADOX instructions */
+#define CPUID_7_0_EBX_ADX (1U << 19)
+/* Supervisor Mode Access Prevention */
+#define CPUID_7_0_EBX_SMAP (1U << 20)
+/* AVX-512 Integer Fused Multiply Add */
+#define CPUID_7_0_EBX_AVX512IFMA (1U << 21)
+/* Persistent Commit */
+#define CPUID_7_0_EBX_PCOMMIT (1U << 22)
+/* Flush a Cache Line Optimized */
+#define CPUID_7_0_EBX_CLFLUSHOPT (1U << 23)
+/* Cache Line Write Back */
+#define CPUID_7_0_EBX_CLWB (1U << 24)
+/* Intel Processor Trace */
+#define CPUID_7_0_EBX_INTEL_PT (1U << 25)
+/* AVX-512 Prefetch */
+#define CPUID_7_0_EBX_AVX512PF (1U << 26)
+/* AVX-512 Exponential and Reciprocal */
+#define CPUID_7_0_EBX_AVX512ER (1U << 27)
+/* AVX-512 Conflict Detection */
+#define CPUID_7_0_EBX_AVX512CD (1U << 28)
+/* SHA1/SHA256 Instruction Extensions */
+#define CPUID_7_0_EBX_SHA_NI (1U << 29)
+/* AVX-512 Byte and Word Instructions */
+#define CPUID_7_0_EBX_AVX512BW (1U << 30)
+/* AVX-512 Vector Length Extensions */
+#define CPUID_7_0_EBX_AVX512VL (1U << 31)
+
+/* AVX-512 Vector Byte Manipulation Instruction */
+#define CPUID_7_0_ECX_AVX512_VBMI (1U << 1)
+/* User-Mode Instruction Prevention */
+#define CPUID_7_0_ECX_UMIP (1U << 2)
+/* Protection Keys for User-mode Pages */
+#define CPUID_7_0_ECX_PKU (1U << 3)
+/* OS Enable Protection Keys */
+#define CPUID_7_0_ECX_OSPKE (1U << 4)
+/* Additional AVX-512 Vector Byte Manipulation Instruction */
+#define CPUID_7_0_ECX_AVX512_VBMI2 (1U << 6)
+/* Galois Field New Instructions */
+#define CPUID_7_0_ECX_GFNI (1U << 8)
+/* Vector AES Instructions */
+#define CPUID_7_0_ECX_VAES (1U << 9)
+/* Carry-Less Multiplication Quadword */
+#define CPUID_7_0_ECX_VPCLMULQDQ (1U << 10)
+/* Vector Neural Network Instructions */
+#define CPUID_7_0_ECX_AVX512VNNI (1U << 11)
+/* Support for VPOPCNT[B,W] and VPSHUFBITQMB */
+#define CPUID_7_0_ECX_AVX512BITALG (1U << 12)
+/* POPCNT for vectors of DW/QW */
+#define CPUID_7_0_ECX_AVX512_VPOPCNTDQ (1U << 14)
+/* 5-level Page Tables */
+#define CPUID_7_0_ECX_LA57 (1U << 16)
+/* Read Processor ID */
+#define CPUID_7_0_ECX_RDPID (1U << 22)
+/* Cache Line Demote Instruction */
+#define CPUID_7_0_ECX_CLDEMOTE (1U << 25)
+/* Move Doubleword as Direct Store Instruction */
+#define CPUID_7_0_ECX_MOVDIRI (1U << 27)
+/* Move 64 Bytes as Direct Store Instruction */
+#define CPUID_7_0_ECX_MOVDIR64B (1U << 28)
+
+/* AVX512 Neural Network Instructions */
+#define CPUID_7_0_EDX_AVX512_4VNNIW (1U << 2)
+/* AVX512 Multiply Accumulation Single Precision */
+#define CPUID_7_0_EDX_AVX512_4FMAPS (1U << 3)
+/* Speculation Control */
+#define CPUID_7_0_EDX_SPEC_CTRL (1U << 26)
+/* Arch Capabilities */
+#define CPUID_7_0_EDX_ARCH_CAPABILITIES (1U << 29)
+/* Core Capability */
+#define CPUID_7_0_EDX_CORE_CAPABILITY (1U << 30)
+/* Speculative Store Bypass Disable */
+#define CPUID_7_0_EDX_SPEC_CTRL_SSBD (1U << 31)
+
+/* AVX512 BFloat16 Instruction */
+#define CPUID_7_1_EAX_AVX512_BF16 (1U << 5)
+
+/* CLZERO instruction */
+#define CPUID_8000_0008_EBX_CLZERO (1U << 0)
+/* Always save/restore FP error pointers */
+#define CPUID_8000_0008_EBX_XSAVEERPTR (1U << 2)
+/* Write back and do not invalidate cache */
+#define CPUID_8000_0008_EBX_WBNOINVD (1U << 9)
+/* Indirect Branch Prediction Barrier */
+#define CPUID_8000_0008_EBX_IBPB (1U << 12)
#define CPUID_XSAVE_XSAVEOPT (1U << 0)
#define CPUID_XSAVE_XSAVEC (1U << 1)
@@ -750,6 +831,117 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS];
#define MSR_CORE_CAP_SPLIT_LOCK_DETECT (1U << 5)
+/* VMX MSR features */
+#define MSR_VMX_BASIC_VMCS_REVISION_MASK 0x7FFFFFFFull
+#define MSR_VMX_BASIC_VMXON_REGION_SIZE_MASK (0x00001FFFull << 32)
+#define MSR_VMX_BASIC_VMCS_MEM_TYPE_MASK (0x003C0000ull << 32)
+#define MSR_VMX_BASIC_DUAL_MONITOR (1ULL << 49)
+#define MSR_VMX_BASIC_INS_OUTS (1ULL << 54)
+#define MSR_VMX_BASIC_TRUE_CTLS (1ULL << 55)
+
+#define MSR_VMX_MISC_PREEMPTION_TIMER_SHIFT_MASK 0x1Full
+#define MSR_VMX_MISC_STORE_LMA (1ULL << 5)
+#define MSR_VMX_MISC_ACTIVITY_HLT (1ULL << 6)
+#define MSR_VMX_MISC_ACTIVITY_SHUTDOWN (1ULL << 7)
+#define MSR_VMX_MISC_ACTIVITY_WAIT_SIPI (1ULL << 8)
+#define MSR_VMX_MISC_MAX_MSR_LIST_SIZE_MASK 0x0E000000ull
+#define MSR_VMX_MISC_VMWRITE_VMEXIT (1ULL << 29)
+#define MSR_VMX_MISC_ZERO_LEN_INJECT (1ULL << 30)
+
+#define MSR_VMX_EPT_EXECONLY (1ULL << 0)
+#define MSR_VMX_EPT_PAGE_WALK_LENGTH_4 (1ULL << 6)
+#define MSR_VMX_EPT_PAGE_WALK_LENGTH_5 (1ULL << 7)
+#define MSR_VMX_EPT_UC (1ULL << 8)
+#define MSR_VMX_EPT_WB (1ULL << 14)
+#define MSR_VMX_EPT_2MB (1ULL << 16)
+#define MSR_VMX_EPT_1GB (1ULL << 17)
+#define MSR_VMX_EPT_INVEPT (1ULL << 20)
+#define MSR_VMX_EPT_AD_BITS (1ULL << 21)
+#define MSR_VMX_EPT_ADVANCED_VMEXIT_INFO (1ULL << 22)
+#define MSR_VMX_EPT_INVEPT_SINGLE_CONTEXT (1ULL << 25)
+#define MSR_VMX_EPT_INVEPT_ALL_CONTEXT (1ULL << 26)
+#define MSR_VMX_EPT_INVVPID (1ULL << 32)
+#define MSR_VMX_EPT_INVVPID_SINGLE_ADDR (1ULL << 40)
+#define MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT (1ULL << 41)
+#define MSR_VMX_EPT_INVVPID_ALL_CONTEXT (1ULL << 42)
+#define MSR_VMX_EPT_INVVPID_SINGLE_CONTEXT_NOGLOBALS (1ULL << 43)
+
+#define MSR_VMX_VMFUNC_EPT_SWITCHING (1ULL << 0)
+
+
+/* VMX controls */
+#define VMX_CPU_BASED_VIRTUAL_INTR_PENDING 0x00000004
+#define VMX_CPU_BASED_USE_TSC_OFFSETING 0x00000008
+#define VMX_CPU_BASED_HLT_EXITING 0x00000080
+#define VMX_CPU_BASED_INVLPG_EXITING 0x00000200
+#define VMX_CPU_BASED_MWAIT_EXITING 0x00000400
+#define VMX_CPU_BASED_RDPMC_EXITING 0x00000800
+#define VMX_CPU_BASED_RDTSC_EXITING 0x00001000
+#define VMX_CPU_BASED_CR3_LOAD_EXITING 0x00008000
+#define VMX_CPU_BASED_CR3_STORE_EXITING 0x00010000
+#define VMX_CPU_BASED_CR8_LOAD_EXITING 0x00080000
+#define VMX_CPU_BASED_CR8_STORE_EXITING 0x00100000
+#define VMX_CPU_BASED_TPR_SHADOW 0x00200000
+#define VMX_CPU_BASED_VIRTUAL_NMI_PENDING 0x00400000
+#define VMX_CPU_BASED_MOV_DR_EXITING 0x00800000
+#define VMX_CPU_BASED_UNCOND_IO_EXITING 0x01000000
+#define VMX_CPU_BASED_USE_IO_BITMAPS 0x02000000
+#define VMX_CPU_BASED_MONITOR_TRAP_FLAG 0x08000000
+#define VMX_CPU_BASED_USE_MSR_BITMAPS 0x10000000
+#define VMX_CPU_BASED_MONITOR_EXITING 0x20000000
+#define VMX_CPU_BASED_PAUSE_EXITING 0x40000000
+#define VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS 0x80000000
+
+#define VMX_SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES 0x00000001
+#define VMX_SECONDARY_EXEC_ENABLE_EPT 0x00000002
+#define VMX_SECONDARY_EXEC_DESC 0x00000004
+#define VMX_SECONDARY_EXEC_RDTSCP 0x00000008
+#define VMX_SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE 0x00000010
+#define VMX_SECONDARY_EXEC_ENABLE_VPID 0x00000020
+#define VMX_SECONDARY_EXEC_WBINVD_EXITING 0x00000040
+#define VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST 0x00000080
+#define VMX_SECONDARY_EXEC_APIC_REGISTER_VIRT 0x00000100
+#define VMX_SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY 0x00000200
+#define VMX_SECONDARY_EXEC_PAUSE_LOOP_EXITING 0x00000400
+#define VMX_SECONDARY_EXEC_RDRAND_EXITING 0x00000800
+#define VMX_SECONDARY_EXEC_ENABLE_INVPCID 0x00001000
+#define VMX_SECONDARY_EXEC_ENABLE_VMFUNC 0x00002000
+#define VMX_SECONDARY_EXEC_SHADOW_VMCS 0x00004000
+#define VMX_SECONDARY_EXEC_ENCLS_EXITING 0x00008000
+#define VMX_SECONDARY_EXEC_RDSEED_EXITING 0x00010000
+#define VMX_SECONDARY_EXEC_ENABLE_PML 0x00020000
+#define VMX_SECONDARY_EXEC_XSAVES 0x00100000
+
+#define VMX_PIN_BASED_EXT_INTR_MASK 0x00000001
+#define VMX_PIN_BASED_NMI_EXITING 0x00000008
+#define VMX_PIN_BASED_VIRTUAL_NMIS 0x00000020
+#define VMX_PIN_BASED_VMX_PREEMPTION_TIMER 0x00000040
+#define VMX_PIN_BASED_POSTED_INTR 0x00000080
+
+#define VMX_VM_EXIT_SAVE_DEBUG_CONTROLS 0x00000004
+#define VMX_VM_EXIT_HOST_ADDR_SPACE_SIZE 0x00000200
+#define VMX_VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL 0x00001000
+#define VMX_VM_EXIT_ACK_INTR_ON_EXIT 0x00008000
+#define VMX_VM_EXIT_SAVE_IA32_PAT 0x00040000
+#define VMX_VM_EXIT_LOAD_IA32_PAT 0x00080000
+#define VMX_VM_EXIT_SAVE_IA32_EFER 0x00100000
+#define VMX_VM_EXIT_LOAD_IA32_EFER 0x00200000
+#define VMX_VM_EXIT_SAVE_VMX_PREEMPTION_TIMER 0x00400000
+#define VMX_VM_EXIT_CLEAR_BNDCFGS 0x00800000
+#define VMX_VM_EXIT_PT_CONCEAL_PIP 0x01000000
+#define VMX_VM_EXIT_CLEAR_IA32_RTIT_CTL 0x02000000
+
+#define VMX_VM_ENTRY_LOAD_DEBUG_CONTROLS 0x00000004
+#define VMX_VM_ENTRY_IA32E_MODE 0x00000200
+#define VMX_VM_ENTRY_SMM 0x00000400
+#define VMX_VM_ENTRY_DEACT_DUAL_MONITOR 0x00000800
+#define VMX_VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL 0x00002000
+#define VMX_VM_ENTRY_LOAD_IA32_PAT 0x00004000
+#define VMX_VM_ENTRY_LOAD_IA32_EFER 0x00008000
+#define VMX_VM_ENTRY_LOAD_BNDCFGS 0x00010000
+#define VMX_VM_ENTRY_PT_CONCEAL_PIP 0x00020000
+#define VMX_VM_ENTRY_LOAD_IA32_RTIT_CTL 0x00040000
+
/* Supported Hyper-V Enlightenments */
#define HYPERV_FEAT_RELAXED 0
#define HYPERV_FEAT_VAPIC 1
@@ -1549,7 +1741,8 @@ void x86_cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list,
void x86_cpu_dump_state(CPUState *cs, FILE *f, int flags);
-hwaddr x86_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+hwaddr x86_cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr,
+ MemTxAttrs *attrs);
int x86_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int x86_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
diff --git a/target/i386/helper.c b/target/i386/helper.c
index 0fa51be..c3a6e4f 100644
--- a/target/i386/helper.c
+++ b/target/i386/helper.c
@@ -715,7 +715,8 @@ void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
}
#if !defined(CONFIG_USER_ONLY)
-hwaddr x86_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
+hwaddr x86_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr,
+ MemTxAttrs *attrs)
{
X86CPU *cpu = X86_CPU(cs);
CPUX86State *env = &cpu->env;
@@ -725,6 +726,8 @@ hwaddr x86_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
uint32_t page_offset;
int page_size;
+ *attrs = cpu_get_mem_attrs(env);
+
a20_mask = x86_get_a20_mask(env);
if (!(env->cr[0] & CR0_PG_MASK)) {
pte = addr & a20_mask;
diff --git a/target/i386/hvf/x86_cpuid.c b/target/i386/hvf/x86_cpuid.c
index 4d957fe..16762b6 100644
--- a/target/i386/hvf/x86_cpuid.c
+++ b/target/i386/hvf/x86_cpuid.c
@@ -89,7 +89,7 @@ uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx,
ebx &= ~CPUID_7_0_EBX_INVPCID;
}
- ecx &= CPUID_7_0_ECX_AVX512BMI | CPUID_7_0_ECX_AVX512_VPOPCNTDQ;
+ ecx &= CPUID_7_0_ECX_AVX512_VBMI | CPUID_7_0_ECX_AVX512_VPOPCNTDQ;
edx &= CPUID_7_0_EDX_AVX512_4VNNIW | CPUID_7_0_EDX_AVX512_4FMAPS;
} else {
ebx = 0;
diff --git a/target/i386/kvm.c b/target/i386/kvm.c
index 8023c67..8c73438 100644
--- a/target/i386/kvm.c
+++ b/target/i386/kvm.c
@@ -41,6 +41,7 @@
#include "hw/i386/apic-msidef.h"
#include "hw/i386/intel_iommu.h"
#include "hw/i386/x86-iommu.h"
+#include "hw/i386/e820_memory_layout.h"
#include "hw/pci/pci.h"
#include "hw/pci/msi.h"
@@ -99,6 +100,7 @@ static bool has_msr_virt_ssbd;
static bool has_msr_smi_count;
static bool has_msr_arch_capabs;
static bool has_msr_core_capabs;
+static bool has_msr_vmx_vmfunc;
static uint32_t has_architectural_pmu_version;
static uint32_t num_architectural_pmu_gp_counters;
@@ -186,7 +188,7 @@ static int kvm_get_tsc(CPUState *cs)
struct {
struct kvm_msrs info;
struct kvm_msr_entry entries[1];
- } msr_data;
+ } msr_data = {};
int ret;
if (env->tsc_valid) {
@@ -441,13 +443,14 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function,
return ret;
}
-uint32_t kvm_arch_get_supported_msr_feature(KVMState *s, uint32_t index)
+uint64_t kvm_arch_get_supported_msr_feature(KVMState *s, uint32_t index)
{
struct {
struct kvm_msrs info;
struct kvm_msr_entry entries[1];
- } msr_data;
- uint32_t ret;
+ } msr_data = {};
+ uint64_t value;
+ uint32_t ret, can_be_one, must_be_one;
if (kvm_feature_msrs == NULL) { /* Host doesn't support feature MSRs */
return 0;
@@ -473,7 +476,42 @@ uint32_t kvm_arch_get_supported_msr_feature(KVMState *s, uint32_t index)
exit(1);
}
- return msr_data.entries[0].data;
+ value = msr_data.entries[0].data;
+ switch (index) {
+ case MSR_IA32_VMX_PROCBASED_CTLS2:
+ /* KVM forgot to add these bits for some time, do this ourselves. */
+ if (kvm_arch_get_supported_cpuid(s, 0xD, 1, R_ECX) & CPUID_XSAVE_XSAVES) {
+ value |= (uint64_t)VMX_SECONDARY_EXEC_XSAVES << 32;
+ }
+ if (kvm_arch_get_supported_cpuid(s, 1, 0, R_ECX) & CPUID_EXT_RDRAND) {
+ value |= (uint64_t)VMX_SECONDARY_EXEC_RDRAND_EXITING << 32;
+ }
+ if (kvm_arch_get_supported_cpuid(s, 7, 0, R_EBX) & CPUID_7_0_EBX_INVPCID) {
+ value |= (uint64_t)VMX_SECONDARY_EXEC_ENABLE_INVPCID << 32;
+ }
+ if (kvm_arch_get_supported_cpuid(s, 7, 0, R_EBX) & CPUID_7_0_EBX_RDSEED) {
+ value |= (uint64_t)VMX_SECONDARY_EXEC_RDSEED_EXITING << 32;
+ }
+ if (kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_EDX) & CPUID_EXT2_RDTSCP) {
+ value |= (uint64_t)VMX_SECONDARY_EXEC_RDTSCP << 32;
+ }
+ /* fall through */
+ case MSR_IA32_VMX_TRUE_PINBASED_CTLS:
+ case MSR_IA32_VMX_TRUE_PROCBASED_CTLS:
+ case MSR_IA32_VMX_TRUE_ENTRY_CTLS:
+ case MSR_IA32_VMX_TRUE_EXIT_CTLS:
+ /*
+ * Return true for bits that can be one, but do not have to be one.
+ * The SDM tells us which bits could have a "must be one" setting,
+ * so we can do the opposite transformation in make_vmx_msr_value.
+ */
+ must_be_one = (uint32_t)value;
+ can_be_one = (uint32_t)(value >> 32);
+ return can_be_one & ~must_be_one;
+
+ default:
+ return value;
+ }
}
@@ -1529,6 +1567,13 @@ int kvm_arch_init_vcpu(CPUState *cs)
c->function = i;
c->flags = 0;
cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
+ if (!c->eax && !c->ebx && !c->ecx && !c->edx) {
+ /*
+ * KVM already returns all zeroes if a CPUID entry is missing,
+ * so we can omit it and avoid hitting KVM's 80-entry limit.
+ */
+ cpuid_i--;
+ }
break;
}
}
@@ -1593,6 +1638,13 @@ int kvm_arch_init_vcpu(CPUState *cs)
c->function = i;
c->flags = 0;
cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx);
+ if (!c->eax && !c->ebx && !c->ecx && !c->edx) {
+ /*
+ * KVM already returns all zeroes if a CPUID entry is missing,
+ * so we can omit it and avoid hitting KVM's 80-entry limit.
+ */
+ cpuid_i--;
+ }
break;
}
}
@@ -1938,6 +1990,9 @@ static int kvm_get_supported_msrs(KVMState *s)
case MSR_IA32_CORE_CAPABILITY:
has_msr_core_capabs = true;
break;
+ case MSR_IA32_VMX_VMFUNC:
+ has_msr_vmx_vmfunc = true;
+ break;
}
}
}
@@ -2076,7 +2131,8 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
if (disable_exits) {
disable_exits &= (KVM_X86_DISABLE_EXITS_MWAIT |
KVM_X86_DISABLE_EXITS_HLT |
- KVM_X86_DISABLE_EXITS_PAUSE);
+ KVM_X86_DISABLE_EXITS_PAUSE |
+ KVM_X86_DISABLE_EXITS_CSTATE);
}
ret = kvm_vm_enable_cap(s, KVM_CAP_X86_DISABLE_EXITS, 0,
@@ -2411,6 +2467,132 @@ static int kvm_put_msr_feature_control(X86CPU *cpu)
return 0;
}
+static uint64_t make_vmx_msr_value(uint32_t index, uint32_t features)
+{
+ uint32_t default1, can_be_one, can_be_zero;
+ uint32_t must_be_one;
+
+ switch (index) {
+ case MSR_IA32_VMX_TRUE_PINBASED_CTLS:
+ default1 = 0x00000016;
+ break;
+ case MSR_IA32_VMX_TRUE_PROCBASED_CTLS:
+ default1 = 0x0401e172;
+ break;
+ case MSR_IA32_VMX_TRUE_ENTRY_CTLS:
+ default1 = 0x000011ff;
+ break;
+ case MSR_IA32_VMX_TRUE_EXIT_CTLS:
+ default1 = 0x00036dff;
+ break;
+ case MSR_IA32_VMX_PROCBASED_CTLS2:
+ default1 = 0;
+ break;
+ default:
+ abort();
+ }
+
+ /* If a feature bit is set, the control can be either set or clear.
+ * Otherwise the value is limited to either 0 or 1 by default1.
+ */
+ can_be_one = features | default1;
+ can_be_zero = features | ~default1;
+ must_be_one = ~can_be_zero;
+
+ /*
+ * Bit 0:31 -> 0 if the control bit can be zero (i.e. 1 if it must be one).
+ * Bit 32:63 -> 1 if the control bit can be one.
+ */
+ return must_be_one | (((uint64_t)can_be_one) << 32);
+}
+
+#define VMCS12_MAX_FIELD_INDEX (0x17)
+
+static void kvm_msr_entry_add_vmx(X86CPU *cpu, FeatureWordArray f)
+{
+ uint64_t kvm_vmx_basic =
+ kvm_arch_get_supported_msr_feature(kvm_state,
+ MSR_IA32_VMX_BASIC);
+ uint64_t kvm_vmx_misc =
+ kvm_arch_get_supported_msr_feature(kvm_state,
+ MSR_IA32_VMX_MISC);
+ uint64_t kvm_vmx_ept_vpid =
+ kvm_arch_get_supported_msr_feature(kvm_state,
+ MSR_IA32_VMX_EPT_VPID_CAP);
+
+ /*
+ * If the guest is 64-bit, a value of 1 is allowed for the host address
+ * space size vmexit control.
+ */
+ uint64_t fixed_vmx_exit = f[FEAT_8000_0001_EDX] & CPUID_EXT2_LM
+ ? (uint64_t)VMX_VM_EXIT_HOST_ADDR_SPACE_SIZE << 32 : 0;
+
+ /*
+ * Bits 0-30, 32-44 and 50-53 come from the host. KVM should
+ * not change them for backwards compatibility.
+ */
+ uint64_t fixed_vmx_basic = kvm_vmx_basic &
+ (MSR_VMX_BASIC_VMCS_REVISION_MASK |
+ MSR_VMX_BASIC_VMXON_REGION_SIZE_MASK |
+ MSR_VMX_BASIC_VMCS_MEM_TYPE_MASK);
+
+ /*
+ * Same for bits 0-4 and 25-27. Bits 16-24 (CR3 target count) can
+ * change in the future but are always zero for now, clear them to be
+ * future proof. Bits 32-63 in theory could change, though KVM does
+ * not support dual-monitor treatment and probably never will; mask
+ * them out as well.
+ */
+ uint64_t fixed_vmx_misc = kvm_vmx_misc &
+ (MSR_VMX_MISC_PREEMPTION_TIMER_SHIFT_MASK |
+ MSR_VMX_MISC_MAX_MSR_LIST_SIZE_MASK);
+
+ /*
+ * EPT memory types should not change either, so we do not bother
+ * adding features for them.
+ */
+ uint64_t fixed_vmx_ept_mask =
+ (f[FEAT_VMX_SECONDARY_CTLS] & VMX_SECONDARY_EXEC_ENABLE_EPT ?
+ MSR_VMX_EPT_UC | MSR_VMX_EPT_WB : 0);
+ uint64_t fixed_vmx_ept_vpid = kvm_vmx_ept_vpid & fixed_vmx_ept_mask;
+
+ kvm_msr_entry_add(cpu, MSR_IA32_VMX_TRUE_PROCBASED_CTLS,
+ make_vmx_msr_value(MSR_IA32_VMX_TRUE_PROCBASED_CTLS,
+ f[FEAT_VMX_PROCBASED_CTLS]));
+ kvm_msr_entry_add(cpu, MSR_IA32_VMX_TRUE_PINBASED_CTLS,
+ make_vmx_msr_value(MSR_IA32_VMX_TRUE_PINBASED_CTLS,
+ f[FEAT_VMX_PINBASED_CTLS]));
+ kvm_msr_entry_add(cpu, MSR_IA32_VMX_TRUE_EXIT_CTLS,
+ make_vmx_msr_value(MSR_IA32_VMX_TRUE_EXIT_CTLS,
+ f[FEAT_VMX_EXIT_CTLS]) | fixed_vmx_exit);
+ kvm_msr_entry_add(cpu, MSR_IA32_VMX_TRUE_ENTRY_CTLS,
+ make_vmx_msr_value(MSR_IA32_VMX_TRUE_ENTRY_CTLS,
+ f[FEAT_VMX_ENTRY_CTLS]));
+ kvm_msr_entry_add(cpu, MSR_IA32_VMX_PROCBASED_CTLS2,
+ make_vmx_msr_value(MSR_IA32_VMX_PROCBASED_CTLS2,
+ f[FEAT_VMX_SECONDARY_CTLS]));
+ kvm_msr_entry_add(cpu, MSR_IA32_VMX_EPT_VPID_CAP,
+ f[FEAT_VMX_EPT_VPID_CAPS] | fixed_vmx_ept_vpid);
+ kvm_msr_entry_add(cpu, MSR_IA32_VMX_BASIC,
+ f[FEAT_VMX_BASIC] | fixed_vmx_basic);
+ kvm_msr_entry_add(cpu, MSR_IA32_VMX_MISC,
+ f[FEAT_VMX_MISC] | fixed_vmx_misc);
+ if (has_msr_vmx_vmfunc) {
+ kvm_msr_entry_add(cpu, MSR_IA32_VMX_VMFUNC, f[FEAT_VMX_VMFUNC]);
+ }
+
+ /*
+ * Just to be safe, write these with constant values. The CRn_FIXED1
+ * MSRs are generated by KVM based on the vCPU's CPUID.
+ */
+ kvm_msr_entry_add(cpu, MSR_IA32_VMX_CR0_FIXED0,
+ CR0_PE_MASK | CR0_PG_MASK | CR0_NE_MASK);
+ kvm_msr_entry_add(cpu, MSR_IA32_VMX_CR4_FIXED0,
+ CR4_VMXE_MASK);
+ kvm_msr_entry_add(cpu, MSR_IA32_VMX_VMCS_ENUM,
+ VMCS12_MAX_FIELD_INDEX << 1);
+}
+
static int kvm_put_msrs(X86CPU *cpu, int level)
{
CPUX86State *env = &cpu->env;
@@ -2655,7 +2837,16 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
/* Note: MSR_IA32_FEATURE_CONTROL is written separately, see
* kvm_put_msr_feature_control. */
+
+ /*
+ * Older kernels do not include VMX MSRs in KVM_GET_MSR_INDEX_LIST, but
+ * all kernels with MSR features should have them.
+ */
+ if (kvm_feature_msrs && cpu_has_vmx(env)) {
+ kvm_msr_entry_add_vmx(cpu, env->features);
+ }
}
+
if (env->mcg_cap) {
int i;
diff --git a/target/i386/whpx-all.c b/target/i386/whpx-all.c
index 0c15241..def0c28 100644
--- a/target/i386/whpx-all.c
+++ b/target/i386/whpx-all.c
@@ -18,6 +18,7 @@
#include "sysemu/cpus.h"
#include "sysemu/runstate.h"
#include "qemu/main-loop.h"
+#include "hw/boards.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "migration/blocker.h"
diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c
index 9b039c8..4137542 100644
--- a/target/m68k/fpu_helper.c
+++ b/target/m68k/fpu_helper.c
@@ -396,14 +396,14 @@ typedef int (*float_access)(CPUM68KState *env, uint32_t addr, FPReg *fp,
uintptr_t ra);
static uint32_t fmovem_predec(CPUM68KState *env, uint32_t addr, uint32_t mask,
- float_access access)
+ float_access access_fn)
{
uintptr_t ra = GETPC();
int i, size;
for (i = 7; i >= 0; i--, mask <<= 1) {
if (mask & 0x80) {
- size = access(env, addr, &env->fregs[i], ra);
+ size = access_fn(env, addr, &env->fregs[i], ra);
if ((mask & 0xff) != 0x80) {
addr -= size;
}
@@ -414,14 +414,14 @@ static uint32_t fmovem_predec(CPUM68KState *env, uint32_t addr, uint32_t mask,
}
static uint32_t fmovem_postinc(CPUM68KState *env, uint32_t addr, uint32_t mask,
- float_access access)
+ float_access access_fn)
{
uintptr_t ra = GETPC();
int i, size;
for (i = 0; i < 8; i++, mask <<= 1) {
if (mask & 0x80) {
- size = access(env, addr, &env->fregs[i], ra);
+ size = access_fn(env, addr, &env->fregs[i], ra);
addr += size;
}
}
diff --git a/target/mips/cpu.c b/target/mips/cpu.c
index 3ffa342..bbcf7ca 100644
--- a/target/mips/cpu.c
+++ b/target/mips/cpu.c
@@ -202,7 +202,7 @@ static void mips_cpu_class_init(ObjectClass *c, void *data)
cc->gdb_read_register = mips_cpu_gdb_read_register;
cc->gdb_write_register = mips_cpu_gdb_write_register;
#ifndef CONFIG_USER_ONLY
- cc->do_unassigned_access = mips_cpu_unassigned_access;
+ cc->do_transaction_failed = mips_cpu_do_transaction_failed;
cc->do_unaligned_access = mips_cpu_do_unaligned_access;
cc->get_phys_page_debug = mips_cpu_get_phys_page_debug;
cc->vmsd = &vmstate_mips_cpu;
diff --git a/target/mips/gdbstub.c b/target/mips/gdbstub.c
index ebcc98b..bbb2544 100644
--- a/target/mips/gdbstub.c
+++ b/target/mips/gdbstub.c
@@ -38,7 +38,7 @@ int mips_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
return gdb_get_regl(mem_buf, (int32_t)env->active_fpu.fcr0);
default:
if (env->CP0_Status & (1 << CP0St_FR)) {
- return gdb_get_reg64(mem_buf,
+ return gdb_get_regl(mem_buf,
env->active_fpu.fpr[n - 38].d);
} else {
return gdb_get_regl(mem_buf,
@@ -99,7 +99,6 @@ int mips_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
break;
default:
if (env->CP0_Status & (1 << CP0St_FR)) {
- uint64_t tmp = ldq_p(mem_buf);
env->active_fpu.fpr[n - 38].d = tmp;
} else {
env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX] = tmp;
diff --git a/target/mips/helper.h b/target/mips/helper.h
index 51f0e1c..d615c83 100644
--- a/target/mips/helper.h
+++ b/target/mips/helper.h
@@ -777,6 +777,123 @@ DEF_HELPER_FLAGS_3(wrdsp, 0, void, tl, tl, env)
DEF_HELPER_FLAGS_2(rddsp, 0, tl, tl, env)
/* MIPS SIMD Architecture */
+
+DEF_HELPER_3(msa_nloc_b, void, env, i32, i32)
+DEF_HELPER_3(msa_nloc_h, void, env, i32, i32)
+DEF_HELPER_3(msa_nloc_w, void, env, i32, i32)
+DEF_HELPER_3(msa_nloc_d, void, env, i32, i32)
+
+DEF_HELPER_3(msa_nlzc_b, void, env, i32, i32)
+DEF_HELPER_3(msa_nlzc_h, void, env, i32, i32)
+DEF_HELPER_3(msa_nlzc_w, void, env, i32, i32)
+DEF_HELPER_3(msa_nlzc_d, void, env, i32, i32)
+
+DEF_HELPER_3(msa_pcnt_b, void, env, i32, i32)
+DEF_HELPER_3(msa_pcnt_h, void, env, i32, i32)
+DEF_HELPER_3(msa_pcnt_w, void, env, i32, i32)
+DEF_HELPER_3(msa_pcnt_d, void, env, i32, i32)
+
+DEF_HELPER_4(msa_binsl_b, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_binsl_h, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_binsl_w, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_binsl_d, void, env, i32, i32, i32)
+
+DEF_HELPER_4(msa_binsr_b, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_binsr_h, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_binsr_w, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_binsr_d, void, env, i32, i32, i32)
+
+DEF_HELPER_4(msa_bmnz_v, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_bmz_v, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_bsel_v, void, env, i32, i32, i32)
+
+DEF_HELPER_4(msa_bclr_b, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_bclr_h, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_bclr_w, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_bclr_d, void, env, i32, i32, i32)
+
+DEF_HELPER_4(msa_bneg_b, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_bneg_h, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_bneg_w, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_bneg_d, void, env, i32, i32, i32)
+
+DEF_HELPER_4(msa_bset_b, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_bset_h, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_bset_w, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_bset_d, void, env, i32, i32, i32)
+
+DEF_HELPER_4(msa_ave_s_b, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_ave_s_h, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_ave_s_w, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_ave_s_d, void, env, i32, i32, i32)
+
+DEF_HELPER_4(msa_ave_u_b, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_ave_u_h, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_ave_u_w, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_ave_u_d, void, env, i32, i32, i32)
+
+DEF_HELPER_4(msa_aver_s_b, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_aver_s_h, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_aver_s_w, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_aver_s_d, void, env, i32, i32, i32)
+
+DEF_HELPER_4(msa_aver_u_b, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_aver_u_h, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_aver_u_w, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_aver_u_d, void, env, i32, i32, i32)
+
+DEF_HELPER_4(msa_ceq_b, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_ceq_h, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_ceq_w, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_ceq_d, void, env, i32, i32, i32)
+
+DEF_HELPER_4(msa_cle_s_b, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_cle_s_h, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_cle_s_w, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_cle_s_d, void, env, i32, i32, i32)
+
+DEF_HELPER_4(msa_cle_u_b, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_cle_u_h, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_cle_u_w, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_cle_u_d, void, env, i32, i32, i32)
+
+DEF_HELPER_4(msa_clt_s_b, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_clt_s_h, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_clt_s_w, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_clt_s_d, void, env, i32, i32, i32)
+
+DEF_HELPER_4(msa_clt_u_b, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_clt_u_h, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_clt_u_w, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_clt_u_d, void, env, i32, i32, i32)
+
+DEF_HELPER_4(msa_div_s_b, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_div_s_h, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_div_s_w, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_div_s_d, void, env, i32, i32, i32)
+
+DEF_HELPER_4(msa_div_u_b, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_div_u_h, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_div_u_w, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_div_u_d, void, env, i32, i32, i32)
+
+DEF_HELPER_4(msa_mod_u_b, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_mod_u_h, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_mod_u_w, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_mod_u_d, void, env, i32, i32, i32)
+
+DEF_HELPER_4(msa_mod_s_b, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_mod_s_h, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_mod_s_w, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_mod_s_d, void, env, i32, i32, i32)
+
+DEF_HELPER_4(msa_and_v, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_nor_v, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_or_v, void, env, i32, i32, i32)
+DEF_HELPER_4(msa_xor_v, void, env, i32, i32, i32)
+
+DEF_HELPER_3(msa_move_v, void, env, i32, i32)
+
DEF_HELPER_4(msa_andi_b, void, env, i32, i32, i32)
DEF_HELPER_4(msa_ori_b, void, env, i32, i32, i32)
DEF_HELPER_4(msa_nori_b, void, env, i32, i32, i32)
@@ -815,9 +932,6 @@ DEF_HELPER_5(msa_srlri_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_sll_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_sra_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_srl_df, void, env, i32, i32, i32, i32)
-DEF_HELPER_5(msa_bclr_df, void, env, i32, i32, i32, i32)
-DEF_HELPER_5(msa_bset_df, void, env, i32, i32, i32, i32)
-DEF_HELPER_5(msa_bneg_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_binsl_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_binsr_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_addv_df, void, env, i32, i32, i32, i32)
@@ -828,19 +942,10 @@ DEF_HELPER_5(msa_min_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_min_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_max_a_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_min_a_df, void, env, i32, i32, i32, i32)
-DEF_HELPER_5(msa_ceq_df, void, env, i32, i32, i32, i32)
-DEF_HELPER_5(msa_clt_s_df, void, env, i32, i32, i32, i32)
-DEF_HELPER_5(msa_clt_u_df, void, env, i32, i32, i32, i32)
-DEF_HELPER_5(msa_cle_s_df, void, env, i32, i32, i32, i32)
-DEF_HELPER_5(msa_cle_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_add_a_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_adds_a_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_adds_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_adds_u_df, void, env, i32, i32, i32, i32)
-DEF_HELPER_5(msa_ave_s_df, void, env, i32, i32, i32, i32)
-DEF_HELPER_5(msa_ave_u_df, void, env, i32, i32, i32, i32)
-DEF_HELPER_5(msa_aver_s_df, void, env, i32, i32, i32, i32)
-DEF_HELPER_5(msa_aver_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_subs_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_subs_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_subsus_u_df, void, env, i32, i32, i32, i32)
@@ -850,10 +955,6 @@ DEF_HELPER_5(msa_asub_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_mulv_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_maddv_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_msubv_df, void, env, i32, i32, i32, i32)
-DEF_HELPER_5(msa_div_s_df, void, env, i32, i32, i32, i32)
-DEF_HELPER_5(msa_div_u_df, void, env, i32, i32, i32, i32)
-DEF_HELPER_5(msa_mod_s_df, void, env, i32, i32, i32, i32)
-DEF_HELPER_5(msa_mod_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_dotp_s_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_dotp_u_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_dpadd_s_df, void, env, i32, i32, i32, i32)
@@ -882,7 +983,6 @@ DEF_HELPER_5(msa_splati_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_insve_df, void, env, i32, i32, i32, i32)
DEF_HELPER_3(msa_ctcmsa, void, env, tl, i32)
DEF_HELPER_2(msa_cfcmsa, tl, env, i32)
-DEF_HELPER_3(msa_move_v, void, env, i32, i32)
DEF_HELPER_5(msa_fcaf_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_fcun_df, void, env, i32, i32, i32, i32)
@@ -926,17 +1026,7 @@ DEF_HELPER_5(msa_mulr_q_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_maddr_q_df, void, env, i32, i32, i32, i32)
DEF_HELPER_5(msa_msubr_q_df, void, env, i32, i32, i32, i32)
-DEF_HELPER_4(msa_and_v, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_or_v, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_nor_v, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_xor_v, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_bmnz_v, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_bmz_v, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_bsel_v, void, env, i32, i32, i32)
DEF_HELPER_4(msa_fill_df, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_pcnt_df, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_nloc_df, void, env, i32, i32, i32)
-DEF_HELPER_4(msa_nlzc_df, void, env, i32, i32, i32)
DEF_HELPER_4(msa_copy_s_b, void, env, i32, i32, i32)
DEF_HELPER_4(msa_copy_s_h, void, env, i32, i32, i32)
diff --git a/target/mips/internal.h b/target/mips/internal.h
index ae29b57..3f435b5 100644
--- a/target/mips/internal.h
+++ b/target/mips/internal.h
@@ -1,4 +1,5 @@
-/* mips internal definitions and helpers
+/*
+ * MIPS internal definitions and helpers
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
@@ -9,8 +10,10 @@
#include "fpu/softfloat-helpers.h"
-/* MMU types, the first four entries have the same layout as the
- CP0C0_MT field. */
+/*
+ * MMU types, the first four entries have the same layout as the
+ * CP0C0_MT field.
+ */
enum mips_mmu_types {
MMU_TYPE_NONE,
MMU_TYPE_R4000,
@@ -139,9 +142,11 @@ void r4k_helper_tlbinv(CPUMIPSState *env);
void r4k_helper_tlbinvf(CPUMIPSState *env);
void r4k_invalidate_tlb(CPUMIPSState *env, int idx, int use_extra);
-void mips_cpu_unassigned_access(CPUState *cpu, hwaddr addr,
- bool is_write, bool is_exec, int unused,
- unsigned size);
+void mips_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
+ vaddr addr, unsigned size,
+ MMUAccessType access_type,
+ int mmu_idx, MemTxAttrs attrs,
+ MemTxResult response, uintptr_t retaddr);
hwaddr cpu_mips_translate_address(CPUMIPSState *env, target_ulong address,
int rw);
#endif
@@ -158,9 +163,11 @@ static inline bool cpu_mips_hw_interrupts_enabled(CPUMIPSState *env)
!(env->CP0_Status & (1 << CP0St_EXL)) &&
!(env->CP0_Status & (1 << CP0St_ERL)) &&
!(env->hflags & MIPS_HFLAG_DM) &&
- /* Note that the TCStatus IXMT field is initialized to zero,
- and only MT capable cores can set it to one. So we don't
- need to check for MT capabilities here. */
+ /*
+ * Note that the TCStatus IXMT field is initialized to zero,
+ * and only MT capable cores can set it to one. So we don't
+ * need to check for MT capabilities here.
+ */
!(env->active_tc.CP0_TCStatus & (1 << CP0TCSt_IXMT));
}
@@ -175,14 +182,18 @@ static inline bool cpu_mips_hw_interrupts_pending(CPUMIPSState *env)
status = env->CP0_Status & CP0Ca_IP_mask;
if (env->CP0_Config3 & (1 << CP0C3_VEIC)) {
- /* A MIPS configured with a vectorizing external interrupt controller
- will feed a vector into the Cause pending lines. The core treats
- the status lines as a vector level, not as indiviual masks. */
+ /*
+ * A MIPS configured with a vectorizing external interrupt controller
+ * will feed a vector into the Cause pending lines. The core treats
+ * the status lines as a vector level, not as indiviual masks.
+ */
r = pending > status;
} else {
- /* A MIPS configured with compatibility or VInt (Vectored Interrupts)
- treats the pending lines as individual interrupt lines, the status
- lines are individual masks. */
+ /*
+ * A MIPS configured with compatibility or VInt (Vectored Interrupts)
+ * treats the pending lines as individual interrupt lines, the status
+ * lines are individual masks.
+ */
r = (pending & status) != 0;
}
return r;
@@ -273,12 +284,14 @@ static inline int mips_vpe_active(CPUMIPSState *env)
active = 0;
}
- /* Now verify that there are active thread contexts in the VPE.
-
- This assumes the CPU model will internally reschedule threads
- if the active one goes to sleep. If there are no threads available
- the active one will be in a sleeping state, and we can turn off
- the entire VPE. */
+ /*
+ * Now verify that there are active thread contexts in the VPE.
+ *
+ * This assumes the CPU model will internally reschedule threads
+ * if the active one goes to sleep. If there are no threads available
+ * the active one will be in a sleeping state, and we can turn off
+ * the entire VPE.
+ */
if (!(env->active_tc.CP0_TCStatus & (1 << CP0TCSt_A))) {
/* TC is not activated. */
active = 0;
@@ -324,7 +337,8 @@ static inline void compute_hflags(CPUMIPSState *env)
if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
!(env->CP0_Status & (1 << CP0St_ERL)) &&
!(env->hflags & MIPS_HFLAG_DM)) {
- env->hflags |= (env->CP0_Status >> CP0St_KSU) & MIPS_HFLAG_KSU;
+ env->hflags |= (env->CP0_Status >> CP0St_KSU) &
+ MIPS_HFLAG_KSU;
}
#if defined(TARGET_MIPS64)
if ((env->insn_flags & ISA_MIPS3) &&
@@ -401,10 +415,12 @@ static inline void compute_hflags(CPUMIPSState *env)
env->hflags |= MIPS_HFLAG_COP1X;
}
} else if (env->insn_flags & ISA_MIPS4) {
- /* All supported MIPS IV CPUs use the XX (CU3) to enable
- and disable the MIPS IV extensions to the MIPS III ISA.
- Some other MIPS IV CPUs ignore the bit, so the check here
- would be too restrictive for them. */
+ /*
+ * All supported MIPS IV CPUs use the XX (CU3) to enable
+ * and disable the MIPS IV extensions to the MIPS III ISA.
+ * Some other MIPS IV CPUs ignore the bit, so the check here
+ * would be too restrictive for them.
+ */
if (env->CP0_Status & (1U << CP0St_CU3)) {
env->hflags |= MIPS_HFLAG_COP1X;
}
diff --git a/target/mips/kvm_mips.h b/target/mips/kvm_mips.h
index ae957f3..1e40147 100644
--- a/target/mips/kvm_mips.h
+++ b/target/mips/kvm_mips.h
@@ -7,7 +7,7 @@
*
* Copyright (C) 2012-2014 Imagination Technologies Ltd.
* Authors: Sanjay Lal <sanjayl@kymasys.com>
-*/
+ */
#ifndef KVM_MIPS_H
#define KVM_MIPS_H
diff --git a/target/mips/mips-defs.h b/target/mips/mips-defs.h
index bbf056a..a831bb4 100644
--- a/target/mips/mips-defs.h
+++ b/target/mips/mips-defs.h
@@ -1,8 +1,11 @@
#ifndef QEMU_MIPS_DEFS_H
#define QEMU_MIPS_DEFS_H
-/* If we want to use host float regs... */
-//#define USE_HOST_FLOAT_REGS
+/*
+ * If we want to use host float regs...
+ *
+ * #define USE_HOST_FLOAT_REGS
+ */
/* Real pages are variable size... */
#define MIPS_TLB_MAX 128
@@ -57,43 +60,46 @@
#define ASE_MXU 0x0200000000000000ULL
/* MIPS CPU defines. */
-#define CPU_MIPS1 (ISA_MIPS1)
-#define CPU_MIPS2 (CPU_MIPS1 | ISA_MIPS2)
-#define CPU_MIPS3 (CPU_MIPS2 | ISA_MIPS3)
-#define CPU_MIPS4 (CPU_MIPS3 | ISA_MIPS4)
-#define CPU_VR54XX (CPU_MIPS4 | INSN_VR54XX)
-#define CPU_R5900 (CPU_MIPS3 | INSN_R5900)
-#define CPU_LOONGSON2E (CPU_MIPS3 | INSN_LOONGSON2E)
-#define CPU_LOONGSON2F (CPU_MIPS3 | INSN_LOONGSON2F)
+#define CPU_MIPS1 (ISA_MIPS1)
+#define CPU_MIPS2 (CPU_MIPS1 | ISA_MIPS2)
+#define CPU_MIPS3 (CPU_MIPS2 | ISA_MIPS3)
+#define CPU_MIPS4 (CPU_MIPS3 | ISA_MIPS4)
+#define CPU_VR54XX (CPU_MIPS4 | INSN_VR54XX)
+#define CPU_R5900 (CPU_MIPS3 | INSN_R5900)
+#define CPU_LOONGSON2E (CPU_MIPS3 | INSN_LOONGSON2E)
+#define CPU_LOONGSON2F (CPU_MIPS3 | INSN_LOONGSON2F)
-#define CPU_MIPS5 (CPU_MIPS4 | ISA_MIPS5)
+#define CPU_MIPS5 (CPU_MIPS4 | ISA_MIPS5)
/* MIPS Technologies "Release 1" */
-#define CPU_MIPS32 (CPU_MIPS2 | ISA_MIPS32)
-#define CPU_MIPS64 (CPU_MIPS5 | CPU_MIPS32 | ISA_MIPS64)
+#define CPU_MIPS32 (CPU_MIPS2 | ISA_MIPS32)
+#define CPU_MIPS64 (CPU_MIPS5 | CPU_MIPS32 | ISA_MIPS64)
/* MIPS Technologies "Release 2" */
-#define CPU_MIPS32R2 (CPU_MIPS32 | ISA_MIPS32R2)
-#define CPU_MIPS64R2 (CPU_MIPS64 | CPU_MIPS32R2 | ISA_MIPS64R2)
+#define CPU_MIPS32R2 (CPU_MIPS32 | ISA_MIPS32R2)
+#define CPU_MIPS64R2 (CPU_MIPS64 | CPU_MIPS32R2 | ISA_MIPS64R2)
/* MIPS Technologies "Release 3" */
-#define CPU_MIPS32R3 (CPU_MIPS32R2 | ISA_MIPS32R3)
-#define CPU_MIPS64R3 (CPU_MIPS64R2 | CPU_MIPS32R3 | ISA_MIPS64R3)
+#define CPU_MIPS32R3 (CPU_MIPS32R2 | ISA_MIPS32R3)
+#define CPU_MIPS64R3 (CPU_MIPS64R2 | CPU_MIPS32R3 | ISA_MIPS64R3)
/* MIPS Technologies "Release 5" */
-#define CPU_MIPS32R5 (CPU_MIPS32R3 | ISA_MIPS32R5)
-#define CPU_MIPS64R5 (CPU_MIPS64R3 | CPU_MIPS32R5 | ISA_MIPS64R5)
+#define CPU_MIPS32R5 (CPU_MIPS32R3 | ISA_MIPS32R5)
+#define CPU_MIPS64R5 (CPU_MIPS64R3 | CPU_MIPS32R5 | ISA_MIPS64R5)
/* MIPS Technologies "Release 6" */
-#define CPU_MIPS32R6 (CPU_MIPS32R5 | ISA_MIPS32R6)
-#define CPU_MIPS64R6 (CPU_MIPS64R5 | CPU_MIPS32R6 | ISA_MIPS64R6)
+#define CPU_MIPS32R6 (CPU_MIPS32R5 | ISA_MIPS32R6)
+#define CPU_MIPS64R6 (CPU_MIPS64R5 | CPU_MIPS32R6 | ISA_MIPS64R6)
/* Wave Computing: "nanoMIPS" */
-#define CPU_NANOMIPS32 (CPU_MIPS32R6 | ISA_NANOMIPS32)
+#define CPU_NANOMIPS32 (CPU_MIPS32R6 | ISA_NANOMIPS32)
-/* Strictly follow the architecture standard:
- - Disallow "special" instruction handling for PMON/SPIM.
- Note that we still maintain Count/Compare to match the host clock. */
-//#define MIPS_STRICT_STANDARD 1
+/*
+ * Strictly follow the architecture standard:
+ * - Disallow "special" instruction handling for PMON/SPIM.
+ * Note that we still maintain Count/Compare to match the host clock.
+ *
+ * #define MIPS_STRICT_STANDARD 1
+ */
#endif /* QEMU_MIPS_DEFS_H */
diff --git a/target/mips/msa_helper.c b/target/mips/msa_helper.c
index f24061e..a2052ba 100644
--- a/target/mips/msa_helper.c
+++ b/target/mips/msa_helper.c
@@ -65,7 +65,221 @@
* +---------------+----------------------------------------------------------+
*/
-/* TODO: insert Bit Count group helpers here */
+static inline int64_t msa_nlzc_df(uint32_t df, int64_t arg)
+{
+ uint64_t x, y;
+ int n, c;
+
+ x = UNSIGNED(arg, df);
+ n = DF_BITS(df);
+ c = DF_BITS(df) / 2;
+
+ do {
+ y = x >> c;
+ if (y != 0) {
+ n = n - c;
+ x = y;
+ }
+ c = c >> 1;
+ } while (c != 0);
+
+ return n - x;
+}
+
+static inline int64_t msa_nloc_df(uint32_t df, int64_t arg)
+{
+ return msa_nlzc_df(df, UNSIGNED((~arg), df));
+}
+
+void helper_msa_nloc_b(CPUMIPSState *env, uint32_t wd, uint32_t ws)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+
+ pwd->b[0] = msa_nloc_df(DF_BYTE, pws->b[0]);
+ pwd->b[1] = msa_nloc_df(DF_BYTE, pws->b[1]);
+ pwd->b[2] = msa_nloc_df(DF_BYTE, pws->b[2]);
+ pwd->b[3] = msa_nloc_df(DF_BYTE, pws->b[3]);
+ pwd->b[4] = msa_nloc_df(DF_BYTE, pws->b[4]);
+ pwd->b[5] = msa_nloc_df(DF_BYTE, pws->b[5]);
+ pwd->b[6] = msa_nloc_df(DF_BYTE, pws->b[6]);
+ pwd->b[7] = msa_nloc_df(DF_BYTE, pws->b[7]);
+ pwd->b[8] = msa_nloc_df(DF_BYTE, pws->b[8]);
+ pwd->b[9] = msa_nloc_df(DF_BYTE, pws->b[9]);
+ pwd->b[10] = msa_nloc_df(DF_BYTE, pws->b[10]);
+ pwd->b[11] = msa_nloc_df(DF_BYTE, pws->b[11]);
+ pwd->b[12] = msa_nloc_df(DF_BYTE, pws->b[12]);
+ pwd->b[13] = msa_nloc_df(DF_BYTE, pws->b[13]);
+ pwd->b[14] = msa_nloc_df(DF_BYTE, pws->b[14]);
+ pwd->b[15] = msa_nloc_df(DF_BYTE, pws->b[15]);
+}
+
+void helper_msa_nloc_h(CPUMIPSState *env, uint32_t wd, uint32_t ws)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+
+ pwd->h[0] = msa_nloc_df(DF_HALF, pws->h[0]);
+ pwd->h[1] = msa_nloc_df(DF_HALF, pws->h[1]);
+ pwd->h[2] = msa_nloc_df(DF_HALF, pws->h[2]);
+ pwd->h[3] = msa_nloc_df(DF_HALF, pws->h[3]);
+ pwd->h[4] = msa_nloc_df(DF_HALF, pws->h[4]);
+ pwd->h[5] = msa_nloc_df(DF_HALF, pws->h[5]);
+ pwd->h[6] = msa_nloc_df(DF_HALF, pws->h[6]);
+ pwd->h[7] = msa_nloc_df(DF_HALF, pws->h[7]);
+}
+
+void helper_msa_nloc_w(CPUMIPSState *env, uint32_t wd, uint32_t ws)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+
+ pwd->w[0] = msa_nloc_df(DF_WORD, pws->w[0]);
+ pwd->w[1] = msa_nloc_df(DF_WORD, pws->w[1]);
+ pwd->w[2] = msa_nloc_df(DF_WORD, pws->w[2]);
+ pwd->w[3] = msa_nloc_df(DF_WORD, pws->w[3]);
+}
+
+void helper_msa_nloc_d(CPUMIPSState *env, uint32_t wd, uint32_t ws)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+
+ pwd->d[0] = msa_nloc_df(DF_DOUBLE, pws->d[0]);
+ pwd->d[1] = msa_nloc_df(DF_DOUBLE, pws->d[1]);
+}
+
+void helper_msa_nlzc_b(CPUMIPSState *env, uint32_t wd, uint32_t ws)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+
+ pwd->b[0] = msa_nlzc_df(DF_BYTE, pws->b[0]);
+ pwd->b[1] = msa_nlzc_df(DF_BYTE, pws->b[1]);
+ pwd->b[2] = msa_nlzc_df(DF_BYTE, pws->b[2]);
+ pwd->b[3] = msa_nlzc_df(DF_BYTE, pws->b[3]);
+ pwd->b[4] = msa_nlzc_df(DF_BYTE, pws->b[4]);
+ pwd->b[5] = msa_nlzc_df(DF_BYTE, pws->b[5]);
+ pwd->b[6] = msa_nlzc_df(DF_BYTE, pws->b[6]);
+ pwd->b[7] = msa_nlzc_df(DF_BYTE, pws->b[7]);
+ pwd->b[8] = msa_nlzc_df(DF_BYTE, pws->b[8]);
+ pwd->b[9] = msa_nlzc_df(DF_BYTE, pws->b[9]);
+ pwd->b[10] = msa_nlzc_df(DF_BYTE, pws->b[10]);
+ pwd->b[11] = msa_nlzc_df(DF_BYTE, pws->b[11]);
+ pwd->b[12] = msa_nlzc_df(DF_BYTE, pws->b[12]);
+ pwd->b[13] = msa_nlzc_df(DF_BYTE, pws->b[13]);
+ pwd->b[14] = msa_nlzc_df(DF_BYTE, pws->b[14]);
+ pwd->b[15] = msa_nlzc_df(DF_BYTE, pws->b[15]);
+}
+
+void helper_msa_nlzc_h(CPUMIPSState *env, uint32_t wd, uint32_t ws)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+
+ pwd->h[0] = msa_nlzc_df(DF_HALF, pws->h[0]);
+ pwd->h[1] = msa_nlzc_df(DF_HALF, pws->h[1]);
+ pwd->h[2] = msa_nlzc_df(DF_HALF, pws->h[2]);
+ pwd->h[3] = msa_nlzc_df(DF_HALF, pws->h[3]);
+ pwd->h[4] = msa_nlzc_df(DF_HALF, pws->h[4]);
+ pwd->h[5] = msa_nlzc_df(DF_HALF, pws->h[5]);
+ pwd->h[6] = msa_nlzc_df(DF_HALF, pws->h[6]);
+ pwd->h[7] = msa_nlzc_df(DF_HALF, pws->h[7]);
+}
+
+void helper_msa_nlzc_w(CPUMIPSState *env, uint32_t wd, uint32_t ws)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+
+ pwd->w[0] = msa_nlzc_df(DF_WORD, pws->w[0]);
+ pwd->w[1] = msa_nlzc_df(DF_WORD, pws->w[1]);
+ pwd->w[2] = msa_nlzc_df(DF_WORD, pws->w[2]);
+ pwd->w[3] = msa_nlzc_df(DF_WORD, pws->w[3]);
+}
+
+void helper_msa_nlzc_d(CPUMIPSState *env, uint32_t wd, uint32_t ws)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+
+ pwd->d[0] = msa_nlzc_df(DF_DOUBLE, pws->d[0]);
+ pwd->d[1] = msa_nlzc_df(DF_DOUBLE, pws->d[1]);
+}
+
+static inline int64_t msa_pcnt_df(uint32_t df, int64_t arg)
+{
+ uint64_t x;
+
+ x = UNSIGNED(arg, df);
+
+ x = (x & 0x5555555555555555ULL) + ((x >> 1) & 0x5555555555555555ULL);
+ x = (x & 0x3333333333333333ULL) + ((x >> 2) & 0x3333333333333333ULL);
+ x = (x & 0x0F0F0F0F0F0F0F0FULL) + ((x >> 4) & 0x0F0F0F0F0F0F0F0FULL);
+ x = (x & 0x00FF00FF00FF00FFULL) + ((x >> 8) & 0x00FF00FF00FF00FFULL);
+ x = (x & 0x0000FFFF0000FFFFULL) + ((x >> 16) & 0x0000FFFF0000FFFFULL);
+ x = (x & 0x00000000FFFFFFFFULL) + ((x >> 32));
+
+ return x;
+}
+
+void helper_msa_pcnt_b(CPUMIPSState *env, uint32_t wd, uint32_t ws)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+
+ pwd->b[0] = msa_pcnt_df(DF_BYTE, pws->b[0]);
+ pwd->b[1] = msa_pcnt_df(DF_BYTE, pws->b[1]);
+ pwd->b[2] = msa_pcnt_df(DF_BYTE, pws->b[2]);
+ pwd->b[3] = msa_pcnt_df(DF_BYTE, pws->b[3]);
+ pwd->b[4] = msa_pcnt_df(DF_BYTE, pws->b[4]);
+ pwd->b[5] = msa_pcnt_df(DF_BYTE, pws->b[5]);
+ pwd->b[6] = msa_pcnt_df(DF_BYTE, pws->b[6]);
+ pwd->b[7] = msa_pcnt_df(DF_BYTE, pws->b[7]);
+ pwd->b[8] = msa_pcnt_df(DF_BYTE, pws->b[8]);
+ pwd->b[9] = msa_pcnt_df(DF_BYTE, pws->b[9]);
+ pwd->b[10] = msa_pcnt_df(DF_BYTE, pws->b[10]);
+ pwd->b[11] = msa_pcnt_df(DF_BYTE, pws->b[11]);
+ pwd->b[12] = msa_pcnt_df(DF_BYTE, pws->b[12]);
+ pwd->b[13] = msa_pcnt_df(DF_BYTE, pws->b[13]);
+ pwd->b[14] = msa_pcnt_df(DF_BYTE, pws->b[14]);
+ pwd->b[15] = msa_pcnt_df(DF_BYTE, pws->b[15]);
+}
+
+void helper_msa_pcnt_h(CPUMIPSState *env, uint32_t wd, uint32_t ws)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+
+ pwd->h[0] = msa_pcnt_df(DF_HALF, pws->h[0]);
+ pwd->h[1] = msa_pcnt_df(DF_HALF, pws->h[1]);
+ pwd->h[2] = msa_pcnt_df(DF_HALF, pws->h[2]);
+ pwd->h[3] = msa_pcnt_df(DF_HALF, pws->h[3]);
+ pwd->h[4] = msa_pcnt_df(DF_HALF, pws->h[4]);
+ pwd->h[5] = msa_pcnt_df(DF_HALF, pws->h[5]);
+ pwd->h[6] = msa_pcnt_df(DF_HALF, pws->h[6]);
+ pwd->h[7] = msa_pcnt_df(DF_HALF, pws->h[7]);
+}
+
+void helper_msa_pcnt_w(CPUMIPSState *env, uint32_t wd, uint32_t ws)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+
+ pwd->w[0] = msa_pcnt_df(DF_WORD, pws->w[0]);
+ pwd->w[1] = msa_pcnt_df(DF_WORD, pws->w[1]);
+ pwd->w[2] = msa_pcnt_df(DF_WORD, pws->w[2]);
+ pwd->w[3] = msa_pcnt_df(DF_WORD, pws->w[3]);
+}
+
+void helper_msa_pcnt_d(CPUMIPSState *env, uint32_t wd, uint32_t ws)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+
+ pwd->d[0] = msa_pcnt_df(DF_DOUBLE, pws->d[0]);
+ pwd->d[1] = msa_pcnt_df(DF_DOUBLE, pws->d[1]);
+}
/*
@@ -87,7 +301,206 @@
* +---------------+----------------------------------------------------------+
*/
-/* TODO: insert Bit Move group helpers here */
+/* Data format bit position and unsigned values */
+#define BIT_POSITION(x, df) ((uint64_t)(x) % DF_BITS(df))
+
+static inline int64_t msa_binsl_df(uint32_t df,
+ int64_t dest, int64_t arg1, int64_t arg2)
+{
+ uint64_t u_arg1 = UNSIGNED(arg1, df);
+ uint64_t u_dest = UNSIGNED(dest, df);
+ int32_t sh_d = BIT_POSITION(arg2, df) + 1;
+ int32_t sh_a = DF_BITS(df) - sh_d;
+ if (sh_d == DF_BITS(df)) {
+ return u_arg1;
+ } else {
+ return UNSIGNED(UNSIGNED(u_dest << sh_d, df) >> sh_d, df) |
+ UNSIGNED(UNSIGNED(u_arg1 >> sh_a, df) << sh_a, df);
+ }
+}
+
+void helper_msa_binsl_b(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->b[0] = msa_binsl_df(DF_BYTE, pwd->b[0], pws->b[0], pwt->b[0]);
+ pwd->b[1] = msa_binsl_df(DF_BYTE, pwd->b[1], pws->b[1], pwt->b[1]);
+ pwd->b[2] = msa_binsl_df(DF_BYTE, pwd->b[2], pws->b[2], pwt->b[2]);
+ pwd->b[3] = msa_binsl_df(DF_BYTE, pwd->b[3], pws->b[3], pwt->b[3]);
+ pwd->b[4] = msa_binsl_df(DF_BYTE, pwd->b[4], pws->b[4], pwt->b[4]);
+ pwd->b[5] = msa_binsl_df(DF_BYTE, pwd->b[5], pws->b[5], pwt->b[5]);
+ pwd->b[6] = msa_binsl_df(DF_BYTE, pwd->b[6], pws->b[6], pwt->b[6]);
+ pwd->b[7] = msa_binsl_df(DF_BYTE, pwd->b[7], pws->b[7], pwt->b[7]);
+ pwd->b[8] = msa_binsl_df(DF_BYTE, pwd->b[8], pws->b[8], pwt->b[8]);
+ pwd->b[9] = msa_binsl_df(DF_BYTE, pwd->b[9], pws->b[9], pwt->b[9]);
+ pwd->b[10] = msa_binsl_df(DF_BYTE, pwd->b[10], pws->b[10], pwt->b[10]);
+ pwd->b[11] = msa_binsl_df(DF_BYTE, pwd->b[11], pws->b[11], pwt->b[11]);
+ pwd->b[12] = msa_binsl_df(DF_BYTE, pwd->b[12], pws->b[12], pwt->b[12]);
+ pwd->b[13] = msa_binsl_df(DF_BYTE, pwd->b[13], pws->b[13], pwt->b[13]);
+ pwd->b[14] = msa_binsl_df(DF_BYTE, pwd->b[14], pws->b[14], pwt->b[14]);
+ pwd->b[15] = msa_binsl_df(DF_BYTE, pwd->b[15], pws->b[15], pwt->b[15]);
+}
+
+void helper_msa_binsl_h(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->h[0] = msa_binsl_df(DF_HALF, pwd->h[0], pws->h[0], pwt->h[0]);
+ pwd->h[1] = msa_binsl_df(DF_HALF, pwd->h[1], pws->h[1], pwt->h[1]);
+ pwd->h[2] = msa_binsl_df(DF_HALF, pwd->h[2], pws->h[2], pwt->h[2]);
+ pwd->h[3] = msa_binsl_df(DF_HALF, pwd->h[3], pws->h[3], pwt->h[3]);
+ pwd->h[4] = msa_binsl_df(DF_HALF, pwd->h[4], pws->h[4], pwt->h[4]);
+ pwd->h[5] = msa_binsl_df(DF_HALF, pwd->h[5], pws->h[5], pwt->h[5]);
+ pwd->h[6] = msa_binsl_df(DF_HALF, pwd->h[6], pws->h[6], pwt->h[6]);
+ pwd->h[7] = msa_binsl_df(DF_HALF, pwd->h[7], pws->h[7], pwt->h[7]);
+}
+
+void helper_msa_binsl_w(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->w[0] = msa_binsl_df(DF_WORD, pwd->w[0], pws->w[0], pwt->w[0]);
+ pwd->w[1] = msa_binsl_df(DF_WORD, pwd->w[1], pws->w[1], pwt->w[1]);
+ pwd->w[2] = msa_binsl_df(DF_WORD, pwd->w[2], pws->w[2], pwt->w[2]);
+ pwd->w[3] = msa_binsl_df(DF_WORD, pwd->w[3], pws->w[3], pwt->w[3]);
+}
+
+void helper_msa_binsl_d(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->d[0] = msa_binsl_df(DF_DOUBLE, pwd->d[0], pws->d[0], pwt->d[0]);
+ pwd->d[1] = msa_binsl_df(DF_DOUBLE, pwd->d[1], pws->d[1], pwt->d[1]);
+}
+
+static inline int64_t msa_binsr_df(uint32_t df,
+ int64_t dest, int64_t arg1, int64_t arg2)
+{
+ uint64_t u_arg1 = UNSIGNED(arg1, df);
+ uint64_t u_dest = UNSIGNED(dest, df);
+ int32_t sh_d = BIT_POSITION(arg2, df) + 1;
+ int32_t sh_a = DF_BITS(df) - sh_d;
+ if (sh_d == DF_BITS(df)) {
+ return u_arg1;
+ } else {
+ return UNSIGNED(UNSIGNED(u_dest >> sh_d, df) << sh_d, df) |
+ UNSIGNED(UNSIGNED(u_arg1 << sh_a, df) >> sh_a, df);
+ }
+}
+
+void helper_msa_binsr_b(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->b[0] = msa_binsr_df(DF_BYTE, pwd->b[0], pws->b[0], pwt->b[0]);
+ pwd->b[1] = msa_binsr_df(DF_BYTE, pwd->b[1], pws->b[1], pwt->b[1]);
+ pwd->b[2] = msa_binsr_df(DF_BYTE, pwd->b[2], pws->b[2], pwt->b[2]);
+ pwd->b[3] = msa_binsr_df(DF_BYTE, pwd->b[3], pws->b[3], pwt->b[3]);
+ pwd->b[4] = msa_binsr_df(DF_BYTE, pwd->b[4], pws->b[4], pwt->b[4]);
+ pwd->b[5] = msa_binsr_df(DF_BYTE, pwd->b[5], pws->b[5], pwt->b[5]);
+ pwd->b[6] = msa_binsr_df(DF_BYTE, pwd->b[6], pws->b[6], pwt->b[6]);
+ pwd->b[7] = msa_binsr_df(DF_BYTE, pwd->b[7], pws->b[7], pwt->b[7]);
+ pwd->b[8] = msa_binsr_df(DF_BYTE, pwd->b[8], pws->b[8], pwt->b[8]);
+ pwd->b[9] = msa_binsr_df(DF_BYTE, pwd->b[9], pws->b[9], pwt->b[9]);
+ pwd->b[10] = msa_binsr_df(DF_BYTE, pwd->b[10], pws->b[10], pwt->b[10]);
+ pwd->b[11] = msa_binsr_df(DF_BYTE, pwd->b[11], pws->b[11], pwt->b[11]);
+ pwd->b[12] = msa_binsr_df(DF_BYTE, pwd->b[12], pws->b[12], pwt->b[12]);
+ pwd->b[13] = msa_binsr_df(DF_BYTE, pwd->b[13], pws->b[13], pwt->b[13]);
+ pwd->b[14] = msa_binsr_df(DF_BYTE, pwd->b[14], pws->b[14], pwt->b[14]);
+ pwd->b[15] = msa_binsr_df(DF_BYTE, pwd->b[15], pws->b[15], pwt->b[15]);
+}
+
+void helper_msa_binsr_h(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->h[0] = msa_binsr_df(DF_HALF, pwd->h[0], pws->h[0], pwt->h[0]);
+ pwd->h[1] = msa_binsr_df(DF_HALF, pwd->h[1], pws->h[1], pwt->h[1]);
+ pwd->h[2] = msa_binsr_df(DF_HALF, pwd->h[2], pws->h[2], pwt->h[2]);
+ pwd->h[3] = msa_binsr_df(DF_HALF, pwd->h[3], pws->h[3], pwt->h[3]);
+ pwd->h[4] = msa_binsr_df(DF_HALF, pwd->h[4], pws->h[4], pwt->h[4]);
+ pwd->h[5] = msa_binsr_df(DF_HALF, pwd->h[5], pws->h[5], pwt->h[5]);
+ pwd->h[6] = msa_binsr_df(DF_HALF, pwd->h[6], pws->h[6], pwt->h[6]);
+ pwd->h[7] = msa_binsr_df(DF_HALF, pwd->h[7], pws->h[7], pwt->h[7]);
+}
+
+void helper_msa_binsr_w(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->w[0] = msa_binsr_df(DF_WORD, pwd->w[0], pws->w[0], pwt->w[0]);
+ pwd->w[1] = msa_binsr_df(DF_WORD, pwd->w[1], pws->w[1], pwt->w[1]);
+ pwd->w[2] = msa_binsr_df(DF_WORD, pwd->w[2], pws->w[2], pwt->w[2]);
+ pwd->w[3] = msa_binsr_df(DF_WORD, pwd->w[3], pws->w[3], pwt->w[3]);
+}
+
+void helper_msa_binsr_d(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->d[0] = msa_binsr_df(DF_DOUBLE, pwd->d[0], pws->d[0], pwt->d[0]);
+ pwd->d[1] = msa_binsr_df(DF_DOUBLE, pwd->d[1], pws->d[1], pwt->d[1]);
+}
+
+void helper_msa_bmnz_v(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->d[0] = UNSIGNED( \
+ ((pwd->d[0] & (~pwt->d[0])) | (pws->d[0] & pwt->d[0])), DF_DOUBLE);
+ pwd->d[1] = UNSIGNED( \
+ ((pwd->d[1] & (~pwt->d[1])) | (pws->d[1] & pwt->d[1])), DF_DOUBLE);
+}
+
+void helper_msa_bmz_v(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->d[0] = UNSIGNED( \
+ ((pwd->d[0] & pwt->d[0]) | (pws->d[0] & (~pwt->d[0]))), DF_DOUBLE);
+ pwd->d[1] = UNSIGNED( \
+ ((pwd->d[1] & pwt->d[1]) | (pws->d[1] & (~pwt->d[1]))), DF_DOUBLE);
+}
+
+void helper_msa_bsel_v(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->d[0] = UNSIGNED( \
+ (pws->d[0] & (~pwd->d[0])) | (pwt->d[0] & pwd->d[0]), DF_DOUBLE);
+ pwd->d[1] = UNSIGNED( \
+ (pws->d[1] & (~pwd->d[1])) | (pwt->d[1] & pwd->d[1]), DF_DOUBLE);
+}
/*
@@ -110,7 +523,210 @@
* +---------------+----------------------------------------------------------+
*/
-/* TODO: insert Bit Set group helpers here */
+static inline int64_t msa_bclr_df(uint32_t df, int64_t arg1, int64_t arg2)
+{
+ int32_t b_arg2 = BIT_POSITION(arg2, df);
+ return UNSIGNED(arg1 & (~(1LL << b_arg2)), df);
+}
+
+void helper_msa_bclr_b(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->b[0] = msa_bclr_df(DF_BYTE, pws->b[0], pwt->b[0]);
+ pwd->b[1] = msa_bclr_df(DF_BYTE, pws->b[1], pwt->b[1]);
+ pwd->b[2] = msa_bclr_df(DF_BYTE, pws->b[2], pwt->b[2]);
+ pwd->b[3] = msa_bclr_df(DF_BYTE, pws->b[3], pwt->b[3]);
+ pwd->b[4] = msa_bclr_df(DF_BYTE, pws->b[4], pwt->b[4]);
+ pwd->b[5] = msa_bclr_df(DF_BYTE, pws->b[5], pwt->b[5]);
+ pwd->b[6] = msa_bclr_df(DF_BYTE, pws->b[6], pwt->b[6]);
+ pwd->b[7] = msa_bclr_df(DF_BYTE, pws->b[7], pwt->b[7]);
+ pwd->b[8] = msa_bclr_df(DF_BYTE, pws->b[8], pwt->b[8]);
+ pwd->b[9] = msa_bclr_df(DF_BYTE, pws->b[9], pwt->b[9]);
+ pwd->b[10] = msa_bclr_df(DF_BYTE, pws->b[10], pwt->b[10]);
+ pwd->b[11] = msa_bclr_df(DF_BYTE, pws->b[11], pwt->b[11]);
+ pwd->b[12] = msa_bclr_df(DF_BYTE, pws->b[12], pwt->b[12]);
+ pwd->b[13] = msa_bclr_df(DF_BYTE, pws->b[13], pwt->b[13]);
+ pwd->b[14] = msa_bclr_df(DF_BYTE, pws->b[14], pwt->b[14]);
+ pwd->b[15] = msa_bclr_df(DF_BYTE, pws->b[15], pwt->b[15]);
+}
+
+void helper_msa_bclr_h(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->h[0] = msa_bclr_df(DF_HALF, pws->h[0], pwt->h[0]);
+ pwd->h[1] = msa_bclr_df(DF_HALF, pws->h[1], pwt->h[1]);
+ pwd->h[2] = msa_bclr_df(DF_HALF, pws->h[2], pwt->h[2]);
+ pwd->h[3] = msa_bclr_df(DF_HALF, pws->h[3], pwt->h[3]);
+ pwd->h[4] = msa_bclr_df(DF_HALF, pws->h[4], pwt->h[4]);
+ pwd->h[5] = msa_bclr_df(DF_HALF, pws->h[5], pwt->h[5]);
+ pwd->h[6] = msa_bclr_df(DF_HALF, pws->h[6], pwt->h[6]);
+ pwd->h[7] = msa_bclr_df(DF_HALF, pws->h[7], pwt->h[7]);
+}
+
+void helper_msa_bclr_w(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->w[0] = msa_bclr_df(DF_WORD, pws->w[0], pwt->w[0]);
+ pwd->w[1] = msa_bclr_df(DF_WORD, pws->w[1], pwt->w[1]);
+ pwd->w[2] = msa_bclr_df(DF_WORD, pws->w[2], pwt->w[2]);
+ pwd->w[3] = msa_bclr_df(DF_WORD, pws->w[3], pwt->w[3]);
+}
+
+void helper_msa_bclr_d(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->d[0] = msa_bclr_df(DF_DOUBLE, pws->d[0], pwt->d[0]);
+ pwd->d[1] = msa_bclr_df(DF_DOUBLE, pws->d[1], pwt->d[1]);
+}
+
+static inline int64_t msa_bneg_df(uint32_t df, int64_t arg1, int64_t arg2)
+{
+ int32_t b_arg2 = BIT_POSITION(arg2, df);
+ return UNSIGNED(arg1 ^ (1LL << b_arg2), df);
+}
+
+void helper_msa_bneg_b(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->b[0] = msa_bneg_df(DF_BYTE, pws->b[0], pwt->b[0]);
+ pwd->b[1] = msa_bneg_df(DF_BYTE, pws->b[1], pwt->b[1]);
+ pwd->b[2] = msa_bneg_df(DF_BYTE, pws->b[2], pwt->b[2]);
+ pwd->b[3] = msa_bneg_df(DF_BYTE, pws->b[3], pwt->b[3]);
+ pwd->b[4] = msa_bneg_df(DF_BYTE, pws->b[4], pwt->b[4]);
+ pwd->b[5] = msa_bneg_df(DF_BYTE, pws->b[5], pwt->b[5]);
+ pwd->b[6] = msa_bneg_df(DF_BYTE, pws->b[6], pwt->b[6]);
+ pwd->b[7] = msa_bneg_df(DF_BYTE, pws->b[7], pwt->b[7]);
+ pwd->b[8] = msa_bneg_df(DF_BYTE, pws->b[8], pwt->b[8]);
+ pwd->b[9] = msa_bneg_df(DF_BYTE, pws->b[9], pwt->b[9]);
+ pwd->b[10] = msa_bneg_df(DF_BYTE, pws->b[10], pwt->b[10]);
+ pwd->b[11] = msa_bneg_df(DF_BYTE, pws->b[11], pwt->b[11]);
+ pwd->b[12] = msa_bneg_df(DF_BYTE, pws->b[12], pwt->b[12]);
+ pwd->b[13] = msa_bneg_df(DF_BYTE, pws->b[13], pwt->b[13]);
+ pwd->b[14] = msa_bneg_df(DF_BYTE, pws->b[14], pwt->b[14]);
+ pwd->b[15] = msa_bneg_df(DF_BYTE, pws->b[15], pwt->b[15]);
+}
+
+void helper_msa_bneg_h(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->h[0] = msa_bneg_df(DF_HALF, pws->h[0], pwt->h[0]);
+ pwd->h[1] = msa_bneg_df(DF_HALF, pws->h[1], pwt->h[1]);
+ pwd->h[2] = msa_bneg_df(DF_HALF, pws->h[2], pwt->h[2]);
+ pwd->h[3] = msa_bneg_df(DF_HALF, pws->h[3], pwt->h[3]);
+ pwd->h[4] = msa_bneg_df(DF_HALF, pws->h[4], pwt->h[4]);
+ pwd->h[5] = msa_bneg_df(DF_HALF, pws->h[5], pwt->h[5]);
+ pwd->h[6] = msa_bneg_df(DF_HALF, pws->h[6], pwt->h[6]);
+ pwd->h[7] = msa_bneg_df(DF_HALF, pws->h[7], pwt->h[7]);
+}
+
+void helper_msa_bneg_w(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->w[0] = msa_bneg_df(DF_WORD, pws->w[0], pwt->w[0]);
+ pwd->w[1] = msa_bneg_df(DF_WORD, pws->w[1], pwt->w[1]);
+ pwd->w[2] = msa_bneg_df(DF_WORD, pws->w[2], pwt->w[2]);
+ pwd->w[3] = msa_bneg_df(DF_WORD, pws->w[3], pwt->w[3]);
+}
+
+void helper_msa_bneg_d(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->d[0] = msa_bneg_df(DF_DOUBLE, pws->d[0], pwt->d[0]);
+ pwd->d[1] = msa_bneg_df(DF_DOUBLE, pws->d[1], pwt->d[1]);
+}
+
+static inline int64_t msa_bset_df(uint32_t df, int64_t arg1,
+ int64_t arg2)
+{
+ int32_t b_arg2 = BIT_POSITION(arg2, df);
+ return UNSIGNED(arg1 | (1LL << b_arg2), df);
+}
+
+void helper_msa_bset_b(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->b[0] = msa_bset_df(DF_BYTE, pws->b[0], pwt->b[0]);
+ pwd->b[1] = msa_bset_df(DF_BYTE, pws->b[1], pwt->b[1]);
+ pwd->b[2] = msa_bset_df(DF_BYTE, pws->b[2], pwt->b[2]);
+ pwd->b[3] = msa_bset_df(DF_BYTE, pws->b[3], pwt->b[3]);
+ pwd->b[4] = msa_bset_df(DF_BYTE, pws->b[4], pwt->b[4]);
+ pwd->b[5] = msa_bset_df(DF_BYTE, pws->b[5], pwt->b[5]);
+ pwd->b[6] = msa_bset_df(DF_BYTE, pws->b[6], pwt->b[6]);
+ pwd->b[7] = msa_bset_df(DF_BYTE, pws->b[7], pwt->b[7]);
+ pwd->b[8] = msa_bset_df(DF_BYTE, pws->b[8], pwt->b[8]);
+ pwd->b[9] = msa_bset_df(DF_BYTE, pws->b[9], pwt->b[9]);
+ pwd->b[10] = msa_bset_df(DF_BYTE, pws->b[10], pwt->b[10]);
+ pwd->b[11] = msa_bset_df(DF_BYTE, pws->b[11], pwt->b[11]);
+ pwd->b[12] = msa_bset_df(DF_BYTE, pws->b[12], pwt->b[12]);
+ pwd->b[13] = msa_bset_df(DF_BYTE, pws->b[13], pwt->b[13]);
+ pwd->b[14] = msa_bset_df(DF_BYTE, pws->b[14], pwt->b[14]);
+ pwd->b[15] = msa_bset_df(DF_BYTE, pws->b[15], pwt->b[15]);
+}
+
+void helper_msa_bset_h(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->h[0] = msa_bset_df(DF_HALF, pws->h[0], pwt->h[0]);
+ pwd->h[1] = msa_bset_df(DF_HALF, pws->h[1], pwt->h[1]);
+ pwd->h[2] = msa_bset_df(DF_HALF, pws->h[2], pwt->h[2]);
+ pwd->h[3] = msa_bset_df(DF_HALF, pws->h[3], pwt->h[3]);
+ pwd->h[4] = msa_bset_df(DF_HALF, pws->h[4], pwt->h[4]);
+ pwd->h[5] = msa_bset_df(DF_HALF, pws->h[5], pwt->h[5]);
+ pwd->h[6] = msa_bset_df(DF_HALF, pws->h[6], pwt->h[6]);
+ pwd->h[7] = msa_bset_df(DF_HALF, pws->h[7], pwt->h[7]);
+}
+
+void helper_msa_bset_w(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->w[0] = msa_bset_df(DF_WORD, pws->w[0], pwt->w[0]);
+ pwd->w[1] = msa_bset_df(DF_WORD, pws->w[1], pwt->w[1]);
+ pwd->w[2] = msa_bset_df(DF_WORD, pws->w[2], pwt->w[2]);
+ pwd->w[3] = msa_bset_df(DF_WORD, pws->w[3], pwt->w[3]);
+}
+
+void helper_msa_bset_d(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->d[0] = msa_bset_df(DF_DOUBLE, pws->d[0], pwt->d[0]);
+ pwd->d[1] = msa_bset_df(DF_DOUBLE, pws->d[1], pwt->d[1]);
+}
/*
@@ -216,7 +832,297 @@
* +---------------+----------------------------------------------------------+
*/
-/* TODO: insert Int Average group helpers here */
+static inline int64_t msa_ave_s_df(uint32_t df, int64_t arg1, int64_t arg2)
+{
+ /* signed shift */
+ return (arg1 >> 1) + (arg2 >> 1) + (arg1 & arg2 & 1);
+}
+
+void helper_msa_ave_s_b(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->b[0] = msa_ave_s_df(DF_BYTE, pws->b[0], pwt->b[0]);
+ pwd->b[1] = msa_ave_s_df(DF_BYTE, pws->b[1], pwt->b[1]);
+ pwd->b[2] = msa_ave_s_df(DF_BYTE, pws->b[2], pwt->b[2]);
+ pwd->b[3] = msa_ave_s_df(DF_BYTE, pws->b[3], pwt->b[3]);
+ pwd->b[4] = msa_ave_s_df(DF_BYTE, pws->b[4], pwt->b[4]);
+ pwd->b[5] = msa_ave_s_df(DF_BYTE, pws->b[5], pwt->b[5]);
+ pwd->b[6] = msa_ave_s_df(DF_BYTE, pws->b[6], pwt->b[6]);
+ pwd->b[7] = msa_ave_s_df(DF_BYTE, pws->b[7], pwt->b[7]);
+ pwd->b[8] = msa_ave_s_df(DF_BYTE, pws->b[8], pwt->b[8]);
+ pwd->b[9] = msa_ave_s_df(DF_BYTE, pws->b[9], pwt->b[9]);
+ pwd->b[10] = msa_ave_s_df(DF_BYTE, pws->b[10], pwt->b[10]);
+ pwd->b[11] = msa_ave_s_df(DF_BYTE, pws->b[11], pwt->b[11]);
+ pwd->b[12] = msa_ave_s_df(DF_BYTE, pws->b[12], pwt->b[12]);
+ pwd->b[13] = msa_ave_s_df(DF_BYTE, pws->b[13], pwt->b[13]);
+ pwd->b[14] = msa_ave_s_df(DF_BYTE, pws->b[14], pwt->b[14]);
+ pwd->b[15] = msa_ave_s_df(DF_BYTE, pws->b[15], pwt->b[15]);
+}
+
+void helper_msa_ave_s_h(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->h[0] = msa_ave_s_df(DF_HALF, pws->h[0], pwt->h[0]);
+ pwd->h[1] = msa_ave_s_df(DF_HALF, pws->h[1], pwt->h[1]);
+ pwd->h[2] = msa_ave_s_df(DF_HALF, pws->h[2], pwt->h[2]);
+ pwd->h[3] = msa_ave_s_df(DF_HALF, pws->h[3], pwt->h[3]);
+ pwd->h[4] = msa_ave_s_df(DF_HALF, pws->h[4], pwt->h[4]);
+ pwd->h[5] = msa_ave_s_df(DF_HALF, pws->h[5], pwt->h[5]);
+ pwd->h[6] = msa_ave_s_df(DF_HALF, pws->h[6], pwt->h[6]);
+ pwd->h[7] = msa_ave_s_df(DF_HALF, pws->h[7], pwt->h[7]);
+}
+
+void helper_msa_ave_s_w(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->w[0] = msa_ave_s_df(DF_WORD, pws->w[0], pwt->w[0]);
+ pwd->w[1] = msa_ave_s_df(DF_WORD, pws->w[1], pwt->w[1]);
+ pwd->w[2] = msa_ave_s_df(DF_WORD, pws->w[2], pwt->w[2]);
+ pwd->w[3] = msa_ave_s_df(DF_WORD, pws->w[3], pwt->w[3]);
+}
+
+void helper_msa_ave_s_d(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->d[0] = msa_ave_s_df(DF_DOUBLE, pws->d[0], pwt->d[0]);
+ pwd->d[1] = msa_ave_s_df(DF_DOUBLE, pws->d[1], pwt->d[1]);
+}
+
+static inline uint64_t msa_ave_u_df(uint32_t df, uint64_t arg1, uint64_t arg2)
+{
+ uint64_t u_arg1 = UNSIGNED(arg1, df);
+ uint64_t u_arg2 = UNSIGNED(arg2, df);
+ /* unsigned shift */
+ return (u_arg1 >> 1) + (u_arg2 >> 1) + (u_arg1 & u_arg2 & 1);
+}
+
+void helper_msa_ave_u_b(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->b[0] = msa_ave_u_df(DF_BYTE, pws->b[0], pwt->b[0]);
+ pwd->b[1] = msa_ave_u_df(DF_BYTE, pws->b[1], pwt->b[1]);
+ pwd->b[2] = msa_ave_u_df(DF_BYTE, pws->b[2], pwt->b[2]);
+ pwd->b[3] = msa_ave_u_df(DF_BYTE, pws->b[3], pwt->b[3]);
+ pwd->b[4] = msa_ave_u_df(DF_BYTE, pws->b[4], pwt->b[4]);
+ pwd->b[5] = msa_ave_u_df(DF_BYTE, pws->b[5], pwt->b[5]);
+ pwd->b[6] = msa_ave_u_df(DF_BYTE, pws->b[6], pwt->b[6]);
+ pwd->b[7] = msa_ave_u_df(DF_BYTE, pws->b[7], pwt->b[7]);
+ pwd->b[8] = msa_ave_u_df(DF_BYTE, pws->b[8], pwt->b[8]);
+ pwd->b[9] = msa_ave_u_df(DF_BYTE, pws->b[9], pwt->b[9]);
+ pwd->b[10] = msa_ave_u_df(DF_BYTE, pws->b[10], pwt->b[10]);
+ pwd->b[11] = msa_ave_u_df(DF_BYTE, pws->b[11], pwt->b[11]);
+ pwd->b[12] = msa_ave_u_df(DF_BYTE, pws->b[12], pwt->b[12]);
+ pwd->b[13] = msa_ave_u_df(DF_BYTE, pws->b[13], pwt->b[13]);
+ pwd->b[14] = msa_ave_u_df(DF_BYTE, pws->b[14], pwt->b[14]);
+ pwd->b[15] = msa_ave_u_df(DF_BYTE, pws->b[15], pwt->b[15]);
+}
+
+void helper_msa_ave_u_h(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->h[0] = msa_ave_u_df(DF_HALF, pws->h[0], pwt->h[0]);
+ pwd->h[1] = msa_ave_u_df(DF_HALF, pws->h[1], pwt->h[1]);
+ pwd->h[2] = msa_ave_u_df(DF_HALF, pws->h[2], pwt->h[2]);
+ pwd->h[3] = msa_ave_u_df(DF_HALF, pws->h[3], pwt->h[3]);
+ pwd->h[4] = msa_ave_u_df(DF_HALF, pws->h[4], pwt->h[4]);
+ pwd->h[5] = msa_ave_u_df(DF_HALF, pws->h[5], pwt->h[5]);
+ pwd->h[6] = msa_ave_u_df(DF_HALF, pws->h[6], pwt->h[6]);
+ pwd->h[7] = msa_ave_u_df(DF_HALF, pws->h[7], pwt->h[7]);
+}
+
+void helper_msa_ave_u_w(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->w[0] = msa_ave_u_df(DF_WORD, pws->w[0], pwt->w[0]);
+ pwd->w[1] = msa_ave_u_df(DF_WORD, pws->w[1], pwt->w[1]);
+ pwd->w[2] = msa_ave_u_df(DF_WORD, pws->w[2], pwt->w[2]);
+ pwd->w[3] = msa_ave_u_df(DF_WORD, pws->w[3], pwt->w[3]);
+}
+
+void helper_msa_ave_u_d(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->d[0] = msa_ave_u_df(DF_DOUBLE, pws->d[0], pwt->d[0]);
+ pwd->d[1] = msa_ave_u_df(DF_DOUBLE, pws->d[1], pwt->d[1]);
+}
+
+static inline int64_t msa_aver_s_df(uint32_t df, int64_t arg1, int64_t arg2)
+{
+ /* signed shift */
+ return (arg1 >> 1) + (arg2 >> 1) + ((arg1 | arg2) & 1);
+}
+
+void helper_msa_aver_s_b(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->b[0] = msa_aver_s_df(DF_BYTE, pws->b[0], pwt->b[0]);
+ pwd->b[1] = msa_aver_s_df(DF_BYTE, pws->b[1], pwt->b[1]);
+ pwd->b[2] = msa_aver_s_df(DF_BYTE, pws->b[2], pwt->b[2]);
+ pwd->b[3] = msa_aver_s_df(DF_BYTE, pws->b[3], pwt->b[3]);
+ pwd->b[4] = msa_aver_s_df(DF_BYTE, pws->b[4], pwt->b[4]);
+ pwd->b[5] = msa_aver_s_df(DF_BYTE, pws->b[5], pwt->b[5]);
+ pwd->b[6] = msa_aver_s_df(DF_BYTE, pws->b[6], pwt->b[6]);
+ pwd->b[7] = msa_aver_s_df(DF_BYTE, pws->b[7], pwt->b[7]);
+ pwd->b[8] = msa_aver_s_df(DF_BYTE, pws->b[8], pwt->b[8]);
+ pwd->b[9] = msa_aver_s_df(DF_BYTE, pws->b[9], pwt->b[9]);
+ pwd->b[10] = msa_aver_s_df(DF_BYTE, pws->b[10], pwt->b[10]);
+ pwd->b[11] = msa_aver_s_df(DF_BYTE, pws->b[11], pwt->b[11]);
+ pwd->b[12] = msa_aver_s_df(DF_BYTE, pws->b[12], pwt->b[12]);
+ pwd->b[13] = msa_aver_s_df(DF_BYTE, pws->b[13], pwt->b[13]);
+ pwd->b[14] = msa_aver_s_df(DF_BYTE, pws->b[14], pwt->b[14]);
+ pwd->b[15] = msa_aver_s_df(DF_BYTE, pws->b[15], pwt->b[15]);
+}
+
+void helper_msa_aver_s_h(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->h[0] = msa_aver_s_df(DF_HALF, pws->h[0], pwt->h[0]);
+ pwd->h[1] = msa_aver_s_df(DF_HALF, pws->h[1], pwt->h[1]);
+ pwd->h[2] = msa_aver_s_df(DF_HALF, pws->h[2], pwt->h[2]);
+ pwd->h[3] = msa_aver_s_df(DF_HALF, pws->h[3], pwt->h[3]);
+ pwd->h[4] = msa_aver_s_df(DF_HALF, pws->h[4], pwt->h[4]);
+ pwd->h[5] = msa_aver_s_df(DF_HALF, pws->h[5], pwt->h[5]);
+ pwd->h[6] = msa_aver_s_df(DF_HALF, pws->h[6], pwt->h[6]);
+ pwd->h[7] = msa_aver_s_df(DF_HALF, pws->h[7], pwt->h[7]);
+}
+
+void helper_msa_aver_s_w(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->w[0] = msa_aver_s_df(DF_WORD, pws->w[0], pwt->w[0]);
+ pwd->w[1] = msa_aver_s_df(DF_WORD, pws->w[1], pwt->w[1]);
+ pwd->w[2] = msa_aver_s_df(DF_WORD, pws->w[2], pwt->w[2]);
+ pwd->w[3] = msa_aver_s_df(DF_WORD, pws->w[3], pwt->w[3]);
+}
+
+void helper_msa_aver_s_d(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->d[0] = msa_aver_s_df(DF_DOUBLE, pws->d[0], pwt->d[0]);
+ pwd->d[1] = msa_aver_s_df(DF_DOUBLE, pws->d[1], pwt->d[1]);
+}
+
+static inline uint64_t msa_aver_u_df(uint32_t df, uint64_t arg1, uint64_t arg2)
+{
+ uint64_t u_arg1 = UNSIGNED(arg1, df);
+ uint64_t u_arg2 = UNSIGNED(arg2, df);
+ /* unsigned shift */
+ return (u_arg1 >> 1) + (u_arg2 >> 1) + ((u_arg1 | u_arg2) & 1);
+}
+
+void helper_msa_aver_u_b(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->b[0] = msa_aver_u_df(DF_BYTE, pws->b[0], pwt->b[0]);
+ pwd->b[1] = msa_aver_u_df(DF_BYTE, pws->b[1], pwt->b[1]);
+ pwd->b[2] = msa_aver_u_df(DF_BYTE, pws->b[2], pwt->b[2]);
+ pwd->b[3] = msa_aver_u_df(DF_BYTE, pws->b[3], pwt->b[3]);
+ pwd->b[4] = msa_aver_u_df(DF_BYTE, pws->b[4], pwt->b[4]);
+ pwd->b[5] = msa_aver_u_df(DF_BYTE, pws->b[5], pwt->b[5]);
+ pwd->b[6] = msa_aver_u_df(DF_BYTE, pws->b[6], pwt->b[6]);
+ pwd->b[7] = msa_aver_u_df(DF_BYTE, pws->b[7], pwt->b[7]);
+ pwd->b[8] = msa_aver_u_df(DF_BYTE, pws->b[8], pwt->b[8]);
+ pwd->b[9] = msa_aver_u_df(DF_BYTE, pws->b[9], pwt->b[9]);
+ pwd->b[10] = msa_aver_u_df(DF_BYTE, pws->b[10], pwt->b[10]);
+ pwd->b[11] = msa_aver_u_df(DF_BYTE, pws->b[11], pwt->b[11]);
+ pwd->b[12] = msa_aver_u_df(DF_BYTE, pws->b[12], pwt->b[12]);
+ pwd->b[13] = msa_aver_u_df(DF_BYTE, pws->b[13], pwt->b[13]);
+ pwd->b[14] = msa_aver_u_df(DF_BYTE, pws->b[14], pwt->b[14]);
+ pwd->b[15] = msa_aver_u_df(DF_BYTE, pws->b[15], pwt->b[15]);
+}
+
+void helper_msa_aver_u_h(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->h[0] = msa_aver_u_df(DF_HALF, pws->h[0], pwt->h[0]);
+ pwd->h[1] = msa_aver_u_df(DF_HALF, pws->h[1], pwt->h[1]);
+ pwd->h[2] = msa_aver_u_df(DF_HALF, pws->h[2], pwt->h[2]);
+ pwd->h[3] = msa_aver_u_df(DF_HALF, pws->h[3], pwt->h[3]);
+ pwd->h[4] = msa_aver_u_df(DF_HALF, pws->h[4], pwt->h[4]);
+ pwd->h[5] = msa_aver_u_df(DF_HALF, pws->h[5], pwt->h[5]);
+ pwd->h[6] = msa_aver_u_df(DF_HALF, pws->h[6], pwt->h[6]);
+ pwd->h[7] = msa_aver_u_df(DF_HALF, pws->h[7], pwt->h[7]);
+}
+
+void helper_msa_aver_u_w(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->w[0] = msa_aver_u_df(DF_WORD, pws->w[0], pwt->w[0]);
+ pwd->w[1] = msa_aver_u_df(DF_WORD, pws->w[1], pwt->w[1]);
+ pwd->w[2] = msa_aver_u_df(DF_WORD, pws->w[2], pwt->w[2]);
+ pwd->w[3] = msa_aver_u_df(DF_WORD, pws->w[3], pwt->w[3]);
+}
+
+void helper_msa_aver_u_d(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->d[0] = msa_aver_u_df(DF_DOUBLE, pws->d[0], pwt->d[0]);
+ pwd->d[1] = msa_aver_u_df(DF_DOUBLE, pws->d[1], pwt->d[1]);
+}
/*
@@ -247,7 +1153,360 @@
* +---------------+----------------------------------------------------------+
*/
-/* TODO: insert Int Compare group helpers here */
+static inline int64_t msa_ceq_df(uint32_t df, int64_t arg1, int64_t arg2)
+{
+ return arg1 == arg2 ? -1 : 0;
+}
+
+void helper_msa_ceq_b(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->b[0] = msa_ceq_df(DF_BYTE, pws->b[0], pwt->b[0]);
+ pwd->b[1] = msa_ceq_df(DF_BYTE, pws->b[1], pwt->b[1]);
+ pwd->b[2] = msa_ceq_df(DF_BYTE, pws->b[2], pwt->b[2]);
+ pwd->b[3] = msa_ceq_df(DF_BYTE, pws->b[3], pwt->b[3]);
+ pwd->b[4] = msa_ceq_df(DF_BYTE, pws->b[4], pwt->b[4]);
+ pwd->b[5] = msa_ceq_df(DF_BYTE, pws->b[5], pwt->b[5]);
+ pwd->b[6] = msa_ceq_df(DF_BYTE, pws->b[6], pwt->b[6]);
+ pwd->b[7] = msa_ceq_df(DF_BYTE, pws->b[7], pwt->b[7]);
+ pwd->b[8] = msa_ceq_df(DF_BYTE, pws->b[8], pwt->b[8]);
+ pwd->b[9] = msa_ceq_df(DF_BYTE, pws->b[9], pwt->b[9]);
+ pwd->b[10] = msa_ceq_df(DF_BYTE, pws->b[10], pwt->b[10]);
+ pwd->b[11] = msa_ceq_df(DF_BYTE, pws->b[11], pwt->b[11]);
+ pwd->b[12] = msa_ceq_df(DF_BYTE, pws->b[12], pwt->b[12]);
+ pwd->b[13] = msa_ceq_df(DF_BYTE, pws->b[13], pwt->b[13]);
+ pwd->b[14] = msa_ceq_df(DF_BYTE, pws->b[14], pwt->b[14]);
+ pwd->b[15] = msa_ceq_df(DF_BYTE, pws->b[15], pwt->b[15]);
+}
+
+void helper_msa_ceq_h(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->h[0] = msa_ceq_df(DF_HALF, pws->h[0], pwt->h[0]);
+ pwd->h[1] = msa_ceq_df(DF_HALF, pws->h[1], pwt->h[1]);
+ pwd->h[2] = msa_ceq_df(DF_HALF, pws->h[2], pwt->h[2]);
+ pwd->h[3] = msa_ceq_df(DF_HALF, pws->h[3], pwt->h[3]);
+ pwd->h[4] = msa_ceq_df(DF_HALF, pws->h[4], pwt->h[4]);
+ pwd->h[5] = msa_ceq_df(DF_HALF, pws->h[5], pwt->h[5]);
+ pwd->h[6] = msa_ceq_df(DF_HALF, pws->h[6], pwt->h[6]);
+ pwd->h[7] = msa_ceq_df(DF_HALF, pws->h[7], pwt->h[7]);
+}
+
+void helper_msa_ceq_w(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->w[0] = msa_ceq_df(DF_WORD, pws->w[0], pwt->w[0]);
+ pwd->w[1] = msa_ceq_df(DF_WORD, pws->w[1], pwt->w[1]);
+ pwd->w[2] = msa_ceq_df(DF_WORD, pws->w[2], pwt->w[2]);
+ pwd->w[3] = msa_ceq_df(DF_WORD, pws->w[3], pwt->w[3]);
+}
+
+void helper_msa_ceq_d(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->d[0] = msa_ceq_df(DF_DOUBLE, pws->d[0], pwt->d[0]);
+ pwd->d[1] = msa_ceq_df(DF_DOUBLE, pws->d[1], pwt->d[1]);
+}
+
+static inline int64_t msa_cle_s_df(uint32_t df, int64_t arg1, int64_t arg2)
+{
+ return arg1 <= arg2 ? -1 : 0;
+}
+
+void helper_msa_cle_s_b(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->b[0] = msa_cle_s_df(DF_BYTE, pws->b[0], pwt->b[0]);
+ pwd->b[1] = msa_cle_s_df(DF_BYTE, pws->b[1], pwt->b[1]);
+ pwd->b[2] = msa_cle_s_df(DF_BYTE, pws->b[2], pwt->b[2]);
+ pwd->b[3] = msa_cle_s_df(DF_BYTE, pws->b[3], pwt->b[3]);
+ pwd->b[4] = msa_cle_s_df(DF_BYTE, pws->b[4], pwt->b[4]);
+ pwd->b[5] = msa_cle_s_df(DF_BYTE, pws->b[5], pwt->b[5]);
+ pwd->b[6] = msa_cle_s_df(DF_BYTE, pws->b[6], pwt->b[6]);
+ pwd->b[7] = msa_cle_s_df(DF_BYTE, pws->b[7], pwt->b[7]);
+ pwd->b[8] = msa_cle_s_df(DF_BYTE, pws->b[8], pwt->b[8]);
+ pwd->b[9] = msa_cle_s_df(DF_BYTE, pws->b[9], pwt->b[9]);
+ pwd->b[10] = msa_cle_s_df(DF_BYTE, pws->b[10], pwt->b[10]);
+ pwd->b[11] = msa_cle_s_df(DF_BYTE, pws->b[11], pwt->b[11]);
+ pwd->b[12] = msa_cle_s_df(DF_BYTE, pws->b[12], pwt->b[12]);
+ pwd->b[13] = msa_cle_s_df(DF_BYTE, pws->b[13], pwt->b[13]);
+ pwd->b[14] = msa_cle_s_df(DF_BYTE, pws->b[14], pwt->b[14]);
+ pwd->b[15] = msa_cle_s_df(DF_BYTE, pws->b[15], pwt->b[15]);
+}
+
+void helper_msa_cle_s_h(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->h[0] = msa_cle_s_df(DF_HALF, pws->h[0], pwt->h[0]);
+ pwd->h[1] = msa_cle_s_df(DF_HALF, pws->h[1], pwt->h[1]);
+ pwd->h[2] = msa_cle_s_df(DF_HALF, pws->h[2], pwt->h[2]);
+ pwd->h[3] = msa_cle_s_df(DF_HALF, pws->h[3], pwt->h[3]);
+ pwd->h[4] = msa_cle_s_df(DF_HALF, pws->h[4], pwt->h[4]);
+ pwd->h[5] = msa_cle_s_df(DF_HALF, pws->h[5], pwt->h[5]);
+ pwd->h[6] = msa_cle_s_df(DF_HALF, pws->h[6], pwt->h[6]);
+ pwd->h[7] = msa_cle_s_df(DF_HALF, pws->h[7], pwt->h[7]);
+}
+
+void helper_msa_cle_s_w(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->w[0] = msa_cle_s_df(DF_WORD, pws->w[0], pwt->w[0]);
+ pwd->w[1] = msa_cle_s_df(DF_WORD, pws->w[1], pwt->w[1]);
+ pwd->w[2] = msa_cle_s_df(DF_WORD, pws->w[2], pwt->w[2]);
+ pwd->w[3] = msa_cle_s_df(DF_WORD, pws->w[3], pwt->w[3]);
+}
+
+void helper_msa_cle_s_d(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->d[0] = msa_cle_s_df(DF_DOUBLE, pws->d[0], pwt->d[0]);
+ pwd->d[1] = msa_cle_s_df(DF_DOUBLE, pws->d[1], pwt->d[1]);
+}
+
+static inline int64_t msa_cle_u_df(uint32_t df, int64_t arg1, int64_t arg2)
+{
+ uint64_t u_arg1 = UNSIGNED(arg1, df);
+ uint64_t u_arg2 = UNSIGNED(arg2, df);
+ return u_arg1 <= u_arg2 ? -1 : 0;
+}
+
+void helper_msa_cle_u_b(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->b[0] = msa_cle_u_df(DF_BYTE, pws->b[0], pwt->b[0]);
+ pwd->b[1] = msa_cle_u_df(DF_BYTE, pws->b[1], pwt->b[1]);
+ pwd->b[2] = msa_cle_u_df(DF_BYTE, pws->b[2], pwt->b[2]);
+ pwd->b[3] = msa_cle_u_df(DF_BYTE, pws->b[3], pwt->b[3]);
+ pwd->b[4] = msa_cle_u_df(DF_BYTE, pws->b[4], pwt->b[4]);
+ pwd->b[5] = msa_cle_u_df(DF_BYTE, pws->b[5], pwt->b[5]);
+ pwd->b[6] = msa_cle_u_df(DF_BYTE, pws->b[6], pwt->b[6]);
+ pwd->b[7] = msa_cle_u_df(DF_BYTE, pws->b[7], pwt->b[7]);
+ pwd->b[8] = msa_cle_u_df(DF_BYTE, pws->b[8], pwt->b[8]);
+ pwd->b[9] = msa_cle_u_df(DF_BYTE, pws->b[9], pwt->b[9]);
+ pwd->b[10] = msa_cle_u_df(DF_BYTE, pws->b[10], pwt->b[10]);
+ pwd->b[11] = msa_cle_u_df(DF_BYTE, pws->b[11], pwt->b[11]);
+ pwd->b[12] = msa_cle_u_df(DF_BYTE, pws->b[12], pwt->b[12]);
+ pwd->b[13] = msa_cle_u_df(DF_BYTE, pws->b[13], pwt->b[13]);
+ pwd->b[14] = msa_cle_u_df(DF_BYTE, pws->b[14], pwt->b[14]);
+ pwd->b[15] = msa_cle_u_df(DF_BYTE, pws->b[15], pwt->b[15]);
+}
+
+void helper_msa_cle_u_h(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->h[0] = msa_cle_u_df(DF_HALF, pws->h[0], pwt->h[0]);
+ pwd->h[1] = msa_cle_u_df(DF_HALF, pws->h[1], pwt->h[1]);
+ pwd->h[2] = msa_cle_u_df(DF_HALF, pws->h[2], pwt->h[2]);
+ pwd->h[3] = msa_cle_u_df(DF_HALF, pws->h[3], pwt->h[3]);
+ pwd->h[4] = msa_cle_u_df(DF_HALF, pws->h[4], pwt->h[4]);
+ pwd->h[5] = msa_cle_u_df(DF_HALF, pws->h[5], pwt->h[5]);
+ pwd->h[6] = msa_cle_u_df(DF_HALF, pws->h[6], pwt->h[6]);
+ pwd->h[7] = msa_cle_u_df(DF_HALF, pws->h[7], pwt->h[7]);
+}
+
+void helper_msa_cle_u_w(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->w[0] = msa_cle_u_df(DF_WORD, pws->w[0], pwt->w[0]);
+ pwd->w[1] = msa_cle_u_df(DF_WORD, pws->w[1], pwt->w[1]);
+ pwd->w[2] = msa_cle_u_df(DF_WORD, pws->w[2], pwt->w[2]);
+ pwd->w[3] = msa_cle_u_df(DF_WORD, pws->w[3], pwt->w[3]);
+}
+
+void helper_msa_cle_u_d(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->d[0] = msa_cle_u_df(DF_DOUBLE, pws->d[0], pwt->d[0]);
+ pwd->d[1] = msa_cle_u_df(DF_DOUBLE, pws->d[1], pwt->d[1]);
+}
+
+static inline int64_t msa_clt_s_df(uint32_t df, int64_t arg1, int64_t arg2)
+{
+ return arg1 < arg2 ? -1 : 0;
+}
+
+void helper_msa_clt_s_b(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->b[0] = msa_clt_s_df(DF_BYTE, pws->b[0], pwt->b[0]);
+ pwd->b[1] = msa_clt_s_df(DF_BYTE, pws->b[1], pwt->b[1]);
+ pwd->b[2] = msa_clt_s_df(DF_BYTE, pws->b[2], pwt->b[2]);
+ pwd->b[3] = msa_clt_s_df(DF_BYTE, pws->b[3], pwt->b[3]);
+ pwd->b[4] = msa_clt_s_df(DF_BYTE, pws->b[4], pwt->b[4]);
+ pwd->b[5] = msa_clt_s_df(DF_BYTE, pws->b[5], pwt->b[5]);
+ pwd->b[6] = msa_clt_s_df(DF_BYTE, pws->b[6], pwt->b[6]);
+ pwd->b[7] = msa_clt_s_df(DF_BYTE, pws->b[7], pwt->b[7]);
+ pwd->b[8] = msa_clt_s_df(DF_BYTE, pws->b[8], pwt->b[8]);
+ pwd->b[9] = msa_clt_s_df(DF_BYTE, pws->b[9], pwt->b[9]);
+ pwd->b[10] = msa_clt_s_df(DF_BYTE, pws->b[10], pwt->b[10]);
+ pwd->b[11] = msa_clt_s_df(DF_BYTE, pws->b[11], pwt->b[11]);
+ pwd->b[12] = msa_clt_s_df(DF_BYTE, pws->b[12], pwt->b[12]);
+ pwd->b[13] = msa_clt_s_df(DF_BYTE, pws->b[13], pwt->b[13]);
+ pwd->b[14] = msa_clt_s_df(DF_BYTE, pws->b[14], pwt->b[14]);
+ pwd->b[15] = msa_clt_s_df(DF_BYTE, pws->b[15], pwt->b[15]);
+}
+
+void helper_msa_clt_s_h(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->h[0] = msa_clt_s_df(DF_HALF, pws->h[0], pwt->h[0]);
+ pwd->h[1] = msa_clt_s_df(DF_HALF, pws->h[1], pwt->h[1]);
+ pwd->h[2] = msa_clt_s_df(DF_HALF, pws->h[2], pwt->h[2]);
+ pwd->h[3] = msa_clt_s_df(DF_HALF, pws->h[3], pwt->h[3]);
+ pwd->h[4] = msa_clt_s_df(DF_HALF, pws->h[4], pwt->h[4]);
+ pwd->h[5] = msa_clt_s_df(DF_HALF, pws->h[5], pwt->h[5]);
+ pwd->h[6] = msa_clt_s_df(DF_HALF, pws->h[6], pwt->h[6]);
+ pwd->h[7] = msa_clt_s_df(DF_HALF, pws->h[7], pwt->h[7]);
+}
+
+void helper_msa_clt_s_w(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->w[0] = msa_clt_s_df(DF_WORD, pws->w[0], pwt->w[0]);
+ pwd->w[1] = msa_clt_s_df(DF_WORD, pws->w[1], pwt->w[1]);
+ pwd->w[2] = msa_clt_s_df(DF_WORD, pws->w[2], pwt->w[2]);
+ pwd->w[3] = msa_clt_s_df(DF_WORD, pws->w[3], pwt->w[3]);
+}
+
+void helper_msa_clt_s_d(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->d[0] = msa_clt_s_df(DF_DOUBLE, pws->d[0], pwt->d[0]);
+ pwd->d[1] = msa_clt_s_df(DF_DOUBLE, pws->d[1], pwt->d[1]);
+}
+
+static inline int64_t msa_clt_u_df(uint32_t df, int64_t arg1, int64_t arg2)
+{
+ uint64_t u_arg1 = UNSIGNED(arg1, df);
+ uint64_t u_arg2 = UNSIGNED(arg2, df);
+ return u_arg1 < u_arg2 ? -1 : 0;
+}
+
+void helper_msa_clt_u_b(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->b[0] = msa_clt_u_df(DF_BYTE, pws->b[0], pwt->b[0]);
+ pwd->b[1] = msa_clt_u_df(DF_BYTE, pws->b[1], pwt->b[1]);
+ pwd->b[2] = msa_clt_u_df(DF_BYTE, pws->b[2], pwt->b[2]);
+ pwd->b[3] = msa_clt_u_df(DF_BYTE, pws->b[3], pwt->b[3]);
+ pwd->b[4] = msa_clt_u_df(DF_BYTE, pws->b[4], pwt->b[4]);
+ pwd->b[5] = msa_clt_u_df(DF_BYTE, pws->b[5], pwt->b[5]);
+ pwd->b[6] = msa_clt_u_df(DF_BYTE, pws->b[6], pwt->b[6]);
+ pwd->b[7] = msa_clt_u_df(DF_BYTE, pws->b[7], pwt->b[7]);
+ pwd->b[8] = msa_clt_u_df(DF_BYTE, pws->b[8], pwt->b[8]);
+ pwd->b[9] = msa_clt_u_df(DF_BYTE, pws->b[9], pwt->b[9]);
+ pwd->b[10] = msa_clt_u_df(DF_BYTE, pws->b[10], pwt->b[10]);
+ pwd->b[11] = msa_clt_u_df(DF_BYTE, pws->b[11], pwt->b[11]);
+ pwd->b[12] = msa_clt_u_df(DF_BYTE, pws->b[12], pwt->b[12]);
+ pwd->b[13] = msa_clt_u_df(DF_BYTE, pws->b[13], pwt->b[13]);
+ pwd->b[14] = msa_clt_u_df(DF_BYTE, pws->b[14], pwt->b[14]);
+ pwd->b[15] = msa_clt_u_df(DF_BYTE, pws->b[15], pwt->b[15]);
+}
+
+void helper_msa_clt_u_h(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->h[0] = msa_clt_u_df(DF_HALF, pws->h[0], pwt->h[0]);
+ pwd->h[1] = msa_clt_u_df(DF_HALF, pws->h[1], pwt->h[1]);
+ pwd->h[2] = msa_clt_u_df(DF_HALF, pws->h[2], pwt->h[2]);
+ pwd->h[3] = msa_clt_u_df(DF_HALF, pws->h[3], pwt->h[3]);
+ pwd->h[4] = msa_clt_u_df(DF_HALF, pws->h[4], pwt->h[4]);
+ pwd->h[5] = msa_clt_u_df(DF_HALF, pws->h[5], pwt->h[5]);
+ pwd->h[6] = msa_clt_u_df(DF_HALF, pws->h[6], pwt->h[6]);
+ pwd->h[7] = msa_clt_u_df(DF_HALF, pws->h[7], pwt->h[7]);
+}
+
+void helper_msa_clt_u_w(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->w[0] = msa_clt_u_df(DF_WORD, pws->w[0], pwt->w[0]);
+ pwd->w[1] = msa_clt_u_df(DF_WORD, pws->w[1], pwt->w[1]);
+ pwd->w[2] = msa_clt_u_df(DF_WORD, pws->w[2], pwt->w[2]);
+ pwd->w[3] = msa_clt_u_df(DF_WORD, pws->w[3], pwt->w[3]);
+}
+
+void helper_msa_clt_u_d(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->d[0] = msa_clt_u_df(DF_DOUBLE, pws->d[0], pwt->d[0]);
+ pwd->d[1] = msa_clt_u_df(DF_DOUBLE, pws->d[1], pwt->d[1]);
+}
/*
@@ -266,7 +1525,154 @@
* +---------------+----------------------------------------------------------+
*/
-/* TODO: insert Int Divide group helpers here */
+
+static inline int64_t msa_div_s_df(uint32_t df, int64_t arg1, int64_t arg2)
+{
+ if (arg1 == DF_MIN_INT(df) && arg2 == -1) {
+ return DF_MIN_INT(df);
+ }
+ return arg2 ? arg1 / arg2
+ : arg1 >= 0 ? -1 : 1;
+}
+
+void helper_msa_div_s_b(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->b[0] = msa_div_s_df(DF_BYTE, pws->b[0], pwt->b[0]);
+ pwd->b[1] = msa_div_s_df(DF_BYTE, pws->b[1], pwt->b[1]);
+ pwd->b[2] = msa_div_s_df(DF_BYTE, pws->b[2], pwt->b[2]);
+ pwd->b[3] = msa_div_s_df(DF_BYTE, pws->b[3], pwt->b[3]);
+ pwd->b[4] = msa_div_s_df(DF_BYTE, pws->b[4], pwt->b[4]);
+ pwd->b[5] = msa_div_s_df(DF_BYTE, pws->b[5], pwt->b[5]);
+ pwd->b[6] = msa_div_s_df(DF_BYTE, pws->b[6], pwt->b[6]);
+ pwd->b[7] = msa_div_s_df(DF_BYTE, pws->b[7], pwt->b[7]);
+ pwd->b[8] = msa_div_s_df(DF_BYTE, pws->b[8], pwt->b[8]);
+ pwd->b[9] = msa_div_s_df(DF_BYTE, pws->b[9], pwt->b[9]);
+ pwd->b[10] = msa_div_s_df(DF_BYTE, pws->b[10], pwt->b[10]);
+ pwd->b[11] = msa_div_s_df(DF_BYTE, pws->b[11], pwt->b[11]);
+ pwd->b[12] = msa_div_s_df(DF_BYTE, pws->b[12], pwt->b[12]);
+ pwd->b[13] = msa_div_s_df(DF_BYTE, pws->b[13], pwt->b[13]);
+ pwd->b[14] = msa_div_s_df(DF_BYTE, pws->b[14], pwt->b[14]);
+ pwd->b[15] = msa_div_s_df(DF_BYTE, pws->b[15], pwt->b[15]);
+}
+
+void helper_msa_div_s_h(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->h[0] = msa_div_s_df(DF_HALF, pws->h[0], pwt->h[0]);
+ pwd->h[1] = msa_div_s_df(DF_HALF, pws->h[1], pwt->h[1]);
+ pwd->h[2] = msa_div_s_df(DF_HALF, pws->h[2], pwt->h[2]);
+ pwd->h[3] = msa_div_s_df(DF_HALF, pws->h[3], pwt->h[3]);
+ pwd->h[4] = msa_div_s_df(DF_HALF, pws->h[4], pwt->h[4]);
+ pwd->h[5] = msa_div_s_df(DF_HALF, pws->h[5], pwt->h[5]);
+ pwd->h[6] = msa_div_s_df(DF_HALF, pws->h[6], pwt->h[6]);
+ pwd->h[7] = msa_div_s_df(DF_HALF, pws->h[7], pwt->h[7]);
+}
+
+void helper_msa_div_s_w(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->w[0] = msa_div_s_df(DF_WORD, pws->w[0], pwt->w[0]);
+ pwd->w[1] = msa_div_s_df(DF_WORD, pws->w[1], pwt->w[1]);
+ pwd->w[2] = msa_div_s_df(DF_WORD, pws->w[2], pwt->w[2]);
+ pwd->w[3] = msa_div_s_df(DF_WORD, pws->w[3], pwt->w[3]);
+}
+
+void helper_msa_div_s_d(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->d[0] = msa_div_s_df(DF_DOUBLE, pws->d[0], pwt->d[0]);
+ pwd->d[1] = msa_div_s_df(DF_DOUBLE, pws->d[1], pwt->d[1]);
+}
+
+static inline int64_t msa_div_u_df(uint32_t df, int64_t arg1, int64_t arg2)
+{
+ uint64_t u_arg1 = UNSIGNED(arg1, df);
+ uint64_t u_arg2 = UNSIGNED(arg2, df);
+ return arg2 ? u_arg1 / u_arg2 : -1;
+}
+
+void helper_msa_div_u_b(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->b[0] = msa_div_u_df(DF_BYTE, pws->b[0], pwt->b[0]);
+ pwd->b[1] = msa_div_u_df(DF_BYTE, pws->b[1], pwt->b[1]);
+ pwd->b[2] = msa_div_u_df(DF_BYTE, pws->b[2], pwt->b[2]);
+ pwd->b[3] = msa_div_u_df(DF_BYTE, pws->b[3], pwt->b[3]);
+ pwd->b[4] = msa_div_u_df(DF_BYTE, pws->b[4], pwt->b[4]);
+ pwd->b[5] = msa_div_u_df(DF_BYTE, pws->b[5], pwt->b[5]);
+ pwd->b[6] = msa_div_u_df(DF_BYTE, pws->b[6], pwt->b[6]);
+ pwd->b[7] = msa_div_u_df(DF_BYTE, pws->b[7], pwt->b[7]);
+ pwd->b[8] = msa_div_u_df(DF_BYTE, pws->b[8], pwt->b[8]);
+ pwd->b[9] = msa_div_u_df(DF_BYTE, pws->b[9], pwt->b[9]);
+ pwd->b[10] = msa_div_u_df(DF_BYTE, pws->b[10], pwt->b[10]);
+ pwd->b[11] = msa_div_u_df(DF_BYTE, pws->b[11], pwt->b[11]);
+ pwd->b[12] = msa_div_u_df(DF_BYTE, pws->b[12], pwt->b[12]);
+ pwd->b[13] = msa_div_u_df(DF_BYTE, pws->b[13], pwt->b[13]);
+ pwd->b[14] = msa_div_u_df(DF_BYTE, pws->b[14], pwt->b[14]);
+ pwd->b[15] = msa_div_u_df(DF_BYTE, pws->b[15], pwt->b[15]);
+}
+
+void helper_msa_div_u_h(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->h[0] = msa_div_u_df(DF_HALF, pws->h[0], pwt->h[0]);
+ pwd->h[1] = msa_div_u_df(DF_HALF, pws->h[1], pwt->h[1]);
+ pwd->h[2] = msa_div_u_df(DF_HALF, pws->h[2], pwt->h[2]);
+ pwd->h[3] = msa_div_u_df(DF_HALF, pws->h[3], pwt->h[3]);
+ pwd->h[4] = msa_div_u_df(DF_HALF, pws->h[4], pwt->h[4]);
+ pwd->h[5] = msa_div_u_df(DF_HALF, pws->h[5], pwt->h[5]);
+ pwd->h[6] = msa_div_u_df(DF_HALF, pws->h[6], pwt->h[6]);
+ pwd->h[7] = msa_div_u_df(DF_HALF, pws->h[7], pwt->h[7]);
+}
+
+void helper_msa_div_u_w(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->w[0] = msa_div_u_df(DF_WORD, pws->w[0], pwt->w[0]);
+ pwd->w[1] = msa_div_u_df(DF_WORD, pws->w[1], pwt->w[1]);
+ pwd->w[2] = msa_div_u_df(DF_WORD, pws->w[2], pwt->w[2]);
+ pwd->w[3] = msa_div_u_df(DF_WORD, pws->w[3], pwt->w[3]);
+}
+
+void helper_msa_div_u_d(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->d[0] = msa_div_u_df(DF_DOUBLE, pws->d[0], pwt->d[0]);
+ pwd->d[1] = msa_div_u_df(DF_DOUBLE, pws->d[1], pwt->d[1]);
+}
/*
@@ -349,7 +1755,152 @@
* +---------------+----------------------------------------------------------+
*/
-/* TODO: insert Int Modulo group helpers here */
+static inline int64_t msa_mod_s_df(uint32_t df, int64_t arg1, int64_t arg2)
+{
+ if (arg1 == DF_MIN_INT(df) && arg2 == -1) {
+ return 0;
+ }
+ return arg2 ? arg1 % arg2 : arg1;
+}
+
+void helper_msa_mod_s_b(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->b[0] = msa_mod_s_df(DF_BYTE, pws->b[0], pwt->b[0]);
+ pwd->b[1] = msa_mod_s_df(DF_BYTE, pws->b[1], pwt->b[1]);
+ pwd->b[2] = msa_mod_s_df(DF_BYTE, pws->b[2], pwt->b[2]);
+ pwd->b[3] = msa_mod_s_df(DF_BYTE, pws->b[3], pwt->b[3]);
+ pwd->b[4] = msa_mod_s_df(DF_BYTE, pws->b[4], pwt->b[4]);
+ pwd->b[5] = msa_mod_s_df(DF_BYTE, pws->b[5], pwt->b[5]);
+ pwd->b[6] = msa_mod_s_df(DF_BYTE, pws->b[6], pwt->b[6]);
+ pwd->b[7] = msa_mod_s_df(DF_BYTE, pws->b[7], pwt->b[7]);
+ pwd->b[8] = msa_mod_s_df(DF_BYTE, pws->b[8], pwt->b[8]);
+ pwd->b[9] = msa_mod_s_df(DF_BYTE, pws->b[9], pwt->b[9]);
+ pwd->b[10] = msa_mod_s_df(DF_BYTE, pws->b[10], pwt->b[10]);
+ pwd->b[11] = msa_mod_s_df(DF_BYTE, pws->b[11], pwt->b[11]);
+ pwd->b[12] = msa_mod_s_df(DF_BYTE, pws->b[12], pwt->b[12]);
+ pwd->b[13] = msa_mod_s_df(DF_BYTE, pws->b[13], pwt->b[13]);
+ pwd->b[14] = msa_mod_s_df(DF_BYTE, pws->b[14], pwt->b[14]);
+ pwd->b[15] = msa_mod_s_df(DF_BYTE, pws->b[15], pwt->b[15]);
+}
+
+void helper_msa_mod_s_h(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->h[0] = msa_mod_s_df(DF_HALF, pws->h[0], pwt->h[0]);
+ pwd->h[1] = msa_mod_s_df(DF_HALF, pws->h[1], pwt->h[1]);
+ pwd->h[2] = msa_mod_s_df(DF_HALF, pws->h[2], pwt->h[2]);
+ pwd->h[3] = msa_mod_s_df(DF_HALF, pws->h[3], pwt->h[3]);
+ pwd->h[4] = msa_mod_s_df(DF_HALF, pws->h[4], pwt->h[4]);
+ pwd->h[5] = msa_mod_s_df(DF_HALF, pws->h[5], pwt->h[5]);
+ pwd->h[6] = msa_mod_s_df(DF_HALF, pws->h[6], pwt->h[6]);
+ pwd->h[7] = msa_mod_s_df(DF_HALF, pws->h[7], pwt->h[7]);
+}
+
+void helper_msa_mod_s_w(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->w[0] = msa_mod_s_df(DF_WORD, pws->w[0], pwt->w[0]);
+ pwd->w[1] = msa_mod_s_df(DF_WORD, pws->w[1], pwt->w[1]);
+ pwd->w[2] = msa_mod_s_df(DF_WORD, pws->w[2], pwt->w[2]);
+ pwd->w[3] = msa_mod_s_df(DF_WORD, pws->w[3], pwt->w[3]);
+}
+
+void helper_msa_mod_s_d(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->d[0] = msa_mod_s_df(DF_DOUBLE, pws->d[0], pwt->d[0]);
+ pwd->d[1] = msa_mod_s_df(DF_DOUBLE, pws->d[1], pwt->d[1]);
+}
+
+static inline int64_t msa_mod_u_df(uint32_t df, int64_t arg1, int64_t arg2)
+{
+ uint64_t u_arg1 = UNSIGNED(arg1, df);
+ uint64_t u_arg2 = UNSIGNED(arg2, df);
+ return u_arg2 ? u_arg1 % u_arg2 : u_arg1;
+}
+
+void helper_msa_mod_u_b(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->b[0] = msa_mod_u_df(DF_BYTE, pws->b[0], pwt->b[0]);
+ pwd->b[1] = msa_mod_u_df(DF_BYTE, pws->b[1], pwt->b[1]);
+ pwd->b[2] = msa_mod_u_df(DF_BYTE, pws->b[2], pwt->b[2]);
+ pwd->b[3] = msa_mod_u_df(DF_BYTE, pws->b[3], pwt->b[3]);
+ pwd->b[4] = msa_mod_u_df(DF_BYTE, pws->b[4], pwt->b[4]);
+ pwd->b[5] = msa_mod_u_df(DF_BYTE, pws->b[5], pwt->b[5]);
+ pwd->b[6] = msa_mod_u_df(DF_BYTE, pws->b[6], pwt->b[6]);
+ pwd->b[7] = msa_mod_u_df(DF_BYTE, pws->b[7], pwt->b[7]);
+ pwd->b[8] = msa_mod_u_df(DF_BYTE, pws->b[8], pwt->b[8]);
+ pwd->b[9] = msa_mod_u_df(DF_BYTE, pws->b[9], pwt->b[9]);
+ pwd->b[10] = msa_mod_u_df(DF_BYTE, pws->b[10], pwt->b[10]);
+ pwd->b[11] = msa_mod_u_df(DF_BYTE, pws->b[11], pwt->b[11]);
+ pwd->b[12] = msa_mod_u_df(DF_BYTE, pws->b[12], pwt->b[12]);
+ pwd->b[13] = msa_mod_u_df(DF_BYTE, pws->b[13], pwt->b[13]);
+ pwd->b[14] = msa_mod_u_df(DF_BYTE, pws->b[14], pwt->b[14]);
+ pwd->b[15] = msa_mod_u_df(DF_BYTE, pws->b[15], pwt->b[15]);
+}
+
+void helper_msa_mod_u_h(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->h[0] = msa_mod_u_df(DF_HALF, pws->h[0], pwt->h[0]);
+ pwd->h[1] = msa_mod_u_df(DF_HALF, pws->h[1], pwt->h[1]);
+ pwd->h[2] = msa_mod_u_df(DF_HALF, pws->h[2], pwt->h[2]);
+ pwd->h[3] = msa_mod_u_df(DF_HALF, pws->h[3], pwt->h[3]);
+ pwd->h[4] = msa_mod_u_df(DF_HALF, pws->h[4], pwt->h[4]);
+ pwd->h[5] = msa_mod_u_df(DF_HALF, pws->h[5], pwt->h[5]);
+ pwd->h[6] = msa_mod_u_df(DF_HALF, pws->h[6], pwt->h[6]);
+ pwd->h[7] = msa_mod_u_df(DF_HALF, pws->h[7], pwt->h[7]);
+}
+
+void helper_msa_mod_u_w(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->w[0] = msa_mod_u_df(DF_WORD, pws->w[0], pwt->w[0]);
+ pwd->w[1] = msa_mod_u_df(DF_WORD, pws->w[1], pwt->w[1]);
+ pwd->w[2] = msa_mod_u_df(DF_WORD, pws->w[2], pwt->w[2]);
+ pwd->w[3] = msa_mod_u_df(DF_WORD, pws->w[3], pwt->w[3]);
+}
+
+void helper_msa_mod_u_d(CPUMIPSState *env,
+ uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->d[0] = msa_mod_u_df(DF_DOUBLE, pws->d[0], pwt->d[0]);
+ pwd->d[1] = msa_mod_u_df(DF_DOUBLE, pws->d[1], pwt->d[1]);
+}
/*
@@ -459,7 +2010,46 @@
* +---------------+----------------------------------------------------------+
*/
-/* TODO: insert Logic group helpers here */
+
+void helper_msa_and_v(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->d[0] = pws->d[0] & pwt->d[0];
+ pwd->d[1] = pws->d[1] & pwt->d[1];
+}
+
+void helper_msa_nor_v(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->d[0] = ~(pws->d[0] | pwt->d[0]);
+ pwd->d[1] = ~(pws->d[1] | pwt->d[1]);
+}
+
+void helper_msa_or_v(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->d[0] = pws->d[0] | pwt->d[0];
+ pwd->d[1] = pws->d[1] | pwt->d[1];
+}
+
+void helper_msa_xor_v(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
+
+ pwd->d[0] = pws->d[0] ^ pwt->d[0];
+ pwd->d[1] = pws->d[1] ^ pwt->d[1];
+}
/*
@@ -471,7 +2061,19 @@
* +---------------+----------------------------------------------------------+
*/
-/* TODO: insert Move group helpers here */
+static inline void msa_move_v(wr_t *pwd, wr_t *pws)
+{
+ pwd->d[0] = pws->d[0];
+ pwd->d[1] = pws->d[1];
+}
+
+void helper_msa_move_v(CPUMIPSState *env, uint32_t wd, uint32_t ws)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+
+ msa_move_v(pwd, pws);
+}
/*
@@ -528,15 +2130,6 @@
/* TODO: insert Shift group helpers here */
-static inline void msa_move_v(wr_t *pwd, wr_t *pws)
-{
- uint32_t i;
-
- for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) {
- pwd->d[i] = pws->d[i];
- }
-}
-
#define MSA_FN_IMM8(FUNC, DEST, OPERATION) \
void helper_msa_ ## FUNC(CPUMIPSState *env, uint32_t wd, uint32_t ws, \
uint32_t i8) \
@@ -569,6 +2162,9 @@ MSA_FN_IMM8(bmzi_b, pwd->b[i],
MSA_FN_IMM8(bseli_b, pwd->b[i],
BIT_SELECT(pwd->b[i], pws->b[i], i8, DF_BYTE))
+#undef BIT_SELECT
+#undef BIT_MOVE_IF_ZERO
+#undef BIT_MOVE_IF_NOT_ZERO
#undef MSA_FN_IMM8
#define SHF_POS(i, imm) (((i) & 0xfc) + (((imm) >> (2 * ((i) & 0x03))) & 0x03))
@@ -603,70 +2199,6 @@ void helper_msa_shf_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
msa_move_v(pwd, pwx);
}
-#define MSA_FN_VECTOR(FUNC, DEST, OPERATION) \
-void helper_msa_ ## FUNC(CPUMIPSState *env, uint32_t wd, uint32_t ws, \
- uint32_t wt) \
-{ \
- wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \
- wr_t *pws = &(env->active_fpu.fpr[ws].wr); \
- wr_t *pwt = &(env->active_fpu.fpr[wt].wr); \
- uint32_t i; \
- for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { \
- DEST = OPERATION; \
- } \
-}
-
-MSA_FN_VECTOR(bmnz_v, pwd->d[i],
- BIT_MOVE_IF_NOT_ZERO(pwd->d[i], pws->d[i], pwt->d[i], DF_DOUBLE))
-MSA_FN_VECTOR(bmz_v, pwd->d[i],
- BIT_MOVE_IF_ZERO(pwd->d[i], pws->d[i], pwt->d[i], DF_DOUBLE))
-MSA_FN_VECTOR(bsel_v, pwd->d[i],
- BIT_SELECT(pwd->d[i], pws->d[i], pwt->d[i], DF_DOUBLE))
-#undef BIT_MOVE_IF_NOT_ZERO
-#undef BIT_MOVE_IF_ZERO
-#undef BIT_SELECT
-#undef MSA_FN_VECTOR
-
-void helper_msa_and_v(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt)
-{
- wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
- wr_t *pws = &(env->active_fpu.fpr[ws].wr);
- wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
-
- pwd->d[0] = pws->d[0] & pwt->d[0];
- pwd->d[1] = pws->d[1] & pwt->d[1];
-}
-
-void helper_msa_or_v(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt)
-{
- wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
- wr_t *pws = &(env->active_fpu.fpr[ws].wr);
- wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
-
- pwd->d[0] = pws->d[0] | pwt->d[0];
- pwd->d[1] = pws->d[1] | pwt->d[1];
-}
-
-void helper_msa_nor_v(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt)
-{
- wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
- wr_t *pws = &(env->active_fpu.fpr[ws].wr);
- wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
-
- pwd->d[0] = ~(pws->d[0] | pwt->d[0]);
- pwd->d[1] = ~(pws->d[1] | pwt->d[1]);
-}
-
-void helper_msa_xor_v(CPUMIPSState *env, uint32_t wd, uint32_t ws, uint32_t wt)
-{
- wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
- wr_t *pws = &(env->active_fpu.fpr[ws].wr);
- wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
-
- pwd->d[0] = pws->d[0] ^ pwt->d[0];
- pwd->d[1] = pws->d[1] ^ pwt->d[1];
-}
-
static inline int64_t msa_addv_df(uint32_t df, int64_t arg1, int64_t arg2)
{
return arg1 + arg2;
@@ -677,35 +2209,6 @@ static inline int64_t msa_subv_df(uint32_t df, int64_t arg1, int64_t arg2)
return arg1 - arg2;
}
-static inline int64_t msa_ceq_df(uint32_t df, int64_t arg1, int64_t arg2)
-{
- return arg1 == arg2 ? -1 : 0;
-}
-
-static inline int64_t msa_cle_s_df(uint32_t df, int64_t arg1, int64_t arg2)
-{
- return arg1 <= arg2 ? -1 : 0;
-}
-
-static inline int64_t msa_cle_u_df(uint32_t df, int64_t arg1, int64_t arg2)
-{
- uint64_t u_arg1 = UNSIGNED(arg1, df);
- uint64_t u_arg2 = UNSIGNED(arg2, df);
- return u_arg1 <= u_arg2 ? -1 : 0;
-}
-
-static inline int64_t msa_clt_s_df(uint32_t df, int64_t arg1, int64_t arg2)
-{
- return arg1 < arg2 ? -1 : 0;
-}
-
-static inline int64_t msa_clt_u_df(uint32_t df, int64_t arg1, int64_t arg2)
-{
- uint64_t u_arg1 = UNSIGNED(arg1, df);
- uint64_t u_arg2 = UNSIGNED(arg2, df);
- return u_arg1 < u_arg2 ? -1 : 0;
-}
-
static inline int64_t msa_max_s_df(uint32_t df, int64_t arg1, int64_t arg2)
{
return arg1 > arg2 ? arg1 : arg2;
@@ -809,9 +2312,6 @@ void helper_msa_ldi_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
}
}
-/* Data format bit position and unsigned values */
-#define BIT_POSITION(x, df) ((uint64_t)(x) % DF_BITS(df))
-
static inline int64_t msa_sll_df(uint32_t df, int64_t arg1, int64_t arg2)
{
int32_t b_arg2 = BIT_POSITION(arg2, df);
@@ -831,55 +2331,6 @@ static inline int64_t msa_srl_df(uint32_t df, int64_t arg1, int64_t arg2)
return u_arg1 >> b_arg2;
}
-static inline int64_t msa_bclr_df(uint32_t df, int64_t arg1, int64_t arg2)
-{
- int32_t b_arg2 = BIT_POSITION(arg2, df);
- return UNSIGNED(arg1 & (~(1LL << b_arg2)), df);
-}
-
-static inline int64_t msa_bset_df(uint32_t df, int64_t arg1,
- int64_t arg2)
-{
- int32_t b_arg2 = BIT_POSITION(arg2, df);
- return UNSIGNED(arg1 | (1LL << b_arg2), df);
-}
-
-static inline int64_t msa_bneg_df(uint32_t df, int64_t arg1, int64_t arg2)
-{
- int32_t b_arg2 = BIT_POSITION(arg2, df);
- return UNSIGNED(arg1 ^ (1LL << b_arg2), df);
-}
-
-static inline int64_t msa_binsl_df(uint32_t df, int64_t dest, int64_t arg1,
- int64_t arg2)
-{
- uint64_t u_arg1 = UNSIGNED(arg1, df);
- uint64_t u_dest = UNSIGNED(dest, df);
- int32_t sh_d = BIT_POSITION(arg2, df) + 1;
- int32_t sh_a = DF_BITS(df) - sh_d;
- if (sh_d == DF_BITS(df)) {
- return u_arg1;
- } else {
- return UNSIGNED(UNSIGNED(u_dest << sh_d, df) >> sh_d, df) |
- UNSIGNED(UNSIGNED(u_arg1 >> sh_a, df) << sh_a, df);
- }
-}
-
-static inline int64_t msa_binsr_df(uint32_t df, int64_t dest, int64_t arg1,
- int64_t arg2)
-{
- uint64_t u_arg1 = UNSIGNED(arg1, df);
- uint64_t u_dest = UNSIGNED(dest, df);
- int32_t sh_d = BIT_POSITION(arg2, df) + 1;
- int32_t sh_a = DF_BITS(df) - sh_d;
- if (sh_d == DF_BITS(df)) {
- return u_arg1;
- } else {
- return UNSIGNED(UNSIGNED(u_dest >> sh_d, df) << sh_d, df) |
- UNSIGNED(UNSIGNED(u_arg1 << sh_a, df) >> sh_a, df);
- }
-}
-
static inline int64_t msa_sat_s_df(uint32_t df, int64_t arg, uint32_t m)
{
return arg < M_MIN_INT(m + 1) ? M_MIN_INT(m + 1) :
@@ -1057,34 +2508,6 @@ static inline uint64_t msa_adds_u_df(uint32_t df, uint64_t arg1, uint64_t arg2)
return (u_arg1 < max_uint - u_arg2) ? u_arg1 + u_arg2 : max_uint;
}
-static inline int64_t msa_ave_s_df(uint32_t df, int64_t arg1, int64_t arg2)
-{
- /* signed shift */
- return (arg1 >> 1) + (arg2 >> 1) + (arg1 & arg2 & 1);
-}
-
-static inline uint64_t msa_ave_u_df(uint32_t df, uint64_t arg1, uint64_t arg2)
-{
- uint64_t u_arg1 = UNSIGNED(arg1, df);
- uint64_t u_arg2 = UNSIGNED(arg2, df);
- /* unsigned shift */
- return (u_arg1 >> 1) + (u_arg2 >> 1) + (u_arg1 & u_arg2 & 1);
-}
-
-static inline int64_t msa_aver_s_df(uint32_t df, int64_t arg1, int64_t arg2)
-{
- /* signed shift */
- return (arg1 >> 1) + (arg2 >> 1) + ((arg1 | arg2) & 1);
-}
-
-static inline uint64_t msa_aver_u_df(uint32_t df, uint64_t arg1, uint64_t arg2)
-{
- uint64_t u_arg1 = UNSIGNED(arg1, df);
- uint64_t u_arg2 = UNSIGNED(arg2, df);
- /* unsigned shift */
- return (u_arg1 >> 1) + (u_arg2 >> 1) + ((u_arg1 | u_arg2) & 1);
-}
-
static inline int64_t msa_subs_s_df(uint32_t df, int64_t arg1, int64_t arg2)
{
int64_t max_int = DF_MAX_INT(df);
@@ -1158,37 +2581,6 @@ static inline int64_t msa_mulv_df(uint32_t df, int64_t arg1, int64_t arg2)
return arg1 * arg2;
}
-static inline int64_t msa_div_s_df(uint32_t df, int64_t arg1, int64_t arg2)
-{
- if (arg1 == DF_MIN_INT(df) && arg2 == -1) {
- return DF_MIN_INT(df);
- }
- return arg2 ? arg1 / arg2
- : arg1 >= 0 ? -1 : 1;
-}
-
-static inline int64_t msa_div_u_df(uint32_t df, int64_t arg1, int64_t arg2)
-{
- uint64_t u_arg1 = UNSIGNED(arg1, df);
- uint64_t u_arg2 = UNSIGNED(arg2, df);
- return arg2 ? u_arg1 / u_arg2 : -1;
-}
-
-static inline int64_t msa_mod_s_df(uint32_t df, int64_t arg1, int64_t arg2)
-{
- if (arg1 == DF_MIN_INT(df) && arg2 == -1) {
- return 0;
- }
- return arg2 ? arg1 % arg2 : arg1;
-}
-
-static inline int64_t msa_mod_u_df(uint32_t df, int64_t arg1, int64_t arg2)
-{
- uint64_t u_arg1 = UNSIGNED(arg1, df);
- uint64_t u_arg2 = UNSIGNED(arg2, df);
- return u_arg2 ? u_arg1 % u_arg2 : u_arg1;
-}
-
#define SIGNED_EVEN(a, df) \
((((int64_t)(a)) << (64 - DF_BITS(df) / 2)) >> (64 - DF_BITS(df) / 2))
@@ -1375,9 +2767,6 @@ void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, \
MSA_BINOP_DF(sll)
MSA_BINOP_DF(sra)
MSA_BINOP_DF(srl)
-MSA_BINOP_DF(bclr)
-MSA_BINOP_DF(bset)
-MSA_BINOP_DF(bneg)
MSA_BINOP_DF(addv)
MSA_BINOP_DF(subv)
MSA_BINOP_DF(max_s)
@@ -1386,19 +2775,10 @@ MSA_BINOP_DF(min_s)
MSA_BINOP_DF(min_u)
MSA_BINOP_DF(max_a)
MSA_BINOP_DF(min_a)
-MSA_BINOP_DF(ceq)
-MSA_BINOP_DF(clt_s)
-MSA_BINOP_DF(clt_u)
-MSA_BINOP_DF(cle_s)
-MSA_BINOP_DF(cle_u)
MSA_BINOP_DF(add_a)
MSA_BINOP_DF(adds_a)
MSA_BINOP_DF(adds_s)
MSA_BINOP_DF(adds_u)
-MSA_BINOP_DF(ave_s)
-MSA_BINOP_DF(ave_u)
-MSA_BINOP_DF(aver_s)
-MSA_BINOP_DF(aver_u)
MSA_BINOP_DF(subs_s)
MSA_BINOP_DF(subs_u)
MSA_BINOP_DF(subsus_u)
@@ -1406,10 +2786,6 @@ MSA_BINOP_DF(subsuu_s)
MSA_BINOP_DF(asub_s)
MSA_BINOP_DF(asub_u)
MSA_BINOP_DF(mulv)
-MSA_BINOP_DF(div_s)
-MSA_BINOP_DF(div_u)
-MSA_BINOP_DF(mod_s)
-MSA_BINOP_DF(mod_u)
MSA_BINOP_DF(dotp_s)
MSA_BINOP_DF(dotp_u)
MSA_BINOP_DF(srar)
@@ -2500,56 +3876,6 @@ target_ulong helper_msa_cfcmsa(CPUMIPSState *env, uint32_t cs)
return 0;
}
-void helper_msa_move_v(CPUMIPSState *env, uint32_t wd, uint32_t ws)
-{
- wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
- wr_t *pws = &(env->active_fpu.fpr[ws].wr);
-
- msa_move_v(pwd, pws);
-}
-
-static inline int64_t msa_pcnt_df(uint32_t df, int64_t arg)
-{
- uint64_t x;
-
- x = UNSIGNED(arg, df);
-
- x = (x & 0x5555555555555555ULL) + ((x >> 1) & 0x5555555555555555ULL);
- x = (x & 0x3333333333333333ULL) + ((x >> 2) & 0x3333333333333333ULL);
- x = (x & 0x0F0F0F0F0F0F0F0FULL) + ((x >> 4) & 0x0F0F0F0F0F0F0F0FULL);
- x = (x & 0x00FF00FF00FF00FFULL) + ((x >> 8) & 0x00FF00FF00FF00FFULL);
- x = (x & 0x0000FFFF0000FFFFULL) + ((x >> 16) & 0x0000FFFF0000FFFFULL);
- x = (x & 0x00000000FFFFFFFFULL) + ((x >> 32));
-
- return x;
-}
-
-static inline int64_t msa_nlzc_df(uint32_t df, int64_t arg)
-{
- uint64_t x, y;
- int n, c;
-
- x = UNSIGNED(arg, df);
- n = DF_BITS(df);
- c = DF_BITS(df) / 2;
-
- do {
- y = x >> c;
- if (y != 0) {
- n = n - c;
- x = y;
- }
- c = c >> 1;
- } while (c != 0);
-
- return n - x;
-}
-
-static inline int64_t msa_nloc_df(uint32_t df, int64_t arg)
-{
- return msa_nlzc_df(df, UNSIGNED((~arg), df));
-}
-
void helper_msa_fill_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
uint32_t rs)
{
@@ -2582,61 +3908,6 @@ void helper_msa_fill_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
}
}
-#define MSA_UNOP_DF(func) \
-void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, \
- uint32_t wd, uint32_t ws) \
-{ \
- wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \
- wr_t *pws = &(env->active_fpu.fpr[ws].wr); \
- \
- switch (df) { \
- case DF_BYTE: \
- pwd->b[0] = msa_ ## func ## _df(df, pws->b[0]); \
- pwd->b[1] = msa_ ## func ## _df(df, pws->b[1]); \
- pwd->b[2] = msa_ ## func ## _df(df, pws->b[2]); \
- pwd->b[3] = msa_ ## func ## _df(df, pws->b[3]); \
- pwd->b[4] = msa_ ## func ## _df(df, pws->b[4]); \
- pwd->b[5] = msa_ ## func ## _df(df, pws->b[5]); \
- pwd->b[6] = msa_ ## func ## _df(df, pws->b[6]); \
- pwd->b[7] = msa_ ## func ## _df(df, pws->b[7]); \
- pwd->b[8] = msa_ ## func ## _df(df, pws->b[8]); \
- pwd->b[9] = msa_ ## func ## _df(df, pws->b[9]); \
- pwd->b[10] = msa_ ## func ## _df(df, pws->b[10]); \
- pwd->b[11] = msa_ ## func ## _df(df, pws->b[11]); \
- pwd->b[12] = msa_ ## func ## _df(df, pws->b[12]); \
- pwd->b[13] = msa_ ## func ## _df(df, pws->b[13]); \
- pwd->b[14] = msa_ ## func ## _df(df, pws->b[14]); \
- pwd->b[15] = msa_ ## func ## _df(df, pws->b[15]); \
- break; \
- case DF_HALF: \
- pwd->h[0] = msa_ ## func ## _df(df, pws->h[0]); \
- pwd->h[1] = msa_ ## func ## _df(df, pws->h[1]); \
- pwd->h[2] = msa_ ## func ## _df(df, pws->h[2]); \
- pwd->h[3] = msa_ ## func ## _df(df, pws->h[3]); \
- pwd->h[4] = msa_ ## func ## _df(df, pws->h[4]); \
- pwd->h[5] = msa_ ## func ## _df(df, pws->h[5]); \
- pwd->h[6] = msa_ ## func ## _df(df, pws->h[6]); \
- pwd->h[7] = msa_ ## func ## _df(df, pws->h[7]); \
- break; \
- case DF_WORD: \
- pwd->w[0] = msa_ ## func ## _df(df, pws->w[0]); \
- pwd->w[1] = msa_ ## func ## _df(df, pws->w[1]); \
- pwd->w[2] = msa_ ## func ## _df(df, pws->w[2]); \
- pwd->w[3] = msa_ ## func ## _df(df, pws->w[3]); \
- break; \
- case DF_DOUBLE: \
- pwd->d[0] = msa_ ## func ## _df(df, pws->d[0]); \
- pwd->d[1] = msa_ ## func ## _df(df, pws->d[1]); \
- break; \
- default: \
- assert(0); \
- } \
-}
-
-MSA_UNOP_DF(nlzc)
-MSA_UNOP_DF(nloc)
-MSA_UNOP_DF(pcnt)
-#undef MSA_UNOP_DF
#define FLOAT_ONE32 make_float32(0x3f8 << 20)
#define FLOAT_ONE64 make_float64(0x3ffULL << 52)
diff --git a/target/mips/op_helper.c b/target/mips/op_helper.c
index 01b9e78..4de6465 100644
--- a/target/mips/op_helper.c
+++ b/target/mips/op_helper.c
@@ -2668,27 +2668,19 @@ void mips_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
do_raise_exception_err(env, excp, error_code, retaddr);
}
-void mips_cpu_unassigned_access(CPUState *cs, hwaddr addr,
- bool is_write, bool is_exec, int unused,
- unsigned size)
+void mips_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
+ vaddr addr, unsigned size,
+ MMUAccessType access_type,
+ int mmu_idx, MemTxAttrs attrs,
+ MemTxResult response, uintptr_t retaddr)
{
MIPSCPU *cpu = MIPS_CPU(cs);
CPUMIPSState *env = &cpu->env;
- /*
- * Raising an exception with KVM enabled will crash because it won't be from
- * the main execution loop so the longjmp won't have a matching setjmp.
- * Until we can trigger a bus error exception through KVM lets just ignore
- * the access.
- */
- if (kvm_enabled()) {
- return;
- }
-
- if (is_exec) {
- raise_exception(env, EXCP_IBE);
+ if (access_type == MMU_INST_FETCH) {
+ do_raise_exception(env, EXCP_IBE, retaddr);
} else {
- raise_exception(env, EXCP_DBE);
+ do_raise_exception(env, EXCP_DBE, retaddr);
}
}
#endif /* !CONFIG_USER_ONLY */
diff --git a/target/mips/translate.c b/target/mips/translate.c
index f211995..5039716 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -7118,7 +7118,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
tcg_gen_andi_tl(arg, arg, ~0xffff);
register_name = "BadInstrX";
break;
- default:
+ default:
goto cp0_unimplemented;
}
break;
@@ -7545,7 +7545,7 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
case CP0_REG31__KSCRATCH6:
CP0_CHECK(ctx->kscrexist & (1 << sel));
tcg_gen_ld_tl(arg, cpu_env,
- offsetof(CPUMIPSState, CP0_KScratch[sel-2]));
+ offsetof(CPUMIPSState, CP0_KScratch[sel - 2]));
tcg_gen_ext32s_tl(arg, arg);
register_name = "KScratch";
break;
@@ -8295,7 +8295,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
case CP0_REG31__KSCRATCH6:
CP0_CHECK(ctx->kscrexist & (1 << sel));
tcg_gen_st_tl(arg, cpu_env,
- offsetof(CPUMIPSState, CP0_KScratch[sel-2]));
+ offsetof(CPUMIPSState, CP0_KScratch[sel - 2]));
register_name = "KScratch";
break;
default:
@@ -8387,17 +8387,20 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REG01__YQMASK:
CP0_CHECK(ctx->insn_flags & ASE_MT);
- tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_YQMask));
+ tcg_gen_ld_tl(arg, cpu_env,
+ offsetof(CPUMIPSState, CP0_YQMask));
register_name = "YQMask";
break;
case CP0_REG01__VPESCHEDULE:
CP0_CHECK(ctx->insn_flags & ASE_MT);
- tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPESchedule));
+ tcg_gen_ld_tl(arg, cpu_env,
+ offsetof(CPUMIPSState, CP0_VPESchedule));
register_name = "VPESchedule";
break;
case CP0_REG01__VPESCHEFBACK:
CP0_CHECK(ctx->insn_flags & ASE_MT);
- tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPEScheFBack));
+ tcg_gen_ld_tl(arg, cpu_env,
+ offsetof(CPUMIPSState, CP0_VPEScheFBack));
register_name = "VPEScheFBack";
break;
case CP0_REG01__VPEOPT:
@@ -8412,7 +8415,8 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
case CP0_REGISTER_02:
switch (sel) {
case CP0_REG02__ENTRYLO0:
- tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EntryLo0));
+ tcg_gen_ld_tl(arg, cpu_env,
+ offsetof(CPUMIPSState, CP0_EntryLo0));
register_name = "EntryLo0";
break;
case CP0_REG02__TCSTATUS:
@@ -8756,7 +8760,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config5));
register_name = "Config5";
break;
- /* 6,7 are implementation dependent */
+ /* 6,7 are implementation dependent */
case CP0_REG16__CONFIG6:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config6));
register_name = "Config6";
@@ -8837,7 +8841,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
}
break;
case CP0_REGISTER_21:
- /* Officially reserved, but sel 0 is used for R1x000 framemask */
+ /* Officially reserved, but sel 0 is used for R1x000 framemask */
CP0_CHECK(!(ctx->insn_flags & ISA_MIPS32R6));
switch (sel) {
case 0:
@@ -9022,7 +9026,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
case CP0_REG31__KSCRATCH6:
CP0_CHECK(ctx->kscrexist & (1 << sel));
tcg_gen_ld_tl(arg, cpu_env,
- offsetof(CPUMIPSState, CP0_KScratch[sel-2]));
+ offsetof(CPUMIPSState, CP0_KScratch[sel - 2]));
register_name = "KScratch";
break;
default:
@@ -9112,12 +9116,14 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case CP0_REG01__VPESCHEDULE:
CP0_CHECK(ctx->insn_flags & ASE_MT);
- tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPESchedule));
+ tcg_gen_st_tl(arg, cpu_env,
+ offsetof(CPUMIPSState, CP0_VPESchedule));
register_name = "VPESchedule";
break;
case CP0_REG01__VPESCHEFBACK:
CP0_CHECK(ctx->insn_flags & ASE_MT);
- tcg_gen_st_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_VPEScheFBack));
+ tcg_gen_st_tl(arg, cpu_env,
+ offsetof(CPUMIPSState, CP0_VPEScheFBack));
register_name = "VPEScheFBack";
break;
case CP0_REG01__VPEOPT:
@@ -28380,15 +28386,300 @@ static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx)
TCGv_i32 twt = tcg_const_i32(wt);
switch (MASK_MSA_3R(ctx->opcode)) {
+ case OPC_BINSL_df:
+ switch (df) {
+ case DF_BYTE:
+ gen_helper_msa_binsl_b(cpu_env, twd, tws, twt);
+ break;
+ case DF_HALF:
+ gen_helper_msa_binsl_h(cpu_env, twd, tws, twt);
+ break;
+ case DF_WORD:
+ gen_helper_msa_binsl_w(cpu_env, twd, tws, twt);
+ break;
+ case DF_DOUBLE:
+ gen_helper_msa_binsl_d(cpu_env, twd, tws, twt);
+ break;
+ }
+ break;
+ case OPC_BINSR_df:
+ switch (df) {
+ case DF_BYTE:
+ gen_helper_msa_binsr_b(cpu_env, twd, tws, twt);
+ break;
+ case DF_HALF:
+ gen_helper_msa_binsr_h(cpu_env, twd, tws, twt);
+ break;
+ case DF_WORD:
+ gen_helper_msa_binsr_w(cpu_env, twd, tws, twt);
+ break;
+ case DF_DOUBLE:
+ gen_helper_msa_binsr_d(cpu_env, twd, tws, twt);
+ break;
+ }
+ break;
+ case OPC_BCLR_df:
+ switch (df) {
+ case DF_BYTE:
+ gen_helper_msa_bclr_b(cpu_env, twd, tws, twt);
+ break;
+ case DF_HALF:
+ gen_helper_msa_bclr_h(cpu_env, twd, tws, twt);
+ break;
+ case DF_WORD:
+ gen_helper_msa_bclr_w(cpu_env, twd, tws, twt);
+ break;
+ case DF_DOUBLE:
+ gen_helper_msa_bclr_d(cpu_env, twd, tws, twt);
+ break;
+ }
+ break;
+ case OPC_BNEG_df:
+ switch (df) {
+ case DF_BYTE:
+ gen_helper_msa_bneg_b(cpu_env, twd, tws, twt);
+ break;
+ case DF_HALF:
+ gen_helper_msa_bneg_h(cpu_env, twd, tws, twt);
+ break;
+ case DF_WORD:
+ gen_helper_msa_bneg_w(cpu_env, twd, tws, twt);
+ break;
+ case DF_DOUBLE:
+ gen_helper_msa_bneg_d(cpu_env, twd, tws, twt);
+ break;
+ }
+ break;
+ case OPC_BSET_df:
+ switch (df) {
+ case DF_BYTE:
+ gen_helper_msa_bset_b(cpu_env, twd, tws, twt);
+ break;
+ case DF_HALF:
+ gen_helper_msa_bset_h(cpu_env, twd, tws, twt);
+ break;
+ case DF_WORD:
+ gen_helper_msa_bset_w(cpu_env, twd, tws, twt);
+ break;
+ case DF_DOUBLE:
+ gen_helper_msa_bset_d(cpu_env, twd, tws, twt);
+ break;
+ }
+ break;
+ case OPC_AVE_S_df:
+ switch (df) {
+ case DF_BYTE:
+ gen_helper_msa_ave_s_b(cpu_env, twd, tws, twt);
+ break;
+ case DF_HALF:
+ gen_helper_msa_ave_s_h(cpu_env, twd, tws, twt);
+ break;
+ case DF_WORD:
+ gen_helper_msa_ave_s_w(cpu_env, twd, tws, twt);
+ break;
+ case DF_DOUBLE:
+ gen_helper_msa_ave_s_d(cpu_env, twd, tws, twt);
+ break;
+ }
+ break;
+ case OPC_AVE_U_df:
+ switch (df) {
+ case DF_BYTE:
+ gen_helper_msa_ave_u_b(cpu_env, twd, tws, twt);
+ break;
+ case DF_HALF:
+ gen_helper_msa_ave_u_h(cpu_env, twd, tws, twt);
+ break;
+ case DF_WORD:
+ gen_helper_msa_ave_u_w(cpu_env, twd, tws, twt);
+ break;
+ case DF_DOUBLE:
+ gen_helper_msa_ave_u_d(cpu_env, twd, tws, twt);
+ break;
+ }
+ break;
+ case OPC_AVER_S_df:
+ switch (df) {
+ case DF_BYTE:
+ gen_helper_msa_aver_s_b(cpu_env, twd, tws, twt);
+ break;
+ case DF_HALF:
+ gen_helper_msa_aver_s_h(cpu_env, twd, tws, twt);
+ break;
+ case DF_WORD:
+ gen_helper_msa_aver_s_w(cpu_env, twd, tws, twt);
+ break;
+ case DF_DOUBLE:
+ gen_helper_msa_aver_s_d(cpu_env, twd, tws, twt);
+ break;
+ }
+ break;
+ case OPC_AVER_U_df:
+ switch (df) {
+ case DF_BYTE:
+ gen_helper_msa_aver_u_b(cpu_env, twd, tws, twt);
+ break;
+ case DF_HALF:
+ gen_helper_msa_aver_u_h(cpu_env, twd, tws, twt);
+ break;
+ case DF_WORD:
+ gen_helper_msa_aver_u_w(cpu_env, twd, tws, twt);
+ break;
+ case DF_DOUBLE:
+ gen_helper_msa_aver_u_d(cpu_env, twd, tws, twt);
+ break;
+ }
+ break;
+ case OPC_CEQ_df:
+ switch (df) {
+ case DF_BYTE:
+ gen_helper_msa_ceq_b(cpu_env, twd, tws, twt);
+ break;
+ case DF_HALF:
+ gen_helper_msa_ceq_h(cpu_env, twd, tws, twt);
+ break;
+ case DF_WORD:
+ gen_helper_msa_ceq_w(cpu_env, twd, tws, twt);
+ break;
+ case DF_DOUBLE:
+ gen_helper_msa_ceq_d(cpu_env, twd, tws, twt);
+ break;
+ }
+ break;
+ case OPC_CLE_S_df:
+ switch (df) {
+ case DF_BYTE:
+ gen_helper_msa_cle_s_b(cpu_env, twd, tws, twt);
+ break;
+ case DF_HALF:
+ gen_helper_msa_cle_s_h(cpu_env, twd, tws, twt);
+ break;
+ case DF_WORD:
+ gen_helper_msa_cle_s_w(cpu_env, twd, tws, twt);
+ break;
+ case DF_DOUBLE:
+ gen_helper_msa_cle_s_d(cpu_env, twd, tws, twt);
+ break;
+ }
+ break;
+ case OPC_CLE_U_df:
+ switch (df) {
+ case DF_BYTE:
+ gen_helper_msa_cle_u_b(cpu_env, twd, tws, twt);
+ break;
+ case DF_HALF:
+ gen_helper_msa_cle_u_h(cpu_env, twd, tws, twt);
+ break;
+ case DF_WORD:
+ gen_helper_msa_cle_u_w(cpu_env, twd, tws, twt);
+ break;
+ case DF_DOUBLE:
+ gen_helper_msa_cle_u_d(cpu_env, twd, tws, twt);
+ break;
+ }
+ break;
+ case OPC_CLT_S_df:
+ switch (df) {
+ case DF_BYTE:
+ gen_helper_msa_clt_s_b(cpu_env, twd, tws, twt);
+ break;
+ case DF_HALF:
+ gen_helper_msa_clt_s_h(cpu_env, twd, tws, twt);
+ break;
+ case DF_WORD:
+ gen_helper_msa_clt_s_w(cpu_env, twd, tws, twt);
+ break;
+ case DF_DOUBLE:
+ gen_helper_msa_clt_s_d(cpu_env, twd, tws, twt);
+ break;
+ }
+ break;
+ case OPC_CLT_U_df:
+ switch (df) {
+ case DF_BYTE:
+ gen_helper_msa_clt_u_b(cpu_env, twd, tws, twt);
+ break;
+ case DF_HALF:
+ gen_helper_msa_clt_u_h(cpu_env, twd, tws, twt);
+ break;
+ case DF_WORD:
+ gen_helper_msa_clt_u_w(cpu_env, twd, tws, twt);
+ break;
+ case DF_DOUBLE:
+ gen_helper_msa_clt_u_d(cpu_env, twd, tws, twt);
+ break;
+ }
+ break;
+ case OPC_DIV_S_df:
+ switch (df) {
+ case DF_BYTE:
+ gen_helper_msa_div_s_b(cpu_env, twd, tws, twt);
+ break;
+ case DF_HALF:
+ gen_helper_msa_div_s_h(cpu_env, twd, tws, twt);
+ break;
+ case DF_WORD:
+ gen_helper_msa_div_s_w(cpu_env, twd, tws, twt);
+ break;
+ case DF_DOUBLE:
+ gen_helper_msa_div_s_d(cpu_env, twd, tws, twt);
+ break;
+ }
+ break;
+ case OPC_DIV_U_df:
+ switch (df) {
+ case DF_BYTE:
+ gen_helper_msa_div_u_b(cpu_env, twd, tws, twt);
+ break;
+ case DF_HALF:
+ gen_helper_msa_div_u_h(cpu_env, twd, tws, twt);
+ break;
+ case DF_WORD:
+ gen_helper_msa_div_u_w(cpu_env, twd, tws, twt);
+ break;
+ case DF_DOUBLE:
+ gen_helper_msa_div_u_d(cpu_env, twd, tws, twt);
+ break;
+ }
+ break;
+ case OPC_MOD_S_df:
+ switch (df) {
+ case DF_BYTE:
+ gen_helper_msa_mod_s_b(cpu_env, twd, tws, twt);
+ break;
+ case DF_HALF:
+ gen_helper_msa_mod_s_h(cpu_env, twd, tws, twt);
+ break;
+ case DF_WORD:
+ gen_helper_msa_mod_s_w(cpu_env, twd, tws, twt);
+ break;
+ case DF_DOUBLE:
+ gen_helper_msa_mod_s_d(cpu_env, twd, tws, twt);
+ break;
+ }
+ break;
+ case OPC_MOD_U_df:
+ switch (df) {
+ case DF_BYTE:
+ gen_helper_msa_mod_u_b(cpu_env, twd, tws, twt);
+ break;
+ case DF_HALF:
+ gen_helper_msa_mod_u_h(cpu_env, twd, tws, twt);
+ break;
+ case DF_WORD:
+ gen_helper_msa_mod_u_w(cpu_env, twd, tws, twt);
+ break;
+ case DF_DOUBLE:
+ gen_helper_msa_mod_u_d(cpu_env, twd, tws, twt);
+ break;
+ }
+ break;
case OPC_SLL_df:
gen_helper_msa_sll_df(cpu_env, tdf, twd, tws, twt);
break;
case OPC_ADDV_df:
gen_helper_msa_addv_df(cpu_env, tdf, twd, tws, twt);
break;
- case OPC_CEQ_df:
- gen_helper_msa_ceq_df(cpu_env, tdf, twd, tws, twt);
- break;
case OPC_ADD_A_df:
gen_helper_msa_add_a_df(cpu_env, tdf, twd, tws, twt);
break;
@@ -28431,9 +28722,6 @@ static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx)
case OPC_MAX_S_df:
gen_helper_msa_max_s_df(cpu_env, tdf, twd, tws, twt);
break;
- case OPC_CLT_S_df:
- gen_helper_msa_clt_s_df(cpu_env, tdf, twd, tws, twt);
- break;
case OPC_ADDS_S_df:
gen_helper_msa_adds_s_df(cpu_env, tdf, twd, tws, twt);
break;
@@ -28449,15 +28737,9 @@ static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx)
case OPC_SRLR_df:
gen_helper_msa_srlr_df(cpu_env, tdf, twd, tws, twt);
break;
- case OPC_BCLR_df:
- gen_helper_msa_bclr_df(cpu_env, tdf, twd, tws, twt);
- break;
case OPC_MAX_U_df:
gen_helper_msa_max_u_df(cpu_env, tdf, twd, tws, twt);
break;
- case OPC_CLT_U_df:
- gen_helper_msa_clt_u_df(cpu_env, tdf, twd, tws, twt);
- break;
case OPC_ADDS_U_df:
gen_helper_msa_adds_u_df(cpu_env, tdf, twd, tws, twt);
break;
@@ -28467,75 +28749,33 @@ static void gen_msa_3r(CPUMIPSState *env, DisasContext *ctx)
case OPC_PCKOD_df:
gen_helper_msa_pckod_df(cpu_env, tdf, twd, tws, twt);
break;
- case OPC_BSET_df:
- gen_helper_msa_bset_df(cpu_env, tdf, twd, tws, twt);
- break;
case OPC_MIN_S_df:
gen_helper_msa_min_s_df(cpu_env, tdf, twd, tws, twt);
break;
- case OPC_CLE_S_df:
- gen_helper_msa_cle_s_df(cpu_env, tdf, twd, tws, twt);
- break;
- case OPC_AVE_S_df:
- gen_helper_msa_ave_s_df(cpu_env, tdf, twd, tws, twt);
- break;
case OPC_ASUB_S_df:
gen_helper_msa_asub_s_df(cpu_env, tdf, twd, tws, twt);
break;
- case OPC_DIV_S_df:
- gen_helper_msa_div_s_df(cpu_env, tdf, twd, tws, twt);
- break;
case OPC_ILVL_df:
gen_helper_msa_ilvl_df(cpu_env, tdf, twd, tws, twt);
break;
- case OPC_BNEG_df:
- gen_helper_msa_bneg_df(cpu_env, tdf, twd, tws, twt);
- break;
case OPC_MIN_U_df:
gen_helper_msa_min_u_df(cpu_env, tdf, twd, tws, twt);
break;
- case OPC_CLE_U_df:
- gen_helper_msa_cle_u_df(cpu_env, tdf, twd, tws, twt);
- break;
- case OPC_AVE_U_df:
- gen_helper_msa_ave_u_df(cpu_env, tdf, twd, tws, twt);
- break;
case OPC_ASUB_U_df:
gen_helper_msa_asub_u_df(cpu_env, tdf, twd, tws, twt);
break;
- case OPC_DIV_U_df:
- gen_helper_msa_div_u_df(cpu_env, tdf, twd, tws, twt);
- break;
case OPC_ILVR_df:
gen_helper_msa_ilvr_df(cpu_env, tdf, twd, tws, twt);
break;
- case OPC_BINSL_df:
- gen_helper_msa_binsl_df(cpu_env, tdf, twd, tws, twt);
- break;
case OPC_MAX_A_df:
gen_helper_msa_max_a_df(cpu_env, tdf, twd, tws, twt);
break;
- case OPC_AVER_S_df:
- gen_helper_msa_aver_s_df(cpu_env, tdf, twd, tws, twt);
- break;
- case OPC_MOD_S_df:
- gen_helper_msa_mod_s_df(cpu_env, tdf, twd, tws, twt);
- break;
case OPC_ILVEV_df:
gen_helper_msa_ilvev_df(cpu_env, tdf, twd, tws, twt);
break;
- case OPC_BINSR_df:
- gen_helper_msa_binsr_df(cpu_env, tdf, twd, tws, twt);
- break;
case OPC_MIN_A_df:
gen_helper_msa_min_a_df(cpu_env, tdf, twd, tws, twt);
break;
- case OPC_AVER_U_df:
- gen_helper_msa_aver_u_df(cpu_env, tdf, twd, tws, twt);
- break;
- case OPC_MOD_U_df:
- gen_helper_msa_mod_u_df(cpu_env, tdf, twd, tws, twt);
- break;
case OPC_ILVOD_df:
gen_helper_msa_ilvod_df(cpu_env, tdf, twd, tws, twt);
break;
@@ -28952,14 +29192,53 @@ static void gen_msa_2r(CPUMIPSState *env, DisasContext *ctx)
#endif
gen_helper_msa_fill_df(cpu_env, tdf, twd, tws); /* trs */
break;
- case OPC_PCNT_df:
- gen_helper_msa_pcnt_df(cpu_env, tdf, twd, tws);
- break;
case OPC_NLOC_df:
- gen_helper_msa_nloc_df(cpu_env, tdf, twd, tws);
+ switch (df) {
+ case DF_BYTE:
+ gen_helper_msa_nloc_b(cpu_env, twd, tws);
+ break;
+ case DF_HALF:
+ gen_helper_msa_nloc_h(cpu_env, twd, tws);
+ break;
+ case DF_WORD:
+ gen_helper_msa_nloc_w(cpu_env, twd, tws);
+ break;
+ case DF_DOUBLE:
+ gen_helper_msa_nloc_d(cpu_env, twd, tws);
+ break;
+ }
break;
case OPC_NLZC_df:
- gen_helper_msa_nlzc_df(cpu_env, tdf, twd, tws);
+ switch (df) {
+ case DF_BYTE:
+ gen_helper_msa_nlzc_b(cpu_env, twd, tws);
+ break;
+ case DF_HALF:
+ gen_helper_msa_nlzc_h(cpu_env, twd, tws);
+ break;
+ case DF_WORD:
+ gen_helper_msa_nlzc_w(cpu_env, twd, tws);
+ break;
+ case DF_DOUBLE:
+ gen_helper_msa_nlzc_d(cpu_env, twd, tws);
+ break;
+ }
+ break;
+ case OPC_PCNT_df:
+ switch (df) {
+ case DF_BYTE:
+ gen_helper_msa_pcnt_b(cpu_env, twd, tws);
+ break;
+ case DF_HALF:
+ gen_helper_msa_pcnt_h(cpu_env, twd, tws);
+ break;
+ case DF_WORD:
+ gen_helper_msa_pcnt_w(cpu_env, twd, tws);
+ break;
+ case DF_DOUBLE:
+ gen_helper_msa_pcnt_d(cpu_env, twd, tws);
+ break;
+ }
break;
default:
MIPS_INVAL("MSA instruction");
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index eaee1a5..e3e8232 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -235,6 +235,7 @@ typedef union _ppc_vsr_t {
} ppc_vsr_t;
typedef ppc_vsr_t ppc_avr_t;
+typedef ppc_vsr_t ppc_fprp_t;
#if !defined(CONFIG_USER_ONLY)
/* Software TLB cache */
@@ -559,6 +560,9 @@ enum {
/*****************************************************************************/
/* Floating point status and control register */
+#define FPSCR_DRN2 34 /* Decimal Floating-Point rounding control */
+#define FPSCR_DRN1 33 /* Decimal Floating-Point rounding control */
+#define FPSCR_DRN0 32 /* Decimal Floating-Point rounding control */
#define FPSCR_FX 31 /* Floating-point exception summary */
#define FPSCR_FEX 30 /* Floating-point enabled exception summary */
#define FPSCR_VX 29 /* Floating-point invalid operation exception summ. */
@@ -592,6 +596,7 @@ enum {
#define FPSCR_NI 2 /* Floating-point non-IEEE mode */
#define FPSCR_RN1 1
#define FPSCR_RN0 0 /* Floating-point rounding control */
+#define fpscr_drn (((env->fpscr) & FP_DRN) >> FPSCR_DRN0)
#define fpscr_fex (((env->fpscr) >> FPSCR_FEX) & 0x1)
#define fpscr_vx (((env->fpscr) >> FPSCR_VX) & 0x1)
#define fpscr_ox (((env->fpscr) >> FPSCR_OX) & 0x1)
@@ -627,6 +632,10 @@ enum {
#define fpscr_eex (((env->fpscr) >> FPSCR_XX) & ((env->fpscr) >> FPSCR_XE) & \
0x1F)
+#define FP_DRN2 (1ull << FPSCR_DRN2)
+#define FP_DRN1 (1ull << FPSCR_DRN1)
+#define FP_DRN0 (1ull << FPSCR_DRN0)
+#define FP_DRN (FP_DRN2 | FP_DRN1 | FP_DRN0)
#define FP_FX (1ull << FPSCR_FX)
#define FP_FEX (1ull << FPSCR_FEX)
#define FP_VX (1ull << FPSCR_VX)
@@ -662,7 +671,6 @@ enum {
#define FP_RN0 (1ull << FPSCR_RN0)
#define FP_RN (FP_RN1 | FP_RN0)
-#define FP_MODE FP_RN
#define FP_ENABLES (FP_VE | FP_OE | FP_UE | FP_ZE | FP_XE)
#define FP_STATUS (FP_FR | FP_FI | FP_FPRF)
diff --git a/target/ppc/dfp_helper.c b/target/ppc/dfp_helper.c
index f102177..2c65bad 100644
--- a/target/ppc/dfp_helper.c
+++ b/target/ppc/dfp_helper.c
@@ -28,17 +28,32 @@
#include "libdecnumber/dpd/decimal64.h"
#include "libdecnumber/dpd/decimal128.h"
-#if defined(HOST_WORDS_BIGENDIAN)
-#define HI_IDX 0
-#define LO_IDX 1
-#else
-#define HI_IDX 1
-#define LO_IDX 0
-#endif
+
+static void get_dfp64(ppc_vsr_t *dst, ppc_fprp_t *dfp)
+{
+ dst->VsrD(1) = dfp->VsrD(0);
+}
+
+static void get_dfp128(ppc_vsr_t *dst, ppc_fprp_t *dfp)
+{
+ dst->VsrD(0) = dfp[0].VsrD(0);
+ dst->VsrD(1) = dfp[1].VsrD(0);
+}
+
+static void set_dfp64(ppc_fprp_t *dfp, ppc_vsr_t *src)
+{
+ dfp->VsrD(0) = src->VsrD(1);
+}
+
+static void set_dfp128(ppc_fprp_t *dfp, ppc_vsr_t *src)
+{
+ dfp[0].VsrD(0) = src->VsrD(0);
+ dfp[1].VsrD(0) = src->VsrD(1);
+}
struct PPC_DFP {
CPUPPCState *env;
- uint64_t t64[2], a64[2], b64[2];
+ ppc_vsr_t vt, va, vb;
decNumber t, a, b;
decContext context;
uint8_t crbf;
@@ -48,7 +63,7 @@ static void dfp_prepare_rounding_mode(decContext *context, uint64_t fpscr)
{
enum rounding rnd;
- switch ((fpscr >> 32) & 0x7) {
+ switch ((fpscr & FP_DRN) >> FPSCR_DRN0) {
case 0:
rnd = DEC_ROUND_HALF_EVEN;
break;
@@ -121,56 +136,64 @@ static void dfp_set_round_mode_from_immediate(uint8_t r, uint8_t rmc,
decContextSetRounding(&dfp->context, rnd);
}
-static void dfp_prepare_decimal64(struct PPC_DFP *dfp, uint64_t *a,
- uint64_t *b, CPUPPCState *env)
+static void dfp_prepare_decimal64(struct PPC_DFP *dfp, ppc_fprp_t *a,
+ ppc_fprp_t *b, CPUPPCState *env)
{
decContextDefault(&dfp->context, DEC_INIT_DECIMAL64);
dfp_prepare_rounding_mode(&dfp->context, env->fpscr);
dfp->env = env;
if (a) {
- dfp->a64[0] = *a;
- decimal64ToNumber((decimal64 *)dfp->a64, &dfp->a);
+ get_dfp64(&dfp->va, a);
+ decimal64ToNumber((decimal64 *)&dfp->va.VsrD(1), &dfp->a);
} else {
- dfp->a64[0] = 0;
+ dfp->va.VsrD(1) = 0;
decNumberZero(&dfp->a);
}
if (b) {
- dfp->b64[0] = *b;
- decimal64ToNumber((decimal64 *)dfp->b64, &dfp->b);
+ get_dfp64(&dfp->vb, b);
+ decimal64ToNumber((decimal64 *)&dfp->vb.VsrD(1), &dfp->b);
} else {
- dfp->b64[0] = 0;
+ dfp->vb.VsrD(1) = 0;
decNumberZero(&dfp->b);
}
}
-static void dfp_prepare_decimal128(struct PPC_DFP *dfp, uint64_t *a,
- uint64_t *b, CPUPPCState *env)
+static void dfp_prepare_decimal128(struct PPC_DFP *dfp, ppc_fprp_t *a,
+ ppc_fprp_t *b, CPUPPCState *env)
{
decContextDefault(&dfp->context, DEC_INIT_DECIMAL128);
dfp_prepare_rounding_mode(&dfp->context, env->fpscr);
dfp->env = env;
if (a) {
- dfp->a64[0] = a[HI_IDX];
- dfp->a64[1] = a[LO_IDX];
- decimal128ToNumber((decimal128 *)dfp->a64, &dfp->a);
+ get_dfp128(&dfp->va, a);
+ decimal128ToNumber((decimal128 *)&dfp->va, &dfp->a);
} else {
- dfp->a64[0] = dfp->a64[1] = 0;
+ dfp->va.VsrD(0) = dfp->va.VsrD(1) = 0;
decNumberZero(&dfp->a);
}
if (b) {
- dfp->b64[0] = b[HI_IDX];
- dfp->b64[1] = b[LO_IDX];
- decimal128ToNumber((decimal128 *)dfp->b64, &dfp->b);
+ get_dfp128(&dfp->vb, b);
+ decimal128ToNumber((decimal128 *)&dfp->vb, &dfp->b);
} else {
- dfp->b64[0] = dfp->b64[1] = 0;
+ dfp->vb.VsrD(0) = dfp->vb.VsrD(1) = 0;
decNumberZero(&dfp->b);
}
}
+static void dfp_finalize_decimal64(struct PPC_DFP *dfp)
+{
+ decimal64FromNumber((decimal64 *)&dfp->vt.VsrD(1), &dfp->t, &dfp->context);
+}
+
+static void dfp_finalize_decimal128(struct PPC_DFP *dfp)
+{
+ decimal128FromNumber((decimal128 *)&dfp->vt, &dfp->t, &dfp->context);
+}
+
static void dfp_set_FPSCR_flag(struct PPC_DFP *dfp, uint64_t flag,
uint64_t enabled)
{
@@ -220,8 +243,8 @@ static void dfp_set_FPRF_from_FRT_with_context(struct PPC_DFP *dfp,
default:
assert(0); /* should never get here */
}
- dfp->env->fpscr &= ~(0x1F << 12);
- dfp->env->fpscr |= (fprf << 12);
+ dfp->env->fpscr &= ~FP_FPRF;
+ dfp->env->fpscr |= (fprf << FPSCR_FPRF);
}
static void dfp_set_FPRF_from_FRT(struct PPC_DFP *dfp)
@@ -369,8 +392,8 @@ static void dfp_set_CRBF_from_T(struct PPC_DFP *dfp)
static void dfp_set_FPCC_from_CRBF(struct PPC_DFP *dfp)
{
- dfp->env->fpscr &= ~(0xF << 12);
- dfp->env->fpscr |= (dfp->crbf << 12);
+ dfp->env->fpscr &= ~FP_FPCC;
+ dfp->env->fpscr |= (dfp->crbf << FPSCR_FPCC);
}
static inline void dfp_makeQNaN(decNumber *dn)
@@ -396,19 +419,15 @@ static inline int dfp_get_digit(decNumber *dn, int n)
}
#define DFP_HELPER_TAB(op, dnop, postprocs, size) \
-void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, uint64_t *b) \
+void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \
+ ppc_fprp_t *b) \
{ \
struct PPC_DFP dfp; \
dfp_prepare_decimal##size(&dfp, a, b, env); \
dnop(&dfp.t, &dfp.a, &dfp.b, &dfp.context); \
- decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, &dfp.context); \
+ dfp_finalize_decimal##size(&dfp); \
postprocs(&dfp); \
- if (size == 64) { \
- t[0] = dfp.t64[0]; \
- } else if (size == 128) { \
- t[0] = dfp.t64[HI_IDX]; \
- t[1] = dfp.t64[LO_IDX]; \
- } \
+ set_dfp##size(t, &dfp.vt); \
}
static void ADD_PPs(struct PPC_DFP *dfp)
@@ -466,12 +485,12 @@ DFP_HELPER_TAB(ddiv, decNumberDivide, DIV_PPs, 64)
DFP_HELPER_TAB(ddivq, decNumberDivide, DIV_PPs, 128)
#define DFP_HELPER_BF_AB(op, dnop, postprocs, size) \
-uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint64_t *b) \
+uint32_t helper_##op(CPUPPCState *env, ppc_fprp_t *a, ppc_fprp_t *b) \
{ \
struct PPC_DFP dfp; \
dfp_prepare_decimal##size(&dfp, a, b, env); \
dnop(&dfp.t, &dfp.a, &dfp.b, &dfp.context); \
- decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, &dfp.context); \
+ dfp_finalize_decimal##size(&dfp); \
postprocs(&dfp); \
return dfp.crbf; \
}
@@ -498,7 +517,7 @@ DFP_HELPER_BF_AB(dcmpo, decNumberCompare, CMPO_PPs, 64)
DFP_HELPER_BF_AB(dcmpoq, decNumberCompare, CMPO_PPs, 128)
#define DFP_HELPER_TSTDC(op, size) \
-uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint32_t dcm) \
+uint32_t helper_##op(CPUPPCState *env, ppc_fprp_t *a, uint32_t dcm) \
{ \
struct PPC_DFP dfp; \
int match = 0; \
@@ -526,7 +545,7 @@ DFP_HELPER_TSTDC(dtstdc, 64)
DFP_HELPER_TSTDC(dtstdcq, 128)
#define DFP_HELPER_TSTDG(op, size) \
-uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint32_t dcm) \
+uint32_t helper_##op(CPUPPCState *env, ppc_fprp_t *a, uint32_t dcm) \
{ \
struct PPC_DFP dfp; \
int minexp, maxexp, nzero_digits, nzero_idx, is_negative, is_zero, \
@@ -581,7 +600,7 @@ DFP_HELPER_TSTDG(dtstdg, 64)
DFP_HELPER_TSTDG(dtstdgq, 128)
#define DFP_HELPER_TSTEX(op, size) \
-uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint64_t *b) \
+uint32_t helper_##op(CPUPPCState *env, ppc_fprp_t *a, ppc_fprp_t *b) \
{ \
struct PPC_DFP dfp; \
int expa, expb, a_is_special, b_is_special; \
@@ -613,14 +632,16 @@ DFP_HELPER_TSTEX(dtstex, 64)
DFP_HELPER_TSTEX(dtstexq, 128)
#define DFP_HELPER_TSTSF(op, size) \
-uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint64_t *b) \
+uint32_t helper_##op(CPUPPCState *env, ppc_fprp_t *a, ppc_fprp_t *b) \
{ \
struct PPC_DFP dfp; \
unsigned k; \
+ ppc_vsr_t va; \
\
dfp_prepare_decimal##size(&dfp, 0, b, env); \
\
- k = *a & 0x3F; \
+ get_dfp64(&va, a); \
+ k = va.VsrD(1) & 0x3F; \
\
if (unlikely(decNumberIsSpecial(&dfp.b))) { \
dfp.crbf = 1; \
@@ -648,7 +669,7 @@ DFP_HELPER_TSTSF(dtstsf, 64)
DFP_HELPER_TSTSF(dtstsfq, 128)
#define DFP_HELPER_TSTSFI(op, size) \
-uint32_t helper_##op(CPUPPCState *env, uint32_t a, uint64_t *b) \
+uint32_t helper_##op(CPUPPCState *env, uint32_t a, ppc_fprp_t *b) \
{ \
struct PPC_DFP dfp; \
unsigned uim; \
@@ -708,7 +729,7 @@ static void dfp_quantize(uint8_t rmc, struct PPC_DFP *dfp)
}
#define DFP_HELPER_QUAI(op, size) \
-void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, \
+void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \
uint32_t te, uint32_t rmc) \
{ \
struct PPC_DFP dfp; \
@@ -719,40 +740,28 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, \
dfp.a.exponent = (int32_t)((int8_t)(te << 3) >> 3); \
\
dfp_quantize(rmc, &dfp); \
- decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \
- &dfp.context); \
+ dfp_finalize_decimal##size(&dfp); \
QUA_PPs(&dfp); \
\
- if (size == 64) { \
- t[0] = dfp.t64[0]; \
- } else if (size == 128) { \
- t[0] = dfp.t64[HI_IDX]; \
- t[1] = dfp.t64[LO_IDX]; \
- } \
+ set_dfp##size(t, &dfp.vt); \
}
DFP_HELPER_QUAI(dquai, 64)
DFP_HELPER_QUAI(dquaiq, 128)
#define DFP_HELPER_QUA(op, size) \
-void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, \
- uint64_t *b, uint32_t rmc) \
+void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \
+ ppc_fprp_t *b, uint32_t rmc) \
{ \
struct PPC_DFP dfp; \
\
dfp_prepare_decimal##size(&dfp, a, b, env); \
\
dfp_quantize(rmc, &dfp); \
- decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \
- &dfp.context); \
+ dfp_finalize_decimal##size(&dfp); \
QUA_PPs(&dfp); \
\
- if (size == 64) { \
- t[0] = dfp.t64[0]; \
- } else if (size == 128) { \
- t[0] = dfp.t64[HI_IDX]; \
- t[1] = dfp.t64[LO_IDX]; \
- } \
+ set_dfp##size(t, &dfp.vt); \
}
DFP_HELPER_QUA(dqua, 64)
@@ -813,33 +822,31 @@ static void _dfp_reround(uint8_t rmc, int32_t ref_sig, int32_t xmax,
}
#define DFP_HELPER_RRND(op, size) \
-void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, \
- uint64_t *b, uint32_t rmc) \
+void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \
+ ppc_fprp_t *b, uint32_t rmc) \
{ \
struct PPC_DFP dfp; \
- int32_t ref_sig = *a & 0x3F; \
+ ppc_vsr_t va; \
+ int32_t ref_sig; \
int32_t xmax = ((size) == 64) ? 369 : 6111; \
\
dfp_prepare_decimal##size(&dfp, 0, b, env); \
\
+ get_dfp64(&va, a); \
+ ref_sig = va.VsrD(1) & 0x3f; \
+ \
_dfp_reround(rmc, ref_sig, xmax, &dfp); \
- decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \
- &dfp.context); \
+ dfp_finalize_decimal##size(&dfp); \
QUA_PPs(&dfp); \
\
- if (size == 64) { \
- t[0] = dfp.t64[0]; \
- } else if (size == 128) { \
- t[0] = dfp.t64[HI_IDX]; \
- t[1] = dfp.t64[LO_IDX]; \
- } \
+ set_dfp##size(t, &dfp.vt); \
}
DFP_HELPER_RRND(drrnd, 64)
DFP_HELPER_RRND(drrndq, 128)
#define DFP_HELPER_RINT(op, postprocs, size) \
-void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, \
+void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \
uint32_t r, uint32_t rmc) \
{ \
struct PPC_DFP dfp; \
@@ -848,15 +855,10 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, \
\
dfp_set_round_mode_from_immediate(r, rmc, &dfp); \
decNumberToIntegralExact(&dfp.t, &dfp.b, &dfp.context); \
- decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, &dfp.context); \
+ dfp_finalize_decimal##size(&dfp); \
postprocs(&dfp); \
\
- if (size == 64) { \
- t[0] = dfp.t64[0]; \
- } else if (size == 128) { \
- t[0] = dfp.t64[HI_IDX]; \
- t[1] = dfp.t64[LO_IDX]; \
- } \
+ set_dfp##size(t, &dfp.vt); \
}
static void RINTX_PPs(struct PPC_DFP *dfp)
@@ -878,34 +880,42 @@ static void RINTN_PPs(struct PPC_DFP *dfp)
DFP_HELPER_RINT(drintn, RINTN_PPs, 64)
DFP_HELPER_RINT(drintnq, RINTN_PPs, 128)
-void helper_dctdp(CPUPPCState *env, uint64_t *t, uint64_t *b)
+void helper_dctdp(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b)
{
struct PPC_DFP dfp;
- uint32_t b_short = *b;
+ ppc_vsr_t vb;
+ uint32_t b_short;
+
+ get_dfp64(&vb, b);
+ b_short = (uint32_t)vb.VsrD(1);
+
dfp_prepare_decimal64(&dfp, 0, 0, env);
decimal32ToNumber((decimal32 *)&b_short, &dfp.t);
- decimal64FromNumber((decimal64 *)t, &dfp.t, &dfp.context);
+ dfp_finalize_decimal64(&dfp);
+ set_dfp64(t, &dfp.vt);
dfp_set_FPRF_from_FRT(&dfp);
}
-void helper_dctqpq(CPUPPCState *env, uint64_t *t, uint64_t *b)
+void helper_dctqpq(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b)
{
struct PPC_DFP dfp;
+ ppc_vsr_t vb;
dfp_prepare_decimal128(&dfp, 0, 0, env);
- decimal64ToNumber((decimal64 *)b, &dfp.t);
+ get_dfp64(&vb, b);
+ decimal64ToNumber((decimal64 *)&vb.VsrD(1), &dfp.t);
dfp_check_for_VXSNAN_and_convert_to_QNaN(&dfp);
dfp_set_FPRF_from_FRT(&dfp);
- decimal128FromNumber((decimal128 *)&dfp.t64, &dfp.t, &dfp.context);
- t[0] = dfp.t64[HI_IDX];
- t[1] = dfp.t64[LO_IDX];
+ dfp_finalize_decimal128(&dfp);
+ set_dfp128(t, &dfp.vt);
}
-void helper_drsp(CPUPPCState *env, uint64_t *t, uint64_t *b)
+void helper_drsp(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b)
{
struct PPC_DFP dfp;
uint32_t t_short = 0;
+ ppc_vsr_t vt;
dfp_prepare_decimal64(&dfp, 0, b, env);
decimal32FromNumber((decimal32 *)&t_short, &dfp.b, &dfp.context);
decimal32ToNumber((decimal32 *)&t_short, &dfp.t);
@@ -915,15 +925,16 @@ void helper_drsp(CPUPPCState *env, uint64_t *t, uint64_t *b)
dfp_check_for_UX(&dfp);
dfp_check_for_XX(&dfp);
- *t = t_short;
+ vt.VsrD(1) = (uint64_t)t_short;
+ set_dfp64(t, &vt);
}
-void helper_drdpq(CPUPPCState *env, uint64_t *t, uint64_t *b)
+void helper_drdpq(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b)
{
struct PPC_DFP dfp;
dfp_prepare_decimal128(&dfp, 0, b, env);
- decimal64FromNumber((decimal64 *)&dfp.t64, &dfp.b, &dfp.context);
- decimal64ToNumber((decimal64 *)&dfp.t64, &dfp.t);
+ decimal64FromNumber((decimal64 *)&dfp.vt.VsrD(1), &dfp.b, &dfp.context);
+ decimal64ToNumber((decimal64 *)&dfp.vt.VsrD(1), &dfp.t);
dfp_check_for_VXSNAN_and_convert_to_QNaN(&dfp);
dfp_set_FPRF_from_FRT_long(&dfp);
@@ -931,26 +942,23 @@ void helper_drdpq(CPUPPCState *env, uint64_t *t, uint64_t *b)
dfp_check_for_UX(&dfp);
dfp_check_for_XX(&dfp);
- decimal64FromNumber((decimal64 *)dfp.t64, &dfp.t, &dfp.context);
- t[0] = dfp.t64[0];
- t[1] = 0;
+ dfp.vt.VsrD(0) = dfp.vt.VsrD(1) = 0;
+ dfp_finalize_decimal64(&dfp);
+ set_dfp128(t, &dfp.vt);
}
#define DFP_HELPER_CFFIX(op, size) \
-void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b) \
+void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) \
{ \
struct PPC_DFP dfp; \
+ ppc_vsr_t vb; \
dfp_prepare_decimal##size(&dfp, 0, b, env); \
- decNumberFromInt64(&dfp.t, (int64_t)(*b)); \
- decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, &dfp.context); \
+ get_dfp64(&vb, b); \
+ decNumberFromInt64(&dfp.t, (int64_t)vb.VsrD(1)); \
+ dfp_finalize_decimal##size(&dfp); \
CFFIX_PPs(&dfp); \
\
- if (size == 64) { \
- t[0] = dfp.t64[0]; \
- } else if (size == 128) { \
- t[0] = dfp.t64[HI_IDX]; \
- t[1] = dfp.t64[LO_IDX]; \
- } \
+ set_dfp##size(t, &dfp.vt); \
}
static void CFFIX_PPs(struct PPC_DFP *dfp)
@@ -963,7 +971,7 @@ DFP_HELPER_CFFIX(dcffix, 64)
DFP_HELPER_CFFIX(dcffixq, 128)
#define DFP_HELPER_CTFIX(op, size) \
-void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b) \
+void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) \
{ \
struct PPC_DFP dfp; \
dfp_prepare_decimal##size(&dfp, 0, b, env); \
@@ -971,62 +979,65 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b) \
if (unlikely(decNumberIsSpecial(&dfp.b))) { \
uint64_t invalid_flags = FP_VX | FP_VXCVI; \
if (decNumberIsInfinite(&dfp.b)) { \
- dfp.t64[0] = decNumberIsNegative(&dfp.b) ? INT64_MIN : INT64_MAX; \
+ dfp.vt.VsrD(1) = decNumberIsNegative(&dfp.b) ? INT64_MIN : \
+ INT64_MAX; \
} else { /* NaN */ \
- dfp.t64[0] = INT64_MIN; \
+ dfp.vt.VsrD(1) = INT64_MIN; \
if (decNumberIsSNaN(&dfp.b)) { \
invalid_flags |= FP_VXSNAN; \
} \
} \
dfp_set_FPSCR_flag(&dfp, invalid_flags, FP_VE); \
} else if (unlikely(decNumberIsZero(&dfp.b))) { \
- dfp.t64[0] = 0; \
+ dfp.vt.VsrD(1) = 0; \
} else { \
decNumberToIntegralExact(&dfp.b, &dfp.b, &dfp.context); \
- dfp.t64[0] = decNumberIntegralToInt64(&dfp.b, &dfp.context); \
+ dfp.vt.VsrD(1) = decNumberIntegralToInt64(&dfp.b, &dfp.context); \
if (decContextTestStatus(&dfp.context, DEC_Invalid_operation)) { \
- dfp.t64[0] = decNumberIsNegative(&dfp.b) ? INT64_MIN : INT64_MAX; \
+ dfp.vt.VsrD(1) = decNumberIsNegative(&dfp.b) ? INT64_MIN : \
+ INT64_MAX; \
dfp_set_FPSCR_flag(&dfp, FP_VX | FP_VXCVI, FP_VE); \
} else { \
dfp_check_for_XX(&dfp); \
} \
} \
\
- *t = dfp.t64[0]; \
+ set_dfp64(t, &dfp.vt); \
}
DFP_HELPER_CTFIX(dctfix, 64)
DFP_HELPER_CTFIX(dctfixq, 128)
-static inline void dfp_set_bcd_digit_64(uint64_t *t, uint8_t digit,
- unsigned n)
+static inline void dfp_set_bcd_digit_64(ppc_vsr_t *t, uint8_t digit,
+ unsigned n)
{
- *t |= ((uint64_t)(digit & 0xF) << (n << 2));
+ t->VsrD(1) |= ((uint64_t)(digit & 0xF) << (n << 2));
}
-static inline void dfp_set_bcd_digit_128(uint64_t *t, uint8_t digit,
- unsigned n)
+static inline void dfp_set_bcd_digit_128(ppc_vsr_t *t, uint8_t digit,
+ unsigned n)
{
- t[(n & 0x10) ? HI_IDX : LO_IDX] |=
+ t->VsrD((n & 0x10) ? 0 : 1) |=
((uint64_t)(digit & 0xF) << ((n & 15) << 2));
}
-static inline void dfp_set_sign_64(uint64_t *t, uint8_t sgn)
+static inline void dfp_set_sign_64(ppc_vsr_t *t, uint8_t sgn)
{
- *t <<= 4;
- *t |= (sgn & 0xF);
+ t->VsrD(1) <<= 4;
+ t->VsrD(1) |= (sgn & 0xF);
}
-static inline void dfp_set_sign_128(uint64_t *t, uint8_t sgn)
+static inline void dfp_set_sign_128(ppc_vsr_t *t, uint8_t sgn)
{
- t[HI_IDX] <<= 4;
- t[HI_IDX] |= (t[LO_IDX] >> 60);
- t[LO_IDX] <<= 4;
- t[LO_IDX] |= (sgn & 0xF);
+ t->VsrD(0) <<= 4;
+ t->VsrD(0) |= (t->VsrD(1) >> 60);
+ t->VsrD(1) <<= 4;
+ t->VsrD(1) |= (sgn & 0xF);
}
#define DFP_HELPER_DEDPD(op, size) \
-void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t sp) \
+void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \
+ uint32_t sp) \
{ \
struct PPC_DFP dfp; \
uint8_t digits[34]; \
@@ -1035,11 +1046,11 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t sp) \
dfp_prepare_decimal##size(&dfp, 0, b, env); \
\
decNumberGetBCD(&dfp.b, digits); \
- dfp.t64[0] = dfp.t64[1] = 0; \
+ dfp.vt.VsrD(0) = dfp.vt.VsrD(1) = 0; \
N = dfp.b.digits; \
\
for (i = 0; (i < N) && (i < (size)/4); i++) { \
- dfp_set_bcd_digit_##size(dfp.t64, digits[N-i-1], i); \
+ dfp_set_bcd_digit_##size(&dfp.vt, digits[N - i - 1], i); \
} \
\
if (sp & 2) { \
@@ -1050,32 +1061,28 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t sp) \
} else { \
sgn = ((sp & 1) ? 0xF : 0xC); \
} \
- dfp_set_sign_##size(dfp.t64, sgn); \
+ dfp_set_sign_##size(&dfp.vt, sgn); \
} \
\
- if (size == 64) { \
- t[0] = dfp.t64[0]; \
- } else if (size == 128) { \
- t[0] = dfp.t64[HI_IDX]; \
- t[1] = dfp.t64[LO_IDX]; \
- } \
+ set_dfp##size(t, &dfp.vt); \
}
DFP_HELPER_DEDPD(ddedpd, 64)
DFP_HELPER_DEDPD(ddedpdq, 128)
-static inline uint8_t dfp_get_bcd_digit_64(uint64_t *t, unsigned n)
+static inline uint8_t dfp_get_bcd_digit_64(ppc_vsr_t *t, unsigned n)
{
- return *t >> ((n << 2) & 63) & 15;
+ return t->VsrD(1) >> ((n << 2) & 63) & 15;
}
-static inline uint8_t dfp_get_bcd_digit_128(uint64_t *t, unsigned n)
+static inline uint8_t dfp_get_bcd_digit_128(ppc_vsr_t *t, unsigned n)
{
- return t[(n & 0x10) ? HI_IDX : LO_IDX] >> ((n << 2) & 63) & 15;
+ return t->VsrD((n & 0x10) ? 0 : 1) >> ((n << 2) & 63) & 15;
}
#define DFP_HELPER_ENBCD(op, size) \
-void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t s) \
+void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \
+ uint32_t s) \
{ \
struct PPC_DFP dfp; \
uint8_t digits[32]; \
@@ -1086,7 +1093,7 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t s) \
decNumberZero(&dfp.t); \
\
if (s) { \
- uint8_t sgnNibble = dfp_get_bcd_digit_##size(dfp.b64, offset++); \
+ uint8_t sgnNibble = dfp_get_bcd_digit_##size(&dfp.vb, offset++); \
switch (sgnNibble) { \
case 0xD: \
case 0xB: \
@@ -1106,7 +1113,8 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t s) \
\
while (offset < (size) / 4) { \
n++; \
- digits[(size) / 4 - n] = dfp_get_bcd_digit_##size(dfp.b64, offset++); \
+ digits[(size) / 4 - n] = dfp_get_bcd_digit_##size(&dfp.vb, \
+ offset++); \
if (digits[(size) / 4 - n] > 10) { \
dfp_set_FPSCR_flag(&dfp, FP_VX | FP_VXCVI, FPSCR_VE); \
return; \
@@ -1122,71 +1130,72 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t s) \
if (s && sgn) { \
dfp.t.bits |= DECNEG; \
} \
- decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \
- &dfp.context); \
+ dfp_finalize_decimal##size(&dfp); \
dfp_set_FPRF_from_FRT(&dfp); \
- if ((size) == 64) { \
- t[0] = dfp.t64[0]; \
- } else if ((size) == 128) { \
- t[0] = dfp.t64[HI_IDX]; \
- t[1] = dfp.t64[LO_IDX]; \
- } \
+ set_dfp##size(t, &dfp.vt); \
}
DFP_HELPER_ENBCD(denbcd, 64)
DFP_HELPER_ENBCD(denbcdq, 128)
#define DFP_HELPER_XEX(op, size) \
-void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b) \
+void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) \
{ \
struct PPC_DFP dfp; \
+ ppc_vsr_t vt; \
\
dfp_prepare_decimal##size(&dfp, 0, b, env); \
\
if (unlikely(decNumberIsSpecial(&dfp.b))) { \
if (decNumberIsInfinite(&dfp.b)) { \
- *t = -1; \
+ vt.VsrD(1) = -1; \
} else if (decNumberIsSNaN(&dfp.b)) { \
- *t = -3; \
+ vt.VsrD(1) = -3; \
} else if (decNumberIsQNaN(&dfp.b)) { \
- *t = -2; \
+ vt.VsrD(1) = -2; \
} else { \
assert(0); \
} \
+ set_dfp64(t, &vt); \
} else { \
if ((size) == 64) { \
- *t = dfp.b.exponent + 398; \
+ vt.VsrD(1) = dfp.b.exponent + 398; \
} else if ((size) == 128) { \
- *t = dfp.b.exponent + 6176; \
+ vt.VsrD(1) = dfp.b.exponent + 6176; \
} else { \
assert(0); \
} \
+ set_dfp64(t, &vt); \
} \
}
DFP_HELPER_XEX(dxex, 64)
DFP_HELPER_XEX(dxexq, 128)
-static void dfp_set_raw_exp_64(uint64_t *t, uint64_t raw)
+static void dfp_set_raw_exp_64(ppc_vsr_t *t, uint64_t raw)
{
- *t &= 0x8003ffffffffffffULL;
- *t |= (raw << (63 - 13));
+ t->VsrD(1) &= 0x8003ffffffffffffULL;
+ t->VsrD(1) |= (raw << (63 - 13));
}
-static void dfp_set_raw_exp_128(uint64_t *t, uint64_t raw)
+static void dfp_set_raw_exp_128(ppc_vsr_t *t, uint64_t raw)
{
- t[HI_IDX] &= 0x80003fffffffffffULL;
- t[HI_IDX] |= (raw << (63 - 17));
+ t->VsrD(0) &= 0x80003fffffffffffULL;
+ t->VsrD(0) |= (raw << (63 - 17));
}
#define DFP_HELPER_IEX(op, size) \
-void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, uint64_t *b) \
+void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \
+ ppc_fprp_t *b) \
{ \
struct PPC_DFP dfp; \
uint64_t raw_qnan, raw_snan, raw_inf, max_exp; \
+ ppc_vsr_t va; \
int bias; \
- int64_t exp = *((int64_t *)a); \
+ int64_t exp; \
\
+ get_dfp64(&va, a); \
+ exp = (int64_t)va.VsrD(1); \
dfp_prepare_decimal##size(&dfp, 0, b, env); \
\
if ((size) == 64) { \
@@ -1206,14 +1215,14 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, uint64_t *b) \
} \
\
if (unlikely((exp < 0) || (exp > max_exp))) { \
- dfp.t64[0] = dfp.b64[0]; \
- dfp.t64[1] = dfp.b64[1]; \
+ dfp.vt.VsrD(0) = dfp.vb.VsrD(0); \
+ dfp.vt.VsrD(1) = dfp.vb.VsrD(1); \
if (exp == -1) { \
- dfp_set_raw_exp_##size(dfp.t64, raw_inf); \
+ dfp_set_raw_exp_##size(&dfp.vt, raw_inf); \
} else if (exp == -3) { \
- dfp_set_raw_exp_##size(dfp.t64, raw_snan); \
+ dfp_set_raw_exp_##size(&dfp.vt, raw_snan); \
} else { \
- dfp_set_raw_exp_##size(dfp.t64, raw_qnan); \
+ dfp_set_raw_exp_##size(&dfp.vt, raw_qnan); \
} \
} else { \
dfp.t = dfp.b; \
@@ -1221,15 +1230,9 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, uint64_t *b) \
dfp.t.bits &= ~DECSPECIAL; \
} \
dfp.t.exponent = exp - bias; \
- decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \
- &dfp.context); \
- } \
- if (size == 64) { \
- t[0] = dfp.t64[0]; \
- } else if (size == 128) { \
- t[0] = dfp.t64[HI_IDX]; \
- t[1] = dfp.t64[LO_IDX]; \
+ dfp_finalize_decimal##size(&dfp); \
} \
+ set_dfp##size(t, &dfp.vt); \
}
DFP_HELPER_IEX(diex, 64)
@@ -1276,7 +1279,7 @@ static void dfp_clear_lmd_from_g5msb(uint64_t *t)
}
#define DFP_HELPER_SHIFT(op, size, shift_left) \
-void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, \
+void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \
uint32_t sh) \
{ \
struct PPC_DFP dfp; \
@@ -1303,26 +1306,21 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, \
dfp.t.digits = max_digits - 1; \
} \
\
- decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \
- &dfp.context); \
+ dfp_finalize_decimal##size(&dfp); \
} else { \
if ((size) == 64) { \
- dfp.t64[0] = dfp.a64[0] & 0xFFFC000000000000ULL; \
- dfp_clear_lmd_from_g5msb(dfp.t64); \
+ dfp.vt.VsrD(1) = dfp.va.VsrD(1) & \
+ 0xFFFC000000000000ULL; \
+ dfp_clear_lmd_from_g5msb(&dfp.vt.VsrD(1)); \
} else { \
- dfp.t64[HI_IDX] = dfp.a64[HI_IDX] & \
- 0xFFFFC00000000000ULL; \
- dfp_clear_lmd_from_g5msb(dfp.t64 + HI_IDX); \
- dfp.t64[LO_IDX] = 0; \
+ dfp.vt.VsrD(0) = dfp.va.VsrD(0) & \
+ 0xFFFFC00000000000ULL; \
+ dfp_clear_lmd_from_g5msb(&dfp.vt.VsrD(0)); \
+ dfp.vt.VsrD(1) = 0; \
} \
} \
\
- if ((size) == 64) { \
- t[0] = dfp.t64[0]; \
- } else { \
- t[0] = dfp.t64[HI_IDX]; \
- t[1] = dfp.t64[LO_IDX]; \
- } \
+ set_dfp##size(t, &dfp.vt); \
}
DFP_HELPER_SHIFT(dscli, 64, 1)
diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c
index 4b1a2e6..dc38324 100644
--- a/target/ppc/fpu_helper.c
+++ b/target/ppc/fpu_helper.c
@@ -180,7 +180,7 @@ static void set_fprf_from_class(CPUPPCState *env, int class)
};
bool isneg = class & is_neg;
- env->fpscr &= ~(0x1F << FPSCR_FPRF);
+ env->fpscr &= ~FP_FPRF;
env->fpscr |= fprf[ctz32(class)][isneg] << FPSCR_FPRF;
}
@@ -199,12 +199,12 @@ COMPUTE_FPRF(float128)
static void finish_invalid_op_excp(CPUPPCState *env, int op, uintptr_t retaddr)
{
/* Update the floating-point invalid operation summary */
- env->fpscr |= 1 << FPSCR_VX;
+ env->fpscr |= FP_VX;
/* Update the floating-point exception summary */
env->fpscr |= FP_FX;
if (fpscr_ve != 0) {
/* Update the floating-point enabled exception summary */
- env->fpscr |= 1 << FPSCR_FEX;
+ env->fpscr |= FP_FEX;
if (fp_exceptions_enabled(env)) {
raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
POWERPC_EXCP_FP | op, retaddr);
@@ -215,11 +215,11 @@ static void finish_invalid_op_excp(CPUPPCState *env, int op, uintptr_t retaddr)
static void finish_invalid_op_arith(CPUPPCState *env, int op,
bool set_fpcc, uintptr_t retaddr)
{
- env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
+ env->fpscr &= ~(FP_FR | FP_FI);
if (fpscr_ve == 0) {
if (set_fpcc) {
- env->fpscr &= ~(0xF << FPSCR_FPCC);
- env->fpscr |= 0x11 << FPSCR_FPCC;
+ env->fpscr &= ~FP_FPCC;
+ env->fpscr |= (FP_C | FP_FU);
}
}
finish_invalid_op_excp(env, op, retaddr);
@@ -228,7 +228,7 @@ static void finish_invalid_op_arith(CPUPPCState *env, int op,
/* Signalling NaN */
static void float_invalid_op_vxsnan(CPUPPCState *env, uintptr_t retaddr)
{
- env->fpscr |= 1 << FPSCR_VXSNAN;
+ env->fpscr |= FP_VXSNAN;
finish_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, retaddr);
}
@@ -236,7 +236,7 @@ static void float_invalid_op_vxsnan(CPUPPCState *env, uintptr_t retaddr)
static void float_invalid_op_vxisi(CPUPPCState *env, bool set_fpcc,
uintptr_t retaddr)
{
- env->fpscr |= 1 << FPSCR_VXISI;
+ env->fpscr |= FP_VXISI;
finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXISI, set_fpcc, retaddr);
}
@@ -244,7 +244,7 @@ static void float_invalid_op_vxisi(CPUPPCState *env, bool set_fpcc,
static void float_invalid_op_vxidi(CPUPPCState *env, bool set_fpcc,
uintptr_t retaddr)
{
- env->fpscr |= 1 << FPSCR_VXIDI;
+ env->fpscr |= FP_VXIDI;
finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXIDI, set_fpcc, retaddr);
}
@@ -252,7 +252,7 @@ static void float_invalid_op_vxidi(CPUPPCState *env, bool set_fpcc,
static void float_invalid_op_vxzdz(CPUPPCState *env, bool set_fpcc,
uintptr_t retaddr)
{
- env->fpscr |= 1 << FPSCR_VXZDZ;
+ env->fpscr |= FP_VXZDZ;
finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXZDZ, set_fpcc, retaddr);
}
@@ -260,7 +260,7 @@ static void float_invalid_op_vxzdz(CPUPPCState *env, bool set_fpcc,
static void float_invalid_op_vximz(CPUPPCState *env, bool set_fpcc,
uintptr_t retaddr)
{
- env->fpscr |= 1 << FPSCR_VXIMZ;
+ env->fpscr |= FP_VXIMZ;
finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXIMZ, set_fpcc, retaddr);
}
@@ -268,7 +268,7 @@ static void float_invalid_op_vximz(CPUPPCState *env, bool set_fpcc,
static void float_invalid_op_vxsqrt(CPUPPCState *env, bool set_fpcc,
uintptr_t retaddr)
{
- env->fpscr |= 1 << FPSCR_VXSQRT;
+ env->fpscr |= FP_VXSQRT;
finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXSQRT, set_fpcc, retaddr);
}
@@ -276,13 +276,13 @@ static void float_invalid_op_vxsqrt(CPUPPCState *env, bool set_fpcc,
static void float_invalid_op_vxvc(CPUPPCState *env, bool set_fpcc,
uintptr_t retaddr)
{
- env->fpscr |= 1 << FPSCR_VXVC;
+ env->fpscr |= FP_VXVC;
if (set_fpcc) {
- env->fpscr &= ~(0xF << FPSCR_FPCC);
- env->fpscr |= 0x11 << FPSCR_FPCC;
+ env->fpscr &= ~FP_FPCC;
+ env->fpscr |= (FP_C | FP_FU);
}
/* Update the floating-point invalid operation summary */
- env->fpscr |= 1 << FPSCR_VX;
+ env->fpscr |= FP_VX;
/* Update the floating-point exception summary */
env->fpscr |= FP_FX;
/* We must update the target FPR before raising the exception */
@@ -292,7 +292,7 @@ static void float_invalid_op_vxvc(CPUPPCState *env, bool set_fpcc,
cs->exception_index = POWERPC_EXCP_PROGRAM;
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC;
/* Update the floating-point enabled exception summary */
- env->fpscr |= 1 << FPSCR_FEX;
+ env->fpscr |= FP_FEX;
/* Exception is differed */
}
}
@@ -301,12 +301,12 @@ static void float_invalid_op_vxvc(CPUPPCState *env, bool set_fpcc,
static void float_invalid_op_vxcvi(CPUPPCState *env, bool set_fpcc,
uintptr_t retaddr)
{
- env->fpscr |= 1 << FPSCR_VXCVI;
- env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
+ env->fpscr |= FP_VXCVI;
+ env->fpscr &= ~(FP_FR | FP_FI);
if (fpscr_ve == 0) {
if (set_fpcc) {
- env->fpscr &= ~(0xF << FPSCR_FPCC);
- env->fpscr |= 0x11 << FPSCR_FPCC;
+ env->fpscr &= ~FP_FPCC;
+ env->fpscr |= (FP_C | FP_FU);
}
}
finish_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, retaddr);
@@ -314,13 +314,13 @@ static void float_invalid_op_vxcvi(CPUPPCState *env, bool set_fpcc,
static inline void float_zero_divide_excp(CPUPPCState *env, uintptr_t raddr)
{
- env->fpscr |= 1 << FPSCR_ZX;
- env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
+ env->fpscr |= FP_ZX;
+ env->fpscr &= ~(FP_FR | FP_FI);
/* Update the floating-point exception summary */
env->fpscr |= FP_FX;
if (fpscr_ze != 0) {
/* Update the floating-point enabled exception summary */
- env->fpscr |= 1 << FPSCR_FEX;
+ env->fpscr |= FP_FEX;
if (fp_exceptions_enabled(env)) {
raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX,
@@ -333,19 +333,19 @@ static inline void float_overflow_excp(CPUPPCState *env)
{
CPUState *cs = env_cpu(env);
- env->fpscr |= 1 << FPSCR_OX;
+ env->fpscr |= FP_OX;
/* Update the floating-point exception summary */
env->fpscr |= FP_FX;
if (fpscr_oe != 0) {
/* XXX: should adjust the result */
/* Update the floating-point enabled exception summary */
- env->fpscr |= 1 << FPSCR_FEX;
+ env->fpscr |= FP_FEX;
/* We must update the target FPR before raising the exception */
cs->exception_index = POWERPC_EXCP_PROGRAM;
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
} else {
- env->fpscr |= 1 << FPSCR_XX;
- env->fpscr |= 1 << FPSCR_FI;
+ env->fpscr |= FP_XX;
+ env->fpscr |= FP_FI;
}
}
@@ -353,13 +353,13 @@ static inline void float_underflow_excp(CPUPPCState *env)
{
CPUState *cs = env_cpu(env);
- env->fpscr |= 1 << FPSCR_UX;
+ env->fpscr |= FP_UX;
/* Update the floating-point exception summary */
env->fpscr |= FP_FX;
if (fpscr_ue != 0) {
/* XXX: should adjust the result */
/* Update the floating-point enabled exception summary */
- env->fpscr |= 1 << FPSCR_FEX;
+ env->fpscr |= FP_FEX;
/* We must update the target FPR before raising the exception */
cs->exception_index = POWERPC_EXCP_PROGRAM;
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
@@ -370,13 +370,13 @@ static inline void float_inexact_excp(CPUPPCState *env)
{
CPUState *cs = env_cpu(env);
- env->fpscr |= 1 << FPSCR_FI;
- env->fpscr |= 1 << FPSCR_XX;
+ env->fpscr |= FP_FI;
+ env->fpscr |= FP_XX;
/* Update the floating-point exception summary */
env->fpscr |= FP_FX;
if (fpscr_xe != 0) {
/* Update the floating-point enabled exception summary */
- env->fpscr |= 1 << FPSCR_FEX;
+ env->fpscr |= FP_FEX;
/* We must update the target FPR before raising the exception */
cs->exception_index = POWERPC_EXCP_PROGRAM;
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
@@ -433,7 +433,7 @@ void helper_fpscr_clrbit(CPUPPCState *env, uint32_t bit)
case FPSCR_VXCVI:
if (!fpscr_ix) {
/* Set VX bit to zero */
- env->fpscr &= ~(1 << FPSCR_VX);
+ env->fpscr &= ~FP_VX;
}
break;
case FPSCR_OX:
@@ -447,7 +447,7 @@ void helper_fpscr_clrbit(CPUPPCState *env, uint32_t bit)
case FPSCR_XE:
if (!fpscr_eex) {
/* Set the FEX bit */
- env->fpscr &= ~(1 << FPSCR_FEX);
+ env->fpscr &= ~FP_FEX;
}
break;
default:
@@ -504,7 +504,7 @@ void helper_fpscr_setbit(CPUPPCState *env, uint32_t bit)
case FPSCR_VXSOFT:
case FPSCR_VXSQRT:
case FPSCR_VXCVI:
- env->fpscr |= 1 << FPSCR_VX;
+ env->fpscr |= FP_VX;
env->fpscr |= FP_FX;
if (fpscr_ve != 0) {
goto raise_ve;
@@ -580,7 +580,7 @@ void helper_fpscr_setbit(CPUPPCState *env, uint32_t bit)
break;
raise_excp:
/* Update the floating-point enabled exception summary */
- env->fpscr |= 1 << FPSCR_FEX;
+ env->fpscr |= FP_FEX;
/* We have to update Rc1 before raising the exception */
cs->exception_index = POWERPC_EXCP_PROGRAM;
break;
@@ -596,8 +596,8 @@ void helper_store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask)
prev = env->fpscr;
new = (target_ulong)arg;
- new &= ~0x60000000LL;
- new |= prev & 0x60000000LL;
+ new &= ~(FP_FEX | FP_VX);
+ new |= prev & (FP_FEX | FP_VX);
for (i = 0; i < sizeof(target_ulong) * 2; i++) {
if (mask & (1 << i)) {
env->fpscr &= ~(0xFLL << (4 * i));
@@ -606,17 +606,17 @@ void helper_store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask)
}
/* Update VX and FEX */
if (fpscr_ix != 0) {
- env->fpscr |= 1 << FPSCR_VX;
+ env->fpscr |= FP_VX;
} else {
- env->fpscr &= ~(1 << FPSCR_VX);
+ env->fpscr &= ~FP_VX;
}
if ((fpscr_ex & fpscr_eex) != 0) {
- env->fpscr |= 1 << FPSCR_FEX;
+ env->fpscr |= FP_FEX;
cs->exception_index = POWERPC_EXCP_PROGRAM;
/* XXX: we should compute it properly */
env->error_code = POWERPC_EXCP_FP;
} else {
- env->fpscr &= ~(1 << FPSCR_FEX);
+ env->fpscr &= ~FP_FEX;
}
fpscr_set_rounding_mode(env);
}
@@ -639,7 +639,7 @@ static void do_float_check_status(CPUPPCState *env, uintptr_t raddr)
if (status & float_flag_inexact) {
float_inexact_excp(env);
} else {
- env->fpscr &= ~(1 << FPSCR_FI); /* clear the FPSCR[FI] bit */
+ env->fpscr &= ~FP_FI; /* clear the FPSCR[FI] bit */
}
if (cs->exception_index == POWERPC_EXCP_PROGRAM &&
@@ -1138,8 +1138,8 @@ void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
ret = 0x02UL;
}
- env->fpscr &= ~(0x0F << FPSCR_FPRF);
- env->fpscr |= ret << FPSCR_FPRF;
+ env->fpscr &= ~FP_FPCC;
+ env->fpscr |= ret << FPSCR_FPCC;
env->crf[crfD] = ret;
if (unlikely(ret == 0x01UL
&& (float64_is_signaling_nan(farg1.d, &env->fp_status) ||
@@ -1169,9 +1169,9 @@ void helper_fcmpo(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
ret = 0x02UL;
}
- env->fpscr &= ~(0x0F << FPSCR_FPRF);
- env->fpscr |= ret << FPSCR_FPRF;
- env->crf[crfD] = ret;
+ env->fpscr &= ~FP_FPCC;
+ env->fpscr |= ret << FPSCR_FPCC;
+ env->crf[crfD] = (uint32_t) ret;
if (unlikely(ret == 0x01UL)) {
float_invalid_op_vxvc(env, 1, GETPC());
if (float64_is_signaling_nan(farg1.d, &env->fp_status) ||
@@ -2431,8 +2431,8 @@ void helper_xscmpexpdp(CPUPPCState *env, uint32_t opcode,
}
}
- env->fpscr &= ~(0x0F << FPSCR_FPRF);
- env->fpscr |= cc << FPSCR_FPRF;
+ env->fpscr &= ~FP_FPCC;
+ env->fpscr |= cc << FPSCR_FPCC;
env->crf[BF(opcode)] = cc;
do_float_check_status(env, GETPC());
@@ -2460,8 +2460,8 @@ void helper_xscmpexpqp(CPUPPCState *env, uint32_t opcode,
}
}
- env->fpscr &= ~(0x0F << FPSCR_FPRF);
- env->fpscr |= cc << FPSCR_FPRF;
+ env->fpscr &= ~FP_FPCC;
+ env->fpscr |= cc << FPSCR_FPCC;
env->crf[BF(opcode)] = cc;
do_float_check_status(env, GETPC());
@@ -2505,8 +2505,8 @@ void helper_##op(CPUPPCState *env, uint32_t opcode, \
cc |= CRF_EQ; \
} \
\
- env->fpscr &= ~(0x0F << FPSCR_FPRF); \
- env->fpscr |= cc << FPSCR_FPRF; \
+ env->fpscr &= ~FP_FPCC; \
+ env->fpscr |= cc << FPSCR_FPCC; \
env->crf[BF(opcode)] = cc; \
\
do_float_check_status(env, GETPC()); \
@@ -2553,8 +2553,8 @@ void helper_##op(CPUPPCState *env, uint32_t opcode, \
cc |= CRF_EQ; \
} \
\
- env->fpscr &= ~(0x0F << FPSCR_FPRF); \
- env->fpscr |= cc << FPSCR_FPRF; \
+ env->fpscr &= ~FP_FPCC; \
+ env->fpscr |= cc << FPSCR_FPCC; \
env->crf[BF(opcode)] = cc; \
\
do_float_check_status(env, GETPC()); \
@@ -3242,8 +3242,8 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
\
if (scrf) { \
cc = sign << CRF_LT_BIT | match << CRF_EQ_BIT; \
- env->fpscr &= ~(0x0F << FPSCR_FPRF); \
- env->fpscr |= cc << FPSCR_FPRF; \
+ env->fpscr &= ~FP_FPCC; \
+ env->fpscr |= cc << FPSCR_FPCC; \
env->crf[BF(opcode)] = cc; \
} else { \
t.tfld = match ? fld_max : 0; \
@@ -3286,8 +3286,8 @@ void helper_xststdcsp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xb)
&env->fp_status), &env->fp_status);
cc = sign << CRF_LT_BIT | match << CRF_EQ_BIT | not_sp << CRF_SO_BIT;
- env->fpscr &= ~(0x0F << FPSCR_FPRF);
- env->fpscr |= cc << FPSCR_FPRF;
+ env->fpscr &= ~FP_FPCC;
+ env->fpscr |= cc << FPSCR_FPCC;
env->crf[BF(opcode)] = cc;
}
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index 54ea9b9..f843814 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -686,7 +686,7 @@ DEF_HELPER_3(store_601_batu, void, env, i32, tl)
#endif
#define dh_alias_fprp ptr
-#define dh_ctype_fprp uint64_t *
+#define dh_ctype_fprp ppc_fprp_t *
#define dh_is_signed_fprp dh_is_signed_ptr
DEF_HELPER_4(dadd, void, env, fprp, fprp, fprp)
diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c
index 46deb57..6d238b9 100644
--- a/target/ppc/int_helper.c
+++ b/target/ppc/int_helper.c
@@ -2052,15 +2052,11 @@ void helper_vsubecuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
#define NATIONAL_PLUS 0x2B
#define NATIONAL_NEG 0x2D
-#if defined(HOST_WORDS_BIGENDIAN)
#define BCD_DIG_BYTE(n) (15 - ((n) / 2))
-#else
-#define BCD_DIG_BYTE(n) ((n) / 2)
-#endif
static int bcd_get_sgn(ppc_avr_t *bcd)
{
- switch (bcd->u8[BCD_DIG_BYTE(0)] & 0xF) {
+ switch (bcd->VsrB(BCD_DIG_BYTE(0)) & 0xF) {
case BCD_PLUS_PREF_1:
case BCD_PLUS_PREF_2:
case BCD_PLUS_ALT_1:
@@ -2095,9 +2091,9 @@ static uint8_t bcd_get_digit(ppc_avr_t *bcd, int n, int *invalid)
{
uint8_t result;
if (n & 1) {
- result = bcd->u8[BCD_DIG_BYTE(n)] >> 4;
+ result = bcd->VsrB(BCD_DIG_BYTE(n)) >> 4;
} else {
- result = bcd->u8[BCD_DIG_BYTE(n)] & 0xF;
+ result = bcd->VsrB(BCD_DIG_BYTE(n)) & 0xF;
}
if (unlikely(result > 9)) {
@@ -2109,11 +2105,11 @@ static uint8_t bcd_get_digit(ppc_avr_t *bcd, int n, int *invalid)
static void bcd_put_digit(ppc_avr_t *bcd, uint8_t digit, int n)
{
if (n & 1) {
- bcd->u8[BCD_DIG_BYTE(n)] &= 0x0F;
- bcd->u8[BCD_DIG_BYTE(n)] |= (digit << 4);
+ bcd->VsrB(BCD_DIG_BYTE(n)) &= 0x0F;
+ bcd->VsrB(BCD_DIG_BYTE(n)) |= (digit << 4);
} else {
- bcd->u8[BCD_DIG_BYTE(n)] &= 0xF0;
- bcd->u8[BCD_DIG_BYTE(n)] |= digit;
+ bcd->VsrB(BCD_DIG_BYTE(n)) &= 0xF0;
+ bcd->VsrB(BCD_DIG_BYTE(n)) |= digit;
}
}
@@ -2228,21 +2224,21 @@ uint32_t helper_bcdadd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
if (!invalid) {
if (sgna == sgnb) {
- result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgna, ps);
+ result.VsrB(BCD_DIG_BYTE(0)) = bcd_preferred_sgn(sgna, ps);
bcd_add_mag(&result, a, b, &invalid, &overflow);
cr = bcd_cmp_zero(&result);
} else {
int magnitude = bcd_cmp_mag(a, b);
if (magnitude > 0) {
- result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgna, ps);
+ result.VsrB(BCD_DIG_BYTE(0)) = bcd_preferred_sgn(sgna, ps);
bcd_sub_mag(&result, a, b, &invalid, &overflow);
cr = (sgna > 0) ? CRF_GT : CRF_LT;
} else if (magnitude < 0) {
- result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgnb, ps);
+ result.VsrB(BCD_DIG_BYTE(0)) = bcd_preferred_sgn(sgnb, ps);
bcd_sub_mag(&result, b, a, &invalid, &overflow);
cr = (sgnb > 0) ? CRF_GT : CRF_LT;
} else {
- result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(0, ps);
+ result.VsrB(BCD_DIG_BYTE(0)) = bcd_preferred_sgn(0, ps);
cr = CRF_EQ;
}
}
@@ -2353,15 +2349,15 @@ uint32_t helper_bcdcfz(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
int zone_lead = ps ? 0xF : 0x3;
int digit = 0;
ppc_avr_t ret = { .u64 = { 0, 0 } };
- int sgnb = b->u8[BCD_DIG_BYTE(0)] >> 4;
+ int sgnb = b->VsrB(BCD_DIG_BYTE(0)) >> 4;
if (unlikely((sgnb < 0xA) && ps)) {
invalid = 1;
}
for (i = 0; i < 16; i++) {
- zone_digit = i ? b->u8[BCD_DIG_BYTE(i * 2)] >> 4 : zone_lead;
- digit = b->u8[BCD_DIG_BYTE(i * 2)] & 0xF;
+ zone_digit = i ? b->VsrB(BCD_DIG_BYTE(i * 2)) >> 4 : zone_lead;
+ digit = b->VsrB(BCD_DIG_BYTE(i * 2)) & 0xF;
if (unlikely(zone_digit != zone_lead || digit > 0x9)) {
invalid = 1;
break;
@@ -2407,7 +2403,7 @@ uint32_t helper_bcdctz(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
break;
}
- ret.u8[BCD_DIG_BYTE(i * 2)] = zone_lead + digit;
+ ret.VsrB(BCD_DIG_BYTE(i * 2)) = zone_lead + digit;
}
if (ps) {
@@ -2519,7 +2515,7 @@ uint32_t helper_bcdcpsgn(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
}
*r = *a;
- bcd_put_digit(r, b->u8[BCD_DIG_BYTE(0)] & 0xF, 0);
+ bcd_put_digit(r, b->VsrB(BCD_DIG_BYTE(0)) & 0xF, 0);
for (i = 1; i < 32; i++) {
bcd_get_digit(a, i, &invalid);
@@ -2549,11 +2545,7 @@ uint32_t helper_bcdsetsgn(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
uint32_t helper_bcds(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
{
int cr;
-#if defined(HOST_WORDS_BIGENDIAN)
- int i = a->s8[7];
-#else
- int i = a->s8[8];
-#endif
+ int i = a->VsrSB(7);
bool ox_flag = false;
int sgnb = bcd_get_sgn(b);
ppc_avr_t ret = *b;
@@ -2602,11 +2594,7 @@ uint32_t helper_bcdus(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
}
}
-#if defined(HOST_WORDS_BIGENDIAN)
- i = a->s8[7];
-#else
- i = a->s8[8];
-#endif
+ i = a->VsrSB(7);
if (i >= 32) {
ox_flag = true;
ret.VsrD(1) = ret.VsrD(0) = 0;
@@ -2637,13 +2625,11 @@ uint32_t helper_bcdsr(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
ppc_avr_t ret = *b;
ret.VsrD(1) &= ~0xf;
-#if defined(HOST_WORDS_BIGENDIAN)
- int i = a->s8[7];
- ppc_avr_t bcd_one = { .u64 = { 0, 0x10 } };
-#else
- int i = a->s8[8];
- ppc_avr_t bcd_one = { .u64 = { 0x10, 0 } };
-#endif
+ int i = a->VsrSB(7);
+ ppc_avr_t bcd_one;
+
+ bcd_one.VsrD(0) = 0;
+ bcd_one.VsrD(1) = 0x10;
if (bcd_is_valid(b) == false) {
return CRF_SO;
@@ -2679,11 +2665,7 @@ uint32_t helper_bcdtrunc(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
{
uint64_t mask;
uint32_t ox_flag = 0;
-#if defined(HOST_WORDS_BIGENDIAN)
- int i = a->s16[3] + 1;
-#else
- int i = a->s16[4] + 1;
-#endif
+ int i = a->VsrSH(3) + 1;
ppc_avr_t ret = *b;
if (bcd_is_valid(b) == false) {
@@ -2728,11 +2710,7 @@ uint32_t helper_bcdutrunc(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
}
}
-#if defined(HOST_WORDS_BIGENDIAN)
- i = a->s16[3];
-#else
- i = a->s16[4];
-#endif
+ i = a->VsrSH(3);
if (i > 16 && i < 33) {
mask = (uint64_t)-1 >> (128 - i * 4);
if (ret.VsrD(0) & ~mask) {
diff --git a/target/ppc/internal.h b/target/ppc/internal.h
index d3d327e..15d655b 100644
--- a/target/ppc/internal.h
+++ b/target/ppc/internal.h
@@ -157,6 +157,9 @@ EXTRACT_HELPER(FPL, 25, 1);
EXTRACT_HELPER(FPFLM, 17, 8);
EXTRACT_HELPER(FPW, 16, 1);
+/* mffscrni */
+EXTRACT_HELPER(RM, 11, 2);
+
/* addpcis */
EXTRACT_HELPER_SPLIT_3(DX, 10, 6, 6, 5, 16, 1, 1, 0, 0)
#if defined(TARGET_PPC64)
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 8c5b1f2..820724c 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -993,6 +993,10 @@ int kvm_arch_put_registers(CPUState *cs, int level)
}
kvm_set_one_reg(cs, KVM_REG_PPC_TB_OFFSET, &env->tb_env->tb_offset);
+
+ if (level > KVM_PUT_RUNTIME_STATE) {
+ kvm_put_one_spr(cs, KVM_REG_PPC_DPDES, SPR_DPDES);
+ }
#endif /* TARGET_PPC64 */
}
@@ -1297,6 +1301,7 @@ int kvm_arch_get_registers(CPUState *cs)
}
kvm_get_one_reg(cs, KVM_REG_PPC_TB_OFFSET, &env->tb_env->tb_offset);
+ kvm_get_one_spr(cs, KVM_REG_PPC_DPDES, SPR_DPDES);
#endif
}
diff --git a/target/ppc/translate/fp-impl.inc.c b/target/ppc/translate/fp-impl.inc.c
index 7cd9d8d..d8e27bf 100644
--- a/target/ppc/translate/fp-impl.inc.c
+++ b/target/ppc/translate/fp-impl.inc.c
@@ -634,11 +634,108 @@ static void gen_mffsl(DisasContext *ctx)
gen_reset_fpstatus();
tcg_gen_extu_tl_i64(t0, cpu_fpscr);
/* Mask everything except mode, status, and enables. */
- tcg_gen_andi_i64(t0, t0, FP_MODE | FP_STATUS | FP_ENABLES);
+ tcg_gen_andi_i64(t0, t0, FP_DRN | FP_STATUS | FP_ENABLES | FP_RN);
set_fpr(rD(ctx->opcode), t0);
tcg_temp_free_i64(t0);
}
+/* mffsce */
+static void gen_mffsce(DisasContext *ctx)
+{
+ TCGv_i64 t0;
+ TCGv_i32 mask;
+
+ if (unlikely(!(ctx->insns_flags2 & PPC2_ISA300))) {
+ return gen_mffs(ctx);
+ }
+
+ if (unlikely(!ctx->fpu_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_FPU);
+ return;
+ }
+
+ t0 = tcg_temp_new_i64();
+
+ gen_reset_fpstatus();
+ tcg_gen_extu_tl_i64(t0, cpu_fpscr);
+ set_fpr(rD(ctx->opcode), t0);
+
+ /* Clear exception enable bits in the FPSCR. */
+ tcg_gen_andi_i64(t0, t0, ~FP_ENABLES);
+ mask = tcg_const_i32(0x0003);
+ gen_helper_store_fpscr(cpu_env, t0, mask);
+
+ tcg_temp_free_i32(mask);
+ tcg_temp_free_i64(t0);
+}
+
+static void gen_helper_mffscrn(DisasContext *ctx, TCGv_i64 t1)
+{
+ TCGv_i64 t0 = tcg_temp_new_i64();
+ TCGv_i32 mask = tcg_const_i32(0x0001);
+
+ gen_reset_fpstatus();
+ tcg_gen_extu_tl_i64(t0, cpu_fpscr);
+ tcg_gen_andi_i64(t0, t0, FP_DRN | FP_ENABLES | FP_RN);
+ set_fpr(rD(ctx->opcode), t0);
+
+ /* Mask FPSCR value to clear RN. */
+ tcg_gen_andi_i64(t0, t0, ~FP_RN);
+
+ /* Merge RN into FPSCR value. */
+ tcg_gen_or_i64(t0, t0, t1);
+
+ gen_helper_store_fpscr(cpu_env, t0, mask);
+
+ tcg_temp_free_i32(mask);
+ tcg_temp_free_i64(t0);
+}
+
+/* mffscrn */
+static void gen_mffscrn(DisasContext *ctx)
+{
+ TCGv_i64 t1;
+
+ if (unlikely(!(ctx->insns_flags2 & PPC2_ISA300))) {
+ return gen_mffs(ctx);
+ }
+
+ if (unlikely(!ctx->fpu_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_FPU);
+ return;
+ }
+
+ t1 = tcg_temp_new_i64();
+ get_fpr(t1, rB(ctx->opcode));
+ /* Mask FRB to get just RN. */
+ tcg_gen_andi_i64(t1, t1, FP_RN);
+
+ gen_helper_mffscrn(ctx, t1);
+
+ tcg_temp_free_i64(t1);
+}
+
+/* mffscrni */
+static void gen_mffscrni(DisasContext *ctx)
+{
+ TCGv_i64 t1;
+
+ if (unlikely(!(ctx->insns_flags2 & PPC2_ISA300))) {
+ return gen_mffs(ctx);
+ }
+
+ if (unlikely(!ctx->fpu_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_FPU);
+ return;
+ }
+
+ t1 = tcg_const_i64((uint64_t)RM(ctx->opcode));
+
+ gen_helper_mffscrn(ctx, t1);
+
+ tcg_temp_free_i64(t1);
+}
+
/* mtfsb0 */
static void gen_mtfsb0(DisasContext *ctx)
{
diff --git a/target/ppc/translate/fp-ops.inc.c b/target/ppc/translate/fp-ops.inc.c
index 88ebc25..88fab65 100644
--- a/target/ppc/translate/fp-ops.inc.c
+++ b/target/ppc/translate/fp-ops.inc.c
@@ -105,8 +105,14 @@ GEN_HANDLER_E(fmrgew, 0x3F, 0x06, 0x1E, 0x00000001, PPC_NONE, PPC2_VSX207),
GEN_HANDLER_E(fmrgow, 0x3F, 0x06, 0x1A, 0x00000001, PPC_NONE, PPC2_VSX207),
GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT),
GEN_HANDLER_E_2(mffs, 0x3F, 0x07, 0x12, 0x00, 0x00000000, PPC_FLOAT, PPC_NONE),
+GEN_HANDLER_E_2(mffsce, 0x3F, 0x07, 0x12, 0x01, 0x00000000, PPC_FLOAT,
+ PPC2_ISA300),
GEN_HANDLER_E_2(mffsl, 0x3F, 0x07, 0x12, 0x18, 0x00000000, PPC_FLOAT,
PPC2_ISA300),
+GEN_HANDLER_E_2(mffscrn, 0x3F, 0x07, 0x12, 0x16, 0x00000000, PPC_FLOAT,
+ PPC_NONE),
+GEN_HANDLER_E_2(mffscrni, 0x3F, 0x07, 0x12, 0x17, 0x00000000, PPC_FLOAT,
+ PPC_NONE),
GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT),
GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT),
GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x00000000, PPC_FLOAT),
diff --git a/target/ppc/translate_init.inc.c b/target/ppc/translate_init.inc.c
index 0fb11c7..ba726de 100644
--- a/target/ppc/translate_init.inc.c
+++ b/target/ppc/translate_init.inc.c
@@ -8200,11 +8200,10 @@ static void gen_spr_power8_dpdes(CPUPPCState *env)
{
#if !defined(CONFIG_USER_ONLY)
/* Directed Privileged Door-bell Exception State, used for IPI */
- spr_register_kvm_hv(env, SPR_DPDES, "DPDES",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- KVM_REG_PPC_DPDES, 0x00000000);
+ spr_register(env, SPR_DPDES, "DPDES",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000);
#endif
}
diff --git a/target/riscv/Makefile.objs b/target/riscv/Makefile.objs
index b1c79bc..ff651f6 100644
--- a/target/riscv/Makefile.objs
+++ b/target/riscv/Makefile.objs
@@ -1,4 +1,9 @@
-obj-y += translate.o op_helper.o cpu_helper.o cpu.o csr.o fpu_helper.o gdbstub.o pmp.o
+obj-y += translate.o op_helper.o cpu_helper.o cpu.o csr.o fpu_helper.o gdbstub.o
+obj-$(CONFIG_SOFTMMU) += pmp.o
+
+ifeq ($(CONFIG_SOFTMMU),y)
+obj-y += monitor.o
+endif
DECODETREE = $(SRC_PATH)/scripts/decodetree.py
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 6d52f97..f13e298 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -34,17 +34,20 @@
static const char riscv_exts[26] = "IEMAFDQCLBJTPVNSUHKORWXYZG";
const char * const riscv_int_regnames[] = {
- "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
- "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5",
- "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7",
- "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"
+ "x0/zero", "x1/ra", "x2/sp", "x3/gp", "x4/tp", "x5/t0", "x6/t1",
+ "x7/t2", "x8/s0", "x9/s1", "x10/a0", "x11/a1", "x12/a2", "x13/a3",
+ "x14/a4", "x15/a5", "x16/a6", "x17/a7", "x18/s2", "x19/s3", "x20/s4",
+ "x21/s5", "x22/s6", "x23/s7", "x24/s8", "x25/s9", "x26/s10", "x27/s11",
+ "x28/t3", "x29/t4", "x30/t5", "x31/t6"
};
const char * const riscv_fpr_regnames[] = {
- "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7",
- "fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5",
- "fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7",
- "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11"
+ "f0/ft0", "f1/ft1", "f2/ft2", "f3/ft3", "f4/ft4", "f5/ft5",
+ "f6/ft6", "f7/ft7", "f8/fs0", "f9/fs1", "f10/fa0", "f11/fa1",
+ "f12/fa2", "f13/fa3", "f14/fa4", "f15/fa5", "f16/fa6", "f17/fa7",
+ "f18/fs2", "f19/fs3", "f20/fs4", "f21/fs5", "f22/fs6", "f23/fs7",
+ "f24/fs8", "f25/fs9", "f26/fs10", "f27/fs11", "f28/ft8", "f29/ft9",
+ "f30/ft10", "f31/ft11"
};
const char * const riscv_excp_names[] = {
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 18d91d0..124ed33 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -255,6 +255,7 @@ void riscv_cpu_do_interrupt(CPUState *cpu);
int riscv_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
+bool riscv_cpu_fp_enabled(CPURISCVState *env);
int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch);
hwaddr riscv_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
@@ -298,7 +299,10 @@ static inline void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc,
#ifdef CONFIG_USER_ONLY
*flags = TB_FLAGS_MSTATUS_FS;
#else
- *flags = cpu_mmu_index(env, 0) | (env->mstatus & MSTATUS_FS);
+ *flags = cpu_mmu_index(env, 0);
+ if (riscv_cpu_fp_enabled(env)) {
+ *flags |= TB_FLAGS_MSTATUS_FS;
+ }
#endif
}
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 11f971a..e998348 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -173,6 +173,24 @@
#define CSR_SPTBR 0x180
#define CSR_SATP 0x180
+/* Hpervisor CSRs */
+#define CSR_HSTATUS 0x600
+#define CSR_HEDELEG 0x602
+#define CSR_HIDELEG 0x603
+#define CSR_HCOUNTERNEN 0x606
+#define CSR_HGATP 0x680
+
+#if defined(TARGET_RISCV32)
+#define HGATP_MODE SATP32_MODE
+#define HGATP_VMID SATP32_ASID
+#define HGATP_PPN SATP32_PPN
+#endif
+#if defined(TARGET_RISCV64)
+#define HGATP_MODE SATP64_MODE
+#define HGATP_VMID SATP64_ASID
+#define HGATP_PPN SATP64_PPN
+#endif
+
/* Physical Memory Protection */
#define CSR_PMPCFG0 0x3a0
#define CSR_PMPCFG1 0x3a1
@@ -206,23 +224,6 @@
#define CSR_DPC 0x7b1
#define CSR_DSCRATCH 0x7b2
-/* Hpervisor CSRs */
-#define CSR_HSTATUS 0xa00
-#define CSR_HEDELEG 0xa02
-#define CSR_HIDELEG 0xa03
-#define CSR_HGATP 0xa80
-
-#if defined(TARGET_RISCV32)
-#define HGATP_MODE SATP32_MODE
-#define HGATP_ASID SATP32_ASID
-#define HGATP_PPN SATP32_PPN
-#endif
-#if defined(TARGET_RISCV64)
-#define HGATP_MODE SATP64_MODE
-#define HGATP_ASID SATP64_ASID
-#define HGATP_PPN SATP64_PPN
-#endif
-
/* Performance Counters */
#define CSR_MHPMCOUNTER3 0xb03
#define CSR_MHPMCOUNTER4 0xb04
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index e32b612..87dd6a6 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -71,6 +71,16 @@ bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
#if !defined(CONFIG_USER_ONLY)
+/* Return true is floating point support is currently enabled */
+bool riscv_cpu_fp_enabled(CPURISCVState *env)
+{
+ if (env->mstatus & MSTATUS_FS) {
+ return true;
+ }
+
+ return false;
+}
+
int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
{
CPURISCVState *env = &cpu->env;
@@ -176,12 +186,12 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
*prot = 0;
- target_ulong base;
+ hwaddr base;
int levels, ptidxbits, ptesize, vm, sum;
int mxr = get_field(env->mstatus, MSTATUS_MXR);
if (env->priv_ver >= PRIV_VERSION_1_10_0) {
- base = get_field(env->satp, SATP_PPN) << PGSHIFT;
+ base = (hwaddr)get_field(env->satp, SATP_PPN) << PGSHIFT;
sum = get_field(env->mstatus, MSTATUS_SUM);
vm = get_field(env->satp, SATP_MODE);
switch (vm) {
@@ -201,7 +211,7 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
g_assert_not_reached();
}
} else {
- base = env->sptbr << PGSHIFT;
+ base = (hwaddr)(env->sptbr) << PGSHIFT;
sum = !get_field(env->mstatus, MSTATUS_PUM);
vm = get_field(env->mstatus, MSTATUS_VM);
switch (vm) {
@@ -239,7 +249,7 @@ restart:
((1 << ptidxbits) - 1);
/* check that physical address of PTE is legal */
- target_ulong pte_addr = base + idx * ptesize;
+ hwaddr pte_addr = base + idx * ptesize;
if (riscv_feature(env, RISCV_FEATURE_PMP) &&
!pmp_hart_has_privs(env, pte_addr, sizeof(target_ulong),
@@ -251,7 +261,7 @@ restart:
#elif defined(TARGET_RISCV64)
target_ulong pte = ldq_phys(cs->as, pte_addr);
#endif
- target_ulong ppn = pte >> PTE_PPN_SHIFT;
+ hwaddr ppn = pte >> PTE_PPN_SHIFT;
if (!(pte & PTE_V)) {
/* Invalid PTE */
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index e0d4586..f767ad2 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -46,7 +46,7 @@ void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops)
static int fs(CPURISCVState *env, int csrno)
{
#if !defined(CONFIG_USER_ONLY)
- if (!env->debugger && !(env->mstatus & MSTATUS_FS)) {
+ if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
return -1;
}
#endif
@@ -108,7 +108,7 @@ static int pmp(CPURISCVState *env, int csrno)
static int read_fflags(CPURISCVState *env, int csrno, target_ulong *val)
{
#if !defined(CONFIG_USER_ONLY)
- if (!env->debugger && !(env->mstatus & MSTATUS_FS)) {
+ if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
return -1;
}
#endif
@@ -119,7 +119,7 @@ static int read_fflags(CPURISCVState *env, int csrno, target_ulong *val)
static int write_fflags(CPURISCVState *env, int csrno, target_ulong val)
{
#if !defined(CONFIG_USER_ONLY)
- if (!env->debugger && !(env->mstatus & MSTATUS_FS)) {
+ if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
return -1;
}
env->mstatus |= MSTATUS_FS;
@@ -131,7 +131,7 @@ static int write_fflags(CPURISCVState *env, int csrno, target_ulong val)
static int read_frm(CPURISCVState *env, int csrno, target_ulong *val)
{
#if !defined(CONFIG_USER_ONLY)
- if (!env->debugger && !(env->mstatus & MSTATUS_FS)) {
+ if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
return -1;
}
#endif
@@ -142,7 +142,7 @@ static int read_frm(CPURISCVState *env, int csrno, target_ulong *val)
static int write_frm(CPURISCVState *env, int csrno, target_ulong val)
{
#if !defined(CONFIG_USER_ONLY)
- if (!env->debugger && !(env->mstatus & MSTATUS_FS)) {
+ if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
return -1;
}
env->mstatus |= MSTATUS_FS;
@@ -154,7 +154,7 @@ static int write_frm(CPURISCVState *env, int csrno, target_ulong val)
static int read_fcsr(CPURISCVState *env, int csrno, target_ulong *val)
{
#if !defined(CONFIG_USER_ONLY)
- if (!env->debugger && !(env->mstatus & MSTATUS_FS)) {
+ if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
return -1;
}
#endif
@@ -166,7 +166,7 @@ static int read_fcsr(CPURISCVState *env, int csrno, target_ulong *val)
static int write_fcsr(CPURISCVState *env, int csrno, target_ulong val)
{
#if !defined(CONFIG_USER_ONLY)
- if (!env->debugger && !(env->mstatus & MSTATUS_FS)) {
+ if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
return -1;
}
env->mstatus |= MSTATUS_FS;
@@ -307,6 +307,7 @@ static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val)
{
target_ulong mstatus = env->mstatus;
target_ulong mask = 0;
+ int dirty;
/* flush tlb on mstatus fields that affect VM */
if (env->priv_ver <= PRIV_VERSION_1_09_1) {
@@ -334,14 +335,15 @@ static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val)
* RV32: MPV and MTL are not in mstatus. The current plan is to
* add them to mstatush. For now, we just don't support it.
*/
- mask |= MSTATUS_MPP | MSTATUS_MPV;
+ mask |= MSTATUS_MTL | MSTATUS_MPV;
#endif
}
mstatus = (mstatus & ~mask) | (val & mask);
- int dirty = ((mstatus & MSTATUS_FS) == MSTATUS_FS) |
- ((mstatus & MSTATUS_XS) == MSTATUS_XS);
+ dirty = (riscv_cpu_fp_enabled(env) &&
+ ((mstatus & MSTATUS_FS) == MSTATUS_FS)) |
+ ((mstatus & MSTATUS_XS) == MSTATUS_XS);
mstatus = set_field(mstatus, MSTATUS_SD, dirty);
env->mstatus = mstatus;
diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c
index 27be932..ded140e 100644
--- a/target/riscv/gdbstub.c
+++ b/target/riscv/gdbstub.c
@@ -313,7 +313,8 @@ static int riscv_gdb_get_fpu(CPURISCVState *env, uint8_t *mem_buf, int n)
* register 33, so we recalculate the map index.
* This also works for CSR_FRM and CSR_FCSR.
*/
- result = riscv_csrrw_debug(env, n - 33 + 8, &val, 0, 0);
+ result = riscv_csrrw_debug(env, n - 33 + csr_register_map[8], &val,
+ 0, 0);
if (result == 0) {
return gdb_get_regl(mem_buf, val);
}
@@ -335,7 +336,8 @@ static int riscv_gdb_set_fpu(CPURISCVState *env, uint8_t *mem_buf, int n)
* register 33, so we recalculate the map index.
* This also works for CSR_FRM and CSR_FCSR.
*/
- result = riscv_csrrw_debug(env, n - 33 + 8, NULL, val, -1);
+ result = riscv_csrrw_debug(env, n - 33 + csr_register_map[8], NULL,
+ val, -1);
if (result == 0) {
return sizeof(target_ulong);
}
diff --git a/target/riscv/monitor.c b/target/riscv/monitor.c
new file mode 100644
index 0000000..d725a7a
--- /dev/null
+++ b/target/riscv/monitor.c
@@ -0,0 +1,229 @@
+/*
+ * QEMU monitor for RISC-V
+ *
+ * Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com>
+ *
+ * RISC-V specific monitor commands implementation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 "cpu_bits.h"
+#include "monitor/monitor.h"
+#include "monitor/hmp-target.h"
+
+#ifdef TARGET_RISCV64
+#define PTE_HEADER_FIELDS "vaddr paddr "\
+ "size attr\n"
+#define PTE_HEADER_DELIMITER "---------------- ---------------- "\
+ "---------------- -------\n"
+#else
+#define PTE_HEADER_FIELDS "vaddr paddr size attr\n"
+#define PTE_HEADER_DELIMITER "-------- ---------------- -------- -------\n"
+#endif
+
+/* Perform linear address sign extension */
+static target_ulong addr_canonical(int va_bits, target_ulong addr)
+{
+#ifdef TARGET_RISCV64
+ if (addr & (1UL << (va_bits - 1))) {
+ addr |= (hwaddr)-(1L << va_bits);
+ }
+#endif
+
+ return addr;
+}
+
+static void print_pte_header(Monitor *mon)
+{
+ monitor_printf(mon, PTE_HEADER_FIELDS);
+ monitor_printf(mon, PTE_HEADER_DELIMITER);
+}
+
+static void print_pte(Monitor *mon, int va_bits, target_ulong vaddr,
+ hwaddr paddr, target_ulong size, int attr)
+{
+ /* santity check on vaddr */
+ if (vaddr >= (1UL << va_bits)) {
+ return;
+ }
+
+ if (!size) {
+ return;
+ }
+
+ monitor_printf(mon, TARGET_FMT_lx " " TARGET_FMT_plx " " TARGET_FMT_lx
+ " %c%c%c%c%c%c%c\n",
+ addr_canonical(va_bits, vaddr),
+ paddr, size,
+ attr & PTE_R ? 'r' : '-',
+ attr & PTE_W ? 'w' : '-',
+ attr & PTE_X ? 'x' : '-',
+ attr & PTE_U ? 'u' : '-',
+ attr & PTE_G ? 'g' : '-',
+ attr & PTE_A ? 'a' : '-',
+ attr & PTE_D ? 'd' : '-');
+}
+
+static void walk_pte(Monitor *mon, hwaddr base, target_ulong start,
+ int level, int ptidxbits, int ptesize, int va_bits,
+ target_ulong *vbase, hwaddr *pbase, hwaddr *last_paddr,
+ target_ulong *last_size, int *last_attr)
+{
+ hwaddr pte_addr;
+ hwaddr paddr;
+ target_ulong pgsize;
+ target_ulong pte;
+ int ptshift;
+ int attr;
+ int idx;
+
+ if (level < 0) {
+ return;
+ }
+
+ ptshift = level * ptidxbits;
+ pgsize = 1UL << (PGSHIFT + ptshift);
+
+ for (idx = 0; idx < (1UL << ptidxbits); idx++) {
+ pte_addr = base + idx * ptesize;
+ cpu_physical_memory_read(pte_addr, &pte, ptesize);
+
+ paddr = (hwaddr)(pte >> PTE_PPN_SHIFT) << PGSHIFT;
+ attr = pte & 0xff;
+
+ /* PTE has to be valid */
+ if (attr & PTE_V) {
+ if (attr & (PTE_R | PTE_W | PTE_X)) {
+ /*
+ * A leaf PTE has been found
+ *
+ * If current PTE's permission bits differ from the last one,
+ * or current PTE's ppn does not make a contiguous physical
+ * address block together with the last one, print out the last
+ * contiguous mapped block details.
+ */
+ if ((*last_attr != attr) ||
+ (*last_paddr + *last_size != paddr)) {
+ print_pte(mon, va_bits, *vbase, *pbase,
+ *last_paddr + *last_size - *pbase, *last_attr);
+
+ *vbase = start;
+ *pbase = paddr;
+ *last_attr = attr;
+ }
+
+ *last_paddr = paddr;
+ *last_size = pgsize;
+ } else {
+ /* pointer to the next level of the page table */
+ walk_pte(mon, paddr, start, level - 1, ptidxbits, ptesize,
+ va_bits, vbase, pbase, last_paddr,
+ last_size, last_attr);
+ }
+ }
+
+ start += pgsize;
+ }
+
+}
+
+static void mem_info_svxx(Monitor *mon, CPUArchState *env)
+{
+ int levels, ptidxbits, ptesize, vm, va_bits;
+ hwaddr base;
+ target_ulong vbase;
+ hwaddr pbase;
+ hwaddr last_paddr;
+ target_ulong last_size;
+ int last_attr;
+
+ base = (hwaddr)get_field(env->satp, SATP_PPN) << PGSHIFT;
+
+ vm = get_field(env->satp, SATP_MODE);
+ switch (vm) {
+ case VM_1_10_SV32:
+ levels = 2;
+ ptidxbits = 10;
+ ptesize = 4;
+ break;
+ case VM_1_10_SV39:
+ levels = 3;
+ ptidxbits = 9;
+ ptesize = 8;
+ break;
+ case VM_1_10_SV48:
+ levels = 4;
+ ptidxbits = 9;
+ ptesize = 8;
+ break;
+ case VM_1_10_SV57:
+ levels = 5;
+ ptidxbits = 9;
+ ptesize = 8;
+ break;
+ default:
+ g_assert_not_reached();
+ break;
+ }
+
+ /* calculate virtual address bits */
+ va_bits = PGSHIFT + levels * ptidxbits;
+
+ /* print header */
+ print_pte_header(mon);
+
+ vbase = -1;
+ pbase = -1;
+ last_paddr = -1;
+ last_size = 0;
+ last_attr = 0;
+
+ /* walk page tables, starting from address 0 */
+ walk_pte(mon, base, 0, levels - 1, ptidxbits, ptesize, va_bits,
+ &vbase, &pbase, &last_paddr, &last_size, &last_attr);
+
+ /* don't forget the last one */
+ print_pte(mon, va_bits, vbase, pbase,
+ last_paddr + last_size - pbase, last_attr);
+}
+
+void hmp_info_mem(Monitor *mon, const QDict *qdict)
+{
+ CPUArchState *env;
+
+ env = mon_get_cpu_env();
+ if (!env) {
+ monitor_printf(mon, "No CPU available\n");
+ return;
+ }
+
+ if (!riscv_feature(env, RISCV_FEATURE_MMU)) {
+ monitor_printf(mon, "S-mode MMU unavailable\n");
+ return;
+ }
+
+ if (env->priv_ver < PRIV_VERSION_1_10_0) {
+ monitor_printf(mon, "Privileged mode < 1.10 unsupported\n");
+ return;
+ }
+
+ if (!(env->satp & SATP_MODE)) {
+ monitor_printf(mon, "No translation or protection\n");
+ return;
+ }
+
+ mem_info_svxx(mon, env);
+}
diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c
index 958c750..d4f1007 100644
--- a/target/riscv/pmp.c
+++ b/target/riscv/pmp.c
@@ -27,16 +27,7 @@
#include "qemu/log.h"
#include "qapi/error.h"
#include "cpu.h"
-
-#ifndef CONFIG_USER_ONLY
-
-#define RISCV_DEBUG_PMP 0
-#define PMP_DEBUG(fmt, ...) \
- do { \
- if (RISCV_DEBUG_PMP) { \
- qemu_log_mask(LOG_TRACE, "%s: " fmt "\n", __func__, ##__VA_ARGS__);\
- } \
- } while (0)
+#include "trace.h"
static void pmp_write_cfg(CPURISCVState *env, uint32_t addr_index,
uint8_t val);
@@ -304,8 +295,7 @@ void pmpcfg_csr_write(CPURISCVState *env, uint32_t reg_index,
int i;
uint8_t cfg_val;
- PMP_DEBUG("hart " TARGET_FMT_ld ": reg%d, val: 0x" TARGET_FMT_lx,
- env->mhartid, reg_index, val);
+ trace_pmpcfg_csr_write(env->mhartid, reg_index, val);
if ((reg_index & 1) && (sizeof(target_ulong) == 8)) {
qemu_log_mask(LOG_GUEST_ERROR,
@@ -334,9 +324,7 @@ target_ulong pmpcfg_csr_read(CPURISCVState *env, uint32_t reg_index)
val = pmp_read_cfg(env, (reg_index * sizeof(target_ulong)) + i);
cfg_val |= (val << (i * 8));
}
-
- PMP_DEBUG("hart " TARGET_FMT_ld ": reg%d, val: 0x" TARGET_FMT_lx,
- env->mhartid, reg_index, cfg_val);
+ trace_pmpcfg_csr_read(env->mhartid, reg_index, cfg_val);
return cfg_val;
}
@@ -348,9 +336,7 @@ target_ulong pmpcfg_csr_read(CPURISCVState *env, uint32_t reg_index)
void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
target_ulong val)
{
- PMP_DEBUG("hart " TARGET_FMT_ld ": addr%d, val: 0x" TARGET_FMT_lx,
- env->mhartid, addr_index, val);
-
+ trace_pmpaddr_csr_write(env->mhartid, addr_index, val);
if (addr_index < MAX_RISCV_PMPS) {
if (!pmp_is_locked(env, addr_index)) {
env->pmp_state.pmp[addr_index].addr_reg = val;
@@ -371,16 +357,15 @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
*/
target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index)
{
- PMP_DEBUG("hart " TARGET_FMT_ld ": addr%d, val: 0x" TARGET_FMT_lx,
- env->mhartid, addr_index,
- env->pmp_state.pmp[addr_index].addr_reg);
+ target_ulong val = 0;
+
if (addr_index < MAX_RISCV_PMPS) {
- return env->pmp_state.pmp[addr_index].addr_reg;
+ val = env->pmp_state.pmp[addr_index].addr_reg;
+ trace_pmpaddr_csr_read(env->mhartid, addr_index, val);
} else {
qemu_log_mask(LOG_GUEST_ERROR,
"ignoring pmpaddr read - out of bounds\n");
- return 0;
}
-}
-#endif
+ return val;
+}
diff --git a/target/riscv/trace-events b/target/riscv/trace-events
index 48af037..4b6c652 100644
--- a/target/riscv/trace-events
+++ b/target/riscv/trace-events
@@ -1,2 +1,8 @@
# target/riscv/cpu_helper.c
riscv_trap(uint64_t hartid, bool async, uint64_t cause, uint64_t epc, uint64_t tval, const char *desc) "hart:%"PRId64", async:%d, cause:%"PRId64", epc:0x%"PRIx64", tval:0x%"PRIx64", desc=%s"
+
+# pmp.c
+pmpcfg_csr_read(uint64_t mhartid, uint32_t reg_index, uint64_t val) "hart %" PRIu64 ": read reg%" PRIu32", val: 0x%" PRIx64
+pmpcfg_csr_write(uint64_t mhartid, uint32_t reg_index, uint64_t val) "hart %" PRIu64 ": write reg%" PRIu32", val: 0x%" PRIx64
+pmpaddr_csr_read(uint64_t mhartid, uint32_t addr_index, uint64_t val) "hart %" PRIu64 ": read addr%" PRIu32", val: 0x%" PRIx64
+pmpaddr_csr_write(uint64_t mhartid, uint32_t addr_index, uint64_t val) "hart %" PRIu64 ": write addr%" PRIu32", val: 0x%" PRIx64
diff --git a/target/s390x/cc_helper.c b/target/s390x/cc_helper.c
index cf68792..44731e4 100644
--- a/target/s390x/cc_helper.c
+++ b/target/s390x/cc_helper.c
@@ -21,6 +21,7 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
+#include "tcg_s390x.h"
#include "exec/exec-all.h"
#include "exec/helper-proto.h"
#include "qemu/host-utils.h"
@@ -588,8 +589,7 @@ void HELPER(sacf)(CPUS390XState *env, uint64_t a1)
break;
default:
HELPER_LOG("unknown sacf mode: %" PRIx64 "\n", a1);
- s390_program_interrupt(env, PGM_SPECIFICATION, 2, GETPC());
- break;
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
}
}
#endif
diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h
index 79202c0..17460ed7 100644
--- a/target/s390x/cpu.h
+++ b/target/s390x/cpu.h
@@ -1,6 +1,10 @@
/*
* 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
*
@@ -30,7 +34,7 @@
/* 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 1
+#define TARGET_INSN_START_EXTRA_WORDS 2
#define MMU_MODE0_SUFFIX _primary
#define MMU_MODE1_SUFFIX _secondary
@@ -311,6 +315,7 @@ extern const VMStateDescription vmstate_s390_cpu;
#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
@@ -328,6 +333,9 @@ extern const VMStateDescription vmstate_s390_cpu;
static inline int cpu_mmu_index(CPUS390XState *env, bool ifetch)
{
+#ifdef CONFIG_USER_ONLY
+ return MMU_USER_IDX;
+#else
if (!(env->psw.mask & PSW_MASK_DAT)) {
return MMU_REAL_IDX;
}
@@ -351,6 +359,7 @@ static inline int cpu_mmu_index(CPUS390XState *env, bool ifetch)
default:
abort();
}
+#endif
}
static inline void cpu_get_tb_cpu_state(CPUS390XState* env, target_ulong *pc,
@@ -554,26 +563,60 @@ QEMU_BUILD_BUG_ON(sizeof(SysIB) != 4096);
#define ASCE_TYPE_SEGMENT 0x00 /* segment table type */
#define ASCE_TABLE_LENGTH 0x03 /* region table length */
-#define REGION_ENTRY_ORIGIN (~0xfffULL) /* region/segment table origin */
-#define REGION_ENTRY_RO 0x200 /* region/segment protection bit */
-#define REGION_ENTRY_TF 0xc0 /* region/segment table offset */
-#define REGION_ENTRY_INV 0x20 /* invalid region table entry */
-#define REGION_ENTRY_TYPE_MASK 0x0c /* region/segment table type mask */
-#define REGION_ENTRY_TYPE_R1 0x0c /* region first table type */
-#define REGION_ENTRY_TYPE_R2 0x08 /* region second table type */
-#define REGION_ENTRY_TYPE_R3 0x04 /* region third table type */
-#define REGION_ENTRY_LENGTH 0x03 /* region third length */
-
-#define SEGMENT_ENTRY_ORIGIN (~0x7ffULL) /* segment table origin */
-#define SEGMENT_ENTRY_FC 0x400 /* format control */
-#define SEGMENT_ENTRY_RO 0x200 /* page protection bit */
-#define SEGMENT_ENTRY_INV 0x20 /* invalid segment table entry */
-
-#define VADDR_PX 0xff000 /* page index bits */
-
-#define PAGE_RO 0x200 /* HW read-only bit */
-#define PAGE_INVALID 0x400 /* HW invalid bit */
-#define PAGE_RES0 0x800 /* bit must be zero */
+#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)
@@ -761,11 +804,8 @@ int cpu_s390x_signal_handler(int host_signum, void *pinfo, void *puc);
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);
-/* automatically detect the instruction length */
-#define ILEN_AUTO 0xff
#define RA_IGNORED 0
-void s390_program_interrupt(CPUS390XState *env, uint32_t code, int ilen,
- uintptr_t ra);
+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);
diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c
index 1d16d7d..7e92fb2 100644
--- a/target/s390x/cpu_models.c
+++ b/target/s390x/cpu_models.c
@@ -84,7 +84,7 @@ static S390CPUDef s390_cpu_defs[] = {
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 8561 GA1"),
+ CPUDEF_INIT(0x8561, 15, 1, 47, 0x08000000U, "gen15a", "IBM z15 GA1"),
CPUDEF_INIT(0x8562, 15, 1, 47, 0x08000000U, "gen15b", "IBM 8562 GA1"),
};
@@ -515,6 +515,7 @@ static void cpu_model_from_info(S390CPUModel *model, const CpuModelInfo *info,
visitor = qobject_input_visitor_new(info->props);
visit_start_struct(visitor, NULL, NULL, 0, errp);
if (*errp) {
+ visit_free(visitor);
object_unref(obj);
return;
}
diff --git a/target/s390x/crypto_helper.c b/target/s390x/crypto_helper.c
index 5c79790..ff3fbc3 100644
--- a/target/s390x/crypto_helper.c
+++ b/target/s390x/crypto_helper.c
@@ -13,6 +13,7 @@
#include "qemu/osdep.h"
#include "qemu/main-loop.h"
#include "internal.h"
+#include "tcg_s390x.h"
#include "exec/helper-proto.h"
#include "exec/exec-all.h"
#include "exec/cpu_ldst.h"
@@ -34,16 +35,14 @@ uint32_t HELPER(msa)(CPUS390XState *env, uint32_t r1, uint32_t r2, uint32_t r3,
case S390_FEAT_TYPE_PCKMO:
case S390_FEAT_TYPE_PCC:
if (mod) {
- s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
- return 0;
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
}
break;
}
s390_get_feat_block(type, subfunc);
if (!test_be_bit(fc, subfunc)) {
- s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
- return 0;
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
}
switch (fc) {
diff --git a/target/s390x/diag.c b/target/s390x/diag.c
index 65eabf0..53c2f81 100644
--- a/target/s390x/diag.c
+++ b/target/s390x/diag.c
@@ -61,12 +61,12 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
IplParameterBlock *iplb;
if (env->psw.mask & PSW_MASK_PSTATE) {
- s390_program_interrupt(env, PGM_PRIVILEGED, ILEN_AUTO, ra);
+ s390_program_interrupt(env, PGM_PRIVILEGED, ra);
return;
}
if ((subcode & ~0x0ffffULL) || (subcode > 6)) {
- s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, ra);
+ s390_program_interrupt(env, PGM_SPECIFICATION, ra);
return;
}
@@ -82,13 +82,13 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
break;
case 5:
if ((r1 & 1) || (addr & 0x0fffULL)) {
- s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, ra);
+ s390_program_interrupt(env, PGM_SPECIFICATION, ra);
return;
}
if (!address_space_access_valid(&address_space_memory, addr,
sizeof(IplParameterBlock), false,
MEMTXATTRS_UNSPECIFIED)) {
- s390_program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO, ra);
+ s390_program_interrupt(env, PGM_ADDRESSING, ra);
return;
}
iplb = g_new0(IplParameterBlock, 1);
@@ -112,13 +112,13 @@ out:
return;
case 6:
if ((r1 & 1) || (addr & 0x0fffULL)) {
- s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, ra);
+ s390_program_interrupt(env, PGM_SPECIFICATION, ra);
return;
}
if (!address_space_access_valid(&address_space_memory, addr,
sizeof(IplParameterBlock), true,
MEMTXATTRS_UNSPECIFIED)) {
- s390_program_interrupt(env, PGM_ADDRESSING, ILEN_AUTO, ra);
+ s390_program_interrupt(env, PGM_ADDRESSING, ra);
return;
}
iplb = s390_ipl_get_iplb();
@@ -130,7 +130,7 @@ out:
}
return;
default:
- s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, ra);
+ s390_program_interrupt(env, PGM_SPECIFICATION, ra);
break;
}
}
diff --git a/target/s390x/excp_helper.c b/target/s390x/excp_helper.c
index 892f659..e70c20d 100644
--- a/target/s390x/excp_helper.c
+++ b/target/s390x/excp_helper.c
@@ -34,15 +34,15 @@
#include "hw/boards.h"
#endif
-void QEMU_NORETURN tcg_s390_program_interrupt(CPUS390XState *env, uint32_t code,
- int ilen, uintptr_t ra)
+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, ilen);
+ trigger_pgm_exception(env, code);
cpu_loop_exit(cs);
}
@@ -60,7 +60,7 @@ void QEMU_NORETURN tcg_s390_data_exception(CPUS390XState *env, uint32_t dxc,
if (env->cregs[0] & CR0_AFP) {
env->fpc = deposit32(env->fpc, 8, 8, dxc);
}
- tcg_s390_program_interrupt(env, PGM_DATA, ILEN_AUTO, ra);
+ tcg_s390_program_interrupt(env, PGM_DATA, ra);
}
void QEMU_NORETURN tcg_s390_vector_exception(CPUS390XState *env, uint32_t vxc,
@@ -75,7 +75,7 @@ void QEMU_NORETURN tcg_s390_vector_exception(CPUS390XState *env, uint32_t vxc,
/* 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, ILEN_AUTO, ra);
+ tcg_s390_program_interrupt(env, PGM_VECTOR_PROCESSING, ra);
}
void HELPER(data_exception)(CPUS390XState *env, uint32_t dxc)
@@ -96,7 +96,7 @@ bool s390_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
{
S390CPU *cpu = S390_CPU(cs);
- trigger_pgm_exception(&cpu->env, PGM_ADDRESSING, ILEN_AUTO);
+ trigger_pgm_exception(&cpu->env, PGM_ADDRESSING);
/* On real machines this value is dropped into LowMem. Since this
is userland, simply put this someplace that cpu_loop can find it. */
cpu->env.__excp_addr = address;
@@ -126,8 +126,8 @@ bool s390_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
S390CPU *cpu = S390_CPU(cs);
CPUS390XState *env = &cpu->env;
target_ulong vaddr, raddr;
- uint64_t asc;
- int prot, fail;
+ 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);
@@ -140,30 +140,30 @@ bool s390_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
if (!(env->psw.mask & PSW_MASK_64)) {
vaddr &= 0x7fffffff;
}
- fail = mmu_translate(env, vaddr, access_type, asc, &raddr, &prot, true);
+ 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;
}
- fail = mmu_translate_real(env, vaddr, access_type, &raddr, &prot);
+ excp = mmu_translate_real(env, vaddr, access_type, &raddr, &prot, &tec);
} else {
g_assert_not_reached();
}
/* check out of RAM access */
- if (!fail &&
+ if (!excp &&
!address_space_access_valid(&address_space_memory, 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);
- trigger_pgm_exception(env, PGM_ADDRESSING, ILEN_AUTO);
- fail = 1;
+ excp = PGM_ADDRESSING;
+ tec = 0; /* unused */
}
- if (!fail) {
+ if (!excp) {
qemu_log_mask(CPU_LOG_MMU,
"%s: set tlb %" PRIx64 " -> %" PRIx64 " (%x)\n",
__func__, (uint64_t)vaddr, (uint64_t)raddr, prot);
@@ -175,23 +175,20 @@ bool s390_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
return false;
}
- cpu_restore_state(cs, retaddr, true);
+ if (excp != PGM_ADDRESSING) {
+ stq_phys(env_cpu(env)->as,
+ env->psa + offsetof(LowCore, trans_exc_code), tec);
+ }
/*
- * The ILC value for code accesses is undefined. The important
- * thing here is to *not* leave env->int_pgm_ilen set to ILEN_AUTO,
- * which would cause do_program_interrupt to attempt to read from
- * env->psw.addr again. C.f. the condition in trigger_page_fault,
- * but is not universally applied.
- *
- * ??? If we remove ILEN_AUTO, by moving the computation of ILEN
- * into cpu_restore_state, then we may remove this entirely.
+ * 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.
*/
- if (access_type == MMU_INST_FETCH) {
- env->int_pgm_ilen = 2;
- }
-
- cpu_loop_exit(cs);
+ env->int_pgm_ilen = 2;
+ trigger_pgm_exception(env, excp);
+ cpu_loop_exit_restore(cs, retaddr);
}
static void do_program_interrupt(CPUS390XState *env)
@@ -200,9 +197,6 @@ static void do_program_interrupt(CPUS390XState *env)
LowCore *lowcore;
int ilen = env->int_pgm_ilen;
- if (ilen == ILEN_AUTO) {
- ilen = get_ilen(cpu_ldub_code(env, env->psw.addr));
- }
assert(ilen == 2 || ilen == 4 || ilen == 6);
switch (env->int_pgm_code) {
@@ -614,7 +608,7 @@ void s390x_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
S390CPU *cpu = S390_CPU(cs);
CPUS390XState *env = &cpu->env;
- s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, retaddr);
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, retaddr);
}
#endif /* CONFIG_USER_ONLY */
diff --git a/target/s390x/fpu_helper.c b/target/s390x/fpu_helper.c
index 5faf973..8bb9f54 100644
--- a/target/s390x/fpu_helper.c
+++ b/target/s390x/fpu_helper.c
@@ -825,7 +825,7 @@ void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc)
{
if (fpc_to_rnd[fpc & 0x7] == -1 || fpc & 0x03030088u ||
(!s390_has_feat(S390_FEAT_FLOATING_POINT_EXT) && fpc & 0x4)) {
- s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, GETPC());
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
}
/* Install everything in the main FPC. */
@@ -843,7 +843,7 @@ void HELPER(sfas)(CPUS390XState *env, uint64_t fpc)
if (fpc_to_rnd[fpc & 0x7] == -1 || fpc & 0x03030088u ||
(!s390_has_feat(S390_FEAT_FLOATING_POINT_EXT) && fpc & 0x4)) {
- s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, GETPC());
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
}
/*
@@ -880,7 +880,7 @@ void HELPER(sfas)(CPUS390XState *env, uint64_t fpc)
void HELPER(srnm)(CPUS390XState *env, uint64_t rnd)
{
if (rnd > 0x7 || fpc_to_rnd[rnd & 0x7] == -1) {
- s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, GETPC());
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
}
env->fpc = deposit32(env->fpc, 0, 3, rnd);
diff --git a/target/s390x/gen-features.c b/target/s390x/gen-features.c
index 49a650a..6278845 100644
--- a/target/s390x/gen-features.c
+++ b/target/s390x/gen-features.c
@@ -698,15 +698,23 @@ static uint16_t qemu_V4_0[] = {
S390_FEAT_ZPCI,
};
-static uint16_t qemu_LATEST[] = {
+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 ******/
@@ -824,6 +832,7 @@ 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),
};
diff --git a/target/s390x/helper.c b/target/s390x/helper.c
index 948c039..a3a4916 100644
--- a/target/s390x/helper.c
+++ b/target/s390x/helper.c
@@ -52,6 +52,7 @@ hwaddr s390_cpu_get_phys_page_debug(CPUState *cs, vaddr vaddr)
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)) {
@@ -63,7 +64,11 @@ hwaddr s390_cpu_get_phys_page_debug(CPUState *cs, vaddr vaddr)
asc = PSW_ASC_PRIMARY;
}
- if (mmu_translate(env, vaddr, MMU_INST_FETCH, asc, &raddr, &prot, false)) {
+ /*
+ * 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;
diff --git a/target/s390x/helper.h b/target/s390x/helper.h
index e9aff83..56e8149 100644
--- a/target/s390x/helper.h
+++ b/target/s390x/helper.h
@@ -20,7 +20,7 @@ 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_4(mvst, i64, env, i64, 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)
diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def
index f421184..449eee1 100644
--- a/target/s390x/insn-data.def
+++ b/target/s390x/insn-data.def
@@ -637,7 +637,7 @@
/* MOVE PAGE */
C(0xb254, MVPG, RRE, Z, r1_o, r2_o, 0, 0, mvpg, 0)
/* MOVE STRING */
- C(0xb255, MVST, RRE, Z, r1_o, r2_o, 0, 0, mvst, 0)
+ C(0xb255, MVST, RRE, Z, 0, 0, 0, 0, mvst, 0)
/* MOVE WITH OPTIONAL SPECIFICATION */
C(0xc800, MVCOS, SSF, MVCOS, la1, a2, 0, 0, mvcos, 0)
/* MOVE WITH OFFSET */
diff --git a/target/s390x/int_helper.c b/target/s390x/int_helper.c
index d13cc49..658507d 100644
--- a/target/s390x/int_helper.c
+++ b/target/s390x/int_helper.c
@@ -21,6 +21,7 @@
#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"
@@ -39,7 +40,7 @@ int64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b64)
int64_t q;
if (b == 0) {
- s390_program_interrupt(env, PGM_FIXPT_DIVIDE, ILEN_AUTO, GETPC());
+ tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
}
ret = q = a / b;
@@ -47,7 +48,7 @@ int64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b64)
/* Catch non-representable quotient. */
if (ret != q) {
- s390_program_interrupt(env, PGM_FIXPT_DIVIDE, ILEN_AUTO, GETPC());
+ tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
}
return ret;
@@ -60,7 +61,7 @@ uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b64)
uint64_t q;
if (b == 0) {
- s390_program_interrupt(env, PGM_FIXPT_DIVIDE, ILEN_AUTO, GETPC());
+ tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
}
ret = q = a / b;
@@ -68,7 +69,7 @@ uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b64)
/* Catch non-representable quotient. */
if (ret != q) {
- s390_program_interrupt(env, PGM_FIXPT_DIVIDE, ILEN_AUTO, GETPC());
+ tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
}
return ret;
@@ -79,7 +80,7 @@ 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))) {
- s390_program_interrupt(env, PGM_FIXPT_DIVIDE, ILEN_AUTO, GETPC());
+ tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
}
env->retxl = a % b;
return a / b;
@@ -92,7 +93,7 @@ uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al,
uint64_t ret;
/* Signal divide by zero. */
if (b == 0) {
- s390_program_interrupt(env, PGM_FIXPT_DIVIDE, ILEN_AUTO, GETPC());
+ tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
}
if (ah == 0) {
/* 64 -> 64/64 case */
@@ -106,7 +107,7 @@ uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al,
env->retxl = a % b;
ret = q;
if (ret != q) {
- s390_program_interrupt(env, PGM_FIXPT_DIVIDE, ILEN_AUTO, GETPC());
+ tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC());
}
#else
/* 32-bit hosts would need special wrapper functionality - just abort if
diff --git a/target/s390x/internal.h b/target/s390x/internal.h
index c243fa7..d378161 100644
--- a/target/s390x/internal.h
+++ b/target/s390x/internal.h
@@ -317,7 +317,7 @@ void cpu_unmap_lowcore(LowCore *lowcore);
/* interrupt.c */
-void trigger_pgm_exception(CPUS390XState *env, uint32_t code, uint32_t ilen);
+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);
@@ -360,9 +360,9 @@ void probe_write_access(CPUS390XState *env, uint64_t addr, uint64_t len,
/* mmu_helper.c */
int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
- target_ulong *raddr, int *flags, bool exc);
+ target_ulong *raddr, int *flags, uint64_t *tec);
int mmu_translate_real(CPUS390XState *env, target_ulong raddr, int rw,
- target_ulong *addr, int *flags);
+ target_ulong *addr, int *flags, uint64_t *tec);
/* misc_helper.c */
diff --git a/target/s390x/interrupt.c b/target/s390x/interrupt.c
index a841f71..4cdbbc8 100644
--- a/target/s390x/interrupt.c
+++ b/target/s390x/interrupt.c
@@ -22,22 +22,21 @@
#endif
/* Ensure to exit the TB after this call! */
-void trigger_pgm_exception(CPUS390XState *env, uint32_t code, uint32_t ilen)
+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 = ilen;
+ /* env->int_pgm_ilen is already set, or will be set during unwinding */
}
-void s390_program_interrupt(CPUS390XState *env, uint32_t code, int ilen,
- uintptr_t ra)
+void s390_program_interrupt(CPUS390XState *env, uint32_t code, uintptr_t ra)
{
if (kvm_enabled()) {
kvm_s390_program_interrupt(env_archcpu(env), code);
} else if (tcg_enabled()) {
- tcg_s390_program_interrupt(env, code, ilen, ra);
+ tcg_s390_program_interrupt(env, code, ra);
} else {
g_assert_not_reached();
}
diff --git a/target/s390x/ioinst.c b/target/s390x/ioinst.c
index 83c164a..c437a1d 100644
--- a/target/s390x/ioinst.c
+++ b/target/s390x/ioinst.c
@@ -44,7 +44,7 @@ void ioinst_handle_xsch(S390CPU *cpu, uint64_t reg1, uintptr_t ra)
SubchDev *sch;
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
- s390_program_interrupt(&cpu->env, PGM_OPERAND, 4, ra);
+ s390_program_interrupt(&cpu->env, PGM_OPERAND, ra);
return;
}
trace_ioinst_sch_id("xsch", cssid, ssid, schid);
@@ -62,7 +62,7 @@ void ioinst_handle_csch(S390CPU *cpu, uint64_t reg1, uintptr_t ra)
SubchDev *sch;
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
- s390_program_interrupt(&cpu->env, PGM_OPERAND, 4, ra);
+ s390_program_interrupt(&cpu->env, PGM_OPERAND, ra);
return;
}
trace_ioinst_sch_id("csch", cssid, ssid, schid);
@@ -80,7 +80,7 @@ void ioinst_handle_hsch(S390CPU *cpu, uint64_t reg1, uintptr_t ra)
SubchDev *sch;
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
- s390_program_interrupt(&cpu->env, PGM_OPERAND, 4, ra);
+ s390_program_interrupt(&cpu->env, PGM_OPERAND, ra);
return;
}
trace_ioinst_sch_id("hsch", cssid, ssid, schid);
@@ -116,7 +116,7 @@ void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra)
addr = decode_basedisp_s(env, ipb, &ar);
if (addr & 3) {
- s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
+ s390_program_interrupt(env, PGM_SPECIFICATION, ra);
return;
}
if (s390_cpu_virt_mem_read(cpu, addr, ar, &schib, sizeof(schib))) {
@@ -125,7 +125,7 @@ void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra)
}
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid) ||
!ioinst_schib_valid(&schib)) {
- s390_program_interrupt(env, PGM_OPERAND, 4, ra);
+ s390_program_interrupt(env, PGM_OPERAND, ra);
return;
}
trace_ioinst_sch_id("msch", cssid, ssid, schid);
@@ -173,7 +173,7 @@ void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra)
addr = decode_basedisp_s(env, ipb, &ar);
if (addr & 3) {
- s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
+ s390_program_interrupt(env, PGM_SPECIFICATION, ra);
return;
}
if (s390_cpu_virt_mem_read(cpu, addr, ar, &orig_orb, sizeof(orb))) {
@@ -183,7 +183,7 @@ void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra)
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, 4, ra);
+ s390_program_interrupt(env, PGM_OPERAND, ra);
return;
}
trace_ioinst_sch_id("ssch", cssid, ssid, schid);
@@ -205,7 +205,7 @@ void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb, uintptr_t ra)
addr = decode_basedisp_s(env, ipb, &ar);
if (addr & 3) {
- s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
+ s390_program_interrupt(env, PGM_SPECIFICATION, ra);
return;
}
@@ -236,7 +236,7 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb,
addr = decode_basedisp_s(env, ipb, &ar);
if (addr & 3) {
- s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
+ s390_program_interrupt(env, PGM_SPECIFICATION, ra);
return;
}
@@ -247,7 +247,7 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb,
* 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, 4, ra);
+ s390_program_interrupt(env, PGM_OPERAND, ra);
} else {
s390_cpu_virt_mem_handle_exc(cpu, ra);
}
@@ -299,13 +299,13 @@ int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra)
uint8_t ar;
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
- s390_program_interrupt(env, PGM_OPERAND, 4, ra);
+ 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, 4, ra);
+ s390_program_interrupt(env, PGM_SPECIFICATION, ra);
return -EIO;
}
@@ -613,7 +613,7 @@ void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb, uintptr_t ra)
addr = env->regs[reg];
/* Page boundary? */
if (addr & 0xfff) {
- s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
+ s390_program_interrupt(env, PGM_SPECIFICATION, ra);
return;
}
/*
@@ -629,7 +629,7 @@ void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb, uintptr_t ra)
len = be16_to_cpu(req->len);
/* Length field valid? */
if ((len < 16) || (len > 4088) || (len & 7)) {
- s390_program_interrupt(env, PGM_OPERAND, 4, ra);
+ s390_program_interrupt(env, PGM_OPERAND, ra);
return;
}
memset((char *)req + len, 0, TARGET_PAGE_SIZE - len);
@@ -678,7 +678,7 @@ void ioinst_handle_schm(S390CPU *cpu, uint64_t reg1, uint64_t reg2,
trace_ioinst("schm");
if (SCHM_REG1_RES(reg1)) {
- s390_program_interrupt(env, PGM_OPERAND, 4, ra);
+ s390_program_interrupt(env, PGM_OPERAND, ra);
return;
}
@@ -687,7 +687,7 @@ void ioinst_handle_schm(S390CPU *cpu, uint64_t reg1, uint64_t reg2,
dct = SCHM_REG1_DCT(reg1);
if (update && (reg2 & 0x000000000000001f)) {
- s390_program_interrupt(env, PGM_OPERAND, 4, ra);
+ s390_program_interrupt(env, PGM_OPERAND, ra);
return;
}
@@ -700,7 +700,7 @@ void ioinst_handle_rsch(S390CPU *cpu, uint64_t reg1, uintptr_t ra)
SubchDev *sch;
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
- s390_program_interrupt(&cpu->env, PGM_OPERAND, 4, ra);
+ s390_program_interrupt(&cpu->env, PGM_OPERAND, ra);
return;
}
trace_ioinst_sch_id("rsch", cssid, ssid, schid);
@@ -724,7 +724,7 @@ void ioinst_handle_rchp(S390CPU *cpu, uint64_t reg1, uintptr_t ra)
CPUS390XState *env = &cpu->env;
if (RCHP_REG1_RES(reg1)) {
- s390_program_interrupt(env, PGM_OPERAND, 4, ra);
+ s390_program_interrupt(env, PGM_OPERAND, ra);
return;
}
@@ -747,7 +747,7 @@ void ioinst_handle_rchp(S390CPU *cpu, uint64_t reg1, uintptr_t ra)
break;
default:
/* Invalid channel subsystem. */
- s390_program_interrupt(env, PGM_OPERAND, 4, ra);
+ s390_program_interrupt(env, PGM_OPERAND, ra);
return;
}
setcc(cpu, cc);
@@ -758,6 +758,6 @@ 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, 4, ra);
+ s390_program_interrupt(&cpu->env, PGM_OPERAND, ra);
}
}
diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
index cea71ac..0c9d14b 100644
--- a/target/s390x/kvm.c
+++ b/target/s390x/kvm.c
@@ -28,6 +28,7 @@
#include "cpu.h"
#include "internal.h"
#include "kvm_s390x.h"
+#include "sysemu/kvm_int.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "qemu/timer.h"
@@ -122,6 +123,14 @@
*/
#define VCPU_IRQ_BUF_SIZE(max_cpus) (sizeof(struct kvm_s390_irq) * \
(max_cpus + NR_LOCAL_IRQS))
+/*
+ * KVM does only support memory slots up to KVM_MEM_MAX_NR_PAGES pages
+ * as the dirty bitmap must be managed by bitops that take an int as
+ * position indicator. This would end at an unaligned address
+ * (0x7fffff00000). As future variants might provide larger pages
+ * and to make all addresses properly aligned, let us split at 4TB.
+ */
+#define KVM_SLOT_MAX_BYTES (4UL * TiB)
static CPUWatchpoint hw_watchpoint;
/*
@@ -311,11 +320,24 @@ void kvm_s390_set_max_pagesize(uint64_t pagesize, Error **errp)
cap_hpage_1m = 1;
}
-int kvm_arch_init(MachineState *ms, KVMState *s)
+static void ccw_machine_class_foreach(ObjectClass *oc, void *opaque)
{
- MachineClass *mc = MACHINE_GET_CLASS(ms);
+ MachineClass *mc = MACHINE_CLASS(oc);
mc->default_cpu_type = S390_CPU_TYPE_NAME("host");
+}
+
+int kvm_arch_init(MachineState *ms, KVMState *s)
+{
+ object_class_foreach(ccw_machine_class_foreach, TYPE_S390_CCW_MACHINE,
+ false, NULL);
+
+ if (!kvm_check_extension(kvm_state, KVM_CAP_DEVICE_CTRL)) {
+ error_report("KVM is missing capability KVM_CAP_DEVICE_CTRL - "
+ "please use kernel 3.15 or newer");
+ return -1;
+ }
+
cap_sync_regs = kvm_check_extension(s, KVM_CAP_SYNC_REGS);
cap_async_pf = kvm_check_extension(s, KVM_CAP_ASYNC_PF);
cap_mem_op = kvm_check_extension(s, KVM_CAP_S390_MEM_OP);
@@ -348,6 +370,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
*/
/* kvm_vm_enable_cap(s, KVM_CAP_S390_AIS, 0); */
+ kvm_set_max_memslot_size(KVM_SLOT_MAX_BYTES);
return 0;
}
diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c
index 29fcce4..2325767 100644
--- a/target/s390x/mem_helper.c
+++ b/target/s390x/mem_helper.c
@@ -21,6 +21,7 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "internal.h"
+#include "tcg_s390x.h"
#include "exec/helper-proto.h"
#include "exec/exec-all.h"
#include "exec/cpu_ldst.h"
@@ -52,15 +53,17 @@ static inline bool psw_key_valid(CPUS390XState *env, uint8_t psw_key)
return true;
}
-/* Reduce the length so that addr + len doesn't cross a page boundary. */
-static inline uint32_t adj_len_to_page(uint32_t len, uint64_t addr)
+static bool is_destructive_overlap(CPUS390XState *env, uint64_t dest,
+ uint64_t src, uint32_t len)
{
-#ifndef CONFIG_USER_ONLY
- if ((addr & ~TARGET_PAGE_MASK) + len - 1 >= TARGET_PAGE_SIZE) {
- return -(addr | TARGET_PAGE_MASK);
+ if (!len || src == dest) {
+ return false;
}
-#endif
- return len;
+ /* Take care of wrapping at the end of address space. */
+ if (unlikely(wrap_address(env, src + len - 1) < src)) {
+ return dest > src || dest <= wrap_address(env, src + len - 1);
+ }
+ return dest > src && dest <= src + len - 1;
}
/* Trigger a SPECIFICATION exception if an address or a length is not
@@ -69,7 +72,7 @@ static inline void check_alignment(CPUS390XState *env, uint64_t v,
int wordsize, uintptr_t ra)
{
if (v % wordsize) {
- s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
}
}
@@ -104,62 +107,207 @@ static inline void cpu_stsize_data_ra(CPUS390XState *env, uint64_t addr,
}
}
-static void fast_memset(CPUS390XState *env, uint64_t dest, uint8_t byte,
- uint32_t l, uintptr_t ra)
+/* An access covers at most 4096 bytes and therefore at most two pages. */
+typedef struct S390Access {
+ target_ulong vaddr1;
+ target_ulong vaddr2;
+ char *haddr1;
+ char *haddr2;
+ uint16_t size1;
+ uint16_t size2;
+ /*
+ * If we can't access the host page directly, we'll have to do I/O access
+ * via ld/st helpers. These are internal details, so we store the
+ * mmu idx to do the access here instead of passing it around in the
+ * helpers. Maybe, one day we can get rid of ld/st access - once we can
+ * handle TLB_NOTDIRTY differently. We don't expect these special accesses
+ * to trigger exceptions - only if we would have TLB_NOTDIRTY on LAP
+ * pages, we might trigger a new MMU translation - very unlikely that
+ * the mapping changes in between and we would trigger a fault.
+ */
+ int mmu_idx;
+} S390Access;
+
+static S390Access access_prepare(CPUS390XState *env, vaddr vaddr, int size,
+ MMUAccessType access_type, int mmu_idx,
+ uintptr_t ra)
{
- int mmu_idx = cpu_mmu_index(env, false);
+ S390Access access = {
+ .vaddr1 = vaddr,
+ .size1 = MIN(size, -(vaddr | TARGET_PAGE_MASK)),
+ .mmu_idx = mmu_idx,
+ };
- while (l > 0) {
- void *p = tlb_vaddr_to_host(env, dest, MMU_DATA_STORE, mmu_idx);
- if (p) {
- /* Access to the whole page in write mode granted. */
- uint32_t l_adj = adj_len_to_page(l, dest);
- memset(p, byte, l_adj);
- dest += l_adj;
- l -= l_adj;
- } else {
- /* We failed to get access to the whole page. The next write
- access will likely fill the QEMU TLB for the next iteration. */
- cpu_stb_data_ra(env, dest, byte, ra);
- dest++;
- l--;
- }
+ g_assert(size > 0 && size <= 4096);
+ access.haddr1 = probe_access(env, access.vaddr1, access.size1, access_type,
+ mmu_idx, ra);
+
+ if (unlikely(access.size1 != size)) {
+ /* The access crosses page boundaries. */
+ access.vaddr2 = wrap_address(env, vaddr + access.size1);
+ access.size2 = size - access.size1;
+ access.haddr2 = probe_access(env, access.vaddr2, access.size2,
+ access_type, mmu_idx, ra);
}
+ return access;
}
-#ifndef CONFIG_USER_ONLY
-static void fast_memmove_idx(CPUS390XState *env, uint64_t dest, uint64_t src,
- uint32_t len, int dest_idx, int src_idx,
+/* Helper to handle memset on a single page. */
+static void do_access_memset(CPUS390XState *env, vaddr vaddr, char *haddr,
+ uint8_t byte, uint16_t size, int mmu_idx,
uintptr_t ra)
{
- TCGMemOpIdx oi_dest = make_memop_idx(MO_UB, dest_idx);
- TCGMemOpIdx oi_src = make_memop_idx(MO_UB, src_idx);
- uint32_t len_adj;
- void *src_p;
- void *dest_p;
- uint8_t x;
-
- while (len > 0) {
- src = wrap_address(env, src);
- dest = wrap_address(env, dest);
- src_p = tlb_vaddr_to_host(env, src, MMU_DATA_LOAD, src_idx);
- dest_p = tlb_vaddr_to_host(env, dest, MMU_DATA_STORE, dest_idx);
-
- if (src_p && dest_p) {
- /* Access to both whole pages granted. */
- len_adj = adj_len_to_page(adj_len_to_page(len, src), dest);
- memmove(dest_p, src_p, len_adj);
+#ifdef CONFIG_USER_ONLY
+ g_assert(haddr);
+ memset(haddr, byte, size);
+#else
+ TCGMemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
+ int i;
+
+ if (likely(haddr)) {
+ memset(haddr, byte, size);
+ } else {
+ /*
+ * Do a single access and test if we can then get access to the
+ * page. This is especially relevant to speed up TLB_NOTDIRTY.
+ */
+ g_assert(size > 0);
+ helper_ret_stb_mmu(env, vaddr, byte, oi, ra);
+ haddr = tlb_vaddr_to_host(env, vaddr, MMU_DATA_STORE, mmu_idx);
+ if (likely(haddr)) {
+ memset(haddr + 1, byte, size - 1);
} else {
- /* We failed to get access to one or both whole pages. The next
- read or write access will likely fill the QEMU TLB for the
- next iteration. */
- len_adj = 1;
- x = helper_ret_ldub_mmu(env, src, oi_src, ra);
- helper_ret_stb_mmu(env, dest, x, oi_dest, ra);
+ for (i = 1; i < size; i++) {
+ helper_ret_stb_mmu(env, vaddr + i, byte, oi, ra);
+ }
+ }
+ }
+#endif
+}
+
+static void access_memset(CPUS390XState *env, S390Access *desta,
+ uint8_t byte, uintptr_t ra)
+{
+
+ do_access_memset(env, desta->vaddr1, desta->haddr1, byte, desta->size1,
+ desta->mmu_idx, ra);
+ if (likely(!desta->size2)) {
+ return;
+ }
+ do_access_memset(env, desta->vaddr2, desta->haddr2, byte, desta->size2,
+ desta->mmu_idx, ra);
+}
+
+static uint8_t do_access_get_byte(CPUS390XState *env, vaddr vaddr, char **haddr,
+ int offset, int mmu_idx, uintptr_t ra)
+{
+#ifdef CONFIG_USER_ONLY
+ return ldub_p(*haddr + offset);
+#else
+ TCGMemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
+ uint8_t byte;
+
+ if (likely(*haddr)) {
+ return ldub_p(*haddr + offset);
+ }
+ /*
+ * Do a single access and test if we can then get access to the
+ * page. This is especially relevant to speed up TLB_NOTDIRTY.
+ */
+ byte = helper_ret_ldub_mmu(env, vaddr + offset, oi, ra);
+ *haddr = tlb_vaddr_to_host(env, vaddr, MMU_DATA_LOAD, mmu_idx);
+ return byte;
+#endif
+}
+
+static uint8_t access_get_byte(CPUS390XState *env, S390Access *access,
+ int offset, uintptr_t ra)
+{
+ if (offset < access->size1) {
+ return do_access_get_byte(env, access->vaddr1, &access->haddr1,
+ offset, access->mmu_idx, ra);
+ }
+ return do_access_get_byte(env, access->vaddr2, &access->haddr2,
+ offset - access->size1, access->mmu_idx, ra);
+}
+
+static void do_access_set_byte(CPUS390XState *env, vaddr vaddr, char **haddr,
+ int offset, uint8_t byte, int mmu_idx,
+ uintptr_t ra)
+{
+#ifdef CONFIG_USER_ONLY
+ stb_p(*haddr + offset, byte);
+#else
+ TCGMemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
+
+ if (likely(*haddr)) {
+ stb_p(*haddr + offset, byte);
+ return;
+ }
+ /*
+ * Do a single access and test if we can then get access to the
+ * page. This is especially relevant to speed up TLB_NOTDIRTY.
+ */
+ helper_ret_stb_mmu(env, vaddr + offset, byte, oi, ra);
+ *haddr = tlb_vaddr_to_host(env, vaddr, MMU_DATA_STORE, mmu_idx);
+#endif
+}
+
+static void access_set_byte(CPUS390XState *env, S390Access *access,
+ int offset, uint8_t byte, uintptr_t ra)
+{
+ if (offset < access->size1) {
+ do_access_set_byte(env, access->vaddr1, &access->haddr1, offset, byte,
+ access->mmu_idx, ra);
+ } else {
+ do_access_set_byte(env, access->vaddr2, &access->haddr2,
+ offset - access->size1, byte, access->mmu_idx, ra);
+ }
+}
+
+/*
+ * Move data with the same semantics as memmove() in case ranges don't overlap
+ * or src > dest. Undefined behavior on destructive overlaps.
+ */
+static void access_memmove(CPUS390XState *env, S390Access *desta,
+ S390Access *srca, uintptr_t ra)
+{
+ int diff;
+
+ g_assert(desta->size1 + desta->size2 == srca->size1 + srca->size2);
+
+ /* Fallback to slow access in case we don't have access to all host pages */
+ if (unlikely(!desta->haddr1 || (desta->size2 && !desta->haddr2) ||
+ !srca->haddr1 || (srca->size2 && !srca->haddr2))) {
+ int i;
+
+ for (i = 0; i < desta->size1 + desta->size2; i++) {
+ uint8_t byte = access_get_byte(env, srca, i, ra);
+
+ access_set_byte(env, desta, i, byte, ra);
+ }
+ return;
+ }
+
+ if (srca->size1 == desta->size1) {
+ memmove(desta->haddr1, srca->haddr1, srca->size1);
+ if (unlikely(srca->size2)) {
+ memmove(desta->haddr2, srca->haddr2, srca->size2);
+ }
+ } else if (srca->size1 < desta->size1) {
+ diff = desta->size1 - srca->size1;
+ memmove(desta->haddr1, srca->haddr1, srca->size1);
+ memmove(desta->haddr1 + srca->size1, srca->haddr2, diff);
+ if (likely(desta->size2)) {
+ memmove(desta->haddr2, srca->haddr2 + diff, desta->size2);
+ }
+ } else {
+ diff = srca->size1 - desta->size1;
+ memmove(desta->haddr1, srca->haddr1, desta->size1);
+ memmove(desta->haddr2, srca->haddr1 + desta->size1, diff);
+ if (likely(srca->size2)) {
+ memmove(desta->haddr2 + diff, srca->haddr2, srca->size2);
}
- src += len_adj;
- dest += len_adj;
- len -= len_adj;
}
}
@@ -178,60 +326,30 @@ static int mmu_idx_from_as(uint8_t as)
}
}
-static void fast_memmove_as(CPUS390XState *env, uint64_t dest, uint64_t src,
- uint32_t len, uint8_t dest_as, uint8_t src_as,
- uintptr_t ra)
-{
- int src_idx = mmu_idx_from_as(src_as);
- int dest_idx = mmu_idx_from_as(dest_as);
-
- fast_memmove_idx(env, dest, src, len, dest_idx, src_idx, ra);
-}
-#endif
-
-static void fast_memmove(CPUS390XState *env, uint64_t dest, uint64_t src,
- uint32_t l, uintptr_t ra)
-{
- int mmu_idx = cpu_mmu_index(env, false);
-
- while (l > 0) {
- void *src_p = tlb_vaddr_to_host(env, src, MMU_DATA_LOAD, mmu_idx);
- void *dest_p = tlb_vaddr_to_host(env, dest, MMU_DATA_STORE, mmu_idx);
- if (src_p && dest_p) {
- /* Access to both whole pages granted. */
- uint32_t l_adj = adj_len_to_page(l, src);
- l_adj = adj_len_to_page(l_adj, dest);
- memmove(dest_p, src_p, l_adj);
- src += l_adj;
- dest += l_adj;
- l -= l_adj;
- } else {
- /* We failed to get access to one or both whole pages. The next
- read or write access will likely fill the QEMU TLB for the
- next iteration. */
- cpu_stb_data_ra(env, dest, cpu_ldub_data_ra(env, src, ra), ra);
- src++;
- dest++;
- l--;
- }
- }
-}
-
/* and on array */
static uint32_t do_helper_nc(CPUS390XState *env, uint32_t l, uint64_t dest,
uint64_t src, uintptr_t ra)
{
+ const int mmu_idx = cpu_mmu_index(env, false);
+ S390Access srca1, srca2, desta;
uint32_t i;
uint8_t c = 0;
HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
__func__, l, dest, src);
- for (i = 0; i <= l; i++) {
- uint8_t x = cpu_ldub_data_ra(env, src + i, ra);
- x &= cpu_ldub_data_ra(env, dest + i, ra);
+ /* NC always processes one more byte than specified - maximum is 256 */
+ l++;
+
+ srca1 = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
+ srca2 = access_prepare(env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
+ desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
+ for (i = 0; i < l; i++) {
+ const uint8_t x = access_get_byte(env, &srca1, i, ra) &
+ access_get_byte(env, &srca2, i, ra);
+
c |= x;
- cpu_stb_data_ra(env, dest + i, x, ra);
+ access_set_byte(env, &desta, i, x, ra);
}
return c != 0;
}
@@ -246,23 +364,33 @@ uint32_t HELPER(nc)(CPUS390XState *env, uint32_t l, uint64_t dest,
static uint32_t do_helper_xc(CPUS390XState *env, uint32_t l, uint64_t dest,
uint64_t src, uintptr_t ra)
{
+ const int mmu_idx = cpu_mmu_index(env, false);
+ S390Access srca1, srca2, desta;
uint32_t i;
uint8_t c = 0;
HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
__func__, l, dest, src);
+ /* XC always processes one more byte than specified - maximum is 256 */
+ l++;
+
+ srca1 = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
+ srca2 = access_prepare(env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
+ desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
+
/* xor with itself is the same as memset(0) */
if (src == dest) {
- fast_memset(env, dest, 0, l + 1, ra);
+ access_memset(env, &desta, 0, ra);
return 0;
}
- for (i = 0; i <= l; i++) {
- uint8_t x = cpu_ldub_data_ra(env, src + i, ra);
- x ^= cpu_ldub_data_ra(env, dest + i, ra);
+ for (i = 0; i < l; i++) {
+ const uint8_t x = access_get_byte(env, &srca1, i, ra) ^
+ access_get_byte(env, &srca2, i, ra);
+
c |= x;
- cpu_stb_data_ra(env, dest + i, x, ra);
+ access_set_byte(env, &desta, i, x, ra);
}
return c != 0;
}
@@ -277,17 +405,26 @@ uint32_t HELPER(xc)(CPUS390XState *env, uint32_t l, uint64_t dest,
static uint32_t do_helper_oc(CPUS390XState *env, uint32_t l, uint64_t dest,
uint64_t src, uintptr_t ra)
{
+ const int mmu_idx = cpu_mmu_index(env, false);
+ S390Access srca1, srca2, desta;
uint32_t i;
uint8_t c = 0;
HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
__func__, l, dest, src);
- for (i = 0; i <= l; i++) {
- uint8_t x = cpu_ldub_data_ra(env, src + i, ra);
- x |= cpu_ldub_data_ra(env, dest + i, ra);
+ /* OC always processes one more byte than specified - maximum is 256 */
+ l++;
+
+ srca1 = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
+ srca2 = access_prepare(env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
+ desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
+ for (i = 0; i < l; i++) {
+ const uint8_t x = access_get_byte(env, &srca1, i, ra) |
+ access_get_byte(env, &srca2, i, ra);
+
c |= x;
- cpu_stb_data_ra(env, dest + i, x, ra);
+ access_set_byte(env, &desta, i, x, ra);
}
return c != 0;
}
@@ -302,23 +439,33 @@ uint32_t HELPER(oc)(CPUS390XState *env, uint32_t l, uint64_t dest,
static uint32_t do_helper_mvc(CPUS390XState *env, uint32_t l, uint64_t dest,
uint64_t src, uintptr_t ra)
{
+ const int mmu_idx = cpu_mmu_index(env, false);
+ S390Access srca, desta;
uint32_t i;
HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
__func__, l, dest, src);
- /* mvc and memmove do not behave the same when areas overlap! */
- /* mvc with source pointing to the byte after the destination is the
- same as memset with the first source byte */
+ /* MVC always copies one more byte than specified - maximum is 256 */
+ l++;
+
+ srca = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
+ desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
+
+ /*
+ * "When the operands overlap, the result is obtained as if the operands
+ * were processed one byte at a time". Only non-destructive overlaps
+ * behave like memmove().
+ */
if (dest == src + 1) {
- fast_memset(env, dest, cpu_ldub_data_ra(env, src, ra), l + 1, ra);
- } else if (dest < src || src + l < dest) {
- fast_memmove(env, dest, src, l + 1, ra);
+ access_memset(env, &desta, access_get_byte(env, &srca, 0, ra), ra);
+ } else if (!is_destructive_overlap(env, dest, src, l)) {
+ access_memmove(env, &desta, &srca, ra);
} else {
- /* slow version with byte accesses which always work */
- for (i = 0; i <= l; i++) {
- uint8_t x = cpu_ldub_data_ra(env, src + i, ra);
- cpu_stb_data_ra(env, dest + i, x, ra);
+ for (i = 0; i < l; i++) {
+ uint8_t byte = access_get_byte(env, &srca, i, ra);
+
+ access_set_byte(env, &desta, i, byte, ra);
}
}
@@ -333,69 +480,99 @@ void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
/* move inverse */
void HELPER(mvcin)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
{
+ const int mmu_idx = cpu_mmu_index(env, false);
+ S390Access srca, desta;
uintptr_t ra = GETPC();
int i;
- for (i = 0; i <= l; i++) {
- uint8_t v = cpu_ldub_data_ra(env, src - i, ra);
- cpu_stb_data_ra(env, dest + i, v, ra);
+ /* MVCIN always copies one more byte than specified - maximum is 256 */
+ l++;
+
+ src = wrap_address(env, src - l + 1);
+ srca = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
+ desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
+ for (i = 0; i < l; i++) {
+ const uint8_t x = access_get_byte(env, &srca, l - i - 1, ra);
+
+ access_set_byte(env, &desta, i, x, ra);
}
}
/* move numerics */
void HELPER(mvn)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
{
+ const int mmu_idx = cpu_mmu_index(env, false);
+ S390Access srca1, srca2, desta;
uintptr_t ra = GETPC();
int i;
- for (i = 0; i <= l; i++) {
- uint8_t v = cpu_ldub_data_ra(env, dest + i, ra) & 0xf0;
- v |= cpu_ldub_data_ra(env, src + i, ra) & 0x0f;
- cpu_stb_data_ra(env, dest + i, v, ra);
+ /* MVN always copies one more byte than specified - maximum is 256 */
+ l++;
+
+ srca1 = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
+ srca2 = access_prepare(env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
+ desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
+ for (i = 0; i < l; i++) {
+ const uint8_t x = (access_get_byte(env, &srca1, i, ra) & 0x0f) |
+ (access_get_byte(env, &srca2, i, ra) & 0xf0);
+
+ access_set_byte(env, &desta, i, x, ra);
}
}
/* move with offset */
void HELPER(mvo)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
{
+ const int mmu_idx = cpu_mmu_index(env, false);
+ /* MVO always processes one more byte than specified - maximum is 16 */
+ const int len_dest = (l >> 4) + 1;
+ const int len_src = (l & 0xf) + 1;
uintptr_t ra = GETPC();
- int len_dest = l >> 4;
- int len_src = l & 0xf;
uint8_t byte_dest, byte_src;
- int i;
+ S390Access srca, desta;
+ int i, j;
- src += len_src;
- dest += len_dest;
+ srca = access_prepare(env, src, len_src, MMU_DATA_LOAD, mmu_idx, ra);
+ desta = access_prepare(env, dest, len_dest, MMU_DATA_STORE, mmu_idx, ra);
/* Handle rightmost byte */
- byte_src = cpu_ldub_data_ra(env, src, ra);
- byte_dest = cpu_ldub_data_ra(env, dest, ra);
+ byte_dest = cpu_ldub_data_ra(env, dest + len_dest - 1, ra);
+ byte_src = access_get_byte(env, &srca, len_src - 1, ra);
byte_dest = (byte_dest & 0x0f) | (byte_src << 4);
- cpu_stb_data_ra(env, dest, byte_dest, ra);
+ access_set_byte(env, &desta, len_dest - 1, byte_dest, ra);
/* Process remaining bytes from right to left */
- for (i = 1; i <= len_dest; i++) {
+ for (i = len_dest - 2, j = len_src - 2; i >= 0; i--, j--) {
byte_dest = byte_src >> 4;
- if (len_src - i >= 0) {
- byte_src = cpu_ldub_data_ra(env, src - i, ra);
+ if (j >= 0) {
+ byte_src = access_get_byte(env, &srca, j, ra);
} else {
byte_src = 0;
}
byte_dest |= byte_src << 4;
- cpu_stb_data_ra(env, dest - i, byte_dest, ra);
+ access_set_byte(env, &desta, i, byte_dest, ra);
}
}
/* move zones */
void HELPER(mvz)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
{
+ const int mmu_idx = cpu_mmu_index(env, false);
+ S390Access srca1, srca2, desta;
uintptr_t ra = GETPC();
int i;
- for (i = 0; i <= l; i++) {
- uint8_t b = cpu_ldub_data_ra(env, dest + i, ra) & 0x0f;
- b |= cpu_ldub_data_ra(env, src + i, ra) & 0xf0;
- cpu_stb_data_ra(env, dest + i, b, ra);
+ /* MVZ always copies one more byte than specified - maximum is 256 */
+ l++;
+
+ srca1 = access_prepare(env, src, l, MMU_DATA_LOAD, mmu_idx, ra);
+ srca2 = access_prepare(env, dest, l, MMU_DATA_LOAD, mmu_idx, ra);
+ desta = access_prepare(env, dest, l, MMU_DATA_STORE, mmu_idx, ra);
+ for (i = 0; i < l; i++) {
+ const uint8_t x = (access_get_byte(env, &srca1, i, ra) & 0xf0) |
+ (access_get_byte(env, &srca2, i, ra) & 0x0f);
+
+ access_set_byte(env, &desta, i, x, ra);
}
}
@@ -469,6 +646,25 @@ static inline uint64_t get_address(CPUS390XState *env, int reg)
return wrap_address(env, env->regs[reg]);
}
+/*
+ * Store the address to the given register, zeroing out unused leftmost
+ * bits in bit positions 32-63 (24-bit and 31-bit mode only).
+ */
+static inline void set_address_zero(CPUS390XState *env, int reg,
+ uint64_t address)
+{
+ if (env->psw.mask & PSW_MASK_64) {
+ env->regs[reg] = address;
+ } else {
+ if (!(env->psw.mask & PSW_MASK_32)) {
+ address &= 0x00ffffff;
+ } else {
+ address &= 0x7fffffff;
+ }
+ env->regs[reg] = deposit64(env->regs[reg], 0, 32, address);
+ }
+}
+
static inline void set_address(CPUS390XState *env, int reg, uint64_t address)
{
if (env->psw.mask & PSW_MASK_64) {
@@ -492,7 +688,15 @@ static inline void set_address(CPUS390XState *env, int reg, uint64_t address)
}
}
-static inline uint64_t wrap_length(CPUS390XState *env, uint64_t length)
+static inline uint64_t wrap_length32(CPUS390XState *env, uint64_t length)
+{
+ if (!(env->psw.mask & PSW_MASK_64)) {
+ return (uint32_t)length;
+ }
+ return length;
+}
+
+static inline uint64_t wrap_length31(CPUS390XState *env, uint64_t length)
{
if (!(env->psw.mask & PSW_MASK_64)) {
/* 24-Bit and 31-Bit mode */
@@ -503,7 +707,7 @@ static inline uint64_t wrap_length(CPUS390XState *env, uint64_t length)
static inline uint64_t get_length(CPUS390XState *env, int reg)
{
- return wrap_length(env, env->regs[reg]);
+ return wrap_length31(env, env->regs[reg]);
}
static inline void set_length(CPUS390XState *env, int reg, uint64_t length)
@@ -527,7 +731,7 @@ void HELPER(srst)(CPUS390XState *env, uint32_t r1, uint32_t r2)
/* Bits 32-55 must contain all 0. */
if (env->regs[0] & 0xffffff00u) {
- s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
}
str = get_address(env, r2);
@@ -564,7 +768,7 @@ void HELPER(srstu)(CPUS390XState *env, uint32_t r1, uint32_t r2)
/* Bits 32-47 of R0 must be zero. */
if (env->regs[0] & 0xffff0000u) {
- s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
}
str = get_address(env, r2);
@@ -636,39 +840,69 @@ uint64_t HELPER(clst)(CPUS390XState *env, uint64_t c, uint64_t s1, uint64_t s2)
/* move page */
uint32_t HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2)
{
- /* ??? missing r0 handling, which includes access keys, but more
- importantly optional suppression of the exception! */
- fast_memmove(env, r1, r2, TARGET_PAGE_SIZE, GETPC());
+ const int mmu_idx = cpu_mmu_index(env, false);
+ const bool f = extract64(r0, 11, 1);
+ const bool s = extract64(r0, 10, 1);
+ uintptr_t ra = GETPC();
+ S390Access srca, desta;
+
+ if ((f && s) || extract64(r0, 12, 4)) {
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
+ }
+
+ r1 = wrap_address(env, r1 & TARGET_PAGE_MASK);
+ r2 = wrap_address(env, r2 & TARGET_PAGE_MASK);
+
+ /*
+ * TODO:
+ * - Access key handling
+ * - CC-option with surpression of page-translation exceptions
+ * - Store r1/r2 register identifiers at real location 162
+ */
+ srca = access_prepare(env, r2, TARGET_PAGE_SIZE, MMU_DATA_LOAD, mmu_idx,
+ ra);
+ desta = access_prepare(env, r1, TARGET_PAGE_SIZE, MMU_DATA_STORE, mmu_idx,
+ ra);
+ access_memmove(env, &desta, &srca, ra);
return 0; /* data moved */
}
-/* string copy (c is string terminator) */
-uint64_t HELPER(mvst)(CPUS390XState *env, uint64_t c, uint64_t d, uint64_t s)
+/* string copy */
+uint32_t HELPER(mvst)(CPUS390XState *env, uint32_t r1, uint32_t r2)
{
+ const int mmu_idx = cpu_mmu_index(env, false);
+ const uint64_t d = get_address(env, r1);
+ const uint64_t s = get_address(env, r2);
+ const uint8_t c = env->regs[0];
+ const int len = MIN(-(d | TARGET_PAGE_MASK), -(s | TARGET_PAGE_MASK));
+ S390Access srca, desta;
uintptr_t ra = GETPC();
- uint32_t len;
+ int i;
- c = c & 0xff;
- d = wrap_address(env, d);
- s = wrap_address(env, s);
+ if (env->regs[0] & 0xffffff00ull) {
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+ }
- /* Lest we fail to service interrupts in a timely manner, limit the
- amount of work we're willing to do. For now, let's cap at 8k. */
- for (len = 0; len < 0x2000; ++len) {
- uint8_t v = cpu_ldub_data_ra(env, s + len, ra);
- cpu_stb_data_ra(env, d + len, v, ra);
+ /*
+ * Our access should not exceed single pages, as we must not report access
+ * exceptions exceeding the actually copied range (which we don't know at
+ * this point). We might over-indicate watchpoints within the pages
+ * (if we ever care, we have to limit processing to a single byte).
+ */
+ srca = access_prepare(env, s, len, MMU_DATA_LOAD, mmu_idx, ra);
+ desta = access_prepare(env, d, len, MMU_DATA_STORE, mmu_idx, ra);
+ for (i = 0; i < len; i++) {
+ const uint8_t v = access_get_byte(env, &srca, i, ra);
+
+ access_set_byte(env, &desta, i, v, ra);
if (v == c) {
- /* Complete. Set CC=1 and advance R1. */
- env->cc_op = 1;
- env->retxl = s;
- return d + len;
+ set_address_zero(env, r1, d + i);
+ return 1;
}
}
-
- /* Incomplete. Set CC=3 and signal to advance R1 and R2. */
- env->cc_op = 3;
- env->retxl = s + len;
- return d + len;
+ set_address_zero(env, r1, d + len);
+ set_address_zero(env, r2, s + len);
+ return 3;
}
/* load access registers r1 to r3 from memory at a2 */
@@ -678,8 +912,7 @@ void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
int i;
if (a2 & 0x3) {
- /* we either came here by lam or lamy, which have different lengths */
- s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, ra);
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
}
for (i = r1;; i = (i + 1) % 16) {
@@ -699,7 +932,7 @@ void HELPER(stam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
int i;
if (a2 & 0x3) {
- s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
}
for (i = r1;; i = (i + 1) % 16) {
@@ -718,8 +951,10 @@ static inline uint32_t do_mvcl(CPUS390XState *env,
uint64_t *src, uint64_t *srclen,
uint16_t pad, int wordsize, uintptr_t ra)
{
- uint64_t len = MIN(*srclen, *destlen);
- uint32_t cc;
+ const int mmu_idx = cpu_mmu_index(env, false);
+ int len = MIN(*destlen, -(*dest | TARGET_PAGE_MASK));
+ S390Access srca, desta;
+ int i, cc;
if (*destlen == *srclen) {
cc = 0;
@@ -729,52 +964,118 @@ static inline uint32_t do_mvcl(CPUS390XState *env,
cc = 2;
}
- /* Copy the src array */
- fast_memmove(env, *dest, *src, len, ra);
- *src += len;
- *srclen -= len;
- *dest += len;
- *destlen -= len;
+ if (!*destlen) {
+ return cc;
+ }
- /* Pad the remaining area */
- if (wordsize == 1) {
- fast_memset(env, *dest, pad, *destlen, ra);
- *dest += *destlen;
- *destlen = 0;
+ /*
+ * Only perform one type of type of operation (move/pad) at a time.
+ * Stay within single pages.
+ */
+ if (*srclen) {
+ /* Copy the src array */
+ len = MIN(MIN(*srclen, -(*src | TARGET_PAGE_MASK)), len);
+ *destlen -= len;
+ *srclen -= len;
+ srca = access_prepare(env, *src, len, MMU_DATA_LOAD, mmu_idx, ra);
+ desta = access_prepare(env, *dest, len, MMU_DATA_STORE, mmu_idx, ra);
+ access_memmove(env, &desta, &srca, ra);
+ *src = wrap_address(env, *src + len);
+ *dest = wrap_address(env, *dest + len);
+ } else if (wordsize == 1) {
+ /* Pad the remaining area */
+ *destlen -= len;
+ desta = access_prepare(env, *dest, len, MMU_DATA_STORE, mmu_idx, ra);
+ access_memset(env, &desta, pad, ra);
+ *dest = wrap_address(env, *dest + len);
} else {
- /* If remaining length is odd, pad with odd byte first. */
- if (*destlen & 1) {
- cpu_stb_data_ra(env, *dest, pad & 0xff, ra);
- *dest += 1;
- *destlen -= 1;
- }
- /* The remaining length is even, pad using words. */
- for (; *destlen; *dest += 2, *destlen -= 2) {
- cpu_stw_data_ra(env, *dest, pad, ra);
+ desta = access_prepare(env, *dest, len, MMU_DATA_STORE, mmu_idx, ra);
+
+ /* The remaining length selects the padding byte. */
+ for (i = 0; i < len; (*destlen)--, i++) {
+ if (*destlen & 1) {
+ access_set_byte(env, &desta, i, pad, ra);
+ } else {
+ access_set_byte(env, &desta, i, pad >> 8, ra);
+ }
}
+ *dest = wrap_address(env, *dest + len);
}
- return cc;
+ return *destlen ? 3 : cc;
}
/* move long */
uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2)
{
+ const int mmu_idx = cpu_mmu_index(env, false);
uintptr_t ra = GETPC();
uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
uint64_t dest = get_address(env, r1);
uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
uint64_t src = get_address(env, r2);
uint8_t pad = env->regs[r2 + 1] >> 24;
- uint32_t cc;
+ CPUState *cs = env_cpu(env);
+ S390Access srca, desta;
+ uint32_t cc, cur_len;
- cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 1, ra);
+ if (is_destructive_overlap(env, dest, src, MIN(srclen, destlen))) {
+ cc = 3;
+ } else if (srclen == destlen) {
+ cc = 0;
+ } else if (destlen < srclen) {
+ cc = 1;
+ } else {
+ cc = 2;
+ }
- env->regs[r1 + 1] = deposit64(env->regs[r1 + 1], 0, 24, destlen);
- env->regs[r2 + 1] = deposit64(env->regs[r2 + 1], 0, 24, srclen);
- set_address(env, r1, dest);
- set_address(env, r2, src);
+ /* We might have to zero-out some bits even if there was no action. */
+ if (unlikely(!destlen || cc == 3)) {
+ set_address_zero(env, r2, src);
+ set_address_zero(env, r1, dest);
+ return cc;
+ } else if (!srclen) {
+ set_address_zero(env, r2, src);
+ }
+ /*
+ * Only perform one type of type of operation (move/pad) in one step.
+ * Stay within single pages.
+ */
+ while (destlen) {
+ cur_len = MIN(destlen, -(dest | TARGET_PAGE_MASK));
+ if (!srclen) {
+ desta = access_prepare(env, dest, cur_len, MMU_DATA_STORE, mmu_idx,
+ ra);
+ access_memset(env, &desta, pad, ra);
+ } else {
+ cur_len = MIN(MIN(srclen, -(src | TARGET_PAGE_MASK)), cur_len);
+
+ srca = access_prepare(env, src, cur_len, MMU_DATA_LOAD, mmu_idx,
+ ra);
+ desta = access_prepare(env, dest, cur_len, MMU_DATA_STORE, mmu_idx,
+ ra);
+ access_memmove(env, &desta, &srca, ra);
+ src = wrap_address(env, src + cur_len);
+ srclen -= cur_len;
+ env->regs[r2 + 1] = deposit64(env->regs[r2 + 1], 0, 24, srclen);
+ set_address_zero(env, r2, src);
+ }
+ dest = wrap_address(env, dest + cur_len);
+ destlen -= cur_len;
+ env->regs[r1 + 1] = deposit64(env->regs[r1 + 1], 0, 24, destlen);
+ set_address_zero(env, r1, dest);
+
+ /*
+ * MVCL is interruptible. Return to the main loop if requested after
+ * writing back all state to registers. If no interrupt will get
+ * injected, we'll end up back in this handler and continue processing
+ * the remaining parts.
+ */
+ if (destlen && unlikely(cpu_loop_exit_requested(cs))) {
+ cpu_loop_exit_restore(cs, ra);
+ }
+ }
return cc;
}
@@ -1596,8 +1897,7 @@ static uint32_t do_csst(CPUS390XState *env, uint32_t r3, uint64_t a1,
return cc;
spec_exception:
- s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
- g_assert_not_reached();
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
}
uint32_t HELPER(csst)(CPUS390XState *env, uint32_t r3, uint64_t a1, uint64_t a2)
@@ -1620,7 +1920,7 @@ void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
uint32_t i;
if (src & 0x7) {
- s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
}
for (i = r1;; i = (i + 1) % 16) {
@@ -1653,7 +1953,7 @@ void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
uint32_t i;
if (src & 0x3) {
- s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
}
for (i = r1;; i = (i + 1) % 16) {
@@ -1684,7 +1984,7 @@ void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
uint32_t i;
if (dest & 0x7) {
- s390_program_interrupt(env, PGM_SPECIFICATION, 6, ra);
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
}
for (i = r1;; i = (i + 1) % 16) {
@@ -1704,7 +2004,7 @@ void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
uint32_t i;
if (dest & 0x3) {
- s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
}
for (i = r1;; i = (i + 1) % 16) {
@@ -1747,7 +2047,7 @@ uint32_t HELPER(tprot)(CPUS390XState *env, uint64_t a1, uint64_t a2)
if (env->int_pgm_code == PGM_PROTECTION) {
/* retry if reading is possible */
- cs->exception_index = 0;
+ cs->exception_index = -1;
if (!s390_cpu_virt_mem_check_read(cpu, a1, 0, 1)) {
/* Fetching permitted; storing not permitted */
return 1;
@@ -1757,7 +2057,7 @@ uint32_t HELPER(tprot)(CPUS390XState *env, uint64_t a1, uint64_t a2)
switch (env->int_pgm_code) {
case PGM_PROTECTION:
/* Fetching not permitted; storing not permitted */
- cs->exception_index = 0;
+ cs->exception_index = -1;
return 2;
case PGM_ADDRESSING:
case PGM_TRANS_SPEC:
@@ -1767,7 +2067,7 @@ uint32_t HELPER(tprot)(CPUS390XState *env, uint64_t a1, uint64_t a2)
}
/* Translation not available */
- cs->exception_index = 0;
+ cs->exception_index = -1;
return 3;
}
@@ -1866,47 +2166,63 @@ uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2)
uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
{
+ const uint8_t psw_as = (env->psw.mask & PSW_MASK_ASC) >> PSW_SHIFT_ASC;
+ S390Access srca, desta;
uintptr_t ra = GETPC();
- int cc = 0, i;
+ int cc = 0;
HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
__func__, l, a1, a2);
+ if (!(env->psw.mask & PSW_MASK_DAT) || !(env->cregs[0] & CR0_SECONDARY) ||
+ psw_as == AS_HOME || psw_as == AS_ACCREG) {
+ s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
+ }
+
+ l = wrap_length32(env, l);
if (l > 256) {
/* max 256 */
l = 256;
cc = 3;
+ } else if (!l) {
+ return cc;
}
- /* XXX replace w/ memcpy */
- for (i = 0; i < l; i++) {
- uint8_t x = cpu_ldub_primary_ra(env, a2 + i, ra);
- cpu_stb_secondary_ra(env, a1 + i, x, ra);
- }
-
+ /* TODO: Access key handling */
+ srca = access_prepare(env, a2, l, MMU_DATA_LOAD, MMU_PRIMARY_IDX, ra);
+ desta = access_prepare(env, a1, l, MMU_DATA_STORE, MMU_SECONDARY_IDX, ra);
+ access_memmove(env, &desta, &srca, ra);
return cc;
}
uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
{
+ const uint8_t psw_as = (env->psw.mask & PSW_MASK_ASC) >> PSW_SHIFT_ASC;
+ S390Access srca, desta;
uintptr_t ra = GETPC();
- int cc = 0, i;
+ int cc = 0;
HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
__func__, l, a1, a2);
+ if (!(env->psw.mask & PSW_MASK_DAT) || !(env->cregs[0] & CR0_SECONDARY) ||
+ psw_as == AS_HOME || psw_as == AS_ACCREG) {
+ s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
+ }
+
+ l = wrap_length32(env, l);
if (l > 256) {
/* max 256 */
l = 256;
cc = 3;
+ } else if (!l) {
+ return cc;
}
- /* XXX replace w/ memcpy */
- for (i = 0; i < l; i++) {
- uint8_t x = cpu_ldub_secondary_ra(env, a2 + i, ra);
- cpu_stb_primary_ra(env, a1 + i, x, ra);
- }
-
+ /* TODO: Access key handling */
+ srca = access_prepare(env, a2, l, MMU_DATA_LOAD, MMU_SECONDARY_IDX, ra);
+ desta = access_prepare(env, a1, l, MMU_DATA_STORE, MMU_PRIMARY_IDX, ra);
+ access_memmove(env, &desta, &srca, ra);
return cc;
}
@@ -1918,7 +2234,7 @@ void HELPER(idte)(CPUS390XState *env, uint64_t r1, uint64_t r2, uint32_t m4)
uint16_t entries, i, index = 0;
if (r2 & 0xff000) {
- s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
}
if (!(r2 & 0x800)) {
@@ -1944,9 +2260,9 @@ void HELPER(idte)(CPUS390XState *env, uint64_t r1, uint64_t r2, uint32_t m4)
/* addresses are not wrapped in 24/31bit mode but table index is */
raddr = table + ((index + i) & 0x7ff) * sizeof(entry);
entry = cpu_ldq_real_ra(env, raddr, ra);
- if (!(entry & REGION_ENTRY_INV)) {
+ if (!(entry & REGION_ENTRY_I)) {
/* we are allowed to not store if already invalid */
- entry |= REGION_ENTRY_INV;
+ entry |= REGION_ENTRY_I;
cpu_stq_real_ra(env, raddr, entry, ra);
}
}
@@ -1971,17 +2287,17 @@ void HELPER(ipte)(CPUS390XState *env, uint64_t pto, uint64_t vaddr,
/* Compute the page table entry address */
pte_addr = (pto & SEGMENT_ENTRY_ORIGIN);
- pte_addr += (vaddr & VADDR_PX) >> 9;
+ pte_addr += VADDR_PAGE_TX(vaddr) * 8;
/* Mark the page table entry as invalid */
pte = cpu_ldq_real_ra(env, pte_addr, ra);
- pte |= PAGE_INVALID;
+ pte |= PAGE_ENTRY_I;
cpu_stq_real_ra(env, pte_addr, pte, ra);
/* XXX we exploit the fact that Linux passes the exact virtual
address here - it's not obliged to! */
if (m4 & 1) {
- if (vaddr & ~VADDR_PX) {
+ if (vaddr & ~VADDR_PAGE_TX_MASK) {
tlb_flush_page(cs, page);
/* XXX 31-bit hack */
tlb_flush_page(cs, page ^ 0x80000000);
@@ -1990,7 +2306,7 @@ void HELPER(ipte)(CPUS390XState *env, uint64_t pto, uint64_t vaddr,
tlb_flush(cs);
}
} else {
- if (vaddr & ~VADDR_PX) {
+ if (vaddr & ~VADDR_PAGE_TX_MASK) {
tlb_flush_page_all_cpus_synced(cs, page);
/* XXX 31-bit hack */
tlb_flush_page_all_cpus_synced(cs, page ^ 0x80000000);
@@ -2054,27 +2370,23 @@ void HELPER(sturg)(CPUS390XState *env, uint64_t addr, uint64_t v1)
/* load real address */
uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr)
{
- CPUState *cs = env_cpu(env);
- uint32_t cc = 0;
uint64_t asc = env->psw.mask & PSW_MASK_ASC;
- uint64_t ret;
- int old_exc, flags;
+ uint64_t ret, tec;
+ int flags, exc, cc;
/* XXX incomplete - has more corner cases */
if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
- s390_program_interrupt(env, PGM_SPECIAL_OP, 2, GETPC());
+ tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, GETPC());
}
- old_exc = cs->exception_index;
- if (mmu_translate(env, addr, 0, asc, &ret, &flags, true)) {
+ exc = mmu_translate(env, addr, 0, asc, &ret, &flags, &tec);
+ if (exc) {
cc = 3;
- }
- if (cs->exception_index == EXCP_PGM) {
- ret = env->int_pgm_code | 0x80000000;
+ ret = exc | 0x80000000;
} else {
+ cc = 0;
ret |= addr & ~TARGET_PAGE_MASK;
}
- cs->exception_index = old_exc;
env->cc_op = cc;
return ret;
@@ -2231,7 +2543,7 @@ uint32_t HELPER(mvcos)(CPUS390XState *env, uint64_t dest, uint64_t src,
__func__, dest, src, len);
if (!(env->psw.mask & PSW_MASK_DAT)) {
- s390_program_interrupt(env, PGM_SPECIAL_OP, 6, ra);
+ tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
}
/* OAC (operand access control) for the first operand -> dest */
@@ -2262,17 +2574,17 @@ uint32_t HELPER(mvcos)(CPUS390XState *env, uint64_t dest, uint64_t src,
}
if (dest_a && dest_as == AS_HOME && (env->psw.mask & PSW_MASK_PSTATE)) {
- s390_program_interrupt(env, PGM_SPECIAL_OP, 6, ra);
+ tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
}
if (!(env->cregs[0] & CR0_SECONDARY) &&
(dest_as == AS_SECONDARY || src_as == AS_SECONDARY)) {
- s390_program_interrupt(env, PGM_SPECIAL_OP, 6, ra);
+ tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, ra);
}
if (!psw_key_valid(env, dest_key) || !psw_key_valid(env, src_key)) {
- s390_program_interrupt(env, PGM_PRIVILEGED, 6, ra);
+ tcg_s390_program_interrupt(env, PGM_PRIVILEGED, ra);
}
- len = wrap_length(env, len);
+ len = wrap_length32(env, len);
if (len > 4096) {
cc = 3;
len = 4096;
@@ -2283,19 +2595,18 @@ uint32_t HELPER(mvcos)(CPUS390XState *env, uint64_t dest, uint64_t src,
(env->psw.mask & PSW_MASK_PSTATE)) {
qemu_log_mask(LOG_UNIMP, "%s: AR-mode and PSTATE support missing\n",
__func__);
- s390_program_interrupt(env, PGM_ADDRESSING, 6, ra);
+ tcg_s390_program_interrupt(env, PGM_ADDRESSING, ra);
}
- /* FIXME: a) LAP
- * b) Access using correct keys
- * c) AR-mode
- */
-#ifdef CONFIG_USER_ONLY
- /* psw keys are never valid in user mode, we will never reach this */
- g_assert_not_reached();
-#else
- fast_memmove_as(env, dest, src, len, dest_as, src_as, ra);
-#endif
+ /* FIXME: Access using correct keys and AR-mode */
+ if (len) {
+ S390Access srca = access_prepare(env, src, len, MMU_DATA_LOAD,
+ mmu_idx_from_as(src_as), ra);
+ S390Access desta = access_prepare(env, dest, len, MMU_DATA_STORE,
+ mmu_idx_from_as(dest_as), ra);
+
+ access_memmove(env, &desta, &srca, ra);
+ }
return cc;
}
diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c
index 7530dcb..bfb457f 100644
--- a/target/s390x/misc_helper.c
+++ b/target/s390x/misc_helper.c
@@ -106,7 +106,7 @@ uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2)
int r = sclp_service_call(env, r1, r2);
qemu_mutex_unlock_iothread();
if (r < 0) {
- s390_program_interrupt(env, -r, 4, GETPC());
+ tcg_s390_program_interrupt(env, -r, GETPC());
}
return r;
}
@@ -143,7 +143,7 @@ void HELPER(diag)(CPUS390XState *env, uint32_t r1, uint32_t r3, uint32_t num)
}
if (r) {
- s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, GETPC());
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
}
}
@@ -222,7 +222,7 @@ void HELPER(sckpf)(CPUS390XState *env, uint64_t r0)
uint32_t val = r0;
if (val & 0xffff0000) {
- s390_program_interrupt(env, PGM_SPECIFICATION, 2, GETPC());
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
}
env->todpr = val;
}
@@ -266,7 +266,7 @@ uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, uint64_t r0, uint64_t r1)
}
if ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK)) {
- s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
}
if ((r0 & STSI_R0_FC_MASK) == STSI_R0_FC_CURRENT) {
@@ -276,7 +276,7 @@ uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, uint64_t r0, uint64_t r1)
}
if (a0 & ~TARGET_PAGE_MASK) {
- s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
}
/* count the cpus and split them into configured and reserved ones */
@@ -509,7 +509,7 @@ uint32_t HELPER(tpi)(CPUS390XState *env, uint64_t addr)
LowCore *lowcore;
if (addr & 0x3) {
- s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
}
qemu_mutex_lock_iothread();
@@ -573,17 +573,8 @@ void HELPER(chsc)(CPUS390XState *env, uint64_t inst)
#ifndef CONFIG_USER_ONLY
void HELPER(per_check_exception)(CPUS390XState *env)
{
- uint32_t ilen;
-
if (env->per_perc_atmid) {
- /*
- * FIXME: ILEN_AUTO is most probably the right thing to use. ilen
- * always has to match the instruction referenced in the PSW. E.g.
- * if a PER interrupt is triggered via EXECUTE, we have to use ilen
- * of EXECUTE, while per_address contains the target of EXECUTE.
- */
- ilen = get_ilen(cpu_ldub_code(env, env->per_address));
- s390_program_interrupt(env, PGM_PER, ilen, GETPC());
+ tcg_s390_program_interrupt(env, PGM_PER, GETPC());
}
}
@@ -673,7 +664,7 @@ uint32_t HELPER(stfle)(CPUS390XState *env, uint64_t addr)
int i;
if (addr & 0x7) {
- s390_program_interrupt(env, PGM_SPECIFICATION, 4, ra);
+ tcg_s390_program_interrupt(env, PGM_SPECIFICATION, ra);
}
prepare_stfl();
@@ -746,7 +737,7 @@ void HELPER(sic)(CPUS390XState *env, uint64_t r1, uint64_t r3)
qemu_mutex_unlock_iothread();
/* css_do_sic() may actually return a PGM_xxx value to inject */
if (r) {
- s390_program_interrupt(env, -r, 4, GETPC());
+ tcg_s390_program_interrupt(env, -r, GETPC());
}
}
diff --git a/target/s390x/mmu_helper.c b/target/s390x/mmu_helper.c
index 7e6b0d0..c9f3f34 100644
--- a/target/s390x/mmu_helper.c
+++ b/target/s390x/mmu_helper.c
@@ -28,37 +28,12 @@
#include "hw/hw.h"
#include "hw/s390x/storage-keys.h"
-/* #define DEBUG_S390 */
-/* #define DEBUG_S390_PTE */
-/* #define DEBUG_S390_STDOUT */
-
-#ifdef DEBUG_S390
-#ifdef DEBUG_S390_STDOUT
-#define DPRINTF(fmt, ...) \
- do { fprintf(stderr, fmt, ## __VA_ARGS__); \
- if (qemu_log_separate()) qemu_log(fmt, ##__VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) \
- do { qemu_log(fmt, ## __VA_ARGS__); } while (0)
-#endif
-#else
-#define DPRINTF(fmt, ...) \
- do { } while (0)
-#endif
-
-#ifdef DEBUG_S390_PTE
-#define PTE_DPRINTF DPRINTF
-#else
-#define PTE_DPRINTF(fmt, ...) \
- do { } while (0)
-#endif
-
/* 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,
- uint32_t ilen, uint64_t tec)
+ uint64_t tec)
{
S390CPU *cpu = env_archcpu(env);
@@ -69,46 +44,8 @@ static void trigger_access_exception(CPUS390XState *env, uint32_t type,
if (type != PGM_ADDRESSING) {
stq_phys(cs->as, env->psa + offsetof(LowCore, trans_exc_code), tec);
}
- trigger_pgm_exception(env, type, ilen);
- }
-}
-
-static void trigger_prot_fault(CPUS390XState *env, target_ulong vaddr,
- uint64_t asc, int rw, bool exc)
-{
- uint64_t tec;
-
- tec = vaddr | (rw == MMU_DATA_STORE ? FS_WRITE : FS_READ) | 4 | asc >> 46;
-
- DPRINTF("%s: trans_exc_code=%016" PRIx64 "\n", __func__, tec);
-
- if (!exc) {
- return;
- }
-
- trigger_access_exception(env, PGM_PROTECTION, ILEN_AUTO, tec);
-}
-
-static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr,
- uint32_t type, uint64_t asc, int rw, bool exc)
-{
- int ilen = ILEN_AUTO;
- uint64_t tec;
-
- tec = vaddr | (rw == MMU_DATA_STORE ? FS_WRITE : FS_READ) | asc >> 46;
-
- DPRINTF("%s: trans_exc_code=%016" PRIx64 "\n", __func__, tec);
-
- if (!exc) {
- return;
- }
-
- /* Code accesses have an undefined ilc. */
- if (rw == MMU_INST_FETCH) {
- ilen = 2;
+ trigger_pgm_exception(env, type);
}
-
- trigger_access_exception(env, type, ilen, tec);
}
/* check whether the address would be proteted by Low-Address Protection */
@@ -156,122 +93,40 @@ target_ulong mmu_real2abs(CPUS390XState *env, target_ulong raddr)
return raddr;
}
-/* Decode page table entry (normal 4KB page) */
-static int mmu_translate_pte(CPUS390XState *env, target_ulong vaddr,
- uint64_t asc, uint64_t pt_entry,
- target_ulong *raddr, int *flags, int rw, bool exc)
-{
- if (pt_entry & PAGE_INVALID) {
- DPRINTF("%s: PTE=0x%" PRIx64 " invalid\n", __func__, pt_entry);
- trigger_page_fault(env, vaddr, PGM_PAGE_TRANS, asc, rw, exc);
- return -1;
- }
- if (pt_entry & PAGE_RES0) {
- trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw, exc);
- return -1;
- }
- if (pt_entry & PAGE_RO) {
- *flags &= ~PAGE_WRITE;
- }
-
- *raddr = pt_entry & ASCE_ORIGIN;
-
- PTE_DPRINTF("%s: PTE=0x%" PRIx64 "\n", __func__, pt_entry);
-
- return 0;
-}
-
-/* Decode segment table entry */
-static int mmu_translate_segment(CPUS390XState *env, target_ulong vaddr,
- uint64_t asc, uint64_t st_entry,
- target_ulong *raddr, int *flags, int rw,
- bool exc)
+static inline bool read_table_entry(CPUS390XState *env, hwaddr gaddr,
+ uint64_t *entry)
{
CPUState *cs = env_cpu(env);
- uint64_t origin, offs, pt_entry;
- if (st_entry & SEGMENT_ENTRY_RO) {
- *flags &= ~PAGE_WRITE;
- }
-
- if ((st_entry & SEGMENT_ENTRY_FC) && (env->cregs[0] & CR0_EDAT)) {
- /* Decode EDAT1 segment frame absolute address (1MB page) */
- *raddr = (st_entry & 0xfffffffffff00000ULL) | (vaddr & 0xfffff);
- PTE_DPRINTF("%s: SEG=0x%" PRIx64 "\n", __func__, st_entry);
- return 0;
- }
-
- /* Look up 4KB page entry */
- origin = st_entry & SEGMENT_ENTRY_ORIGIN;
- offs = (vaddr & VADDR_PX) >> 9;
- pt_entry = ldq_phys(cs->as, origin + offs);
- PTE_DPRINTF("%s: 0x%" PRIx64 " + 0x%" PRIx64 " => 0x%016" PRIx64 "\n",
- __func__, origin, offs, pt_entry);
- return mmu_translate_pte(env, vaddr, asc, pt_entry, raddr, flags, rw, exc);
-}
-
-/* Decode region table entries */
-static int mmu_translate_region(CPUS390XState *env, target_ulong vaddr,
- uint64_t asc, uint64_t entry, int level,
- target_ulong *raddr, int *flags, int rw,
- bool exc)
-{
- CPUState *cs = env_cpu(env);
- uint64_t origin, offs, new_entry;
- const int pchks[4] = {
- PGM_SEGMENT_TRANS, PGM_REG_THIRD_TRANS,
- PGM_REG_SEC_TRANS, PGM_REG_FIRST_TRANS
- };
-
- PTE_DPRINTF("%s: 0x%" PRIx64 "\n", __func__, entry);
-
- origin = entry & REGION_ENTRY_ORIGIN;
- offs = (vaddr >> (17 + 11 * level / 4)) & 0x3ff8;
-
- new_entry = ldq_phys(cs->as, origin + offs);
- PTE_DPRINTF("%s: 0x%" PRIx64 " + 0x%" PRIx64 " => 0x%016" PRIx64 "\n",
- __func__, origin, offs, new_entry);
-
- if ((new_entry & REGION_ENTRY_INV) != 0) {
- DPRINTF("%s: invalid region\n", __func__);
- trigger_page_fault(env, vaddr, pchks[level / 4], asc, rw, exc);
- return -1;
- }
-
- if ((new_entry & REGION_ENTRY_TYPE_MASK) != level) {
- trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw, exc);
- return -1;
- }
-
- if (level == ASCE_TYPE_SEGMENT) {
- return mmu_translate_segment(env, vaddr, asc, new_entry, raddr, flags,
- rw, exc);
- }
-
- /* Check region table offset and length */
- offs = (vaddr >> (28 + 11 * (level - 4) / 4)) & 3;
- if (offs < ((new_entry & REGION_ENTRY_TF) >> 6)
- || offs > (new_entry & REGION_ENTRY_LENGTH)) {
- DPRINTF("%s: invalid offset or len (%lx)\n", __func__, new_entry);
- trigger_page_fault(env, vaddr, pchks[level / 4 - 1], asc, rw, exc);
- return -1;
- }
-
- if ((env->cregs[0] & CR0_EDAT) && (new_entry & REGION_ENTRY_RO)) {
- *flags &= ~PAGE_WRITE;
+ /*
+ * 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,
+ (uint8_t *)entry, sizeof(*entry)) !=
+ MEMTX_OK)) {
+ return false;
}
-
- /* yet another region */
- return mmu_translate_region(env, vaddr, asc, new_entry, level - 4,
- raddr, flags, rw, exc);
+ *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, bool exc)
+ int *flags, int rw)
{
- int level;
- int r;
+ const bool edat1 = (env->cregs[0] & CR0_EDAT) &&
+ s390_has_feat(S390_FEAT_EDAT);
+ const bool edat2 = edat1 && s390_has_feat(S390_FEAT_EDAT_2);
+ const bool iep = (env->cregs[0] & CR0_IEP) &&
+ s390_has_feat(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 */
@@ -279,60 +134,158 @@ static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr,
return 0;
}
- level = asce & ASCE_TYPE_MASK;
- switch (level) {
+ switch (asce & ASCE_TYPE_MASK) {
case ASCE_TYPE_REGION1:
- if ((vaddr >> 62) > (asce & ASCE_TABLE_LENGTH)) {
- trigger_page_fault(env, vaddr, PGM_REG_FIRST_TRANS, asc, rw, exc);
- return -1;
+ 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 & 0xffe0000000000000ULL) {
- DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64
- " 0xffe0000000000000ULL\n", __func__, vaddr);
- trigger_page_fault(env, vaddr, PGM_ASCE_TYPE, asc, rw, exc);
- return -1;
+ if (VADDR_REGION1_TX(vaddr)) {
+ return PGM_ASCE_TYPE;
}
- if ((vaddr >> 51 & 3) > (asce & ASCE_TABLE_LENGTH)) {
- trigger_page_fault(env, vaddr, PGM_REG_SEC_TRANS, asc, rw, exc);
- return -1;
+ 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 & 0xfffffc0000000000ULL) {
- DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64
- " 0xfffffc0000000000ULL\n", __func__, vaddr);
- trigger_page_fault(env, vaddr, PGM_ASCE_TYPE, asc, rw, exc);
- return -1;
+ if (VADDR_REGION1_TX(vaddr) || VADDR_REGION2_TX(vaddr)) {
+ return PGM_ASCE_TYPE;
}
- if ((vaddr >> 40 & 3) > (asce & ASCE_TABLE_LENGTH)) {
- trigger_page_fault(env, vaddr, PGM_REG_THIRD_TRANS, asc, rw, exc);
- return -1;
+ 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 & 0xffffffff80000000ULL) {
- DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64
- " 0xffffffff80000000ULL\n", __func__, vaddr);
- trigger_page_fault(env, vaddr, PGM_ASCE_TYPE, asc, rw, exc);
- return -1;
+ 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 ((vaddr >> 29 & 3) > (asce & ASCE_TABLE_LENGTH)) {
- trigger_page_fault(env, vaddr, PGM_SEGMENT_TRANS, asc, rw, exc);
- return -1;
+ 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;
}
- r = mmu_translate_region(env, vaddr, asc, asce, level, raddr, flags, rw,
- exc);
- if (!r && rw == MMU_DATA_STORE && !(*flags & PAGE_WRITE)) {
- trigger_prot_fault(env, vaddr, asc, rw, exc);
- return -1;
+ 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;
}
- return r;
+ *raddr = entry & TARGET_PAGE_MASK;
+ return 0;
}
static void mmu_handle_skey(target_ulong addr, int rw, int *flags)
@@ -412,16 +365,18 @@ static void mmu_handle_skey(target_ulong addr, int rw, int *flags)
* @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 if the translation was successful, -1 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, bool exc)
+ 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
@@ -433,10 +388,9 @@ int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
*/
*flags |= PAGE_WRITE_INV;
if (is_low_address(vaddr) && rw == MMU_DATA_STORE) {
- if (exc) {
- trigger_access_exception(env, PGM_PROTECTION, ILEN_AUTO, 0);
- }
- return -EACCES;
+ /* LAP sets bit 56 */
+ *tec |= 0x80;
+ return PGM_PROTECTION;
}
}
@@ -449,15 +403,12 @@ int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
switch (asc) {
case PSW_ASC_PRIMARY:
- PTE_DPRINTF("%s: asc=primary\n", __func__);
asce = env->cregs[1];
break;
case PSW_ASC_HOME:
- PTE_DPRINTF("%s: asc=home\n", __func__);
asce = env->cregs[13];
break;
case PSW_ASC_SECONDARY:
- PTE_DPRINTF("%s: asc=secondary\n", __func__);
asce = env->cregs[7];
break;
case PSW_ASC_ACCREG:
@@ -467,11 +418,25 @@ int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
}
/* perform the DAT translation */
- r = mmu_translate_asce(env, vaddr, asc, asce, raddr, flags, rw, exc);
- if (r) {
+ 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);
@@ -486,22 +451,22 @@ nodat:
* the MEMOP interface.
*/
static int translate_pages(S390CPU *cpu, vaddr addr, int nr_pages,
- target_ulong *pages, bool is_write)
+ 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, true);
+ ret = mmu_translate(env, addr, is_write, asc, &pages[i], &pflags, tec);
if (ret) {
return ret;
}
if (!address_space_access_valid(&address_space_memory, pages[i],
TARGET_PAGE_SIZE, is_write,
MEMTXATTRS_UNSPECIFIED)) {
- trigger_access_exception(env, PGM_ADDRESSING, ILEN_AUTO, 0);
- return -EFAULT;
+ *tec = 0; /* unused */
+ return PGM_ADDRESSING;
}
addr += TARGET_PAGE_SIZE;
}
@@ -529,6 +494,7 @@ int s390_cpu_virt_mem_rw(S390CPU *cpu, vaddr laddr, uint8_t ar, void *hostbuf,
{
int currlen, nr_pages, i;
target_ulong *pages;
+ uint64_t tec;
int ret;
if (kvm_enabled()) {
@@ -542,8 +508,10 @@ int s390_cpu_virt_mem_rw(S390CPU *cpu, vaddr laddr, uint8_t ar, void *hostbuf,
+ 1;
pages = g_malloc(nr_pages * sizeof(*pages));
- ret = translate_pages(cpu, laddr, nr_pages, pages, is_write);
- if (ret == 0 && hostbuf != NULL) {
+ 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));
@@ -575,10 +543,10 @@ void s390_cpu_virt_mem_handle_exc(S390CPU *cpu, uintptr_t ra)
* @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 if the translation was successful, < 0 if a fault occurred
+ * @return 0 = success, != 0, the exception to raise
*/
int mmu_translate_real(CPUS390XState *env, target_ulong raddr, int rw,
- target_ulong *addr, int *flags)
+ target_ulong *addr, int *flags, uint64_t *tec)
{
const bool lowprot_enabled = env->cregs[0] & CR0_LOWPROT;
@@ -587,8 +555,9 @@ int mmu_translate_real(CPUS390XState *env, target_ulong raddr, int rw,
/* see comment in mmu_translate() how this works */
*flags |= PAGE_WRITE_INV;
if (is_low_address(raddr) && rw == MMU_DATA_STORE) {
- trigger_access_exception(env, PGM_PROTECTION, ILEN_AUTO, 0);
- return -EACCES;
+ /* LAP sets bit 56 */
+ *tec = (raddr & TARGET_PAGE_MASK) | FS_WRITE | 0x80;
+ return PGM_PROTECTION;
}
}
diff --git a/target/s390x/tcg-stub.c b/target/s390x/tcg-stub.c
index 32adb72..d22c898 100644
--- a/target/s390x/tcg-stub.c
+++ b/target/s390x/tcg-stub.c
@@ -18,8 +18,8 @@
void tcg_s390_tod_updated(CPUState *cs, run_on_cpu_data opaque)
{
}
-void QEMU_NORETURN tcg_s390_program_interrupt(CPUS390XState *env, uint32_t code,
- int ilen, uintptr_t ra)
+void QEMU_NORETURN tcg_s390_program_interrupt(CPUS390XState *env,
+ uint32_t code, uintptr_t ra)
{
g_assert_not_reached();
}
diff --git a/target/s390x/tcg_s390x.h b/target/s390x/tcg_s390x.h
index 2813f9d..2f54ccb 100644
--- a/target/s390x/tcg_s390x.h
+++ b/target/s390x/tcg_s390x.h
@@ -14,8 +14,8 @@
#define TCG_S390X_H
void tcg_s390_tod_updated(CPUState *cs, run_on_cpu_data opaque);
-void QEMU_NORETURN tcg_s390_program_interrupt(CPUS390XState *env, uint32_t code,
- int ilen, uintptr_t ra);
+void QEMU_NORETURN tcg_s390_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,
diff --git a/target/s390x/translate.c b/target/s390x/translate.c
index 2927247..151dfa9 100644
--- a/target/s390x/translate.c
+++ b/target/s390x/translate.c
@@ -318,6 +318,9 @@ static inline uint64_t ld_code4(CPUS390XState *env, uint64_t pc)
static int get_mem_index(DisasContext *s)
{
+#ifdef CONFIG_USER_ONLY
+ return MMU_USER_IDX;
+#else
if (!(s->base.tb->flags & FLAG_MASK_DAT)) {
return MMU_REAL_IDX;
}
@@ -333,6 +336,7 @@ static int get_mem_index(DisasContext *s)
tcg_abort();
break;
}
+#endif
}
static void gen_exception(int excp)
@@ -3488,9 +3492,13 @@ static DisasJumpType op_mvpg(DisasContext *s, DisasOps *o)
static DisasJumpType op_mvst(DisasContext *s, DisasOps *o)
{
- gen_helper_mvst(o->in1, cpu_env, regs[0], o->in1, o->in2);
+ TCGv_i32 t1 = tcg_const_i32(get_field(s->fields, r1));
+ TCGv_i32 t2 = tcg_const_i32(get_field(s->fields, r2));
+
+ gen_helper_mvst(cc_op, cpu_env, t1, t2);
+ tcg_temp_free_i32(t1);
+ tcg_temp_free_i32(t2);
set_cc_static(s);
- return_low128(o->in2);
return DISAS_NEXT;
}
@@ -6301,6 +6309,9 @@ static DisasJumpType translate_one(CPUS390XState *env, DisasContext *s)
/* Search for the insn in the table. */
insn = extract_insn(env, s, &f);
+ /* Emit insn_start now that we know the ILEN. */
+ tcg_gen_insn_start(s->base.pc_next, s->cc_op, s->ilen);
+
/* Not found means unimplemented/illegal opcode. */
if (insn == NULL) {
qemu_log_mask(LOG_UNIMP, "unimplemented opcode 0x%02x%02x\n",
@@ -6455,9 +6466,6 @@ static void s390x_tr_tb_start(DisasContextBase *db, CPUState *cs)
static void s390x_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
{
- DisasContext *dc = container_of(dcbase, DisasContext, base);
-
- tcg_gen_insn_start(dc->base.pc_next, dc->cc_op);
}
static bool s390x_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs,
@@ -6465,6 +6473,14 @@ static bool s390x_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs,
{
DisasContext *dc = container_of(dcbase, DisasContext, base);
+ /*
+ * Emit an insn_start to accompany the breakpoint exception.
+ * The ILEN value is a dummy, since this does not result in
+ * an s390x exception, but an internal qemu exception which
+ * brings us back to interact with the gdbstub.
+ */
+ tcg_gen_insn_start(dc->base.pc_next, dc->cc_op, 2);
+
dc->base.is_jmp = DISAS_PC_STALE;
dc->do_debug = true;
/* The address covered by the breakpoint must be included in
@@ -6559,8 +6575,14 @@ void restore_state_to_opc(CPUS390XState *env, TranslationBlock *tb,
target_ulong *data)
{
int cc_op = data[1];
+
env->psw.addr = data[0];
+
+ /* Update the CC opcode if it is not already up-to-date. */
if ((cc_op != CC_OP_DYNAMIC) && (cc_op != CC_OP_STATIC)) {
env->cc_op = cc_op;
}
+
+ /* Record ILEN. */
+ env->int_pgm_ilen = data[2];
}
diff --git a/target/s390x/translate_vx.inc.c b/target/s390x/translate_vx.inc.c
index 5ce7bfb..71059f9 100644
--- a/target/s390x/translate_vx.inc.c
+++ b/target/s390x/translate_vx.inc.c
@@ -2132,12 +2132,12 @@ static DisasJumpType op_vs(DisasContext *s, DisasOps *o)
static void gen_scbi_i32(TCGv_i32 d, TCGv_i32 a, TCGv_i32 b)
{
- tcg_gen_setcond_i32(TCG_COND_LTU, d, a, b);
+ tcg_gen_setcond_i32(TCG_COND_GEU, d, a, b);
}
static void gen_scbi_i64(TCGv_i64 d, TCGv_i64 a, TCGv_i64 b)
{
- tcg_gen_setcond_i64(TCG_COND_LTU, d, a, b);
+ tcg_gen_setcond_i64(TCG_COND_GEU, d, a, b);
}
static void gen_scbi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al,
@@ -2151,7 +2151,8 @@ static void gen_scbi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al,
tcg_gen_andi_i64(th, th, 1);
tcg_gen_sub2_i64(tl, th, ah, zero, th, zero);
tcg_gen_sub2_i64(tl, th, tl, th, bh, zero);
- tcg_gen_andi_i64(dl, th, 1);
+ /* "invert" the result: -1 -> 0; 0 -> 1 */
+ tcg_gen_addi_i64(dl, th, 1);
tcg_gen_mov_i64(dh, zero);
tcg_temp_free_i64(th);
@@ -2186,13 +2187,13 @@ static void gen_sbi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
TCGv_i64 bl, TCGv_i64 bh, TCGv_i64 cl, TCGv_i64 ch)
{
TCGv_i64 tl = tcg_temp_new_i64();
- TCGv_i64 zero = tcg_const_i64(0);
+ TCGv_i64 th = tcg_temp_new_i64();
- tcg_gen_andi_i64(tl, cl, 1);
- tcg_gen_sub2_i64(dl, dh, al, ah, bl, bh);
- tcg_gen_sub2_i64(dl, dh, dl, dh, tl, zero);
+ tcg_gen_not_i64(tl, bl);
+ tcg_gen_not_i64(th, bh);
+ gen_ac2_i64(dl, dh, al, ah, tl, th, cl, ch);
tcg_temp_free_i64(tl);
- tcg_temp_free_i64(zero);
+ tcg_temp_free_i64(th);
}
static DisasJumpType op_vsbi(DisasContext *s, DisasOps *o)
@@ -2213,20 +2214,13 @@ static void gen_sbcbi2_i64(TCGv_i64 dl, TCGv_i64 dh, TCGv_i64 al, TCGv_i64 ah,
{
TCGv_i64 th = tcg_temp_new_i64();
TCGv_i64 tl = tcg_temp_new_i64();
- TCGv_i64 zero = tcg_const_i64(0);
- tcg_gen_andi_i64(tl, cl, 1);
- tcg_gen_sub2_i64(tl, th, al, zero, tl, zero);
- tcg_gen_sub2_i64(tl, th, tl, th, bl, zero);
- tcg_gen_andi_i64(th, th, 1);
- tcg_gen_sub2_i64(tl, th, ah, zero, th, zero);
- tcg_gen_sub2_i64(tl, th, tl, th, bh, zero);
- tcg_gen_andi_i64(dl, th, 1);
- tcg_gen_mov_i64(dh, zero);
+ tcg_gen_not_i64(tl, bl);
+ tcg_gen_not_i64(th, bh);
+ gen_accc2_i64(dl, dh, al, ah, tl, th, cl, ch);
tcg_temp_free_i64(tl);
tcg_temp_free_i64(th);
- tcg_temp_free_i64(zero);
}
static DisasJumpType op_vsbcbi(DisasContext *s, DisasOps *o)
diff --git a/target/s390x/vec_int_helper.c b/target/s390x/vec_int_helper.c
index 68eaae4..0d6bc13 100644
--- a/target/s390x/vec_int_helper.c
+++ b/target/s390x/vec_int_helper.c
@@ -70,15 +70,17 @@ static void s390_vec_sar(S390Vector *d, const S390Vector *a, uint64_t count)
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] = 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] = 0;
+ d->doubleword[0] = tmp;
}
}
@@ -336,7 +338,7 @@ void HELPER(gvec_vmae##BITS)(void *v1, const void *v2, const void *v3, \
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 = (int##BITS##_t)s390_vec_read_element##BITS(v4, j); \
+ int##TBITS##_t c = s390_vec_read_element##TBITS(v4, i); \
\
s390_vec_write_element##TBITS(v1, i, a * b + c); \
} \
@@ -354,7 +356,7 @@ void HELPER(gvec_vmale##BITS)(void *v1, const void *v2, const void *v3, \
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##BITS(v4, j); \
+ uint##TBITS##_t c = s390_vec_read_element##TBITS(v4, i); \
\
s390_vec_write_element##TBITS(v1, i, a * b + c); \
} \
@@ -372,7 +374,7 @@ void HELPER(gvec_vmao##BITS)(void *v1, const void *v2, const void *v3, \
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 = (int##BITS##_t)s390_vec_read_element##BITS(v4, j); \
+ int##TBITS##_t c = s390_vec_read_element##TBITS(v4, i); \
\
s390_vec_write_element##TBITS(v1, i, a * b + c); \
} \
@@ -390,7 +392,7 @@ void HELPER(gvec_vmalo##BITS)(void *v1, const void *v2, const void *v3, \
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##BITS(v4, j); \
+ uint##TBITS##_t c = s390_vec_read_element##TBITS(v4, i); \
\
s390_vec_write_element##TBITS(v1, i, a * b + c); \
} \
@@ -488,7 +490,7 @@ void HELPER(gvec_vmlo##BITS)(void *v1, const void *v2, const void *v3, \
{ \
int i, j; \
\
- for (i = 0, j = 0; i < (128 / TBITS); i++, j += 2) { \
+ 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); \
\
@@ -591,7 +593,7 @@ void HELPER(gvec_vscbi##BITS)(void *v1, const void *v2, const void *v3, \
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); \
+ s390_vec_write_element##BITS(v1, i, a >= b); \
} \
}
DEF_VSCBI(8)
diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c
index ee60a55..bc65929 100644
--- a/target/sparc/cpu.c
+++ b/target/sparc/cpu.c
@@ -877,7 +877,7 @@ static void sparc_cpu_class_init(ObjectClass *oc, void *data)
cc->gdb_write_register = sparc_cpu_gdb_write_register;
cc->tlb_fill = sparc_cpu_tlb_fill;
#ifndef CONFIG_USER_ONLY
- cc->do_unassigned_access = sparc_cpu_unassigned_access;
+ cc->do_transaction_failed = sparc_cpu_do_transaction_failed;
cc->do_unaligned_access = sparc_cpu_do_unaligned_access;
cc->get_phys_page_debug = sparc_cpu_get_phys_page_debug;
cc->vmsd = &vmstate_sparc_cpu;
diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h
index 490e14d..778aa8e 100644
--- a/target/sparc/cpu.h
+++ b/target/sparc/cpu.h
@@ -614,9 +614,11 @@ static inline int tlb_compare_context(const SparcTLBEntry *tlb,
/* cpu-exec.c */
#if !defined(CONFIG_USER_ONLY)
-void sparc_cpu_unassigned_access(CPUState *cpu, hwaddr addr,
- bool is_write, bool is_exec, int is_asi,
- unsigned size);
+void sparc_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
+ vaddr addr, unsigned size,
+ MMUAccessType access_type,
+ int mmu_idx, MemTxAttrs attrs,
+ MemTxResult response, uintptr_t retaddr);
#if defined(TARGET_SPARC64)
hwaddr cpu_get_phys_page_nofault(CPUSPARCState *env, target_ulong addr,
int mmu_idx);
diff --git a/target/sparc/ldst_helper.c b/target/sparc/ldst_helper.c
index 7f56c10..7345827 100644
--- a/target/sparc/ldst_helper.c
+++ b/target/sparc/ldst_helper.c
@@ -422,6 +422,99 @@ static void dump_asi(const char *txt, target_ulong addr, int asi, int size,
}
#endif
+#ifndef CONFIG_USER_ONLY
+#ifndef TARGET_SPARC64
+static void sparc_raise_mmu_fault(CPUState *cs, hwaddr addr,
+ bool is_write, bool is_exec, int is_asi,
+ unsigned size, uintptr_t retaddr)
+{
+ SPARCCPU *cpu = SPARC_CPU(cs);
+ CPUSPARCState *env = &cpu->env;
+ int fault_type;
+
+#ifdef DEBUG_UNASSIGNED
+ if (is_asi) {
+ printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx
+ " asi 0x%02x from " TARGET_FMT_lx "\n",
+ is_exec ? "exec" : is_write ? "write" : "read", size,
+ size == 1 ? "" : "s", addr, is_asi, env->pc);
+ } else {
+ printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx
+ " from " TARGET_FMT_lx "\n",
+ is_exec ? "exec" : is_write ? "write" : "read", size,
+ size == 1 ? "" : "s", addr, env->pc);
+ }
+#endif
+ /* Don't overwrite translation and access faults */
+ fault_type = (env->mmuregs[3] & 0x1c) >> 2;
+ if ((fault_type > 4) || (fault_type == 0)) {
+ env->mmuregs[3] = 0; /* Fault status register */
+ if (is_asi) {
+ env->mmuregs[3] |= 1 << 16;
+ }
+ if (env->psrs) {
+ env->mmuregs[3] |= 1 << 5;
+ }
+ if (is_exec) {
+ env->mmuregs[3] |= 1 << 6;
+ }
+ if (is_write) {
+ env->mmuregs[3] |= 1 << 7;
+ }
+ env->mmuregs[3] |= (5 << 2) | 2;
+ /* SuperSPARC will never place instruction fault addresses in the FAR */
+ if (!is_exec) {
+ env->mmuregs[4] = addr; /* Fault address register */
+ }
+ }
+ /* overflow (same type fault was not read before another fault) */
+ if (fault_type == ((env->mmuregs[3] & 0x1c)) >> 2) {
+ env->mmuregs[3] |= 1;
+ }
+
+ if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) {
+ int tt = is_exec ? TT_CODE_ACCESS : TT_DATA_ACCESS;
+ cpu_raise_exception_ra(env, tt, retaddr);
+ }
+
+ /*
+ * flush neverland mappings created during no-fault mode,
+ * so the sequential MMU faults report proper fault types
+ */
+ if (env->mmuregs[0] & MMU_NF) {
+ tlb_flush(cs);
+ }
+}
+#else
+static void sparc_raise_mmu_fault(CPUState *cs, hwaddr addr,
+ bool is_write, bool is_exec, int is_asi,
+ unsigned size, uintptr_t retaddr)
+{
+ SPARCCPU *cpu = SPARC_CPU(cs);
+ CPUSPARCState *env = &cpu->env;
+
+#ifdef DEBUG_UNASSIGNED
+ printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx
+ "\n", addr, env->pc);
+#endif
+
+ if (is_exec) { /* XXX has_hypervisor */
+ if (env->lsu & (IMMU_E)) {
+ cpu_raise_exception_ra(env, TT_CODE_ACCESS, retaddr);
+ } else if (cpu_has_hypervisor(env) && !(env->hpstate & HS_PRIV)) {
+ cpu_raise_exception_ra(env, TT_INSN_REAL_TRANSLATION_MISS, retaddr);
+ }
+ } else {
+ if (env->lsu & (DMMU_E)) {
+ cpu_raise_exception_ra(env, TT_DATA_ACCESS, retaddr);
+ } else if (cpu_has_hypervisor(env) && !(env->hpstate & HS_PRIV)) {
+ cpu_raise_exception_ra(env, TT_DATA_REAL_TRANSLATION_MISS, retaddr);
+ }
+ }
+}
+#endif
+#endif
+
#ifndef TARGET_SPARC64
#ifndef CONFIG_USER_ONLY
@@ -625,26 +718,36 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr,
case ASI_M_DATAC_DATA: /* SparcStation 5 D-cache data */
break;
case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */
+ {
+ MemTxResult result;
+ hwaddr access_addr = (hwaddr)addr | ((hwaddr)(asi & 0xf) << 32);
+
switch (size) {
case 1:
- ret = ldub_phys(cs->as, (hwaddr)addr
- | ((hwaddr)(asi & 0xf) << 32));
+ ret = address_space_ldub(cs->as, access_addr,
+ MEMTXATTRS_UNSPECIFIED, &result);
break;
case 2:
- ret = lduw_phys(cs->as, (hwaddr)addr
- | ((hwaddr)(asi & 0xf) << 32));
+ ret = address_space_lduw(cs->as, access_addr,
+ MEMTXATTRS_UNSPECIFIED, &result);
break;
default:
case 4:
- ret = ldl_phys(cs->as, (hwaddr)addr
- | ((hwaddr)(asi & 0xf) << 32));
+ ret = address_space_ldl(cs->as, access_addr,
+ MEMTXATTRS_UNSPECIFIED, &result);
break;
case 8:
- ret = ldq_phys(cs->as, (hwaddr)addr
- | ((hwaddr)(asi & 0xf) << 32));
+ ret = address_space_ldq(cs->as, access_addr,
+ MEMTXATTRS_UNSPECIFIED, &result);
break;
}
+
+ if (result != MEMTX_OK) {
+ sparc_raise_mmu_fault(cs, access_addr, false, false, false,
+ size, GETPC());
+ }
break;
+ }
case 0x30: /* Turbosparc secondary cache diagnostic */
case 0x31: /* Turbosparc RAM snoop */
case 0x32: /* Turbosparc page table descriptor diagnostic */
@@ -688,7 +791,7 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr,
break;
case ASI_USERTXT: /* User code access, XXX */
default:
- cpu_unassigned_access(cs, addr, false, false, asi, size);
+ sparc_raise_mmu_fault(cs, addr, false, false, asi, size, GETPC());
ret = 0;
break;
@@ -777,6 +880,9 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val,
}
break;
case 0x01c00100: /* MXCC stream source */
+ {
+ int i;
+
if (size == 8) {
env->mxccregs[0] = val;
} else {
@@ -784,20 +890,27 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val,
"%08x: unimplemented access size: %d\n", addr,
size);
}
- env->mxccdata[0] = ldq_phys(cs->as,
- (env->mxccregs[0] & 0xffffffffULL) +
- 0);
- env->mxccdata[1] = ldq_phys(cs->as,
- (env->mxccregs[0] & 0xffffffffULL) +
- 8);
- env->mxccdata[2] = ldq_phys(cs->as,
- (env->mxccregs[0] & 0xffffffffULL) +
- 16);
- env->mxccdata[3] = ldq_phys(cs->as,
- (env->mxccregs[0] & 0xffffffffULL) +
- 24);
+
+ for (i = 0; i < 4; i++) {
+ MemTxResult result;
+ hwaddr access_addr = (env->mxccregs[0] & 0xffffffffULL) + 8 * i;
+
+ env->mxccdata[i] = address_space_ldq(cs->as,
+ access_addr,
+ MEMTXATTRS_UNSPECIFIED,
+ &result);
+ if (result != MEMTX_OK) {
+ /* TODO: investigate whether this is the right behaviour */
+ sparc_raise_mmu_fault(cs, access_addr, false, false,
+ false, size, GETPC());
+ }
+ }
break;
+ }
case 0x01c00200: /* MXCC stream destination */
+ {
+ int i;
+
if (size == 8) {
env->mxccregs[1] = val;
} else {
@@ -805,15 +918,22 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val,
"%08x: unimplemented access size: %d\n", addr,
size);
}
- stq_phys(cs->as, (env->mxccregs[1] & 0xffffffffULL) + 0,
- env->mxccdata[0]);
- stq_phys(cs->as, (env->mxccregs[1] & 0xffffffffULL) + 8,
- env->mxccdata[1]);
- stq_phys(cs->as, (env->mxccregs[1] & 0xffffffffULL) + 16,
- env->mxccdata[2]);
- stq_phys(cs->as, (env->mxccregs[1] & 0xffffffffULL) + 24,
- env->mxccdata[3]);
+
+ for (i = 0; i < 4; i++) {
+ MemTxResult result;
+ hwaddr access_addr = (env->mxccregs[1] & 0xffffffffULL) + 8 * i;
+
+ address_space_stq(cs->as, access_addr, env->mxccdata[i],
+ MEMTXATTRS_UNSPECIFIED, &result);
+
+ if (result != MEMTX_OK) {
+ /* TODO: investigate whether this is the right behaviour */
+ sparc_raise_mmu_fault(cs, access_addr, true, false,
+ false, size, GETPC());
+ }
+ }
break;
+ }
case 0x01c00a00: /* MXCC control register */
if (size == 8) {
env->mxccregs[3] = val;
@@ -960,25 +1080,32 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val,
break;
case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */
{
+ MemTxResult result;
+ hwaddr access_addr = (hwaddr)addr | ((hwaddr)(asi & 0xf) << 32);
+
switch (size) {
case 1:
- stb_phys(cs->as, (hwaddr)addr
- | ((hwaddr)(asi & 0xf) << 32), val);
+ address_space_stb(cs->as, access_addr, val,
+ MEMTXATTRS_UNSPECIFIED, &result);
break;
case 2:
- stw_phys(cs->as, (hwaddr)addr
- | ((hwaddr)(asi & 0xf) << 32), val);
+ address_space_stw(cs->as, access_addr, val,
+ MEMTXATTRS_UNSPECIFIED, &result);
break;
case 4:
default:
- stl_phys(cs->as, (hwaddr)addr
- | ((hwaddr)(asi & 0xf) << 32), val);
+ address_space_stl(cs->as, access_addr, val,
+ MEMTXATTRS_UNSPECIFIED, &result);
break;
case 8:
- stq_phys(cs->as, (hwaddr)addr
- | ((hwaddr)(asi & 0xf) << 32), val);
+ address_space_stq(cs->as, access_addr, val,
+ MEMTXATTRS_UNSPECIFIED, &result);
break;
}
+ if (result != MEMTX_OK) {
+ sparc_raise_mmu_fault(cs, access_addr, true, false, false,
+ size, GETPC());
+ }
}
break;
case 0x30: /* store buffer tags or Turbosparc secondary cache diagnostic */
@@ -1026,7 +1153,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, uint64_t val,
case ASI_USERTXT: /* User code access, XXX */
case ASI_KERNELTXT: /* Supervisor code access, XXX */
default:
- cpu_unassigned_access(cs, addr, true, false, asi, size);
+ sparc_raise_mmu_fault(cs, addr, true, false, asi, size, GETPC());
break;
case ASI_USERDATA: /* User data access */
@@ -1292,7 +1419,7 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr,
ret = env->immu.tag_access;
break;
default:
- cpu_unassigned_access(cs, addr, false, false, 1, size);
+ sparc_raise_mmu_fault(cs, addr, false, false, 1, size, GETPC());
ret = 0;
}
break;
@@ -1358,7 +1485,7 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr,
ret = env->dmmu.physical_watchpoint;
break;
default:
- cpu_unassigned_access(cs, addr, false, false, 1, size);
+ sparc_raise_mmu_fault(cs, addr, false, false, 1, size, GETPC());
ret = 0;
}
break;
@@ -1407,7 +1534,7 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr,
case ASI_SCRATCHPAD: /* UA2005 privileged scratchpad */
if (unlikely((addr >= 0x20) && (addr < 0x30))) {
/* Hyperprivileged access only */
- cpu_unassigned_access(cs, addr, false, false, 1, size);
+ sparc_raise_mmu_fault(cs, addr, false, false, 1, size, GETPC());
}
/* fall through */
case ASI_HYP_SCRATCHPAD: /* UA2005 hyperprivileged scratchpad */
@@ -1425,7 +1552,7 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr,
ret = env->dmmu.mmu_secondary_context;
break;
default:
- cpu_unassigned_access(cs, addr, true, false, 1, size);
+ sparc_raise_mmu_fault(cs, addr, true, false, 1, size, GETPC());
}
break;
case ASI_DCACHE_DATA: /* D-cache data */
@@ -1448,7 +1575,7 @@ uint64_t helper_ld_asi(CPUSPARCState *env, target_ulong addr,
case ASI_DMMU_DEMAP: /* D-MMU demap, WO */
case ASI_INTR_W: /* Interrupt vector, WO */
default:
- cpu_unassigned_access(cs, addr, false, false, 1, size);
+ sparc_raise_mmu_fault(cs, addr, false, false, 1, size, GETPC());
ret = 0;
break;
}
@@ -1622,7 +1749,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
case 8:
return;
default:
- cpu_unassigned_access(cs, addr, true, false, 1, size);
+ sparc_raise_mmu_fault(cs, addr, true, false, 1, size, GETPC());
break;
}
@@ -1706,7 +1833,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
env->dmmu.physical_watchpoint = val;
break;
default:
- cpu_unassigned_access(cs, addr, true, false, 1, size);
+ sparc_raise_mmu_fault(cs, addr, true, false, 1, size, GETPC());
break;
}
@@ -1750,7 +1877,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
case ASI_SCRATCHPAD: /* UA2005 privileged scratchpad */
if (unlikely((addr >= 0x20) && (addr < 0x30))) {
/* Hyperprivileged access only */
- cpu_unassigned_access(cs, addr, true, false, 1, size);
+ sparc_raise_mmu_fault(cs, addr, true, false, 1, size, GETPC());
}
/* fall through */
case ASI_HYP_SCRATCHPAD: /* UA2005 hyperprivileged scratchpad */
@@ -1776,7 +1903,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
(1 << MMU_KERNEL_SECONDARY_IDX));
break;
default:
- cpu_unassigned_access(cs, addr, true, false, 1, size);
+ sparc_raise_mmu_fault(cs, addr, true, false, 1, size, GETPC());
}
}
return;
@@ -1808,7 +1935,7 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
case ASI_PNFL: /* Primary no-fault LE, RO */
case ASI_SNFL: /* Secondary no-fault LE, RO */
default:
- cpu_unassigned_access(cs, addr, true, false, 1, size);
+ sparc_raise_mmu_fault(cs, addr, true, false, 1, size, GETPC());
return;
}
}
@@ -1816,95 +1943,21 @@ void helper_st_asi(CPUSPARCState *env, target_ulong addr, target_ulong val,
#endif /* TARGET_SPARC64 */
#if !defined(CONFIG_USER_ONLY)
-#ifndef TARGET_SPARC64
-void sparc_cpu_unassigned_access(CPUState *cs, hwaddr addr,
- bool is_write, bool is_exec, int is_asi,
- unsigned size)
-{
- SPARCCPU *cpu = SPARC_CPU(cs);
- CPUSPARCState *env = &cpu->env;
- int fault_type;
-#ifdef DEBUG_UNASSIGNED
- if (is_asi) {
- printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx
- " asi 0x%02x from " TARGET_FMT_lx "\n",
- is_exec ? "exec" : is_write ? "write" : "read", size,
- size == 1 ? "" : "s", addr, is_asi, env->pc);
- } else {
- printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx
- " from " TARGET_FMT_lx "\n",
- is_exec ? "exec" : is_write ? "write" : "read", size,
- size == 1 ? "" : "s", addr, env->pc);
- }
-#endif
- /* Don't overwrite translation and access faults */
- fault_type = (env->mmuregs[3] & 0x1c) >> 2;
- if ((fault_type > 4) || (fault_type == 0)) {
- env->mmuregs[3] = 0; /* Fault status register */
- if (is_asi) {
- env->mmuregs[3] |= 1 << 16;
- }
- if (env->psrs) {
- env->mmuregs[3] |= 1 << 5;
- }
- if (is_exec) {
- env->mmuregs[3] |= 1 << 6;
- }
- if (is_write) {
- env->mmuregs[3] |= 1 << 7;
- }
- env->mmuregs[3] |= (5 << 2) | 2;
- /* SuperSPARC will never place instruction fault addresses in the FAR */
- if (!is_exec) {
- env->mmuregs[4] = addr; /* Fault address register */
- }
- }
- /* overflow (same type fault was not read before another fault) */
- if (fault_type == ((env->mmuregs[3] & 0x1c)) >> 2) {
- env->mmuregs[3] |= 1;
- }
-
- if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) {
- int tt = is_exec ? TT_CODE_ACCESS : TT_DATA_ACCESS;
- cpu_raise_exception_ra(env, tt, GETPC());
- }
-
- /* flush neverland mappings created during no-fault mode,
- so the sequential MMU faults report proper fault types */
- if (env->mmuregs[0] & MMU_NF) {
- tlb_flush(cs);
- }
-}
-#else
-void sparc_cpu_unassigned_access(CPUState *cs, hwaddr addr,
- bool is_write, bool is_exec, int is_asi,
- unsigned size)
+void sparc_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
+ vaddr addr, unsigned size,
+ MMUAccessType access_type,
+ int mmu_idx, MemTxAttrs attrs,
+ MemTxResult response, uintptr_t retaddr)
{
- SPARCCPU *cpu = SPARC_CPU(cs);
- CPUSPARCState *env = &cpu->env;
-
-#ifdef DEBUG_UNASSIGNED
- printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx
- "\n", addr, env->pc);
-#endif
+ bool is_write = access_type == MMU_DATA_STORE;
+ bool is_exec = access_type == MMU_INST_FETCH;
+ bool is_asi = false;
- if (is_exec) { /* XXX has_hypervisor */
- if (env->lsu & (IMMU_E)) {
- cpu_raise_exception_ra(env, TT_CODE_ACCESS, GETPC());
- } else if (cpu_has_hypervisor(env) && !(env->hpstate & HS_PRIV)) {
- cpu_raise_exception_ra(env, TT_INSN_REAL_TRANSLATION_MISS, GETPC());
- }
- } else {
- if (env->lsu & (DMMU_E)) {
- cpu_raise_exception_ra(env, TT_DATA_ACCESS, GETPC());
- } else if (cpu_has_hypervisor(env) && !(env->hpstate & HS_PRIV)) {
- cpu_raise_exception_ra(env, TT_DATA_REAL_TRANSLATION_MISS, GETPC());
- }
- }
+ sparc_raise_mmu_fault(cs, physaddr, is_write, is_exec,
+ is_asi, size, retaddr);
}
#endif
-#endif
#if !defined(CONFIG_USER_ONLY)
void QEMU_NORETURN sparc_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
diff --git a/target/sparc/mmu_helper.c b/target/sparc/mmu_helper.c
index 77dc86a..afbfba7 100644
--- a/target/sparc/mmu_helper.c
+++ b/target/sparc/mmu_helper.c
@@ -98,6 +98,7 @@ static int get_physical_address(CPUSPARCState *env, hwaddr *physical,
int error_code = 0, is_dirty, is_user;
unsigned long page_offset;
CPUState *cs = env_cpu(env);
+ MemTxResult result;
is_user = mmu_idx == MMU_USER_IDX;
@@ -120,7 +121,10 @@ static int get_physical_address(CPUSPARCState *env, hwaddr *physical,
/* SPARC reference MMU table walk: Context table->L1->L2->PTE */
/* Context base + context number */
pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
- pde = ldl_phys(cs->as, pde_ptr);
+ pde = address_space_ldl(cs->as, pde_ptr, MEMTXATTRS_UNSPECIFIED, &result);
+ if (result != MEMTX_OK) {
+ return 4 << 2; /* Translation fault, L = 0 */
+ }
/* Ctx pde */
switch (pde & PTE_ENTRYTYPE_MASK) {
@@ -132,7 +136,11 @@ static int get_physical_address(CPUSPARCState *env, hwaddr *physical,
return 4 << 2;
case 1: /* L0 PDE */
pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
- pde = ldl_phys(cs->as, pde_ptr);
+ pde = address_space_ldl(cs->as, pde_ptr,
+ MEMTXATTRS_UNSPECIFIED, &result);
+ if (result != MEMTX_OK) {
+ return (1 << 8) | (4 << 2); /* Translation fault, L = 1 */
+ }
switch (pde & PTE_ENTRYTYPE_MASK) {
default:
@@ -142,7 +150,11 @@ static int get_physical_address(CPUSPARCState *env, hwaddr *physical,
return (1 << 8) | (4 << 2);
case 1: /* L1 PDE */
pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
- pde = ldl_phys(cs->as, pde_ptr);
+ pde = address_space_ldl(cs->as, pde_ptr,
+ MEMTXATTRS_UNSPECIFIED, &result);
+ if (result != MEMTX_OK) {
+ return (2 << 8) | (4 << 2); /* Translation fault, L = 2 */
+ }
switch (pde & PTE_ENTRYTYPE_MASK) {
default:
@@ -152,7 +164,11 @@ static int get_physical_address(CPUSPARCState *env, hwaddr *physical,
return (2 << 8) | (4 << 2);
case 1: /* L2 PDE */
pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
- pde = ldl_phys(cs->as, pde_ptr);
+ pde = address_space_ldl(cs->as, pde_ptr,
+ MEMTXATTRS_UNSPECIFIED, &result);
+ if (result != MEMTX_OK) {
+ return (3 << 8) | (4 << 2); /* Translation fault, L = 3 */
+ }
switch (pde & PTE_ENTRYTYPE_MASK) {
default:
@@ -272,11 +288,20 @@ target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev)
CPUState *cs = env_cpu(env);
hwaddr pde_ptr;
uint32_t pde;
+ MemTxResult result;
+
+ /*
+ * TODO: MMU probe operations are supposed to set the fault
+ * status registers, but we don't do this.
+ */
/* Context base + context number */
pde_ptr = (hwaddr)(env->mmuregs[1] << 4) +
(env->mmuregs[2] << 2);
- pde = ldl_phys(cs->as, pde_ptr);
+ pde = address_space_ldl(cs->as, pde_ptr, MEMTXATTRS_UNSPECIFIED, &result);
+ if (result != MEMTX_OK) {
+ return 0;
+ }
switch (pde & PTE_ENTRYTYPE_MASK) {
default:
@@ -289,7 +314,11 @@ target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev)
return pde;
}
pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
- pde = ldl_phys(cs->as, pde_ptr);
+ pde = address_space_ldl(cs->as, pde_ptr,
+ MEMTXATTRS_UNSPECIFIED, &result);
+ if (result != MEMTX_OK) {
+ return 0;
+ }
switch (pde & PTE_ENTRYTYPE_MASK) {
default:
@@ -303,7 +332,11 @@ target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev)
return pde;
}
pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
- pde = ldl_phys(cs->as, pde_ptr);
+ pde = address_space_ldl(cs->as, pde_ptr,
+ MEMTXATTRS_UNSPECIFIED, &result);
+ if (result != MEMTX_OK) {
+ return 0;
+ }
switch (pde & PTE_ENTRYTYPE_MASK) {
default:
@@ -317,7 +350,11 @@ target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev)
return pde;
}
pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
- pde = ldl_phys(cs->as, pde_ptr);
+ pde = address_space_ldl(cs->as, pde_ptr,
+ MEMTXATTRS_UNSPECIFIED, &result);
+ if (result != MEMTX_OK) {
+ return 0;
+ }
switch (pde & PTE_ENTRYTYPE_MASK) {
default:
@@ -339,11 +376,9 @@ void dump_mmu(CPUSPARCState *env)
CPUState *cs = env_cpu(env);
target_ulong va, va1, va2;
unsigned int n, m, o;
- hwaddr pde_ptr, pa;
+ hwaddr pa;
uint32_t pde;
- pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
- pde = ldl_phys(cs->as, pde_ptr);
qemu_printf("Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
(hwaddr)env->mmuregs[1] << 4, env->mmuregs[2]);
for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {