mirror of https://github.com/xemu-project/xemu.git
linux-user/arm: Fix identification of syscall numbers
Our code to identify syscall numbers has some issues: * for Thumb mode, we never need the immediate value from the insn, but we always read it anyway * bad immediate values in the svc insn should cause a SIGILL, but we were abort()ing instead (via "goto error") We can fix both these things by refactoring the code that identifies the syscall number to more closely follow the kernel COMPAT_OABI code: * for Thumb it is always r7 * for Arm, if the immediate value is 0, then this is an EABI call with the syscall number in r7 * otherwise, we XOR the immediate value with 0x900000 (ARM_SYSCALL_BASE for QEMU; __NR_OABI_SYSCALL_BASE in the kernel), which converts valid syscall immediates into the desired value, and puts all invalid immediates in the range 0x100000 or above * then we can just let the existing "value too large, deliver SIGILL" case handle invalid numbers, and drop the 'goto error' Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com> Message-id: 20200420212206.12776-5-peter.maydell@linaro.org
This commit is contained in:
parent
ab546bd238
commit
3986a1721e
|
@ -299,23 +299,33 @@ void cpu_loop(CPUARMState *env)
|
|||
env->eabi = 1;
|
||||
/* system call */
|
||||
if (env->thumb) {
|
||||
/* FIXME - what to do if get_user() fails? */
|
||||
get_user_code_u16(insn, env->regs[15] - 2, env);
|
||||
n = insn & 0xff;
|
||||
/* Thumb is always EABI style with syscall number in r7 */
|
||||
n = env->regs[7];
|
||||
} else {
|
||||
/*
|
||||
* Equivalent of kernel CONFIG_OABI_COMPAT: read the
|
||||
* Arm SVC insn to extract the immediate, which is the
|
||||
* syscall number in OABI.
|
||||
*/
|
||||
/* FIXME - what to do if get_user() fails? */
|
||||
get_user_code_u32(insn, env->regs[15] - 4, env);
|
||||
n = insn & 0xffffff;
|
||||
}
|
||||
|
||||
if (n == 0 || n >= ARM_SYSCALL_BASE || env->thumb) {
|
||||
/* linux syscall */
|
||||
if (env->thumb || n == 0) {
|
||||
if (n == 0) {
|
||||
/* zero immediate: EABI, syscall number in r7 */
|
||||
n = env->regs[7];
|
||||
} else {
|
||||
n -= ARM_SYSCALL_BASE;
|
||||
/*
|
||||
* This XOR matches the kernel code: an immediate
|
||||
* in the valid range (0x900000 .. 0x9fffff) is
|
||||
* converted into the correct EABI-style syscall
|
||||
* number; invalid immediates end up as values
|
||||
* > 0xfffff and are handled below as out-of-range.
|
||||
*/
|
||||
n ^= ARM_SYSCALL_BASE;
|
||||
env->eabi = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (n > ARM_NR_BASE) {
|
||||
switch (n) {
|
||||
case ARM_NR_cacheflush:
|
||||
|
@ -345,7 +355,11 @@ void cpu_loop(CPUARMState *env)
|
|||
n);
|
||||
env->regs[0] = -TARGET_ENOSYS;
|
||||
} else {
|
||||
/* Otherwise SIGILL */
|
||||
/*
|
||||
* Otherwise SIGILL. This includes any SWI with
|
||||
* immediate not originally 0x9fxxxx, because
|
||||
* of the earlier XOR.
|
||||
*/
|
||||
info.si_signo = TARGET_SIGILL;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_ILL_ILLTRP;
|
||||
|
@ -376,9 +390,6 @@ void cpu_loop(CPUARMState *env)
|
|||
env->regs[0] = ret;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EXCP_SEMIHOST:
|
||||
|
|
Loading…
Reference in New Issue