Skip to content

Commit 5039e31

Browse files
daveyoungMatt Fleming
authored andcommitted
x86: Export x86 boot_params to sysfs
kexec-tools use boot_params for getting the 1st kernel hardware_subarch, the kexec kernel EFI runtime support also needs to read the old efi_info from boot_params. Currently it exists in debugfs which is not a good place for such infomation. Per HPA, we should avoid "sploit debugfs". In this patch /sys/kernel/boot_params are exported, also the setup_data is exported as a subdirectory. kexec-tools is using debugfs for hardware_subarch for a long time now so we're not removing it yet. Structure is like below: /sys/kernel/boot_params |__ data /* boot_params in binary*/ |__ setup_data | |__ 0 /* the first setup_data node */ | | |__ data /* setup_data node 0 in binary*/ | | |__ type /* setup_data type of setup_data node 0, hex string */ [snip] |__ version /* boot protocal version (in hex, "0x" prefixed)*/ Signed-off-by: Dave Young <[email protected]> Acked-by: Borislav Petkov <[email protected]> Tested-by: Toshi Kani <[email protected]> Signed-off-by: Matt Fleming <[email protected]>
1 parent 456a29d commit 5039e31

File tree

3 files changed

+378
-0
lines changed

3 files changed

+378
-0
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
What: /sys/kernel/boot_params
2+
Date: December 2013
3+
Contact: Dave Young <[email protected]>
4+
Description: The /sys/kernel/boot_params directory contains two
5+
files: "data" and "version" and one subdirectory "setup_data".
6+
It is used to export the kernel boot parameters of an x86
7+
platform to userspace for kexec and debugging purpose.
8+
9+
If there's no setup_data in boot_params the subdirectory will
10+
not be created.
11+
12+
"data" file is the binary representation of struct boot_params.
13+
14+
"version" file is the string representation of boot
15+
protocol version.
16+
17+
"setup_data" subdirectory contains the setup_data data
18+
structure in boot_params. setup_data is maintained in kernel
19+
as a link list. In "setup_data" subdirectory there's one
20+
subdirectory for each link list node named with the number
21+
of the list nodes. The list node subdirectory contains two
22+
files "type" and "data". "type" file is the string
23+
representation of setup_data type. "data" file is the binary
24+
representation of setup_data payload.
25+
26+
The whole boot_params directory structure is like below:
27+
/sys/kernel/boot_params
28+
|__ data
29+
|__ setup_data
30+
| |__ 0
31+
| | |__ data
32+
| | |__ type
33+
| |__ 1
34+
| |__ data
35+
| |__ type
36+
|__ version
37+
38+
Users: Kexec

arch/x86/kernel/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ obj-$(CONFIG_X86_64) += sys_x86_64.o x8664_ksyms_64.o
2929
obj-y += syscall_$(BITS).o
3030
obj-$(CONFIG_X86_64) += vsyscall_64.o
3131
obj-$(CONFIG_X86_64) += vsyscall_emu_64.o
32+
obj-$(CONFIG_SYSFS) += ksysfs.o
3233
obj-y += bootflag.o e820.o
3334
obj-y += pci-dma.o quirks.o topology.o kdebugfs.o
3435
obj-y += alternative.o i8253.o pci-nommu.o hw_breakpoint.o

arch/x86/kernel/ksysfs.c

Lines changed: 339 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,339 @@
1+
/*
2+
* Architecture specific sysfs attributes in /sys/kernel
3+
*
4+
* Copyright (C) 2007, Intel Corp.
5+
* Huang Ying <[email protected]>
6+
* Copyright (C) 2013, 2013 Red Hat, Inc.
7+
* Dave Young <[email protected]>
8+
*
9+
* This file is released under the GPLv2
10+
*/
11+
12+
#include <linux/kobject.h>
13+
#include <linux/string.h>
14+
#include <linux/sysfs.h>
15+
#include <linux/init.h>
16+
#include <linux/stat.h>
17+
#include <linux/slab.h>
18+
#include <linux/mm.h>
19+
20+
#include <asm/setup.h>
21+
22+
static ssize_t version_show(struct kobject *kobj,
23+
struct kobj_attribute *attr, char *buf)
24+
{
25+
return sprintf(buf, "0x%04x\n", boot_params.hdr.version);
26+
}
27+
28+
static struct kobj_attribute boot_params_version_attr = __ATTR_RO(version);
29+
30+
static ssize_t boot_params_data_read(struct file *fp, struct kobject *kobj,
31+
struct bin_attribute *bin_attr,
32+
char *buf, loff_t off, size_t count)
33+
{
34+
memcpy(buf, (void *)&boot_params + off, count);
35+
return count;
36+
}
37+
38+
static struct bin_attribute boot_params_data_attr = {
39+
.attr = {
40+
.name = "data",
41+
.mode = S_IRUGO,
42+
},
43+
.read = boot_params_data_read,
44+
.size = sizeof(boot_params),
45+
};
46+
47+
static struct attribute *boot_params_version_attrs[] = {
48+
&boot_params_version_attr.attr,
49+
NULL,
50+
};
51+
52+
static struct bin_attribute *boot_params_data_attrs[] = {
53+
&boot_params_data_attr,
54+
NULL,
55+
};
56+
57+
static struct attribute_group boot_params_attr_group = {
58+
.attrs = boot_params_version_attrs,
59+
.bin_attrs = boot_params_data_attrs,
60+
};
61+
62+
static int kobj_to_setup_data_nr(struct kobject *kobj, int *nr)
63+
{
64+
const char *name;
65+
66+
name = kobject_name(kobj);
67+
return kstrtoint(name, 10, nr);
68+
}
69+
70+
static int get_setup_data_paddr(int nr, u64 *paddr)
71+
{
72+
int i = 0;
73+
struct setup_data *data;
74+
u64 pa_data = boot_params.hdr.setup_data;
75+
76+
while (pa_data) {
77+
if (nr == i) {
78+
*paddr = pa_data;
79+
return 0;
80+
}
81+
data = ioremap_cache(pa_data, sizeof(*data));
82+
if (!data)
83+
return -ENOMEM;
84+
85+
pa_data = data->next;
86+
iounmap(data);
87+
i++;
88+
}
89+
return -EINVAL;
90+
}
91+
92+
static int __init get_setup_data_size(int nr, size_t *size)
93+
{
94+
int i = 0;
95+
struct setup_data *data;
96+
u64 pa_data = boot_params.hdr.setup_data;
97+
98+
while (pa_data) {
99+
data = ioremap_cache(pa_data, sizeof(*data));
100+
if (!data)
101+
return -ENOMEM;
102+
if (nr == i) {
103+
*size = data->len;
104+
iounmap(data);
105+
return 0;
106+
}
107+
108+
pa_data = data->next;
109+
iounmap(data);
110+
i++;
111+
}
112+
return -EINVAL;
113+
}
114+
115+
static ssize_t type_show(struct kobject *kobj,
116+
struct kobj_attribute *attr, char *buf)
117+
{
118+
int nr, ret;
119+
u64 paddr;
120+
struct setup_data *data;
121+
122+
ret = kobj_to_setup_data_nr(kobj, &nr);
123+
if (ret)
124+
return ret;
125+
126+
ret = get_setup_data_paddr(nr, &paddr);
127+
if (ret)
128+
return ret;
129+
data = ioremap_cache(paddr, sizeof(*data));
130+
if (!data)
131+
return -ENOMEM;
132+
133+
ret = sprintf(buf, "0x%x\n", data->type);
134+
iounmap(data);
135+
return ret;
136+
}
137+
138+
static ssize_t setup_data_data_read(struct file *fp,
139+
struct kobject *kobj,
140+
struct bin_attribute *bin_attr,
141+
char *buf,
142+
loff_t off, size_t count)
143+
{
144+
int nr, ret = 0;
145+
u64 paddr;
146+
struct setup_data *data;
147+
void *p;
148+
149+
ret = kobj_to_setup_data_nr(kobj, &nr);
150+
if (ret)
151+
return ret;
152+
153+
ret = get_setup_data_paddr(nr, &paddr);
154+
if (ret)
155+
return ret;
156+
data = ioremap_cache(paddr, sizeof(*data));
157+
if (!data)
158+
return -ENOMEM;
159+
160+
if (off > data->len) {
161+
ret = -EINVAL;
162+
goto out;
163+
}
164+
165+
if (count > data->len - off)
166+
count = data->len - off;
167+
168+
if (!count)
169+
goto out;
170+
171+
ret = count;
172+
p = ioremap_cache(paddr + sizeof(*data), data->len);
173+
if (!p) {
174+
ret = -ENOMEM;
175+
goto out;
176+
}
177+
memcpy(buf, p + off, count);
178+
iounmap(p);
179+
out:
180+
iounmap(data);
181+
return ret;
182+
}
183+
184+
static struct kobj_attribute type_attr = __ATTR_RO(type);
185+
186+
static struct bin_attribute data_attr = {
187+
.attr = {
188+
.name = "data",
189+
.mode = S_IRUGO,
190+
},
191+
.read = setup_data_data_read,
192+
};
193+
194+
static struct attribute *setup_data_type_attrs[] = {
195+
&type_attr.attr,
196+
NULL,
197+
};
198+
199+
static struct bin_attribute *setup_data_data_attrs[] = {
200+
&data_attr,
201+
NULL,
202+
};
203+
204+
static struct attribute_group setup_data_attr_group = {
205+
.attrs = setup_data_type_attrs,
206+
.bin_attrs = setup_data_data_attrs,
207+
};
208+
209+
static int __init create_setup_data_node(struct kobject *parent,
210+
struct kobject **kobjp, int nr)
211+
{
212+
int ret = 0;
213+
size_t size;
214+
struct kobject *kobj;
215+
char name[16]; /* should be enough for setup_data nodes numbers */
216+
snprintf(name, 16, "%d", nr);
217+
218+
kobj = kobject_create_and_add(name, parent);
219+
if (!kobj)
220+
return -ENOMEM;
221+
222+
ret = get_setup_data_size(nr, &size);
223+
if (ret)
224+
goto out_kobj;
225+
226+
data_attr.size = size;
227+
ret = sysfs_create_group(kobj, &setup_data_attr_group);
228+
if (ret)
229+
goto out_kobj;
230+
*kobjp = kobj;
231+
232+
return 0;
233+
out_kobj:
234+
kobject_put(kobj);
235+
return ret;
236+
}
237+
238+
static void __init cleanup_setup_data_node(struct kobject *kobj)
239+
{
240+
sysfs_remove_group(kobj, &setup_data_attr_group);
241+
kobject_put(kobj);
242+
}
243+
244+
static int __init get_setup_data_total_num(u64 pa_data, int *nr)
245+
{
246+
int ret = 0;
247+
struct setup_data *data;
248+
249+
*nr = 0;
250+
while (pa_data) {
251+
*nr += 1;
252+
data = ioremap_cache(pa_data, sizeof(*data));
253+
if (!data) {
254+
ret = -ENOMEM;
255+
goto out;
256+
}
257+
pa_data = data->next;
258+
iounmap(data);
259+
}
260+
261+
out:
262+
return ret;
263+
}
264+
265+
static int __init create_setup_data_nodes(struct kobject *parent)
266+
{
267+
struct kobject *setup_data_kobj, **kobjp;
268+
u64 pa_data;
269+
int i, j, nr, ret = 0;
270+
271+
pa_data = boot_params.hdr.setup_data;
272+
if (!pa_data)
273+
return 0;
274+
275+
setup_data_kobj = kobject_create_and_add("setup_data", parent);
276+
if (!setup_data_kobj) {
277+
ret = -ENOMEM;
278+
goto out;
279+
}
280+
281+
ret = get_setup_data_total_num(pa_data, &nr);
282+
if (ret)
283+
goto out_setup_data_kobj;
284+
285+
kobjp = kmalloc(sizeof(*kobjp) * nr, GFP_KERNEL);
286+
if (!kobjp) {
287+
ret = -ENOMEM;
288+
goto out_setup_data_kobj;
289+
}
290+
291+
for (i = 0; i < nr; i++) {
292+
ret = create_setup_data_node(setup_data_kobj, kobjp + i, i);
293+
if (ret)
294+
goto out_clean_nodes;
295+
}
296+
297+
kfree(kobjp);
298+
return 0;
299+
300+
out_clean_nodes:
301+
for (j = i - 1; j > 0; j--)
302+
cleanup_setup_data_node(*(kobjp + j));
303+
kfree(kobjp);
304+
out_setup_data_kobj:
305+
kobject_put(setup_data_kobj);
306+
out:
307+
return ret;
308+
}
309+
310+
static int __init boot_params_ksysfs_init(void)
311+
{
312+
int ret;
313+
struct kobject *boot_params_kobj;
314+
315+
boot_params_kobj = kobject_create_and_add("boot_params",
316+
kernel_kobj);
317+
if (!boot_params_kobj) {
318+
ret = -ENOMEM;
319+
goto out;
320+
}
321+
322+
ret = sysfs_create_group(boot_params_kobj, &boot_params_attr_group);
323+
if (ret)
324+
goto out_boot_params_kobj;
325+
326+
ret = create_setup_data_nodes(boot_params_kobj);
327+
if (ret)
328+
goto out_create_group;
329+
330+
return 0;
331+
out_create_group:
332+
sysfs_remove_group(boot_params_kobj, &boot_params_attr_group);
333+
out_boot_params_kobj:
334+
kobject_put(boot_params_kobj);
335+
out:
336+
return ret;
337+
}
338+
339+
arch_initcall(boot_params_ksysfs_init);

0 commit comments

Comments
 (0)