2019-06-04 16:11:33 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2013-01-18 17:42:20 +08:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/sched.h>
|
|
|
|
#include <linux/mm.h>
|
|
|
|
#include <linux/interrupt.h>
|
|
|
|
#include <linux/thread_info.h>
|
|
|
|
#include <linux/kbuild.h>
|
2013-03-06 19:23:44 +08:00
|
|
|
#include <linux/ptrace.h>
|
2013-01-18 17:42:20 +08:00
|
|
|
#include <asm/hardirq.h>
|
|
|
|
#include <asm/page.h>
|
|
|
|
|
2020-03-06 04:02:51 +08:00
|
|
|
|
2013-01-18 17:42:20 +08:00
|
|
|
int main(void)
|
|
|
|
{
|
|
|
|
DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
|
|
|
|
DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, stack));
|
|
|
|
|
|
|
|
BLANK();
|
|
|
|
|
|
|
|
DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
|
|
|
|
DEFINE(THREAD_CALLEE_REG, offsetof(struct thread_struct, callee_reg));
|
|
|
|
DEFINE(THREAD_FAULT_ADDR,
|
|
|
|
offsetof(struct thread_struct, fault_address));
|
|
|
|
|
|
|
|
BLANK();
|
|
|
|
|
|
|
|
DEFINE(THREAD_INFO_FLAGS, offsetof(struct thread_info, flags));
|
|
|
|
DEFINE(THREAD_INFO_PREEMPT_COUNT,
|
|
|
|
offsetof(struct thread_info, preempt_count));
|
|
|
|
|
|
|
|
BLANK();
|
|
|
|
|
|
|
|
DEFINE(TASK_ACT_MM, offsetof(struct task_struct, active_mm));
|
|
|
|
DEFINE(TASK_TGID, offsetof(struct task_struct, tgid));
|
2014-12-03 22:52:41 +08:00
|
|
|
DEFINE(TASK_PID, offsetof(struct task_struct, pid));
|
|
|
|
DEFINE(TASK_COMM, offsetof(struct task_struct, comm));
|
2013-01-18 17:42:20 +08:00
|
|
|
|
|
|
|
DEFINE(MM_CTXT, offsetof(struct mm_struct, context));
|
|
|
|
DEFINE(MM_PGD, offsetof(struct mm_struct, pgd));
|
|
|
|
|
|
|
|
DEFINE(MM_CTXT_ASID, offsetof(mm_context_t, asid));
|
|
|
|
|
|
|
|
BLANK();
|
|
|
|
|
|
|
|
DEFINE(PT_status32, offsetof(struct pt_regs, status32));
|
2013-06-11 21:26:54 +08:00
|
|
|
DEFINE(PT_event, offsetof(struct pt_regs, event));
|
2013-01-18 17:42:20 +08:00
|
|
|
DEFINE(PT_sp, offsetof(struct pt_regs, sp));
|
|
|
|
DEFINE(PT_r0, offsetof(struct pt_regs, r0));
|
|
|
|
DEFINE(PT_r1, offsetof(struct pt_regs, r1));
|
|
|
|
DEFINE(PT_r2, offsetof(struct pt_regs, r2));
|
|
|
|
DEFINE(PT_r3, offsetof(struct pt_regs, r3));
|
|
|
|
DEFINE(PT_r4, offsetof(struct pt_regs, r4));
|
|
|
|
DEFINE(PT_r5, offsetof(struct pt_regs, r5));
|
|
|
|
DEFINE(PT_r6, offsetof(struct pt_regs, r6));
|
|
|
|
DEFINE(PT_r7, offsetof(struct pt_regs, r7));
|
2019-05-16 06:36:46 +08:00
|
|
|
DEFINE(PT_r8, offsetof(struct pt_regs, r8));
|
|
|
|
DEFINE(PT_r10, offsetof(struct pt_regs, r10));
|
|
|
|
DEFINE(PT_r26, offsetof(struct pt_regs, r26));
|
2014-09-22 19:21:47 +08:00
|
|
|
DEFINE(PT_ret, offsetof(struct pt_regs, ret));
|
2019-05-16 06:36:46 +08:00
|
|
|
DEFINE(PT_blink, offsetof(struct pt_regs, blink));
|
|
|
|
DEFINE(PT_lpe, offsetof(struct pt_regs, lp_end));
|
|
|
|
DEFINE(PT_lpc, offsetof(struct pt_regs, lp_count));
|
|
|
|
DEFINE(PT_user_r25, offsetof(struct pt_regs, user_r25));
|
2013-01-18 17:42:20 +08:00
|
|
|
|
2013-05-28 00:13:41 +08:00
|
|
|
DEFINE(SZ_CALLEE_REGS, sizeof(struct callee_regs));
|
ARC: pt_regs update #4: r25 saved/restored unconditionally
(This is a VERY IMP change for low level interrupt/exception handling)
-----------------------------------------------------------------------
WHAT
-----------------------------------------------------------------------
* User 25 now saved in pt_regs->user_r25 (vs. tsk->thread_info.user_r25)
* This allows Low level interrupt code to unconditionally save r25
(vs. the prev version which would only do it for U->K transition).
Ofcourse for nested interrupts, only the pt_regs->user_r25 of
bottom-most frame is useful.
* simplifies the interrupt prologue/epilogue
* Needed for ARCv2 ISA code and done here to keep design similar with
ARCompact event handling
-----------------------------------------------------------------------
WHY
-------------------------------------------------------------------------
With CONFIG_ARC_CURR_IN_REG, r25 is used to cache "current" task pointer
in kernel mode. So when entering kernel mode from User Mode
- user r25 is specially safe-kept (it being a callee reg is NOT part of
pt_regs which are saved by default on each interrupt/trap/exception)
- r25 loaded with current task pointer.
Further, if interrupt was taken in kernel mode, this is skipped since we
know that r25 already has valid "current" pointer.
With 2 level of interrupts in ARCompact ISA, detecting this is difficult
but still possible, since we could be in kernel mode but r25 not already saved
(in fact the stack itself might not have been switched).
A. User mode
B. L1 IRQ taken
C. L2 IRQ taken (while on 1st line of L1 ISR)
So in #C, although in kernel mode, r25 not saved (infact SP not
switched at all)
Given that ARcompact has manual stack switching, we could use a bit of
trickey - The low level code would make sure that SP is only set to kernel
mode value at the very end (after saving r25). So a non kernel mode SP,
even if in kernel mode, meant r25 was NOT saved.
The same paradigm won't work in ARCv2 ISA since SP is auto-switched so
it's setting can't be delayed/constrained.
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
2013-05-28 16:20:41 +08:00
|
|
|
DEFINE(SZ_PT_REGS, sizeof(struct pt_regs));
|
ARCv2: STAR 9000808988: signals involving Delay Slot
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>
2014-10-07 16:42:13 +08:00
|
|
|
|
2019-12-28 02:03:43 +08:00
|
|
|
#ifdef CONFIG_ISA_ARCV2
|
|
|
|
OFFSET(PT_r12, pt_regs, r12);
|
|
|
|
OFFSET(PT_r30, pt_regs, r30);
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_ARC_HAS_ACCL_REGS
|
|
|
|
OFFSET(PT_r58, pt_regs, r58);
|
|
|
|
OFFSET(PT_r59, pt_regs, r59);
|
|
|
|
#endif
|
2020-03-06 04:02:51 +08:00
|
|
|
#ifdef CONFIG_ARC_DSP_SAVE_RESTORE_REGS
|
|
|
|
OFFSET(PT_DSP_CTRL, pt_regs, DSP_CTRL);
|
|
|
|
#endif
|
2019-12-28 02:03:43 +08:00
|
|
|
|
2013-01-18 17:42:20 +08:00
|
|
|
return 0;
|
|
|
|
}
|