Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tools arch x86: Add Intel SDSi provisiong tool

Add tool for key certificate and activation payload provisioning on
Intel CPUs supporting Software Defined Silicon (SDSi).

Signed-off-by: David E. Box <david.e.box@linux.intel.com>
Link: https://lore.kernel.org/r/20220225012457.1661574-1-david.e.box@linux.intel.com
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>

authored by

David E. Box and committed by
Hans de Goede
f6d92cfc faabb268

+580
+1
MAINTAINERS
··· 9881 9881 M: David E. Box <david.e.box@linux.intel.com> 9882 9882 S: Supported 9883 9883 F: drivers/platform/x86/intel/sdsi.c 9884 + F: tools/arch/x86/intel_sdsi/ 9884 9885 9885 9886 INTEL SKYLAKE INT3472 ACPI DEVICE DRIVER 9886 9887 M: Daniel Scally <djrscally@gmail.com>
+21
tools/arch/x86/intel_sdsi/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + # Makefile for Intel Software Defined Silicon provisioning tool 3 + 4 + intel_sdsi: intel_sdsi.c 5 + 6 + CFLAGS = -Wextra 7 + 8 + BINDIR ?= /usr/sbin 9 + 10 + override CFLAGS += -O2 -Wall 11 + 12 + %: %.c 13 + $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) 14 + 15 + .PHONY : clean 16 + clean : 17 + @rm -f intel_sdsi 18 + 19 + install : intel_sdsi 20 + install -d $(DESTDIR)$(BINDIR) 21 + install -m 755 -p intel_sdsi $(DESTDIR)$(BINDIR)/intel_sdsi
+558
tools/arch/x86/intel_sdsi/intel_sdsi.c
··· 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 + }