tools/arch/x86: intel_sdsi: Add support for reading meter certificates
authorDavid E. Box <david.e.box@linux.intel.com>
Sat, 19 Nov 2022 00:23:43 +0000 (16:23 -0800)
committerHans de Goede <hdegoede@redhat.com>
Mon, 21 Nov 2022 09:56:17 +0000 (10:56 +0100)
Add option to read and decode On Demand meter certificates.

Link: https://github.com/intel/intel-sdsi/blob/master/meter-certificate.rst
Signed-off-by: David E. Box <david.e.box@linux.intel.com>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Link: https://lore.kernel.org/r/20221119002343.1281885-10-david.e.box@linux.intel.com
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
tools/arch/x86/intel_sdsi/intel_sdsi.c

index b42e1b6..2cd9276 100644 (file)
 #define GUID_V2                        0xF210D9EF
 #define REGS_SIZE_GUID_V2      80
 #define STATE_CERT_MAX_SIZE    4096
+#define METER_CERT_MAX_SIZE    4096
 #define STATE_MAX_NUM_LICENSES 16
 #define STATE_MAX_NUM_IN_BUNDLE        (uint32_t)8
+#define METER_MAX_NUM_BUNDLES  8
 
 #define __round_mask(x, y) ((__typeof__(x))((y) - 1))
 #define round_up(x, y) ((((x) - 1) | __round_mask(x, y)) + 1)
@@ -151,6 +153,21 @@ struct bundle_encoding {
        uint32_t encoding_rsvd[7];
 };
 
+struct meter_certificate {
+       uint32_t block_signature;
+       uint32_t counter_unit;
+       uint64_t ppin;
+       uint32_t bundle_length;
+       uint32_t reserved;
+       uint32_t mmrc_encoding;
+       uint32_t mmrc_counter;
+};
+
+struct bundle_encoding_counter {
+       uint32_t encoding;
+       uint32_t counter;
+};
+
 struct sdsi_dev {
        struct sdsi_regs regs;
        struct state_certificate sc;
@@ -161,6 +178,7 @@ struct sdsi_dev {
 
 enum command {
        CMD_SOCKET_INFO,
+       CMD_METER_CERT,
        CMD_STATE_CERT,
        CMD_PROV_AKC,
        CMD_PROV_CAP,
@@ -308,6 +326,86 @@ static void get_feature(uint32_t encoding, char *feature)
        feature[0] = name[3];
 }
 
+static int sdsi_meter_cert_show(struct sdsi_dev *s)
+{
+       char buf[METER_CERT_MAX_SIZE] = {0};
+       struct bundle_encoding_counter *bec;
+       struct meter_certificate *mc;
+       uint32_t count = 0;
+       FILE *cert_ptr;
+       int ret, size;
+
+       ret = sdsi_update_registers(s);
+       if (ret)
+               return ret;
+
+       if (!s->regs.en_features.sdsi) {
+               fprintf(stderr, "SDSi feature is present but not enabled.\n");
+               fprintf(stderr, " Unable to read meter certificate\n");
+               return -1;
+       }
+
+       if (!s->regs.en_features.metering) {
+               fprintf(stderr, "Metering not supporting on this socket.\n");
+               return -1;
+       }
+
+       ret = chdir(s->dev_path);
+       if (ret == -1) {
+               perror("chdir");
+               return ret;
+       }
+
+       cert_ptr = fopen("meter_certificate", "r");
+       if (!cert_ptr) {
+               perror("Could not open 'meter_certificate' file");
+               return -1;
+       }
+
+       size = fread(buf, 1, sizeof(buf), cert_ptr);
+       if (!size) {
+               fprintf(stderr, "Could not read 'meter_certificate' file\n");
+               fclose(cert_ptr);
+               return -1;
+       }
+       fclose(cert_ptr);
+
+       mc = (struct meter_certificate *)buf;
+
+       printf("\n");
+       printf("Meter certificate for device %s\n", s->dev_name);
+       printf("\n");
+       printf("Block Signature:       0x%x\n", mc->block_signature);
+       printf("Count Unit:            %dms\n", mc->counter_unit);
+       printf("PPIN:                  0x%lx\n", mc->ppin);
+       printf("Feature Bundle Length: %d\n", mc->bundle_length);
+       printf("MMRC encoding:         %d\n", mc->mmrc_encoding);
+       printf("MMRC counter:          %d\n", mc->mmrc_counter);
+       if (mc->bundle_length % 8) {
+               fprintf(stderr, "Invalid bundle length\n");
+               return -1;
+       }
+
+       if (mc->bundle_length > METER_MAX_NUM_BUNDLES * 8)  {
+               fprintf(stderr, "More than %d bundles: %d\n",
+                       METER_MAX_NUM_BUNDLES, mc->bundle_length / 8);
+               return -1;
+       }
+
+       bec = (void *)(mc) + sizeof(mc);
+
+       printf("Number of Feature Counters:          %d\n", mc->bundle_length / 8);
+       while (count++ < mc->bundle_length / 8) {
+               char feature[5];
+
+               feature[4] = '\0';
+               get_feature(bec[count].encoding, feature);
+               printf("    %s:          %d\n", feature, bec[count].counter);
+       }
+
+       return 0;
+}
+
 static int sdsi_state_cert_show(struct sdsi_dev *s)
 {
        char buf[STATE_CERT_MAX_SIZE] = {0};
@@ -627,7 +725,7 @@ static void sdsi_free_dev(struct sdsi_dev *s)
 
 static void usage(char *prog)
 {
-       printf("Usage: %s [-l] [-d DEVNO [-i] [-s] [-a FILE] [-c FILE]]\n", prog);
+       printf("Usage: %s [-l] [-d DEVNO [-i] [-s] [-m] [-a FILE] [-c FILE]]\n", prog);
 }
 
 static void show_help(void)
@@ -637,6 +735,7 @@ static void show_help(void)
        printf("  %-18s\t%s\n", "-d, --devno DEVNO",    "On Demand device number");
        printf("  %-18s\t%s\n", "-i, --info",           "show socket information");
        printf("  %-18s\t%s\n", "-s, --state",          "show state certificate");
+       printf("  %-18s\t%s\n", "-m, --meter",          "show meter certificate");
        printf("  %-18s\t%s\n", "-a, --akc FILE",       "provision socket with AKC FILE");
        printf("  %-18s\t%s\n", "-c, --cap FILE>",      "provision socket with CAP FILE");
 }
@@ -658,6 +757,7 @@ int main(int argc, char *argv[])
                {"help",        no_argument,            0, 'h'},
                {"info",        no_argument,            0, 'i'},
                {"list",        no_argument,            0, 'l'},
+               {"meter",       no_argument,            0, 'm'},
                {"state",       no_argument,            0, 's'},
                {0,             0,                      0, 0 }
        };
@@ -665,7 +765,7 @@ int main(int argc, char *argv[])
 
        progname = argv[0];
 
-       while ((opt = getopt_long_only(argc, argv, "+a:c:d:hils", long_options,
+       while ((opt = getopt_long_only(argc, argv, "+a:c:d:hilms", long_options,
                        &option_index)) != -1) {
                switch (opt) {
                case 'd':
@@ -678,6 +778,9 @@ int main(int argc, char *argv[])
                case 'i':
                        command = CMD_SOCKET_INFO;
                        break;
+               case 'm':
+                       command = CMD_METER_CERT;
+                       break;
                case 's':
                        command = CMD_STATE_CERT;
                        break;
@@ -715,6 +818,9 @@ int main(int argc, char *argv[])
                case CMD_SOCKET_INFO:
                        ret = sdsi_read_reg(s);
                        break;
+               case CMD_METER_CERT:
+                       ret = sdsi_meter_cert_show(s);
+                       break;
                case CMD_STATE_CERT:
                        ret = sdsi_state_cert_show(s);
                        break;