![Vineet Gupta](/assets/img/avatar_default.png)
Reported by Anton as LTP:munmap01 failing with Illegal Instruction Exception. --------------------->8-------------------------------------- mmap2(NULL, 24576, PROT_READ|PROT_WRITE, MAP_SHARED, 3, 0) = 0x200d2000 munmap(0x200d2000, 24576) = 0 --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x200d2000} --- potentially unexpected fatal signal 4. Path: /munmap01 CPU: 0 PID: 61 Comm: munmap01 Not tainted 3.13.0-g5d5c46d9a556 #8 task: 9f1a8000 ti: 9f154000 task.ti: 9f154000 [ECR ]: 0x00020100 => Illegal Insn [EFA ]: 0x0001354c [BLINK ]: 0x200515d4 [ERET ]: 0x1354c @off 0x1354c in [/munmap01] VMA: 0x00010000 to 0x00018000 [STAT32]: 0x800802c0 ... --------------------->8-------------------------------------- The issue was 1. munmap01 accessed unmapped memory (on purpose) with signal handler installed for SIGSEGV 2. The faulting instruction happened to be in Delay Slot 00011864 <main>: 11908: bl.d 13284 <tst_resm> 1190c: stb r16,[r2] 3. kernel sets up the reg file for signal handler and correctly clears the DE bit in pt_regs->status32 placeholder 4. However RESTORE_CALLEE_SAVED_USER macro is not adjusted for ARCv2, and it over-writes the above with orig/stale value of status32 5. After RTIE, userspace signal handler executes a non branch instruction with DE bit set, triggering Illegal Instruction Exception. Reported-by: Anton Kolesov <akolesov@synopsys.com> Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
305 lines
6.7 KiB
C
305 lines
6.7 KiB
C
/*
|
|
* Copyright (C) 2014-15 Synopsys, Inc. (www.synopsys.com)
|
|
* Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
|
|
#ifndef __ASM_ARC_ENTRY_H
|
|
#define __ASM_ARC_ENTRY_H
|
|
|
|
#include <asm/unistd.h> /* For NR_syscalls defination */
|
|
#include <asm/arcregs.h>
|
|
#include <asm/ptrace.h>
|
|
#include <asm/processor.h> /* For VMALLOC_START */
|
|
#include <asm/mmu.h>
|
|
|
|
#ifdef CONFIG_ISA_ARCOMPACT
|
|
#include <asm/entry-compact.h> /* ISA specific bits */
|
|
#else
|
|
#include <asm/entry-arcv2.h>
|
|
#endif
|
|
|
|
/* Note on the LD/ST addr modes with addr reg wback
|
|
*
|
|
* LD.a same as LD.aw
|
|
*
|
|
* LD.a reg1, [reg2, x] => Pre Incr
|
|
* Eff Addr for load = [reg2 + x]
|
|
*
|
|
* LD.ab reg1, [reg2, x] => Post Incr
|
|
* Eff Addr for load = [reg2]
|
|
*/
|
|
|
|
.macro PUSH reg
|
|
st.a \reg, [sp, -4]
|
|
.endm
|
|
|
|
.macro PUSHAX aux
|
|
lr r9, [\aux]
|
|
PUSH r9
|
|
.endm
|
|
|
|
.macro POP reg
|
|
ld.ab \reg, [sp, 4]
|
|
.endm
|
|
|
|
.macro POPAX aux
|
|
POP r9
|
|
sr r9, [\aux]
|
|
.endm
|
|
|
|
/*--------------------------------------------------------------
|
|
* Helpers to save/restore Scratch Regs:
|
|
* used by Interrupt/Exception Prologue/Epilogue
|
|
*-------------------------------------------------------------*/
|
|
.macro SAVE_R0_TO_R12
|
|
PUSH r0
|
|
PUSH r1
|
|
PUSH r2
|
|
PUSH r3
|
|
PUSH r4
|
|
PUSH r5
|
|
PUSH r6
|
|
PUSH r7
|
|
PUSH r8
|
|
PUSH r9
|
|
PUSH r10
|
|
PUSH r11
|
|
PUSH r12
|
|
.endm
|
|
|
|
.macro RESTORE_R12_TO_R0
|
|
POP r12
|
|
POP r11
|
|
POP r10
|
|
POP r9
|
|
POP r8
|
|
POP r7
|
|
POP r6
|
|
POP r5
|
|
POP r4
|
|
POP r3
|
|
POP r2
|
|
POP r1
|
|
POP r0
|
|
|
|
#ifdef CONFIG_ARC_CURR_IN_REG
|
|
ld r25, [sp, 12]
|
|
#endif
|
|
.endm
|
|
|
|
/*--------------------------------------------------------------
|
|
* Helpers to save/restore callee-saved regs:
|
|
* used by several macros below
|
|
*-------------------------------------------------------------*/
|
|
.macro SAVE_R13_TO_R24
|
|
PUSH r13
|
|
PUSH r14
|
|
PUSH r15
|
|
PUSH r16
|
|
PUSH r17
|
|
PUSH r18
|
|
PUSH r19
|
|
PUSH r20
|
|
PUSH r21
|
|
PUSH r22
|
|
PUSH r23
|
|
PUSH r24
|
|
.endm
|
|
|
|
.macro RESTORE_R24_TO_R13
|
|
POP r24
|
|
POP r23
|
|
POP r22
|
|
POP r21
|
|
POP r20
|
|
POP r19
|
|
POP r18
|
|
POP r17
|
|
POP r16
|
|
POP r15
|
|
POP r14
|
|
POP r13
|
|
.endm
|
|
|
|
/*--------------------------------------------------------------
|
|
* Collect User Mode callee regs as struct callee_regs - needed by
|
|
* fork/do_signal/unaligned-access-emulation.
|
|
* (By default only scratch regs are saved on entry to kernel)
|
|
*
|
|
* Special handling for r25 if used for caching Task Pointer.
|
|
* It would have been saved in task->thread.user_r25 already, but to keep
|
|
* the interface same it is copied into regular r25 placeholder in
|
|
* struct callee_regs.
|
|
*-------------------------------------------------------------*/
|
|
.macro SAVE_CALLEE_SAVED_USER
|
|
|
|
mov r12, sp ; save SP as ref to pt_regs
|
|
SAVE_R13_TO_R24
|
|
|
|
#ifdef CONFIG_ARC_CURR_IN_REG
|
|
; Retrieve orig r25 and save it with rest of callee_regs
|
|
ld.as r12, [r12, PT_user_r25]
|
|
PUSH r12
|
|
#else
|
|
PUSH r25
|
|
#endif
|
|
|
|
.endm
|
|
|
|
/*--------------------------------------------------------------
|
|
* Save kernel Mode callee regs at the time of Contect Switch.
|
|
*
|
|
* Special handling for r25 if used for caching Task Pointer.
|
|
* Kernel simply skips saving it since it will be loaded with
|
|
* incoming task pointer anyways
|
|
*-------------------------------------------------------------*/
|
|
.macro SAVE_CALLEE_SAVED_KERNEL
|
|
|
|
SAVE_R13_TO_R24
|
|
|
|
#ifdef CONFIG_ARC_CURR_IN_REG
|
|
sub sp, sp, 4
|
|
#else
|
|
PUSH r25
|
|
#endif
|
|
.endm
|
|
|
|
/*--------------------------------------------------------------
|
|
* Opposite of SAVE_CALLEE_SAVED_KERNEL
|
|
*-------------------------------------------------------------*/
|
|
.macro RESTORE_CALLEE_SAVED_KERNEL
|
|
|
|
#ifdef CONFIG_ARC_CURR_IN_REG
|
|
add sp, sp, 4 /* skip usual r25 placeholder */
|
|
#else
|
|
POP r25
|
|
#endif
|
|
RESTORE_R24_TO_R13
|
|
.endm
|
|
|
|
/*--------------------------------------------------------------
|
|
* Opposite of SAVE_CALLEE_SAVED_USER
|
|
*
|
|
* ptrace tracer or unaligned-access fixup might have changed a user mode
|
|
* callee reg which is saved back to usual r25 storage location
|
|
*-------------------------------------------------------------*/
|
|
.macro RESTORE_CALLEE_SAVED_USER
|
|
|
|
#ifdef CONFIG_ARC_CURR_IN_REG
|
|
POP r12
|
|
#else
|
|
POP r25
|
|
#endif
|
|
RESTORE_R24_TO_R13
|
|
|
|
; SP is back to start of pt_regs
|
|
#ifdef CONFIG_ARC_CURR_IN_REG
|
|
st.as r12, [sp, PT_user_r25]
|
|
#endif
|
|
.endm
|
|
|
|
/*--------------------------------------------------------------
|
|
* Super FAST Restore callee saved regs by simply re-adjusting SP
|
|
*-------------------------------------------------------------*/
|
|
.macro DISCARD_CALLEE_SAVED_USER
|
|
add sp, sp, SZ_CALLEE_REGS
|
|
.endm
|
|
|
|
/*-------------------------------------------------------------
|
|
* given a tsk struct, get to the base of it's kernel mode stack
|
|
* tsk->thread_info is really a PAGE, whose bottom hoists stack
|
|
* which grows upwards towards thread_info
|
|
*------------------------------------------------------------*/
|
|
|
|
.macro GET_TSK_STACK_BASE tsk, out
|
|
|
|
/* Get task->thread_info (this is essentially start of a PAGE) */
|
|
ld \out, [\tsk, TASK_THREAD_INFO]
|
|
|
|
/* Go to end of page where stack begins (grows upwards) */
|
|
add2 \out, \out, (THREAD_SIZE)/4
|
|
|
|
.endm
|
|
|
|
/*
|
|
* @reg [OUT] thread_info->flags of "current"
|
|
*/
|
|
.macro GET_CURR_THR_INFO_FLAGS reg
|
|
GET_CURR_THR_INFO_FROM_SP \reg
|
|
ld \reg, [\reg, THREAD_INFO_FLAGS]
|
|
.endm
|
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
/*-------------------------------------------------
|
|
* Retrieve the current running task on this CPU
|
|
* 1. Determine curr CPU id.
|
|
* 2. Use it to index into _current_task[ ]
|
|
*/
|
|
.macro GET_CURR_TASK_ON_CPU reg
|
|
GET_CPU_ID \reg
|
|
ld.as \reg, [@_current_task, \reg]
|
|
.endm
|
|
|
|
/*-------------------------------------------------
|
|
* Save a new task as the "current" task on this CPU
|
|
* 1. Determine curr CPU id.
|
|
* 2. Use it to index into _current_task[ ]
|
|
*
|
|
* Coded differently than GET_CURR_TASK_ON_CPU (which uses LD.AS)
|
|
* because ST r0, [r1, offset] can ONLY have s9 @offset
|
|
* while LD can take s9 (4 byte insn) or LIMM (8 byte insn)
|
|
*/
|
|
|
|
.macro SET_CURR_TASK_ON_CPU tsk, tmp
|
|
GET_CPU_ID \tmp
|
|
add2 \tmp, @_current_task, \tmp
|
|
st \tsk, [\tmp]
|
|
#ifdef CONFIG_ARC_CURR_IN_REG
|
|
mov r25, \tsk
|
|
#endif
|
|
|
|
.endm
|
|
|
|
|
|
#else /* Uniprocessor implementation of macros */
|
|
|
|
.macro GET_CURR_TASK_ON_CPU reg
|
|
ld \reg, [@_current_task]
|
|
.endm
|
|
|
|
.macro SET_CURR_TASK_ON_CPU tsk, tmp
|
|
st \tsk, [@_current_task]
|
|
#ifdef CONFIG_ARC_CURR_IN_REG
|
|
mov r25, \tsk
|
|
#endif
|
|
.endm
|
|
|
|
#endif /* SMP / UNI */
|
|
|
|
/* ------------------------------------------------------------------
|
|
* Get the ptr to some field of Current Task at @off in task struct
|
|
* -Uses r25 for Current task ptr if that is enabled
|
|
*/
|
|
|
|
#ifdef CONFIG_ARC_CURR_IN_REG
|
|
|
|
.macro GET_CURR_TASK_FIELD_PTR off, reg
|
|
add \reg, r25, \off
|
|
.endm
|
|
|
|
#else
|
|
|
|
.macro GET_CURR_TASK_FIELD_PTR off, reg
|
|
GET_CURR_TASK_ON_CPU \reg
|
|
add \reg, \reg, \off
|
|
.endm
|
|
|
|
#endif /* CONFIG_ARC_CURR_IN_REG */
|
|
|
|
#endif /* __ASM_ARC_ENTRY_H */
|