]> Git Repo - qemu.git/blobdiff - target-ppc/mem_helper.c
taget-ppc: Fix read access to IBAT registers higher than IBAT3
[qemu.git] / target-ppc / mem_helper.c
index 5b5f1bdd23d43bd318d282f0b874fd25c1c6c4f1..6d37dae7b0fb594a199a753766cb929c21a259c2 100644 (file)
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 #include "cpu.h"
-#include "host-utils.h"
-#include "helper.h"
+#include "qemu/host-utils.h"
+#include "exec/helper-proto.h"
 
 #include "helper_regs.h"
-
-#if !defined(CONFIG_USER_ONLY)
-#include "softmmu_exec.h"
-#endif /* !defined(CONFIG_USER_ONLY) */
+#include "exec/cpu_ldst.h"
 
 //#define DEBUG_OP
 
+static inline bool needs_byteswap(const CPUPPCState *env)
+{
+#if defined(TARGET_WORDS_BIGENDIAN)
+  return msr_le;
+#else
+  return !msr_le;
+#endif
+}
+
 /*****************************************************************************/
 /* Memory load and stores */
 
@@ -47,7 +53,7 @@ static inline target_ulong addr_add(CPUPPCState *env, target_ulong addr,
 void helper_lmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
 {
     for (; reg < 32; reg++) {
-        if (msr_le) {
+        if (needs_byteswap(env)) {
             env->gpr[reg] = bswap32(cpu_ldl_data(env, addr));
         } else {
             env->gpr[reg] = cpu_ldl_data(env, addr);
@@ -59,7 +65,7 @@ void helper_lmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
 void helper_stmw(CPUPPCState *env, target_ulong addr, uint32_t reg)
 {
     for (; reg < 32; reg++) {
-        if (msr_le) {
+        if (needs_byteswap(env)) {
             cpu_stl_data(env, addr, bswap32((uint32_t)env->gpr[reg]));
         } else {
             cpu_stl_data(env, addr, (uint32_t)env->gpr[reg]);
@@ -136,18 +142,21 @@ static void do_dcbz(CPUPPCState *env, target_ulong addr, int dcache_line_size)
     }
 }
 
-void helper_dcbz(CPUPPCState *env, target_ulong addr)
+void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t is_dcbzl)
 {
-    do_dcbz(env, addr, env->dcache_line_size);
-}
+    int dcbz_size = env->dcache_line_size;
 
-void helper_dcbz_970(CPUPPCState *env, target_ulong addr)
-{
-    if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) {
-        do_dcbz(env, addr, 32);
-    } else {
-        do_dcbz(env, addr, env->dcache_line_size);
+#if defined(TARGET_PPC64)
+    if (!is_dcbzl &&
+        (env->excp_model == POWERPC_EXCP_970) &&
+        ((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) {
+        dcbz_size = 32;
     }
+#endif
+
+    /* XXX add e500mc support */
+
+    do_dcbz(env, addr, dcbz_size);
 }
 
 void helper_icbi(CPUPPCState *env, target_ulong addr)
@@ -199,6 +208,11 @@ target_ulong helper_lscbx(CPUPPCState *env, target_ulong addr, uint32_t reg,
 #define LO_IDX 0
 #endif
 
+/* We use msr_le to determine index ordering in a vector.  However,
+   byteswapping is not simply controlled by msr_le.  We also need to take
+   into account endianness of the target.  This is done for the little-endian
+   PPC64 user-mode target. */
+
 #define LVE(name, access, swap, element)                        \
     void helper_##name(CPUPPCState *env, ppc_avr_t *r,          \
                        target_ulong addr)                       \
@@ -207,8 +221,11 @@ target_ulong helper_lscbx(CPUPPCState *env, target_ulong addr, uint32_t reg,
         int adjust = HI_IDX*(n_elems - 1);                      \
         int sh = sizeof(r->element[0]) >> 1;                    \
         int index = (addr & 0xf) >> sh;                         \
-                                                                \
         if (msr_le) {                                           \
+            index = n_elems - index - 1;                        \
+        }                                                       \
+                                                                \
+        if (needs_byteswap(env)) {                              \
             r->element[LO_IDX ? index : (adjust - index)] =     \
                 swap(access(env, addr));                        \
         } else {                                                \
@@ -231,8 +248,11 @@ LVE(lvewx, cpu_ldl_data, bswap32, u32)
         int adjust = HI_IDX * (n_elems - 1);                            \
         int sh = sizeof(r->element[0]) >> 1;                            \
         int index = (addr & 0xf) >> sh;                                 \
-                                                                        \
         if (msr_le) {                                                   \
+            index = n_elems - index - 1;                                \
+        }                                                               \
+                                                                        \
+        if (needs_byteswap(env)) {                                      \
             access(env, addr, swap(r->element[LO_IDX ? index :          \
                                               (adjust - index)]));      \
         } else {                                                        \
@@ -250,46 +270,24 @@ STVE(stvewx, cpu_stl_data, bswap32, u32)
 #undef HI_IDX
 #undef LO_IDX
 
-/*****************************************************************************/
-/* Softmmu support */
-#if !defined(CONFIG_USER_ONLY)
-
-#define MMUSUFFIX _mmu
-
-#define SHIFT 0
-#include "softmmu_template.h"
-
-#define SHIFT 1
-#include "softmmu_template.h"
-
-#define SHIFT 2
-#include "softmmu_template.h"
-
-#define SHIFT 3
-#include "softmmu_template.h"
-
-/* try to fill the TLB and return an exception if error. If retaddr is
-   NULL, it means that the function was called in C code (i.e. not
-   from generated code or from helper.c) */
-/* XXX: fix it to restore all registers */
-void tlb_fill(CPUPPCState *env, target_ulong addr, int is_write, int mmu_idx,
-              uintptr_t retaddr)
+void helper_tbegin(CPUPPCState *env)
 {
-    TranslationBlock *tb;
-    int ret;
+    /* As a degenerate implementation, always fail tbegin.  The reason
+     * given is "Nesting overflow".  The "persistent" bit is set,
+     * providing a hint to the error handler to not retry.  The TFIAR
+     * captures the address of the failure, which is this tbegin
+     * instruction.  Instruction execution will continue with the
+     * next instruction in memory, which is precisely what we want.
+     */
 
-    ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
-    if (unlikely(ret != 0)) {
-        if (likely(retaddr)) {
-            /* now we have a real cpu fault */
-            tb = tb_find_pc(retaddr);
-            if (likely(tb)) {
-                /* the PC is inside the translated code. It means that we have
-                   a virtual CPU fault */
-                cpu_restore_state(tb, env, retaddr);
-            }
-        }
-        helper_raise_exception_err(env, env->exception_index, env->error_code);
-    }
+    env->spr[SPR_TEXASR] =
+        (1ULL << TEXASR_FAILURE_PERSISTENT) |
+        (1ULL << TEXASR_NESTING_OVERFLOW) |
+        (msr_hv << TEXASR_PRIVILEGE_HV) |
+        (msr_pr << TEXASR_PRIVILEGE_PR) |
+        (1ULL << TEXASR_FAILURE_SUMMARY) |
+        (1ULL << TEXASR_TFIAR_EXACT);
+    env->spr[SPR_TFIAR] = env->nip | (msr_hv << 1) | msr_pr;
+    env->spr[SPR_TFHAR] = env->nip + 4;
+    env->crf[0] = 0xB; /* 0b1010 = transaction failure */
 }
-#endif /* !CONFIG_USER_ONLY */
This page took 0.02882 seconds and 4 git commands to generate.