-
Notifications
You must be signed in to change notification settings - Fork 865
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
patcher: fix powerpc/power support in patcher/linux
This commit does the following: - Move code necessary for powerpc/power support to the patcher base. The code is needed by both the overwrite and linux components. - Move patch structure down to base and move the patch list to mca_patcher_base_module_t. The structure has been modified to include a function pointer to the function that will unapply the patch. This allows the mixing of multiple different types of patches in the patch_list. - Update linux patching code to keep track of the matching between got entry and original (unpatched) address. This allows us to completely clean up the patch on finalize. Signed-off-by: Nathan Hjelm <[email protected]>
- Loading branch information
Showing
11 changed files
with
415 additions
and
298 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ | ||
/* | ||
* Copyright (c) 2016 Los Alamos National Security, LLC. All rights | ||
* reserved. | ||
* $COPYRIGHT$ | ||
* | ||
* Additional copyrights may follow | ||
* | ||
* $HEADER$ | ||
*/ | ||
|
||
#include "opal_config.h" | ||
|
||
#include "opal/mca/patcher/patcher.h" | ||
#include "opal/mca/patcher/base/base.h" | ||
#include "opal/util/sys_limits.h" | ||
#include "opal/prefetch.h" | ||
#include <sys/mman.h> | ||
|
||
static void mca_patcher_base_patch_construct (mca_patcher_base_patch_t *patch) | ||
{ | ||
patch->patch_symbol = NULL; | ||
patch->patch_data_size = 0; | ||
} | ||
|
||
static void mca_patcher_base_patch_destruct (mca_patcher_base_patch_t *patch) | ||
{ | ||
free (patch->patch_symbol); | ||
} | ||
|
||
OBJ_CLASS_INSTANCE(mca_patcher_base_patch_t, opal_list_item_t, | ||
mca_patcher_base_patch_construct, | ||
mca_patcher_base_patch_destruct); | ||
|
||
#if defined(__PPC__) | ||
|
||
// PowerPC instructions used in patching | ||
// Reference: "PowerPC User Instruction Set Architecture" | ||
static unsigned int addis(unsigned int RT, unsigned int RS, unsigned int UI) { | ||
return (15<<26) + (RT<<21) + (RS<<16) + (UI&0xffff); | ||
} | ||
static unsigned int ori(unsigned int RT, unsigned int RS, unsigned int UI) { | ||
return (24<<26) + (RS<<21) + (RT<<16) + (UI&0xffff); | ||
} | ||
static unsigned int oris(unsigned int RT, unsigned int RS, unsigned int UI) { | ||
return (25<<26) + (RS<<21) + (RT<<16) + (UI&0xffff); | ||
} | ||
static unsigned int mtspr(unsigned int SPR, unsigned int RS) { | ||
return (31<<26) + (RS<<21) + ((SPR&0x1f)<<16) + ((SPR>>5)<<11) + (467<<1); | ||
} | ||
static unsigned int bcctr(unsigned int BO, unsigned int BI, unsigned int BH) { | ||
return (19<<26) + (BO<<21) + (BI<<16) + (BH<<11) + (528<<1); | ||
} | ||
static unsigned int rldicr(unsigned int RT, unsigned int RS, unsigned int SH, unsigned int MB) | ||
{ | ||
return (30<<26) + (RS<<21) + (RT<<16) + ((SH&0x1f)<<11) + ((SH>>5)<<1) | ||
+ ((MB&0x1f)<<6) + ((MB>>5)<<5) + (1<<2); | ||
} | ||
|
||
static int PatchLoadImm (uintptr_t addr, unsigned int reg, size_t value) | ||
{ | ||
#if defined(__PPC64__) | ||
*(unsigned int *) (addr + 0) = addis ( reg, 0, (value >> 48)); | ||
*(unsigned int *) (addr + 4) = ori ( reg, reg, (value >> 32)); | ||
*(unsigned int *) (addr + 8) = rldicr( reg, reg, 32, 31); | ||
*(unsigned int *) (addr +12) = oris ( reg, reg, (value >> 16)); | ||
*(unsigned int *) (addr +16) = ori ( reg, reg, (value >> 0)); | ||
return 20; | ||
#else | ||
*(unsigned int *) (addr + 0) = addis ( reg, 0, (value >> 16)); | ||
*(unsigned int *) (addr + 4) = ori ( reg, reg, (value >> 0)); | ||
return 8; | ||
#endif | ||
} | ||
|
||
#endif | ||
|
||
#if defined(__i386__) || defined(__x86_64__) || defined(__ia64__) | ||
|
||
static void flush_and_invalidate_cache (unsigned long a) | ||
{ | ||
#if defined(__i386__) | ||
/* does not work with AMD processors */ | ||
__asm__ volatile("mfence;clflush %0;mfence" : :"m" (*(char*)a)); | ||
#elif defined(__x86_64__) | ||
__asm__ volatile("mfence;clflush %0;mfence" : :"m" (*(char*)a)); | ||
#elif defined(__ia64__) | ||
__asm__ volatile ("fc %0;; sync.i;; srlz.i;;" : : "r"(a) : "memory"); | ||
#endif | ||
} | ||
#endif | ||
|
||
// modify protection of memory range | ||
static void ModifyMemoryProtection (uintptr_t addr, size_t length, int prot) | ||
{ | ||
long page_size = opal_getpagesize (); | ||
uintptr_t base = (addr & ~(page_size-1)); | ||
uintptr_t bound = ((addr + length + page_size-1) & ~(page_size-1)); | ||
|
||
length = bound - base; | ||
|
||
#if defined(__PPC__) | ||
/* NTH: is a loop necessary here? */ | ||
do { | ||
if (mprotect((void *)base, page_size, prot)) | ||
perror("MemHook: mprotect failed"); | ||
base += page_size; | ||
} while (base < addr + length); | ||
#else | ||
if (mprotect((void *) base, length, prot)) { | ||
perror("MemHook: mprotect failed"); | ||
} | ||
#endif | ||
} | ||
|
||
static inline void apply_patch (unsigned char *patch_data, uintptr_t address, size_t data_size) | ||
{ | ||
ModifyMemoryProtection (address, data_size, PROT_EXEC|PROT_READ|PROT_WRITE); | ||
memcpy ((void *) address, patch_data, data_size); | ||
#if defined(__i386__) || defined(__x86_64__) || defined(__ia64__) | ||
for (size_t i = 0 ; i < data_size ; i += 16) { | ||
flush_and_invalidate_cache (address + i); | ||
} | ||
#endif | ||
|
||
ModifyMemoryProtection (address, data_size, PROT_EXEC|PROT_READ); | ||
} | ||
|
||
static void mca_base_patcher_patch_unapply_binary (mca_patcher_base_patch_t *patch) | ||
{ | ||
apply_patch (patch->patch_orig_data, patch->patch_orig, patch->patch_data_size); | ||
} | ||
|
||
void mca_base_patcher_patch_apply_binary (mca_patcher_base_patch_t *patch) | ||
{ | ||
memcpy (patch->patch_orig_data, (void *) patch->patch_orig, patch->patch_data_size); | ||
apply_patch (patch->patch_data, patch->patch_orig, patch->patch_data_size); | ||
patch->patch_restore = mca_base_patcher_patch_unapply_binary; | ||
} | ||
|
||
|
||
int mca_patcher_base_patch_hook (mca_patcher_base_module_t *module, uintptr_t hook_addr) | ||
{ | ||
#if defined(__PPC64__) || defined(__powerpc64__) || defined(__PPC__) | ||
mca_patcher_base_patch_t *hook_patch; | ||
const unsigned int nop = 0x60000000; | ||
unsigned int *nop_addr; | ||
|
||
fprintf (stderr, "Patching hook @ 0x%lx\n", hook_addr); | ||
|
||
hook_patch = OBJ_NEW(mca_patcher_base_patch_t); | ||
if (OPAL_UNLIKELY(NULL == hook_patch)) { | ||
return OPAL_ERR_OUT_OF_RESOURCE; | ||
} | ||
|
||
// locate reserved code space in hook function | ||
for (nop_addr = (unsigned int *)hook_addr ; ; nop_addr++) { | ||
if (nop_addr[0] == nop && nop_addr[1] == nop && nop_addr[2] == nop | ||
&& nop_addr[3] == nop && nop_addr[4] == nop) { | ||
break; | ||
} | ||
} | ||
// generate code to restore TOC | ||
register unsigned long toc asm("r2"); | ||
hook_patch->patch_orig = (uintptr_t) nop_addr; | ||
hook_patch->patch_data_size = PatchLoadImm((uintptr_t)hook_patch->patch_data, 2, toc); | ||
|
||
/* put the hook patch on the patch list so it will be undone on finalize */ | ||
opal_list_append (&module->patch_list, &hook_patch->super); | ||
|
||
mca_base_patcher_patch_apply_binary (hook_patch); | ||
#endif | ||
|
||
return OPAL_SUCCESS; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.