cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ftrace_mprofile.S (5701B)


      1/* SPDX-License-Identifier: GPL-2.0-or-later */
      2/*
      3 * Split from ftrace_64.S
      4 */
      5
      6#include <linux/magic.h>
      7#include <asm/ppc_asm.h>
      8#include <asm/asm-offsets.h>
      9#include <asm/ftrace.h>
     10#include <asm/ppc-opcode.h>
     11#include <asm/export.h>
     12#include <asm/thread_info.h>
     13#include <asm/bug.h>
     14#include <asm/ptrace.h>
     15
     16/*
     17 *
     18 * ftrace_caller()/ftrace_regs_caller() is the function that replaces _mcount()
     19 * when ftrace is active.
     20 *
     21 * We arrive here after a function A calls function B, and we are the trace
     22 * function for B. When we enter r1 points to A's stack frame, B has not yet
     23 * had a chance to allocate one yet.
     24 *
     25 * Additionally r2 may point either to the TOC for A, or B, depending on
     26 * whether B did a TOC setup sequence before calling us.
     27 *
     28 * On entry the LR points back to the _mcount() call site, and r0 holds the
     29 * saved LR as it was on entry to B, ie. the original return address at the
     30 * call site in A.
     31 *
     32 * Our job is to save the register state into a struct pt_regs (on the stack)
     33 * and then arrange for the ftrace function to be called.
     34 */
     35.macro	ftrace_regs_entry allregs
     36	/* Create our stack frame + pt_regs */
     37	PPC_STLU	r1,-SWITCH_FRAME_SIZE(r1)
     38
     39	/* Save all gprs to pt_regs */
     40	SAVE_GPR(0, r1)
     41	SAVE_GPRS(3, 10, r1)
     42
     43#ifdef CONFIG_PPC64
     44	/* Save the original return address in A's stack frame */
     45	std	r0, LRSAVE+SWITCH_FRAME_SIZE(r1)
     46	/* Ok to continue? */
     47	lbz	r3, PACA_FTRACE_ENABLED(r13)
     48	cmpdi	r3, 0
     49	beq	ftrace_no_trace
     50#endif
     51
     52	.if \allregs == 1
     53	SAVE_GPR(2, r1)
     54	SAVE_GPRS(11, 31, r1)
     55	.else
     56#ifdef CONFIG_LIVEPATCH_64
     57	SAVE_GPR(14, r1)
     58#endif
     59	.endif
     60
     61	/* Save previous stack pointer (r1) */
     62	addi	r8, r1, SWITCH_FRAME_SIZE
     63	PPC_STL	r8, GPR1(r1)
     64
     65	.if \allregs == 1
     66	/* Load special regs for save below */
     67	mfmsr   r8
     68	mfctr   r9
     69	mfxer   r10
     70	mfcr	r11
     71	.else
     72	/* Clear MSR to flag as ftrace_caller versus frace_regs_caller */
     73	li	r8, 0
     74	.endif
     75
     76	/* Get the _mcount() call site out of LR */
     77	mflr	r7
     78	/* Save it as pt_regs->nip */
     79	PPC_STL	r7, _NIP(r1)
     80	/* Save the read LR in pt_regs->link */
     81	PPC_STL	r0, _LINK(r1)
     82
     83#ifdef CONFIG_PPC64
     84	/* Save callee's TOC in the ABI compliant location */
     85	std	r2, STK_GOT(r1)
     86	ld	r2,PACATOC(r13)	/* get kernel TOC in r2 */
     87
     88	addis	r3,r2,function_trace_op@toc@ha
     89	addi	r3,r3,function_trace_op@toc@l
     90	ld	r5,0(r3)
     91#else
     92	lis	r3,function_trace_op@ha
     93	lwz	r5,function_trace_op@l(r3)
     94#endif
     95
     96#ifdef CONFIG_LIVEPATCH_64
     97	mr	r14, r7		/* remember old NIP */
     98#endif
     99
    100	/* Calculate ip from nip-4 into r3 for call below */
    101	subi    r3, r7, MCOUNT_INSN_SIZE
    102
    103	/* Put the original return address in r4 as parent_ip */
    104	mr	r4, r0
    105
    106	/* Save special regs */
    107	PPC_STL	r8, _MSR(r1)
    108	.if \allregs == 1
    109	PPC_STL	r9, _CTR(r1)
    110	PPC_STL	r10, _XER(r1)
    111	PPC_STL	r11, _CCR(r1)
    112	.endif
    113
    114	/* Load &pt_regs in r6 for call below */
    115	addi    r6, r1, STACK_FRAME_OVERHEAD
    116.endm
    117
    118.macro	ftrace_regs_exit allregs
    119	/* Load ctr with the possibly modified NIP */
    120	PPC_LL	r3, _NIP(r1)
    121	mtctr	r3
    122
    123#ifdef CONFIG_LIVEPATCH_64
    124	cmpd	r14, r3		/* has NIP been altered? */
    125#endif
    126
    127	/* Restore gprs */
    128	.if \allregs == 1
    129	REST_GPRS(2, 31, r1)
    130	.else
    131	REST_GPRS(3, 10, r1)
    132#ifdef CONFIG_LIVEPATCH_64
    133	REST_GPR(14, r1)
    134#endif
    135	.endif
    136
    137	/* Restore possibly modified LR */
    138	PPC_LL	r0, _LINK(r1)
    139	mtlr	r0
    140
    141#ifdef CONFIG_PPC64
    142	/* Restore callee's TOC */
    143	ld	r2, STK_GOT(r1)
    144#endif
    145
    146	/* Pop our stack frame */
    147	addi r1, r1, SWITCH_FRAME_SIZE
    148
    149#ifdef CONFIG_LIVEPATCH_64
    150        /* Based on the cmpd above, if the NIP was altered handle livepatch */
    151	bne-	livepatch_handler
    152#endif
    153	bctr			/* jump after _mcount site */
    154.endm
    155
    156_GLOBAL(ftrace_regs_caller)
    157	ftrace_regs_entry 1
    158	/* ftrace_call(r3, r4, r5, r6) */
    159.globl ftrace_regs_call
    160ftrace_regs_call:
    161	bl	ftrace_stub
    162	nop
    163	ftrace_regs_exit 1
    164
    165_GLOBAL(ftrace_caller)
    166	ftrace_regs_entry 0
    167	/* ftrace_call(r3, r4, r5, r6) */
    168.globl ftrace_call
    169ftrace_call:
    170	bl	ftrace_stub
    171	nop
    172	ftrace_regs_exit 0
    173
    174_GLOBAL(ftrace_stub)
    175	blr
    176
    177#ifdef CONFIG_PPC64
    178ftrace_no_trace:
    179	mflr	r3
    180	mtctr	r3
    181	REST_GPR(3, r1)
    182	addi	r1, r1, SWITCH_FRAME_SIZE
    183	mtlr	r0
    184	bctr
    185#endif
    186
    187#ifdef CONFIG_LIVEPATCH_64
    188	/*
    189	 * This function runs in the mcount context, between two functions. As
    190	 * such it can only clobber registers which are volatile and used in
    191	 * function linkage.
    192	 *
    193	 * We get here when a function A, calls another function B, but B has
    194	 * been live patched with a new function C.
    195	 *
    196	 * On entry:
    197	 *  - we have no stack frame and can not allocate one
    198	 *  - LR points back to the original caller (in A)
    199	 *  - CTR holds the new NIP in C
    200	 *  - r0, r11 & r12 are free
    201	 */
    202livepatch_handler:
    203	ld	r12, PACA_THREAD_INFO(r13)
    204
    205	/* Allocate 3 x 8 bytes */
    206	ld	r11, TI_livepatch_sp(r12)
    207	addi	r11, r11, 24
    208	std	r11, TI_livepatch_sp(r12)
    209
    210	/* Save toc & real LR on livepatch stack */
    211	std	r2,  -24(r11)
    212	mflr	r12
    213	std	r12, -16(r11)
    214
    215	/* Store stack end marker */
    216	lis     r12, STACK_END_MAGIC@h
    217	ori     r12, r12, STACK_END_MAGIC@l
    218	std	r12, -8(r11)
    219
    220	/* Put ctr in r12 for global entry and branch there */
    221	mfctr	r12
    222	bctrl
    223
    224	/*
    225	 * Now we are returning from the patched function to the original
    226	 * caller A. We are free to use r11, r12 and we can use r2 until we
    227	 * restore it.
    228	 */
    229
    230	ld	r12, PACA_THREAD_INFO(r13)
    231
    232	ld	r11, TI_livepatch_sp(r12)
    233
    234	/* Check stack marker hasn't been trashed */
    235	lis     r2,  STACK_END_MAGIC@h
    236	ori     r2,  r2, STACK_END_MAGIC@l
    237	ld	r12, -8(r11)
    2381:	tdne	r12, r2
    239	EMIT_BUG_ENTRY 1b, __FILE__, __LINE__ - 1, 0
    240
    241	/* Restore LR & toc from livepatch stack */
    242	ld	r12, -16(r11)
    243	mtlr	r12
    244	ld	r2,  -24(r11)
    245
    246	/* Pop livepatch stack frame */
    247	ld	r12, PACA_THREAD_INFO(r13)
    248	subi	r11, r11, 24
    249	std	r11, TI_livepatch_sp(r12)
    250
    251	/* Return to original caller of live patched function */
    252	blr
    253#endif /* CONFIG_LIVEPATCH */