diff options
| author | Courtney Goeltzenleuchter <courtney@LunarG.com> | 2015-02-10 18:40:14 -0700 |
|---|---|---|
| committer | Courtney Goeltzenleuchter <courtney@LunarG.com> | 2015-02-12 16:31:13 -0700 |
| commit | 7250e7ecab292ac5debd1e11bed31e3fda034baa (patch) | |
| tree | 3c3f7c9b56037328992dda571783b0b14362889d | |
| parent | 22ec3a52c48963ef92a87fd32a9cc27dae617868 (diff) | |
| download | usermoji-7250e7ecab292ac5debd1e11bed31e3fda034baa.tar.xz | |
icd: add loader magic word to verify ICD is compatible
We wanted a more explicit way to determine if the driver
ICD being loaded is providing compatible objects. To do
that we check for a magic dword value at the beginning
of the object. Non-compliant ICDs will assert in the loader
or the loader's dispatch functions if an object does
not have the correct value.
Dispatch checks are debug only.
| -rw-r--r-- | include/xglIcd.h | 32 | ||||
| -rw-r--r-- | loader/CMakeLists.txt | 6 | ||||
| -rw-r--r-- | loader/README.md | 16 | ||||
| -rw-r--r-- | loader/loader.c | 9 | ||||
| -rwxr-xr-x | xgl-generate.py | 60 |
5 files changed, 105 insertions, 18 deletions
diff --git a/include/xglIcd.h b/include/xglIcd.h new file mode 100644 index 00000000..3efffe6d --- /dev/null +++ b/include/xglIcd.h @@ -0,0 +1,32 @@ +#ifndef XGLICD_H +#define XGLICD_H + +#include <stdint.h> +#include <stdbool.h> +#include "xglPlatform.h" + +/* + * The ICD must reserve space for a pointer for the loader's dispatch + * table, at the start of <each object>. + * The ICD must initialize this variable using the SET_LOADER_MAGIC_VALUE macro. + */ + +#define ICD_LOADER_MAGIC 0x01CDC0DE + +typedef union _XGL_LOADER_DATA { + uint32_t loaderMagic; + void *loaderData; +} XGL_LOADER_DATA; + +STATIC_INLINE void set_loader_magic_value(void *pNewObject) { + XGL_LOADER_DATA *loader_info = (XGL_LOADER_DATA *) pNewObject; + loader_info->loaderMagic = ICD_LOADER_MAGIC; +} + +STATIC_INLINE bool valid_loader_magic_value(void *pNewObject) { + const XGL_LOADER_DATA *loader_info = (XGL_LOADER_DATA *) pNewObject; + return loader_info->loaderMagic == ICD_LOADER_MAGIC; +} + +#endif // XGLICD_H + diff --git a/loader/CMakeLists.txt b/loader/CMakeLists.txt index 15702307..a4eba041 100644 --- a/loader/CMakeLists.txt +++ b/loader/CMakeLists.txt @@ -1,6 +1,7 @@ add_custom_command(OUTPUT dispatch.c COMMAND ${PROJECT_SOURCE_DIR}/xgl-generate.py loader-entrypoints > dispatch.c - DEPENDS ${PROJECT_SOURCE_DIR}/xgl-generate.py ${PROJECT_SOURCE_DIR}/xgl.py) + DEPENDS ${PROJECT_SOURCE_DIR}/xgl-generate.py ${PROJECT_SOURCE_DIR}/xgl.py + ${PROJECT_SOURCE_DIR}/include/xglIcd.h) add_custom_command(OUTPUT table_ops.h COMMAND ${PROJECT_SOURCE_DIR}/xgl-generate.py dispatch-table-ops loader > table_ops.h @@ -11,6 +12,9 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR} ) +# DEBUG enables runtime loader ICD verification +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG") +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG") if (WIN32) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DXGL_PROTOTYPES -D_CRT_SECURE_NO_WARNINGS") diff --git a/loader/README.md b/loader/README.md index fe012974..f1971676 100644 --- a/loader/README.md +++ b/loader/README.md @@ -3,9 +3,9 @@ ## Overview The Loader implements the main XGL library: libXGL.so on Linux. It handles layer management and driver management. Loader driver management includes -finding driver librairies and loading them. Aditionally, the loader dispatches +finding driver librairies and loading them. Additionally, the loader dispatches the API calls to the correct driver based on the GPU selected by the app. The -loader fully supports multi-gpu operation. +loader fully supports multi-gpu operation. Loader layer management includes finding layer libraries and activating them as requested. Loader correctly sets up layer and its own dispatch tables to @@ -27,20 +27,22 @@ LIBXGL\_LAYER\_NAMES colon separate list of layer names to be activated. Examp - xglCreateInstance exported - xglDestroyInstance exported - xglGetProcAddr exported and returns valid function pointers for all the XGL API entrypoints -- all objects created by ICD can be cast to (XGL\_LAYER\_DISPATCH\_TABLE **) +- all objects created by ICD can be cast to (XGL\_LAYER\_DISPATCH\_TABLE \*\*) where the loader will replace the first entry with a pointer to the dispatch table which is - owned by the loader. This implies two things for ICD drivers: + owned by the loader. This implies three things for ICD drivers: 1. the ICD must return a pointer for the opaque object handle 2. this pointer points to a regular C structure with the first entry being a pointer. Note: for any C++ ICD's that implement XGL objects directly as C++ classes. - The C++ compiler may put a vtable at offset zero if your class is virtual. - In this case use a regular C structure as follows for your C++ objects: + The C++ compiler may put a vtable at offset zero if your class is virtual. + In this case use a regular C structure as follows for your C++ objects: ``` + #include "xglIcd.h" struct { - void *reservedForLoader; + XGL_LOADER_DATA *reservedForLoader; myObjectClass myObj; } xglObj; ``` + 3. the reservedForLoader.loaderMagic member must be initialized with ICD\_LOADER\_MAGIC - the ICD may or may not implement a dispatch table - ICD entrypoints can be named anything including the offcial xgl name such as xglCreateDevice(). However, beware of interposing by dynamic OS library loaders if the offical names are used. On Linux, if offical names are used, the ICD library must be linked with -Bsymbolic diff --git a/loader/loader.c b/loader/loader.c index 6dd4013f..4cc7c1a0 100644 --- a/loader/loader.c +++ b/loader/loader.c @@ -42,6 +42,7 @@ #include "loader_platform.h" #include "table_ops.h" #include "loader.h" +#include "xglIcd.h" struct loader_instance { struct loader_icd *icds; @@ -967,6 +968,14 @@ LOADER_EXPORT XGL_RESULT XGLAPI xglEnumerateGpus( memcpy(pGpus + count, &wrapped_gpus, sizeof(*pGpus)); loader_init_dispatch_table(icd->loader_dispatch + i, get_proc_addr, gpus[i]); + + /* Verify ICD compatibility */ + if (!valid_loader_magic_value(gpus[i])) { + loader_log(XGL_DBG_MSG_WARNING, 0, + "Loader: Incompatible ICD, first dword must be initialized to ICD_LOADER_MAGIC. See loader/README.md for details.\n"); + assert(0); + } + const XGL_LAYER_DISPATCH_TABLE **disp; disp = (const XGL_LAYER_DISPATCH_TABLE **) gpus[i]; *disp = icd->loader_dispatch + i; diff --git a/xgl-generate.py b/xgl-generate.py index 2fe51b09..202b30f2 100755 --- a/xgl-generate.py +++ b/xgl-generate.py @@ -98,7 +98,7 @@ class Subcommand(object): class LoaderEntrypointsSubcommand(Subcommand): def generate_header(self): - return "#include \"loader.h\"" + return "#include \"loader.h\"\n#include \"xglIcd.h\"\n#include \"assert.h\"" def _does_function_create_object(self, proto): out_objs = proto.object_out_params() @@ -116,6 +116,7 @@ class LoaderEntrypointsSubcommand(Subcommand): qual += " " funcs = [] + obj_check_magic_stmt = "#ifdef DEBUG\n if (!valid_loader_magic_value(*%s)) {\n assert(0 && \"Incompatible ICD, first dword must be initialized to ICD_LOADER_MAGIC. See loader/README.md for details.\");\n }\n#endif" for proto in self.protos: if not self._is_dispatchable(proto): continue @@ -124,6 +125,7 @@ class LoaderEntrypointsSubcommand(Subcommand): decl = proto.c_func(prefix="xgl", attr="XGLAPI") stmt = "(*disp)->%s" % proto.c_call() if proto.name == "CreateDevice": + magic_stmt = obj_check_magic_stmt % proto.params[-1].name funcs.append("%s%s\n" "{\n" " loader_activate_layers(%s, %s);\n" @@ -132,28 +134,60 @@ class LoaderEntrypointsSubcommand(Subcommand): " (const XGL_LAYER_DISPATCH_TABLE **) wrapped_obj->baseObject;\n" " %s = wrapped_obj->nextObject;\n" " XGL_RESULT res = %s;\n" - " if (res == XGL_SUCCESS)\n" + " if (res == XGL_SUCCESS) {\n" + "%s\n" " *(const XGL_LAYER_DISPATCH_TABLE **) (*%s) = *disp;\n" + " }\n" " return res;\n" "}" % (qual, decl, proto.params[0].name, proto.params[1].name, proto.params[0].name, proto.params[0].name, stmt, + magic_stmt, proto.params[-1].name)) + elif proto.name == "WsiX11CreatePresentableImage": + magic_stmt1 = obj_check_magic_stmt % proto.params[-1].name + magic_stmt2 = obj_check_magic_stmt % proto.params[-2].name + funcs.append("%s%s\n" + "{\n" + " const XGL_LAYER_DISPATCH_TABLE **disp =\n" + " (const XGL_LAYER_DISPATCH_TABLE **) %s;\n" + " XGL_RESULT res = %s;\n" + " if (res == XGL_SUCCESS) {\n" + "%s\n" + "%s\n" + " *(const XGL_LAYER_DISPATCH_TABLE **) (*%s) = *disp;\n" + " *(const XGL_LAYER_DISPATCH_TABLE **) (*%s) = *disp;\n" + " }\n" + " return res;\n" + "}" + % (qual, decl, proto.params[0].name, stmt, magic_stmt1, magic_stmt2, proto.params[-1].name, proto.params[-2].name)) + elif proto.name == "GetDeviceQueue": + # GetDeviceQueue returns an existing Queue object so cannot check for magic header as + # it may have already been replaced with a function table pointer + funcs.append("%s%s\n" + "{\n" + " const XGL_LAYER_DISPATCH_TABLE **disp =\n" + " (const XGL_LAYER_DISPATCH_TABLE **) %s;\n" + " XGL_RESULT res = %s;\n" + " if (res == XGL_SUCCESS) {\n" + " *(const XGL_LAYER_DISPATCH_TABLE **) (*%s) = *disp;\n" + " }\n" + " return res;\n" + "}" + % (qual, decl, proto.params[0].name, stmt, proto.params[-1].name)) elif self._does_function_create_object(proto): - if proto.name == "WsiX11CreatePresentableImage": - obj_write_stmt = "\n *(const XGL_LAYER_DISPATCH_TABLE **) (*%s) = *disp;" % ( proto.params[-2].name) - else: - obj_write_stmt = "" + magic_stmt = obj_check_magic_stmt % proto.params[-1].name funcs.append("%s%s\n" "{\n" " const XGL_LAYER_DISPATCH_TABLE **disp =\n" " (const XGL_LAYER_DISPATCH_TABLE **) %s;\n" " XGL_RESULT res = %s;\n" - " if (res == XGL_SUCCESS) {%s\n" + " if (res == XGL_SUCCESS) {\n" + "%s\n" " *(const XGL_LAYER_DISPATCH_TABLE **) (*%s) = *disp;\n" " }\n" " return res;\n" "}" - % (qual, decl, proto.params[0].name, stmt, obj_write_stmt, proto.params[-1].name)) + % (qual, decl, proto.params[0].name, stmt, magic_stmt, proto.params[-1].name)) elif proto.name == "AllocDescriptorSets": funcs.append("%s%s\n" "{\n" @@ -161,10 +195,16 @@ class LoaderEntrypointsSubcommand(Subcommand): " (const XGL_LAYER_DISPATCH_TABLE **) %s;\n" " uint32_t i;\n" " XGL_RESULT res = %s;\n" - " for (i = 0; i < *%s; i++)\n" + " for (i = 0; i < *%s; i++) {\n" + "#ifdef DEBUG\n" + " if (!valid_loader_magic_value(%s[i])) {\n" + " assert(0 && \"Incompatible ICD, first dword must be initialized to ICD_LOADER_MAGIC. See loader/README.md for details.\");\n" + " }\n" + "#endif\n" " *(const XGL_LAYER_DISPATCH_TABLE **) (%s[i]) = *disp;\n" + " }\n" " return res;\n" - "}" % (qual, decl, proto.params[0].name, stmt, proto.params[-1].name, proto.params[-2].name)) + "}" % (qual, decl, proto.params[0].name, stmt, proto.params[-1].name, proto.params[-2].name, proto.params[-2].name)) elif proto.name == "GetMultiGpuCompatibility": funcs.append("%s%s\n" "{\n" |
