This source file includes following definitions.
- sfi_map_memory
- sfi_unmap_memory
- sfi_print_table_header
- sfi_verify_table
- sfi_map_table
- sfi_unmap_table
- sfi_table_check_key
- sfi_check_table
- sfi_get_table
- sfi_put_table
- sfi_table_parse
- sfi_parse_syst
- sfi_find_syst
- sfi_table_show
- sfi_sysfs_install_table
- sfi_sysfs_init
- sfi_init
- sfi_init_late
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59 #define KMSG_COMPONENT "SFI"
60 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
61
62 #include <linux/memblock.h>
63 #include <linux/kernel.h>
64 #include <linux/module.h>
65 #include <linux/errno.h>
66 #include <linux/types.h>
67 #include <linux/acpi.h>
68 #include <linux/init.h>
69 #include <linux/sfi.h>
70 #include <linux/slab.h>
71 #include <linux/io.h>
72
73 #include "sfi_core.h"
74
75 #define ON_SAME_PAGE(addr1, addr2) \
76 (((unsigned long)(addr1) & PAGE_MASK) == \
77 ((unsigned long)(addr2) & PAGE_MASK))
78 #define TABLE_ON_PAGE(page, table, size) (ON_SAME_PAGE(page, table) && \
79 ON_SAME_PAGE(page, table + size))
80
81 int sfi_disabled __read_mostly;
82 EXPORT_SYMBOL(sfi_disabled);
83
84 static u64 syst_pa __read_mostly;
85 static struct sfi_table_simple *syst_va __read_mostly;
86
87
88
89
90
91
92
93 static u32 sfi_use_memremap __read_mostly;
94
95
96
97
98
99 static void __iomem * __ref sfi_map_memory(u64 phys, u32 size)
100 {
101 if (!phys || !size)
102 return NULL;
103
104 if (sfi_use_memremap)
105 return memremap(phys, size, MEMREMAP_WB);
106 else
107 return early_memremap(phys, size);
108 }
109
110 static void __ref sfi_unmap_memory(void __iomem *virt, u32 size)
111 {
112 if (!virt || !size)
113 return;
114
115 if (sfi_use_memremap)
116 memunmap(virt);
117 else
118 early_memunmap(virt, size);
119 }
120
121 static void sfi_print_table_header(unsigned long long pa,
122 struct sfi_table_header *header)
123 {
124 pr_info("%4.4s %llX, %04X (v%d %6.6s %8.8s)\n",
125 header->sig, pa,
126 header->len, header->rev, header->oem_id,
127 header->oem_table_id);
128 }
129
130
131
132
133
134 static int sfi_verify_table(struct sfi_table_header *table)
135 {
136
137 u8 checksum = 0;
138 u8 *puchar = (u8 *)table;
139 u32 length = table->len;
140
141
142 if (length > 0x100000) {
143 pr_err("Invalid table length 0x%x\n", length);
144 return -1;
145 }
146
147 while (length--)
148 checksum += *puchar++;
149
150 if (checksum) {
151 pr_err("Checksum %2.2X should be %2.2X\n",
152 table->csum, table->csum - checksum);
153 return -1;
154 }
155 return 0;
156 }
157
158
159
160
161
162
163
164
165 static struct sfi_table_header *sfi_map_table(u64 pa)
166 {
167 struct sfi_table_header *th;
168 u32 length;
169
170 if (!TABLE_ON_PAGE(syst_pa, pa, sizeof(struct sfi_table_header)))
171 th = sfi_map_memory(pa, sizeof(struct sfi_table_header));
172 else
173 th = (void *)syst_va + (pa - syst_pa);
174
175
176 if (TABLE_ON_PAGE(th, th, th->len))
177 return th;
178
179
180 length = th->len;
181 if (!TABLE_ON_PAGE(syst_pa, pa, sizeof(struct sfi_table_header)))
182 sfi_unmap_memory(th, sizeof(struct sfi_table_header));
183
184 return sfi_map_memory(pa, length);
185 }
186
187
188
189
190
191
192
193 static void sfi_unmap_table(struct sfi_table_header *th)
194 {
195 if (!TABLE_ON_PAGE(syst_va, th, th->len))
196 sfi_unmap_memory(th, TABLE_ON_PAGE(th, th, th->len) ?
197 sizeof(*th) : th->len);
198 }
199
200 static int sfi_table_check_key(struct sfi_table_header *th,
201 struct sfi_table_key *key)
202 {
203
204 if (strncmp(th->sig, key->sig, SFI_SIGNATURE_SIZE)
205 || (key->oem_id && strncmp(th->oem_id,
206 key->oem_id, SFI_OEM_ID_SIZE))
207 || (key->oem_table_id && strncmp(th->oem_table_id,
208 key->oem_table_id, SFI_OEM_TABLE_ID_SIZE)))
209 return -1;
210
211 return 0;
212 }
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231 struct sfi_table_header *
232 __ref sfi_check_table(u64 pa, struct sfi_table_key *key)
233 {
234 struct sfi_table_header *th;
235 void *ret = NULL;
236
237 th = sfi_map_table(pa);
238 if (!th)
239 return ERR_PTR(-ENOMEM);
240
241 if (!key->sig) {
242 sfi_print_table_header(pa, th);
243 if (sfi_verify_table(th))
244 ret = ERR_PTR(-EINVAL);
245 } else {
246 if (!sfi_table_check_key(th, key))
247 return th;
248 }
249
250 sfi_unmap_table(th);
251 return ret;
252 }
253
254
255
256
257
258
259
260 struct sfi_table_header *sfi_get_table(struct sfi_table_key *key)
261 {
262 struct sfi_table_header *th;
263 u32 tbl_cnt, i;
264
265 tbl_cnt = SFI_GET_NUM_ENTRIES(syst_va, u64);
266 for (i = 0; i < tbl_cnt; i++) {
267 th = sfi_check_table(syst_va->pentry[i], key);
268 if (!IS_ERR(th) && th)
269 return th;
270 }
271
272 return NULL;
273 }
274
275 void sfi_put_table(struct sfi_table_header *th)
276 {
277 sfi_unmap_table(th);
278 }
279
280
281 int sfi_table_parse(char *signature, char *oem_id, char *oem_table_id,
282 sfi_table_handler handler)
283 {
284 struct sfi_table_header *table = NULL;
285 struct sfi_table_key key;
286 int ret = -EINVAL;
287
288 if (sfi_disabled || !handler || !signature)
289 goto exit;
290
291 key.sig = signature;
292 key.oem_id = oem_id;
293 key.oem_table_id = oem_table_id;
294
295 table = sfi_get_table(&key);
296 if (!table)
297 goto exit;
298
299 ret = handler(table);
300 sfi_put_table(table);
301 exit:
302 return ret;
303 }
304 EXPORT_SYMBOL_GPL(sfi_table_parse);
305
306
307
308
309
310
311
312 static int __init sfi_parse_syst(void)
313 {
314 struct sfi_table_key key = SFI_ANY_KEY;
315 int tbl_cnt, i;
316 void *ret;
317
318 syst_va = sfi_map_memory(syst_pa, sizeof(struct sfi_table_simple));
319 if (!syst_va)
320 return -ENOMEM;
321
322 tbl_cnt = SFI_GET_NUM_ENTRIES(syst_va, u64);
323 for (i = 0; i < tbl_cnt; i++) {
324 ret = sfi_check_table(syst_va->pentry[i], &key);
325 if (IS_ERR(ret))
326 return PTR_ERR(ret);
327 }
328
329 return 0;
330 }
331
332
333
334
335
336
337
338
339
340
341 static __init int sfi_find_syst(void)
342 {
343 unsigned long offset, len;
344 void *start;
345
346 len = SFI_SYST_SEARCH_END - SFI_SYST_SEARCH_BEGIN;
347 start = sfi_map_memory(SFI_SYST_SEARCH_BEGIN, len);
348 if (!start)
349 return -1;
350
351 for (offset = 0; offset < len; offset += 16) {
352 struct sfi_table_header *syst_hdr;
353
354 syst_hdr = start + offset;
355 if (strncmp(syst_hdr->sig, SFI_SIG_SYST,
356 SFI_SIGNATURE_SIZE))
357 continue;
358
359 if (syst_hdr->len > PAGE_SIZE)
360 continue;
361
362 sfi_print_table_header(SFI_SYST_SEARCH_BEGIN + offset,
363 syst_hdr);
364
365 if (sfi_verify_table(syst_hdr))
366 continue;
367
368
369
370
371 if (!ON_SAME_PAGE(syst_pa, syst_pa + syst_hdr->len)) {
372 pr_info("SYST 0x%llx + 0x%x crosses page\n",
373 syst_pa, syst_hdr->len);
374 continue;
375 }
376
377
378 syst_pa = SFI_SYST_SEARCH_BEGIN + offset;
379 sfi_unmap_memory(start, len);
380 return 0;
381 }
382
383 sfi_unmap_memory(start, len);
384 return -1;
385 }
386
387 static struct kobject *sfi_kobj;
388 static struct kobject *tables_kobj;
389
390 static ssize_t sfi_table_show(struct file *filp, struct kobject *kobj,
391 struct bin_attribute *bin_attr, char *buf,
392 loff_t offset, size_t count)
393 {
394 struct sfi_table_attr *tbl_attr =
395 container_of(bin_attr, struct sfi_table_attr, attr);
396 struct sfi_table_header *th = NULL;
397 struct sfi_table_key key;
398 ssize_t cnt;
399
400 key.sig = tbl_attr->name;
401 key.oem_id = NULL;
402 key.oem_table_id = NULL;
403
404 if (strncmp(SFI_SIG_SYST, tbl_attr->name, SFI_SIGNATURE_SIZE)) {
405 th = sfi_get_table(&key);
406 if (!th)
407 return 0;
408
409 cnt = memory_read_from_buffer(buf, count, &offset,
410 th, th->len);
411 sfi_put_table(th);
412 } else
413 cnt = memory_read_from_buffer(buf, count, &offset,
414 syst_va, syst_va->header.len);
415
416 return cnt;
417 }
418
419 struct sfi_table_attr __init *sfi_sysfs_install_table(u64 pa)
420 {
421 struct sfi_table_attr *tbl_attr;
422 struct sfi_table_header *th;
423 int ret;
424
425 tbl_attr = kzalloc(sizeof(struct sfi_table_attr), GFP_KERNEL);
426 if (!tbl_attr)
427 return NULL;
428
429 th = sfi_map_table(pa);
430 if (!th || !th->sig[0]) {
431 kfree(tbl_attr);
432 return NULL;
433 }
434
435 sysfs_attr_init(&tbl_attr->attr.attr);
436 memcpy(tbl_attr->name, th->sig, SFI_SIGNATURE_SIZE);
437
438 tbl_attr->attr.size = 0;
439 tbl_attr->attr.read = sfi_table_show;
440 tbl_attr->attr.attr.name = tbl_attr->name;
441 tbl_attr->attr.attr.mode = 0400;
442
443 ret = sysfs_create_bin_file(tables_kobj,
444 &tbl_attr->attr);
445 if (ret) {
446 kfree(tbl_attr);
447 tbl_attr = NULL;
448 }
449
450 sfi_unmap_table(th);
451 return tbl_attr;
452 }
453
454 static int __init sfi_sysfs_init(void)
455 {
456 int tbl_cnt, i;
457
458 if (sfi_disabled)
459 return 0;
460
461 sfi_kobj = kobject_create_and_add("sfi", firmware_kobj);
462 if (!sfi_kobj)
463 return 0;
464
465 tables_kobj = kobject_create_and_add("tables", sfi_kobj);
466 if (!tables_kobj) {
467 kobject_put(sfi_kobj);
468 return 0;
469 }
470
471 sfi_sysfs_install_table(syst_pa);
472
473 tbl_cnt = SFI_GET_NUM_ENTRIES(syst_va, u64);
474
475 for (i = 0; i < tbl_cnt; i++)
476 sfi_sysfs_install_table(syst_va->pentry[i]);
477
478 sfi_acpi_sysfs_init();
479 kobject_uevent(sfi_kobj, KOBJ_ADD);
480 kobject_uevent(tables_kobj, KOBJ_ADD);
481 pr_info("SFI sysfs interfaces init success\n");
482 return 0;
483 }
484
485 void __init sfi_init(void)
486 {
487 if (!acpi_disabled)
488 disable_sfi();
489
490 if (sfi_disabled)
491 return;
492
493 pr_info("Simple Firmware Interface v0.81 http://simplefirmware.org\n");
494
495 if (sfi_find_syst() || sfi_parse_syst() || sfi_platform_init())
496 disable_sfi();
497
498 return;
499 }
500
501 void __init sfi_init_late(void)
502 {
503 int length;
504
505 if (sfi_disabled)
506 return;
507
508 length = syst_va->header.len;
509 sfi_unmap_memory(syst_va, sizeof(struct sfi_table_simple));
510
511
512 sfi_use_memremap = 1;
513 syst_va = sfi_map_memory(syst_pa, length);
514
515 sfi_acpi_init();
516 }
517
518
519
520
521
522 core_initcall(sfi_sysfs_init);