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