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"
19 #include "../afs/sysincludes.h"
20 #include "../afs/afsincludes.h"
21 #include "../h/unistd.h" /* For syscall numbers. */
24 #include <linux/module.h>
25 #include <linux/slab.h>
26 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
27 #include <linux/init.h>
32 #ifdef AFS_SPARC64_LINUX24_ENV
33 #define __NR_setgroups32 82 /* This number is not exported for some bizarre reason. */
36 asmlinkage int (*sys_settimeofdayp)(struct timeval *tv, struct timezone *tz);
37 #if !defined(AFS_ALPHA_LINUX20_ENV)
38 asmlinkage int (*sys_socketcallp)(int call, long *args);
39 #endif /* no socketcall on alpha */
40 asmlinkage int (*sys_killp)(int pid, int signal);
41 asmlinkage long (*sys_setgroupsp)(int gidsetsize, gid_t *grouplist);
43 #ifdef AFS_SPARC64_LINUX20_ENV
44 extern unsigned int sys_call_table[]; /* changed to uint because SPARC64 has syscaltable of 32bit items */
46 extern void * sys_call_table[]; /* safer for other linuces */
48 extern struct file_system_type afs_file_system;
50 static long get_page_offset(void);
52 #if defined(AFS_LINUX24_ENV)
53 DECLARE_MUTEX(afs_global_lock);
55 struct semaphore afs_global_lock = MUTEX;
57 int afs_global_owner = 0;
58 unsigned long afs_linux_page_offset = 0; /* contains the PAGE_OFFSET value */
60 /* Since sys_ni_syscall is not exported, I need to cache it in order to restore
63 #ifdef AFS_SPARC64_LINUX20_ENV
64 static unsigned int afs_ni_syscall = 0;
66 static void* afs_ni_syscall = 0;
69 #ifdef AFS_SPARC64_LINUX20_ENV
70 static unsigned int afs_ni_syscall32 = 0;
71 asmlinkage int (*sys32_setgroupsp)(int gidsetsize, __kernel_gid_t32 *grouplist);
72 #if defined(__NR_setgroups32)
73 asmlinkage int (*sys32_setgroups32p)(int gidsetsize, __kernel_gid_t32 *grouplist);
75 extern unsigned int sys_call_table32[];
77 asmlinkage int afs_syscall32(long syscall, long parm1, long parm2, long parm3,
78 long parm4, long parm5)
80 __asm__ __volatile__ ("
91 #ifdef AFS_IA64_LINUX20_ENV
92 unsigned char ia64_syscall_stub[] =
94 0x00, 0x50, 0x45, 0x16, 0x80, 0x05, // [MII] alloc r42=ar.pfs,8,3,6,0
95 0x90, 0x02, 0x00, 0x62, 0x00, 0x60, // mov r41=b0
96 0x05, 0x00, 0x01, 0x84, // mov r43=r32
97 0x00, 0x60, 0x01, 0x42, 0x00, 0x21, // [MII] mov r44=r33
98 0xd0, 0x02, 0x88, 0x00, 0x42, 0xc0, // mov r45=r34
99 0x05, 0x18, 0x01, 0x84, // mov r46=r35
100 0x0d, 0x78, 0x01, 0x48, 0x00, 0x21, // [MFI] mov r47=r36
101 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, // nop.f 0x0
102 0x06, 0x08, 0x00, 0x84, // mov r48=gp;;
103 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, // [MLX] nop.m 0x0
104 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, // movl r15=0x0;;
105 0x01, 0x00, 0x00, 0x60, //
106 0x0a, 0x80, 0x20, 0x1e, 0x18, 0x14, // [MMI] ld8 r16=[r15],8;;
107 0x10, 0x00, 0x3c, 0x30, 0x20, 0xc0, // ld8 gp=[r15]
108 0x00, 0x09, 0x00, 0x07, // mov b6=r16
109 0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, // [MFB] nop.m 0x0
110 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, // nop.f 0x0
111 0x68, 0x00, 0x00, 0x10, // br.call.sptk.many b0=b6;;
112 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, // [MII] nop.m 0x0
113 0x00, 0x50, 0x01, 0x55, 0x00, 0x00, // mov.i ar.pfs=r42
114 0x90, 0x0a, 0x00, 0x07, // mov b0=r41
115 0x1d, 0x08, 0x00, 0x60, 0x00, 0x21, // [MFB] mov gp=r48
116 0x00, 0x00, 0x00, 0x02, 0x00, 0x80, // nop.f 0x0
117 0x08, 0x00, 0x84, 0x00 // br.ret.sptk.many b0;;
120 void ia64_imm64_fixup(unsigned long v, void *code)
122 unsigned long *bundle = (unsigned long *) code;
127 insn = ((v & 0x8000000000000000) >> 27) | ((v & 0x0000000000200000)) |
128 ((v & 0x00000000001f0000) << 6) | ((v & 0x000000000000ff80) << 20) |
129 ((v & 0x000000000000007f) << 13);
131 slot1 = (v & 0x7fffffffffc00000) >> 22;
133 *bundle |= slot1 << 46;
134 *(bundle+1) |= insn << 23;
135 *(bundle+1) |= slot1 >> 18;
138 unsigned char *afs_syscall_stub, *afs_xsetgroups_stub;
146 #endif /* AFS_IA64_LINUX20_ENV */
148 #ifdef AFS_LINUX24_ENV
149 asmlinkage int (*sys_setgroups32p)(int gidsetsize, __kernel_gid32_t *grouplist);
152 #ifdef AFS_SPARC64_LINUX20_ENV
153 #define POINTER2SYSCALL (unsigned int)(unsigned long)
154 #define SYSCALL2POINTER (void *)(long)
156 #define POINTER2SYSCALL (void *)
157 #define SYSCALL2POINTER (void *)
160 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
161 int __init afs_init(void)
163 int init_module(void)
166 #if defined(AFS_IA64_LINUX20_ENV)
167 unsigned long kernel_gp;
168 static struct fptr sys_kill, sys_settimeofday, sys_setgroups;
170 extern int afs_syscall();
171 extern long afs_xsetgroups();
172 #if defined(__NR_setgroups32)
173 extern int afs_xsetgroups32();
175 #ifdef AFS_SPARC64_LINUX20_ENV
176 extern int afs32_xsetgroups();
177 #if defined(__NR_setgroups32)
178 extern int afs32_xsetgroups32();
184 /* obtain PAGE_OFFSET value */
185 afs_linux_page_offset = get_page_offset();
187 #ifndef AFS_S390_LINUX22_ENV
188 if (afs_linux_page_offset == 0) {
189 /* couldn't obtain page offset so can't continue */
190 printf("afs: Unable to obtain PAGE_OFFSET. Exiting..");
195 /* Initialize pointers to kernel syscalls. */
196 #if defined(AFS_IA64_LINUX20_ENV)
197 kernel_gp = ((struct fptr *)printk)->gp;
199 sys_settimeofdayp = (void *) &sys_settimeofday;
200 sys_killp = (void *) &sys_kill;
202 ((struct fptr *)sys_settimeofdayp)->ip =
203 SYSCALL2POINTER sys_call_table[__NR_settimeofday - 1024];
204 ((struct fptr *)sys_settimeofdayp)->gp = kernel_gp;
206 ((struct fptr *)sys_killp)->ip =
207 SYSCALL2POINTER sys_call_table[__NR_kill - 1024];
208 ((struct fptr *)sys_killp)->gp = kernel_gp;
209 #else /* !AFS_IA64_LINUX20_ENV */
210 sys_settimeofdayp = SYSCALL2POINTER sys_call_table[__NR_settimeofday];
211 #ifdef __NR_socketcall
212 sys_socketcallp = SYSCALL2POINTER sys_call_table[__NR_socketcall];
213 #endif /* no socketcall on alpha */
214 sys_killp = SYSCALL2POINTER sys_call_table[__NR_kill];
215 #endif /* AFS_IA64_LINUX20_ENV */
217 /* setup AFS entry point. */
219 #if defined(AFS_IA64_LINUX20_ENV)
220 SYSCALL2POINTER sys_call_table[__NR_afs_syscall - 1024]
222 SYSCALL2POINTER sys_call_table[__NR_afs_syscall]
225 printf("AFS syscall entry point already in use!\n");
230 #if defined(AFS_IA64_LINUX20_ENV)
231 afs_ni_syscall = sys_call_table[__NR_afs_syscall - 1024];
233 afs_syscall_stub = (void *) kmalloc(sizeof(ia64_syscall_stub), GFP_KERNEL);
234 memcpy(afs_syscall_stub, ia64_syscall_stub, sizeof(ia64_syscall_stub));
235 ia64_imm64_fixup((unsigned long)afs_syscall, afs_syscall_stub+0x30);
236 sys_call_table[__NR_afs_syscall - 1024] = POINTER2SYSCALL afs_syscall_stub;
237 #else /* AFS_IA64_LINUX20_ENV */
238 afs_ni_syscall = sys_call_table[__NR_afs_syscall];
239 sys_call_table[__NR_afs_syscall] = POINTER2SYSCALL afs_syscall;
240 # ifdef AFS_SPARC64_LINUX20_ENV
241 afs_ni_syscall32 = sys_call_table32[__NR_afs_syscall];
242 sys_call_table32[__NR_afs_syscall] = POINTER2SYSCALL afs_syscall32;
244 #endif /* AFS_IA64_LINUX20_ENV */
247 register_filesystem(&afs_file_system);
249 /* Intercept setgroups calls */
250 #if defined(AFS_IA64_LINUX20_ENV)
251 sys_setgroupsp = (void *) &sys_setgroups;
253 afs_xsetgroups_stub = (void *) kmalloc(sizeof(ia64_syscall_stub), GFP_KERNEL);
254 memcpy(afs_xsetgroups_stub, ia64_syscall_stub, sizeof(ia64_syscall_stub));
255 ia64_imm64_fixup((unsigned long)afs_xsetgroups, afs_xsetgroups_stub+0x30);
257 ((struct fptr *)sys_setgroupsp)->ip =
258 SYSCALL2POINTER sys_call_table[__NR_setgroups - 1024];
259 ((struct fptr *)sys_setgroupsp)->gp = kernel_gp;
261 sys_call_table[__NR_setgroups - 1024] = POINTER2SYSCALL afs_xsetgroups_stub;
262 #else /* AFS_IA64_LINUX20_ENV */
263 sys_setgroupsp = SYSCALL2POINTER sys_call_table[__NR_setgroups];
264 sys_call_table[__NR_setgroups] = POINTER2SYSCALL afs_xsetgroups;
265 # ifdef AFS_SPARC64_LINUX20_ENV
266 sys32_setgroupsp = SYSCALL2POINTER sys_call_table32[__NR_setgroups];
267 sys_call_table32[__NR_setgroups] = POINTER2SYSCALL afs32_xsetgroups;
269 # if defined(__NR_setgroups32)
270 sys_setgroups32p = SYSCALL2POINTER sys_call_table[__NR_setgroups32];
271 sys_call_table[__NR_setgroups32] = POINTER2SYSCALL afs_xsetgroups32;
272 # ifdef AFS_SPARC64_LINUX20_ENV
273 sys32_setgroups32p = SYSCALL2POINTER sys_call_table32[__NR_setgroups32];
274 sys_call_table32[__NR_setgroups32] = POINTER2SYSCALL afs32_xsetgroups32;
277 #endif /* AFS_IA64_LINUX20_ENV */
284 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
285 void __exit afs_cleanup(void)
287 void cleanup_module(void)
290 struct task_struct *t;
294 #if defined(AFS_IA64_LINUX20_ENV)
295 sys_call_table[__NR_setgroups - 1024] = POINTER2SYSCALL ((struct fptr *) sys_setgroupsp)->ip;
296 sys_call_table[__NR_afs_syscall - 1024] = afs_ni_syscall;
297 #else /* AFS_IA64_LINUX20_ENV */
298 sys_call_table[__NR_setgroups] = POINTER2SYSCALL sys_setgroupsp;
299 sys_call_table[__NR_afs_syscall] = afs_ni_syscall;
300 # ifdef AFS_SPARC64_LINUX20_ENV
301 sys_call_table32[__NR_setgroups] = POINTER2SYSCALL sys32_setgroupsp;
302 sys_call_table32[__NR_afs_syscall] = afs_ni_syscall32;
304 # if defined(__NR_setgroups32)
305 sys_call_table[__NR_setgroups32] = POINTER2SYSCALL sys_setgroups32p;
306 # ifdef AFS_SPARC64_LINUX20_ENV
307 sys_call_table32[__NR_setgroups32] = POINTER2SYSCALL sys32_setgroups32p;
310 #endif /* AFS_IA64_LINUX20_ENV */
311 unregister_filesystem(&afs_file_system);
313 osi_linux_free_inode_pages(); /* Invalidate all pages using AFS inodes. */
314 osi_linux_free_afs_memory();
319 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
320 module_init(afs_init);
321 module_exit(afs_cleanup);
325 static long get_page_offset(void)
327 #if defined(AFS_PPC_LINUX22_ENV) || defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_SPARC_LINUX20_ENV) || defined(AFS_ALPHA_LINUX20_ENV) || defined(AFS_S390_LINUX22_ENV) || defined(AFS_IA64_LINUX20_ENV) || defined(AFS_PARISC_LINUX24_ENV)
330 struct task_struct *p;
332 /* search backward thru the circular list */
333 for(p = current; p; p = p->prev_task)
335 return p->addr_limit.seg;