Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  Sample application for SMBIOS communication over WMI interface
0004  *  Performs the following:
0005  *  - Simple cmd_class/cmd_select lookup for TPM information
0006  *  - Simple query of known tokens and their values
0007  *  - Simple activation of a token
0008  *
0009  *  Copyright (C) 2017 Dell, Inc.
0010  */
0011 
0012 #include <errno.h>
0013 #include <fcntl.h>
0014 #include <stdio.h>
0015 #include <stdlib.h>
0016 #include <sys/ioctl.h>
0017 #include <unistd.h>
0018 
0019 /* if uapi header isn't installed, this might not yet exist */
0020 #ifndef __packed
0021 #define __packed __attribute__((packed))
0022 #endif
0023 #include <linux/wmi.h>
0024 
0025 /* It would be better to discover these using udev, but for a simple
0026  * application they're hardcoded
0027  */
0028 static const char *ioctl_devfs = "/dev/wmi/dell-smbios";
0029 static const char *token_sysfs =
0030             "/sys/bus/platform/devices/dell-smbios.0/tokens";
0031 
0032 static void show_buffer(struct dell_wmi_smbios_buffer *buffer)
0033 {
0034     printf("Call: %x/%x [%x,%x,%x,%x]\nResults: [%8x,%8x,%8x,%8x]\n",
0035     buffer->std.cmd_class, buffer->std.cmd_select,
0036     buffer->std.input[0], buffer->std.input[1],
0037     buffer->std.input[2], buffer->std.input[3],
0038     buffer->std.output[0], buffer->std.output[1],
0039     buffer->std.output[2], buffer->std.output[3]);
0040 }
0041 
0042 static int run_wmi_smbios_cmd(struct dell_wmi_smbios_buffer *buffer)
0043 {
0044     int fd;
0045     int ret;
0046 
0047     fd = open(ioctl_devfs, O_NONBLOCK);
0048     ret = ioctl(fd, DELL_WMI_SMBIOS_CMD, buffer);
0049     close(fd);
0050     return ret;
0051 }
0052 
0053 static int find_token(__u16 token, __u16 *location, __u16 *value)
0054 {
0055     char location_sysfs[60];
0056     char value_sysfs[57];
0057     char buf[4096];
0058     FILE *f;
0059     int ret;
0060 
0061     ret = sprintf(value_sysfs, "%s/%04x_value", token_sysfs, token);
0062     if (ret < 0) {
0063         printf("sprintf value failed\n");
0064         return 2;
0065     }
0066     f = fopen(value_sysfs, "rb");
0067     if (!f) {
0068         printf("failed to open %s\n", value_sysfs);
0069         return 2;
0070     }
0071     fread(buf, 1, 4096, f);
0072     fclose(f);
0073     *value = (__u16) strtol(buf, NULL, 16);
0074 
0075     ret = sprintf(location_sysfs, "%s/%04x_location", token_sysfs, token);
0076     if (ret < 0) {
0077         printf("sprintf location failed\n");
0078         return 1;
0079     }
0080     f = fopen(location_sysfs, "rb");
0081     if (!f) {
0082         printf("failed to open %s\n", location_sysfs);
0083         return 2;
0084     }
0085     fread(buf, 1, 4096, f);
0086     fclose(f);
0087     *location = (__u16) strtol(buf, NULL, 16);
0088 
0089     if (*location)
0090         return 0;
0091     return 2;
0092 }
0093 
0094 static int token_is_active(__u16 *location, __u16 *cmpvalue,
0095                struct dell_wmi_smbios_buffer *buffer)
0096 {
0097     int ret;
0098 
0099     buffer->std.cmd_class = CLASS_TOKEN_READ;
0100     buffer->std.cmd_select = SELECT_TOKEN_STD;
0101     buffer->std.input[0] = *location;
0102     ret = run_wmi_smbios_cmd(buffer);
0103     if (ret != 0 || buffer->std.output[0] != 0)
0104         return ret;
0105     ret = (buffer->std.output[1] == *cmpvalue);
0106     return ret;
0107 }
0108 
0109 static int query_token(__u16 token, struct dell_wmi_smbios_buffer *buffer)
0110 {
0111     __u16 location;
0112     __u16 value;
0113     int ret;
0114 
0115     ret = find_token(token, &location, &value);
0116     if (ret != 0) {
0117         printf("unable to find token %04x\n", token);
0118         return 1;
0119     }
0120     return token_is_active(&location, &value, buffer);
0121 }
0122 
0123 static int activate_token(struct dell_wmi_smbios_buffer *buffer,
0124            __u16 token)
0125 {
0126     __u16 location;
0127     __u16 value;
0128     int ret;
0129 
0130     ret = find_token(token, &location, &value);
0131     if (ret != 0) {
0132         printf("unable to find token %04x\n", token);
0133         return 1;
0134     }
0135     buffer->std.cmd_class = CLASS_TOKEN_WRITE;
0136     buffer->std.cmd_select = SELECT_TOKEN_STD;
0137     buffer->std.input[0] = location;
0138     buffer->std.input[1] = 1;
0139     ret = run_wmi_smbios_cmd(buffer);
0140     return ret;
0141 }
0142 
0143 static int query_buffer_size(__u64 *buffer_size)
0144 {
0145     FILE *f;
0146 
0147     f = fopen(ioctl_devfs, "rb");
0148     if (!f)
0149         return -EINVAL;
0150     fread(buffer_size, sizeof(__u64), 1, f);
0151     fclose(f);
0152     return EXIT_SUCCESS;
0153 }
0154 
0155 int main(void)
0156 {
0157     struct dell_wmi_smbios_buffer *buffer;
0158     int ret;
0159     __u64 value = 0;
0160 
0161     ret = query_buffer_size(&value);
0162     if (ret == EXIT_FAILURE || !value) {
0163         printf("Unable to read buffer size\n");
0164         goto out;
0165     }
0166     printf("Detected required buffer size %lld\n", value);
0167 
0168     buffer = malloc(value);
0169     if (buffer == NULL) {
0170         printf("failed to alloc memory for ioctl\n");
0171         ret = -ENOMEM;
0172         goto out;
0173     }
0174     buffer->length = value;
0175 
0176     /* simple SMBIOS call for looking up TPM info */
0177     buffer->std.cmd_class = CLASS_FLASH_INTERFACE;
0178     buffer->std.cmd_select = SELECT_FLASH_INTERFACE;
0179     buffer->std.input[0] = 2;
0180     ret = run_wmi_smbios_cmd(buffer);
0181     if (ret) {
0182         printf("smbios ioctl failed: %d\n", ret);
0183         ret = EXIT_FAILURE;
0184         goto out;
0185     }
0186     show_buffer(buffer);
0187 
0188     /* query some tokens */
0189     ret = query_token(CAPSULE_EN_TOKEN, buffer);
0190     printf("UEFI Capsule enabled token is: %d\n", ret);
0191     ret = query_token(CAPSULE_DIS_TOKEN, buffer);
0192     printf("UEFI Capsule disabled token is: %d\n", ret);
0193 
0194     /* activate UEFI capsule token if disabled */
0195     if (ret) {
0196         printf("Enabling UEFI capsule token");
0197         if (activate_token(buffer, CAPSULE_EN_TOKEN)) {
0198             printf("activate failed\n");
0199             ret = -1;
0200             goto out;
0201         }
0202     }
0203     ret = EXIT_SUCCESS;
0204 out:
0205     free(buffer);
0206     return ret;
0207 }