1 /*
2  * Copyright (C) 2016-2017 Andes Technology, Inc.
3  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
4  */
5 
6 #ifndef _LINUX_NDS32_SYSDEP_H
7 #define _LINUX_NDS32_SYSDEP_H 1
8 
9 #include <common/sysdep.h>
10 
11 #ifdef	__ASSEMBLER__
12 /* Define an entry point visible from C.  */
13 # ifdef PIC
14 # define ENTRY(name)                      \
15   .pic										\
16   .align 2;                              \
17   .globl C_SYMBOL_NAME(name);            \
18   .func  C_SYMBOL_NAME(name);            \
19   .type  C_SYMBOL_NAME(name), @function; \
20 C_SYMBOL_NAME(name):			\
21 	        cfi_startproc;
22 
23 # else
24 # define ENTRY(name)                      \
25   .align 2;                              \
26   .globl C_SYMBOL_NAME(name);            \
27   .func  C_SYMBOL_NAME(name);            \
28   .type  C_SYMBOL_NAME(name), @function; \
29 C_SYMBOL_NAME(name):			\
30 	        cfi_startproc;
31 # endif
32 
33 #undef END
34 #define END(name) \
35   cfi_endproc;        \
36   .endfunc;           \
37   .size C_SYMBOL_NAME(name), .-C_SYMBOL_NAME(name)
38 
39 /* If compiled for profiling, call `mcount' at the start of each function.  */
40 # ifdef HAVE_ELF
41 	#undef NO_UNDERSCORES
42 	#define NO_UNDERSCORES
43 # endif
44 
45 # ifdef NO_UNDERSCORES
46 	#define syscall_error __syscall_error
47 # endif
48 
49 #define SYS_ify(syscall_name)  (__NR_##syscall_name)
50 
51 #define __do_syscall(syscall_name)		\
52   syscall	SYS_ify(syscall_name);
53 
54 # ifdef PIC
55 # define PSEUDO(name, syscall_name, args)				\
56   .pic;									\
57   .align 2;								\
58   99:	mfusr $r15, $PC;						\
59 	sethi	$r1,	hi20(_GLOBAL_OFFSET_TABLE_ + 4);		\
60 	ori	$r1,	$r1,	lo12(_GLOBAL_OFFSET_TABLE_ + 8);	\
61 	add	$r1,	$r15,	$r1;					\
62 	sethi $r15, hi20(SYSCALL_ERROR@PLT);				\
63 	ori	$r15,	$r15, 	lo12(SYSCALL_ERROR@PLT);		\
64 	add	$r15,	$r15, 	$r1;					\
65 	jr	$r15;							\
66 	nop;                                   				\
67 	ENTRY(name);                          				\
68 	__do_syscall(syscall_name);            				\
69 	bgez $r0, 2f;							\
70 	sltsi	$r1, 	$r0, 	-4096;					\
71 	beqz	$r1, 	99b;						\
72   2:
73 # else
74 # define PSEUDO(name, syscall_name, args)				\
75   .align 2;								\
76   99:	j SYSCALL_ERROR;                  				\
77 	nop;                                   				\
78 	ENTRY(name);                          				\
79 	__do_syscall(syscall_name);            				\
80         bgez $r0, 2f;                           			\
81         sltsi   $r1, $r0, -4096;                			\
82         beqz    $r1, 99b;                       			\
83   2:
84 # endif
85 
86 
87 #define PSEUDO_NOERRNO(name, syscall_name, args) 			\
88   ENTRY(name);                                   			\
89   __do_syscall(syscall_name);
90 
91 #undef PSEUDO_END
92 #define PSEUDO_END(sym)							\
93 	SYSCALL_ERROR_HANDLER						\
94 	END(sym)
95 
96 #undef PSEUDO_END_ERRVAL
97 #define PSEUDO_END_ERRVAL(sym) END(sym)
98 
99 #define PSEUDO_ERRVAL(name, syscall_name, args) PSEUDO_NOERRNO(name, syscall_name, args)
100 
101 #define ret_ERRVAL ret
102 
103 #define ret_NOERRNO ret
104 #if defined NOT_IN_libc
105 	#define SYSCALL_ERROR __local_syscall_error
106 	#ifdef PIC
107 		#define SYSCALL_ERROR_HANDLER						\
108 			__local_syscall_error:						\
109 				pushm	$gp, 	$lp;					\
110 			        cfi_adjust_cfa_offset(8)				\
111 			        cfi_rel_offset(gp, 0)					\
112 			        cfi_rel_offset(lp, 4)					\
113 				mfusr 	$r15, 	$PC;					\
114 				sethi	$gp,	hi20(_GLOBAL_OFFSET_TABLE_+4);		\
115 				ori	$gp,	$gp,	lo12(_GLOBAL_OFFSET_TABLE_+8);	\
116 				add	$gp,	$gp,	$r15;				\
117 				neg	$r0, 	$r0;					\
118 				push	$r0;						\
119 			        cfi_adjust_cfa_offset(4)				\
120 			        cfi_rel_offset(r0, 0)					\
121 				addi    $sp,    $sp, 	-4; 			\
122 				bal	C_SYMBOL_NAME(__errno_location@PLT);		\
123 				addi    $sp,    $sp, 	4; 			\
124 				pop	$r1;						\
125 			        cfi_adjust_cfa_offset(-4);                      	\
126 			        cfi_restore(r1);                                	\
127 				swi	$r1,	[$r0];					\
128 				li	$r0,	-1;					\
129 				popm	$gp,	$lp;					\
130 			        cfi_adjust_cfa_offset(-8);                      	\
131 			        cfi_restore(lp);                                	\
132 			        cfi_restore(gp);  					\
133 			1:	ret;
134 	#else
135 		#define SYSCALL_ERROR_HANDLER						\
136 			__local_syscall_error:						\
137 				push	$lp;						\
138 			        cfi_adjust_cfa_offset(4)				\
139 			        cfi_rel_offset(lp, 0)					\
140 				neg	$r0,	$r0;					\
141 				push	$r0;						\
142 			        cfi_adjust_cfa_offset(4)				\
143 			        cfi_rel_offset(r0, 0)					\
144 				addi    $sp,    $sp, 	-4; 			\
145 				bal	C_SYMBOL_NAME(__errno_location);		\
146 				addi    $sp,    $sp, 	4; 			\
147 				pop	$r1;						\
148 			        cfi_adjust_cfa_offset(-4);                      	\
149 			        cfi_restore(r1);                                	\
150 				swi	$r1,	[$r0];					\
151 				li	$r0,	-1;					\
152 				pop	$lp;						\
153 			        cfi_adjust_cfa_offset(-4);                      	\
154 			        cfi_restore(lp);                                	\
155 				ret;
156 	#endif
157 
158 #else
159 	#define SYSCALL_ERROR_HANDLER
160 	#define SYSCALL_ERROR __syscall_error
161 #endif
162 
163 #endif	/* __ASSEMBLER__ */
164 #endif //_LINUX_NDS32_SYSDEP_H
165