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 40static amdgpu_device_handle device_handle; 41static uint32_t major_version; 42static uint32_t minor_version; 43 44static 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 91struct sec_amdgpu_bo { 92 struct amdgpu_bo *bo; 93 struct amdgpu_va *va; 94}; 95 96struct 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 */ 120static 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 141static 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 152static 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 169static 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 */ 190static 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 */ 223static 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 */ 258static const uint8_t secure_pattern[] = { 0x5A, 0xFE, 0x05, 0xEC }; 259 260#define SECURE_BUFFER_SIZE (4 * 1024 * sizeof(secure_pattern)) 261 262static 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 356Out_free_all: 357 amdgpu_bo_unmap_free(&bob, SECURE_BUFFER_SIZE); 358Out_free_Alice: 359 amdgpu_bo_unmap_free(&alice, SECURE_BUFFER_SIZE); 360Out_free_ctx: 361 res = amdgpu_cs_ctx_free(sb_ctx.context); 362 CU_ASSERT_EQUAL(res, 0); 363} 364 365/* ----------------------------------------------------------------- */ 366 367static 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 403static 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 410static 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 419CU_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 427CU_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 455int 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 477int 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