linux/tools/arch/x86/intel_sdsi/intel_sdsi.c
<<
>>
Prefs
   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
  34struct enabled_features {
  35        uint64_t reserved:3;
  36        uint64_t sdsi:1;
  37        uint64_t reserved1:60;
  38};
  39
  40struct 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
  48struct availability {
  49        uint64_t reserved:48;
  50        uint64_t available:3;
  51        uint64_t threshold:3;
  52};
  53
  54struct 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
  66struct sdsi_dev {
  67        struct sdsi_regs regs;
  68        char *dev_name;
  69        char *dev_path;
  70        int guid;
  71};
  72
  73enum command {
  74        CMD_NONE,
  75        CMD_SOCKET_INFO,
  76        CMD_DUMP_CERT,
  77        CMD_PROV_AKC,
  78        CMD_PROV_CAP,
  79};
  80
  81static 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
 104static 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
 143static 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
 171static 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
 231static 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
 292static 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
 322static 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
 352static 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
 375static 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
 437static void sdsi_free_dev(struct sdsi_dev *s)
 438{
 439        free(s->dev_path);
 440        free(s->dev_name);
 441        free(s);
 442}
 443
 444static void usage(char *prog)
 445{
 446        printf("Usage: %s [-l] [-d DEVNO [-iD] [-a FILE] [-c FILE]]\n", prog);
 447}
 448
 449static 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
 460int 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