1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
29d64fc08SMario Limonciello /*
39d64fc08SMario Limonciello  *  Sample application for SMBIOS communication over WMI interface
49d64fc08SMario Limonciello  *  Performs the following:
59d64fc08SMario Limonciello  *  - Simple cmd_class/cmd_select lookup for TPM information
69d64fc08SMario Limonciello  *  - Simple query of known tokens and their values
79d64fc08SMario Limonciello  *  - Simple activation of a token
89d64fc08SMario Limonciello  *
99d64fc08SMario Limonciello  *  Copyright (C) 2017 Dell, Inc.
109d64fc08SMario Limonciello  */
119d64fc08SMario Limonciello 
129d64fc08SMario Limonciello #include <errno.h>
139d64fc08SMario Limonciello #include <fcntl.h>
149d64fc08SMario Limonciello #include <stdio.h>
159d64fc08SMario Limonciello #include <stdlib.h>
169d64fc08SMario Limonciello #include <sys/ioctl.h>
179d64fc08SMario Limonciello #include <unistd.h>
189d64fc08SMario Limonciello 
199d64fc08SMario Limonciello /* if uapi header isn't installed, this might not yet exist */
209d64fc08SMario Limonciello #ifndef __packed
219d64fc08SMario Limonciello #define __packed __attribute__((packed))
229d64fc08SMario Limonciello #endif
239d64fc08SMario Limonciello #include <linux/wmi.h>
249d64fc08SMario Limonciello 
259d64fc08SMario Limonciello /* It would be better to discover these using udev, but for a simple
269d64fc08SMario Limonciello  * application they're hardcoded
279d64fc08SMario Limonciello  */
289d64fc08SMario Limonciello static const char *ioctl_devfs = "/dev/wmi/dell-smbios";
299d64fc08SMario Limonciello static const char *token_sysfs =
309d64fc08SMario Limonciello 			"/sys/bus/platform/devices/dell-smbios.0/tokens";
319d64fc08SMario Limonciello 
show_buffer(struct dell_wmi_smbios_buffer * buffer)329d64fc08SMario Limonciello static void show_buffer(struct dell_wmi_smbios_buffer *buffer)
339d64fc08SMario Limonciello {
349d64fc08SMario Limonciello 	printf("Call: %x/%x [%x,%x,%x,%x]\nResults: [%8x,%8x,%8x,%8x]\n",
359d64fc08SMario Limonciello 	buffer->std.cmd_class, buffer->std.cmd_select,
369d64fc08SMario Limonciello 	buffer->std.input[0], buffer->std.input[1],
379d64fc08SMario Limonciello 	buffer->std.input[2], buffer->std.input[3],
389d64fc08SMario Limonciello 	buffer->std.output[0], buffer->std.output[1],
399d64fc08SMario Limonciello 	buffer->std.output[2], buffer->std.output[3]);
409d64fc08SMario Limonciello }
419d64fc08SMario Limonciello 
run_wmi_smbios_cmd(struct dell_wmi_smbios_buffer * buffer)429d64fc08SMario Limonciello static int run_wmi_smbios_cmd(struct dell_wmi_smbios_buffer *buffer)
439d64fc08SMario Limonciello {
449d64fc08SMario Limonciello 	int fd;
459d64fc08SMario Limonciello 	int ret;
469d64fc08SMario Limonciello 
479d64fc08SMario Limonciello 	fd = open(ioctl_devfs, O_NONBLOCK);
489d64fc08SMario Limonciello 	ret = ioctl(fd, DELL_WMI_SMBIOS_CMD, buffer);
499d64fc08SMario Limonciello 	close(fd);
509d64fc08SMario Limonciello 	return ret;
519d64fc08SMario Limonciello }
529d64fc08SMario Limonciello 
find_token(__u16 token,__u16 * location,__u16 * value)539d64fc08SMario Limonciello static int find_token(__u16 token, __u16 *location, __u16 *value)
549d64fc08SMario Limonciello {
559d64fc08SMario Limonciello 	char location_sysfs[60];
569d64fc08SMario Limonciello 	char value_sysfs[57];
579d64fc08SMario Limonciello 	char buf[4096];
589d64fc08SMario Limonciello 	FILE *f;
599d64fc08SMario Limonciello 	int ret;
609d64fc08SMario Limonciello 
619d64fc08SMario Limonciello 	ret = sprintf(value_sysfs, "%s/%04x_value", token_sysfs, token);
629d64fc08SMario Limonciello 	if (ret < 0) {
639d64fc08SMario Limonciello 		printf("sprintf value failed\n");
649d64fc08SMario Limonciello 		return 2;
659d64fc08SMario Limonciello 	}
669d64fc08SMario Limonciello 	f = fopen(value_sysfs, "rb");
679d64fc08SMario Limonciello 	if (!f) {
689d64fc08SMario Limonciello 		printf("failed to open %s\n", value_sysfs);
699d64fc08SMario Limonciello 		return 2;
709d64fc08SMario Limonciello 	}
719d64fc08SMario Limonciello 	fread(buf, 1, 4096, f);
729d64fc08SMario Limonciello 	fclose(f);
739d64fc08SMario Limonciello 	*value = (__u16) strtol(buf, NULL, 16);
749d64fc08SMario Limonciello 
759d64fc08SMario Limonciello 	ret = sprintf(location_sysfs, "%s/%04x_location", token_sysfs, token);
769d64fc08SMario Limonciello 	if (ret < 0) {
779d64fc08SMario Limonciello 		printf("sprintf location failed\n");
789d64fc08SMario Limonciello 		return 1;
799d64fc08SMario Limonciello 	}
809d64fc08SMario Limonciello 	f = fopen(location_sysfs, "rb");
819d64fc08SMario Limonciello 	if (!f) {
829d64fc08SMario Limonciello 		printf("failed to open %s\n", location_sysfs);
839d64fc08SMario Limonciello 		return 2;
849d64fc08SMario Limonciello 	}
859d64fc08SMario Limonciello 	fread(buf, 1, 4096, f);
869d64fc08SMario Limonciello 	fclose(f);
879d64fc08SMario Limonciello 	*location = (__u16) strtol(buf, NULL, 16);
889d64fc08SMario Limonciello 
899d64fc08SMario Limonciello 	if (*location)
909d64fc08SMario Limonciello 		return 0;
919d64fc08SMario Limonciello 	return 2;
929d64fc08SMario Limonciello }
939d64fc08SMario Limonciello 
token_is_active(__u16 * location,__u16 * cmpvalue,struct dell_wmi_smbios_buffer * buffer)949d64fc08SMario Limonciello static int token_is_active(__u16 *location, __u16 *cmpvalue,
959d64fc08SMario Limonciello 			   struct dell_wmi_smbios_buffer *buffer)
969d64fc08SMario Limonciello {
979d64fc08SMario Limonciello 	int ret;
989d64fc08SMario Limonciello 
999d64fc08SMario Limonciello 	buffer->std.cmd_class = CLASS_TOKEN_READ;
1009d64fc08SMario Limonciello 	buffer->std.cmd_select = SELECT_TOKEN_STD;
1019d64fc08SMario Limonciello 	buffer->std.input[0] = *location;
1029d64fc08SMario Limonciello 	ret = run_wmi_smbios_cmd(buffer);
1039d64fc08SMario Limonciello 	if (ret != 0 || buffer->std.output[0] != 0)
1049d64fc08SMario Limonciello 		return ret;
1059d64fc08SMario Limonciello 	ret = (buffer->std.output[1] == *cmpvalue);
1069d64fc08SMario Limonciello 	return ret;
1079d64fc08SMario Limonciello }
1089d64fc08SMario Limonciello 
query_token(__u16 token,struct dell_wmi_smbios_buffer * buffer)1099d64fc08SMario Limonciello static int query_token(__u16 token, struct dell_wmi_smbios_buffer *buffer)
1109d64fc08SMario Limonciello {
1119d64fc08SMario Limonciello 	__u16 location;
1129d64fc08SMario Limonciello 	__u16 value;
1139d64fc08SMario Limonciello 	int ret;
1149d64fc08SMario Limonciello 
1159d64fc08SMario Limonciello 	ret = find_token(token, &location, &value);
1169d64fc08SMario Limonciello 	if (ret != 0) {
1179d64fc08SMario Limonciello 		printf("unable to find token %04x\n", token);
1189d64fc08SMario Limonciello 		return 1;
1199d64fc08SMario Limonciello 	}
1209d64fc08SMario Limonciello 	return token_is_active(&location, &value, buffer);
1219d64fc08SMario Limonciello }
1229d64fc08SMario Limonciello 
activate_token(struct dell_wmi_smbios_buffer * buffer,__u16 token)1239d64fc08SMario Limonciello static int activate_token(struct dell_wmi_smbios_buffer *buffer,
1249d64fc08SMario Limonciello 		   __u16 token)
1259d64fc08SMario Limonciello {
1269d64fc08SMario Limonciello 	__u16 location;
1279d64fc08SMario Limonciello 	__u16 value;
1289d64fc08SMario Limonciello 	int ret;
1299d64fc08SMario Limonciello 
1309d64fc08SMario Limonciello 	ret = find_token(token, &location, &value);
1319d64fc08SMario Limonciello 	if (ret != 0) {
1329d64fc08SMario Limonciello 		printf("unable to find token %04x\n", token);
1339d64fc08SMario Limonciello 		return 1;
1349d64fc08SMario Limonciello 	}
1359d64fc08SMario Limonciello 	buffer->std.cmd_class = CLASS_TOKEN_WRITE;
1369d64fc08SMario Limonciello 	buffer->std.cmd_select = SELECT_TOKEN_STD;
1379d64fc08SMario Limonciello 	buffer->std.input[0] = location;
1389d64fc08SMario Limonciello 	buffer->std.input[1] = 1;
1399d64fc08SMario Limonciello 	ret = run_wmi_smbios_cmd(buffer);
1409d64fc08SMario Limonciello 	return ret;
1419d64fc08SMario Limonciello }
1429d64fc08SMario Limonciello 
query_buffer_size(__u64 * buffer_size)1439d64fc08SMario Limonciello static int query_buffer_size(__u64 *buffer_size)
1449d64fc08SMario Limonciello {
1459d64fc08SMario Limonciello 	FILE *f;
1469d64fc08SMario Limonciello 
1479d64fc08SMario Limonciello 	f = fopen(ioctl_devfs, "rb");
1489d64fc08SMario Limonciello 	if (!f)
1499d64fc08SMario Limonciello 		return -EINVAL;
1509d64fc08SMario Limonciello 	fread(buffer_size, sizeof(__u64), 1, f);
1519d64fc08SMario Limonciello 	fclose(f);
1529d64fc08SMario Limonciello 	return EXIT_SUCCESS;
1539d64fc08SMario Limonciello }
1549d64fc08SMario Limonciello 
main(void)1559d64fc08SMario Limonciello int main(void)
1569d64fc08SMario Limonciello {
1579d64fc08SMario Limonciello 	struct dell_wmi_smbios_buffer *buffer;
1589d64fc08SMario Limonciello 	int ret;
1599d64fc08SMario Limonciello 	__u64 value = 0;
1609d64fc08SMario Limonciello 
1619d64fc08SMario Limonciello 	ret = query_buffer_size(&value);
1629d64fc08SMario Limonciello 	if (ret == EXIT_FAILURE || !value) {
1639d64fc08SMario Limonciello 		printf("Unable to read buffer size\n");
1649d64fc08SMario Limonciello 		goto out;
1659d64fc08SMario Limonciello 	}
1669d64fc08SMario Limonciello 	printf("Detected required buffer size %lld\n", value);
1679d64fc08SMario Limonciello 
1689d64fc08SMario Limonciello 	buffer = malloc(value);
1699d64fc08SMario Limonciello 	if (buffer == NULL) {
1709d64fc08SMario Limonciello 		printf("failed to alloc memory for ioctl\n");
1719d64fc08SMario Limonciello 		ret = -ENOMEM;
1729d64fc08SMario Limonciello 		goto out;
1739d64fc08SMario Limonciello 	}
1749d64fc08SMario Limonciello 	buffer->length = value;
1759d64fc08SMario Limonciello 
1769d64fc08SMario Limonciello 	/* simple SMBIOS call for looking up TPM info */
1779d64fc08SMario Limonciello 	buffer->std.cmd_class = CLASS_FLASH_INTERFACE;
1789d64fc08SMario Limonciello 	buffer->std.cmd_select = SELECT_FLASH_INTERFACE;
1799d64fc08SMario Limonciello 	buffer->std.input[0] = 2;
1809d64fc08SMario Limonciello 	ret = run_wmi_smbios_cmd(buffer);
1819d64fc08SMario Limonciello 	if (ret) {
1829d64fc08SMario Limonciello 		printf("smbios ioctl failed: %d\n", ret);
1839d64fc08SMario Limonciello 		ret = EXIT_FAILURE;
1849d64fc08SMario Limonciello 		goto out;
1859d64fc08SMario Limonciello 	}
1869d64fc08SMario Limonciello 	show_buffer(buffer);
1879d64fc08SMario Limonciello 
1889d64fc08SMario Limonciello 	/* query some tokens */
1899d64fc08SMario Limonciello 	ret = query_token(CAPSULE_EN_TOKEN, buffer);
1909d64fc08SMario Limonciello 	printf("UEFI Capsule enabled token is: %d\n", ret);
1919d64fc08SMario Limonciello 	ret = query_token(CAPSULE_DIS_TOKEN, buffer);
1929d64fc08SMario Limonciello 	printf("UEFI Capsule disabled token is: %d\n", ret);
1939d64fc08SMario Limonciello 
1949d64fc08SMario Limonciello 	/* activate UEFI capsule token if disabled */
1959d64fc08SMario Limonciello 	if (ret) {
1969d64fc08SMario Limonciello 		printf("Enabling UEFI capsule token");
1979d64fc08SMario Limonciello 		if (activate_token(buffer, CAPSULE_EN_TOKEN)) {
1989d64fc08SMario Limonciello 			printf("activate failed\n");
1999d64fc08SMario Limonciello 			ret = -1;
2009d64fc08SMario Limonciello 			goto out;
2019d64fc08SMario Limonciello 		}
2029d64fc08SMario Limonciello 	}
2039d64fc08SMario Limonciello 	ret = EXIT_SUCCESS;
2049d64fc08SMario Limonciello out:
2059d64fc08SMario Limonciello 	free(buffer);
2069d64fc08SMario Limonciello 	return ret;
2079d64fc08SMario Limonciello }
208