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)
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" "mov %o7, %i7\n\t"
127 "call afs_syscall\n\t" "srl %o5, 0, %o5\n\t"
130 #endif /* AFS_SPARC64_LINUX20_ENV */
134 #ifdef AFS_IA64_LINUX20_ENV
137 afs_syscall_stub(int r0, int r1, long r2, long r3, long r4, long gp)
139 __asm__ __volatile__("alloc r42 = ar.pfs, 8, 3, 6, 0\n\t" "mov r41 = b0\n\t" /* save rp */
140 "mov out0 = in0\n\t" "mov out1 = in1\n\t" "mov out2 = in2\n\t" "mov out3 = in3\n\t" "mov out4 = in4\n\t" "mov out5 = gp\n\t" /* save gp */
141 ";;\n" ".L1:\n\t" "mov r3 = ip\n\t" ";;\n\t" "addl r15=.fptr_afs_syscall-.L1,r3\n\t" ";;\n\t" "ld8 r15=[r15]\n\t" ";;\n\t" "ld8 r16=[r15],8\n\t" ";;\n\t" "ld8 gp=[r15]\n\t" "mov b6=r16\n\t" "br.call.sptk.many b0 = b6\n\t" ";;\n\t" "mov ar.pfs = r42\n\t" "mov b0 = r41\n\t" "mov gp = r48\n\t" /* restore gp */
142 "br.ret.sptk.many b0\n" ".fptr_afs_syscall:\n\t"
143 "data8 @fptr(afs_syscall)\n\t" ".skip 8");
147 afs_xsetgroups_stub(int r0, int r1, long r2, long r3, long r4, long gp)
149 __asm__ __volatile__("alloc r42 = ar.pfs, 8, 3, 6, 0\n\t" "mov r41 = b0\n\t" /* save rp */
150 "mov out0 = in0\n\t" "mov out1 = in1\n\t" "mov out2 = in2\n\t" "mov out3 = in3\n\t" "mov out4 = in4\n\t" "mov out5 = gp\n\t" /* save gp */
151 ";;\n" ".L2:\n\t" "mov r3 = ip\n\t" ";;\n\t" "addl r15=.fptr_afs_xsetgroups - .L2,r3\n\t" ";;\n\t" "ld8 r15=[r15]\n\t" ";;\n\t" "ld8 r16=[r15],8\n\t" ";;\n\t" "ld8 gp=[r15]\n\t" "mov b6=r16\n\t" "br.call.sptk.many b0 = b6\n\t" ";;\n\t" "mov ar.pfs = r42\n\t" "mov b0 = r41\n\t" "mov gp = r48\n\t" /* restore gp */
152 "br.ret.sptk.many b0\n" ".fptr_afs_xsetgroups:\n\t"
153 "data8 @fptr(afs_xsetgroups)\n\t" ".skip 8");
161 #endif /* AFS_IA64_LINUX20_ENV */
165 /**********************************************************************/
166 /********************* System Call Initialization *********************/
167 /**********************************************************************/
169 int osi_syscall_init(void)
172 #ifdef AFS_IA64_LINUX20_ENV
173 /* This needs to be first because we are declaring variables, and
174 * also because the handling of syscall pointers is bizarre enough
175 * that we want to special-case even the "common" part.
177 unsigned long kernel_gp = 0;
178 static struct fptr sys_setgroups;
180 afs_sys_call_table = osi_find_syscall_table(0);
181 if (afs_sys_call_table) {
183 #if !defined(AFS_LINUX24_ENV)
184 /* XXX no sys_settimeofday on IA64? */
187 /* check we aren't already loaded */
188 /* XXX this can't be right */
189 if (SYSCALL2POINTER afs_sys_call_table[_S(__NR_afs_syscall)]
191 printf("AFS syscall entry point already in use!\n");
195 /* setup AFS entry point */
196 afs_ni_syscall = afs_sys_call_table[_S(__NR_afs_syscall)];
197 afs_sys_call_table[_S(__NR_afs_syscall)] =
198 POINTER2SYSCALL((struct fptr *)afs_syscall_stub)->ip;
200 /* setup setgroups */
201 sys_setgroupsp = (void *)&sys_setgroups;
203 ((struct fptr *)sys_setgroupsp)->ip =
204 SYSCALL2POINTER afs_sys_call_table[_S(__NR_setgroups)];
205 ((struct fptr *)sys_setgroupsp)->gp = kernel_gp;
207 afs_sys_call_table[__S(_NR_setgroups)] =
208 POINTER2SYSCALL((struct fptr *)afs_xsetgroups_stub)->ip;
211 /* XXX no 32-bit syscalls on IA64? */
214 /***** COMMON (except IA64) *****/
215 #else /* !AFS_IA64_LINUX20_ENV */
217 afs_sys_call_table = osi_find_syscall_table(0);
218 if (afs_sys_call_table) {
219 #if !defined(AFS_LINUX24_ENV)
221 SYSCALL2POINTER afs_sys_call_table[_S(__NR_settimeofday)];
222 #endif /* AFS_LINUX24_ENV */
224 /* check we aren't already loaded */
225 if (SYSCALL2POINTER afs_sys_call_table[_S(__NR_afs_syscall)]
227 printf("AFS syscall entry point already in use!\n");
231 /* setup AFS entry point */
232 afs_ni_syscall = afs_sys_call_table[_S(__NR_afs_syscall)];
233 afs_sys_call_table[_S(__NR_afs_syscall)] = POINTER2SYSCALL afs_syscall;
235 /* setup setgroups */
236 sys_setgroupsp = SYSCALL2POINTER afs_sys_call_table[_S(__NR_setgroups)];
237 afs_sys_call_table[_S(__NR_setgroups)] = POINTER2SYSCALL afs_xsetgroups;
239 #if defined(__NR_setgroups32)
240 /* setup setgroups32 */
241 sys_setgroups32p = SYSCALL2POINTER afs_sys_call_table[__NR_setgroups32];
242 afs_sys_call_table[__NR_setgroups32] = POINTER2SYSCALL afs_xsetgroups32;
245 #endif /* !AFS_IA64_LINUX20_ENV */
249 #ifdef AFS_AMD64_LINUX20_ENV
250 afs_ia32_sys_call_table = osi_find_syscall_table(1);
251 if (afs_ia32_sys_call_table) {
252 /* setup AFS entry point for IA32 */
253 ia32_ni_syscall = afs_ia32_sys_call_table[__NR_ia32_afs_syscall];
254 afs_ia32_sys_call_table[__NR_ia32_afs_syscall] =
255 POINTER2SYSCALL afs_syscall;
257 /* setup setgroups for IA32 */
259 SYSCALL2POINTER afs_ia32_sys_call_table[__NR_ia32_setgroups];
260 afs_ia32_sys_call_table[__NR_ia32_setgroups] =
261 POINTER2SYSCALL afs32_xsetgroups;
264 /* setup setgroups32 for IA32 */
266 SYSCALL2POINTER afs_ia32_sys_call_table[__NR_ia32_setgroups32];
267 afs_ia32_sys_call_table[__NR_ia32_setgroups32] =
268 POINTER2SYSCALL afs32_xsetgroups32;
269 #endif /* __NR_ia32_setgroups32 */
271 #endif /* AFS_AMD64_LINUX20_ENV */
275 #ifdef AFS_PPC64_LINUX20_ENV
276 /* XXX no 32-bit syscalls on PPC64? */
280 /***** SPARC64 *****/
281 #ifdef AFS_SPARC64_LINUX20_ENV
282 afs_sys_call_table32 = osi_find_syscall_table(1);
283 if (afs_sys_call_table32) {
284 /* setup AFS entry point for 32-bit SPARC */
285 afs_ni_syscall32 = afs_sys_call_table32[__NR_afs_syscall];
286 afs_sys_call_table32[__NR_afs_syscall] = POINTER2SYSCALL afs_syscall32;
288 /* setup setgroups for 32-bit SPARC */
289 sys32_setgroupsp = SYSCALL2POINTER afs_sys_call_table32[__NR_setgroups];
290 afs_sys_call_table32[__NR_setgroups] = POINTER2SYSCALL afs32_xsetgroups;
292 #ifdef AFS_LINUX24_ENV
293 /* setup setgroups32 for 32-bit SPARC */
295 SYSCALL2POINTER afs_sys_call_table32[__NR_setgroups32];
296 afs_sys_call_table32[__NR_setgroups32] =
297 POINTER2SYSCALL afs32_xsetgroups32;
300 #endif /* AFS_SPARC64_LINUX20_ENV */
306 /**********************************************************************/
307 /************************ System Call Cleanup *************************/
308 /**********************************************************************/
310 void osi_syscall_clean(void)
313 if (afs_sys_call_table) {
314 /* put back the AFS entry point */
315 afs_sys_call_table[_S(__NR_afs_syscall)] = afs_ni_syscall;
317 /* put back setgroups */
318 #if defined(AFS_IA64_LINUX20_ENV)
319 afs_sys_call_table[_S(__NR_setgroups)] =
320 POINTER2SYSCALL((struct fptr *)sys_setgroupsp)->ip;
321 #else /* AFS_IA64_LINUX20_ENV */
322 afs_sys_call_table[_S(__NR_setgroups)] =
323 POINTER2SYSCALL sys_setgroupsp;
326 #if defined(__NR_setgroups32) && !defined(AFS_IA64_LINUX20_ENV)
327 /* put back setgroups32 */
328 afs_sys_call_table[__NR_setgroups32] = POINTER2SYSCALL sys_setgroups32p;
334 #ifdef AFS_IA64_LINUX20_ENV
335 /* XXX no 32-bit syscalls on IA64? */
340 #ifdef AFS_AMD64_LINUX20_ENV
341 if (afs_ia32_sys_call_table) {
342 /* put back AFS entry point for IA32 */
343 afs_ia32_sys_call_table[__NR_ia32_afs_syscall] =
344 POINTER2SYSCALL ia32_ni_syscall;
346 /* put back setgroups for IA32 */
347 afs_ia32_sys_call_table[__NR_ia32_setgroups] =
348 POINTER2SYSCALL sys32_setgroupsp;
350 #ifdef AFS_LINUX24_ENV
351 /* put back setgroups32 for IA32 */
352 afs_ia32_sys_call_table[__NR_ia32_setgroups32] =
353 POINTER2SYSCALL sys32_setgroups32p;
360 #ifdef AFS_PPC64_LINUX20_ENV
361 /* XXX no 32-bit syscalls on PPC64? */
365 /***** SPARC64 *****/
366 #ifdef AFS_SPARC64_LINUX20_ENV
367 if (afs_sys_call_table32) {
368 /* put back AFS entry point for 32-bit SPARC */
369 afs_sys_call_table32[__NR_afs_syscall] = afs_ni_syscall32;
371 /* put back setgroups for IA32 */
372 afs_sys_call_table32[__NR_setgroups] =
373 POINTER2SYSCALL sys32_setgroupsp;
375 #ifdef AFS_LINUX24_ENV
376 /* put back setgroups32 for IA32 */
377 afs_sys_call_table32[__NR_setgroups32] =
378 POINTER2SYSCALL sys32_setgroups32p;