2 * Copyright 2000, International Business Machines Corporation and others.
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
11 * Linux module support routines.
14 #include <afsconfig.h>
15 #include "afs/param.h"
20 #ifdef AFS_LINUX24_ENV
21 #include <linux/module.h> /* early to avoid printf->printk mapping */
23 #include "afs/sysincludes.h"
24 #include "afsincludes.h"
25 #include "h/unistd.h" /* For syscall numbers. */
28 #ifdef AFS_AMD64_LINUX20_ENV
29 #include "../asm/ia32_unistd.h"
32 #include <linux/proc_fs.h>
33 #include <linux/slab.h>
34 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
35 #include <linux/init.h>
36 #include <linux/sched.h>
40 /* On SPARC64 and S390X, sys_call_table contains 32-bit entries
41 * even though pointers are 64 bit quantities.
42 * XXX unify this with osi_probe.c
44 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390X_LINUX24_ENV)
45 #define SYSCALLTYPE unsigned int
46 #define POINTER2SYSCALL (unsigned int)(unsigned long)
47 #define SYSCALL2POINTER (void *)(long)
49 #define SYSCALLTYPE void *
50 #define POINTER2SYSCALL (void *)
51 #define SYSCALL2POINTER (void *)
54 #if defined(AFS_S390X_LINUX24_ENV) && !defined(AFS_LINUX26_ENV)
55 #define _S(x) ((x)<<1)
56 #elif defined(AFS_IA64_LINUX20_ENV)
57 #define _S(x) ((x)-1024)
63 /***** ALL PLATFORMS *****/
64 extern asmlinkage long
65 afs_syscall(long syscall, long parm1, long parm2, long parm3, long parm4);
67 static SYSCALLTYPE *afs_sys_call_table;
68 static SYSCALLTYPE afs_ni_syscall = 0;
70 extern long afs_xsetgroups();
71 asmlinkage long (*sys_setgroupsp) (int gidsetsize, gid_t * grouplist);
73 #ifdef AFS_LINUX24_ENV
74 extern int afs_xsetgroups32();
75 asmlinkage int (*sys_setgroups32p) (int gidsetsize,
76 __kernel_gid32_t * grouplist);
79 #if !defined(AFS_LINUX24_ENV)
80 asmlinkage int (*sys_settimeofdayp) (struct timeval * tv, struct timezone * tz);
85 #ifdef AFS_AMD64_LINUX20_ENV
86 static SYSCALLTYPE *afs_ia32_sys_call_table;
87 static SYSCALLTYPE ia32_ni_syscall = 0;
89 extern int afs32_xsetgroups();
90 asmlinkage long (*sys32_setgroupsp) (int gidsetsize, u16 * grouplist);
91 #ifdef AFS_LINUX24_ENV
92 extern int afs32_xsetgroups32();
93 asmlinkage long (*sys32_setgroups32p) (int gidsetsize, gid_t * grouplist);
94 #endif /* __NR_ia32_setgroups32 */
95 #endif /* AFS_AMD64_LINUX20_ENV */
99 #ifdef AFS_PPC64_LINUX20_ENV
100 extern SYSCALLTYPE *afs_sys_call_table32;
101 static SYSCALLTYPE afs_ni_syscall32 = 0;
103 extern int afs32_xsetgroups();
104 asmlinkage long (*sys32_setgroupsp)(int gidsetsize, gid_t *grouplist);
105 #endif /* AFS_AMD64_LINUX20_ENV */
108 /***** SPARC64 *****/
109 #ifdef AFS_SPARC64_LINUX20_ENV
110 extern SYSCALLTYPE *afs_sys_call_table32;
111 static SYSCALLTYPE afs_ni_syscall32 = 0;
113 extern int afs32_xsetgroups();
114 asmlinkage int (*sys32_setgroupsp) (int gidsetsize,
115 __kernel_gid_t32 * grouplist);
116 #ifdef AFS_LINUX24_ENV
117 /* This number is not exported for some bizarre reason. */
118 #define __NR_setgroups32 82
119 extern int afs32_xsetgroups32();
120 asmlinkage int (*sys32_setgroups32p) (int gidsetsize,
121 __kernel_gid_t32 * grouplist);
125 afs_syscall32(long syscall, long parm1, long parm2, long parm3, long parm4,
128 __asm__ __volatile__("srl %o4, 0, %o4\n\t"
130 "call afs_syscall\n\t"
131 "srl %o5, 0, %o5\n\t"
135 #endif /* AFS_SPARC64_LINUX20_ENV */
139 #ifdef AFS_IA64_LINUX20_ENV
142 afs_syscall_stub(int r0, int r1, long r2, long r3, long r4, long gp)
144 __asm__ __volatile__("alloc r42 = ar.pfs, 8, 3, 6, 0\n\t"
145 "mov r41 = b0\n\t" /* save rp */
151 "mov out5 = gp\n\t" /* save gp */
156 "addl r15=.fptr_afs_syscall-.L1,r3\n\t"
160 "ld8 r16=[r15],8\n\t"
164 "br.call.sptk.many b0 = b6\n\t"
166 "mov ar.pfs = r42\n\t"
168 "mov gp = r48\n\t" /* restore gp */
169 "br.ret.sptk.many b0\n"
170 ".fptr_afs_syscall:\n\t"
171 "data8 @fptr(afs_syscall)\n\t"
176 afs_xsetgroups_stub(int r0, int r1, long r2, long r3, long r4, long gp)
178 __asm__ __volatile__("alloc r42 = ar.pfs, 8, 3, 6, 0\n\t"
179 "mov r41 = b0\n\t" /* save rp */
185 "mov out5 = gp\n\t" /* save gp */
190 "addl r15=.fptr_afs_xsetgroups - .L2,r3\n\t"
194 "ld8 r16=[r15],8\n\t"
198 "br.call.sptk.many b0 = b6\n\t"
200 "mov ar.pfs = r42\n\t"
202 "mov gp = r48\n\t" /* restore gp */
203 "br.ret.sptk.many b0\n"
204 ".fptr_afs_xsetgroups:\n\t"
205 "data8 @fptr(afs_xsetgroups)\n\t"
214 #endif /* AFS_IA64_LINUX20_ENV */
218 /**********************************************************************/
219 /********************* System Call Initialization *********************/
220 /**********************************************************************/
222 int osi_syscall_init(void)
225 #ifdef AFS_IA64_LINUX20_ENV
226 /* This needs to be first because we are declaring variables, and
227 * also because the handling of syscall pointers is bizarre enough
228 * that we want to special-case even the "common" part.
230 unsigned long kernel_gp = 0;
231 static struct fptr sys_setgroups;
233 afs_sys_call_table = osi_find_syscall_table(0);
234 if (afs_sys_call_table) {
236 #if !defined(AFS_LINUX24_ENV)
237 /* XXX no sys_settimeofday on IA64? */
240 /* check we aren't already loaded */
241 /* XXX this can't be right */
242 if (SYSCALL2POINTER afs_sys_call_table[_S(__NR_afs_syscall)]
244 printf("AFS syscall entry point already in use!\n");
248 /* setup AFS entry point */
249 afs_ni_syscall = afs_sys_call_table[_S(__NR_afs_syscall)];
250 afs_sys_call_table[_S(__NR_afs_syscall)] =
251 POINTER2SYSCALL((struct fptr *)afs_syscall_stub)->ip;
253 /* setup setgroups */
254 sys_setgroupsp = (void *)&sys_setgroups;
256 ((struct fptr *)sys_setgroupsp)->ip =
257 SYSCALL2POINTER afs_sys_call_table[_S(__NR_setgroups)];
258 ((struct fptr *)sys_setgroupsp)->gp = kernel_gp;
260 afs_sys_call_table[_S(__NR_setgroups)] =
261 POINTER2SYSCALL((struct fptr *)afs_xsetgroups_stub)->ip;
264 /* XXX no 32-bit syscalls on IA64? */
267 /***** COMMON (except IA64) *****/
268 #else /* !AFS_IA64_LINUX20_ENV */
270 afs_sys_call_table = osi_find_syscall_table(0);
271 if (afs_sys_call_table) {
272 #if !defined(AFS_LINUX24_ENV)
274 SYSCALL2POINTER afs_sys_call_table[_S(__NR_settimeofday)];
275 #endif /* AFS_LINUX24_ENV */
277 /* check we aren't already loaded */
278 if (SYSCALL2POINTER afs_sys_call_table[_S(__NR_afs_syscall)]
280 printf("AFS syscall entry point already in use!\n");
284 /* setup AFS entry point */
285 afs_ni_syscall = afs_sys_call_table[_S(__NR_afs_syscall)];
286 afs_sys_call_table[_S(__NR_afs_syscall)] = POINTER2SYSCALL afs_syscall;
288 /* setup setgroups */
289 sys_setgroupsp = SYSCALL2POINTER afs_sys_call_table[_S(__NR_setgroups)];
290 afs_sys_call_table[_S(__NR_setgroups)] = POINTER2SYSCALL afs_xsetgroups;
292 #if defined(__NR_setgroups32)
293 /* setup setgroups32 */
294 sys_setgroups32p = SYSCALL2POINTER afs_sys_call_table[__NR_setgroups32];
295 afs_sys_call_table[__NR_setgroups32] = POINTER2SYSCALL afs_xsetgroups32;
298 #endif /* !AFS_IA64_LINUX20_ENV */
302 #ifdef AFS_AMD64_LINUX20_ENV
303 afs_ia32_sys_call_table = osi_find_syscall_table(1);
304 if (afs_ia32_sys_call_table) {
305 /* setup AFS entry point for IA32 */
306 ia32_ni_syscall = afs_ia32_sys_call_table[__NR_ia32_afs_syscall];
307 afs_ia32_sys_call_table[__NR_ia32_afs_syscall] =
308 POINTER2SYSCALL afs_syscall;
310 /* setup setgroups for IA32 */
312 SYSCALL2POINTER afs_ia32_sys_call_table[__NR_ia32_setgroups];
313 afs_ia32_sys_call_table[__NR_ia32_setgroups] =
314 POINTER2SYSCALL afs32_xsetgroups;
317 /* setup setgroups32 for IA32 */
319 SYSCALL2POINTER afs_ia32_sys_call_table[__NR_ia32_setgroups32];
320 afs_ia32_sys_call_table[__NR_ia32_setgroups32] =
321 POINTER2SYSCALL afs32_xsetgroups32;
322 #endif /* __NR_ia32_setgroups32 */
324 #endif /* AFS_AMD64_LINUX20_ENV */
328 #ifdef AFS_PPC64_LINUX20_ENV
329 /* XXX no 32-bit syscalls on PPC64? */
333 /***** SPARC64 *****/
334 #ifdef AFS_SPARC64_LINUX20_ENV
335 afs_sys_call_table32 = osi_find_syscall_table(1);
336 if (afs_sys_call_table32) {
337 /* setup AFS entry point for 32-bit SPARC */
338 afs_ni_syscall32 = afs_sys_call_table32[__NR_afs_syscall];
339 afs_sys_call_table32[__NR_afs_syscall] = POINTER2SYSCALL afs_syscall32;
341 /* setup setgroups for 32-bit SPARC */
342 sys32_setgroupsp = SYSCALL2POINTER afs_sys_call_table32[__NR_setgroups];
343 afs_sys_call_table32[__NR_setgroups] = POINTER2SYSCALL afs32_xsetgroups;
345 #ifdef AFS_LINUX24_ENV
346 /* setup setgroups32 for 32-bit SPARC */
348 SYSCALL2POINTER afs_sys_call_table32[__NR_setgroups32];
349 afs_sys_call_table32[__NR_setgroups32] =
350 POINTER2SYSCALL afs32_xsetgroups32;
353 #endif /* AFS_SPARC64_LINUX20_ENV */
359 /**********************************************************************/
360 /************************ System Call Cleanup *************************/
361 /**********************************************************************/
363 void osi_syscall_clean(void)
366 if (afs_sys_call_table) {
367 /* put back the AFS entry point */
368 afs_sys_call_table[_S(__NR_afs_syscall)] = afs_ni_syscall;
370 /* put back setgroups */
371 #if defined(AFS_IA64_LINUX20_ENV)
372 afs_sys_call_table[_S(__NR_setgroups)] =
373 POINTER2SYSCALL((struct fptr *)sys_setgroupsp)->ip;
374 #else /* AFS_IA64_LINUX20_ENV */
375 afs_sys_call_table[_S(__NR_setgroups)] =
376 POINTER2SYSCALL sys_setgroupsp;
379 #if defined(__NR_setgroups32) && !defined(AFS_IA64_LINUX20_ENV)
380 /* put back setgroups32 */
381 afs_sys_call_table[__NR_setgroups32] = POINTER2SYSCALL sys_setgroups32p;
387 #ifdef AFS_IA64_LINUX20_ENV
388 /* XXX no 32-bit syscalls on IA64? */
393 #ifdef AFS_AMD64_LINUX20_ENV
394 if (afs_ia32_sys_call_table) {
395 /* put back AFS entry point for IA32 */
396 afs_ia32_sys_call_table[__NR_ia32_afs_syscall] =
397 POINTER2SYSCALL ia32_ni_syscall;
399 /* put back setgroups for IA32 */
400 afs_ia32_sys_call_table[__NR_ia32_setgroups] =
401 POINTER2SYSCALL sys32_setgroupsp;
403 #ifdef AFS_LINUX24_ENV
404 /* put back setgroups32 for IA32 */
405 afs_ia32_sys_call_table[__NR_ia32_setgroups32] =
406 POINTER2SYSCALL sys32_setgroups32p;
413 #ifdef AFS_PPC64_LINUX20_ENV
414 /* XXX no 32-bit syscalls on PPC64? */
418 /***** SPARC64 *****/
419 #ifdef AFS_SPARC64_LINUX20_ENV
420 if (afs_sys_call_table32) {
421 /* put back AFS entry point for 32-bit SPARC */
422 afs_sys_call_table32[__NR_afs_syscall] = afs_ni_syscall32;
424 /* put back setgroups for IA32 */
425 afs_sys_call_table32[__NR_setgroups] =
426 POINTER2SYSCALL sys32_setgroupsp;
428 #ifdef AFS_LINUX24_ENV
429 /* put back setgroups32 for IA32 */
430 afs_sys_call_table32[__NR_setgroups32] =
431 POINTER2SYSCALL sys32_setgroups32p;