cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dell-smbios-example.c (4863B)


      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 */
     28static const char *ioctl_devfs = "/dev/wmi/dell-smbios";
     29static const char *token_sysfs =
     30			"/sys/bus/platform/devices/dell-smbios.0/tokens";
     31
     32static 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
     42static 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
     53static 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
     94static 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
    109static 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
    123static 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
    143static 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
    155int 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;
    204out:
    205	free(buffer);
    206	return ret;
    207}