• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* sfi_core.c Simple Firmware Interface - core internals */
2 
3 /*
4 
5   This file is provided under a dual BSD/GPLv2 license.  When using or
6   redistributing this file, you may do so under either license.
7 
8   GPL LICENSE SUMMARY
9 
10   Copyright(c) 2009 Intel Corporation. All rights reserved.
11 
12   This program is free software; you can redistribute it and/or modify
13   it under the terms of version 2 of the GNU General Public License as
14   published by the Free Software Foundation.
15 
16   This program is distributed in the hope that it will be useful, but
17   WITHOUT ANY WARRANTY; without even the implied warranty of
18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19   General Public License for more details.
20 
21   You should have received a copy of the GNU General Public License
22   along with this program; if not, write to the Free Software
23   Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
24   The full GNU General Public License is included in this distribution
25   in the file called LICENSE.GPL.
26 
27   BSD LICENSE
28 
29   Copyright(c) 2009 Intel Corporation. All rights reserved.
30 
31   Redistribution and use in source and binary forms, with or without
32   modification, are permitted provided that the following conditions
33   are met:
34 
35     * Redistributions of source code must retain the above copyright
36       notice, this list of conditions and the following disclaimer.
37     * Redistributions in binary form must reproduce the above copyright
38       notice, this list of conditions and the following disclaimer in
39       the documentation and/or other materials provided with the
40       distribution.
41     * Neither the name of Intel Corporation nor the names of its
42       contributors may be used to endorse or promote products derived
43       from this software without specific prior written permission.
44 
45   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
46   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
47   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
48   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
49   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
50   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
51   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
52   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
53   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
54   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
55   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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  * FW creates and saves the SFI tables in memory. When these tables get
89  * used, they may need to be mapped to virtual address space, and the mapping
90  * can happen before or after the memremap() is ready, so a flag is needed
91  * to indicating this
92  */
93 static u32 sfi_use_memremap __read_mostly;
94 
95 /*
96  * sfi_un/map_memory calls early_memremap/memunmap which is a __init function
97  * and introduces section mismatch. So use __ref to make it calm.
98  */
sfi_map_memory(u64 phys,u32 size)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 
sfi_unmap_memory(void __iomem * virt,u32 size)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 
sfi_print_table_header(unsigned long long pa,struct sfi_table_header * header)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  * sfi_verify_table()
132  * Sanity check table lengh, calculate checksum
133  */
sfi_verify_table(struct sfi_table_header * table)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 	/* Sanity check table length against arbitrary 1MB limit */
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  * sfi_map_table()
160  *
161  * Return address of mapped table
162  * Check for common case that we can re-use mapping to SYST,
163  * which requires syst_pa, syst_va to be initialized.
164  */
sfi_map_table(u64 pa)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 	 /* If table fits on same page as its header, we are done */
176 	if (TABLE_ON_PAGE(th, th, th->len))
177 		return th;
178 
179 	/* Entire table does not fit on same page as SYST */
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  * sfi_unmap_table()
189  *
190  * Undoes effect of sfi_map_table() by unmapping table
191  * if it did not completely fit on same page as SYST.
192  */
sfi_unmap_table(struct sfi_table_header * th)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 
sfi_table_check_key(struct sfi_table_header * th,struct sfi_table_key * key)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  * This function will be used in 2 cases:
216  * 1. used to enumerate and verify the tables addressed by SYST/XSDT,
217  *    thus no signature will be given (in kernel boot phase)
218  * 2. used to parse one specific table, signature must exist, and
219  *    the mapped virt address will be returned, and the virt space
220  *    will be released by call sfi_put_table() later
221  *
222  * This two cases are from two different functions with two different
223  * sections and causes section mismatch warning. So use __ref to tell
224  * modpost not to make any noise.
225  *
226  * Return value:
227  *	NULL:			when can't find a table matching the key
228  *	ERR_PTR(error):		error value
229  *	virt table address:	when a matched table is found
230  */
231 struct sfi_table_header *
sfi_check_table(u64 pa,struct sfi_table_key * key)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;	/* Success */
248 	}
249 
250 	sfi_unmap_table(th);
251 	return ret;
252 }
253 
254 /*
255  * sfi_get_table()
256  *
257  * Search SYST for the specified table with the signature in
258  * the key, and return the mapped table
259  */
sfi_get_table(struct sfi_table_key * key)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 
sfi_put_table(struct sfi_table_header * th)275 void sfi_put_table(struct sfi_table_header *th)
276 {
277 	sfi_unmap_table(th);
278 }
279 
280 /* Find table with signature, run handler on it */
sfi_table_parse(char * signature,char * oem_id,char * oem_table_id,sfi_table_handler handler)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  * sfi_parse_syst()
308  * Checksum all the tables in SYST and print their headers
309  *
310  * success: set syst_va, return 0
311  */
sfi_parse_syst(void)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  * The OS finds the System Table by searching 16-byte boundaries between
334  * physical address 0x000E0000 and 0x000FFFFF. The OS shall search this region
335  * starting at the low address and shall stop searching when the 1st valid SFI
336  * System Table is found.
337  *
338  * success: set syst_pa, return 0
339  * fail: return -1
340  */
sfi_find_syst(void)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 		 * Enforce SFI spec mandate that SYST reside within a page.
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 		/* Success */
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 
sfi_table_show(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t offset,size_t count)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 
sfi_sysfs_install_table(u64 pa)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 
sfi_sysfs_init(void)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 
sfi_init(void)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 
sfi_init_late(void)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 	/* Use memremap now after it is ready */
512 	sfi_use_memremap = 1;
513 	syst_va = sfi_map_memory(syst_pa, length);
514 
515 	sfi_acpi_init();
516 }
517 
518 /*
519  * The reason we put it here because we need wait till the /sys/firmware
520  * is setup, then our interface can be registered in /sys/firmware/sfi
521  */
522 core_initcall(sfi_sysfs_init);
523