#include <linux/unistd.h>
#include <linux/mm.h>
+#if defined(AFS_PPC64_LINUX26_ENV)
+#include <asm/abs_addr.h>
+#endif
+
#ifdef AFS_AMD64_LINUX20_ENV
#include <asm/ia32_unistd.h>
#endif
/* lower bound of valid kernel text pointers */
#ifdef AFS_IA64_LINUX20_ENV
#define ktxt_lower_bound (((unsigned long)&kernel_thread ) & 0xfff00000L)
+#elif defined(AFS_PPC64_LINUX20_ENV)
+#define ktxt_lower_bound (KERNELBASE)
#else
#define ktxt_lower_bound (((unsigned long)&kernel_thread ) & ~0xfffffL)
#endif
extern SYSCALLTYPE sys_call_table32[] __attribute__((weak));
extern SYSCALLTYPE sys_call_table_emu[] __attribute__((weak));
+extern asmlinkage ssize_t sys_read(unsigned int fd, char __user * buf, size_t count) __attribute__((weak));
extern asmlinkage long sys_close(unsigned int) __attribute__((weak));
extern asmlinkage long sys_chdir(const char *) __attribute__((weak));
extern asmlinkage ssize_t sys_write(unsigned int, const char *, size_t) __attribute__((weak));
(unsigned long)(&tasklist_lock) - 0x30000,
0,
0x6000,
+#elif defined(AFS_PPC64_LINUX26_ENV)
+ (unsigned long)(&do_signal),
+ 0xfff,
+ 0x400,
#elif defined(AFS_PPC_LINUX20_ENV) || defined(AFS_PPC_LINUX20_ENV)
(unsigned long)&init_mm,
0xffff,
/********** Probing Configuration: ppc64, sparc64 sys_call_table32 **********/
#elif defined(AFS_PPC64_LINUX20_ENV) || defined(AFS_SPARC64_LINUX20_ENV)
+struct fptr {
+ void *ip;
+ unsigned long gp;
+};
/*
* syscall pairs/triplets to probe
(unsigned long)(&sys_close),
0xfffff,
0x10000,
+#elif defined(AFS_PPC64_LINUX26_ENV)
+ (unsigned long)(&do_signal),
+ 0xfff,
+ 0x400,
#else
(unsigned long)&init_mm,
0,
return -1;
}
-static void *try(probectl *P, tryctl *T, PROBETYPE *ptr,
+static void *try(probectl *P, tryctl *T, PROBETYPE *aptr,
unsigned long datalen)
{
#ifdef OSI_PROBE_KALLSYMS
#endif
unsigned long offset, ip1, ip2, ip3;
int ret;
+ PROBETYPE *ptr;
-#ifdef AFS_IA64_LINUX20_ENV
+#if defined(AFS_IA64_LINUX20_ENV) || defined(AFS_PPC64_LINUX20_ENV)
ip1 = T->fn1 ? (unsigned long)((struct fptr *)T->fn1)->ip : 0;
ip2 = T->fn2 ? (unsigned long)((struct fptr *)T->fn2)->ip : 0;
ip3 = T->fn3 ? (unsigned long)((struct fptr *)T->fn3)->ip : 0;
if (!ip1 || !ip2 || (T->NR3 >= 0 && !ip3))
return 0;
- for (offset = 0; offset < datalen; offset++, ptr++) {
+ for (offset = 0; offset < datalen; offset++, aptr++) {
+#if defined(AFS_PPC64_LINUX20_ENV)
+ ptr = (PROBETYPE*)(*aptr);
+ if ((unsigned long)ptr <= KERNELBASE) {
+ continue;
+ }
+#else
+ ptr = aptr;
+#endif
ret = check_table(P, ptr);
if (ret >= 0) {
/* return value is number of entries to skip */
- ptr += ret;
+ aptr += ret;
offset += ret;
continue;
}
}
}
-#ifdef AFS_IA64_LINUX20_ENV
+#if defined(AFS_IA64_LINUX20_ENV) || defined(AFS_PPC64_LINUX20_ENV)
ip1 = P->verify_fn ? (unsigned long)((struct fptr *)(P->verify_fn))->ip : 0;
#else
ip1 = (unsigned long)(P->verify_fn);
#include <linux/sched.h>
#endif
+#ifndef NR_syscalls
+#define NR_syscalls 222
+#endif
/* On SPARC64 and S390X, sys_call_table contains 32-bit entries
* even though pointers are 64 bit quantities.
/***** PPC64 *****/
-#ifdef AFS_PPC64_LINUX20_ENV
-extern SYSCALLTYPE *afs_sys_call_table32;
+#ifdef AFS_PPC64_LINUX26_ENV
+static SYSCALLTYPE *afs_sys_call_table32;
static SYSCALLTYPE afs_ni_syscall32 = 0;
+static SYSCALLTYPE old_sys_setgroupsp = 0;
+static SYSCALLTYPE old_sys32_setgroupsp = 0;
extern int afs32_xsetgroups();
asmlinkage long (*sys32_setgroupsp)(int gidsetsize, gid_t *grouplist);
+
+asmlinkage long sys_close(unsigned int fd);
+static void sys_setgroups_stub()
+ __attribute__ ((pure,const,no_instrument_function));
+static void sys_setgroups_stub()
+{
+ printf("*** error! sys_setgroups_stub called\n");
+}
+
+static void sys32_setgroups_stub()
+ __attribute__ ((pure,const,no_instrument_function));
+static void sys32_setgroups_stub()
+{
+ printf("*** error! sys32_setgroups_stub called\n");
+}
+
#endif /* AFS_AMD64_LINUX20_ENV */
#endif /* AFS_IA64_LINUX20_ENV */
+/***** PPC64 *****
+ * Spring 2005
+ * sys_call_table hook for PPC64
+ * by Soewono Effendi <Soewono.Effendi@sysgo.de>
+ * for IBM Deutschland
+ * Thanks go to SYSGO's team for their support:
+ * Horst Birthelmer <Horst.Birthelmer@sysgo.de>
+ * Marius Groeger <Marius.Groeger@sysgo.de>
+ */
+#if defined(AFS_PPC64_LINUX26_ENV)
+extern void flush_cache(void *, unsigned long);
+#define PPC_LO(v) ((v) & 0xffff)
+#define PPC_HI(v) (((v) >> 16) & 0xffff)
+#define PPC_HA(v) PPC_HI ((v) + 0x8000)
+#define PPC_HLO(v) ((short)(((v) >> 32) & 0xffff))
+#define PPC_HHI(v) ((short)(((v) >> 48) & 0xffff))
+
+struct ppc64_opd
+{
+ unsigned long funcaddr;
+ unsigned long r2;
+};
+
+struct ppc64_stub
+{
+ unsigned char jump[136];
+ unsigned long r2;
+ unsigned long lr;
+ struct ppc64_opd opd;
+} __attribute__ ((packed));
+
+/* a stub to fix up r2 (TOC ptr) and to jump to our sys_call hook
+ function. We patch the new r2 value and function pointer into
+ the stub. */
+#define PPC64_STUB(stub) \
+static struct ppc64_stub stub = \
+{ .jump = { \
+ 0xf8, 0x41, 0x00, 0x28, /* std r2,40(r1) */ \
+ 0xfb, 0xc1, 0xff, 0xf0, /* std r30,-16(r1) */ \
+ 0xfb, 0xa1, 0xff, 0xe8, /* std r29,-24(r1) */ \
+ 0x7c, 0x5d, 0x13, 0x78, /* mr r29,r2 */ \
+ 0x3c, 0x40, 0x12, 0x34, /*16: lis r2,4660 */ \
+ 0x60, 0x42, 0x56, 0x78, /*20: ori r2,r2,22136 */ \
+ 0x78, 0x42, 0x07, 0xc6, /* rldicr r2,r2,32,31 */ \
+ 0x64, 0x42, 0x90, 0xab, /*28: oris r2,r2,37035 */ \
+ 0x60, 0x42, 0xcd, 0xef, /*32: ori r2,r2,52719 */ \
+ 0x3f, 0xc2, 0x00, 0x00, /*36: addis r30,r2,0 */ \
+ 0x3b, 0xde, 0x00, 0x00, /*40: addi r30,r30,0 */ \
+ 0xfb, 0xbe, 0x00, 0x88, /* std r29,136(r30) */ \
+ 0x7f, 0xa8, 0x02, 0xa6, /* mflr r29 */ \
+ 0xfb, 0xbe, 0x00, 0x90, /* std r29,144(r30) */ \
+ 0xeb, 0xde, 0x00, 0x98, /* ld r30,152(r30) */ \
+ 0x7f, 0xc8, 0x03, 0xa6, /* mtlr r30 */ \
+ 0xeb, 0xa1, 0xff, 0xe8, /* ld r29,-24(r1) */ \
+ 0xeb, 0xc1, 0xff, 0xf0, /* ld r30,-16(r1) */ \
+ 0x4e, 0x80, 0x00, 0x21, /* blrl */ \
+ 0x3c, 0x40, 0x12, 0x34, /*76: lis r2,4660 */ \
+ 0x60, 0x42, 0x56, 0x78, /*80: ori r2,r2,22136 */ \
+ 0x78, 0x42, 0x07, 0xc6, /* rldicr r2,r2,32,31 */ \
+ 0x64, 0x42, 0x90, 0xab, /*88: oris r2,r2,37035 */ \
+ 0x60, 0x42, 0xcd, 0xef, /*92: ori r2,r2,52719 */ \
+ 0xfb, 0xc1, 0xff, 0xf0, /* std r30,-16(r1) */ \
+ 0xfb, 0xa1, 0xff, 0xe8, /* std r29,-24(r1) */ \
+ 0x3f, 0xc2, 0xab, 0xcd, /*104: addis r30,r2,-21555 */ \
+ 0x3b, 0xde, 0x78, 0x90, /*108: addi r30,r30,30864 */ \
+ 0xeb, 0xbe, 0x00, 0x90, /* ld r29,144(r30) */ \
+ 0x7f, 0xa8, 0x03, 0xa6, /* mtlr r29 */ \
+ 0xe8, 0x5e, 0x00, 0x88, /* ld r2,136(r30) */ \
+ 0xeb, 0xa1, 0xff, 0xe8, /* ld r29,-24(r1) */ \
+ 0xeb, 0xc1, 0xff, 0xf0, /* ld r30,-16(r1) */ \
+ 0x4e, 0x80, 0x00, 0x20 /* blr */ \
+}}
+
+static void * create_stub(struct ppc64_stub *stub,
+ struct ppc64_opd *opd)
+{
+ unsigned short *p1, *p2, *p3, *p4;
+ unsigned long addr;
+
+ stub->opd.funcaddr = opd->funcaddr;
+ stub->opd.r2 = opd->r2;
+ addr = (unsigned long) opd->r2;
+ p1 = (unsigned short*) &stub->jump[18];
+ p2 = (unsigned short*) &stub->jump[22];
+ p3 = (unsigned short*) &stub->jump[30];
+ p4 = (unsigned short*) &stub->jump[34];
+
+ *p1 = PPC_HHI(addr);
+ *p2 = PPC_HLO(addr);
+ *p3 = PPC_HI(addr);
+ *p4 = PPC_LO(addr);
+
+ addr = (unsigned long) stub - opd->r2;
+ p1 = (unsigned short*) &stub->jump[38];
+ p2 = (unsigned short*) &stub->jump[42];
+ *p1 = PPC_HA(addr);
+ *p2 = PPC_LO(addr);
+ p1 = (unsigned short*) &stub->jump[106];
+ p2 = (unsigned short*) &stub->jump[110];
+ *p1 = PPC_HA(addr);
+ *p2 = PPC_LO(addr);
+
+ addr = (unsigned long) opd->r2;
+ p1 = (unsigned short*) &stub->jump[78];
+ p2 = (unsigned short*) &stub->jump[82];
+ p3 = (unsigned short*) &stub->jump[90];
+ p4 = (unsigned short*) &stub->jump[94];
+
+ *p1 = PPC_HHI(addr);
+ *p2 = PPC_HLO(addr);
+ *p3 = PPC_HI(addr);
+ *p4 = PPC_LO(addr);
+
+ flush_cache((void *)stub, sizeof(*stub));
+ return ((void*)(stub));
+}
+
+PPC64_STUB(afs_sys_call_stub);
+PPC64_STUB(afs_xsetgroups_stub);
+PPC64_STUB(afs_xsetgroups32_stub);
+#endif /* AFS_PPC64_LINUX26_ENV */
/**********************************************************************/
/* XXX no 32-bit syscalls on IA64? */
-/***** COMMON (except IA64) *****/
+#elif defined(AFS_PPC64_LINUX26_ENV)
+
+ afs_sys_call_table = osi_find_syscall_table(0);
+ if (afs_sys_call_table) {
+ SYSCALLTYPE p;
+ struct ppc64_opd* opd = (struct ppc64_opd*) sys_close;
+ unsigned long r2 = opd->r2;
+ opd = (struct ppc64_opd*) afs_syscall;
+ afs_sys_call_table32 = (unsigned long)afs_sys_call_table -
+ NR_syscalls * sizeof(SYSCALLTYPE);
+ /* check we aren't already loaded */
+ p = SYSCALL2POINTER afs_sys_call_table[_S(__NR_afs_syscall)];
+ if ((unsigned long)p == opd->funcaddr) {
+ printf("AFS syscall entry point already in use!\n");
+ return -EBUSY;
+ }
+ /* setup AFS entry point */
+ p = create_stub(&afs_sys_call_stub, opd);
+ afs_ni_syscall = afs_sys_call_table[_S(__NR_afs_syscall)];
+ afs_sys_call_table[_S(__NR_afs_syscall)] = POINTER2SYSCALL p;
+
+ /* setup setgroups */
+ opd = (struct ppc64_opd*) afs_xsetgroups;
+ p = create_stub(&afs_xsetgroups_stub, opd);
+ old_sys_setgroupsp = SYSCALL2POINTER afs_sys_call_table[_S(__NR_setgroups)];
+ afs_sys_call_table[_S(__NR_setgroups)] = POINTER2SYSCALL p;
+ opd = (struct ppc64_opd*) sys_setgroups_stub;
+ opd->funcaddr = old_sys_setgroupsp;
+ opd->r2 = r2;
+
+ /* setup setgroups32 */
+ opd = (struct ppc64_opd*) afs32_xsetgroups;
+ p = create_stub(&afs_xsetgroups32_stub, opd);
+ old_sys32_setgroupsp = SYSCALL2POINTER afs_sys_call_table32[_S(__NR_setgroups)];
+ afs_sys_call_table32[_S(__NR_setgroups)] = POINTER2SYSCALL p;
+ opd = (struct ppc64_opd*) sys32_setgroups_stub;
+ opd->funcaddr = old_sys32_setgroupsp;
+ opd->r2 = r2;
+
+ flush_cache((void *)afs_sys_call_table, 2*NR_syscalls*sizeof(void*));
+
+ sys_setgroupsp = sys_setgroups_stub;
+ sys32_setgroupsp = sys32_setgroups_stub;
+ }
+/***** COMMON (except IA64 or PPC64) *****/
#else /* !AFS_IA64_LINUX20_ENV */
afs_sys_call_table = osi_find_syscall_table(0);
#endif /* AFS_AMD64_LINUX20_ENV */
-/***** PPC64 *****/
-#ifdef AFS_PPC64_LINUX20_ENV
- /* XXX no 32-bit syscalls on PPC64? */
-#endif
-
-
/***** SPARC64 *****/
#ifdef AFS_SPARC64_LINUX20_ENV
afs_sys_call_table32 = osi_find_syscall_table(1);
#if defined(AFS_IA64_LINUX20_ENV)
afs_sys_call_table[_S(__NR_setgroups)] =
POINTER2SYSCALL((struct fptr *)sys_setgroupsp)->ip;
+#elif defined(AFS_PPC64_LINUX26_ENV)
+ afs_sys_call_table[_S(__NR_setgroups)] =
+ POINTER2SYSCALL old_sys_setgroupsp;
+ /* put back setgroups32 for PPC64 */
+ afs_sys_call_table32[__NR_setgroups] =
+ POINTER2SYSCALL old_sys32_setgroupsp;
#else /* AFS_IA64_LINUX20_ENV */
afs_sys_call_table[_S(__NR_setgroups)] =
POINTER2SYSCALL sys_setgroupsp;
#endif
-/***** PPC64 *****/
-#ifdef AFS_PPC64_LINUX20_ENV
- /* XXX no 32-bit syscalls on PPC64? */
-#endif
-
-
/***** SPARC64 *****/
#ifdef AFS_SPARC64_LINUX20_ENV
if (afs_sys_call_table32) {