Commit | Line | Data |
---|---|---|
55716d26 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
6d7d7433 HY |
2 | /* |
3 | * Architecture specific debugfs files | |
4 | * | |
5 | * Copyright (C) 2007, Intel Corp. | |
6 | * Huang Ying <ying.huang@intel.com> | |
6d7d7433 | 7 | */ |
6d7d7433 | 8 | #include <linux/debugfs.h> |
c14b2adf | 9 | #include <linux/uaccess.h> |
186f4360 | 10 | #include <linux/export.h> |
5a0e3ad6 | 11 | #include <linux/slab.h> |
6d7d7433 | 12 | #include <linux/init.h> |
390cd85c | 13 | #include <linux/stat.h> |
c14b2adf HY |
14 | #include <linux/io.h> |
15 | #include <linux/mm.h> | |
6d7d7433 HY |
16 | |
17 | #include <asm/setup.h> | |
18 | ||
ae79cdaa | 19 | struct dentry *arch_debugfs_dir; |
20 | EXPORT_SYMBOL(arch_debugfs_dir); | |
21 | ||
6d7d7433 | 22 | #ifdef CONFIG_DEBUG_BOOT_PARAMS |
c14b2adf HY |
23 | struct setup_data_node { |
24 | u64 paddr; | |
25 | u32 type; | |
26 | u32 len; | |
27 | }; | |
28 | ||
390cd85c JSR |
29 | static ssize_t setup_data_read(struct file *file, char __user *user_buf, |
30 | size_t count, loff_t *ppos) | |
c14b2adf HY |
31 | { |
32 | struct setup_data_node *node = file->private_data; | |
33 | unsigned long remain; | |
34 | loff_t pos = *ppos; | |
c14b2adf HY |
35 | void *p; |
36 | u64 pa; | |
37 | ||
38 | if (pos < 0) | |
39 | return -EINVAL; | |
390cd85c | 40 | |
c14b2adf HY |
41 | if (pos >= node->len) |
42 | return 0; | |
43 | ||
44 | if (count > node->len - pos) | |
45 | count = node->len - pos; | |
390cd85c | 46 | |
b3c72fc9 DK |
47 | pa = node->paddr + pos; |
48 | ||
49 | /* Is it direct data or invalid indirect one? */ | |
50 | if (!(node->type & SETUP_INDIRECT) || node->type == SETUP_INDIRECT) | |
51 | pa += sizeof(struct setup_data); | |
52 | ||
f7750a79 TL |
53 | p = memremap(pa, count, MEMREMAP_WB); |
54 | if (!p) | |
55 | return -ENOMEM; | |
c14b2adf HY |
56 | |
57 | remain = copy_to_user(user_buf, p, count); | |
58 | ||
f7750a79 | 59 | memunmap(p); |
c14b2adf HY |
60 | |
61 | if (remain) | |
62 | return -EFAULT; | |
63 | ||
64 | *ppos = pos + count; | |
65 | ||
66 | return count; | |
67 | } | |
68 | ||
c14b2adf | 69 | static const struct file_operations fops_setup_data = { |
390cd85c | 70 | .read = setup_data_read, |
234e3405 | 71 | .open = simple_open, |
6038f373 | 72 | .llseek = default_llseek, |
c14b2adf HY |
73 | }; |
74 | ||
0fc811e5 | 75 | static void __init |
c14b2adf HY |
76 | create_setup_data_node(struct dentry *parent, int no, |
77 | struct setup_data_node *node) | |
78 | { | |
0fc811e5 | 79 | struct dentry *d; |
c14b2adf | 80 | char buf[16]; |
c14b2adf HY |
81 | |
82 | sprintf(buf, "%d", no); | |
83 | d = debugfs_create_dir(buf, parent); | |
390cd85c | 84 | |
0fc811e5 GKH |
85 | debugfs_create_x32("type", S_IRUGO, d, &node->type); |
86 | debugfs_create_file("data", S_IRUGO, d, node, &fops_setup_data); | |
c14b2adf HY |
87 | } |
88 | ||
89 | static int __init create_setup_data_nodes(struct dentry *parent) | |
90 | { | |
91 | struct setup_data_node *node; | |
92 | struct setup_data *data; | |
41fb433b | 93 | int error; |
c14b2adf | 94 | struct dentry *d; |
c14b2adf | 95 | u64 pa_data; |
390cd85c | 96 | int no = 0; |
c14b2adf HY |
97 | |
98 | d = debugfs_create_dir("setup_data", parent); | |
c14b2adf HY |
99 | |
100 | pa_data = boot_params.hdr.setup_data; | |
101 | ||
102 | while (pa_data) { | |
103 | node = kmalloc(sizeof(*node), GFP_KERNEL); | |
41fb433b JL |
104 | if (!node) { |
105 | error = -ENOMEM; | |
c14b2adf | 106 | goto err_dir; |
41fb433b | 107 | } |
390cd85c | 108 | |
f7750a79 TL |
109 | data = memremap(pa_data, sizeof(*data), MEMREMAP_WB); |
110 | if (!data) { | |
111 | kfree(node); | |
112 | error = -ENOMEM; | |
113 | goto err_dir; | |
114 | } | |
c14b2adf | 115 | |
b3c72fc9 DK |
116 | if (data->type == SETUP_INDIRECT && |
117 | ((struct setup_indirect *)data->data)->type != SETUP_INDIRECT) { | |
118 | node->paddr = ((struct setup_indirect *)data->data)->addr; | |
119 | node->type = ((struct setup_indirect *)data->data)->type; | |
120 | node->len = ((struct setup_indirect *)data->data)->len; | |
121 | } else { | |
122 | node->paddr = pa_data; | |
123 | node->type = data->type; | |
124 | node->len = data->len; | |
125 | } | |
126 | ||
0fc811e5 | 127 | create_setup_data_node(d, no, node); |
c14b2adf HY |
128 | pa_data = data->next; |
129 | ||
f7750a79 | 130 | memunmap(data); |
c14b2adf HY |
131 | no++; |
132 | } | |
390cd85c | 133 | |
c14b2adf HY |
134 | return 0; |
135 | ||
136 | err_dir: | |
0fc811e5 | 137 | debugfs_remove_recursive(d); |
c14b2adf HY |
138 | return error; |
139 | } | |
140 | ||
6d7d7433 | 141 | static struct debugfs_blob_wrapper boot_params_blob = { |
c14b2adf HY |
142 | .data = &boot_params, |
143 | .size = sizeof(boot_params), | |
6d7d7433 HY |
144 | }; |
145 | ||
146 | static int __init boot_params_kdebugfs_init(void) | |
147 | { | |
0fc811e5 GKH |
148 | struct dentry *dbp; |
149 | int error; | |
6d7d7433 | 150 | |
10bce841 | 151 | dbp = debugfs_create_dir("boot_params", arch_debugfs_dir); |
390cd85c | 152 | |
0fc811e5 GKH |
153 | debugfs_create_x16("version", S_IRUGO, dbp, &boot_params.hdr.version); |
154 | debugfs_create_blob("data", S_IRUGO, dbp, &boot_params_blob); | |
390cd85c | 155 | |
c14b2adf HY |
156 | error = create_setup_data_nodes(dbp); |
157 | if (error) | |
0fc811e5 | 158 | debugfs_remove_recursive(dbp); |
390cd85c | 159 | |
6d7d7433 HY |
160 | return error; |
161 | } | |
390cd85c | 162 | #endif /* CONFIG_DEBUG_BOOT_PARAMS */ |
6d7d7433 HY |
163 | |
164 | static int __init arch_kdebugfs_init(void) | |
165 | { | |
166 | int error = 0; | |
167 | ||
ae79cdaa | 168 | arch_debugfs_dir = debugfs_create_dir("x86", NULL); |
ae79cdaa | 169 | |
6d7d7433 HY |
170 | #ifdef CONFIG_DEBUG_BOOT_PARAMS |
171 | error = boot_params_kdebugfs_init(); | |
172 | #endif | |
173 | ||
174 | return error; | |
175 | } | |
6d7d7433 | 176 | arch_initcall(arch_kdebugfs_init); |