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 #include <linux/module.h> /* early to avoid printf->printk mapping */
21 #include "afs/sysincludes.h"
22 #include "afsincludes.h"
23 #include "h/unistd.h" /* For syscall numbers. */
26 #ifdef AFS_AMD64_LINUX20_ENV
27 #include "../asm/ia32_unistd.h"
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>
38 /* On SPARC64 and S390X, sys_call_table contains 32-bit entries
39 * even though pointers are 64 bit quantities.
40 * XXX unify this with osi_probe.c
42 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390X_LINUX24_ENV)
43 #define SYSCALLTYPE unsigned int
44 #define POINTER2SYSCALL (unsigned int)(unsigned long)
45 #define SYSCALL2POINTER (void *)(long)
47 #define SYSCALLTYPE void *
48 #define POINTER2SYSCALL (void *)
49 #define SYSCALL2POINTER (void *)
52 #if defined(AFS_S390X_LINUX24_ENV) && !defined(AFS_LINUX26_ENV)
53 #define _S(x) ((x)<<1)
54 #elif defined(AFS_IA64_LINUX20_ENV)
55 #define _S(x) ((x)-1024)
61 /***** ALL PLATFORMS *****/
62 extern asmlinkage long
63 afs_syscall(long syscall, long parm1, long parm2, long parm3, long parm4);
65 static SYSCALLTYPE *afs_sys_call_table;
66 static SYSCALLTYPE afs_ni_syscall = 0;
68 extern long afs_xsetgroups();
69 asmlinkage long (*sys_setgroupsp) (int gidsetsize, gid_t * grouplist);
71 #ifdef AFS_LINUX24_ENV
72 extern int afs_xsetgroups32();
73 asmlinkage int (*sys_setgroups32p) (int gidsetsize,
74 __kernel_gid32_t * grouplist);
77 #if !defined(AFS_LINUX24_ENV)
78 asmlinkage int (*sys_settimeofdayp) (struct timeval * tv, struct timezone * tz);
83 #ifdef AFS_AMD64_LINUX20_ENV
84 static SYSCALLTYPE *afs_ia32_sys_call_table;
85 static SYSCALLTYPE ia32_ni_syscall = 0;
87 extern int afs32_xsetgroups();
88 asmlinkage long (*sys32_setgroupsp) (int gidsetsize, u16 * grouplist);
89 #ifdef AFS_LINUX24_ENV
90 extern int afs32_xsetgroups32();
91 asmlinkage long (*sys32_setgroups32p) (int gidsetsize, gid_t * grouplist);
92 #endif /* __NR_ia32_setgroups32 */
93 #endif /* AFS_AMD64_LINUX20_ENV */
97 #ifdef AFS_PPC64_LINUX20_ENV
98 extern SYSCALLTYPE *afs_sys_call_table32;
99 static SYSCALLTYPE afs_ni_syscall32 = 0;
101 extern int afs32_xsetgroups();
102 asmlinkage long (*sys32_setgroupsp)(int gidsetsize, gid_t *grouplist);
103 #endif /* AFS_AMD64_LINUX20_ENV */
106 /***** SPARC64 *****/
107 #ifdef AFS_SPARC64_LINUX20_ENV
108 extern SYSCALLTYPE *afs_sys_call_table32;
109 static SYSCALLTYPE afs_ni_syscall32 = 0;
111 extern int afs32_xsetgroups();
112 asmlinkage int (*sys32_setgroupsp) (int gidsetsize,
113 __kernel_gid_t32 * grouplist);
114 #ifdef AFS_LINUX24_ENV
115 /* This number is not exported for some bizarre reason. */
116 #define __NR_setgroups32 82
117 extern int afs32_xsetgroups32();
118 asmlinkage int (*sys32_setgroups32p) (int gidsetsize,
119 __kernel_gid_t32 * grouplist);
123 afs_syscall32(long syscall, long parm1, long parm2, long parm3, long parm4,
126 __asm__ __volatile__("srl %o4, 0, %o4\n\t"
128 "call afs_syscall\n\t"
129 "srl %o5, 0, %o5\n\t"
133 #endif /* AFS_SPARC64_LINUX20_ENV */
137 #ifdef AFS_IA64_LINUX20_ENV
140 afs_syscall_stub(int r0, int r1, long r2, long r3, long r4, long gp)
142 __asm__ __volatile__("alloc r42 = ar.pfs, 8, 3, 6, 0\n\t"
143 "mov r41 = b0\n\t" /* save rp */
149 "mov out5 = gp\n\t" /* save gp */
154 "addl r15=.fptr_afs_syscall-.L1,r3\n\t"
158 "ld8 r16=[r15],8\n\t"
162 "br.call.sptk.many b0 = b6\n\t"
164 "mov ar.pfs = r42\n\t"
166 "mov gp = r48\n\t" /* restore gp */
167 "br.ret.sptk.many b0\n"
168 ".fptr_afs_syscall:\n\t"
169 "data8 @fptr(afs_syscall)\n\t"
174 afs_xsetgroups_stub(int r0, int r1, long r2, long r3, long r4, long gp)
176 __asm__ __volatile__("alloc r42 = ar.pfs, 8, 3, 6, 0\n\t"
177 "mov r41 = b0\n\t" /* save rp */
183 "mov out5 = gp\n\t" /* save gp */
188 "addl r15=.fptr_afs_xsetgroups - .L2,r3\n\t"
192 "ld8 r16=[r15],8\n\t"
196 "br.call.sptk.many b0 = b6\n\t"
198 "mov ar.pfs = r42\n\t"
200 "mov gp = r48\n\t" /* restore gp */
201 "br.ret.sptk.many b0\n"
202 ".fptr_afs_xsetgroups:\n\t"
203 "data8 @fptr(afs_xsetgroups)\n\t"
212 #endif /* AFS_IA64_LINUX20_ENV */
216 /**********************************************************************/
217 /********************* System Call Initialization *********************/
218 /**********************************************************************/
220 int osi_syscall_init(void)
223 #ifdef AFS_IA64_LINUX20_ENV
224 /* This needs to be first because we are declaring variables, and
225 * also because the handling of syscall pointers is bizarre enough
226 * that we want to special-case even the "common" part.
228 unsigned long kernel_gp = 0;
229 static struct fptr sys_setgroups;
231 afs_sys_call_table = osi_find_syscall_table(0);
232 if (afs_sys_call_table) {
234 #if !defined(AFS_LINUX24_ENV)
235 /* XXX no sys_settimeofday on IA64? */
238 /* check we aren't already loaded */
239 /* XXX this can't be right */
240 if (SYSCALL2POINTER afs_sys_call_table[_S(__NR_afs_syscall)]
242 printf("AFS syscall entry point already in use!\n");
246 /* setup AFS entry point */
247 afs_ni_syscall = afs_sys_call_table[_S(__NR_afs_syscall)];
248 afs_sys_call_table[_S(__NR_afs_syscall)] =
249 POINTER2SYSCALL((struct fptr *)afs_syscall_stub)->ip;
251 /* setup setgroups */
252 sys_setgroupsp = (void *)&sys_setgroups;
254 ((struct fptr *)sys_setgroupsp)->ip =
255 SYSCALL2POINTER afs_sys_call_table[_S(__NR_setgroups)];
256 ((struct fptr *)sys_setgroupsp)->gp = kernel_gp;
258 afs_sys_call_table[_S(_NR_setgroups)] =
259 POINTER2SYSCALL((struct fptr *)afs_xsetgroups_stub)->ip;
262 /* XXX no 32-bit syscalls on IA64? */
265 /***** COMMON (except IA64) *****/
266 #else /* !AFS_IA64_LINUX20_ENV */
268 afs_sys_call_table = osi_find_syscall_table(0);
269 if (afs_sys_call_table) {
270 #if !defined(AFS_LINUX24_ENV)
272 SYSCALL2POINTER afs_sys_call_table[_S(__NR_settimeofday)];
273 #endif /* AFS_LINUX24_ENV */
275 /* check we aren't already loaded */
276 if (SYSCALL2POINTER afs_sys_call_table[_S(__NR_afs_syscall)]
278 printf("AFS syscall entry point already in use!\n");
282 /* setup AFS entry point */
283 afs_ni_syscall = afs_sys_call_table[_S(__NR_afs_syscall)];
284 afs_sys_call_table[_S(__NR_afs_syscall)] = POINTER2SYSCALL afs_syscall;
286 /* setup setgroups */
287 sys_setgroupsp = SYSCALL2POINTER afs_sys_call_table[_S(__NR_setgroups)];
288 afs_sys_call_table[_S(__NR_setgroups)] = POINTER2SYSCALL afs_xsetgroups;
290 #if defined(__NR_setgroups32)
291 /* setup setgroups32 */
292 sys_setgroups32p = SYSCALL2POINTER afs_sys_call_table[__NR_setgroups32];
293 afs_sys_call_table[__NR_setgroups32] = POINTER2SYSCALL afs_xsetgroups32;
296 #endif /* !AFS_IA64_LINUX20_ENV */
300 #ifdef AFS_AMD64_LINUX20_ENV
301 afs_ia32_sys_call_table = osi_find_syscall_table(1);
302 if (afs_ia32_sys_call_table) {
303 /* setup AFS entry point for IA32 */
304 ia32_ni_syscall = afs_ia32_sys_call_table[__NR_ia32_afs_syscall];
305 afs_ia32_sys_call_table[__NR_ia32_afs_syscall] =
306 POINTER2SYSCALL afs_syscall;
308 /* setup setgroups for IA32 */
310 SYSCALL2POINTER afs_ia32_sys_call_table[__NR_ia32_setgroups];
311 afs_ia32_sys_call_table[__NR_ia32_setgroups] =
312 POINTER2SYSCALL afs32_xsetgroups;
315 /* setup setgroups32 for IA32 */
317 SYSCALL2POINTER afs_ia32_sys_call_table[__NR_ia32_setgroups32];
318 afs_ia32_sys_call_table[__NR_ia32_setgroups32] =
319 POINTER2SYSCALL afs32_xsetgroups32;
320 #endif /* __NR_ia32_setgroups32 */
322 #endif /* AFS_AMD64_LINUX20_ENV */
326 #ifdef AFS_PPC64_LINUX20_ENV
327 /* XXX no 32-bit syscalls on PPC64? */
331 /***** SPARC64 *****/
332 #ifdef AFS_SPARC64_LINUX20_ENV
333 afs_sys_call_table32 = osi_find_syscall_table(1);
334 if (afs_sys_call_table32) {
335 /* setup AFS entry point for 32-bit SPARC */
336 afs_ni_syscall32 = afs_sys_call_table32[__NR_afs_syscall];
337 afs_sys_call_table32[__NR_afs_syscall] = POINTER2SYSCALL afs_syscall32;
339 /* setup setgroups for 32-bit SPARC */
340 sys32_setgroupsp = SYSCALL2POINTER afs_sys_call_table32[__NR_setgroups];
341 afs_sys_call_table32[__NR_setgroups] = POINTER2SYSCALL afs32_xsetgroups;
343 #ifdef AFS_LINUX24_ENV
344 /* setup setgroups32 for 32-bit SPARC */
346 SYSCALL2POINTER afs_sys_call_table32[__NR_setgroups32];
347 afs_sys_call_table32[__NR_setgroups32] =
348 POINTER2SYSCALL afs32_xsetgroups32;
351 #endif /* AFS_SPARC64_LINUX20_ENV */
357 /**********************************************************************/
358 /************************ System Call Cleanup *************************/
359 /**********************************************************************/
361 void osi_syscall_clean(void)
364 if (afs_sys_call_table) {
365 /* put back the AFS entry point */
366 afs_sys_call_table[_S(__NR_afs_syscall)] = afs_ni_syscall;
368 /* put back setgroups */
369 #if defined(AFS_IA64_LINUX20_ENV)
370 afs_sys_call_table[_S(__NR_setgroups)] =
371 POINTER2SYSCALL((struct fptr *)sys_setgroupsp)->ip;
372 #else /* AFS_IA64_LINUX20_ENV */
373 afs_sys_call_table[_S(__NR_setgroups)] =
374 POINTER2SYSCALL sys_setgroupsp;
377 #if defined(__NR_setgroups32) && !defined(AFS_IA64_LINUX20_ENV)
378 /* put back setgroups32 */
379 afs_sys_call_table[__NR_setgroups32] = POINTER2SYSCALL sys_setgroups32p;
385 #ifdef AFS_IA64_LINUX20_ENV
386 /* XXX no 32-bit syscalls on IA64? */
391 #ifdef AFS_AMD64_LINUX20_ENV
392 if (afs_ia32_sys_call_table) {
393 /* put back AFS entry point for IA32 */
394 afs_ia32_sys_call_table[__NR_ia32_afs_syscall] =
395 POINTER2SYSCALL ia32_ni_syscall;
397 /* put back setgroups for IA32 */
398 afs_ia32_sys_call_table[__NR_ia32_setgroups] =
399 POINTER2SYSCALL sys32_setgroupsp;
401 #ifdef AFS_LINUX24_ENV
402 /* put back setgroups32 for IA32 */
403 afs_ia32_sys_call_table[__NR_ia32_setgroups32] =
404 POINTER2SYSCALL sys32_setgroups32p;
411 #ifdef AFS_PPC64_LINUX20_ENV
412 /* XXX no 32-bit syscalls on PPC64? */
416 /***** SPARC64 *****/
417 #ifdef AFS_SPARC64_LINUX20_ENV
418 if (afs_sys_call_table32) {
419 /* put back AFS entry point for 32-bit SPARC */
420 afs_sys_call_table32[__NR_afs_syscall] = afs_ni_syscall32;
422 /* put back setgroups for IA32 */
423 afs_sys_call_table32[__NR_setgroups] =
424 POINTER2SYSCALL sys32_setgroupsp;
426 #ifdef AFS_LINUX24_ENV
427 /* put back setgroups32 for IA32 */
428 afs_sys_call_table32[__NR_setgroups32] =
429 POINTER2SYSCALL sys32_setgroups32p;