1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * sdsi: Intel Software Defined Silicon tool for provisioning certificates 4 * and activation payloads on supported cpus. 5 * 6 * See https://github.com/intel/intel-sdsi/blob/master/os-interface.rst 7 * for register descriptions. 8 * 9 * Copyright (C) 2022 Intel Corporation. All rights reserved. 10 */ 11 12 #include <dirent.h> 13 #include <errno.h> 14 #include <fcntl.h> 15 #include <getopt.h> 16 #include <stdbool.h> 17 #include <stdio.h> 18 #include <stdint.h> 19 #include <stdlib.h> 20 #include <string.h> 21 #include <unistd.h> 22 23 #include <sys/types.h> 24 25 #define SDSI_DEV "intel_vsec.sdsi" 26 #define AUX_DEV_PATH "/sys/bus/auxiliary/devices/" 27 #define SDSI_PATH (AUX_DEV_DIR SDSI_DEV) 28 #define GUID 0x6dd191 29 #define REGISTERS_MIN_SIZE 72 30 31 #define __round_mask(x, y) ((__typeof__(x))((y) - 1)) 32 #define round_up(x, y) ((((x) - 1) | __round_mask(x, y)) + 1) 33 34 struct enabled_features { 35 uint64_t reserved:3; 36 uint64_t sdsi:1; 37 uint64_t reserved1:60; 38 }; 39 40 struct auth_fail_count { 41 uint64_t key_failure_count:3; 42 uint64_t key_failure_threshold:3; 43 uint64_t auth_failure_count:3; 44 uint64_t auth_failure_threshold:3; 45 uint64_t reserved:52; 46 }; 47 48 struct availability { 49 uint64_t reserved:48; 50 uint64_t available:3; 51 uint64_t threshold:3; 52 }; 53 54 struct sdsi_regs { 55 uint64_t ppin; 56 uint64_t reserved; 57 struct enabled_features en_features; 58 uint64_t reserved1; 59 struct auth_fail_count auth_fail_count; 60 struct availability prov_avail; 61 uint64_t reserved2; 62 uint64_t reserved3; 63 uint64_t socket_id; 64 }; 65 66 struct sdsi_dev { 67 struct sdsi_regs regs; 68 char *dev_name; 69 char *dev_path; 70 int guid; 71 }; 72 73 enum command { 74 CMD_NONE, 75 CMD_SOCKET_INFO, 76 CMD_DUMP_CERT, 77 CMD_PROV_AKC, 78 CMD_PROV_CAP, 79 }; 80 81 static void sdsi_list_devices(void) 82 { 83 struct dirent *entry; 84 DIR *aux_dir; 85 bool found = false; 86 87 aux_dir = opendir(AUX_DEV_PATH); 88 if (!aux_dir) { 89 fprintf(stderr, "Cannot open directory %s\n", AUX_DEV_PATH); 90 return; 91 } 92 93 while ((entry = readdir(aux_dir))) { 94 if (!strncmp(SDSI_DEV, entry->d_name, strlen(SDSI_DEV))) { 95 found = true; 96 printf("%s\n", entry->d_name); 97 } 98 } 99 100 if (!found) 101 fprintf(stderr, "No sdsi devices found.\n"); 102 } 103 104 static int sdsi_update_registers(struct sdsi_dev *s) 105 { 106 FILE *regs_ptr; 107 int ret; 108 109 memset(&s->regs, 0, sizeof(s->regs)); 110 111 /* Open the registers file */ 112 ret = chdir(s->dev_path); 113 if (ret == -1) { 114 perror("chdir"); 115 return ret; 116 } 117 118 regs_ptr = fopen("registers", "r"); 119 if (!regs_ptr) { 120 perror("Could not open 'registers' file"); 121 return -1; 122 } 123 124 if (s->guid != GUID) { 125 fprintf(stderr, "Unrecognized guid, 0x%x\n", s->guid); 126 fclose(regs_ptr); 127 return -1; 128 } 129 130 /* Update register info for this guid */ 131 ret = fread(&s->regs, sizeof(uint8_t), sizeof(s->regs), regs_ptr); 132 if (ret != sizeof(s->regs)) { 133 fprintf(stderr, "Could not read 'registers' file\n"); 134 fclose(regs_ptr); 135 return -1; 136 } 137 138 fclose(regs_ptr); 139 140 return 0; 141 } 142 143 static int sdsi_read_reg(struct sdsi_dev *s) 144 { 145 int ret; 146 147 ret = sdsi_update_registers(s); 148 if (ret) 149 return ret; 150 151 /* Print register info for this guid */ 152 printf("\n"); 153 printf("Socket information for device %s\n", s->dev_name); 154 printf("\n"); 155 printf("PPIN: 0x%lx\n", s->regs.ppin); 156 printf("Enabled Features\n"); 157 printf(" SDSi: %s\n", !!s->regs.en_features.sdsi ? "Enabled" : "Disabled"); 158 printf("Authorization Failure Count\n"); 159 printf(" AKC Failure Count: %d\n", s->regs.auth_fail_count.key_failure_count); 160 printf(" AKC Failure Threshold: %d\n", s->regs.auth_fail_count.key_failure_threshold); 161 printf(" CAP Failure Count: %d\n", s->regs.auth_fail_count.auth_failure_count); 162 printf(" CAP Failure Threshold: %d\n", s->regs.auth_fail_count.auth_failure_threshold); 163 printf("Provisioning Availability\n"); 164 printf(" Updates Available: %d\n", s->regs.prov_avail.available); 165 printf(" Updates Threshold: %d\n", s->regs.prov_avail.threshold); 166 printf("Socket ID: %ld\n", s->regs.socket_id & 0xF); 167 168 return 0; 169 } 170 171 static int sdsi_certificate_dump(struct sdsi_dev *s) 172 { 173 uint64_t state_certificate[512] = {0}; 174 bool first_instance; 175 uint64_t previous; 176 FILE *cert_ptr; 177 int i, ret, size; 178 179 ret = sdsi_update_registers(s); 180 if (ret) 181 return ret; 182 183 if (!s->regs.en_features.sdsi) { 184 fprintf(stderr, "SDSi feature is present but not enabled."); 185 fprintf(stderr, " Unable to read state certificate"); 186 return -1; 187 } 188 189 ret = chdir(s->dev_path); 190 if (ret == -1) { 191 perror("chdir"); 192 return ret; 193 } 194 195 cert_ptr = fopen("state_certificate", "r"); 196 if (!cert_ptr) { 197 perror("Could not open 'state_certificate' file"); 198 return -1; 199 } 200 201 size = fread(state_certificate, 1, sizeof(state_certificate), cert_ptr); 202 if (!size) { 203 fprintf(stderr, "Could not read 'state_certificate' file\n"); 204 fclose(cert_ptr); 205 return -1; 206 } 207 208 printf("%3d: 0x%lx\n", 0, state_certificate[0]); 209 previous = state_certificate[0]; 210 first_instance = true; 211 212 for (i = 1; i < (int)(round_up(size, sizeof(uint64_t))/sizeof(uint64_t)); i++) { 213 if (state_certificate[i] == previous) { 214 if (first_instance) { 215 puts("*"); 216 first_instance = false; 217 } 218 continue; 219 } 220 printf("%3d: 0x%lx\n", i, state_certificate[i]); 221 previous = state_certificate[i]; 222 first_instance = true; 223 } 224 printf("%3d\n", i); 225 226 fclose(cert_ptr); 227 228 return 0; 229 } 230 231 static int sdsi_provision(struct sdsi_dev *s, char *bin_file, enum command command) 232 { 233 int bin_fd, prov_fd, size, ret; 234 char buf[4096] = { 0 }; 235 char cap[] = "provision_cap"; 236 char akc[] = "provision_akc"; 237 char *prov_file; 238 239 if (!bin_file) { 240 fprintf(stderr, "No binary file provided\n"); 241 return -1; 242 } 243 244 /* Open the binary */ 245 bin_fd = open(bin_file, O_RDONLY); 246 if (bin_fd == -1) { 247 fprintf(stderr, "Could not open file %s: %s\n", bin_file, strerror(errno)); 248 return bin_fd; 249 } 250 251 prov_file = (command == CMD_PROV_AKC) ? akc : cap; 252 253 ret = chdir(s->dev_path); 254 if (ret == -1) { 255 perror("chdir"); 256 close(bin_fd); 257 return ret; 258 } 259 260 /* Open the provision file */ 261 prov_fd = open(prov_file, O_WRONLY); 262 if (prov_fd == -1) { 263 fprintf(stderr, "Could not open file %s: %s\n", prov_file, strerror(errno)); 264 close(bin_fd); 265 return prov_fd; 266 } 267 268 /* Read the binary file into the buffer */ 269 size = read(bin_fd, buf, 4096); 270 if (size == -1) { 271 close(bin_fd); 272 close(prov_fd); 273 return -1; 274 } 275 276 ret = write(prov_fd, buf, size); 277 if (ret == -1) { 278 close(bin_fd); 279 close(prov_fd); 280 perror("Provisioning failed"); 281 return ret; 282 } 283 284 printf("Provisioned %s file %s successfully\n", prov_file, bin_file); 285 286 close(bin_fd); 287 close(prov_fd); 288 289 return 0; 290 } 291 292 static int sdsi_provision_akc(struct sdsi_dev *s, char *bin_file) 293 { 294 int ret; 295 296 ret = sdsi_update_registers(s); 297 if (ret) 298 return ret; 299 300 if (!s->regs.en_features.sdsi) { 301 fprintf(stderr, "SDSi feature is present but not enabled. Unable to provision"); 302 return -1; 303 } 304 305 if (!s->regs.prov_avail.available) { 306 fprintf(stderr, "Maximum number of updates (%d) has been reached.\n", 307 s->regs.prov_avail.threshold); 308 return -1; 309 } 310 311 if (s->regs.auth_fail_count.key_failure_count == 312 s->regs.auth_fail_count.key_failure_threshold) { 313 fprintf(stderr, "Maximum number of AKC provision failures (%d) has been reached.\n", 314 s->regs.auth_fail_count.key_failure_threshold); 315 fprintf(stderr, "Power cycle the system to reset the counter\n"); 316 return -1; 317 } 318 319 return sdsi_provision(s, bin_file, CMD_PROV_AKC); 320 } 321 322 static int sdsi_provision_cap(struct sdsi_dev *s, char *bin_file) 323 { 324 int ret; 325 326 ret = sdsi_update_registers(s); 327 if (ret) 328 return ret; 329 330 if (!s->regs.en_features.sdsi) { 331 fprintf(stderr, "SDSi feature is present but not enabled. Unable to provision"); 332 return -1; 333 } 334 335 if (!s->regs.prov_avail.available) { 336 fprintf(stderr, "Maximum number of updates (%d) has been reached.\n", 337 s->regs.prov_avail.threshold); 338 return -1; 339 } 340 341 if (s->regs.auth_fail_count.auth_failure_count == 342 s->regs.auth_fail_count.auth_failure_threshold) { 343 fprintf(stderr, "Maximum number of CAP provision failures (%d) has been reached.\n", 344 s->regs.auth_fail_count.auth_failure_threshold); 345 fprintf(stderr, "Power cycle the system to reset the counter\n"); 346 return -1; 347 } 348 349 return sdsi_provision(s, bin_file, CMD_PROV_CAP); 350 } 351 352 static int read_sysfs_data(const char *file, int *value) 353 { 354 char buff[16]; 355 FILE *fp; 356 357 fp = fopen(file, "r"); 358 if (!fp) { 359 perror(file); 360 return -1; 361 } 362 363 if (!fgets(buff, 16, fp)) { 364 fprintf(stderr, "Failed to read file '%s'", file); 365 fclose(fp); 366 return -1; 367 } 368 369 fclose(fp); 370 *value = strtol(buff, NULL, 0); 371 372 return 0; 373 } 374 375 static struct sdsi_dev *sdsi_create_dev(char *dev_no) 376 { 377 int dev_name_len = sizeof(SDSI_DEV) + strlen(dev_no) + 1; 378 struct sdsi_dev *s; 379 int guid; 380 DIR *dir; 381 382 s = (struct sdsi_dev *)malloc(sizeof(*s)); 383 if (!s) { 384 perror("malloc"); 385 return NULL; 386 } 387 388 s->dev_name = (char *)malloc(sizeof(SDSI_DEV) + strlen(dev_no) + 1); 389 if (!s->dev_name) { 390 perror("malloc"); 391 free(s); 392 return NULL; 393 } 394 395 snprintf(s->dev_name, dev_name_len, "%s.%s", SDSI_DEV, dev_no); 396 397 s->dev_path = (char *)malloc(sizeof(AUX_DEV_PATH) + dev_name_len); 398 if (!s->dev_path) { 399 perror("malloc"); 400 free(s->dev_name); 401 free(s); 402 return NULL; 403 } 404 405 snprintf(s->dev_path, sizeof(AUX_DEV_PATH) + dev_name_len, "%s%s", AUX_DEV_PATH, 406 s->dev_name); 407 dir = opendir(s->dev_path); 408 if (!dir) { 409 fprintf(stderr, "Could not open directory '%s': %s\n", s->dev_path, 410 strerror(errno)); 411 free(s->dev_path); 412 free(s->dev_name); 413 free(s); 414 return NULL; 415 } 416 417 if (chdir(s->dev_path) == -1) { 418 perror("chdir"); 419 free(s->dev_path); 420 free(s->dev_name); 421 free(s); 422 return NULL; 423 } 424 425 if (read_sysfs_data("guid", &guid)) { 426 free(s->dev_path); 427 free(s->dev_name); 428 free(s); 429 return NULL; 430 } 431 432 s->guid = guid; 433 434 return s; 435 } 436 437 static void sdsi_free_dev(struct sdsi_dev *s) 438 { 439 free(s->dev_path); 440 free(s->dev_name); 441 free(s); 442 } 443 444 static void usage(char *prog) 445 { 446 printf("Usage: %s [-l] [-d DEVNO [-iD] [-a FILE] [-c FILE]]\n", prog); 447 } 448 449 static void show_help(void) 450 { 451 printf("Commands:\n"); 452 printf(" %-18s\t%s\n", "-l, --list", "list available sdsi devices"); 453 printf(" %-18s\t%s\n", "-d, --devno DEVNO", "sdsi device number"); 454 printf(" %-18s\t%s\n", "-i --info", "show socket information"); 455 printf(" %-18s\t%s\n", "-D --dump", "dump state certificate data"); 456 printf(" %-18s\t%s\n", "-a --akc FILE", "provision socket with AKC FILE"); 457 printf(" %-18s\t%s\n", "-c --cap FILE>", "provision socket with CAP FILE"); 458 } 459 460 int main(int argc, char *argv[]) 461 { 462 char bin_file[PATH_MAX], *dev_no = NULL; 463 char *progname; 464 enum command command = CMD_NONE; 465 struct sdsi_dev *s; 466 int ret = 0, opt; 467 int option_index = 0; 468 469 static struct option long_options[] = { 470 {"akc", required_argument, 0, 'a'}, 471 {"cap", required_argument, 0, 'c'}, 472 {"devno", required_argument, 0, 'd'}, 473 {"dump", no_argument, 0, 'D'}, 474 {"help", no_argument, 0, 'h'}, 475 {"info", no_argument, 0, 'i'}, 476 {"list", no_argument, 0, 'l'}, 477 {0, 0, 0, 0 } 478 }; 479 480 481 progname = argv[0]; 482 483 while ((opt = getopt_long_only(argc, argv, "+a:c:d:Da:c:h", long_options, 484 &option_index)) != -1) { 485 switch (opt) { 486 case 'd': 487 dev_no = optarg; 488 break; 489 case 'l': 490 sdsi_list_devices(); 491 return 0; 492 case 'i': 493 command = CMD_SOCKET_INFO; 494 break; 495 case 'D': 496 command = CMD_DUMP_CERT; 497 break; 498 case 'a': 499 case 'c': 500 if (!access(optarg, F_OK) == 0) { 501 fprintf(stderr, "Could not open file '%s': %s\n", optarg, 502 strerror(errno)); 503 return -1; 504 } 505 506 if (!realpath(optarg, bin_file)) { 507 perror("realpath"); 508 return -1; 509 } 510 511 command = (opt == 'a') ? CMD_PROV_AKC : CMD_PROV_CAP; 512 break; 513 case 'h': 514 usage(progname); 515 show_help(); 516 return 0; 517 default: 518 usage(progname); 519 return -1; 520 } 521 } 522 523 if (!dev_no) { 524 if (command != CMD_NONE) 525 fprintf(stderr, "Missing device number, DEVNO, for this command\n"); 526 usage(progname); 527 return -1; 528 } 529 530 s = sdsi_create_dev(dev_no); 531 if (!s) 532 return -1; 533 534 /* Run the command */ 535 switch (command) { 536 case CMD_NONE: 537 fprintf(stderr, "Missing command for device %s\n", dev_no); 538 usage(progname); 539 break; 540 case CMD_SOCKET_INFO: 541 ret = sdsi_read_reg(s); 542 break; 543 case CMD_DUMP_CERT: 544 ret = sdsi_certificate_dump(s); 545 break; 546 case CMD_PROV_AKC: 547 ret = sdsi_provision_akc(s, bin_file); 548 break; 549 case CMD_PROV_CAP: 550 ret = sdsi_provision_cap(s, bin_file); 551 break; 552 } 553 554 555 sdsi_free_dev(s); 556 557 return ret; 558 } 559