1 /*
2 * Copyright 2019 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 */
23
24 #include "CUnit/Basic.h"
25
26 #include "amdgpu_test.h"
27 #include "amdgpu_drm.h"
28 #include "amdgpu_internal.h"
29
30 #include <string.h>
31 #include <unistd.h>
32 #ifdef __FreeBSD__
33 #include <sys/endian.h>
34 #else
35 #include <endian.h>
36 #endif
37 #include <strings.h>
38 #include <xf86drm.h>
39
40 static amdgpu_device_handle device_handle;
41 static uint32_t major_version;
42 static uint32_t minor_version;
43
44 static struct drm_amdgpu_info_hw_ip sdma_info;
45
46 #ifndef ARRAY_SIZE
47 #define ARRAY_SIZE(_Arr) (sizeof(_Arr)/sizeof((_Arr)[0]))
48 #endif
49
50
51 /* --------------------- Secure bounce test ------------------------ *
52 *
53 * The secure bounce test tests that we can evict a TMZ buffer,
54 * and page it back in, via a bounce buffer, as it encryption/decryption
55 * depends on its physical address, and have the same data, i.e. data
56 * integrity is preserved.
57 *
58 * The steps are as follows (from Christian K.):
59 *
60 * Buffer A which is TMZ protected and filled by the CPU with a
61 * certain pattern. That the GPU is reading only random nonsense from
62 * that pattern is irrelevant for the test.
63 *
64 * This buffer A is then secure copied into buffer B which is also
65 * TMZ protected.
66 *
67 * Buffer B is moved around, from VRAM to GTT, GTT to SYSTEM,
68 * etc.
69 *
70 * Then, we use another secure copy of buffer B back to buffer A.
71 *
72 * And lastly we check with the CPU the pattern.
73 *
74 * Assuming that we don't have memory contention and buffer A stayed
75 * at the same place, we should still see the same pattern when read
76 * by the CPU.
77 *
78 * If we don't see the same pattern then something in the buffer
79 * migration code is not working as expected.
80 */
81
82 #define SECURE_BOUNCE_TEST_STR "secure bounce"
83 #define SECURE_BOUNCE_FAILED_STR SECURE_BOUNCE_TEST_STR " failed"
84
85 #define PRINT_ERROR(_Res) fprintf(stderr, "%s:%d: %s (%d)\n", \
86 __func__, __LINE__, strerror(-(_Res)), _Res)
87
88 #define PACKET_LCOPY_SIZE 7
89 #define PACKET_NOP_SIZE 12
90
91 struct sec_amdgpu_bo {
92 struct amdgpu_bo *bo;
93 struct amdgpu_va *va;
94 };
95
96 struct command_ctx {
97 struct amdgpu_device *dev;
98 struct amdgpu_cs_ib_info cs_ibinfo;
99 struct amdgpu_cs_request cs_req;
100 struct amdgpu_context *context;
101 int ring_id;
102 };
103
104 /**
105 * amdgpu_bo_alloc_map -- Allocate and map a buffer object (BO)
106 * @dev: The AMDGPU device this BO belongs to.
107 * @size: The size of the BO.
108 * @alignment: Alignment of the BO.
109 * @gem_domain: One of AMDGPU_GEM_DOMAIN_xyz.
110 * @alloc_flags: One of AMDGPU_GEM_CREATE_xyz.
111 * @sbo: the result
112 *
113 * Allocate a buffer object (BO) with the desired attributes
114 * as specified by the argument list and write out the result
115 * into @sbo.
116 *
117 * Return 0 on success and @sbo->bo and @sbo->va are set,
118 * or -errno on error.
119 */
amdgpu_bo_alloc_map(struct amdgpu_device * dev,unsigned size,unsigned alignment,unsigned gem_domain,uint64_t alloc_flags,struct sec_amdgpu_bo * sbo)120 static int amdgpu_bo_alloc_map(struct amdgpu_device *dev,
121 unsigned size,
122 unsigned alignment,
123 unsigned gem_domain,
124 uint64_t alloc_flags,
125 struct sec_amdgpu_bo *sbo)
126 {
127 void *cpu;
128 uint64_t mc_addr;
129
130 return amdgpu_bo_alloc_and_map_raw(dev,
131 size,
132 alignment,
133 gem_domain,
134 alloc_flags,
135 0,
136 &sbo->bo,
137 &cpu, &mc_addr,
138 &sbo->va);
139 }
140
amdgpu_bo_unmap_free(struct sec_amdgpu_bo * sbo,const uint64_t size)141 static void amdgpu_bo_unmap_free(struct sec_amdgpu_bo *sbo,
142 const uint64_t size)
143 {
144 (void) amdgpu_bo_unmap_and_free(sbo->bo,
145 sbo->va,
146 sbo->va->address,
147 size);
148 sbo->bo = NULL;
149 sbo->va = NULL;
150 }
151
amdgpu_sdma_lcopy(uint32_t * packet,const uint64_t dst,const uint64_t src,const uint32_t size,const int secure)152 static void amdgpu_sdma_lcopy(uint32_t *packet,
153 const uint64_t dst,
154 const uint64_t src,
155 const uint32_t size,
156 const int secure)
157 {
158 /* Set the packet to Linear copy with TMZ set.
159 */
160 packet[0] = htole32(secure << 18 | 1);
161 packet[1] = htole32(size-1);
162 packet[2] = htole32(0);
163 packet[3] = htole32((uint32_t)(src & 0xFFFFFFFFU));
164 packet[4] = htole32((uint32_t)(src >> 32));
165 packet[5] = htole32((uint32_t)(dst & 0xFFFFFFFFU));
166 packet[6] = htole32((uint32_t)(dst >> 32));
167 }
168
amdgpu_sdma_nop(uint32_t * packet,uint32_t nop_count)169 static void amdgpu_sdma_nop(uint32_t *packet, uint32_t nop_count)
170 {
171 /* A packet of the desired number of NOPs.
172 */
173 packet[0] = htole32(nop_count << 16);
174 for ( ; nop_count > 0; nop_count--)
175 packet[nop_count-1] = 0;
176 }
177
178 /**
179 * amdgpu_bo_lcopy -- linear copy with TMZ set, using sDMA
180 * @dev: AMDGPU device to which both buffer objects belong to
181 * @dst: destination buffer object
182 * @src: source buffer object
183 * @size: size of memory to move, in bytes.
184 * @secure: Set to 1 to perform secure copy, 0 for clear
185 *
186 * Issues and waits for completion of a Linear Copy with TMZ
187 * set, to the sDMA engine. @size should be a multiple of
188 * at least 16 bytes.
189 */
amdgpu_bo_lcopy(struct command_ctx * ctx,struct sec_amdgpu_bo * dst,struct sec_amdgpu_bo * src,const uint32_t size,int secure)190 static void amdgpu_bo_lcopy(struct command_ctx *ctx,
191 struct sec_amdgpu_bo *dst,
192 struct sec_amdgpu_bo *src,
193 const uint32_t size,
194 int secure)
195 {
196 struct amdgpu_bo *bos[] = { dst->bo, src->bo };
197 uint32_t packet[PACKET_LCOPY_SIZE];
198
199 amdgpu_sdma_lcopy(packet,
200 dst->va->address,
201 src->va->address,
202 size, secure);
203 amdgpu_test_exec_cs_helper_raw(ctx->dev, ctx->context,
204 AMDGPU_HW_IP_DMA, ctx->ring_id,
205 ARRAY_SIZE(packet), packet,
206 ARRAY_SIZE(bos), bos,
207 &ctx->cs_ibinfo, &ctx->cs_req,
208 secure == 1);
209 }
210
211 /**
212 * amdgpu_bo_move -- Evoke a move of the buffer object (BO)
213 * @dev: device to which this buffer object belongs to
214 * @bo: the buffer object to be moved
215 * @whereto: one of AMDGPU_GEM_DOMAIN_xyz
216 * @secure: set to 1 to submit secure IBs
217 *
218 * Evokes a move of the buffer object @bo to the GEM domain
219 * descibed by @whereto.
220 *
221 * Returns 0 on sucess; -errno on error.
222 */
amdgpu_bo_move(struct command_ctx * ctx,struct amdgpu_bo * bo,uint64_t whereto,int secure)223 static int amdgpu_bo_move(struct command_ctx *ctx,
224 struct amdgpu_bo *bo,
225 uint64_t whereto,
226 int secure)
227 {
228 struct amdgpu_bo *bos[] = { bo };
229 struct drm_amdgpu_gem_op gop = {
230 .handle = bo->handle,
231 .op = AMDGPU_GEM_OP_SET_PLACEMENT,
232 .value = whereto,
233 };
234 uint32_t packet[PACKET_NOP_SIZE];
235 int res;
236
237 /* Change the buffer's placement.
238 */
239 res = drmIoctl(ctx->dev->fd, DRM_IOCTL_AMDGPU_GEM_OP, &gop);
240 if (res)
241 return -errno;
242
243 /* Now issue a NOP to actually evoke the MM to move
244 * it to the desired location.
245 */
246 amdgpu_sdma_nop(packet, PACKET_NOP_SIZE);
247 amdgpu_test_exec_cs_helper_raw(ctx->dev, ctx->context,
248 AMDGPU_HW_IP_DMA, ctx->ring_id,
249 ARRAY_SIZE(packet), packet,
250 ARRAY_SIZE(bos), bos,
251 &ctx->cs_ibinfo, &ctx->cs_req,
252 secure == 1);
253 return 0;
254 }
255
256 /* Safe, O Sec!
257 */
258 static const uint8_t secure_pattern[] = { 0x5A, 0xFE, 0x05, 0xEC };
259
260 #define SECURE_BUFFER_SIZE (4 * 1024 * sizeof(secure_pattern))
261
amdgpu_secure_bounce(void)262 static void amdgpu_secure_bounce(void)
263 {
264 struct sec_amdgpu_bo alice, bob;
265 struct command_ctx sb_ctx;
266 long page_size;
267 uint8_t *pp;
268 int res;
269
270 page_size = sysconf(_SC_PAGESIZE);
271
272 memset(&sb_ctx, 0, sizeof(sb_ctx));
273 sb_ctx.dev = device_handle;
274 res = amdgpu_cs_ctx_create(sb_ctx.dev, &sb_ctx.context);
275 if (res) {
276 PRINT_ERROR(res);
277 CU_FAIL(SECURE_BOUNCE_FAILED_STR);
278 return;
279 }
280
281 /* Use the first present ring.
282 */
283 res = ffs(sdma_info.available_rings) - 1;
284 if (res == -1) {
285 PRINT_ERROR(-ENOENT);
286 CU_FAIL(SECURE_BOUNCE_FAILED_STR);
287 goto Out_free_ctx;
288 }
289 sb_ctx.ring_id = res;
290
291 /* Allocate a buffer named Alice in VRAM.
292 */
293 res = amdgpu_bo_alloc_map(device_handle,
294 SECURE_BUFFER_SIZE,
295 page_size,
296 AMDGPU_GEM_DOMAIN_VRAM,
297 AMDGPU_GEM_CREATE_ENCRYPTED,
298 &alice);
299 if (res) {
300 PRINT_ERROR(res);
301 CU_FAIL(SECURE_BOUNCE_FAILED_STR);
302 return;
303 }
304
305 /* Fill Alice with a pattern.
306 */
307 for (pp = alice.bo->cpu_ptr;
308 pp < (__typeof__(pp)) alice.bo->cpu_ptr + SECURE_BUFFER_SIZE;
309 pp += sizeof(secure_pattern))
310 memcpy(pp, secure_pattern, sizeof(secure_pattern));
311
312 /* Allocate a buffer named Bob in VRAM.
313 */
314 res = amdgpu_bo_alloc_map(device_handle,
315 SECURE_BUFFER_SIZE,
316 page_size,
317 AMDGPU_GEM_DOMAIN_VRAM,
318 AMDGPU_GEM_CREATE_ENCRYPTED,
319 &bob);
320 if (res) {
321 PRINT_ERROR(res);
322 CU_FAIL(SECURE_BOUNCE_FAILED_STR);
323 goto Out_free_Alice;
324 }
325
326 /* sDMA TMZ copy from Alice to Bob.
327 */
328 amdgpu_bo_lcopy(&sb_ctx, &bob, &alice, SECURE_BUFFER_SIZE, 1);
329
330 /* Move Bob to the GTT domain.
331 */
332 res = amdgpu_bo_move(&sb_ctx, bob.bo, AMDGPU_GEM_DOMAIN_GTT, 0);
333 if (res) {
334 PRINT_ERROR(res);
335 CU_FAIL(SECURE_BOUNCE_FAILED_STR);
336 goto Out_free_all;
337 }
338
339 /* sDMA TMZ copy from Bob to Alice.
340 */
341 amdgpu_bo_lcopy(&sb_ctx, &alice, &bob, SECURE_BUFFER_SIZE, 1);
342
343 /* Verify the contents of Alice.
344 */
345 for (pp = alice.bo->cpu_ptr;
346 pp < (__typeof__(pp)) alice.bo->cpu_ptr + SECURE_BUFFER_SIZE;
347 pp += sizeof(secure_pattern)) {
348 res = memcmp(pp, secure_pattern, sizeof(secure_pattern));
349 if (res) {
350 fprintf(stderr, SECURE_BOUNCE_FAILED_STR);
351 CU_FAIL(SECURE_BOUNCE_FAILED_STR);
352 break;
353 }
354 }
355
356 Out_free_all:
357 amdgpu_bo_unmap_free(&bob, SECURE_BUFFER_SIZE);
358 Out_free_Alice:
359 amdgpu_bo_unmap_free(&alice, SECURE_BUFFER_SIZE);
360 Out_free_ctx:
361 res = amdgpu_cs_ctx_free(sb_ctx.context);
362 CU_ASSERT_EQUAL(res, 0);
363 }
364
365 /* ----------------------------------------------------------------- */
366
amdgpu_security_alloc_buf_test(void)367 static void amdgpu_security_alloc_buf_test(void)
368 {
369 amdgpu_bo_handle bo;
370 amdgpu_va_handle va_handle;
371 uint64_t bo_mc;
372 int r;
373
374 /* Test secure buffer allocation in VRAM */
375 bo = gpu_mem_alloc(device_handle, 4096, 4096,
376 AMDGPU_GEM_DOMAIN_VRAM,
377 AMDGPU_GEM_CREATE_ENCRYPTED,
378 &bo_mc, &va_handle);
379
380 r = gpu_mem_free(bo, va_handle, bo_mc, 4096);
381 CU_ASSERT_EQUAL(r, 0);
382
383 /* Test secure buffer allocation in system memory */
384 bo = gpu_mem_alloc(device_handle, 4096, 4096,
385 AMDGPU_GEM_DOMAIN_GTT,
386 AMDGPU_GEM_CREATE_ENCRYPTED,
387 &bo_mc, &va_handle);
388
389 r = gpu_mem_free(bo, va_handle, bo_mc, 4096);
390 CU_ASSERT_EQUAL(r, 0);
391
392 /* Test secure buffer allocation in invisible VRAM */
393 bo = gpu_mem_alloc(device_handle, 4096, 4096,
394 AMDGPU_GEM_DOMAIN_GTT,
395 AMDGPU_GEM_CREATE_ENCRYPTED |
396 AMDGPU_GEM_CREATE_NO_CPU_ACCESS,
397 &bo_mc, &va_handle);
398
399 r = gpu_mem_free(bo, va_handle, bo_mc, 4096);
400 CU_ASSERT_EQUAL(r, 0);
401 }
402
amdgpu_security_gfx_submission_test(void)403 static void amdgpu_security_gfx_submission_test(void)
404 {
405 amdgpu_command_submission_write_linear_helper_with_secure(device_handle,
406 AMDGPU_HW_IP_GFX,
407 true);
408 }
409
amdgpu_security_sdma_submission_test(void)410 static void amdgpu_security_sdma_submission_test(void)
411 {
412 amdgpu_command_submission_write_linear_helper_with_secure(device_handle,
413 AMDGPU_HW_IP_DMA,
414 true);
415 }
416
417 /* ----------------------------------------------------------------- */
418
419 CU_TestInfo security_tests[] = {
420 { "allocate secure buffer test", amdgpu_security_alloc_buf_test },
421 { "graphics secure command submission", amdgpu_security_gfx_submission_test },
422 { "sDMA secure command submission", amdgpu_security_sdma_submission_test },
423 { SECURE_BOUNCE_TEST_STR, amdgpu_secure_bounce },
424 CU_TEST_INFO_NULL,
425 };
426
suite_security_tests_enable(void)427 CU_BOOL suite_security_tests_enable(void)
428 {
429 CU_BOOL enable = CU_TRUE;
430
431 if (amdgpu_device_initialize(drm_amdgpu[0], &major_version,
432 &minor_version, &device_handle))
433 return CU_FALSE;
434
435
436 if (!(device_handle->dev_info.ids_flags & AMDGPU_IDS_FLAGS_TMZ)) {
437 printf("\n\nDon't support TMZ (trust memory zone), security suite disabled\n");
438 enable = CU_FALSE;
439 }
440
441 if ((major_version < 3) ||
442 ((major_version == 3) && (minor_version < 37))) {
443 printf("\n\nDon't support TMZ (trust memory zone), kernel DRM version (%d.%d)\n",
444 major_version, minor_version);
445 printf("is older, security suite disabled\n");
446 enable = CU_FALSE;
447 }
448
449 if (amdgpu_device_deinitialize(device_handle))
450 return CU_FALSE;
451
452 return enable;
453 }
454
suite_security_tests_init(void)455 int suite_security_tests_init(void)
456 {
457 int res;
458
459 res = amdgpu_device_initialize(drm_amdgpu[0], &major_version,
460 &minor_version, &device_handle);
461 if (res) {
462 PRINT_ERROR(res);
463 return CUE_SINIT_FAILED;
464 }
465
466 res = amdgpu_query_hw_ip_info(device_handle,
467 AMDGPU_HW_IP_DMA,
468 0, &sdma_info);
469 if (res) {
470 PRINT_ERROR(res);
471 return CUE_SINIT_FAILED;
472 }
473
474 return CUE_SUCCESS;
475 }
476
suite_security_tests_clean(void)477 int suite_security_tests_clean(void)
478 {
479 int res;
480
481 res = amdgpu_device_deinitialize(device_handle);
482 if (res)
483 return CUE_SCLEAN_FAILED;
484
485 return CUE_SUCCESS;
486 }
487