aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--linux-user/elfload.c2
-rw-r--r--linux-user/syscall.c54
-rw-r--r--linux-user/syscall_defs.h5
-rw-r--r--target-xtensa/cpu.h6
-rw-r--r--target-xtensa/op_helper.c6
-rw-r--r--tests/tcg/xtensa/test_windowed.S51
6 files changed, 102 insertions, 22 deletions
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 84123baa58..e2596a4201 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1824,7 +1824,7 @@ static void load_elf_image(const char *image_name, int image_fd,
if (a < loaddr) {
loaddr = a;
}
- a += phdr[i].p_memsz;
+ a = phdr[i].p_vaddr + phdr[i].p_memsz;
if (a > hiaddr) {
hiaddr = a;
}
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index a175cc15f8..aaac6a25ce 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5473,6 +5473,27 @@ static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags,
return get_errno(sys_openat(dirfd, path(pathname), flags, mode));
}
+#define TIMER_MAGIC 0x0caf0000
+#define TIMER_MAGIC_MASK 0xffff0000
+
+/* Convert QEMU provided timer ID back to internal 16bit index format */
+static target_timer_t get_timer_id(abi_long arg)
+{
+ target_timer_t timerid = arg;
+
+ if ((timerid & TIMER_MAGIC_MASK) != TIMER_MAGIC) {
+ return -TARGET_EINVAL;
+ }
+
+ timerid &= 0xffff;
+
+ if (timerid >= ARRAY_SIZE(g_posix_timers)) {
+ return -TARGET_EINVAL;
+ }
+
+ return timerid;
+}
+
/* do_syscall() should always have a single exit point at the end so
that actions, such as logging of syscall results, can be performed.
All errnos that do_syscall() returns must be -TARGET_<errcode>. */
@@ -9579,7 +9600,6 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
/* args: clockid_t clockid, struct sigevent *sevp, timer_t *timerid */
struct sigevent host_sevp = { {0}, }, *phost_sevp = NULL;
- struct target_timer_t *ptarget_timer;
int clkid = arg1;
int timer_index = next_free_host_timer();
@@ -9601,11 +9621,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
if (ret) {
phtimer = NULL;
} else {
- if (!lock_user_struct(VERIFY_WRITE, ptarget_timer, arg3, 1)) {
+ if (put_user(TIMER_MAGIC | timer_index, arg3, target_timer_t)) {
goto efault;
}
- ptarget_timer->ptr = tswap32(0xcafe0000 | timer_index);
- unlock_user_struct(ptarget_timer, arg3, 1);
}
}
break;
@@ -9617,9 +9635,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
{
/* args: timer_t timerid, int flags, const struct itimerspec *new_value,
* struct itimerspec * old_value */
- target_ulong timerid = arg1;
+ target_timer_t timerid = get_timer_id(arg1);
- if (arg3 == 0 || timerid >= ARRAY_SIZE(g_posix_timers)) {
+ if (timerid < 0) {
+ ret = timerid;
+ } else if (arg3 == 0) {
ret = -TARGET_EINVAL;
} else {
timer_t htimer = g_posix_timers[timerid];
@@ -9638,12 +9658,12 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
case TARGET_NR_timer_gettime:
{
/* args: timer_t timerid, struct itimerspec *curr_value */
- target_ulong timerid = arg1;
+ target_timer_t timerid = get_timer_id(arg1);
- if (!arg2) {
- return -TARGET_EFAULT;
- } else if (timerid >= ARRAY_SIZE(g_posix_timers)) {
- ret = -TARGET_EINVAL;
+ if (timerid < 0) {
+ ret = timerid;
+ } else if (!arg2) {
+ ret = -TARGET_EFAULT;
} else {
timer_t htimer = g_posix_timers[timerid];
struct itimerspec hspec;
@@ -9661,10 +9681,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
case TARGET_NR_timer_getoverrun:
{
/* args: timer_t timerid */
- target_ulong timerid = arg1;
+ target_timer_t timerid = get_timer_id(arg1);
- if (timerid >= ARRAY_SIZE(g_posix_timers)) {
- ret = -TARGET_EINVAL;
+ if (timerid < 0) {
+ ret = timerid;
} else {
timer_t htimer = g_posix_timers[timerid];
ret = get_errno(timer_getoverrun(htimer));
@@ -9677,10 +9697,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
case TARGET_NR_timer_delete:
{
/* args: timer_t timerid */
- target_ulong timerid = arg1;
+ target_timer_t timerid = get_timer_id(arg1);
- if (timerid >= ARRAY_SIZE(g_posix_timers)) {
- ret = -TARGET_EINVAL;
+ if (timerid < 0) {
+ ret = timerid;
} else {
timer_t htimer = g_posix_timers[timerid];
ret = get_errno(timer_delete(htimer));
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index c9e6323905..ebb3be1196 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -2564,10 +2564,7 @@ struct target_ucred {
#endif
-
-struct target_timer_t {
- abi_ulong ptr;
-};
+typedef int32_t target_timer_t;
#define TARGET_SIGEV_MAX_SIZE 64
diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index beb5486fc7..ac463f27fe 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -472,6 +472,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] |=
diff --git a/tests/tcg/xtensa/test_windowed.S b/tests/tcg/xtensa/test_windowed.S
index 3de6d3763a..d851e8f43c 100644
--- a/tests/tcg/xtensa/test_windowed.S
+++ b/tests/tcg/xtensa/test_windowed.S
@@ -299,4 +299,55 @@ test entry
entry_test 12
test_end
+.macro entry_overflow_test window, free, next_window
+ set_vector window_overflow_4, 0
+ set_vector window_overflow_8, 0
+ set_vector window_overflow_12, 0
+ set_vector window_overflow_\next_window, 10f
+
+ movi a2, \window
+ movi a2, \free
+ movi a2, \next_window
+ reset_window %(1 | ((1 | (1 << ((\next_window) / 4))) << ((\free) / 4)))
+ reset_ps
+ movi a2, 0x4000f | ((\window) << 14)
+ wsr a2, ps
+ isync
+ movi a3, 0x12345678
+ j 1f
+ .align 4
+1:
+ entry a3, 0x5678
+ test_fail
+ .align 4
+10:
+ rsr a2, epc1
+ movi a3, 1b
+ assert eq, a2, a3
+ movi a2, 2f
+ wsr a2, epc1
+
+ rsr a2, windowbase
+ movi a3, (\free) / 4
+ assert eq, a2, a3
+ rfwo
+2:
+.endm
+
+.macro all_entry_overflow_tests
+ .irp window, 4, 8, 12
+ .irp next_window, 4, 8, 12
+ .irp free, 4, 8, 12
+ .if \free <= \window
+ entry_overflow_test \window, \free, \next_window
+ .endif
+ .endr
+ .endr
+ .endr
+.endm
+
+test entry_overflow
+ all_entry_overflow_tests
+test_end
+
test_suite_end