/* Function to insert the current process's MM into the hash-table -- * necessary to trampoline syscalls back into the user library. The * trampoline_entry parameter is the address in the library we'll * trampoline to. * * Returns zero on success, or -ve error code on failure. */ int efab_linux_trampoline_register (ci_private_t *priv, void *arg) { const ci_tramp_reg_args_t *args = arg; int rc = 0; struct mm_hash *p; TRAMP_DEBUG ("Register entry-point 0x%"CI_PRIx64"(0x%"CI_PRIx64") for mm %p (pid %d)", args->trampoline_entry.ptr, args->trampoline_exclude.ptr, current->mm, current->pid); write_lock (&oo_mm_tbl_lock); p = oo_mm_tbl_lookup(current->mm); /* Either we found the entry on the hash table already, or we just created * one. Either way, update the trampoline entry-point */ if (!p) { /* This means current mm is not in the hash, implying that client * hasn't mmapped anything yet. Fail the request since we have no * way of cleaning up. */ ci_log("Unexpected trampoline registration with no maps"); rc = -ENOENT; goto exit; } ci_assert (p); ci_assert (p->mm == current->mm); p->trampoline_entry = args->trampoline_entry; p->trampoline_exclude = args->trampoline_exclude; p->trampoline_toc = args->trampoline_toc; p->trampoline_user_fixup = args->trampoline_user_fixup; CI_DEBUG(p->trampoline_ul_fail = args->trampoline_ul_fail;)
/* Trampoline into userland failure - this function is never called, and * would need to know whether userspace was 64 or 32 bit in order to * work out how to buld the trampoline, so it does nothing for now - rrw * 2012-12-14 */ void efab_linux_trampoline_ul_fail(void) { struct pt_regs *regs = 0; /* don't know how to do this on this platform */ struct mm_hash *p; ci_uintptr_t trampoline_ul_fail = 0; ci_assert(regs); if (current->mm) { read_lock (&oo_mm_tbl_lock); p = oo_mm_tbl_lookup(current->mm); read_unlock (&oo_mm_tbl_lock); if (p) { trampoline_ul_fail = (ci_uintptr_t) CI_USER_PTR_GET (p->trampoline_ul_fail); } else { ci_log("%s: no entry for pid %u", __FUNCTION__, current->tgid); return; } } else { ci_log("%s: pid %u is dying - no mm", __FUNCTION__, current->tgid); return; } ci_log("%s: syscall backtrace (pid %d)", __FUNCTION__, current->tgid); ci_backtrace(); ci_log("%s: provoking user-level fail on syscall exit for pid %d", __FUNCTION__, current->tgid); ci_log("(not really, don't know how on this platform)"); return; }
static int efab_signal_get_tramp_data(struct mm_signal_data **tramp_data) { struct mm_hash *p; read_lock (&oo_mm_tbl_lock); p = oo_mm_tbl_lookup(current->mm); if( p == NULL || CI_USER_PTR_GET(p->signal_data.user_data) == NULL) { read_unlock (&oo_mm_tbl_lock); return -ENOSYS; } efab_get_mm_hash_locked(p); *tramp_data = &p->signal_data; read_unlock (&oo_mm_tbl_lock); return 0; }
static int setup_trampoline(struct pt_regs *regs, int opcode, int arg, int bits) { struct mm_hash *p; ci_uintptr_t trampoline_entry = 0, trampoline_exclude = 0, trampoline_toc = 0, trampoline_fixup = 0; int rc = -EBADF; read_lock(&oo_mm_tbl_lock); p = oo_mm_tbl_lookup(current->mm); if (p) { trampoline_entry = (ci_uintptr_t) CI_USER_PTR_GET(p->trampoline_entry); trampoline_exclude = (ci_uintptr_t) CI_USER_PTR_GET(p->trampoline_exclude); trampoline_toc = (ci_uintptr_t) CI_USER_PTR_GET(p->trampoline_toc); trampoline_fixup = (ci_uintptr_t) CI_USER_PTR_GET(p->trampoline_user_fixup); } read_unlock(&oo_mm_tbl_lock); TRAMP_DEBUG("%s: trampoline_entry = %p \n", __func__, (void *)trampoline_entry); /* OK. We have the entry - set up a trampoline to user space */ if (trampoline_entry) { if (!access_ok(VERIFY_READ, trampoline_entry, 1)) { /* Can't read this address. Fail! */ ci_log("Pid %d (mm=%p) has bad trampoline entry: %p", current->tgid, current->mm, (void *)trampoline_entry); return -EBADF; } /* Check for the excluded address */ if (regs->nip == trampoline_exclude) { TRAMP_DEBUG("Ignoring call from excluded address 0x%08lx", (unsigned long)trampoline_exclude); return -EBUSY; } TRAMP_DEBUG("%s: bits = %d; set up trampoline. \n", __func__, bits); if (bits == TRAMPOLINE_BITS_64) { setup_trampoline64(regs, opcode, arg, (void *)trampoline_entry, (void *)trampoline_toc, (void *)trampoline_fixup); } #ifdef CONFIG_COMPAT else { setup_trampoline32(regs, opcode, arg, (void *)trampoline_entry, (void *)trampoline_toc, (void *)trampoline_fixup); } #endif rc = 0; } else { OO_DEBUG_VERB(ci_log("Error -- attempt to trampoline for unknown process")); rc = -ENOENT; } return rc; }