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 #define NR_syscalls 222
43 /* On SPARC64 and S390X, sys_call_table contains 32-bit entries
44 * even though pointers are 64 bit quantities.
45 * XXX unify this with osi_probe.c
47 #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390X_LINUX24_ENV)
48 #define SYSCALLTYPE unsigned int
49 #define POINTER2SYSCALL (unsigned int)(unsigned long)
50 #define SYSCALL2POINTER (void *)(long)
52 #define SYSCALLTYPE void *
53 #define POINTER2SYSCALL (void *)
54 #define SYSCALL2POINTER (void *)
57 #if defined(AFS_S390X_LINUX24_ENV) && !defined(AFS_LINUX26_ENV)
58 #define _S(x) ((x)<<1)
59 #elif defined(AFS_IA64_LINUX20_ENV)
60 #define _S(x) ((x)-1024)
66 /***** ALL PLATFORMS *****/
67 extern asmlinkage long
68 afs_syscall(long syscall, long parm1, long parm2, long parm3, long parm4);
70 static SYSCALLTYPE *afs_sys_call_table;
71 static SYSCALLTYPE afs_ni_syscall = 0;
73 extern long afs_xsetgroups();
74 asmlinkage long (*sys_setgroupsp) (int gidsetsize, gid_t * grouplist);
76 #ifdef AFS_LINUX24_ENV
77 extern int afs_xsetgroups32();
78 asmlinkage int (*sys_setgroups32p) (int gidsetsize,
79 __kernel_gid32_t * grouplist);
82 #if !defined(AFS_LINUX24_ENV)
83 asmlinkage int (*sys_settimeofdayp) (struct timeval * tv, struct timezone * tz);
88 #ifdef AFS_AMD64_LINUX20_ENV
89 static SYSCALLTYPE *afs_ia32_sys_call_table;
90 static SYSCALLTYPE ia32_ni_syscall = 0;
92 extern int afs32_xsetgroups();
93 asmlinkage long (*sys32_setgroupsp) (int gidsetsize, u16 * grouplist);
94 #ifdef AFS_LINUX24_ENV
95 extern int afs32_xsetgroups32();
96 asmlinkage long (*sys32_setgroups32p) (int gidsetsize, gid_t * grouplist);
97 #endif /* __NR_ia32_setgroups32 */
98 #endif /* AFS_AMD64_LINUX20_ENV */
102 #ifdef AFS_PPC64_LINUX26_ENV
103 static SYSCALLTYPE *afs_sys_call_table32;
104 static SYSCALLTYPE afs_ni_syscall32 = 0;
105 static SYSCALLTYPE old_sys_setgroupsp = 0;
106 static SYSCALLTYPE old_sys32_setgroupsp = 0;
108 extern int afs32_xsetgroups();
109 asmlinkage long (*sys32_setgroupsp)(int gidsetsize, gid_t *grouplist);
111 asmlinkage long sys_close(unsigned int fd);
112 static void sys_setgroups_stub()
113 __attribute__ ((pure,const,no_instrument_function));
114 static void sys_setgroups_stub()
116 printf("*** error! sys_setgroups_stub called\n");
119 static void sys32_setgroups_stub()
120 __attribute__ ((pure,const,no_instrument_function));
121 static void sys32_setgroups_stub()
123 printf("*** error! sys32_setgroups_stub called\n");
126 #endif /* AFS_AMD64_LINUX20_ENV */
129 /***** SPARC64 *****/
130 #ifdef AFS_SPARC64_LINUX20_ENV
131 #ifdef AFS_SPARC64_LINUX26_ENV
132 static SYSCALLTYPE *afs_sys_call_table32;
134 extern SYSCALLTYPE *afs_sys_call_table32;
136 static SYSCALLTYPE afs_ni_syscall32 = 0;
138 extern int afs32_xsetgroups();
139 #ifdef AFS_SPARC64_LINUX26_ENV
140 asmlinkage int (*sys32_setgroupsp) (int gidsetsize,
141 __kernel_gid32_t * grouplist);
143 asmlinkage int (*sys32_setgroupsp) (int gidsetsize,
144 __kernel_gid_t32 * grouplist);
146 #ifdef AFS_LINUX24_ENV
147 /* This number is not exported for some bizarre reason. */
148 #define __NR_setgroups32 82
149 extern int afs32_xsetgroups32();
150 #ifdef AFS_SPARC64_LINUX26_ENV
151 asmlinkage int (*sys32_setgroups32p) (int gidsetsize,
152 __kernel_gid32_t * grouplist);
154 asmlinkage int (*sys32_setgroups32p) (int gidsetsize,
155 __kernel_gid_t32 * grouplist);
160 afs_syscall32(long syscall, long parm1, long parm2, long parm3, long parm4,
163 __asm__ __volatile__("srl %o4, 0, %o4\n\t"
165 "call afs_syscall\n\t"
166 "srl %o5, 0, %o5\n\t"
170 #endif /* AFS_SPARC64_LINUX20_ENV */
174 #ifdef AFS_IA64_LINUX20_ENV
177 afs_syscall_stub(int r0, int r1, long r2, long r3, long r4, long gp)
179 __asm__ __volatile__("alloc r42 = ar.pfs, 8, 3, 6, 0\n\t"
180 "mov r41 = b0\n\t" /* save rp */
186 "mov out5 = gp\n\t" /* save gp */
191 "addl r15=.fptr_afs_syscall-.L1,r3\n\t"
195 "ld8 r16=[r15],8\n\t"
199 "br.call.sptk.many b0 = b6\n\t"
201 "mov ar.pfs = r42\n\t"
203 "mov gp = r48\n\t" /* restore gp */
204 "br.ret.sptk.many b0\n"
205 ".fptr_afs_syscall:\n\t"
206 "data8 @fptr(afs_syscall)\n\t"
211 afs_xsetgroups_stub(int r0, int r1, long r2, long r3, long r4, long gp)
213 __asm__ __volatile__("alloc r42 = ar.pfs, 8, 3, 6, 0\n\t"
214 "mov r41 = b0\n\t" /* save rp */
220 "mov out5 = gp\n\t" /* save gp */
225 "addl r15=.fptr_afs_xsetgroups - .L2,r3\n\t"
229 "ld8 r16=[r15],8\n\t"
233 "br.call.sptk.many b0 = b6\n\t"
235 "mov ar.pfs = r42\n\t"
237 "mov gp = r48\n\t" /* restore gp */
238 "br.ret.sptk.many b0\n"
239 ".fptr_afs_xsetgroups:\n\t"
240 "data8 @fptr(afs_xsetgroups)\n\t"
249 #endif /* AFS_IA64_LINUX20_ENV */
253 * sys_call_table hook for PPC64
254 * by Soewono Effendi <Soewono.Effendi@sysgo.de>
255 * for IBM Deutschland
256 * Thanks go to SYSGO's team for their support:
257 * Horst Birthelmer <Horst.Birthelmer@sysgo.de>
258 * Marius Groeger <Marius.Groeger@sysgo.de>
260 #if defined(AFS_PPC64_LINUX26_ENV)
261 extern void flush_cache(void *, unsigned long);
262 #define PPC_LO(v) ((v) & 0xffff)
263 #define PPC_HI(v) (((v) >> 16) & 0xffff)
264 #define PPC_HA(v) PPC_HI ((v) + 0x8000)
265 #define PPC_HLO(v) ((short)(((v) >> 32) & 0xffff))
266 #define PPC_HHI(v) ((short)(((v) >> 48) & 0xffff))
270 unsigned long funcaddr;
276 unsigned char jump[136];
279 struct ppc64_opd opd;
280 } __attribute__ ((packed));
282 /* a stub to fix up r2 (TOC ptr) and to jump to our sys_call hook
283 function. We patch the new r2 value and function pointer into
285 #define PPC64_STUB(stub) \
286 static struct ppc64_stub stub = \
288 0xf8, 0x41, 0x00, 0x28, /* std r2,40(r1) */ \
289 0xfb, 0xc1, 0xff, 0xf0, /* std r30,-16(r1) */ \
290 0xfb, 0xa1, 0xff, 0xe8, /* std r29,-24(r1) */ \
291 0x7c, 0x5d, 0x13, 0x78, /* mr r29,r2 */ \
292 0x3c, 0x40, 0x12, 0x34, /*16: lis r2,4660 */ \
293 0x60, 0x42, 0x56, 0x78, /*20: ori r2,r2,22136 */ \
294 0x78, 0x42, 0x07, 0xc6, /* rldicr r2,r2,32,31 */ \
295 0x64, 0x42, 0x90, 0xab, /*28: oris r2,r2,37035 */ \
296 0x60, 0x42, 0xcd, 0xef, /*32: ori r2,r2,52719 */ \
297 0x3f, 0xc2, 0x00, 0x00, /*36: addis r30,r2,0 */ \
298 0x3b, 0xde, 0x00, 0x00, /*40: addi r30,r30,0 */ \
299 0xfb, 0xbe, 0x00, 0x88, /* std r29,136(r30) */ \
300 0x7f, 0xa8, 0x02, 0xa6, /* mflr r29 */ \
301 0xfb, 0xbe, 0x00, 0x90, /* std r29,144(r30) */ \
302 0xeb, 0xde, 0x00, 0x98, /* ld r30,152(r30) */ \
303 0x7f, 0xc8, 0x03, 0xa6, /* mtlr r30 */ \
304 0xeb, 0xa1, 0xff, 0xe8, /* ld r29,-24(r1) */ \
305 0xeb, 0xc1, 0xff, 0xf0, /* ld r30,-16(r1) */ \
306 0x4e, 0x80, 0x00, 0x21, /* blrl */ \
307 0x3c, 0x40, 0x12, 0x34, /*76: lis r2,4660 */ \
308 0x60, 0x42, 0x56, 0x78, /*80: ori r2,r2,22136 */ \
309 0x78, 0x42, 0x07, 0xc6, /* rldicr r2,r2,32,31 */ \
310 0x64, 0x42, 0x90, 0xab, /*88: oris r2,r2,37035 */ \
311 0x60, 0x42, 0xcd, 0xef, /*92: ori r2,r2,52719 */ \
312 0xfb, 0xc1, 0xff, 0xf0, /* std r30,-16(r1) */ \
313 0xfb, 0xa1, 0xff, 0xe8, /* std r29,-24(r1) */ \
314 0x3f, 0xc2, 0xab, 0xcd, /*104: addis r30,r2,-21555 */ \
315 0x3b, 0xde, 0x78, 0x90, /*108: addi r30,r30,30864 */ \
316 0xeb, 0xbe, 0x00, 0x90, /* ld r29,144(r30) */ \
317 0x7f, 0xa8, 0x03, 0xa6, /* mtlr r29 */ \
318 0xe8, 0x5e, 0x00, 0x88, /* ld r2,136(r30) */ \
319 0xeb, 0xa1, 0xff, 0xe8, /* ld r29,-24(r1) */ \
320 0xeb, 0xc1, 0xff, 0xf0, /* ld r30,-16(r1) */ \
321 0x4e, 0x80, 0x00, 0x20 /* blr */ \
324 static void * create_stub(struct ppc64_stub *stub,
325 struct ppc64_opd *opd)
327 unsigned short *p1, *p2, *p3, *p4;
330 stub->opd.funcaddr = opd->funcaddr;
331 stub->opd.r2 = opd->r2;
332 addr = (unsigned long) opd->r2;
333 p1 = (unsigned short*) &stub->jump[18];
334 p2 = (unsigned short*) &stub->jump[22];
335 p3 = (unsigned short*) &stub->jump[30];
336 p4 = (unsigned short*) &stub->jump[34];
343 addr = (unsigned long) stub - opd->r2;
344 p1 = (unsigned short*) &stub->jump[38];
345 p2 = (unsigned short*) &stub->jump[42];
348 p1 = (unsigned short*) &stub->jump[106];
349 p2 = (unsigned short*) &stub->jump[110];
353 addr = (unsigned long) opd->r2;
354 p1 = (unsigned short*) &stub->jump[78];
355 p2 = (unsigned short*) &stub->jump[82];
356 p3 = (unsigned short*) &stub->jump[90];
357 p4 = (unsigned short*) &stub->jump[94];
364 flush_cache((void *)stub, sizeof(*stub));
365 return ((void*)(stub));
368 PPC64_STUB(afs_sys_call_stub);
369 PPC64_STUB(afs_xsetgroups_stub);
370 PPC64_STUB(afs_xsetgroups32_stub);
371 #endif /* AFS_PPC64_LINUX26_ENV */
374 /**********************************************************************/
375 /********************* System Call Initialization *********************/
376 /**********************************************************************/
378 int osi_syscall_init(void)
381 #ifdef AFS_IA64_LINUX20_ENV
382 /* This needs to be first because we are declaring variables, and
383 * also because the handling of syscall pointers is bizarre enough
384 * that we want to special-case even the "common" part.
386 unsigned long kernel_gp = 0;
387 static struct fptr sys_setgroups;
389 afs_sys_call_table = osi_find_syscall_table(0);
390 if (afs_sys_call_table) {
392 #if !defined(AFS_LINUX24_ENV)
393 /* XXX no sys_settimeofday on IA64? */
396 /* check we aren't already loaded */
397 /* XXX this can't be right */
398 if (SYSCALL2POINTER afs_sys_call_table[_S(__NR_afs_syscall)]
400 printf("AFS syscall entry point already in use!\n");
404 /* setup AFS entry point */
405 afs_ni_syscall = afs_sys_call_table[_S(__NR_afs_syscall)];
406 afs_sys_call_table[_S(__NR_afs_syscall)] =
407 POINTER2SYSCALL((struct fptr *)afs_syscall_stub)->ip;
409 /* setup setgroups */
410 sys_setgroupsp = (void *)&sys_setgroups;
412 ((struct fptr *)sys_setgroupsp)->ip =
413 SYSCALL2POINTER afs_sys_call_table[_S(__NR_setgroups)];
414 ((struct fptr *)sys_setgroupsp)->gp = kernel_gp;
416 afs_sys_call_table[_S(__NR_setgroups)] =
417 POINTER2SYSCALL((struct fptr *)afs_xsetgroups_stub)->ip;
420 /* XXX no 32-bit syscalls on IA64? */
423 #elif defined(AFS_PPC64_LINUX26_ENV)
425 afs_sys_call_table = osi_find_syscall_table(0);
426 if (afs_sys_call_table) {
428 struct ppc64_opd* opd = (struct ppc64_opd*) sys_close;
429 unsigned long r2 = opd->r2;
430 opd = (struct ppc64_opd*) afs_syscall;
431 afs_sys_call_table32 = (unsigned long)afs_sys_call_table -
432 NR_syscalls * sizeof(SYSCALLTYPE);
433 /* check we aren't already loaded */
434 p = SYSCALL2POINTER afs_sys_call_table[_S(__NR_afs_syscall)];
435 if ((unsigned long)p == opd->funcaddr) {
436 printf("AFS syscall entry point already in use!\n");
439 /* setup AFS entry point */
440 p = create_stub(&afs_sys_call_stub, opd);
441 afs_ni_syscall = afs_sys_call_table[_S(__NR_afs_syscall)];
442 afs_sys_call_table[_S(__NR_afs_syscall)] = POINTER2SYSCALL p;
444 /* setup setgroups */
445 opd = (struct ppc64_opd*) afs_xsetgroups;
446 p = create_stub(&afs_xsetgroups_stub, opd);
447 old_sys_setgroupsp = SYSCALL2POINTER afs_sys_call_table[_S(__NR_setgroups)];
448 afs_sys_call_table[_S(__NR_setgroups)] = POINTER2SYSCALL p;
449 opd = (struct ppc64_opd*) sys_setgroups_stub;
450 opd->funcaddr = old_sys_setgroupsp;
453 /* setup setgroups32 */
454 opd = (struct ppc64_opd*) afs32_xsetgroups;
455 p = create_stub(&afs_xsetgroups32_stub, opd);
456 old_sys32_setgroupsp = SYSCALL2POINTER afs_sys_call_table32[_S(__NR_setgroups)];
457 afs_sys_call_table32[_S(__NR_setgroups)] = POINTER2SYSCALL p;
458 opd = (struct ppc64_opd*) sys32_setgroups_stub;
459 opd->funcaddr = old_sys32_setgroupsp;
462 flush_cache((void *)afs_sys_call_table, 2*NR_syscalls*sizeof(void*));
464 sys_setgroupsp = sys_setgroups_stub;
465 sys32_setgroupsp = sys32_setgroups_stub;
467 /***** COMMON (except IA64 or PPC64) *****/
468 #else /* !AFS_IA64_LINUX20_ENV */
470 afs_sys_call_table = osi_find_syscall_table(0);
471 if (afs_sys_call_table) {
472 #if !defined(AFS_LINUX24_ENV)
474 SYSCALL2POINTER afs_sys_call_table[_S(__NR_settimeofday)];
475 #endif /* AFS_LINUX24_ENV */
477 /* check we aren't already loaded */
478 if (SYSCALL2POINTER afs_sys_call_table[_S(__NR_afs_syscall)]
480 printf("AFS syscall entry point already in use!\n");
484 /* setup AFS entry point */
485 afs_ni_syscall = afs_sys_call_table[_S(__NR_afs_syscall)];
486 afs_sys_call_table[_S(__NR_afs_syscall)] = POINTER2SYSCALL afs_syscall;
488 /* setup setgroups */
489 sys_setgroupsp = SYSCALL2POINTER afs_sys_call_table[_S(__NR_setgroups)];
490 afs_sys_call_table[_S(__NR_setgroups)] = POINTER2SYSCALL afs_xsetgroups;
492 #if defined(__NR_setgroups32)
493 /* setup setgroups32 */
494 sys_setgroups32p = SYSCALL2POINTER afs_sys_call_table[__NR_setgroups32];
495 afs_sys_call_table[__NR_setgroups32] = POINTER2SYSCALL afs_xsetgroups32;
498 #endif /* !AFS_IA64_LINUX20_ENV */
502 #ifdef AFS_AMD64_LINUX20_ENV
503 afs_ia32_sys_call_table = osi_find_syscall_table(1);
504 if (afs_ia32_sys_call_table) {
505 /* setup AFS entry point for IA32 */
506 ia32_ni_syscall = afs_ia32_sys_call_table[__NR_ia32_afs_syscall];
507 afs_ia32_sys_call_table[__NR_ia32_afs_syscall] =
508 POINTER2SYSCALL afs_syscall;
510 /* setup setgroups for IA32 */
512 SYSCALL2POINTER afs_ia32_sys_call_table[__NR_ia32_setgroups];
513 afs_ia32_sys_call_table[__NR_ia32_setgroups] =
514 POINTER2SYSCALL afs32_xsetgroups;
517 /* setup setgroups32 for IA32 */
519 SYSCALL2POINTER afs_ia32_sys_call_table[__NR_ia32_setgroups32];
520 afs_ia32_sys_call_table[__NR_ia32_setgroups32] =
521 POINTER2SYSCALL afs32_xsetgroups32;
522 #endif /* __NR_ia32_setgroups32 */
524 #endif /* AFS_AMD64_LINUX20_ENV */
527 /***** SPARC64 *****/
528 #ifdef AFS_SPARC64_LINUX20_ENV
529 afs_sys_call_table32 = osi_find_syscall_table(1);
530 if (afs_sys_call_table32) {
531 /* setup AFS entry point for 32-bit SPARC */
532 afs_ni_syscall32 = afs_sys_call_table32[__NR_afs_syscall];
533 afs_sys_call_table32[__NR_afs_syscall] = POINTER2SYSCALL afs_syscall32;
535 /* setup setgroups for 32-bit SPARC */
536 sys32_setgroupsp = SYSCALL2POINTER afs_sys_call_table32[__NR_setgroups];
537 afs_sys_call_table32[__NR_setgroups] = POINTER2SYSCALL afs32_xsetgroups;
539 #ifdef AFS_LINUX24_ENV
540 /* setup setgroups32 for 32-bit SPARC */
542 SYSCALL2POINTER afs_sys_call_table32[__NR_setgroups32];
543 afs_sys_call_table32[__NR_setgroups32] =
544 POINTER2SYSCALL afs32_xsetgroups32;
547 #endif /* AFS_SPARC64_LINUX20_ENV */
553 /**********************************************************************/
554 /************************ System Call Cleanup *************************/
555 /**********************************************************************/
557 void osi_syscall_clean(void)
560 if (afs_sys_call_table) {
561 /* put back the AFS entry point */
562 afs_sys_call_table[_S(__NR_afs_syscall)] = afs_ni_syscall;
564 /* put back setgroups */
565 #if defined(AFS_IA64_LINUX20_ENV)
566 afs_sys_call_table[_S(__NR_setgroups)] =
567 POINTER2SYSCALL((struct fptr *)sys_setgroupsp)->ip;
568 #elif defined(AFS_PPC64_LINUX26_ENV)
569 afs_sys_call_table[_S(__NR_setgroups)] =
570 POINTER2SYSCALL old_sys_setgroupsp;
571 /* put back setgroups32 for PPC64 */
572 afs_sys_call_table32[__NR_setgroups] =
573 POINTER2SYSCALL old_sys32_setgroupsp;
574 #else /* AFS_IA64_LINUX20_ENV */
575 afs_sys_call_table[_S(__NR_setgroups)] =
576 POINTER2SYSCALL sys_setgroupsp;
579 #if defined(__NR_setgroups32) && !defined(AFS_IA64_LINUX20_ENV)
580 /* put back setgroups32 */
581 afs_sys_call_table[__NR_setgroups32] = POINTER2SYSCALL sys_setgroups32p;
587 #ifdef AFS_IA64_LINUX20_ENV
588 /* XXX no 32-bit syscalls on IA64? */
593 #ifdef AFS_AMD64_LINUX20_ENV
594 if (afs_ia32_sys_call_table) {
595 /* put back AFS entry point for IA32 */
596 afs_ia32_sys_call_table[__NR_ia32_afs_syscall] =
597 POINTER2SYSCALL ia32_ni_syscall;
599 /* put back setgroups for IA32 */
600 afs_ia32_sys_call_table[__NR_ia32_setgroups] =
601 POINTER2SYSCALL sys32_setgroupsp;
603 #ifdef AFS_LINUX24_ENV
604 /* put back setgroups32 for IA32 */
605 afs_ia32_sys_call_table[__NR_ia32_setgroups32] =
606 POINTER2SYSCALL sys32_setgroups32p;
612 /***** SPARC64 *****/
613 #ifdef AFS_SPARC64_LINUX20_ENV
614 if (afs_sys_call_table32) {
615 /* put back AFS entry point for 32-bit SPARC */
616 afs_sys_call_table32[__NR_afs_syscall] = afs_ni_syscall32;
618 /* put back setgroups for IA32 */
619 afs_sys_call_table32[__NR_setgroups] =
620 POINTER2SYSCALL sys32_setgroupsp;
622 #ifdef AFS_LINUX24_ENV
623 /* put back setgroups32 for IA32 */
624 afs_sys_call_table32[__NR_setgroups32] =
625 POINTER2SYSCALL sys32_setgroups32p;