2 * Copyright 2019 Advanced Micro Devices, Inc.
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
24 #include "CUnit/Basic.h"
26 #include "amdgpu_test.h"
27 #include "amdgpu_drm.h"
28 #include "amdgpu_internal.h"
36 static amdgpu_device_handle device_handle;
37 static uint32_t major_version;
38 static uint32_t minor_version;
40 static struct drm_amdgpu_info_hw_ip sdma_info;
43 #define ARRAY_SIZE(_Arr) (sizeof(_Arr)/sizeof((_Arr)[0]))
47 /* --------------------- Secure bounce test ------------------------ *
49 * The secure bounce test tests that we can evict a TMZ buffer,
50 * and page it back in, via a bounce buffer, as it encryption/decryption
51 * depends on its physical address, and have the same data, i.e. data
52 * integrity is preserved.
54 * The steps are as follows (from Christian K.):
56 * Buffer A which is TMZ protected and filled by the CPU with a
57 * certain pattern. That the GPU is reading only random nonsense from
58 * that pattern is irrelevant for the test.
60 * This buffer A is then secure copied into buffer B which is also
63 * Buffer B is moved around, from VRAM to GTT, GTT to SYSTEM,
66 * Then, we use another secure copy of buffer B back to buffer A.
68 * And lastly we check with the CPU the pattern.
70 * Assuming that we don't have memory contention and buffer A stayed
71 * at the same place, we should still see the same pattern when read
74 * If we don't see the same pattern then something in the buffer
75 * migration code is not working as expected.
78 #define SECURE_BOUNCE_TEST_STR "secure bounce"
79 #define SECURE_BOUNCE_FAILED_STR SECURE_BOUNCE_TEST_STR " failed"
81 #define PRINT_ERROR(_Res) fprintf(stderr, "%s:%d: %s (%d)\n", \
82 __func__, __LINE__, strerror(-(_Res)), _Res)
84 #define PACKET_LCOPY_SIZE 7
85 #define PACKET_NOP_SIZE 12
87 struct sec_amdgpu_bo {
93 struct amdgpu_device *dev;
94 struct amdgpu_cs_ib_info cs_ibinfo;
95 struct amdgpu_cs_request cs_req;
96 struct amdgpu_context *context;
101 * amdgpu_bo_alloc_map -- Allocate and map a buffer object (BO)
102 * @dev: The AMDGPU device this BO belongs to.
103 * @size: The size of the BO.
104 * @alignment: Alignment of the BO.
105 * @gem_domain: One of AMDGPU_GEM_DOMAIN_xyz.
106 * @alloc_flags: One of AMDGPU_GEM_CREATE_xyz.
109 * Allocate a buffer object (BO) with the desired attributes
110 * as specified by the argument list and write out the result
113 * Return 0 on success and @sbo->bo and @sbo->va are set,
114 * or -errno on error.
116 static int amdgpu_bo_alloc_map(struct amdgpu_device *dev,
120 uint64_t alloc_flags,
121 struct sec_amdgpu_bo *sbo)
126 return amdgpu_bo_alloc_and_map_raw(dev,
137 static void amdgpu_bo_unmap_free(struct sec_amdgpu_bo *sbo,
140 (void) amdgpu_bo_unmap_and_free(sbo->bo,
148 static void amdgpu_sdma_lcopy(uint32_t *packet,
154 /* Set the packet to Linear copy with TMZ set.
156 packet[0] = htole32(secure << 18 | 1);
157 packet[1] = htole32(size-1);
158 packet[2] = htole32(0);
159 packet[3] = htole32((uint32_t)(src & 0xFFFFFFFFU));
160 packet[4] = htole32((uint32_t)(src >> 32));
161 packet[5] = htole32((uint32_t)(dst & 0xFFFFFFFFU));
162 packet[6] = htole32((uint32_t)(dst >> 32));
165 static void amdgpu_sdma_nop(uint32_t *packet, uint32_t nop_count)
167 /* A packet of the desired number of NOPs.
169 packet[0] = htole32(nop_count << 16);
170 for ( ; nop_count > 0; nop_count--)
171 packet[nop_count-1] = 0;
175 * amdgpu_bo_lcopy -- linear copy with TZM set, using sDMA
176 * @dev: AMDGPU device to which both buffer objects belong to
177 * @dst: destination buffer object
178 * @src: source buffer object
179 * @size: size of memory to move, in bytes.
180 * @secure: Set to 1 to perform secure copy, 0 for clear
182 * Issues and waits for completion of a Linear Copy with TMZ
183 * set, to the sDMA engine. @size should be a multiple of
186 static void amdgpu_bo_lcopy(struct command_ctx *ctx,
187 struct sec_amdgpu_bo *dst,
188 struct sec_amdgpu_bo *src,
192 struct amdgpu_bo *bos[] = { dst->bo, src->bo };
193 uint32_t packet[PACKET_LCOPY_SIZE];
195 amdgpu_sdma_lcopy(packet,
199 amdgpu_test_exec_cs_helper_raw(ctx->dev, ctx->context,
200 AMDGPU_HW_IP_DMA, ctx->ring_id,
201 ARRAY_SIZE(packet), packet,
202 ARRAY_SIZE(bos), bos,
203 &ctx->cs_ibinfo, &ctx->cs_req,
208 * amdgpu_bo_move -- Evoke a move of the buffer object (BO)
209 * @dev: device to which this buffer object belongs to
210 * @bo: the buffer object to be moved
211 * @whereto: one of AMDGPU_GEM_DOMAIN_xyz
212 * @secure: set to 1 to submit secure IBs
214 * Evokes a move of the buffer object @bo to the GEM domain
215 * descibed by @whereto.
217 * Returns 0 on sucess; -errno on error.
219 static int amdgpu_bo_move(struct command_ctx *ctx,
220 struct amdgpu_bo *bo,
224 struct amdgpu_bo *bos[] = { bo };
225 struct drm_amdgpu_gem_op gop = {
226 .handle = bo->handle,
227 .op = AMDGPU_GEM_OP_SET_PLACEMENT,
230 uint32_t packet[PACKET_NOP_SIZE];
233 /* Change the buffer's placement.
235 res = drmIoctl(ctx->dev->fd, DRM_IOCTL_AMDGPU_GEM_OP, &gop);
239 /* Now issue a NOP to actually evoke the MM to move
240 * it to the desired location.
242 amdgpu_sdma_nop(packet, PACKET_NOP_SIZE);
243 amdgpu_test_exec_cs_helper_raw(ctx->dev, ctx->context,
244 AMDGPU_HW_IP_DMA, ctx->ring_id,
245 ARRAY_SIZE(packet), packet,
246 ARRAY_SIZE(bos), bos,
247 &ctx->cs_ibinfo, &ctx->cs_req,
254 static const uint8_t secure_pattern[] = { 0x5A, 0xFE, 0x05, 0xEC };
256 #define SECURE_BUFFER_SIZE (4 * 1024 * sizeof(secure_pattern))
258 static void amdgpu_secure_bounce(void)
260 struct sec_amdgpu_bo alice, bob;
261 struct command_ctx sb_ctx;
266 page_size = sysconf(_SC_PAGESIZE);
268 memset(&sb_ctx, 0, sizeof(sb_ctx));
269 sb_ctx.dev = device_handle;
270 res = amdgpu_cs_ctx_create(sb_ctx.dev, &sb_ctx.context);
273 CU_FAIL(SECURE_BOUNCE_FAILED_STR);
277 /* Use the first present ring.
279 res = ffs(sdma_info.available_rings) - 1;
281 PRINT_ERROR(-ENOENT);
282 CU_FAIL(SECURE_BOUNCE_FAILED_STR);
285 sb_ctx.ring_id = res;
287 /* Allocate a buffer named Alice in VRAM.
289 res = amdgpu_bo_alloc_map(device_handle,
292 AMDGPU_GEM_DOMAIN_VRAM,
293 AMDGPU_GEM_CREATE_ENCRYPTED,
297 CU_FAIL(SECURE_BOUNCE_FAILED_STR);
301 /* Fill Alice with a pattern.
303 for (pp = alice.bo->cpu_ptr;
304 pp < (typeof(pp)) alice.bo->cpu_ptr + SECURE_BUFFER_SIZE;
305 pp += sizeof(secure_pattern))
306 memcpy(pp, secure_pattern, sizeof(secure_pattern));
308 /* Allocate a buffer named Bob in VRAM.
310 res = amdgpu_bo_alloc_map(device_handle,
313 AMDGPU_GEM_DOMAIN_VRAM,
314 0 /* AMDGPU_GEM_CREATE_ENCRYPTED */,
318 CU_FAIL(SECURE_BOUNCE_FAILED_STR);
322 /* sDMA clear copy from Alice to Bob.
324 amdgpu_bo_lcopy(&sb_ctx, &bob, &alice, SECURE_BUFFER_SIZE, 0);
326 /* Move Bob to the GTT domain.
328 res = amdgpu_bo_move(&sb_ctx, bob.bo, AMDGPU_GEM_DOMAIN_GTT, 0);
331 CU_FAIL(SECURE_BOUNCE_FAILED_STR);
335 /* sDMA clear copy from Bob to Alice.
337 amdgpu_bo_lcopy(&sb_ctx, &alice, &bob, SECURE_BUFFER_SIZE, 0);
339 /* Verify the contents of Alice.
341 for (pp = alice.bo->cpu_ptr;
342 pp < (typeof(pp)) alice.bo->cpu_ptr + SECURE_BUFFER_SIZE;
343 pp += sizeof(secure_pattern)) {
344 res = memcmp(pp, secure_pattern, sizeof(secure_pattern));
346 fprintf(stderr, SECURE_BOUNCE_FAILED_STR);
347 CU_FAIL(SECURE_BOUNCE_FAILED_STR);
353 amdgpu_bo_unmap_free(&bob, SECURE_BUFFER_SIZE);
355 amdgpu_bo_unmap_free(&alice, SECURE_BUFFER_SIZE);
357 res = amdgpu_cs_ctx_free(sb_ctx.context);
358 CU_ASSERT_EQUAL(res, 0);
361 /* ----------------------------------------------------------------- */
363 static void amdgpu_security_alloc_buf_test(void)
366 amdgpu_va_handle va_handle;
370 /* Test secure buffer allocation in VRAM */
371 bo = gpu_mem_alloc(device_handle, 4096, 4096,
372 AMDGPU_GEM_DOMAIN_VRAM,
373 AMDGPU_GEM_CREATE_ENCRYPTED,
376 r = gpu_mem_free(bo, va_handle, bo_mc, 4096);
377 CU_ASSERT_EQUAL(r, 0);
379 /* Test secure buffer allocation in system memory */
380 bo = gpu_mem_alloc(device_handle, 4096, 4096,
381 AMDGPU_GEM_DOMAIN_GTT,
382 AMDGPU_GEM_CREATE_ENCRYPTED,
385 r = gpu_mem_free(bo, va_handle, bo_mc, 4096);
386 CU_ASSERT_EQUAL(r, 0);
388 /* Test secure buffer allocation in invisible VRAM */
389 bo = gpu_mem_alloc(device_handle, 4096, 4096,
390 AMDGPU_GEM_DOMAIN_GTT,
391 AMDGPU_GEM_CREATE_ENCRYPTED |
392 AMDGPU_GEM_CREATE_NO_CPU_ACCESS,
395 r = gpu_mem_free(bo, va_handle, bo_mc, 4096);
396 CU_ASSERT_EQUAL(r, 0);
399 static void amdgpu_security_gfx_submission_test(void)
401 amdgpu_command_submission_write_linear_helper_with_secure(device_handle,
406 static void amdgpu_security_sdma_submission_test(void)
408 amdgpu_command_submission_write_linear_helper_with_secure(device_handle,
413 /* ----------------------------------------------------------------- */
415 CU_TestInfo security_tests[] = {
416 { "allocate secure buffer test", amdgpu_security_alloc_buf_test },
417 { "graphics secure command submission", amdgpu_security_gfx_submission_test },
418 { "sDMA secure command submission", amdgpu_security_sdma_submission_test },
419 { SECURE_BOUNCE_TEST_STR, amdgpu_secure_bounce },
423 CU_BOOL suite_security_tests_enable(void)
425 CU_BOOL enable = CU_TRUE;
427 if (amdgpu_device_initialize(drm_amdgpu[0], &major_version,
428 &minor_version, &device_handle))
431 if (device_handle->info.family_id != AMDGPU_FAMILY_RV) {
432 printf("\n\nDon't support TMZ (trust memory zone), security suite disabled\n");
436 if ((major_version < 3) ||
437 ((major_version == 3) && (minor_version < 37))) {
438 printf("\n\nDon't support TMZ (trust memory zone), kernel DRM version (%d.%d)\n",
439 major_version, minor_version);
440 printf("is older, security suite disabled\n");
444 if (amdgpu_device_deinitialize(device_handle))
450 int suite_security_tests_init(void)
454 res = amdgpu_device_initialize(drm_amdgpu[0], &major_version,
455 &minor_version, &device_handle);
458 return CUE_SINIT_FAILED;
461 res = amdgpu_query_hw_ip_info(device_handle,
466 return CUE_SINIT_FAILED;
472 int suite_security_tests_clean(void)
476 res = amdgpu_device_deinitialize(device_handle);
478 return CUE_SCLEAN_FAILED;