Linux: Fix prototypes for afs_xsetgroups and sys_setgroupsp and friends
[openafs.git] / src / afs / LINUX24 / osi_syscall.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * Linux module support routines.
12  *
13  */
14 #include <afsconfig.h>
15 #include "afs/param.h"
16
17
18 #ifdef AFS_LINUX24_ENV
19 #include <linux/module.h> /* early to avoid printf->printk mapping */
20 #endif
21 #include "afs/sysincludes.h"
22 #include "afsincludes.h"
23 #include "h/unistd.h"           /* For syscall numbers. */
24 #include "h/mm.h"
25
26 #ifdef AFS_AMD64_LINUX20_ENV
27 #include <asm/ia32_unistd.h>
28 #endif
29
30 #include <linux/proc_fs.h>
31 #include <linux/slab.h>
32 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
33 #include <linux/init.h>
34 #include <linux/sched.h>
35 #endif
36
37 #ifndef NR_syscalls
38 #define NR_syscalls 222
39 #endif
40
41 /* On SPARC64 and S390X, sys_call_table contains 32-bit entries
42  * even though pointers are 64 bit quantities.
43  * XXX unify this with osi_probe.c
44  */
45 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390X_LINUX24_ENV)
46 #define SYSCALLTYPE unsigned int
47 #define POINTER2SYSCALL (unsigned int)(unsigned long)
48 #define SYSCALL2POINTER (void *)(long)
49 #else
50 #define SYSCALLTYPE void *
51 #define POINTER2SYSCALL (void *)
52 #define SYSCALL2POINTER (void *)
53 #endif
54
55 #if defined(AFS_S390X_LINUX24_ENV) 
56 #define INSERT_SYSCALL(SLOT, TMPPAGE, FUNC) \
57         if (SYSCALL2POINTER FUNC > 0x7fffffff) { \
58             TMPPAGE = kmalloc ( PAGE_SIZE, GFP_DMA|GFP_KERNEL );        \
59             if (SYSCALL2POINTER TMPPAGE > 0x7fffffff) { \
60                 printf("Cannot allocate page for FUNC syscall jump vector\n"); \
61                 return EINVAL; \
62             } \
63             memcpy(TMPPAGE, syscall_jump_code, sizeof(syscall_jump_code)); \
64             *(void **)(TMPPAGE + 0x0c) = &FUNC; \
65             afs_sys_call_table[_S(SLOT)] = POINTER2SYSCALL TMPPAGE; \
66         } else \
67             afs_sys_call_table[_S(SLOT)] = POINTER2SYSCALL FUNC;
68 #else
69 #define INSERT_SYSCALL(SLOT, TMPPAGE, FUNC) \
70     afs_sys_call_table[_S(SLOT)] = POINTER2SYSCALL FUNC;
71 #endif 
72
73 #if defined(AFS_S390X_LINUX24_ENV)
74 #define _S(x) ((x)<<1)
75 #elif defined(AFS_IA64_LINUX20_ENV)
76 #define _S(x) ((x)-1024)
77 #else
78 #define _S(x) x
79 #endif
80
81
82 /***** ALL PLATFORMS *****/
83 extern asmlinkage long
84 afs_syscall(long syscall, long parm1, long parm2, long parm3, long parm4);
85
86 static SYSCALLTYPE *afs_sys_call_table;
87 static SYSCALLTYPE afs_ni_syscall = 0;
88
89 #ifdef AFS_S390X_LINUX24_ENV
90 static void *afs_sys_setgroups_page = 0;
91 static void *afs_sys_setgroups32_page = 0;
92 static void *afs_syscall_page = 0;
93
94 /* Because of how the syscall table is handled, we need to ensure our 
95    syscalls are within the first 2gb of address space. This means we need
96    self-modifying code we can inject to call our handlers if the module 
97    is loaded high. If keyrings had advanced as fast as false protection
98    this would be unnecessary. */
99
100 uint32_t syscall_jump_code[] = {
101   0xe3d0f030, 0x00240dd0, 0xa7f40006, 0xffffffff, 0xffffffff, 0xe310d004, 
102   0x0004e3d0, 0xf0300004, 0x07f10000, 
103 };
104 #endif
105
106 extern asmlinkage long afs_xsetgroups(int gidsetsize, gid_t * grouplist);
107 asmlinkage long (*sys_setgroupsp) (int gidsetsize, gid_t * grouplist);
108
109 #ifdef AFS_LINUX24_ENV
110 extern asmlinkage long afs_xsetgroups32(int gidsetsize, gid_t * grouplist);
111 asmlinkage int (*sys_setgroups32p) (int gidsetsize,
112                                     __kernel_gid32_t * grouplist);
113 #endif
114
115 #if !defined(AFS_LINUX24_ENV)
116 asmlinkage int (*sys_settimeofdayp) (struct timeval * tv, struct timezone * tz);
117 #endif
118
119
120 /***** AMD64 *****/
121 #ifdef AFS_AMD64_LINUX20_ENV
122 static SYSCALLTYPE *afs_ia32_sys_call_table;
123 static SYSCALLTYPE ia32_ni_syscall = 0;
124
125 extern asmlinkage long afs32_xsetgroups(int gidsetsize, u16 * grouplist);
126 asmlinkage long (*sys32_setgroupsp) (int gidsetsize, u16 * grouplist);
127 #ifdef AFS_LINUX24_ENV
128 extern asmlinkage long afs32_xsetgroups32(int gidsetsize, gid_t * grouplist);
129 asmlinkage long (*sys32_setgroups32p) (int gidsetsize, gid_t * grouplist);
130 #endif /* __NR_ia32_setgroups32 */
131 #endif /* AFS_AMD64_LINUX20_ENV */
132
133
134 /***** SPARC64 *****/
135 #ifdef AFS_SPARC64_LINUX20_ENV
136 extern SYSCALLTYPE *afs_sys_call_table32;
137 static SYSCALLTYPE afs_ni_syscall32 = 0;
138
139 extern asmlinkage long afs32_xsetgroups(int gidsetsize, u16 * grouplist);
140 asmlinkage int (*sys32_setgroupsp) (int gidsetsize,
141                                     __kernel_gid_t32 * grouplist);
142 #ifdef AFS_LINUX24_ENV
143 /* This number is not exported for some bizarre reason. */
144 #define __NR_setgroups32      82
145 extern asmlinkage long afs32_xsetgroups32(int gidsetsize, gid_t * grouplist);
146 asmlinkage int (*sys32_setgroups32p) (int gidsetsize,
147                                       __kernel_gid_t32 * grouplist);
148 #endif
149
150 asmlinkage int
151 afs_syscall32(long syscall, long parm1, long parm2, long parm3, long parm4,
152               long parm5)
153 {
154     __asm__ __volatile__("srl %o4, 0, %o4\n\t"
155                          "mov %o7, %i7\n\t"
156                          "call afs_syscall\n\t"
157                          "srl %o5, 0, %o5\n\t"
158                          "ret\n\t"
159                          "nop");
160 }
161 #endif /* AFS_SPARC64_LINUX20_ENV */
162
163
164 /***** IA64 *****/
165 #ifdef AFS_IA64_LINUX20_ENV
166
167 asmlinkage long
168 afs_syscall_stub(int r0, int r1, long r2, long r3, long r4, long gp)
169 {
170     __asm__ __volatile__("alloc r42 = ar.pfs, 8, 3, 6, 0\n\t"
171                          "mov r41 = b0\n\t"     /* save rp */
172                          "mov out0 = in0\n\t"
173                          "mov out1 = in1\n\t"
174                          "mov out2 = in2\n\t"
175                          "mov out3 = in3\n\t"
176                          "mov out4 = in4\n\t"
177                          "mov out5 = gp\n\t"    /* save gp */
178                          ";;\n"
179                          ".L1:\n\t"
180                          "mov r3 = ip\n\t"
181                          ";;\n\t"
182                          "addl r15=.fptr_afs_syscall-.L1,r3\n\t"
183                          ";;\n\t"
184                          "ld8 r15=[r15]\n\t"
185                          ";;\n\t"
186                          "ld8 r16=[r15],8\n\t"
187                          ";;\n\t"
188                          "ld8 gp=[r15]\n\t"
189                          "mov b6=r16\n\t"
190                          "br.call.sptk.many b0 = b6\n\t"
191                          ";;\n\t"
192                          "mov ar.pfs = r42\n\t"
193                          "mov b0 = r41\n\t"
194                          "mov gp = r48\n\t"     /* restore gp */
195                          "br.ret.sptk.many b0\n"
196                          ".fptr_afs_syscall:\n\t"
197                          "data8 @fptr(afs_syscall)\n\t"
198                          ".skip 8");
199 }
200
201 asmlinkage long
202 afs_xsetgroups_stub(int r0, int r1, long r2, long r3, long r4, long gp)
203 {
204     __asm__ __volatile__("alloc r42 = ar.pfs, 8, 3, 6, 0\n\t"
205                          "mov r41 = b0\n\t"     /* save rp */
206                          "mov out0 = in0\n\t"
207                          "mov out1 = in1\n\t"
208                          "mov out2 = in2\n\t"
209                          "mov out3 = in3\n\t"
210                          "mov out4 = in4\n\t"
211                          "mov out5 = gp\n\t"    /* save gp */
212                          ";;\n"
213                          ".L2:\n\t"
214                          "mov r3 = ip\n\t"
215                          ";;\n\t"
216                          "addl r15=.fptr_afs_xsetgroups - .L2,r3\n\t"
217                          ";;\n\t"
218                          "ld8 r15=[r15]\n\t"
219                          ";;\n\t"
220                          "ld8 r16=[r15],8\n\t"
221                          ";;\n\t"
222                          "ld8 gp=[r15]\n\t"
223                          "mov b6=r16\n\t"
224                          "br.call.sptk.many b0 = b6\n\t"
225                          ";;\n\t"
226                          "mov ar.pfs = r42\n\t"
227                          "mov b0 = r41\n\t"
228                          "mov gp = r48\n\t"     /* restore gp */
229                          "br.ret.sptk.many b0\n"
230                          ".fptr_afs_xsetgroups:\n\t"
231                          "data8 @fptr(afs_xsetgroups)\n\t"
232                          ".skip 8");
233 }
234
235 struct fptr {
236     void *ip;
237     unsigned long gp;
238 };
239
240 #endif /* AFS_IA64_LINUX20_ENV */
241
242 /**********************************************************************/
243 /********************* System Call Initialization *********************/
244 /**********************************************************************/
245
246 int osi_syscall_init(void)
247 {
248 /***** IA64 *****/
249 #ifdef AFS_IA64_LINUX20_ENV
250     /* This needs to be first because we are declaring variables, and
251      * also because the handling of syscall pointers is bizarre enough
252      * that we want to special-case even the "common" part.
253      */
254     unsigned long kernel_gp = 0;
255     static struct fptr sys_setgroups;
256
257     afs_sys_call_table = osi_find_syscall_table(0);
258     if (afs_sys_call_table) {
259
260 #if !defined(AFS_LINUX24_ENV)
261         /* XXX no sys_settimeofday on IA64? */
262 #endif
263
264         /* check we aren't already loaded */
265         /* XXX this can't be right */
266         if (SYSCALL2POINTER afs_sys_call_table[_S(__NR_afs_syscall)]
267             == afs_syscall) {
268             printf("AFS syscall entry point already in use!\n");
269             return -EBUSY;
270         }
271
272         /* setup AFS entry point */
273         afs_ni_syscall = afs_sys_call_table[_S(__NR_afs_syscall)];
274         afs_sys_call_table[_S(__NR_afs_syscall)] =
275                 POINTER2SYSCALL((struct fptr *)afs_syscall_stub)->ip;
276
277         /* setup setgroups */
278         sys_setgroupsp = (void *)&sys_setgroups;
279
280         ((struct fptr *)sys_setgroupsp)->ip =
281             SYSCALL2POINTER afs_sys_call_table[_S(__NR_setgroups)];
282         ((struct fptr *)sys_setgroupsp)->gp = kernel_gp;
283
284         afs_sys_call_table[_S(__NR_setgroups)] =
285             POINTER2SYSCALL((struct fptr *)afs_xsetgroups_stub)->ip;
286     }
287
288     /* XXX no 32-bit syscalls on IA64? */
289
290
291 /***** COMMON (except IA64 or PPC64) *****/
292 #else /* !AFS_IA64_LINUX20_ENV */
293
294     afs_sys_call_table = osi_find_syscall_table(0);
295     if (afs_sys_call_table) {
296 #if !defined(AFS_LINUX24_ENV)
297         sys_settimeofdayp =
298             SYSCALL2POINTER afs_sys_call_table[_S(__NR_settimeofday)];
299 #endif /* AFS_LINUX24_ENV */
300
301         /* check we aren't already loaded */
302         if (SYSCALL2POINTER afs_sys_call_table[_S(__NR_afs_syscall)]
303             == afs_syscall) {
304             printf("AFS syscall entry point already in use!\n");
305             return -EBUSY;
306         }
307
308         /* setup AFS entry point */
309         afs_ni_syscall = afs_sys_call_table[_S(__NR_afs_syscall)];
310
311         INSERT_SYSCALL(__NR_afs_syscall, afs_syscall_page, afs_syscall)
312
313         /* setup setgroups */
314         sys_setgroupsp = SYSCALL2POINTER afs_sys_call_table[_S(__NR_setgroups)];
315         INSERT_SYSCALL(__NR_setgroups, afs_sys_setgroups_page, afs_xsetgroups)
316
317 #if defined(__NR_setgroups32)
318         /* setup setgroups32 */
319         sys_setgroups32p = SYSCALL2POINTER afs_sys_call_table[__NR_setgroups32];
320         INSERT_SYSCALL(__NR_setgroups32, afs_sys_setgroups32_page, afs_xsetgroups32)
321 #endif
322     }
323 #endif /* !AFS_IA64_LINUX20_ENV */
324
325
326 /***** AMD64 *****/
327 #ifdef AFS_AMD64_LINUX20_ENV
328     afs_ia32_sys_call_table = osi_find_syscall_table(1);
329     if (afs_ia32_sys_call_table) {
330         /* setup AFS entry point for IA32 */
331         ia32_ni_syscall = afs_ia32_sys_call_table[__NR_ia32_afs_syscall];
332         afs_ia32_sys_call_table[__NR_ia32_afs_syscall] =
333             POINTER2SYSCALL afs_syscall;
334
335         /* setup setgroups for IA32 */
336         sys32_setgroupsp =
337             SYSCALL2POINTER afs_ia32_sys_call_table[__NR_ia32_setgroups];
338         afs_ia32_sys_call_table[__NR_ia32_setgroups] =
339             POINTER2SYSCALL afs32_xsetgroups;
340
341 #if AFS_LINUX24_ENV
342         /* setup setgroups32 for IA32 */
343         sys32_setgroups32p =
344             SYSCALL2POINTER afs_ia32_sys_call_table[__NR_ia32_setgroups32];
345         afs_ia32_sys_call_table[__NR_ia32_setgroups32] =
346             POINTER2SYSCALL afs32_xsetgroups32;
347 #endif /* __NR_ia32_setgroups32 */
348     }
349 #endif /* AFS_AMD64_LINUX20_ENV */
350
351
352 /***** SPARC64 *****/
353 #ifdef AFS_SPARC64_LINUX20_ENV
354     afs_sys_call_table32 = osi_find_syscall_table(1);
355     if (afs_sys_call_table32) {
356         /* setup AFS entry point for 32-bit SPARC */
357         afs_ni_syscall32 = afs_sys_call_table32[__NR_afs_syscall];
358         afs_sys_call_table32[__NR_afs_syscall] = POINTER2SYSCALL afs_syscall32;
359
360         /* setup setgroups for 32-bit SPARC */
361         sys32_setgroupsp = SYSCALL2POINTER afs_sys_call_table32[__NR_setgroups];
362         afs_sys_call_table32[__NR_setgroups] = POINTER2SYSCALL afs32_xsetgroups;
363
364 #ifdef AFS_LINUX24_ENV
365         /* setup setgroups32 for 32-bit SPARC */
366         sys32_setgroups32p =
367             SYSCALL2POINTER afs_sys_call_table32[__NR_setgroups32];
368         afs_sys_call_table32[__NR_setgroups32] =
369             POINTER2SYSCALL afs32_xsetgroups32;
370 #endif
371     }
372 #endif /* AFS_SPARC64_LINUX20_ENV */
373     return 0;
374 }
375
376
377
378 /**********************************************************************/
379 /************************ System Call Cleanup *************************/
380 /**********************************************************************/
381
382 void osi_syscall_clean(void)
383 {
384 /***** COMMON *****/
385     if (afs_sys_call_table) {
386         /* put back the AFS entry point */
387         afs_sys_call_table[_S(__NR_afs_syscall)] = afs_ni_syscall;
388
389         /* put back setgroups */
390 #if defined(AFS_IA64_LINUX20_ENV)
391         afs_sys_call_table[_S(__NR_setgroups)] =
392             POINTER2SYSCALL((struct fptr *)sys_setgroupsp)->ip;
393 #else /* AFS_IA64_LINUX20_ENV */
394         afs_sys_call_table[_S(__NR_setgroups)] =
395             POINTER2SYSCALL sys_setgroupsp;
396 #endif
397
398 #if defined(__NR_setgroups32) && !defined(AFS_IA64_LINUX20_ENV)
399         /* put back setgroups32 */
400         afs_sys_call_table[__NR_setgroups32] = POINTER2SYSCALL sys_setgroups32p;
401 #endif
402 #if defined(AFS_S390X_LINUX24_ENV)
403 #if defined(__NR_setgroups32) && !defined(AFS_IA64_LINUX20_ENV)
404         if (afs_sys_setgroups32_page)
405             kfree(afs_sys_setgroups32_page);
406 #endif
407         if (afs_sys_setgroups_page)
408             kfree(afs_sys_setgroups_page);
409         if (afs_syscall_page)
410             kfree(afs_syscall_page);
411 #endif
412     }
413
414
415 /***** IA64 *****/
416 #ifdef AFS_IA64_LINUX20_ENV
417     /* XXX no 32-bit syscalls on IA64? */
418 #endif
419
420
421 /***** AMD64 *****/
422 #ifdef AFS_AMD64_LINUX20_ENV
423     if (afs_ia32_sys_call_table) {
424         /* put back AFS entry point for IA32 */
425         afs_ia32_sys_call_table[__NR_ia32_afs_syscall] =
426             POINTER2SYSCALL ia32_ni_syscall;
427
428         /* put back setgroups for IA32 */
429         afs_ia32_sys_call_table[__NR_ia32_setgroups] =
430             POINTER2SYSCALL sys32_setgroupsp;
431
432 #ifdef AFS_LINUX24_ENV
433         /* put back setgroups32 for IA32 */
434         afs_ia32_sys_call_table[__NR_ia32_setgroups32] =
435             POINTER2SYSCALL sys32_setgroups32p;
436 #endif
437     }
438 #endif
439
440
441 /***** SPARC64 *****/
442 #ifdef AFS_SPARC64_LINUX20_ENV
443     if (afs_sys_call_table32) {
444         /* put back AFS entry point for 32-bit SPARC */
445         afs_sys_call_table32[__NR_afs_syscall] = afs_ni_syscall32;
446
447         /* put back setgroups for IA32 */
448         afs_sys_call_table32[__NR_setgroups] =
449             POINTER2SYSCALL sys32_setgroupsp;
450
451 #ifdef AFS_LINUX24_ENV
452         /* put back setgroups32 for IA32 */
453         afs_sys_call_table32[__NR_setgroups32] =
454             POINTER2SYSCALL sys32_setgroups32p;
455 #endif
456     }
457 #endif
458 }