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

coprocessor.S (6815B)


      1/*
      2 * arch/xtensa/kernel/coprocessor.S
      3 *
      4 * Xtensa processor configuration-specific table of coprocessor and
      5 * other custom register layout information.
      6 *
      7 * This file is subject to the terms and conditions of the GNU General Public
      8 * License.  See the file "COPYING" in the main directory of this archive
      9 * for more details.
     10 *
     11 * Copyright (C) 2003 - 2007 Tensilica Inc.
     12 */
     13
     14
     15#include <linux/linkage.h>
     16#include <asm/asm-offsets.h>
     17#include <asm/asmmacro.h>
     18#include <asm/coprocessor.h>
     19#include <asm/current.h>
     20#include <asm/regs.h>
     21
     22/*
     23 * Rules for coprocessor state manipulation on SMP:
     24 *
     25 * - a task may have live coprocessors only on one CPU.
     26 *
     27 * - whether coprocessor context of task T is live on some CPU is
     28 *   denoted by T's thread_info->cpenable.
     29 *
     30 * - non-zero thread_info->cpenable means that thread_info->cp_owner_cpu
     31 *   is valid in the T's thread_info. Zero thread_info->cpenable means that
     32 *   coprocessor context is valid in the T's thread_info.
     33 *
     34 * - if a coprocessor context of task T is live on CPU X, only CPU X changes
     35 *   T's thread_info->cpenable, cp_owner_cpu and coprocessor save area.
     36 *   This is done by making sure that for the task T with live coprocessor
     37 *   on CPU X cpenable SR is 0 when T runs on any other CPU Y.
     38 *   When fast_coprocessor exception is taken on CPU Y it goes to the
     39 *   C-level do_coprocessor that uses IPI to make CPU X flush T's coprocessors.
     40 */
     41
     42#if XTENSA_HAVE_COPROCESSORS
     43
     44/*
     45 * Macros for lazy context switch. 
     46 */
     47
     48#define SAVE_CP_REGS(x)							\
     49	.if XTENSA_HAVE_COPROCESSOR(x);					\
     50		.align 4;						\
     51	.Lsave_cp_regs_cp##x:						\
     52		xchal_cp##x##_store a2 a3 a4 a5 a6;			\
     53		ret;							\
     54	.endif
     55
     56#define LOAD_CP_REGS(x)							\
     57	.if XTENSA_HAVE_COPROCESSOR(x);					\
     58		.align 4;						\
     59	.Lload_cp_regs_cp##x:						\
     60		xchal_cp##x##_load a2 a3 a4 a5 a6;			\
     61		ret;							\
     62	.endif
     63
     64#define CP_REGS_TAB(x)							\
     65	.if XTENSA_HAVE_COPROCESSOR(x);					\
     66		.long .Lsave_cp_regs_cp##x;				\
     67		.long .Lload_cp_regs_cp##x;				\
     68	.else;								\
     69		.long 0, 0;						\
     70	.endif;								\
     71	.long THREAD_XTREGS_CP##x
     72
     73#define CP_REGS_TAB_SAVE 0
     74#define CP_REGS_TAB_LOAD 4
     75#define CP_REGS_TAB_OFFSET 8
     76
     77	__XTENSA_HANDLER
     78
     79	SAVE_CP_REGS(0)
     80	SAVE_CP_REGS(1)
     81	SAVE_CP_REGS(2)
     82	SAVE_CP_REGS(3)
     83	SAVE_CP_REGS(4)
     84	SAVE_CP_REGS(5)
     85	SAVE_CP_REGS(6)
     86	SAVE_CP_REGS(7)
     87
     88	LOAD_CP_REGS(0)
     89	LOAD_CP_REGS(1)
     90	LOAD_CP_REGS(2)
     91	LOAD_CP_REGS(3)
     92	LOAD_CP_REGS(4)
     93	LOAD_CP_REGS(5)
     94	LOAD_CP_REGS(6)
     95	LOAD_CP_REGS(7)
     96
     97	.align 4
     98.Lcp_regs_jump_table:
     99	CP_REGS_TAB(0)
    100	CP_REGS_TAB(1)
    101	CP_REGS_TAB(2)
    102	CP_REGS_TAB(3)
    103	CP_REGS_TAB(4)
    104	CP_REGS_TAB(5)
    105	CP_REGS_TAB(6)
    106	CP_REGS_TAB(7)
    107
    108/*
    109 * Entry condition:
    110 *
    111 *   a0:	trashed, original value saved on stack (PT_AREG0)
    112 *   a1:	a1
    113 *   a2:	new stack pointer, original in DEPC
    114 *   a3:	a3
    115 *   depc:	a2, original value saved on stack (PT_DEPC)
    116 *   excsave_1:	dispatch table
    117 *
    118 *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
    119 *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
    120 */
    121
    122ENTRY(fast_coprocessor)
    123
    124	s32i	a3, a2, PT_AREG3
    125
    126#ifdef CONFIG_SMP
    127	/*
    128	 * Check if any coprocessor context is live on another CPU
    129	 * and if so go through the C-level coprocessor exception handler
    130	 * to flush it to memory.
    131	 */
    132	GET_THREAD_INFO (a0, a2)
    133	l32i	a3, a0, THREAD_CPENABLE
    134	beqz	a3, .Lload_local
    135
    136	/*
    137	 * Pairs with smp_wmb in local_coprocessor_release_all
    138	 * and with both memws below.
    139	 */
    140	memw
    141	l32i	a3, a0, THREAD_CPU
    142	l32i	a0, a0, THREAD_CP_OWNER_CPU
    143	beq	a0, a3, .Lload_local
    144
    145	rsr	a0, ps
    146	l32i	a3, a2, PT_AREG3
    147	bbci.l	a0, PS_UM_BIT, 1f
    148	call0	user_exception
    1491:	call0	kernel_exception
    150#endif
    151
    152	/* Save remaining registers a1-a3 and SAR */
    153
    154.Lload_local:
    155	rsr	a3, sar
    156	s32i	a1, a2, PT_AREG1
    157	s32i	a3, a2, PT_SAR
    158	mov	a1, a2
    159	rsr	a2, depc
    160	s32i	a2, a1, PT_AREG2
    161
    162	/* The hal macros require up to 4 temporary registers. We use a3..a6. */
    163
    164	s32i	a4, a1, PT_AREG4
    165	s32i	a5, a1, PT_AREG5
    166	s32i	a6, a1, PT_AREG6
    167	s32i	a7, a1, PT_AREG7
    168	s32i	a8, a1, PT_AREG8
    169	s32i	a9, a1, PT_AREG9
    170	s32i	a10, a1, PT_AREG10
    171
    172	/* Find coprocessor number. Subtract first CP EXCCAUSE from EXCCAUSE */
    173
    174	rsr	a3, exccause
    175	addi	a3, a3, -EXCCAUSE_COPROCESSOR0_DISABLED
    176
    177	/* Set corresponding CPENABLE bit -> (sar:cp-index, a3: 1<<cp-index)*/
    178
    179	ssl	a3			# SAR: 32 - coprocessor_number
    180	movi	a2, 1
    181	rsr	a0, cpenable
    182	sll	a2, a2
    183	or	a0, a0, a2
    184	wsr	a0, cpenable
    185	rsync
    186
    187	/* Get coprocessor save/load table entry (a7). */
    188
    189	movi	a7, .Lcp_regs_jump_table
    190	addx8	a7, a3, a7
    191	addx4	a7, a3, a7
    192
    193	/* Retrieve previous owner (a8). */
    194
    195	rsr	a0, excsave1		# exc_table
    196	addx4	a0, a3, a0		# entry for CP
    197	l32i	a8, a0, EXC_TABLE_COPROCESSOR_OWNER
    198
    199	/* Set new owner (a9). */
    200
    201	GET_THREAD_INFO (a9, a1)
    202	l32i	a4, a9, THREAD_CPU
    203	s32i	a9, a0, EXC_TABLE_COPROCESSOR_OWNER
    204	s32i	a4, a9, THREAD_CP_OWNER_CPU
    205
    206	/*
    207	 * Enable coprocessor for the new owner. (a2 = 1 << CP number)
    208	 * This can be done before loading context into the coprocessor.
    209	 */
    210	l32i	a4, a9, THREAD_CPENABLE
    211	or	a4, a4, a2
    212
    213	/*
    214	 * Make sure THREAD_CP_OWNER_CPU is in memory before updating
    215	 * THREAD_CPENABLE
    216	 */
    217	memw				# (2)
    218	s32i	a4, a9, THREAD_CPENABLE
    219
    220	beqz	a8, 1f			# skip 'save' if no previous owner
    221
    222	/* Disable coprocessor for previous owner. (a2 = 1 << CP number) */
    223
    224	l32i	a10, a8, THREAD_CPENABLE
    225	xor	a10, a10, a2
    226
    227	/* Get context save area and call save routine. */
    228
    229	l32i	a2, a7, CP_REGS_TAB_OFFSET
    230	l32i	a3, a7, CP_REGS_TAB_SAVE
    231	add	a2, a2, a8
    232	callx0	a3
    233
    234	/*
    235	 * Make sure coprocessor context and THREAD_CP_OWNER_CPU are in memory
    236	 * before updating THREAD_CPENABLE
    237	 */
    238	memw				# (3)
    239	s32i	a10, a8, THREAD_CPENABLE
    2401:
    241	/* Get context save area and call load routine. */
    242
    243	l32i	a2, a7, CP_REGS_TAB_OFFSET
    244	l32i	a3, a7, CP_REGS_TAB_LOAD
    245	add	a2, a2, a9
    246	callx0	a3
    247
    248	/* Restore all registers and return from exception handler. */
    249
    250	l32i	a10, a1, PT_AREG10
    251	l32i	a9, a1, PT_AREG9
    252	l32i	a8, a1, PT_AREG8
    253	l32i	a7, a1, PT_AREG7
    254	l32i	a6, a1, PT_AREG6
    255	l32i	a5, a1, PT_AREG5
    256	l32i	a4, a1, PT_AREG4
    257
    258	l32i	a0, a1, PT_SAR
    259	l32i	a3, a1, PT_AREG3
    260	l32i	a2, a1, PT_AREG2
    261	wsr	a0, sar
    262	l32i	a0, a1, PT_AREG0
    263	l32i	a1, a1, PT_AREG1
    264
    265	rfe
    266
    267ENDPROC(fast_coprocessor)
    268
    269	.text
    270
    271/*
    272 * coprocessor_flush(struct thread_info*, index)
    273 *                             a2        a3
    274 *
    275 * Save coprocessor registers for coprocessor 'index'.
    276 * The register values are saved to or loaded from the coprocessor area
    277 * inside the task_info structure.
    278 *
    279 * Note that this function doesn't update the coprocessor_owner information!
    280 *
    281 */
    282
    283ENTRY(coprocessor_flush)
    284
    285	abi_entry_default
    286
    287	movi	a4, .Lcp_regs_jump_table
    288	addx8	a4, a3, a4
    289	addx4	a3, a3, a4
    290	l32i	a4, a3, CP_REGS_TAB_SAVE
    291	beqz	a4, 1f
    292	l32i	a3, a3, CP_REGS_TAB_OFFSET
    293	add	a2, a2, a3
    294	mov	a7, a0
    295	callx0	a4
    296	mov	a0, a7
    2971:
    298	abi_ret_default
    299
    300ENDPROC(coprocessor_flush)
    301
    302#endif /* XTENSA_HAVE_COPROCESSORS */