xref: /aosp_15_r20/external/OpenCL-ICD-Loader/loader/linux/icd_linux.c (revision 1cddb830dba8aa7c1cc1039338e56b3b9fa24952)
1*1cddb830SAndroid Build Coastguard Worker /*
2*1cddb830SAndroid Build Coastguard Worker  * Copyright (c) 2016-2020 The Khronos Group Inc.
3*1cddb830SAndroid Build Coastguard Worker  *
4*1cddb830SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*1cddb830SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*1cddb830SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*1cddb830SAndroid Build Coastguard Worker  *
8*1cddb830SAndroid Build Coastguard Worker  *     http://www.apache.org/licenses/LICENSE-2.0
9*1cddb830SAndroid Build Coastguard Worker  *
10*1cddb830SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*1cddb830SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*1cddb830SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*1cddb830SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*1cddb830SAndroid Build Coastguard Worker  * limitations under the License.
15*1cddb830SAndroid Build Coastguard Worker  *
16*1cddb830SAndroid Build Coastguard Worker  * OpenCL is a trademark of Apple Inc. used under license by Khronos.
17*1cddb830SAndroid Build Coastguard Worker  */
18*1cddb830SAndroid Build Coastguard Worker 
19*1cddb830SAndroid Build Coastguard Worker #include "icd.h"
20*1cddb830SAndroid Build Coastguard Worker #include "icd_envvars.h"
21*1cddb830SAndroid Build Coastguard Worker 
22*1cddb830SAndroid Build Coastguard Worker #include <dlfcn.h>
23*1cddb830SAndroid Build Coastguard Worker #include <stdio.h>
24*1cddb830SAndroid Build Coastguard Worker #include <string.h>
25*1cddb830SAndroid Build Coastguard Worker #include <stdlib.h>
26*1cddb830SAndroid Build Coastguard Worker #include <sys/types.h>
27*1cddb830SAndroid Build Coastguard Worker #include <sys/stat.h>
28*1cddb830SAndroid Build Coastguard Worker #include <dirent.h>
29*1cddb830SAndroid Build Coastguard Worker #include <pthread.h>
30*1cddb830SAndroid Build Coastguard Worker #include <limits.h>
31*1cddb830SAndroid Build Coastguard Worker 
32*1cddb830SAndroid Build Coastguard Worker static pthread_once_t initialized = PTHREAD_ONCE_INIT;
33*1cddb830SAndroid Build Coastguard Worker 
34*1cddb830SAndroid Build Coastguard Worker /*
35*1cddb830SAndroid Build Coastguard Worker  *
36*1cddb830SAndroid Build Coastguard Worker  * Vendor enumeration functions
37*1cddb830SAndroid Build Coastguard Worker  *
38*1cddb830SAndroid Build Coastguard Worker  */
39*1cddb830SAndroid Build Coastguard Worker 
40*1cddb830SAndroid Build Coastguard Worker typedef void khrIcdFileAdd(const char *);
41*1cddb830SAndroid Build Coastguard Worker 
khrIcdOsDirEntryValidateAndAdd(const char * d_name,const char * path,const char * extension,khrIcdFileAdd addFunc)42*1cddb830SAndroid Build Coastguard Worker static inline void khrIcdOsDirEntryValidateAndAdd(const char *d_name, const char *path,
43*1cddb830SAndroid Build Coastguard Worker                                                   const char *extension, khrIcdFileAdd addFunc)
44*1cddb830SAndroid Build Coastguard Worker {
45*1cddb830SAndroid Build Coastguard Worker     struct stat statBuff;
46*1cddb830SAndroid Build Coastguard Worker     char* fileName = NULL;
47*1cddb830SAndroid Build Coastguard Worker 
48*1cddb830SAndroid Build Coastguard Worker     // make sure the file name ends in `extension` (eg. .icd, or .lay)
49*1cddb830SAndroid Build Coastguard Worker     if (strlen(extension) > strlen(d_name))
50*1cddb830SAndroid Build Coastguard Worker     {
51*1cddb830SAndroid Build Coastguard Worker         return;
52*1cddb830SAndroid Build Coastguard Worker     }
53*1cddb830SAndroid Build Coastguard Worker     if (strcmp(d_name + strlen(d_name) - strlen(extension), extension))
54*1cddb830SAndroid Build Coastguard Worker     {
55*1cddb830SAndroid Build Coastguard Worker         return;
56*1cddb830SAndroid Build Coastguard Worker     }
57*1cddb830SAndroid Build Coastguard Worker 
58*1cddb830SAndroid Build Coastguard Worker     // allocate space for the full path of the vendor library name
59*1cddb830SAndroid Build Coastguard Worker     fileName = malloc(strlen(d_name) + strlen(path) + 2);
60*1cddb830SAndroid Build Coastguard Worker     if (!fileName)
61*1cddb830SAndroid Build Coastguard Worker     {
62*1cddb830SAndroid Build Coastguard Worker         KHR_ICD_TRACE("Failed allocate space for ICD file path\n");
63*1cddb830SAndroid Build Coastguard Worker         return;
64*1cddb830SAndroid Build Coastguard Worker     }
65*1cddb830SAndroid Build Coastguard Worker     sprintf(fileName, "%s/%s", path, d_name);
66*1cddb830SAndroid Build Coastguard Worker 
67*1cddb830SAndroid Build Coastguard Worker     if (stat(fileName, &statBuff))
68*1cddb830SAndroid Build Coastguard Worker     {
69*1cddb830SAndroid Build Coastguard Worker         KHR_ICD_TRACE("Failed stat for: %s, continuing\n", fileName);
70*1cddb830SAndroid Build Coastguard Worker         free(fileName);
71*1cddb830SAndroid Build Coastguard Worker         return;
72*1cddb830SAndroid Build Coastguard Worker     }
73*1cddb830SAndroid Build Coastguard Worker 
74*1cddb830SAndroid Build Coastguard Worker     if (S_ISREG(statBuff.st_mode) || S_ISLNK(statBuff.st_mode))
75*1cddb830SAndroid Build Coastguard Worker     {
76*1cddb830SAndroid Build Coastguard Worker         FILE *fin = NULL;
77*1cddb830SAndroid Build Coastguard Worker         char* buffer = NULL;
78*1cddb830SAndroid Build Coastguard Worker         long bufferSize = 0;
79*1cddb830SAndroid Build Coastguard Worker 
80*1cddb830SAndroid Build Coastguard Worker         // open the file and read its contents
81*1cddb830SAndroid Build Coastguard Worker         fin = fopen(fileName, "r");
82*1cddb830SAndroid Build Coastguard Worker         if (!fin)
83*1cddb830SAndroid Build Coastguard Worker         {
84*1cddb830SAndroid Build Coastguard Worker             free(fileName);
85*1cddb830SAndroid Build Coastguard Worker             return;
86*1cddb830SAndroid Build Coastguard Worker         }
87*1cddb830SAndroid Build Coastguard Worker         fseek(fin, 0, SEEK_END);
88*1cddb830SAndroid Build Coastguard Worker         bufferSize = ftell(fin);
89*1cddb830SAndroid Build Coastguard Worker 
90*1cddb830SAndroid Build Coastguard Worker         buffer = malloc(bufferSize+1);
91*1cddb830SAndroid Build Coastguard Worker         if (!buffer)
92*1cddb830SAndroid Build Coastguard Worker         {
93*1cddb830SAndroid Build Coastguard Worker             free(fileName);
94*1cddb830SAndroid Build Coastguard Worker             fclose(fin);
95*1cddb830SAndroid Build Coastguard Worker             return;
96*1cddb830SAndroid Build Coastguard Worker         }
97*1cddb830SAndroid Build Coastguard Worker         memset(buffer, 0, bufferSize+1);
98*1cddb830SAndroid Build Coastguard Worker         fseek(fin, 0, SEEK_SET);
99*1cddb830SAndroid Build Coastguard Worker         if (bufferSize != (long)fread(buffer, 1, bufferSize, fin))
100*1cddb830SAndroid Build Coastguard Worker         {
101*1cddb830SAndroid Build Coastguard Worker             free(fileName);
102*1cddb830SAndroid Build Coastguard Worker             free(buffer);
103*1cddb830SAndroid Build Coastguard Worker             fclose(fin);
104*1cddb830SAndroid Build Coastguard Worker             return;
105*1cddb830SAndroid Build Coastguard Worker         }
106*1cddb830SAndroid Build Coastguard Worker         // ignore a newline at the end of the file
107*1cddb830SAndroid Build Coastguard Worker         if (buffer[bufferSize-1] == '\n') buffer[bufferSize-1] = '\0';
108*1cddb830SAndroid Build Coastguard Worker 
109*1cddb830SAndroid Build Coastguard Worker         // load the string read from the file
110*1cddb830SAndroid Build Coastguard Worker         addFunc(buffer);
111*1cddb830SAndroid Build Coastguard Worker 
112*1cddb830SAndroid Build Coastguard Worker         free(fileName);
113*1cddb830SAndroid Build Coastguard Worker         free(buffer);
114*1cddb830SAndroid Build Coastguard Worker         fclose(fin);
115*1cddb830SAndroid Build Coastguard Worker      }
116*1cddb830SAndroid Build Coastguard Worker      else
117*1cddb830SAndroid Build Coastguard Worker      {
118*1cddb830SAndroid Build Coastguard Worker          KHR_ICD_TRACE("File %s is not a regular file nor symbolic link, continuing\n", fileName);
119*1cddb830SAndroid Build Coastguard Worker          free(fileName);
120*1cddb830SAndroid Build Coastguard Worker      }
121*1cddb830SAndroid Build Coastguard Worker }
122*1cddb830SAndroid Build Coastguard Worker 
123*1cddb830SAndroid Build Coastguard Worker struct dirElem
124*1cddb830SAndroid Build Coastguard Worker {
125*1cddb830SAndroid Build Coastguard Worker     char *d_name;
126*1cddb830SAndroid Build Coastguard Worker     unsigned char d_type;
127*1cddb830SAndroid Build Coastguard Worker };
128*1cddb830SAndroid Build Coastguard Worker 
compareDirElem(const void * a,const void * b)129*1cddb830SAndroid Build Coastguard Worker static int compareDirElem(const void *a, const void *b)
130*1cddb830SAndroid Build Coastguard Worker {
131*1cddb830SAndroid Build Coastguard Worker     // sort files the same way libc alpahnumerically sorts directory entries.
132*1cddb830SAndroid Build Coastguard Worker     return strcoll(((struct dirElem *)a)->d_name, ((struct dirElem *)b)->d_name);
133*1cddb830SAndroid Build Coastguard Worker }
134*1cddb830SAndroid Build Coastguard Worker 
khrIcdOsDirEnumerate(const char * path,const char * env,const char * extension,khrIcdFileAdd addFunc,int bSort)135*1cddb830SAndroid Build Coastguard Worker static inline void khrIcdOsDirEnumerate(const char *path, const char *env,
136*1cddb830SAndroid Build Coastguard Worker                                         const char *extension,
137*1cddb830SAndroid Build Coastguard Worker                                         khrIcdFileAdd addFunc, int bSort)
138*1cddb830SAndroid Build Coastguard Worker {
139*1cddb830SAndroid Build Coastguard Worker     DIR *dir = NULL;
140*1cddb830SAndroid Build Coastguard Worker     char* envPath = NULL;
141*1cddb830SAndroid Build Coastguard Worker 
142*1cddb830SAndroid Build Coastguard Worker     envPath = khrIcd_secure_getenv(env);
143*1cddb830SAndroid Build Coastguard Worker     if (NULL != envPath)
144*1cddb830SAndroid Build Coastguard Worker     {
145*1cddb830SAndroid Build Coastguard Worker         path = envPath;
146*1cddb830SAndroid Build Coastguard Worker     }
147*1cddb830SAndroid Build Coastguard Worker 
148*1cddb830SAndroid Build Coastguard Worker     dir = opendir(path);
149*1cddb830SAndroid Build Coastguard Worker     if (NULL == dir)
150*1cddb830SAndroid Build Coastguard Worker     {
151*1cddb830SAndroid Build Coastguard Worker         KHR_ICD_TRACE("Failed to open path %s, continuing\n", path);
152*1cddb830SAndroid Build Coastguard Worker     }
153*1cddb830SAndroid Build Coastguard Worker     else
154*1cddb830SAndroid Build Coastguard Worker     {
155*1cddb830SAndroid Build Coastguard Worker         struct dirent *dirEntry = NULL;
156*1cddb830SAndroid Build Coastguard Worker 
157*1cddb830SAndroid Build Coastguard Worker         // attempt to load all files in the directory
158*1cddb830SAndroid Build Coastguard Worker         if (bSort) {
159*1cddb830SAndroid Build Coastguard Worker             // store the entries name and type in a buffer for sorting
160*1cddb830SAndroid Build Coastguard Worker             size_t sz = 0;
161*1cddb830SAndroid Build Coastguard Worker             size_t elemCount = 0;
162*1cddb830SAndroid Build Coastguard Worker             size_t elemAlloc = 0;
163*1cddb830SAndroid Build Coastguard Worker             struct dirElem *dirElems = NULL;
164*1cddb830SAndroid Build Coastguard Worker             struct dirElem *newDirElems = NULL;
165*1cddb830SAndroid Build Coastguard Worker             const size_t startupAlloc = 8;
166*1cddb830SAndroid Build Coastguard Worker 
167*1cddb830SAndroid Build Coastguard Worker             // start with a small buffer
168*1cddb830SAndroid Build Coastguard Worker             dirElems = (struct dirElem *)malloc(startupAlloc*sizeof(struct dirElem));
169*1cddb830SAndroid Build Coastguard Worker             if (NULL != dirElems) {
170*1cddb830SAndroid Build Coastguard Worker                 elemAlloc = startupAlloc;
171*1cddb830SAndroid Build Coastguard Worker                 for (dirEntry = readdir(dir); dirEntry; dirEntry = readdir(dir) ) {
172*1cddb830SAndroid Build Coastguard Worker                     char *nameCopy = NULL;
173*1cddb830SAndroid Build Coastguard Worker 
174*1cddb830SAndroid Build Coastguard Worker                     if (elemCount + 1 > elemAlloc) {
175*1cddb830SAndroid Build Coastguard Worker                         // double buffer size if necessary and possible
176*1cddb830SAndroid Build Coastguard Worker                         if (elemAlloc >= UINT_MAX/2)
177*1cddb830SAndroid Build Coastguard Worker                             break;
178*1cddb830SAndroid Build Coastguard Worker                         newDirElems = (struct dirElem *)realloc(dirElems, elemAlloc*2*sizeof(struct dirElem));
179*1cddb830SAndroid Build Coastguard Worker                         if (NULL == newDirElems)
180*1cddb830SAndroid Build Coastguard Worker                             break;
181*1cddb830SAndroid Build Coastguard Worker                         dirElems = newDirElems;
182*1cddb830SAndroid Build Coastguard Worker                         elemAlloc *= 2;
183*1cddb830SAndroid Build Coastguard Worker                     }
184*1cddb830SAndroid Build Coastguard Worker                     sz = strlen(dirEntry->d_name) + 1;
185*1cddb830SAndroid Build Coastguard Worker                     nameCopy = (char *)malloc(sz);
186*1cddb830SAndroid Build Coastguard Worker                     if (NULL == nameCopy)
187*1cddb830SAndroid Build Coastguard Worker                          break;
188*1cddb830SAndroid Build Coastguard Worker                     memcpy(nameCopy, dirEntry->d_name, sz);
189*1cddb830SAndroid Build Coastguard Worker                     dirElems[elemCount].d_name = nameCopy;
190*1cddb830SAndroid Build Coastguard Worker                     dirElems[elemCount].d_type = dirEntry->d_type;
191*1cddb830SAndroid Build Coastguard Worker                     elemCount++;
192*1cddb830SAndroid Build Coastguard Worker                 }
193*1cddb830SAndroid Build Coastguard Worker                 qsort(dirElems, elemCount, sizeof(struct dirElem), compareDirElem);
194*1cddb830SAndroid Build Coastguard Worker                 for (struct dirElem *elem = dirElems; elem < dirElems + elemCount; ++elem) {
195*1cddb830SAndroid Build Coastguard Worker                     khrIcdOsDirEntryValidateAndAdd(elem->d_name, path, extension, addFunc);
196*1cddb830SAndroid Build Coastguard Worker                     free(elem->d_name);
197*1cddb830SAndroid Build Coastguard Worker                 }
198*1cddb830SAndroid Build Coastguard Worker                 free(dirElems);
199*1cddb830SAndroid Build Coastguard Worker             }
200*1cddb830SAndroid Build Coastguard Worker         } else
201*1cddb830SAndroid Build Coastguard Worker             // use system provided ordering
202*1cddb830SAndroid Build Coastguard Worker             for (dirEntry = readdir(dir); dirEntry; dirEntry = readdir(dir) )
203*1cddb830SAndroid Build Coastguard Worker                 khrIcdOsDirEntryValidateAndAdd(dirEntry->d_name, path, extension, addFunc);
204*1cddb830SAndroid Build Coastguard Worker 
205*1cddb830SAndroid Build Coastguard Worker         closedir(dir);
206*1cddb830SAndroid Build Coastguard Worker     }
207*1cddb830SAndroid Build Coastguard Worker 
208*1cddb830SAndroid Build Coastguard Worker     if (NULL != envPath)
209*1cddb830SAndroid Build Coastguard Worker     {
210*1cddb830SAndroid Build Coastguard Worker         khrIcd_free_getenv(envPath);
211*1cddb830SAndroid Build Coastguard Worker     }
212*1cddb830SAndroid Build Coastguard Worker }
213*1cddb830SAndroid Build Coastguard Worker 
214*1cddb830SAndroid Build Coastguard Worker // go through the list of vendors in the two configuration files
khrIcdOsVendorsEnumerate(void)215*1cddb830SAndroid Build Coastguard Worker void khrIcdOsVendorsEnumerate(void)
216*1cddb830SAndroid Build Coastguard Worker {
217*1cddb830SAndroid Build Coastguard Worker     khrIcdInitializeTrace();
218*1cddb830SAndroid Build Coastguard Worker     khrIcdVendorsEnumerateEnv();
219*1cddb830SAndroid Build Coastguard Worker 
220*1cddb830SAndroid Build Coastguard Worker     khrIcdOsDirEnumerate(ICD_VENDOR_PATH, "OCL_ICD_VENDORS", ".icd", khrIcdVendorAdd, 0);
221*1cddb830SAndroid Build Coastguard Worker 
222*1cddb830SAndroid Build Coastguard Worker #if defined(CL_ENABLE_LAYERS)
223*1cddb830SAndroid Build Coastguard Worker     // system layers should be closer to the driver
224*1cddb830SAndroid Build Coastguard Worker     khrIcdOsDirEnumerate(LAYER_PATH, "OPENCL_LAYER_PATH", ".lay", khrIcdLayerAdd, 1);
225*1cddb830SAndroid Build Coastguard Worker 
226*1cddb830SAndroid Build Coastguard Worker     khrIcdLayersEnumerateEnv();
227*1cddb830SAndroid Build Coastguard Worker #endif // defined(CL_ENABLE_LAYERS)
228*1cddb830SAndroid Build Coastguard Worker }
229*1cddb830SAndroid Build Coastguard Worker 
230*1cddb830SAndroid Build Coastguard Worker // go through the list of vendors only once
khrIcdOsVendorsEnumerateOnce(void)231*1cddb830SAndroid Build Coastguard Worker void khrIcdOsVendorsEnumerateOnce(void)
232*1cddb830SAndroid Build Coastguard Worker {
233*1cddb830SAndroid Build Coastguard Worker     pthread_once(&initialized, khrIcdOsVendorsEnumerate);
234*1cddb830SAndroid Build Coastguard Worker }
235*1cddb830SAndroid Build Coastguard Worker 
236*1cddb830SAndroid Build Coastguard Worker /*
237*1cddb830SAndroid Build Coastguard Worker  *
238*1cddb830SAndroid Build Coastguard Worker  * Dynamic library loading functions
239*1cddb830SAndroid Build Coastguard Worker  *
240*1cddb830SAndroid Build Coastguard Worker  */
241*1cddb830SAndroid Build Coastguard Worker 
242*1cddb830SAndroid Build Coastguard Worker // dynamically load a library.  returns NULL on failure
khrIcdOsLibraryLoad(const char * libraryName)243*1cddb830SAndroid Build Coastguard Worker void *khrIcdOsLibraryLoad(const char *libraryName)
244*1cddb830SAndroid Build Coastguard Worker {
245*1cddb830SAndroid Build Coastguard Worker     void* ret = dlopen (libraryName, RTLD_NOW);
246*1cddb830SAndroid Build Coastguard Worker     if (NULL == ret)
247*1cddb830SAndroid Build Coastguard Worker     {
248*1cddb830SAndroid Build Coastguard Worker         KHR_ICD_TRACE("Failed to load driver because %s.\n", dlerror());
249*1cddb830SAndroid Build Coastguard Worker     }
250*1cddb830SAndroid Build Coastguard Worker     return ret;
251*1cddb830SAndroid Build Coastguard Worker }
252*1cddb830SAndroid Build Coastguard Worker 
253*1cddb830SAndroid Build Coastguard Worker // get a function pointer from a loaded library.  returns NULL on failure.
khrIcdOsLibraryGetFunctionAddress(void * library,const char * functionName)254*1cddb830SAndroid Build Coastguard Worker void *khrIcdOsLibraryGetFunctionAddress(void *library, const char *functionName)
255*1cddb830SAndroid Build Coastguard Worker {
256*1cddb830SAndroid Build Coastguard Worker     return dlsym(library, functionName);
257*1cddb830SAndroid Build Coastguard Worker }
258*1cddb830SAndroid Build Coastguard Worker 
259*1cddb830SAndroid Build Coastguard Worker // unload a library
khrIcdOsLibraryUnload(void * library)260*1cddb830SAndroid Build Coastguard Worker void khrIcdOsLibraryUnload(void *library)
261*1cddb830SAndroid Build Coastguard Worker {
262*1cddb830SAndroid Build Coastguard Worker     dlclose(library);
263*1cddb830SAndroid Build Coastguard Worker }
264