1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Sample application for SMBIOS communication over WMI interface 4 * Performs the following: 5 * - Simple cmd_class/cmd_select lookup for TPM information 6 * - Simple query of known tokens and their values 7 * - Simple activation of a token 8 * 9 * Copyright (C) 2017 Dell, Inc. 10 */ 11 12 #include <errno.h> 13 #include <fcntl.h> 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <sys/ioctl.h> 17 #include <unistd.h> 18 19 /* if uapi header isn't installed, this might not yet exist */ 20 #ifndef __packed 21 #define __packed __attribute__((packed)) 22 #endif 23 #include <linux/wmi.h> 24 25 /* It would be better to discover these using udev, but for a simple 26 * application they're hardcoded 27 */ 28 static const char *ioctl_devfs = "/dev/wmi/dell-smbios"; 29 static const char *token_sysfs = 30 "/sys/bus/platform/devices/dell-smbios.0/tokens"; 31 32 static void show_buffer(struct dell_wmi_smbios_buffer *buffer) 33 { 34 printf("Call: %x/%x [%x,%x,%x,%x]\nResults: [%8x,%8x,%8x,%8x]\n", 35 buffer->std.cmd_class, buffer->std.cmd_select, 36 buffer->std.input[0], buffer->std.input[1], 37 buffer->std.input[2], buffer->std.input[3], 38 buffer->std.output[0], buffer->std.output[1], 39 buffer->std.output[2], buffer->std.output[3]); 40 } 41 42 static int run_wmi_smbios_cmd(struct dell_wmi_smbios_buffer *buffer) 43 { 44 int fd; 45 int ret; 46 47 fd = open(ioctl_devfs, O_NONBLOCK); 48 ret = ioctl(fd, DELL_WMI_SMBIOS_CMD, buffer); 49 close(fd); 50 return ret; 51 } 52 53 static int find_token(__u16 token, __u16 *location, __u16 *value) 54 { 55 char location_sysfs[60]; 56 char value_sysfs[57]; 57 char buf[4096]; 58 FILE *f; 59 int ret; 60 61 ret = sprintf(value_sysfs, "%s/%04x_value", token_sysfs, token); 62 if (ret < 0) { 63 printf("sprintf value failed\n"); 64 return 2; 65 } 66 f = fopen(value_sysfs, "rb"); 67 if (!f) { 68 printf("failed to open %s\n", value_sysfs); 69 return 2; 70 } 71 fread(buf, 1, 4096, f); 72 fclose(f); 73 *value = (__u16) strtol(buf, NULL, 16); 74 75 ret = sprintf(location_sysfs, "%s/%04x_location", token_sysfs, token); 76 if (ret < 0) { 77 printf("sprintf location failed\n"); 78 return 1; 79 } 80 f = fopen(location_sysfs, "rb"); 81 if (!f) { 82 printf("failed to open %s\n", location_sysfs); 83 return 2; 84 } 85 fread(buf, 1, 4096, f); 86 fclose(f); 87 *location = (__u16) strtol(buf, NULL, 16); 88 89 if (*location) 90 return 0; 91 return 2; 92 } 93 94 static int token_is_active(__u16 *location, __u16 *cmpvalue, 95 struct dell_wmi_smbios_buffer *buffer) 96 { 97 int ret; 98 99 buffer->std.cmd_class = CLASS_TOKEN_READ; 100 buffer->std.cmd_select = SELECT_TOKEN_STD; 101 buffer->std.input[0] = *location; 102 ret = run_wmi_smbios_cmd(buffer); 103 if (ret != 0 || buffer->std.output[0] != 0) 104 return ret; 105 ret = (buffer->std.output[1] == *cmpvalue); 106 return ret; 107 } 108 109 static int query_token(__u16 token, struct dell_wmi_smbios_buffer *buffer) 110 { 111 __u16 location; 112 __u16 value; 113 int ret; 114 115 ret = find_token(token, &location, &value); 116 if (ret != 0) { 117 printf("unable to find token %04x\n", token); 118 return 1; 119 } 120 return token_is_active(&location, &value, buffer); 121 } 122 123 static int activate_token(struct dell_wmi_smbios_buffer *buffer, 124 __u16 token) 125 { 126 __u16 location; 127 __u16 value; 128 int ret; 129 130 ret = find_token(token, &location, &value); 131 if (ret != 0) { 132 printf("unable to find token %04x\n", token); 133 return 1; 134 } 135 buffer->std.cmd_class = CLASS_TOKEN_WRITE; 136 buffer->std.cmd_select = SELECT_TOKEN_STD; 137 buffer->std.input[0] = location; 138 buffer->std.input[1] = 1; 139 ret = run_wmi_smbios_cmd(buffer); 140 return ret; 141 } 142 143 static int query_buffer_size(__u64 *buffer_size) 144 { 145 FILE *f; 146 147 f = fopen(ioctl_devfs, "rb"); 148 if (!f) 149 return -EINVAL; 150 fread(buffer_size, sizeof(__u64), 1, f); 151 fclose(f); 152 return EXIT_SUCCESS; 153 } 154 155 int main(void) 156 { 157 struct dell_wmi_smbios_buffer *buffer; 158 int ret; 159 __u64 value = 0; 160 161 ret = query_buffer_size(&value); 162 if (ret == EXIT_FAILURE || !value) { 163 printf("Unable to read buffer size\n"); 164 goto out; 165 } 166 printf("Detected required buffer size %lld\n", value); 167 168 buffer = malloc(value); 169 if (buffer == NULL) { 170 printf("failed to alloc memory for ioctl\n"); 171 ret = -ENOMEM; 172 goto out; 173 } 174 buffer->length = value; 175 176 /* simple SMBIOS call for looking up TPM info */ 177 buffer->std.cmd_class = CLASS_FLASH_INTERFACE; 178 buffer->std.cmd_select = SELECT_FLASH_INTERFACE; 179 buffer->std.input[0] = 2; 180 ret = run_wmi_smbios_cmd(buffer); 181 if (ret) { 182 printf("smbios ioctl failed: %d\n", ret); 183 ret = EXIT_FAILURE; 184 goto out; 185 } 186 show_buffer(buffer); 187 188 /* query some tokens */ 189 ret = query_token(CAPSULE_EN_TOKEN, buffer); 190 printf("UEFI Capsule enabled token is: %d\n", ret); 191 ret = query_token(CAPSULE_DIS_TOKEN, buffer); 192 printf("UEFI Capsule disabled token is: %d\n", ret); 193 194 /* activate UEFI capsule token if disabled */ 195 if (ret) { 196 printf("Enabling UEFI capsule token"); 197 if (activate_token(buffer, CAPSULE_EN_TOKEN)) { 198 printf("activate failed\n"); 199 ret = -1; 200 goto out; 201 } 202 } 203 ret = EXIT_SUCCESS; 204 out: 205 free(buffer); 206 return ret; 207 } 208