hc
2024-05-10 ee930fffee469d076998274a2ca55e13dc1efb67
kernel/arch/x86/kernel/ksysfs.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Architecture specific sysfs attributes in /sys/kernel
34 *
....@@ -5,8 +6,6 @@
56 * Huang Ying <ying.huang@intel.com>
67 * Copyright (C) 2013, 2013 Red Hat, Inc.
78 * Dave Young <dyoung@redhat.com>
8
- *
9
- * This file is released under the GPLv2
109 */
1110
1211 #include <linux/kobject.h>
....@@ -92,21 +91,41 @@
9291
9392 static int __init get_setup_data_size(int nr, size_t *size)
9493 {
95
- int i = 0;
94
+ u64 pa_data = boot_params.hdr.setup_data, pa_next;
95
+ struct setup_indirect *indirect;
9696 struct setup_data *data;
97
- u64 pa_data = boot_params.hdr.setup_data;
97
+ int i = 0;
98
+ u32 len;
9899
99100 while (pa_data) {
100101 data = memremap(pa_data, sizeof(*data), MEMREMAP_WB);
101102 if (!data)
102103 return -ENOMEM;
104
+ pa_next = data->next;
105
+
103106 if (nr == i) {
104
- *size = data->len;
107
+ if (data->type == SETUP_INDIRECT) {
108
+ len = sizeof(*data) + data->len;
109
+ memunmap(data);
110
+ data = memremap(pa_data, len, MEMREMAP_WB);
111
+ if (!data)
112
+ return -ENOMEM;
113
+
114
+ indirect = (struct setup_indirect *)data->data;
115
+
116
+ if (indirect->type != SETUP_INDIRECT)
117
+ *size = indirect->len;
118
+ else
119
+ *size = data->len;
120
+ } else {
121
+ *size = data->len;
122
+ }
123
+
105124 memunmap(data);
106125 return 0;
107126 }
108127
109
- pa_data = data->next;
128
+ pa_data = pa_next;
110129 memunmap(data);
111130 i++;
112131 }
....@@ -116,9 +135,11 @@
116135 static ssize_t type_show(struct kobject *kobj,
117136 struct kobj_attribute *attr, char *buf)
118137 {
138
+ struct setup_indirect *indirect;
139
+ struct setup_data *data;
119140 int nr, ret;
120141 u64 paddr;
121
- struct setup_data *data;
142
+ u32 len;
122143
123144 ret = kobj_to_setup_data_nr(kobj, &nr);
124145 if (ret)
....@@ -131,7 +152,20 @@
131152 if (!data)
132153 return -ENOMEM;
133154
134
- ret = sprintf(buf, "0x%x\n", data->type);
155
+ if (data->type == SETUP_INDIRECT) {
156
+ len = sizeof(*data) + data->len;
157
+ memunmap(data);
158
+ data = memremap(paddr, len, MEMREMAP_WB);
159
+ if (!data)
160
+ return -ENOMEM;
161
+
162
+ indirect = (struct setup_indirect *)data->data;
163
+
164
+ ret = sprintf(buf, "0x%x\n", indirect->type);
165
+ } else {
166
+ ret = sprintf(buf, "0x%x\n", data->type);
167
+ }
168
+
135169 memunmap(data);
136170 return ret;
137171 }
....@@ -142,9 +176,10 @@
142176 char *buf,
143177 loff_t off, size_t count)
144178 {
145
- int nr, ret = 0;
146
- u64 paddr;
179
+ struct setup_indirect *indirect;
147180 struct setup_data *data;
181
+ int nr, ret = 0;
182
+ u64 paddr, len;
148183 void *p;
149184
150185 ret = kobj_to_setup_data_nr(kobj, &nr);
....@@ -158,19 +193,45 @@
158193 if (!data)
159194 return -ENOMEM;
160195
161
- if (off > data->len) {
196
+ if (data->type == SETUP_INDIRECT) {
197
+ len = sizeof(*data) + data->len;
198
+ memunmap(data);
199
+ data = memremap(paddr, len, MEMREMAP_WB);
200
+ if (!data)
201
+ return -ENOMEM;
202
+
203
+ indirect = (struct setup_indirect *)data->data;
204
+
205
+ if (indirect->type != SETUP_INDIRECT) {
206
+ paddr = indirect->addr;
207
+ len = indirect->len;
208
+ } else {
209
+ /*
210
+ * Even though this is technically undefined, return
211
+ * the data as though it is a normal setup_data struct.
212
+ * This will at least allow it to be inspected.
213
+ */
214
+ paddr += sizeof(*data);
215
+ len = data->len;
216
+ }
217
+ } else {
218
+ paddr += sizeof(*data);
219
+ len = data->len;
220
+ }
221
+
222
+ if (off > len) {
162223 ret = -EINVAL;
163224 goto out;
164225 }
165226
166
- if (count > data->len - off)
167
- count = data->len - off;
227
+ if (count > len - off)
228
+ count = len - off;
168229
169230 if (!count)
170231 goto out;
171232
172233 ret = count;
173
- p = memremap(paddr + sizeof(*data), data->len, MEMREMAP_WB);
234
+ p = memremap(paddr, len, MEMREMAP_WB);
174235 if (!p) {
175236 ret = -ENOMEM;
176237 goto out;