xref: /openbmc/linux/arch/x86/kernel/kdebugfs.c (revision 22246614)
1 /*
2  * Architecture specific debugfs files
3  *
4  * Copyright (C) 2007, Intel Corp.
5  *	Huang Ying <ying.huang@intel.com>
6  *
7  * This file is released under the GPLv2.
8  */
9 #include <linux/debugfs.h>
10 #include <linux/uaccess.h>
11 #include <linux/stat.h>
12 #include <linux/init.h>
13 #include <linux/io.h>
14 #include <linux/mm.h>
15 
16 #include <asm/setup.h>
17 
18 #ifdef CONFIG_DEBUG_BOOT_PARAMS
19 struct setup_data_node {
20 	u64 paddr;
21 	u32 type;
22 	u32 len;
23 };
24 
25 static ssize_t
26 setup_data_read(struct file *file, char __user *user_buf, size_t count,
27 		loff_t *ppos)
28 {
29 	struct setup_data_node *node = file->private_data;
30 	unsigned long remain;
31 	loff_t pos = *ppos;
32 	struct page *pg;
33 	void *p;
34 	u64 pa;
35 
36 	if (pos < 0)
37 		return -EINVAL;
38 	if (pos >= node->len)
39 		return 0;
40 
41 	if (count > node->len - pos)
42 		count = node->len - pos;
43 	pa = node->paddr + sizeof(struct setup_data) + pos;
44 	pg = pfn_to_page((pa + count - 1) >> PAGE_SHIFT);
45 	if (PageHighMem(pg)) {
46 		p = ioremap_cache(pa, count);
47 		if (!p)
48 			return -ENXIO;
49 	} else {
50 		p = __va(pa);
51 	}
52 
53 	remain = copy_to_user(user_buf, p, count);
54 
55 	if (PageHighMem(pg))
56 		iounmap(p);
57 
58 	if (remain)
59 		return -EFAULT;
60 
61 	*ppos = pos + count;
62 
63 	return count;
64 }
65 
66 static int setup_data_open(struct inode *inode, struct file *file)
67 {
68 	file->private_data = inode->i_private;
69 	return 0;
70 }
71 
72 static const struct file_operations fops_setup_data = {
73 	.read =		setup_data_read,
74 	.open =		setup_data_open,
75 };
76 
77 static int __init
78 create_setup_data_node(struct dentry *parent, int no,
79 		       struct setup_data_node *node)
80 {
81 	struct dentry *d, *type, *data;
82 	char buf[16];
83 	int error;
84 
85 	sprintf(buf, "%d", no);
86 	d = debugfs_create_dir(buf, parent);
87 	if (!d) {
88 		error = -ENOMEM;
89 		goto err_return;
90 	}
91 	type = debugfs_create_x32("type", S_IRUGO, d, &node->type);
92 	if (!type) {
93 		error = -ENOMEM;
94 		goto err_dir;
95 	}
96 	data = debugfs_create_file("data", S_IRUGO, d, node, &fops_setup_data);
97 	if (!data) {
98 		error = -ENOMEM;
99 		goto err_type;
100 	}
101 	return 0;
102 
103 err_type:
104 	debugfs_remove(type);
105 err_dir:
106 	debugfs_remove(d);
107 err_return:
108 	return error;
109 }
110 
111 static int __init create_setup_data_nodes(struct dentry *parent)
112 {
113 	struct setup_data_node *node;
114 	struct setup_data *data;
115 	int error, no = 0;
116 	struct dentry *d;
117 	struct page *pg;
118 	u64 pa_data;
119 
120 	d = debugfs_create_dir("setup_data", parent);
121 	if (!d) {
122 		error = -ENOMEM;
123 		goto err_return;
124 	}
125 
126 	pa_data = boot_params.hdr.setup_data;
127 
128 	while (pa_data) {
129 		node = kmalloc(sizeof(*node), GFP_KERNEL);
130 		if (!node) {
131 			error = -ENOMEM;
132 			goto err_dir;
133 		}
134 		pg = pfn_to_page((pa_data+sizeof(*data)-1) >> PAGE_SHIFT);
135 		if (PageHighMem(pg)) {
136 			data = ioremap_cache(pa_data, sizeof(*data));
137 			if (!data) {
138 				error = -ENXIO;
139 				goto err_dir;
140 			}
141 		} else {
142 			data = __va(pa_data);
143 		}
144 
145 		node->paddr = pa_data;
146 		node->type = data->type;
147 		node->len = data->len;
148 		error = create_setup_data_node(d, no, node);
149 		pa_data = data->next;
150 
151 		if (PageHighMem(pg))
152 			iounmap(data);
153 		if (error)
154 			goto err_dir;
155 		no++;
156 	}
157 	return 0;
158 
159 err_dir:
160 	debugfs_remove(d);
161 err_return:
162 	return error;
163 }
164 
165 static struct debugfs_blob_wrapper boot_params_blob = {
166 	.data		= &boot_params,
167 	.size		= sizeof(boot_params),
168 };
169 
170 static int __init boot_params_kdebugfs_init(void)
171 {
172 	struct dentry *dbp, *version, *data;
173 	int error;
174 
175 	dbp = debugfs_create_dir("boot_params", NULL);
176 	if (!dbp) {
177 		error = -ENOMEM;
178 		goto err_return;
179 	}
180 	version = debugfs_create_x16("version", S_IRUGO, dbp,
181 				     &boot_params.hdr.version);
182 	if (!version) {
183 		error = -ENOMEM;
184 		goto err_dir;
185 	}
186 	data = debugfs_create_blob("data", S_IRUGO, dbp,
187 				   &boot_params_blob);
188 	if (!data) {
189 		error = -ENOMEM;
190 		goto err_version;
191 	}
192 	error = create_setup_data_nodes(dbp);
193 	if (error)
194 		goto err_data;
195 	return 0;
196 
197 err_data:
198 	debugfs_remove(data);
199 err_version:
200 	debugfs_remove(version);
201 err_dir:
202 	debugfs_remove(dbp);
203 err_return:
204 	return error;
205 }
206 #endif
207 
208 static int __init arch_kdebugfs_init(void)
209 {
210 	int error = 0;
211 
212 #ifdef CONFIG_DEBUG_BOOT_PARAMS
213 	error = boot_params_kdebugfs_init();
214 #endif
215 
216 	return error;
217 }
218 arch_initcall(arch_kdebugfs_init);
219