Commit | Line | Data |
---|---|---|
805e021f CE |
1 | /* |
2 | * Copyright 2000, International Business Machines Corporation and others. | |
3 | * All Rights Reserved. | |
4 | * | |
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 | |
8 | */ | |
9 | ||
10 | /* | |
11 | * Linux module support routines. | |
12 | * | |
13 | */ | |
14 | #include <afsconfig.h> | |
15 | #include "afs/param.h" | |
16 | ||
17 | #ifdef LINUX_KEYRING_SUPPORT | |
18 | /* The syscall probing stuff is unnecessary (and is never called) if we have | |
19 | * keyrings support; we rely on keyrings instead of group ids to track PAGs. | |
20 | * So if we have keyrings, just stub out the syscall functions to do nothing. */ | |
21 | int | |
22 | osi_syscall_init(void) | |
23 | { | |
24 | return 0; | |
25 | } | |
26 | void | |
27 | osi_syscall_clean(void) | |
28 | { | |
29 | return; | |
30 | } | |
31 | ||
32 | #else /* LINUX_KEYRING_SUPPORT */ | |
33 | ||
34 | #include <linux/module.h> /* early to avoid printf->printk mapping */ | |
35 | #include "afs/sysincludes.h" | |
36 | #include "afsincludes.h" | |
37 | #include <linux/unistd.h> /* For syscall numbers. */ | |
38 | #include <linux/mm.h> | |
39 | ||
40 | #ifdef AFS_AMD64_LINUX20_ENV | |
41 | #include <asm/ia32_unistd.h> | |
42 | #endif | |
43 | ||
44 | #include <linux/proc_fs.h> | |
45 | #include <linux/slab.h> | |
46 | #include <linux/init.h> | |
47 | #include <linux/sched.h> | |
48 | ||
49 | #ifndef NR_syscalls | |
50 | #define NR_syscalls 222 | |
51 | #endif | |
52 | ||
53 | /* On SPARC64 and S390X, sys_call_table contains 32-bit entries | |
54 | * even though pointers are 64 bit quantities. | |
55 | * XXX unify this with osi_probe.c | |
56 | */ | |
57 | #if defined(AFS_SPARC64_LINUX20_ENV) || defined(AFS_S390X_LINUX24_ENV) | |
58 | #define SYSCALLTYPE unsigned int | |
59 | #define POINTER2SYSCALL (unsigned int)(unsigned long) | |
60 | #define SYSCALL2POINTER (void *)(long) | |
61 | #else | |
62 | #define SYSCALLTYPE void * | |
63 | #define POINTER2SYSCALL (void *) | |
64 | #define SYSCALL2POINTER (void *) | |
65 | #endif | |
66 | ||
67 | #if defined(AFS_S390X_LINUX24_ENV) | |
68 | #define INSERT_SYSCALL(SLOT, TMPPAGE, FUNC) \ | |
69 | if (SYSCALL2POINTER FUNC > 0x7fffffff) { \ | |
70 | TMPPAGE = kmalloc ( PAGE_SIZE, GFP_DMA|GFP_KERNEL ); \ | |
71 | if (SYSCALL2POINTER TMPPAGE > 0x7fffffff) { \ | |
72 | printf("Cannot allocate page for FUNC syscall jump vector\n"); \ | |
73 | return EINVAL; \ | |
74 | } \ | |
75 | memcpy(TMPPAGE, syscall_jump_code, sizeof(syscall_jump_code)); \ | |
76 | *(void **)(TMPPAGE + 0x0c) = &FUNC; \ | |
77 | afs_sys_call_table[_S(SLOT)] = POINTER2SYSCALL TMPPAGE; \ | |
78 | } else \ | |
79 | afs_sys_call_table[_S(SLOT)] = POINTER2SYSCALL FUNC; | |
80 | #else | |
81 | #define INSERT_SYSCALL(SLOT, TMPPAGE, FUNC) \ | |
82 | afs_sys_call_table[_S(SLOT)] = POINTER2SYSCALL FUNC; | |
83 | #endif | |
84 | ||
85 | #if defined(AFS_IA64_LINUX20_ENV) | |
86 | #define _S(x) ((x)-1024) | |
87 | #else | |
88 | #define _S(x) x | |
89 | #endif | |
90 | ||
91 | ||
92 | /***** ALL PLATFORMS *****/ | |
93 | extern asmlinkage long | |
94 | afs_syscall(long syscall, long parm1, long parm2, long parm3, long parm4); | |
95 | ||
96 | static SYSCALLTYPE *afs_sys_call_table; | |
97 | static SYSCALLTYPE afs_ni_syscall = 0; | |
98 | ||
99 | #ifdef AFS_S390X_LINUX24_ENV | |
100 | static void *afs_sys_setgroups_page = 0; | |
101 | #if defined(__NR_setgroups32) | |
102 | static void *afs_sys_setgroups32_page = 0; | |
103 | #endif | |
104 | static void *afs_syscall_page = 0; | |
105 | ||
106 | /* Because of how the syscall table is handled, we need to ensure our | |
107 | syscalls are within the first 2gb of address space. This means we need | |
108 | self-modifying code we can inject to call our handlers if the module | |
109 | is loaded high. If keyrings had advanced as fast as false protection | |
110 | this would be unnecessary. */ | |
111 | ||
112 | uint32_t syscall_jump_code[] = { | |
113 | 0xe3d0f030, 0x00240dd0, 0xa7f40006, 0xffffffff, 0xffffffff, 0xe310d004, | |
114 | 0x0004e3d0, 0xf0300004, 0x07f10000, | |
115 | }; | |
116 | #endif | |
117 | ||
118 | extern asmlinkage long afs_xsetgroups(int gidsetsize, gid_t * grouplist); | |
119 | asmlinkage long (*sys_setgroupsp) (int gidsetsize, gid_t * grouplist); | |
120 | ||
121 | extern asmlinkage long afs_xsetgroups32(int gidsetsize, gid_t * grouplist); | |
122 | asmlinkage int (*sys_setgroups32p) (int gidsetsize, | |
123 | __kernel_gid32_t * grouplist); | |
124 | ||
125 | /***** AMD64 *****/ | |
126 | #ifdef AFS_AMD64_LINUX20_ENV | |
127 | static SYSCALLTYPE *afs_ia32_sys_call_table; | |
128 | static SYSCALLTYPE ia32_ni_syscall = 0; | |
129 | ||
130 | extern asmlinkage long afs32_xsetgroups(int gidsetsize, u16 * grouplist); | |
131 | asmlinkage long (*sys32_setgroupsp) (int gidsetsize, u16 * grouplist); | |
132 | extern asmlinkage long afs32_xsetgroups32(int gidsetsize, gid_t * grouplist); | |
133 | asmlinkage long (*sys32_setgroups32p) (int gidsetsize, gid_t * grouplist); | |
134 | #endif /* AFS_AMD64_LINUX20_ENV */ | |
135 | ||
136 | ||
137 | /***** PPC64 *****/ | |
138 | #ifdef AFS_PPC64_LINUX26_ENV | |
139 | static SYSCALLTYPE *afs_sys_call_table32; | |
140 | static SYSCALLTYPE afs_ni_syscall32 = 0; | |
141 | static SYSCALLTYPE old_sys_setgroupsp = 0; | |
142 | static SYSCALLTYPE old_sys32_setgroupsp = 0; | |
143 | ||
144 | asmlinkage long afs32_xsetgroups(int gidsetsize, gid_t *grouplist); | |
145 | asmlinkage long (*sys32_setgroupsp)(int gidsetsize, gid_t *grouplist); | |
146 | ||
147 | asmlinkage long sys_close(unsigned int fd); | |
148 | static void sys_setgroups_stub(void) | |
149 | __attribute__ ((pure,const,no_instrument_function)); | |
150 | static void sys_setgroups_stub(void) | |
151 | { | |
152 | printf("*** error! sys_setgroups_stub called\n"); | |
153 | } | |
154 | ||
155 | static void sys32_setgroups_stub(void) | |
156 | __attribute__ ((pure,const,no_instrument_function)); | |
157 | static void sys32_setgroups_stub(void) | |
158 | { | |
159 | printf("*** error! sys32_setgroups_stub called\n"); | |
160 | } | |
161 | ||
162 | #endif /* AFS_PPC64_LINUX26_ENV */ | |
163 | ||
164 | ||
165 | /***** SPARC64 *****/ | |
166 | #ifdef AFS_SPARC64_LINUX26_ENV | |
167 | static SYSCALLTYPE *afs_sys_call_table32; | |
168 | static SYSCALLTYPE afs_ni_syscall32 = 0; | |
169 | ||
170 | extern asmlinkage long afs32_xsetgroups(int gidsetsize, u16 * grouplist); | |
171 | asmlinkage int (*sys32_setgroupsp) (int gidsetsize, | |
172 | __kernel_gid32_t * grouplist); | |
173 | /* This number is not exported for some bizarre reason. */ | |
174 | #define __NR_setgroups32 82 | |
175 | extern asmlinkage long afs32_xsetgroups32(int gidsetsize, gid_t * grouplist); | |
176 | asmlinkage int (*sys32_setgroups32p) (int gidsetsize, | |
177 | __kernel_gid32_t * grouplist); | |
178 | ||
179 | asmlinkage int | |
180 | afs_syscall32(long syscall, long parm1, long parm2, long parm3, long parm4, | |
181 | long parm5) | |
182 | { | |
183 | __asm__ __volatile__("srl %o4, 0, %o4\n\t" | |
184 | "mov %o7, %i7\n\t" | |
185 | "call afs_syscall\n\t" | |
186 | "srl %o5, 0, %o5\n\t" | |
187 | "ret\n\t" | |
188 | "nop"); | |
189 | } | |
190 | #endif /* AFS_SPARC64_LINUX20_ENV */ | |
191 | ||
192 | ||
193 | /***** IA64 *****/ | |
194 | #ifdef AFS_IA64_LINUX20_ENV | |
195 | ||
196 | asmlinkage long | |
197 | afs_syscall_stub(int r0, int r1, long r2, long r3, long r4, long gp) | |
198 | { | |
199 | __asm__ __volatile__("alloc r42 = ar.pfs, 8, 3, 6, 0\n\t" | |
200 | "mov r41 = b0\n\t" /* save rp */ | |
201 | "mov out0 = in0\n\t" | |
202 | "mov out1 = in1\n\t" | |
203 | "mov out2 = in2\n\t" | |
204 | "mov out3 = in3\n\t" | |
205 | "mov out4 = in4\n\t" | |
206 | "mov out5 = gp\n\t" /* save gp */ | |
207 | ";;\n" | |
208 | ".L1:\n\t" | |
209 | "mov r3 = ip\n\t" | |
210 | ";;\n\t" | |
211 | "addl r15=.fptr_afs_syscall-.L1,r3\n\t" | |
212 | ";;\n\t" | |
213 | "ld8 r15=[r15]\n\t" | |
214 | ";;\n\t" | |
215 | "ld8 r16=[r15],8\n\t" | |
216 | ";;\n\t" | |
217 | "ld8 gp=[r15]\n\t" | |
218 | "mov b6=r16\n\t" | |
219 | "br.call.sptk.many b0 = b6\n\t" | |
220 | ";;\n\t" | |
221 | "mov ar.pfs = r42\n\t" | |
222 | "mov b0 = r41\n\t" | |
223 | "mov gp = r48\n\t" /* restore gp */ | |
224 | "br.ret.sptk.many b0\n" | |
225 | ".fptr_afs_syscall:\n\t" | |
226 | "data8 @fptr(afs_syscall)\n\t" | |
227 | ".skip 8"); | |
228 | } | |
229 | ||
230 | asmlinkage long | |
231 | afs_xsetgroups_stub(int r0, int r1, long r2, long r3, long r4, long gp) | |
232 | { | |
233 | __asm__ __volatile__("alloc r42 = ar.pfs, 8, 3, 6, 0\n\t" | |
234 | "mov r41 = b0\n\t" /* save rp */ | |
235 | "mov out0 = in0\n\t" | |
236 | "mov out1 = in1\n\t" | |
237 | "mov out2 = in2\n\t" | |
238 | "mov out3 = in3\n\t" | |
239 | "mov out4 = in4\n\t" | |
240 | "mov out5 = gp\n\t" /* save gp */ | |
241 | ";;\n" | |
242 | ".L2:\n\t" | |
243 | "mov r3 = ip\n\t" | |
244 | ";;\n\t" | |
245 | "addl r15=.fptr_afs_xsetgroups - .L2,r3\n\t" | |
246 | ";;\n\t" | |
247 | "ld8 r15=[r15]\n\t" | |
248 | ";;\n\t" | |
249 | "ld8 r16=[r15],8\n\t" | |
250 | ";;\n\t" | |
251 | "ld8 gp=[r15]\n\t" | |
252 | "mov b6=r16\n\t" | |
253 | "br.call.sptk.many b0 = b6\n\t" | |
254 | ";;\n\t" | |
255 | "mov ar.pfs = r42\n\t" | |
256 | "mov b0 = r41\n\t" | |
257 | "mov gp = r48\n\t" /* restore gp */ | |
258 | "br.ret.sptk.many b0\n" | |
259 | ".fptr_afs_xsetgroups:\n\t" | |
260 | "data8 @fptr(afs_xsetgroups)\n\t" | |
261 | ".skip 8"); | |
262 | } | |
263 | ||
264 | struct fptr { | |
265 | void *ip; | |
266 | unsigned long gp; | |
267 | }; | |
268 | ||
269 | #endif /* AFS_IA64_LINUX20_ENV */ | |
270 | ||
271 | /***** PPC64 ***** | |
272 | * Spring 2005 | |
273 | * sys_call_table hook for PPC64 | |
274 | * by Soewono Effendi <Soewono.Effendi@sysgo.de> | |
275 | * for IBM Deutschland | |
276 | * Thanks go to SYSGO's team for their support: | |
277 | * Horst Birthelmer <Horst.Birthelmer@sysgo.de> | |
278 | * Marius Groeger <Marius.Groeger@sysgo.de> | |
279 | */ | |
280 | #if defined(AFS_PPC64_LINUX26_ENV) | |
281 | extern void flush_cache(void *, unsigned long); | |
282 | #define PPC_LO(v) ((v) & 0xffff) | |
283 | #define PPC_HI(v) (((v) >> 16) & 0xffff) | |
284 | #define PPC_HA(v) PPC_HI ((v) + 0x8000) | |
285 | #define PPC_HLO(v) ((short)(((v) >> 32) & 0xffff)) | |
286 | #define PPC_HHI(v) ((short)(((v) >> 48) & 0xffff)) | |
287 | ||
288 | struct ppc64_opd | |
289 | { | |
290 | unsigned long funcaddr; | |
291 | unsigned long r2; | |
292 | }; | |
293 | ||
294 | struct ppc64_stub | |
295 | { | |
296 | unsigned char jump[136]; | |
297 | unsigned long r2; | |
298 | unsigned long lr; | |
299 | struct ppc64_opd opd; | |
300 | } __attribute__ ((packed)); | |
301 | ||
302 | /* a stub to fix up r2 (TOC ptr) and to jump to our sys_call hook | |
303 | function. We patch the new r2 value and function pointer into | |
304 | the stub. */ | |
305 | #define PPC64_STUB(stub) \ | |
306 | static struct ppc64_stub stub = \ | |
307 | { .jump = { \ | |
308 | 0xf8, 0x41, 0x00, 0x28, /* std r2,40(r1) */ \ | |
309 | 0xfb, 0xc1, 0xff, 0xf0, /* std r30,-16(r1) */ \ | |
310 | 0xfb, 0xa1, 0xff, 0xe8, /* std r29,-24(r1) */ \ | |
311 | 0x7c, 0x5d, 0x13, 0x78, /* mr r29,r2 */ \ | |
312 | 0x3c, 0x40, 0x12, 0x34, /*16: lis r2,4660 */ \ | |
313 | 0x60, 0x42, 0x56, 0x78, /*20: ori r2,r2,22136 */ \ | |
314 | 0x78, 0x42, 0x07, 0xc6, /* rldicr r2,r2,32,31 */ \ | |
315 | 0x64, 0x42, 0x90, 0xab, /*28: oris r2,r2,37035 */ \ | |
316 | 0x60, 0x42, 0xcd, 0xef, /*32: ori r2,r2,52719 */ \ | |
317 | 0x3f, 0xc2, 0x00, 0x00, /*36: addis r30,r2,0 */ \ | |
318 | 0x3b, 0xde, 0x00, 0x00, /*40: addi r30,r30,0 */ \ | |
319 | 0xfb, 0xbe, 0x00, 0x88, /* std r29,136(r30) */ \ | |
320 | 0x7f, 0xa8, 0x02, 0xa6, /* mflr r29 */ \ | |
321 | 0xfb, 0xbe, 0x00, 0x90, /* std r29,144(r30) */ \ | |
322 | 0xeb, 0xde, 0x00, 0x98, /* ld r30,152(r30) */ \ | |
323 | 0x7f, 0xc8, 0x03, 0xa6, /* mtlr r30 */ \ | |
324 | 0xeb, 0xa1, 0xff, 0xe8, /* ld r29,-24(r1) */ \ | |
325 | 0xeb, 0xc1, 0xff, 0xf0, /* ld r30,-16(r1) */ \ | |
326 | 0x4e, 0x80, 0x00, 0x21, /* blrl */ \ | |
327 | 0x3c, 0x40, 0x12, 0x34, /*76: lis r2,4660 */ \ | |
328 | 0x60, 0x42, 0x56, 0x78, /*80: ori r2,r2,22136 */ \ | |
329 | 0x78, 0x42, 0x07, 0xc6, /* rldicr r2,r2,32,31 */ \ | |
330 | 0x64, 0x42, 0x90, 0xab, /*88: oris r2,r2,37035 */ \ | |
331 | 0x60, 0x42, 0xcd, 0xef, /*92: ori r2,r2,52719 */ \ | |
332 | 0xfb, 0xc1, 0xff, 0xf0, /* std r30,-16(r1) */ \ | |
333 | 0xfb, 0xa1, 0xff, 0xe8, /* std r29,-24(r1) */ \ | |
334 | 0x3f, 0xc2, 0xab, 0xcd, /*104: addis r30,r2,-21555 */ \ | |
335 | 0x3b, 0xde, 0x78, 0x90, /*108: addi r30,r30,30864 */ \ | |
336 | 0xeb, 0xbe, 0x00, 0x90, /* ld r29,144(r30) */ \ | |
337 | 0x7f, 0xa8, 0x03, 0xa6, /* mtlr r29 */ \ | |
338 | 0xe8, 0x5e, 0x00, 0x88, /* ld r2,136(r30) */ \ | |
339 | 0xeb, 0xa1, 0xff, 0xe8, /* ld r29,-24(r1) */ \ | |
340 | 0xeb, 0xc1, 0xff, 0xf0, /* ld r30,-16(r1) */ \ | |
341 | 0x4e, 0x80, 0x00, 0x20 /* blr */ \ | |
342 | }} | |
343 | ||
344 | static void * create_stub(struct ppc64_stub *stub, | |
345 | struct ppc64_opd *opd) | |
346 | { | |
347 | unsigned short *p1, *p2, *p3, *p4; | |
348 | unsigned long addr; | |
349 | ||
350 | stub->opd.funcaddr = opd->funcaddr; | |
351 | stub->opd.r2 = opd->r2; | |
352 | addr = (unsigned long) opd->r2; | |
353 | p1 = (unsigned short*) &stub->jump[18]; | |
354 | p2 = (unsigned short*) &stub->jump[22]; | |
355 | p3 = (unsigned short*) &stub->jump[30]; | |
356 | p4 = (unsigned short*) &stub->jump[34]; | |
357 | ||
358 | *p1 = PPC_HHI(addr); | |
359 | *p2 = PPC_HLO(addr); | |
360 | *p3 = PPC_HI(addr); | |
361 | *p4 = PPC_LO(addr); | |
362 | ||
363 | addr = (unsigned long) stub - opd->r2; | |
364 | p1 = (unsigned short*) &stub->jump[38]; | |
365 | p2 = (unsigned short*) &stub->jump[42]; | |
366 | *p1 = PPC_HA(addr); | |
367 | *p2 = PPC_LO(addr); | |
368 | p1 = (unsigned short*) &stub->jump[106]; | |
369 | p2 = (unsigned short*) &stub->jump[110]; | |
370 | *p1 = PPC_HA(addr); | |
371 | *p2 = PPC_LO(addr); | |
372 | ||
373 | addr = (unsigned long) opd->r2; | |
374 | p1 = (unsigned short*) &stub->jump[78]; | |
375 | p2 = (unsigned short*) &stub->jump[82]; | |
376 | p3 = (unsigned short*) &stub->jump[90]; | |
377 | p4 = (unsigned short*) &stub->jump[94]; | |
378 | ||
379 | *p1 = PPC_HHI(addr); | |
380 | *p2 = PPC_HLO(addr); | |
381 | *p3 = PPC_HI(addr); | |
382 | *p4 = PPC_LO(addr); | |
383 | ||
384 | flush_cache((void *)stub, sizeof(*stub)); | |
385 | return ((void*)(stub)); | |
386 | } | |
387 | ||
388 | PPC64_STUB(afs_sys_call_stub); | |
389 | PPC64_STUB(afs_xsetgroups_stub); | |
390 | PPC64_STUB(afs_xsetgroups32_stub); | |
391 | #endif /* AFS_PPC64_LINUX26_ENV */ | |
392 | ||
393 | ||
394 | /**********************************************************************/ | |
395 | /********************* System Call Initialization *********************/ | |
396 | /**********************************************************************/ | |
397 | ||
398 | int osi_syscall_init(void) | |
399 | { | |
400 | /***** IA64 *****/ | |
401 | #ifdef AFS_IA64_LINUX20_ENV | |
402 | /* This needs to be first because we are declaring variables, and | |
403 | * also because the handling of syscall pointers is bizarre enough | |
404 | * that we want to special-case even the "common" part. | |
405 | */ | |
406 | unsigned long kernel_gp = 0; | |
407 | static struct fptr sys_setgroups; | |
408 | ||
409 | afs_sys_call_table = osi_find_syscall_table(0); | |
410 | if (afs_sys_call_table) { | |
411 | ||
412 | /* check we aren't already loaded */ | |
413 | /* XXX this can't be right */ | |
414 | if (SYSCALL2POINTER afs_sys_call_table[_S(__NR_afs_syscall)] | |
415 | == afs_syscall) { | |
416 | printf("AFS syscall entry point already in use!\n"); | |
417 | return -EBUSY; | |
418 | } | |
419 | ||
420 | /* setup AFS entry point */ | |
421 | afs_ni_syscall = afs_sys_call_table[_S(__NR_afs_syscall)]; | |
422 | afs_sys_call_table[_S(__NR_afs_syscall)] = | |
423 | POINTER2SYSCALL((struct fptr *)afs_syscall_stub)->ip; | |
424 | ||
425 | /* setup setgroups */ | |
426 | sys_setgroupsp = (void *)&sys_setgroups; | |
427 | ||
428 | ((struct fptr *)sys_setgroupsp)->ip = | |
429 | SYSCALL2POINTER afs_sys_call_table[_S(__NR_setgroups)]; | |
430 | ((struct fptr *)sys_setgroupsp)->gp = kernel_gp; | |
431 | ||
432 | afs_sys_call_table[_S(__NR_setgroups)] = | |
433 | POINTER2SYSCALL((struct fptr *)afs_xsetgroups_stub)->ip; | |
434 | } | |
435 | ||
436 | /* XXX no 32-bit syscalls on IA64? */ | |
437 | ||
438 | ||
439 | #elif defined(AFS_PPC64_LINUX26_ENV) | |
440 | ||
441 | afs_sys_call_table = osi_find_syscall_table(0); | |
442 | if (afs_sys_call_table) { | |
443 | SYSCALLTYPE p; | |
444 | struct ppc64_opd* opd = (struct ppc64_opd*) sys_close; | |
445 | unsigned long r2 = opd->r2; | |
446 | opd = (struct ppc64_opd*) afs_syscall; | |
447 | afs_sys_call_table32 = (unsigned long)afs_sys_call_table - | |
448 | NR_syscalls * sizeof(SYSCALLTYPE); | |
449 | /* check we aren't already loaded */ | |
450 | p = SYSCALL2POINTER afs_sys_call_table[_S(__NR_afs_syscall)]; | |
451 | if ((unsigned long)p == opd->funcaddr) { | |
452 | printf("AFS syscall entry point already in use!\n"); | |
453 | return -EBUSY; | |
454 | } | |
455 | /* setup AFS entry point */ | |
456 | p = create_stub(&afs_sys_call_stub, opd); | |
457 | afs_ni_syscall = afs_sys_call_table[_S(__NR_afs_syscall)]; | |
458 | afs_sys_call_table[_S(__NR_afs_syscall)] = POINTER2SYSCALL p; | |
459 | ||
460 | /* setup setgroups */ | |
461 | opd = (struct ppc64_opd*) afs_xsetgroups; | |
462 | p = create_stub(&afs_xsetgroups_stub, opd); | |
463 | old_sys_setgroupsp = SYSCALL2POINTER afs_sys_call_table[_S(__NR_setgroups)]; | |
464 | afs_sys_call_table[_S(__NR_setgroups)] = POINTER2SYSCALL p; | |
465 | opd = (struct ppc64_opd*) sys_setgroups_stub; | |
466 | opd->funcaddr = old_sys_setgroupsp; | |
467 | opd->r2 = r2; | |
468 | ||
469 | /* setup setgroups32 */ | |
470 | opd = (struct ppc64_opd*) afs32_xsetgroups; | |
471 | p = create_stub(&afs_xsetgroups32_stub, opd); | |
472 | old_sys32_setgroupsp = SYSCALL2POINTER afs_sys_call_table32[_S(__NR_setgroups)]; | |
473 | afs_sys_call_table32[_S(__NR_setgroups)] = POINTER2SYSCALL p; | |
474 | opd = (struct ppc64_opd*) sys32_setgroups_stub; | |
475 | opd->funcaddr = old_sys32_setgroupsp; | |
476 | opd->r2 = r2; | |
477 | ||
478 | flush_cache((void *)afs_sys_call_table, 2*NR_syscalls*sizeof(void*)); | |
479 | ||
480 | sys_setgroupsp = POINTER2SYSCALL sys_setgroups_stub; | |
481 | sys32_setgroupsp = POINTER2SYSCALL sys32_setgroups_stub; | |
482 | } | |
483 | /***** COMMON (except IA64 or PPC64) *****/ | |
484 | #else /* !AFS_IA64_LINUX20_ENV */ | |
485 | ||
486 | afs_sys_call_table = osi_find_syscall_table(0); | |
487 | if (afs_sys_call_table) { | |
488 | ||
489 | /* check we aren't already loaded */ | |
490 | if (SYSCALL2POINTER afs_sys_call_table[_S(__NR_afs_syscall)] | |
491 | == afs_syscall) { | |
492 | printf("AFS syscall entry point already in use!\n"); | |
493 | return -EBUSY; | |
494 | } | |
495 | ||
496 | /* setup AFS entry point */ | |
497 | afs_ni_syscall = afs_sys_call_table[_S(__NR_afs_syscall)]; | |
498 | ||
499 | INSERT_SYSCALL(__NR_afs_syscall, afs_syscall_page, afs_syscall) | |
500 | ||
501 | /* setup setgroups */ | |
502 | sys_setgroupsp = SYSCALL2POINTER afs_sys_call_table[_S(__NR_setgroups)]; | |
503 | INSERT_SYSCALL(__NR_setgroups, afs_sys_setgroups_page, afs_xsetgroups) | |
504 | ||
505 | #if defined(__NR_setgroups32) | |
506 | /* setup setgroups32 */ | |
507 | sys_setgroups32p = SYSCALL2POINTER afs_sys_call_table[__NR_setgroups32]; | |
508 | INSERT_SYSCALL(__NR_setgroups32, afs_sys_setgroups32_page, afs_xsetgroups32) | |
509 | #endif | |
510 | } | |
511 | #endif /* !AFS_IA64_LINUX20_ENV */ | |
512 | ||
513 | ||
514 | /***** AMD64 *****/ | |
515 | #ifdef AFS_AMD64_LINUX20_ENV | |
516 | afs_ia32_sys_call_table = osi_find_syscall_table(1); | |
517 | if (afs_ia32_sys_call_table) { | |
518 | /* setup AFS entry point for IA32 */ | |
519 | ia32_ni_syscall = afs_ia32_sys_call_table[__NR_ia32_afs_syscall]; | |
520 | afs_ia32_sys_call_table[__NR_ia32_afs_syscall] = | |
521 | POINTER2SYSCALL afs_syscall; | |
522 | ||
523 | /* setup setgroups for IA32 */ | |
524 | sys32_setgroupsp = | |
525 | SYSCALL2POINTER afs_ia32_sys_call_table[__NR_ia32_setgroups]; | |
526 | afs_ia32_sys_call_table[__NR_ia32_setgroups] = | |
527 | POINTER2SYSCALL afs32_xsetgroups; | |
528 | ||
529 | /* setup setgroups32 for IA32 */ | |
530 | sys32_setgroups32p = | |
531 | SYSCALL2POINTER afs_ia32_sys_call_table[__NR_ia32_setgroups32]; | |
532 | afs_ia32_sys_call_table[__NR_ia32_setgroups32] = | |
533 | POINTER2SYSCALL afs32_xsetgroups32; | |
534 | } | |
535 | #endif /* AFS_AMD64_LINUX20_ENV */ | |
536 | ||
537 | ||
538 | /***** SPARC64 *****/ | |
539 | #ifdef AFS_SPARC64_LINUX20_ENV | |
540 | afs_sys_call_table32 = osi_find_syscall_table(1); | |
541 | if (afs_sys_call_table32) { | |
542 | /* setup AFS entry point for 32-bit SPARC */ | |
543 | afs_ni_syscall32 = afs_sys_call_table32[__NR_afs_syscall]; | |
544 | afs_sys_call_table32[__NR_afs_syscall] = POINTER2SYSCALL afs_syscall32; | |
545 | ||
546 | /* setup setgroups for 32-bit SPARC */ | |
547 | sys32_setgroupsp = SYSCALL2POINTER afs_sys_call_table32[__NR_setgroups]; | |
548 | afs_sys_call_table32[__NR_setgroups] = POINTER2SYSCALL afs32_xsetgroups; | |
549 | ||
550 | /* setup setgroups32 for 32-bit SPARC */ | |
551 | sys32_setgroups32p = | |
552 | SYSCALL2POINTER afs_sys_call_table32[__NR_setgroups32]; | |
553 | afs_sys_call_table32[__NR_setgroups32] = | |
554 | POINTER2SYSCALL afs32_xsetgroups32; | |
555 | } | |
556 | #endif /* AFS_SPARC64_LINUX20_ENV */ | |
557 | return 0; | |
558 | } | |
559 | ||
560 | ||
561 | ||
562 | /**********************************************************************/ | |
563 | /************************ System Call Cleanup *************************/ | |
564 | /**********************************************************************/ | |
565 | ||
566 | void osi_syscall_clean(void) | |
567 | { | |
568 | /***** COMMON *****/ | |
569 | if (afs_sys_call_table) { | |
570 | /* put back the AFS entry point */ | |
571 | afs_sys_call_table[_S(__NR_afs_syscall)] = afs_ni_syscall; | |
572 | ||
573 | /* put back setgroups */ | |
574 | #if defined(AFS_IA64_LINUX20_ENV) | |
575 | afs_sys_call_table[_S(__NR_setgroups)] = | |
576 | POINTER2SYSCALL((struct fptr *)sys_setgroupsp)->ip; | |
577 | #elif defined(AFS_PPC64_LINUX26_ENV) | |
578 | afs_sys_call_table[_S(__NR_setgroups)] = | |
579 | POINTER2SYSCALL old_sys_setgroupsp; | |
580 | /* put back setgroups32 for PPC64 */ | |
581 | afs_sys_call_table32[__NR_setgroups] = | |
582 | POINTER2SYSCALL old_sys32_setgroupsp; | |
583 | #else /* AFS_IA64_LINUX20_ENV */ | |
584 | afs_sys_call_table[_S(__NR_setgroups)] = | |
585 | POINTER2SYSCALL sys_setgroupsp; | |
586 | #endif | |
587 | ||
588 | #if defined(__NR_setgroups32) && !defined(AFS_IA64_LINUX20_ENV) | |
589 | /* put back setgroups32 */ | |
590 | afs_sys_call_table[__NR_setgroups32] = POINTER2SYSCALL sys_setgroups32p; | |
591 | #endif | |
592 | #if defined(AFS_S390X_LINUX24_ENV) | |
593 | #if defined(__NR_setgroups32) && !defined(AFS_IA64_LINUX20_ENV) | |
594 | if (afs_sys_setgroups32_page) | |
595 | kfree(afs_sys_setgroups32_page); | |
596 | #endif | |
597 | if (afs_sys_setgroups_page) | |
598 | kfree(afs_sys_setgroups_page); | |
599 | if (afs_syscall_page) | |
600 | kfree(afs_syscall_page); | |
601 | #endif | |
602 | } | |
603 | ||
604 | ||
605 | /***** IA64 *****/ | |
606 | #ifdef AFS_IA64_LINUX20_ENV | |
607 | /* XXX no 32-bit syscalls on IA64? */ | |
608 | #endif | |
609 | ||
610 | ||
611 | /***** AMD64 *****/ | |
612 | #ifdef AFS_AMD64_LINUX20_ENV | |
613 | if (afs_ia32_sys_call_table) { | |
614 | /* put back AFS entry point for IA32 */ | |
615 | afs_ia32_sys_call_table[__NR_ia32_afs_syscall] = | |
616 | POINTER2SYSCALL ia32_ni_syscall; | |
617 | ||
618 | /* put back setgroups for IA32 */ | |
619 | afs_ia32_sys_call_table[__NR_ia32_setgroups] = | |
620 | POINTER2SYSCALL sys32_setgroupsp; | |
621 | ||
622 | /* put back setgroups32 for IA32 */ | |
623 | afs_ia32_sys_call_table[__NR_ia32_setgroups32] = | |
624 | POINTER2SYSCALL sys32_setgroups32p; | |
625 | } | |
626 | #endif | |
627 | ||
628 | ||
629 | /***** SPARC64 *****/ | |
630 | #ifdef AFS_SPARC64_LINUX20_ENV | |
631 | if (afs_sys_call_table32) { | |
632 | /* put back AFS entry point for 32-bit SPARC */ | |
633 | afs_sys_call_table32[__NR_afs_syscall] = afs_ni_syscall32; | |
634 | ||
635 | /* put back setgroups for IA32 */ | |
636 | afs_sys_call_table32[__NR_setgroups] = | |
637 | POINTER2SYSCALL sys32_setgroupsp; | |
638 | ||
639 | /* put back setgroups32 for IA32 */ | |
640 | afs_sys_call_table32[__NR_setgroups32] = | |
641 | POINTER2SYSCALL sys32_setgroups32p; | |
642 | } | |
643 | #endif | |
644 | } | |
645 | ||
646 | #endif /* !LINUX_KEYRING_SUPPORT */ |