aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Filippov <jcmvbkbc@gmail.com>2014-11-07 21:11:07 +0300
committerMichael Roth <mdroth@linux.vnet.ibm.com>2015-01-07 14:31:19 -0600
commitea227e222bacb16539128b6b201614847374453c (patch)
tree4c033a99936053f6319704e61028edd67aaed712
parentaae114b7edd25c2c15bd126ffc6dbe4696f74f7f (diff)
target-xtensa: add missing window check for entry
Entry opcode needs to check if moving to new register frame would cause register window overflow. Entry used in function prologue never overflows because preceding windowed call* opcode writes return address to the target register window frame, causing overflow exceptions at the point of call. But when a sequence of entry opcodes is used for register window spilling there may not be a call or other opcode that would cause window check between entries and they would not raise overflow exception themselves resulting in data corruption. Cc: qemu-stable@nongnu.org Signed-off-by: Max Filippov <jcmvbkbc@gmail.com> (cherry picked from commit 1b3e71f8ee17ced609213d9b41758110f3c026e9) Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
-rw-r--r--target-xtensa/cpu.h6
-rw-r--r--target-xtensa/op_helper.c6
2 files changed, 12 insertions, 0 deletions
diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index d797d2649a..6e4e2b2ed9 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -471,6 +471,12 @@ static inline xtensa_tlb_entry *xtensa_tlb_get_entry(CPUXtensaState *env,
env->itlb[wi] + ei;
}
+static inline uint32_t xtensa_replicate_windowstart(CPUXtensaState *env)
+{
+ return env->sregs[WINDOW_START] |
+ (env->sregs[WINDOW_START] << env->config->nareg / 4);
+}
+
/* MMU modes definitions */
#define MMU_MODE0_SUFFIX _ring0
#define MMU_MODE1_SUFFIX _ring1
diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
index dae13866ef..872e5a823b 100644
--- a/target-xtensa/op_helper.c
+++ b/target-xtensa/op_helper.c
@@ -235,6 +235,12 @@ void HELPER(entry)(CPUXtensaState *env, uint32_t pc, uint32_t s, uint32_t imm)
pc, env->sregs[PS]);
HELPER(exception_cause)(env, pc, ILLEGAL_INSTRUCTION_CAUSE);
} else {
+ uint32_t windowstart = xtensa_replicate_windowstart(env) >>
+ (env->sregs[WINDOW_BASE] + 1);
+
+ if (windowstart & ((1 << callinc) - 1)) {
+ HELPER(window_check)(env, pc, callinc);
+ }
env->regs[(callinc << 2) | (s & 3)] = env->regs[s] - (imm << 3);
rotate_window(env, callinc);
env->sregs[WINDOW_START] |=