Makefile and structural changes for ppc64le support.

Added the files and makefile changes needed for adding support for ppc64le
dispatch stubs.

The actual assembly code still needs to be written, along with any other
arch-specific requirements for self-modifying code.

The new entry_ppc64le_*.c files are mostly based on the x86-64 files.

It still needs:
- Assembly code for OpenGL dispatch stubs in entry_ppc64le_tls.c,
  entry_ppc64le_tsd.c, or both.
- Assembly code for GLX dispatch stubs in glvnd_genentry.c.
- Assembly code for the entrypoint patching tests in patchentrypoints.c.
This commit is contained in:
Kyle Brenneman 2017-01-24 11:20:28 -07:00
parent 8e6e102820
commit e77d29a67c
7 changed files with 330 additions and 1 deletions

View file

@ -68,6 +68,7 @@ AC_ARG_ENABLE([asm],
[enable_asm="$enableval"],
[enable_asm=yes]
)
asm_arch=""
AC_MSG_CHECKING([whether to enable assembly])
test "x$enable_asm" = xno && AC_MSG_RESULT([no])
@ -97,6 +98,9 @@ if test "x$enable_asm" = xyes; then
aarch64)
asm_arch=aarch64
;;
powerpc64le)
asm_arch=ppc64le
;;
esac
case "$asm_arch" in
@ -116,6 +120,10 @@ if test "x$enable_asm" = xyes; then
DEFINES="$DEFINES -DUSE_AARCH64_ASM"
AC_MSG_RESULT([yes, aarch64])
;;
ppc64le)
DEFINES="$DEFINES -DUSE_PPC64LE_ASM"
AC_MSG_RESULT([yes, ppc64le])
;;
*)
AC_MSG_RESULT([no, platform '$host_cpu' not supported])
;;
@ -184,6 +192,16 @@ xaarch64)
gldispatch_entry_type=aarch64_tsd
gldispatch_use_tls=no
;;
xppc64le)
# For ppc64le, allow both the TLS and TSD stubs for now.
if test "x$HAVE_INIT_TLS" = "xyes" ; then
gldispatch_entry_type=ppc64le_tls
gldispatch_use_tls=yes
else
gldispatch_entry_type=ppc64le_tsd
gldispatch_use_tls=no
fi
;;
*)
# The C stubs will work with either TLS or TSD.
gldispatch_entry_type=pure_c
@ -200,6 +218,8 @@ AM_CONDITIONAL([GLDISPATCH_TYPE_X86_TLS], [test "x$gldispatch_entry_type" = "xx8
AM_CONDITIONAL([GLDISPATCH_TYPE_X86_TSD], [test "x$gldispatch_entry_type" = "xx86_tsd"])
AM_CONDITIONAL([GLDISPATCH_TYPE_X86_64_TLS], [test "x$gldispatch_entry_type" = "xx86_64_tls"])
AM_CONDITIONAL([GLDISPATCH_TYPE_X86_64_TSD], [test "x$gldispatch_entry_type" = "xx86_64_tsd"])
AM_CONDITIONAL([GLDISPATCH_TYPE_PPC64LE_TLS], [test "x$gldispatch_entry_type" = "xppc64le_tls"])
AM_CONDITIONAL([GLDISPATCH_TYPE_PPC64LE_TSD], [test "x$gldispatch_entry_type" = "xppc64le_tsd"])
AM_CONDITIONAL([GLDISPATCH_TYPE_ARMV7_TSD], [test "x$gldispatch_entry_type" = "xarmv7_tsd"])
AM_CONDITIONAL([GLDISPATCH_TYPE_AARCH64_TSD], [test "x$gldispatch_entry_type" = "xaarch64_tsd"])
AM_CONDITIONAL([GLDISPATCH_TYPE_PURE_C], [test "x$gldispatch_entry_type" = "xpure_c"])

View file

@ -93,6 +93,11 @@ enum {
* Used for stubs on x32 builds (x86-64 with 32-bit pointers).
*/
__GLDISPATCH_STUB_X32,
/*!
* Used for stubs on PPC64LE systems.
*/
__GLDISPATCH_STUB_PPC64LE,
};
/*!

View file

@ -37,6 +37,18 @@ MAPI_GLDISPATCH_ENTRY_FILES = entry_aarch64_tsd.c
MAPI_GLDISPATCH_ENTRY_FILES += entry_common.c
endif
if GLDISPATCH_TYPE_PPC64LE_TSD
MAPI_GLDISPATCH_ENTRY_FILES = entry_ppc64le_tsd.c
MAPI_GLDISPATCH_ENTRY_FILES += entry_x86_64_common.c
MAPI_GLDISPATCH_ENTRY_FILES += entry_common.c
endif
if GLDISPATCH_TYPE_PPC64LE_TLS
MAPI_GLDISPATCH_ENTRY_FILES = entry_ppc64le_tls.c
MAPI_GLDISPATCH_ENTRY_FILES += entry_x86_64_common.c
MAPI_GLDISPATCH_ENTRY_FILES += entry_common.c
endif
if GLDISPATCH_TYPE_PURE_C
MAPI_GLDISPATCH_ENTRY_FILES = entry_pure_c.c
endif

View file

@ -0,0 +1,113 @@
/*
* Copyright (C) 2010 LunarG Inc.
* Copyright (c) 2017, NVIDIA CORPORATION.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "entry.h"
#include "entry_common.h"
#include <assert.h>
#include <stdint.h>
#include <sys/mman.h>
#include <unistd.h>
#include <string.h>
#include "u_macros.h"
#include "glapi.h"
#include "glvnd/GLdispatchABI.h"
// TODO: Change this macro to be the size of the dispatch stubs.
#define PPC64LE_ENTRY_SIZE 32
__asm__(".section wtext,\"ax\",@progbits\n");
__asm__(".balign 4096\n"
".globl public_entry_start\n"
".hidden public_entry_start\n"
"public_entry_start:");
#define STUB_ASM_ENTRY(func) \
".globl " func "\n" \
".type " func ", @function\n" \
".balign " U_STRINGIFY(PPC64LE_ENTRY_SIZE) "\n" \
func ":"
#define STUB_ASM_CODE(slot) \
"nop"
// TODO: Fill in this assembly code
// Conceptually, this is:
// {
// void **dispatchTable = _glapi_tls_Current;
// jump_to_address(dispatchTable[slot];
// }
//
// Note that _glapi_tls_Current is a global variable declared with
// __thread.
// See the x86-64 TLS code for an example.
#define MAPI_TMP_STUB_ASM_GCC
#include "mapi_tmp.h"
__asm__(".balign 4096\n"
".globl public_entry_end\n"
".hidden public_entry_end\n"
"public_entry_end:");
__asm__(".text\n");
const int entry_type = __GLDISPATCH_STUB_PPC64LE;
const int entry_stub_size = PPC64LE_ENTRY_SIZE;
static const unsigned char ENTRY_TEMPLATE[] =
{
// TODO: Fill in the assembly code here as well. This should be
// functionally the same code as would be generated from the STUB_ASM_CODE
// macro, but defined as a buffer.
// This is used to generate new dispatch stubs. libglvnd will copy this
// data to the dispatch stub, and then it will patch the slot number and
// any addresses that it needs to.
};
// These are the offsets in ENTRY_TEMPLATE of the values that we have to patch.
static const int TEMPLATE_OFFSET_SLOT = 0;
/*
* TODO: Fill in these offsets. These are used in entry_generate_default_code
* to patch the dispatch table index and any memory addresses in the generated
* function.
*
* TEMPLATE_OFFSET_SLOT is the dispatch table index.
*/
void entry_generate_default_code(char *entry, int slot)
{
char *writeEntry = u_execmem_get_writable(entry);
memcpy(writeEntry, ENTRY_TEMPLATE, sizeof(ENTRY_TEMPLATE));
// TODO: Patch the dispatch table slot.
*((uint32_t *) (writeEntry + TEMPLATE_OFFSET_SLOT)) = slot * sizeof(mapi_func);
// TODO: Patch any addresses necessary to look up the _glapi_tls_Current
// variable from TLS.
// TODO: Do any cache clears or anything else that is necessary on PPC64LE
// to make self-modifying code work.
}

View file

@ -0,0 +1,127 @@
/*
* Copyright (C) 2010 LunarG Inc.
* Copyright (c) 2017, NVIDIA CORPORATION.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "entry.h"
#include "entry_common.h"
#include <assert.h>
#include <stdint.h>
#include <sys/mman.h>
#include <unistd.h>
#include <string.h>
#include "u_macros.h"
#include "glapi.h"
#include "glvnd/GLdispatchABI.h"
// TODO: Change this macro to be the size of the dispatch stubs.
#define PPC64LE_ENTRY_SIZE 32
__asm__(".section wtext,\"ax\",@progbits\n");
__asm__(".balign 4096\n"
".globl public_entry_start\n"
".hidden public_entry_start\n"
"public_entry_start:");
#define STUB_ASM_ENTRY(func) \
".globl " func "\n" \
".type " func ", @function\n" \
".balign " U_STRINGIFY(PPC64LE_ENTRY_SIZE) "\n" \
func ":"
#define STUB_ASM_CODE(slot) \
"nop"
// TODO: Fill in this assembly code.
// Conceptually, this is:
// {
// void **dispatchTable = _glapi_Current[GLAPI_CURRENT_DISPATCH];
// if (dispatchTable == NULL) {
// dispatchTable = _glapi_get_current();
// }
// jump_to_address(dispatchTable[slot]);
// }
//
// Note that _glapi_Current is a simple global variable.
// See the x86 or x86-64 TSD code for examples.
#define MAPI_TMP_STUB_ASM_GCC
#include "mapi_tmp.h"
__asm__(".balign 4096\n"
".globl public_entry_end\n"
".hidden public_entry_end\n"
"public_entry_end:");
__asm__(".text\n");
const int entry_type = __GLDISPATCH_STUB_PPC64LE;
const int entry_stub_size = PPC64LE_ENTRY_SIZE;
static const unsigned char ENTRY_TEMPLATE[] =
{
// TODO: Fill in the assembly code here as well. This should be
// functionally the same code as would be generated from the STUB_ASM_CODE
// macro, but defined as a buffer.
// This is used to generate new dispatch stubs. libglvnd will copy this
// data to the dispatch stub, and then it will patch the slot number and
// any addresses that it needs to.
};
// These are the offsets in ENTRY_TEMPLATE of the values that we have to patch.
static const int TEMPLATE_OFFSET_CURRENT_TABLE = 0;
static const int TEMPLATE_OFFSET_CURRENT_TABLE_GET = 0;
static const int TEMPLATE_OFFSET_SLOT = 0;
/*
* TODO: Fill in these offsets. These are used in entry_generate_default_code
* to patch the dispatch table index and any memory addresses in the generated
* function.
*
* TEMPLATE_OFFSET_SLOT is the dispatch table index.
*
* TEMPLATE_OFFSET_CURRENT_TABLE is the address of the global _glapi_Current
* variable.
*
* TEMPLATE_OFFSET_CURRENT_TABLE_GET is the address of the function
* _glapi_get_current.
*/
void entry_generate_default_code(char *entry, int slot)
{
char *writeEntry = u_execmem_get_writable(entry);
memcpy(writeEntry, ENTRY_TEMPLATE, sizeof(ENTRY_TEMPLATE));
// TODO: Patch the dispatch table slot and the addresses of the
// _glapi_Current variable and _glapi_get_current function.
// Note that (entry) is the executable pointer, and (writeEntry) is the
// writable pointer, which may or may not be the same. So, if the stub
// needs to use IP-relative addresses, then calculate those addresses based
// on (entry).
*((uint32_t *) (writeEntry + TEMPLATE_OFFSET_SLOT)) = slot * sizeof(mapi_func);
*((uintptr_t *) (writeEntry + TEMPLATE_OFFSET_CURRENT_TABLE)) = (uintptr_t) _glapi_Current;
*((uintptr_t *) (writeEntry + TEMPLATE_OFFSET_CURRENT_TABLE_GET)) = (uintptr_t) _glapi_get_current;
// TODO: Do any cache clears or anything else that is necessary on PPC64LE
// to make self-modifying code work.
}

View file

@ -40,7 +40,8 @@
#define USE_ASM (defined(USE_X86_ASM) || \
defined(USE_X86_64_ASM) || \
defined(USE_ARMV7_ASM) || \
defined(USE_AARCH64_ASM))
defined(USE_AARCH64_ASM) || \
defined(USE_PPC64LE_ASM))
#if defined(__GNUC__) && USE_ASM
@ -108,6 +109,19 @@ static const uint32_t STUB_TEMPLATE[] =
static const int DISPATCH_FUNC_OFFSET = 12;
#elif defined(USE_PPC64LE_ASM)
static unsigned char STUB_TEMPLATE[] =
{
// TODO: Fill in assembly code.
// This function should just jump to an immediate address. See the x86
// and x86-64 versions above for the simplest examples.
};
// TODO: Set this to the offset in STUB_TEMPLATE which contains the address to
// jump to.
static const int DISPATCH_FUNC_OFFSET = 0;
#else
#error "Can't happen -- not implemented"
#endif
@ -293,6 +307,15 @@ void SetDispatchFuncPointer(GLVNDGenEntrypoint *entry,
// See http://community.arm.com/groups/processors/blog/2010/02/17/caches-and-self-modifying-code
__builtin___clear_cache((char *)entry->entrypointExec - 1,
(char *)entry->entrypointExec - 1 + sizeof(STUB_TEMPLATE));
#elif defined(USE_PPC64LE_ASM)
// TODO: Update this if necessary:
// - Set the address correctly -- should it be an absolute or IP-relative
// address?
// - Does it need to do anything to make self-modifying code work?
*((uintptr_t *)(code + DISPATCH_FUNC_OFFSET)) = (uintptr_t)dispatch;
#else
#error "Can't happen -- not implemented"
#endif

View file

@ -164,6 +164,31 @@ static void patch_aarch64(char *writeEntry, const char *execEntry,
#endif
}
static void patch_ppc64le(char *writeEntry, const char *execEntry,
int stubSize, void *incrementPtr)
{
#if defined(__PPC64__)
const unsigned char tmpl[] = {
// TODO: Fill in this assembly code
// The assembly code should increment the integer at (*incrementPtr).
};
if (stubSize < sizeof(tmpl)) {
return;
}
memcpy(writeEntry, tmpl, sizeof(tmpl));
// TODO: Patch the address of (*incrementPtr) in the writeEntry buffer.
memcpy(writeEntry + 0, &incrementPtr, sizeof(incrementPtr));
// TODO: Do any other architecture-specific stuff that is required for
// self-modifying code (e.g., a jmp for x86, or a cache clear for ARM).
#else
assert(0); // Should not be calling this
#endif
}
GLboolean dummyCheckPatchSupported(int type, int stubSize)
{
switch (type) {
@ -172,6 +197,7 @@ GLboolean dummyCheckPatchSupported(int type, int stubSize)
case __GLDISPATCH_STUB_ARMV7_THUMB:
case __GLDISPATCH_STUB_AARCH64:
case __GLDISPATCH_STUB_X32:
case __GLDISPATCH_STUB_PPC64LE:
return GL_TRUE;
default:
return GL_FALSE;
@ -204,6 +230,9 @@ GLboolean dummyPatchFunction(int type, int stubSize,
case __GLDISPATCH_STUB_AARCH64:
patch_aarch64(writeAddr, execAddr, stubSize, incrementPtr);
break;
case __GLDISPATCH_STUB_PPC64LE:
patch_ppc64le(writeAddr, execAddr, stubSize, incrementPtr);
break;
default:
assert(0);
}