[V2 5/6] sample/sdsi: Sample of SDSi provisiong using sysfs

David E. Box
2021-12-07T17:16:43Z

Sample application showing usage of Intel Software Defined Silicon
sysfs ABI.

Signed-off-by: David E. Box <david.e.box@linux.intel.com>
---
V2
- New patch

MAINTAINERS | 1 +
samples/sdsi/Makefile | 9 +
samples/sdsi/sdsi-sample.c | 399 +++++++++++++++++++++++++++++++++++++
3 files changed, 409 insertions(+)
create mode 100644 samples/sdsi/Makefile
create mode 100644 samples/sdsi/sdsi-sample.c

diff --git a/MAINTAINERS b/MAINTAINERS
index af7f17e7400f..ba9603fb7f62 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9787,6 +9787,7 @@ INTEL SDSI DRIVER
M: David E. Box <david.e.box@linux.intel.com>
S: Supported
F: drivers/platform/x86/intel/sdsi.c
+F: samples/sdsi/

INTEL SKYLAKE INT3472 ACPI DEVICE DRIVER
M: Daniel Scally <djrscally@gmail.com>
diff --git a/samples/sdsi/Makefile b/samples/sdsi/Makefile
new file mode 100644
index 000000000000..17ac82a5623d
--- /dev/null
+++ b/samples/sdsi/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+
+.PHONY: sdsi-sample
+
+sdsi-sample: sdsi-sample.o
+ $(CC) -Wall $^ -o $@
+
+clean:
+ rm *.o sdsi-sample
diff --git a/samples/sdsi/sdsi-sample.c b/samples/sdsi/sdsi-sample.c
new file mode 100644
index 000000000000..6b3b48359aa0
--- /dev/null
+++ b/samples/sdsi/sdsi-sample.c
@@ -0,0 +1,399 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * sdsi_test: Example program using the sysfs interface of the
+ * Intel Software Defined Silicon Linux driver.
+ *
+ * See https://github.com/intel/intel-sdsi/blob/master/os-interface.rst
+ * for register descriptions.
+ *
+ * Copyright (C) 2021 Intel Corporation. All rights reserved.
+ */
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define SDSI_DIR "/sys/bus/auxiliary/devices/intel_vsec.sdsi"
+#define GUID "0x6dd191"
+#define REGISTERS_MIN_SIZE 72
+
+struct enabled_features {
+ uint64_t reserved:3;
+ uint64_t sdsi:1;
+ uint64_t reserved1:60;
+};
+
+struct auth_fail_count {
+ uint64_t key_failure_count:3;
+ uint64_t key_failure_threshold:3;
+ uint64_t auth_failure_count:3;
+ uint64_t auth_failure_threshold:3;
+ uint64_t reserved:52;
+};
+
+struct availability {
+ uint64_t reserved:58;
+ uint64_t updates_available:3;
+ uint64_t updates_threshold:3;
+};
+
+struct sdsi_reg_6dd191 {
+ uint64_t ppin;
+ uint64_t reserved;
+ struct enabled_features en_features;
+ uint64_t reserved1;
+ struct auth_fail_count auth_fail_count;
+ struct availability prov_avail;
+ uint64_t reserved2;
+ uint64_t reserved3;
+ uint64_t socket_id;
+};
+
+enum command {
+ CMD_NONE,
+ CMD_READ_LIC,
+ CMD_READ_REG,
+ CMD_PROV_AKC,
+ CMD_PROV_CAP,
+};
+
+static int get_file_size(FILE *stream, char *name)
+{
+ long size;
+ int ret;
+
+ ret = fseek(stream, 0L, SEEK_END);
+ if (ret == -1) {
+ fprintf(stderr, "...Could not seek to EOF %s: %s\n", name, strerror(errno));
+ return ret;
+ }
+
+ size = ftell(stream);
+ if (size == -1) {
+ fprintf(stderr, "...Could not get size of file %s: %s\n", name, strerror(errno));
+ return size;
+ }
+
+ rewind(stream);
+
+ return size;
+}
+
+static int sdsi_read_reg(char *socket)
+{
+ FILE *regs_ptr, *guid_ptr;
+ struct sdsi_reg_6dd191 registers;
+ char guid_val[20], *buf;
+ char regs_file[70];
+ char guid_file[70];
+ int ret, i;
+ long size;
+
+ snprintf(regs_file, sizeof(regs_file), "%s%s%s%s",
+ SDSI_DIR, ".", socket, "/registers");
+
+ snprintf(guid_file, sizeof(guid_file), "%s%s%s%s",
+ SDSI_DIR, ".", socket, "/guid");
+
+ memset(&registers, 0, sizeof(registers));
+
+ /* Open the guid file */
+ guid_ptr = fopen(guid_file, "r");
+ if (!guid_ptr) {
+ fprintf(stderr, "...Could not open file %s: %s\n", guid_file, strerror(errno));
+ return -1;
+ }
+
+ fscanf(guid_ptr, "%20s", guid_val);
+ fclose(guid_ptr);
+
+ /* Open the registers file */
+ regs_ptr = fopen(regs_file, "r");
+ if (!regs_ptr) {
+ fprintf(stderr, "...Could not open file %s: %s\n", regs_file, strerror(errno));
+ return -1;
+ }
+
+ /* Get size of the registers file */
+ size = get_file_size(regs_ptr, regs_file);
+ if (size < 0) {
+ ret = size;
+ goto close_regs_ptr;
+ }
+
+ /* Unknown guid. Just dump raw data */
+ if (strcmp(GUID, guid_val)) {
+ printf("Unrecognized guid, %s\n", guid_val);
+
+ buf = (char *)malloc(sizeof(char) * size);
+ if (!buf) {
+ perror("malloc");
+ goto close_regs_ptr;
+ }
+
+ ret = fread(buf, sizeof(uint8_t), size, regs_ptr);
+ if (!ret) {
+ fprintf(stderr, "...Could not read file %s: %s\n", regs_file,
+ strerror(errno));
+ free(buf);
+ goto close_regs_ptr;
+ }
+
+ for (i = 0; i < size; i += sizeof(uint64_t))
+ printf("%3d: 0x%lx\n", i, *(uint64_t *)&buf[i]);
+
+ free(buf);
+ goto close_regs_ptr;
+ }
+
+ /* Print register info for this guid */
+ ret = fread(&registers, sizeof(uint8_t), sizeof(registers), regs_ptr);
+ if (!ret) {
+ fprintf(stderr, "...Could not read file %s: %s\n", regs_file, strerror(errno));
+ goto close_regs_ptr;
+ }
+
+ printf("\n");
+ printf("Info for device %s.%s\n", "intel_vsec.sdsi", socket);
+ printf("\n");
+ printf("PPIN: 0x%lx\n", registers.ppin);
+ printf("Enabled Features\n");
+ printf(" SDSi: %s\n", !!registers.en_features.sdsi ? "Enabled" : "Disabled");
+ printf("Authorization Failure Count\n");
+ printf(" Key Failure Count: %d\n", registers.auth_fail_count.key_failure_count);
+ printf(" Key Failure Count: %d\n", registers.auth_fail_count.key_failure_threshold);
+ printf(" Auth Failure Count: %d\n", registers.auth_fail_count.auth_failure_count);
+ printf(" Auth Failure Count: %d\n", registers.auth_fail_count.key_failure_threshold);
+ printf("Provisioning Availability\n");
+ printf(" Updates Available: %d\n", registers.prov_avail.updates_available);
+ printf(" Updates Threshold: %d\n", registers.prov_avail.updates_threshold);
+ printf("Socket ID: 0x%lx\n", registers.socket_id);
+
+close_regs_ptr:
+ fclose(regs_ptr);
+
+ return 0;
+}
+
+static int sdsi_certificate_dump(char *socket)
+{
+ uint64_t state_certificate[512] = {0};
+ bool first_instance;
+ char cert_file[70];
+ uint64_t previous;
+ FILE *cert_ptr;
+ int i, ret;
+
+ snprintf(cert_file, sizeof(cert_file), "%s%s%s%s",
+ SDSI_DIR, ".", socket, "/state_certificate");
+
+ /* Open the registers file */
+ cert_ptr = fopen(cert_file, "r");
+ if (!cert_ptr) {
+ fprintf(stderr, "...Could not open file %s: %s\n", cert_file, strerror(errno));
+ return -1;
+ }
+
+ /* Read registers */
+ ret = fread(state_certificate, sizeof(uint8_t), sizeof(state_certificate), cert_ptr);
+ if (!ret) {
+ fprintf(stderr, "...Could not read file %s: %s\n", cert_file, strerror(errno));
+ goto close_cert_ptr;
+ }
+
+ printf("%3d: 0x%lx\n", 0, state_certificate[0]);
+ previous = state_certificate[0];
+ first_instance = true;
+
+ for (i = 1; i < (sizeof(state_certificate)/sizeof(uint64_t)); i++) {
+ if (state_certificate[i] == previous) {
+ if (first_instance) {
+ puts("*");
+ first_instance = false;
+ }
+ continue;
+ }
+ printf("%3d: 0x%lx\n", i, state_certificate[i]);
+ previous = state_certificate[i];
+ first_instance = true;
+ }
+ printf("%3d\n", i);
+
+close_cert_ptr:
+ fclose(cert_ptr);
+
+ return 0;
+}
+
+static int sdsi_provision(char *prov_file, char *bin_file)
+{
+ char buf[4096] = { 0 };
+ int bin_fd, prov_fd, size, ret = 0;
+
+ if (!bin_file) {
+ fprintf(stderr, "...No binary file provided\n");
+ return -1;
+ }
+
+ /* Open the provision file */
+ prov_fd = open(prov_file, O_WRONLY);
+ if (prov_fd == -1) {
+ fprintf(stderr, "...Could not open file %s: %s\n", prov_file, strerror(errno));
+ return prov_fd;
+ }
+
+ /* Open the binary */
+ bin_fd = open(bin_file, O_RDONLY);
+ if (bin_fd == -1) {
+ fprintf(stderr, "...Could not open file %s: %s\n", bin_file, strerror(errno));
+ ret = bin_fd;
+ goto close_provision_fd;
+ }
+
+ /* Read the binary file into the buffer */
+ ret = read(bin_fd, buf, 4096);
+ if (ret == -1)
+ goto close_bin_fd;
+
+ size = ret;
+ ret = write(prov_fd, buf, size);
+ if (ret < size) {
+ fprintf(stderr, "...Could not write file %s: %s\n", prov_file, strerror(errno));
+ goto close_bin_fd;
+ }
+
+ printf("Provisioned %s file %s successfully\n", prov_file, bin_file);
+
+close_bin_fd:
+ close(bin_fd);
+close_provision_fd:
+ close(prov_fd);
+
+ return ret;
+}
+
+static int sdsi_provision_akc(char *socket, char *bin_file)
+{
+ char akc_file[70];
+
+ snprintf(akc_file, sizeof(akc_file), "%s%s%s%s",
+ SDSI_DIR, ".", socket, "/provision_akc");
+
+ return sdsi_provision(akc_file, bin_file);
+}
+
+static int sdsi_provision_cap(char *socket, char *bin_file)
+{
+ char cap_file[70];
+
+ snprintf(cap_file, sizeof(cap_file), "%s%s%s%s",
+ SDSI_DIR, ".", socket, "/provision_cap");
+
+ return sdsi_provision(cap_file, bin_file);
+}
+
+static void print_help(char *prog)
+{
+ printf("Usage:\n");
+
+ printf("\t%s -s socket [-r [lic] [reg]] [-a file] [-c file]\n", prog);
+
+ printf("Options:\n");
+ printf("%-13s\t%s\n", "-s <socket>", "socket number to open");
+ printf("%-13s\t%s\n", "-r lic", "read licence data");
+ printf("%-13s\t%s\n", "-r reg", "read SDSi register data");
+ printf("%-13s\t%s\n", "-a <file>", "provision socket with AKC file");
+ printf("%-13s\t%s\n", "-c <file>", "provision socket with CAP file");
+}
+
+int main(int argc, char *argv[])
+{
+ char *bin_file = NULL, *socket = NULL;
+ enum command command = CMD_NONE;
+ int ret, opt, cmd_count = 0;
+
+ while ((opt = getopt(argc, argv, "hs:ra:c:t:")) != -1) {
+ switch (opt) {
+ case 's':
+ socket = optarg;
+ break;
+ case 'r':
+ if (!argv[optind]) {
+ print_help(argv[0]);
+ return -1;
+ }
+
+ if (strlen(argv[optind]) != strlen("lic")) {
+ print_help(argv[0]);
+ return -1;
+ }
+
+ if (!strcmp(argv[optind], "lic")) {
+ command = CMD_READ_LIC;
+ ++cmd_count;
+ break;
+ } else if (!strcmp(argv[optind], "reg")) {
+ command = CMD_READ_REG;
+ ++cmd_count;
+ break;
+ }
+
+ print_help(argv[0]);
+ return -1;
+ case 'a':
+ command = CMD_PROV_AKC;
+ bin_file = optarg;
+ ++cmd_count;
+ break;
+ case 'c':
+ command = CMD_PROV_CAP;
+ bin_file = optarg;
+ ++cmd_count;
+ break;
+ case 'h':
+ print_help(argv[0]);
+ break;
+ default:
+ print_help(argv[0]);
+ return 0;
+ }
+ }
+
+ if (!socket) {
+ fprintf(stderr, "socket is required\n");
+ print_help(argv[0]);
+ return -1;
+ }
+
+ if (!cmd_count) {
+ fprintf(stderr, "need to specify a command\n");
+ print_help(argv[0]);
+ return -1;
+ }
+
+ /* If applicable, check file exists */
+ if (bin_file) {
+ if (!access(bin_file, F_OK) == 0) {
+ fprintf(stderr, "...Could not open file %s: %s\n", bin_file, strerror(errno));
+ return -1;
+ }
+ }
+
+ /* Run the command */
+ if (command == CMD_READ_LIC)
+ ret = sdsi_certificate_dump(socket);
+ else if (command == CMD_READ_REG)
+ ret = sdsi_read_reg(socket);
+ else if (command == CMD_PROV_AKC)
+ ret = sdsi_provision_akc(socket, bin_file);
+ else
+ ret = sdsi_provision_cap(socket, bin_file);
+
+ return ret;
+}
--
2.25.1