aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCourtney Goeltzenleuchter <courtney@LunarG.com>2015-02-10 18:40:14 -0700
committerCourtney Goeltzenleuchter <courtney@LunarG.com>2015-02-12 16:31:13 -0700
commit7250e7ecab292ac5debd1e11bed31e3fda034baa (patch)
tree3c3f7c9b56037328992dda571783b0b14362889d
parent22ec3a52c48963ef92a87fd32a9cc27dae617868 (diff)
downloadusermoji-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.h32
-rw-r--r--loader/CMakeLists.txt6
-rw-r--r--loader/README.md16
-rw-r--r--loader/loader.c9
-rwxr-xr-xxgl-generate.py60
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"