1 //
2 // Copyright (c) 2017 The Khronos Group Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 #include "typeWrappers.h"
17 #include "kernelHelpers.h"
18 #include "errorHelpers.h"
19 #include <stdlib.h>
20 #include "clImageHelper.h"
21
22 #define ROUND_SIZE_UP(_size, _align) \
23 (((size_t)(_size) + (size_t)(_align)-1) & -((size_t)(_align)))
24
25 #if defined(__APPLE__)
26 #define kPageSize 4096
27 #include <sys/mman.h>
28 #include <stdlib.h>
29 #elif defined(__linux__)
30 #include <unistd.h>
31 #define kPageSize (getpagesize())
32 #endif
33
clProtectedImage(cl_context context,cl_mem_flags mem_flags,const cl_image_format * fmt,size_t width,cl_int * errcode_ret)34 clProtectedImage::clProtectedImage(cl_context context, cl_mem_flags mem_flags,
35 const cl_image_format *fmt, size_t width,
36 cl_int *errcode_ret)
37 {
38 cl_int err = Create(context, mem_flags, fmt, width);
39 if (errcode_ret != NULL) *errcode_ret = err;
40 }
41
Create(cl_context context,cl_mem_flags mem_flags,const cl_image_format * fmt,size_t width)42 cl_int clProtectedImage::Create(cl_context context, cl_mem_flags mem_flags,
43 const cl_image_format *fmt, size_t width)
44 {
45 cl_int error;
46 #if defined(__APPLE__)
47 int protect_pages = 1;
48 cl_device_id devices[16];
49 size_t number_of_devices;
50 error = clGetContextInfo(context, CL_CONTEXT_DEVICES, sizeof(devices),
51 devices, &number_of_devices);
52 test_error(error, "clGetContextInfo for CL_CONTEXT_DEVICES failed");
53
54 number_of_devices /= sizeof(cl_device_id);
55 for (int i = 0; i < (int)number_of_devices; i++)
56 {
57 cl_device_type type;
58 error = clGetDeviceInfo(devices[i], CL_DEVICE_TYPE, sizeof(type), &type,
59 NULL);
60 test_error(error, "clGetDeviceInfo for CL_DEVICE_TYPE failed");
61 if (type == CL_DEVICE_TYPE_GPU)
62 {
63 protect_pages = 0;
64 break;
65 }
66 }
67
68 if (protect_pages)
69 {
70 size_t pixelBytes = get_pixel_bytes(fmt);
71 size_t rowBytes = ROUND_SIZE_UP(width * pixelBytes, kPageSize);
72 size_t rowStride = rowBytes + kPageSize;
73
74 // create backing store
75 backingStoreSize = rowStride + 8 * rowStride;
76 backingStore = mmap(0, backingStoreSize, PROT_READ | PROT_WRITE,
77 MAP_ANON | MAP_PRIVATE, 0, 0);
78
79 // add guard pages
80 size_t row;
81 char *p = (char *)backingStore;
82 char *imagePtr = (char *)backingStore + 4 * rowStride;
83 for (row = 0; row < 4; row++)
84 {
85 mprotect(p, rowStride, PROT_NONE);
86 p += rowStride;
87 }
88 p += rowBytes;
89 mprotect(p, kPageSize, PROT_NONE);
90 p += rowStride;
91 p -= rowBytes;
92 for (row = 0; row < 4; row++)
93 {
94 mprotect(p, rowStride, PROT_NONE);
95 p += rowStride;
96 }
97
98 if (getenv("CL_ALIGN_RIGHT"))
99 {
100 static int spewEnv = 1;
101 if (spewEnv)
102 {
103 log_info("***CL_ALIGN_RIGHT is set. Aligning images at right "
104 "edge of page\n");
105 spewEnv = 0;
106 }
107 imagePtr += rowBytes - pixelBytes * width;
108 }
109
110 image = create_image_1d(context, mem_flags | CL_MEM_USE_HOST_PTR, fmt,
111 width, rowStride, imagePtr, NULL, &error);
112 }
113 else
114 {
115 backingStore = NULL;
116 image = create_image_1d(context, mem_flags, fmt, width, 0, NULL, NULL,
117 &error);
118 }
119 #else
120
121 backingStore = NULL;
122 image =
123 create_image_1d(context, mem_flags, fmt, width, 0, NULL, NULL, &error);
124
125 #endif
126 return error;
127 }
128
129
clProtectedImage(cl_context context,cl_mem_flags mem_flags,const cl_image_format * fmt,size_t width,size_t height,cl_int * errcode_ret)130 clProtectedImage::clProtectedImage(cl_context context, cl_mem_flags mem_flags,
131 const cl_image_format *fmt, size_t width,
132 size_t height, cl_int *errcode_ret)
133 {
134 cl_int err = Create(context, mem_flags, fmt, width, height);
135 if (errcode_ret != NULL) *errcode_ret = err;
136 }
137
Create(cl_context context,cl_mem_flags mem_flags,const cl_image_format * fmt,size_t width,size_t height)138 cl_int clProtectedImage::Create(cl_context context, cl_mem_flags mem_flags,
139 const cl_image_format *fmt, size_t width,
140 size_t height)
141 {
142 cl_int error;
143 #if defined(__APPLE__)
144 int protect_pages = 1;
145 cl_device_id devices[16];
146 size_t number_of_devices;
147 error = clGetContextInfo(context, CL_CONTEXT_DEVICES, sizeof(devices),
148 devices, &number_of_devices);
149 test_error(error, "clGetContextInfo for CL_CONTEXT_DEVICES failed");
150
151 number_of_devices /= sizeof(cl_device_id);
152 for (int i = 0; i < (int)number_of_devices; i++)
153 {
154 cl_device_type type;
155 error = clGetDeviceInfo(devices[i], CL_DEVICE_TYPE, sizeof(type), &type,
156 NULL);
157 test_error(error, "clGetDeviceInfo for CL_DEVICE_TYPE failed");
158 if (type == CL_DEVICE_TYPE_GPU)
159 {
160 protect_pages = 0;
161 break;
162 }
163 }
164
165 if (protect_pages)
166 {
167 size_t pixelBytes = get_pixel_bytes(fmt);
168 size_t rowBytes = ROUND_SIZE_UP(width * pixelBytes, kPageSize);
169 size_t rowStride = rowBytes + kPageSize;
170
171 // create backing store
172 backingStoreSize = height * rowStride + 8 * rowStride;
173 backingStore = mmap(0, backingStoreSize, PROT_READ | PROT_WRITE,
174 MAP_ANON | MAP_PRIVATE, 0, 0);
175
176 // add guard pages
177 size_t row;
178 char *p = (char *)backingStore;
179 char *imagePtr = (char *)backingStore + 4 * rowStride;
180 for (row = 0; row < 4; row++)
181 {
182 mprotect(p, rowStride, PROT_NONE);
183 p += rowStride;
184 }
185 p += rowBytes;
186 for (row = 0; row < height; row++)
187 {
188 mprotect(p, kPageSize, PROT_NONE);
189 p += rowStride;
190 }
191 p -= rowBytes;
192 for (row = 0; row < 4; row++)
193 {
194 mprotect(p, rowStride, PROT_NONE);
195 p += rowStride;
196 }
197
198 if (getenv("CL_ALIGN_RIGHT"))
199 {
200 static int spewEnv = 1;
201 if (spewEnv)
202 {
203 log_info("***CL_ALIGN_RIGHT is set. Aligning images at right "
204 "edge of page\n");
205 spewEnv = 0;
206 }
207 imagePtr += rowBytes - pixelBytes * width;
208 }
209
210 image = create_image_2d(context, mem_flags | CL_MEM_USE_HOST_PTR, fmt,
211 width, height, rowStride, imagePtr, &error);
212 }
213 else
214 {
215 backingStore = NULL;
216 image = create_image_2d(context, mem_flags, fmt, width, height, 0, NULL,
217 &error);
218 }
219 #else
220
221 backingStore = NULL;
222 image = create_image_2d(context, mem_flags, fmt, width, height, 0, NULL,
223 &error);
224
225 #endif
226 return error;
227 }
228
clProtectedImage(cl_context context,cl_mem_flags mem_flags,const cl_image_format * fmt,size_t width,size_t height,size_t depth,cl_int * errcode_ret)229 clProtectedImage::clProtectedImage(cl_context context, cl_mem_flags mem_flags,
230 const cl_image_format *fmt, size_t width,
231 size_t height, size_t depth,
232 cl_int *errcode_ret)
233 {
234 cl_int err = Create(context, mem_flags, fmt, width, height, depth);
235 if (errcode_ret != NULL) *errcode_ret = err;
236 }
237
Create(cl_context context,cl_mem_flags mem_flags,const cl_image_format * fmt,size_t width,size_t height,size_t depth)238 cl_int clProtectedImage::Create(cl_context context, cl_mem_flags mem_flags,
239 const cl_image_format *fmt, size_t width,
240 size_t height, size_t depth)
241 {
242 cl_int error;
243
244 #if defined(__APPLE__)
245 int protect_pages = 1;
246 cl_device_id devices[16];
247 size_t number_of_devices;
248 error = clGetContextInfo(context, CL_CONTEXT_DEVICES, sizeof(devices),
249 devices, &number_of_devices);
250 test_error(error, "clGetContextInfo for CL_CONTEXT_DEVICES failed");
251
252 number_of_devices /= sizeof(cl_device_id);
253 for (int i = 0; i < (int)number_of_devices; i++)
254 {
255 cl_device_type type;
256 error = clGetDeviceInfo(devices[i], CL_DEVICE_TYPE, sizeof(type), &type,
257 NULL);
258 test_error(error, "clGetDeviceInfo for CL_DEVICE_TYPE failed");
259 if (type == CL_DEVICE_TYPE_GPU)
260 {
261 protect_pages = 0;
262 break;
263 }
264 }
265
266 if (protect_pages)
267 {
268 size_t pixelBytes = get_pixel_bytes(fmt);
269 size_t rowBytes = ROUND_SIZE_UP(width * pixelBytes, kPageSize);
270 size_t rowStride = rowBytes + kPageSize;
271
272 // create backing store
273 backingStoreSize = height * depth * rowStride + 8 * rowStride;
274 backingStore = mmap(0, backingStoreSize, PROT_READ | PROT_WRITE,
275 MAP_ANON | MAP_PRIVATE, 0, 0);
276
277 // add guard pages
278 size_t row;
279 char *p = (char *)backingStore;
280 char *imagePtr = (char *)backingStore + 4 * rowStride;
281 for (row = 0; row < 4; row++)
282 {
283 mprotect(p, rowStride, PROT_NONE);
284 p += rowStride;
285 }
286 p += rowBytes;
287 for (row = 0; row < height * depth; row++)
288 {
289 mprotect(p, kPageSize, PROT_NONE);
290 p += rowStride;
291 }
292 p -= rowBytes;
293 for (row = 0; row < 4; row++)
294 {
295 mprotect(p, rowStride, PROT_NONE);
296 p += rowStride;
297 }
298
299 if (getenv("CL_ALIGN_RIGHT"))
300 {
301 static int spewEnv = 1;
302 if (spewEnv)
303 {
304 log_info("***CL_ALIGN_RIGHT is set. Aligning images at right "
305 "edge of page\n");
306 spewEnv = 0;
307 }
308 imagePtr += rowBytes - pixelBytes * width;
309 }
310
311 image = create_image_3d(context, mem_flags | CL_MEM_USE_HOST_PTR, fmt,
312 width, height, depth, rowStride,
313 height * rowStride, imagePtr, &error);
314 }
315 else
316 {
317 backingStore = NULL;
318 image = create_image_3d(context, mem_flags, fmt, width, height, depth,
319 0, 0, NULL, &error);
320 }
321 #else
322
323 backingStore = NULL;
324 image = create_image_3d(context, mem_flags, fmt, width, height, depth, 0, 0,
325 NULL, &error);
326
327 #endif
328
329 return error;
330 }
331
332
clProtectedImage(cl_context context,cl_mem_object_type imageType,cl_mem_flags mem_flags,const cl_image_format * fmt,size_t width,size_t height,size_t depth,size_t arraySize,cl_int * errcode_ret)333 clProtectedImage::clProtectedImage(cl_context context,
334 cl_mem_object_type imageType,
335 cl_mem_flags mem_flags,
336 const cl_image_format *fmt, size_t width,
337 size_t height, size_t depth,
338 size_t arraySize, cl_int *errcode_ret)
339 {
340 cl_int err = Create(context, imageType, mem_flags, fmt, width, height,
341 depth, arraySize);
342 if (errcode_ret != NULL) *errcode_ret = err;
343 }
344
Create(cl_context context,cl_mem_object_type imageType,cl_mem_flags mem_flags,const cl_image_format * fmt,size_t width,size_t height,size_t depth,size_t arraySize)345 cl_int clProtectedImage::Create(cl_context context,
346 cl_mem_object_type imageType,
347 cl_mem_flags mem_flags,
348 const cl_image_format *fmt, size_t width,
349 size_t height, size_t depth, size_t arraySize)
350 {
351 cl_int error;
352 #if defined(__APPLE__)
353 int protect_pages = 1;
354 cl_device_id devices[16];
355 size_t number_of_devices;
356 error = clGetContextInfo(context, CL_CONTEXT_DEVICES, sizeof(devices),
357 devices, &number_of_devices);
358 test_error(error, "clGetContextInfo for CL_CONTEXT_DEVICES failed");
359
360 number_of_devices /= sizeof(cl_device_id);
361 for (int i = 0; i < (int)number_of_devices; i++)
362 {
363 cl_device_type type;
364 error = clGetDeviceInfo(devices[i], CL_DEVICE_TYPE, sizeof(type), &type,
365 NULL);
366 test_error(error, "clGetDeviceInfo for CL_DEVICE_TYPE failed");
367 if (type == CL_DEVICE_TYPE_GPU)
368 {
369 protect_pages = 0;
370 break;
371 }
372 }
373
374 if (protect_pages)
375 {
376 size_t pixelBytes = get_pixel_bytes(fmt);
377 size_t rowBytes = ROUND_SIZE_UP(width * pixelBytes, kPageSize);
378 size_t rowStride = rowBytes + kPageSize;
379
380 // create backing store
381 switch (imageType)
382 {
383 case CL_MEM_OBJECT_IMAGE1D:
384 backingStoreSize = rowStride + 8 * rowStride;
385 break;
386 case CL_MEM_OBJECT_IMAGE2D:
387 backingStoreSize = height * rowStride + 8 * rowStride;
388 break;
389 case CL_MEM_OBJECT_IMAGE3D:
390 backingStoreSize = height * depth * rowStride + 8 * rowStride;
391 break;
392 case CL_MEM_OBJECT_IMAGE1D_ARRAY:
393 backingStoreSize = arraySize * rowStride + 8 * rowStride;
394 break;
395 case CL_MEM_OBJECT_IMAGE2D_ARRAY:
396 backingStoreSize =
397 height * arraySize * rowStride + 8 * rowStride;
398 break;
399 }
400 backingStore = mmap(0, backingStoreSize, PROT_READ | PROT_WRITE,
401 MAP_ANON | MAP_PRIVATE, 0, 0);
402
403 // add guard pages
404 size_t row;
405 char *p = (char *)backingStore;
406 char *imagePtr = (char *)backingStore + 4 * rowStride;
407 for (row = 0; row < 4; row++)
408 {
409 mprotect(p, rowStride, PROT_NONE);
410 p += rowStride;
411 }
412 p += rowBytes;
413 size_t sz = (height > 0 ? height : 1) * (depth > 0 ? depth : 1)
414 * (arraySize > 0 ? arraySize : 1);
415 for (row = 0; row < sz; row++)
416 {
417 mprotect(p, kPageSize, PROT_NONE);
418 p += rowStride;
419 }
420 p -= rowBytes;
421 for (row = 0; row < 4; row++)
422 {
423 mprotect(p, rowStride, PROT_NONE);
424 p += rowStride;
425 }
426
427 if (getenv("CL_ALIGN_RIGHT"))
428 {
429 static int spewEnv = 1;
430 if (spewEnv)
431 {
432 log_info("***CL_ALIGN_RIGHT is set. Aligning images at right "
433 "edge of page\n");
434 spewEnv = 0;
435 }
436 imagePtr += rowBytes - pixelBytes * width;
437 }
438
439 switch (imageType)
440 {
441 case CL_MEM_OBJECT_IMAGE1D:
442 image = create_image_1d(
443 context, mem_flags | CL_MEM_USE_HOST_PTR, fmt, width,
444 rowStride, imagePtr, NULL, &error);
445 break;
446 case CL_MEM_OBJECT_IMAGE2D:
447 image = create_image_2d(
448 context, mem_flags | CL_MEM_USE_HOST_PTR, fmt, width,
449 height, rowStride, imagePtr, &error);
450 break;
451 case CL_MEM_OBJECT_IMAGE3D:
452 image =
453 create_image_3d(context, mem_flags | CL_MEM_USE_HOST_PTR,
454 fmt, width, height, depth, rowStride,
455 height * rowStride, imagePtr, &error);
456 break;
457 case CL_MEM_OBJECT_IMAGE1D_ARRAY:
458 image = create_image_1d_array(
459 context, mem_flags | CL_MEM_USE_HOST_PTR, fmt, width,
460 arraySize, rowStride, rowStride, imagePtr, &error);
461 break;
462 case CL_MEM_OBJECT_IMAGE2D_ARRAY:
463 image = create_image_2d_array(
464 context, mem_flags | CL_MEM_USE_HOST_PTR, fmt, width,
465 height, arraySize, rowStride, height * rowStride, imagePtr,
466 &error);
467 break;
468 }
469 }
470 else
471 {
472 backingStore = NULL;
473 switch (imageType)
474 {
475 case CL_MEM_OBJECT_IMAGE1D:
476 image = create_image_1d(context, mem_flags, fmt, width, 0, NULL,
477 NULL, &error);
478 break;
479 case CL_MEM_OBJECT_IMAGE2D:
480 image = create_image_2d(context, mem_flags, fmt, width, height,
481 0, NULL, &error);
482 break;
483 case CL_MEM_OBJECT_IMAGE3D:
484 image = create_image_3d(context, mem_flags, fmt, width, height,
485 depth, 0, 0, NULL, &error);
486 break;
487 case CL_MEM_OBJECT_IMAGE1D_ARRAY:
488 image = create_image_1d_array(context, mem_flags, fmt, width,
489 arraySize, 0, 0, NULL, &error);
490 break;
491 case CL_MEM_OBJECT_IMAGE2D_ARRAY:
492 image = create_image_2d_array(context, mem_flags, fmt, width,
493 height, arraySize, 0, 0, NULL,
494 &error);
495 break;
496 }
497 }
498 #else
499
500 backingStore = NULL;
501 switch (imageType)
502 {
503 case CL_MEM_OBJECT_IMAGE1D:
504 image = create_image_1d(context, mem_flags, fmt, width, 0, NULL,
505 NULL, &error);
506 break;
507 case CL_MEM_OBJECT_IMAGE2D:
508 image = create_image_2d(context, mem_flags, fmt, width, height, 0,
509 NULL, &error);
510 break;
511 case CL_MEM_OBJECT_IMAGE3D:
512 image = create_image_3d(context, mem_flags, fmt, width, height,
513 depth, 0, 0, NULL, &error);
514 break;
515 case CL_MEM_OBJECT_IMAGE1D_ARRAY:
516 image = create_image_1d_array(context, mem_flags, fmt, width,
517 arraySize, 0, 0, NULL, &error);
518 break;
519 case CL_MEM_OBJECT_IMAGE2D_ARRAY:
520 image =
521 create_image_2d_array(context, mem_flags, fmt, width, height,
522 arraySize, 0, 0, NULL, &error);
523 break;
524 }
525 #endif
526 return error;
527 }
528
529
530 /*******
531 * clProtectedArray implementation
532 *******/
clProtectedArray()533 clProtectedArray::clProtectedArray() { mBuffer = mValidBuffer = NULL; }
534
clProtectedArray(size_t sizeInBytes)535 clProtectedArray::clProtectedArray(size_t sizeInBytes)
536 {
537 mBuffer = mValidBuffer = NULL;
538 Allocate(sizeInBytes);
539 }
540
~clProtectedArray()541 clProtectedArray::~clProtectedArray()
542 {
543 if (mBuffer != NULL)
544 {
545 #if defined(__APPLE__)
546 int error = munmap(mBuffer, mRealSize);
547 if (error) log_error("WARNING: munmap failed in clProtectedArray.\n");
548 #else
549 free(mBuffer);
550 #endif
551 }
552 }
553
Allocate(size_t sizeInBytes)554 void clProtectedArray::Allocate(size_t sizeInBytes)
555 {
556
557 #if defined(__APPLE__)
558
559 // Allocate enough space to: round up our actual allocation to an even
560 // number of pages and allocate two pages on either side
561 mRoundedSize = ROUND_SIZE_UP(sizeInBytes, kPageSize);
562 mRealSize = mRoundedSize + kPageSize * 2;
563
564 // Use mmap here to ensure we start on a page boundary, so the mprotect
565 // calls will work OK
566 mBuffer = (char *)mmap(0, mRealSize, PROT_READ | PROT_WRITE,
567 MAP_ANON | MAP_PRIVATE, 0, 0);
568
569 mValidBuffer = mBuffer + kPageSize;
570
571 // Protect guard area from access
572 mprotect(mValidBuffer - kPageSize, kPageSize, PROT_NONE);
573 mprotect(mValidBuffer + mRoundedSize, kPageSize, PROT_NONE);
574 #else
575 mRoundedSize = mRealSize = sizeInBytes;
576 mBuffer = mValidBuffer = (char *)calloc(1, mRealSize);
577 #endif
578 }
579