Skip to content

Commit 33b9ca1

Browse files
Mario Limonciellodvhart
authored andcommitted
platform/x86: dell-smbios: Add a sysfs interface for SMBIOS tokens
Currently userspace tools can access system tokens via the dcdbas kernel module and a SMI call that will cause the platform to execute SMM code. With a goal in mind of deprecating the dcdbas kernel module a different method for accessing these tokens from userspace needs to be created. This is intentionally marked to only be readable as a process with CAP_SYS_ADMIN as it can contain sensitive information about the platform's configuration. While adding this interface I found that some tokens are duplicated. These need to be ignored from sysfs to avoid duplicate files. MAINTAINERS was missing for this driver. Add myself and Pali to maintainers list for it. Signed-off-by: Mario Limonciello <[email protected]> Reviewed-by: Edward O'Callaghan <[email protected]> Signed-off-by: Darren Hart (VMware) <[email protected]>
1 parent 980f481 commit 33b9ca1

File tree

3 files changed

+240
-1
lines changed

3 files changed

+240
-1
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
What: /sys/devices/platform/<platform>/tokens/*
2+
Date: November 2017
3+
KernelVersion: 4.15
4+
Contact: "Mario Limonciello" <[email protected]>
5+
Description:
6+
A read-only description of Dell platform tokens
7+
available on the machine.
8+
9+
Each token attribute is available as a pair of
10+
sysfs attributes readable by a process with
11+
CAP_SYS_ADMIN.
12+
13+
For example the token ID "5" would be available
14+
as the following attributes:
15+
16+
0005_location
17+
0005_value
18+
19+
Tokens will vary from machine to machine, and
20+
only tokens available on that machine will be
21+
displayed.

MAINTAINERS

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3978,6 +3978,13 @@ M: "Maciej W. Rozycki" <[email protected]>
39783978
S: Maintained
39793979
F: drivers/net/fddi/defxx.*
39803980

3981+
DELL SMBIOS DRIVER
3982+
M: Pali Rohár <[email protected]>
3983+
M: Mario Limonciello <[email protected]>
3984+
3985+
S: Maintained
3986+
F: drivers/platform/x86/dell-smbios.*
3987+
39813988
DELL LAPTOP DRIVER
39823989
M: Matthew Garrett <[email protected]>
39833990
M: Pali Rohár <[email protected]>

drivers/platform/x86/dell-smbios.c

Lines changed: 212 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@
1616

1717
#include <linux/kernel.h>
1818
#include <linux/module.h>
19+
#include <linux/capability.h>
1920
#include <linux/dmi.h>
2021
#include <linux/err.h>
2122
#include <linux/gfp.h>
2223
#include <linux/mutex.h>
24+
#include <linux/platform_device.h>
2325
#include <linux/slab.h>
2426
#include <linux/io.h>
2527
#include "../../firmware/dcdbas.h"
@@ -39,7 +41,11 @@ static DEFINE_MUTEX(buffer_mutex);
3941
static int da_command_address;
4042
static int da_command_code;
4143
static int da_num_tokens;
44+
static struct platform_device *platform_device;
4245
static struct calling_interface_token *da_tokens;
46+
static struct device_attribute *token_location_attrs;
47+
static struct device_attribute *token_value_attrs;
48+
static struct attribute **token_attrs;
4349

4450
int dell_smbios_error(int value)
4551
{
@@ -157,6 +163,27 @@ static void __init parse_da_table(const struct dmi_header *dm)
157163
da_num_tokens += tokens;
158164
}
159165

166+
static void zero_duplicates(struct device *dev)
167+
{
168+
int i, j;
169+
170+
for (i = 0; i < da_num_tokens; i++) {
171+
if (da_tokens[i].tokenID == 0)
172+
continue;
173+
for (j = i+1; j < da_num_tokens; j++) {
174+
if (da_tokens[j].tokenID == 0)
175+
continue;
176+
if (da_tokens[i].tokenID == da_tokens[j].tokenID) {
177+
dev_dbg(dev, "Zeroing dup token ID %x(%x/%x)\n",
178+
da_tokens[j].tokenID,
179+
da_tokens[j].location,
180+
da_tokens[j].value);
181+
da_tokens[j].tokenID = 0;
182+
}
183+
}
184+
}
185+
}
186+
160187
static void __init find_tokens(const struct dmi_header *dm, void *dummy)
161188
{
162189
switch (dm->type) {
@@ -170,6 +197,154 @@ static void __init find_tokens(const struct dmi_header *dm, void *dummy)
170197
}
171198
}
172199

200+
static int match_attribute(struct device *dev,
201+
struct device_attribute *attr)
202+
{
203+
int i;
204+
205+
for (i = 0; i < da_num_tokens * 2; i++) {
206+
if (!token_attrs[i])
207+
continue;
208+
if (strcmp(token_attrs[i]->name, attr->attr.name) == 0)
209+
return i/2;
210+
}
211+
dev_dbg(dev, "couldn't match: %s\n", attr->attr.name);
212+
return -EINVAL;
213+
}
214+
215+
static ssize_t location_show(struct device *dev,
216+
struct device_attribute *attr, char *buf)
217+
{
218+
int i;
219+
220+
if (!capable(CAP_SYS_ADMIN))
221+
return -EPERM;
222+
223+
i = match_attribute(dev, attr);
224+
if (i > 0)
225+
return scnprintf(buf, PAGE_SIZE, "%08x", da_tokens[i].location);
226+
return 0;
227+
}
228+
229+
static ssize_t value_show(struct device *dev,
230+
struct device_attribute *attr, char *buf)
231+
{
232+
int i;
233+
234+
if (!capable(CAP_SYS_ADMIN))
235+
return -EPERM;
236+
237+
i = match_attribute(dev, attr);
238+
if (i > 0)
239+
return scnprintf(buf, PAGE_SIZE, "%08x", da_tokens[i].value);
240+
return 0;
241+
}
242+
243+
static struct attribute_group smbios_attribute_group = {
244+
.name = "tokens"
245+
};
246+
247+
static struct platform_driver platform_driver = {
248+
.driver = {
249+
.name = "dell-smbios",
250+
},
251+
};
252+
253+
static int build_tokens_sysfs(struct platform_device *dev)
254+
{
255+
char buffer_location[13];
256+
char buffer_value[10];
257+
char *location_name;
258+
char *value_name;
259+
size_t size;
260+
int ret;
261+
int i, j;
262+
263+
/* (number of tokens + 1 for null terminated */
264+
size = sizeof(struct device_attribute) * (da_num_tokens + 1);
265+
token_location_attrs = kzalloc(size, GFP_KERNEL);
266+
if (!token_location_attrs)
267+
return -ENOMEM;
268+
token_value_attrs = kzalloc(size, GFP_KERNEL);
269+
if (!token_value_attrs)
270+
goto out_allocate_value;
271+
272+
/* need to store both location and value + terminator*/
273+
size = sizeof(struct attribute *) * ((2 * da_num_tokens) + 1);
274+
token_attrs = kzalloc(size, GFP_KERNEL);
275+
if (!token_attrs)
276+
goto out_allocate_attrs;
277+
278+
for (i = 0, j = 0; i < da_num_tokens; i++) {
279+
/* skip empty */
280+
if (da_tokens[i].tokenID == 0)
281+
continue;
282+
/* add location */
283+
sprintf(buffer_location, "%04x_location",
284+
da_tokens[i].tokenID);
285+
location_name = kstrdup(buffer_location, GFP_KERNEL);
286+
if (location_name == NULL)
287+
goto out_unwind_strings;
288+
sysfs_attr_init(&token_location_attrs[i].attr);
289+
token_location_attrs[i].attr.name = location_name;
290+
token_location_attrs[i].attr.mode = 0444;
291+
token_location_attrs[i].show = location_show;
292+
token_attrs[j++] = &token_location_attrs[i].attr;
293+
294+
/* add value */
295+
sprintf(buffer_value, "%04x_value",
296+
da_tokens[i].tokenID);
297+
value_name = kstrdup(buffer_value, GFP_KERNEL);
298+
if (value_name == NULL)
299+
goto loop_fail_create_value;
300+
sysfs_attr_init(&token_value_attrs[i].attr);
301+
token_value_attrs[i].attr.name = value_name;
302+
token_value_attrs[i].attr.mode = 0444;
303+
token_value_attrs[i].show = value_show;
304+
token_attrs[j++] = &token_value_attrs[i].attr;
305+
continue;
306+
307+
loop_fail_create_value:
308+
kfree(value_name);
309+
goto out_unwind_strings;
310+
}
311+
smbios_attribute_group.attrs = token_attrs;
312+
313+
ret = sysfs_create_group(&dev->dev.kobj, &smbios_attribute_group);
314+
if (ret)
315+
goto out_unwind_strings;
316+
return 0;
317+
318+
out_unwind_strings:
319+
for (i = i-1; i > 0; i--) {
320+
kfree(token_location_attrs[i].attr.name);
321+
kfree(token_value_attrs[i].attr.name);
322+
}
323+
kfree(token_attrs);
324+
out_allocate_attrs:
325+
kfree(token_value_attrs);
326+
out_allocate_value:
327+
kfree(token_location_attrs);
328+
329+
return -ENOMEM;
330+
}
331+
332+
static void free_group(struct platform_device *pdev)
333+
{
334+
int i;
335+
336+
sysfs_remove_group(&pdev->dev.kobj,
337+
&smbios_attribute_group);
338+
for (i = 0; i < da_num_tokens; i++) {
339+
kfree(token_location_attrs[i].attr.name);
340+
kfree(token_value_attrs[i].attr.name);
341+
}
342+
kfree(token_attrs);
343+
kfree(token_value_attrs);
344+
kfree(token_location_attrs);
345+
}
346+
347+
173348
static int __init dell_smbios_init(void)
174349
{
175350
const struct dmi_device *valid;
@@ -197,18 +372,54 @@ static int __init dell_smbios_init(void)
197372
ret = -ENOMEM;
198373
goto fail_buffer;
199374
}
375+
ret = platform_driver_register(&platform_driver);
376+
if (ret)
377+
goto fail_platform_driver;
378+
379+
platform_device = platform_device_alloc("dell-smbios", 0);
380+
if (!platform_device) {
381+
ret = -ENOMEM;
382+
goto fail_platform_device_alloc;
383+
}
384+
ret = platform_device_add(platform_device);
385+
if (ret)
386+
goto fail_platform_device_add;
387+
388+
/* duplicate tokens will cause problems building sysfs files */
389+
zero_duplicates(&platform_device->dev);
390+
391+
ret = build_tokens_sysfs(platform_device);
392+
if (ret)
393+
goto fail_create_group;
200394

201395
return 0;
202396

397+
fail_create_group:
398+
platform_device_del(platform_device);
399+
400+
fail_platform_device_add:
401+
platform_device_put(platform_device);
402+
403+
fail_platform_device_alloc:
404+
platform_driver_unregister(&platform_driver);
405+
406+
fail_platform_driver:
407+
free_page((unsigned long)buffer);
408+
203409
fail_buffer:
204410
kfree(da_tokens);
205411
return ret;
206412
}
207413

208414
static void __exit dell_smbios_exit(void)
209415
{
210-
kfree(da_tokens);
416+
if (platform_device) {
417+
free_group(platform_device);
418+
platform_device_unregister(platform_device);
419+
platform_driver_unregister(&platform_driver);
420+
}
211421
free_page((unsigned long)buffer);
422+
kfree(da_tokens);
212423
}
213424

214425
subsys_initcall(dell_smbios_init);

0 commit comments

Comments
 (0)