Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
sfi_core.c
Go to the documentation of this file.
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/bootmem.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 
72 #include "sfi_core.h"
73 
74 #define ON_SAME_PAGE(addr1, addr2) \
75  (((unsigned long)(addr1) & PAGE_MASK) == \
76  ((unsigned long)(addr2) & PAGE_MASK))
77 #define TABLE_ON_PAGE(page, table, size) (ON_SAME_PAGE(page, table) && \
78  ON_SAME_PAGE(page, table + size))
79 
82 
83 static u64 syst_pa __read_mostly;
84 static struct sfi_table_simple *syst_va __read_mostly;
85 
86 /*
87  * FW creates and saves the SFI tables in memory. When these tables get
88  * used, they may need to be mapped to virtual address space, and the mapping
89  * can happen before or after the ioremap() is ready, so a flag is needed
90  * to indicating this
91  */
92 static u32 sfi_use_ioremap __read_mostly;
93 
94 /*
95  * sfi_un/map_memory calls early_ioremap/iounmap which is a __init function
96  * and introduces section mismatch. So use __ref to make it calm.
97  */
98 static void __iomem * __ref sfi_map_memory(u64 phys, u32 size)
99 {
100  if (!phys || !size)
101  return NULL;
102 
103  if (sfi_use_ioremap)
104  return ioremap_cache(phys, size);
105  else
106  return early_ioremap(phys, size);
107 }
108 
109 static void __ref sfi_unmap_memory(void __iomem *virt, u32 size)
110 {
111  if (!virt || !size)
112  return;
113 
114  if (sfi_use_ioremap)
115  iounmap(virt);
116  else
117  early_iounmap(virt, size);
118 }
119 
120 static void sfi_print_table_header(unsigned long long pa,
121  struct sfi_table_header *header)
122 {
123  pr_info("%4.4s %llX, %04X (v%d %6.6s %8.8s)\n",
124  header->sig, pa,
125  header->len, header->rev, header->oem_id,
126  header->oem_table_id);
127 }
128 
129 /*
130  * sfi_verify_table()
131  * Sanity check table lengh, calculate checksum
132  */
133 static int sfi_verify_table(struct sfi_table_header *table)
134 {
135 
136  u8 checksum = 0;
137  u8 *puchar = (u8 *)table;
138  u32 length = table->len;
139 
140  /* Sanity check table length against arbitrary 1MB limit */
141  if (length > 0x100000) {
142  pr_err("Invalid table length 0x%x\n", length);
143  return -1;
144  }
145 
146  while (length--)
147  checksum += *puchar++;
148 
149  if (checksum) {
150  pr_err("Checksum %2.2X should be %2.2X\n",
151  table->csum, table->csum - checksum);
152  return -1;
153  }
154  return 0;
155 }
156 
157 /*
158  * sfi_map_table()
159  *
160  * Return address of mapped table
161  * Check for common case that we can re-use mapping to SYST,
162  * which requires syst_pa, syst_va to be initialized.
163  */
165 {
166  struct sfi_table_header *th;
167  u32 length;
168 
169  if (!TABLE_ON_PAGE(syst_pa, pa, sizeof(struct sfi_table_header)))
170  th = sfi_map_memory(pa, sizeof(struct sfi_table_header));
171  else
172  th = (void *)syst_va + (pa - syst_pa);
173 
174  /* If table fits on same page as its header, we are done */
175  if (TABLE_ON_PAGE(th, th, th->len))
176  return th;
177 
178  /* Entire table does not fit on same page as SYST */
179  length = th->len;
180  if (!TABLE_ON_PAGE(syst_pa, pa, sizeof(struct sfi_table_header)))
181  sfi_unmap_memory(th, sizeof(struct sfi_table_header));
182 
183  return sfi_map_memory(pa, length);
184 }
185 
186 /*
187  * sfi_unmap_table()
188  *
189  * Undoes effect of sfi_map_table() by unmapping table
190  * if it did not completely fit on same page as SYST.
191  */
193 {
194  if (!TABLE_ON_PAGE(syst_va, th, th->len))
195  sfi_unmap_memory(th, TABLE_ON_PAGE(th, th, th->len) ?
196  sizeof(*th) : th->len);
197 }
198 
199 static int sfi_table_check_key(struct sfi_table_header *th,
200  struct sfi_table_key *key)
201 {
202 
203  if (strncmp(th->sig, key->sig, SFI_SIGNATURE_SIZE)
204  || (key->oem_id && strncmp(th->oem_id,
205  key->oem_id, SFI_OEM_ID_SIZE))
206  || (key->oem_table_id && strncmp(th->oem_table_id,
208  return -1;
209 
210  return 0;
211 }
212 
213 /*
214  * This function will be used in 2 cases:
215  * 1. used to enumerate and verify the tables addressed by SYST/XSDT,
216  * thus no signature will be given (in kernel boot phase)
217  * 2. used to parse one specific table, signature must exist, and
218  * the mapped virt address will be returned, and the virt space
219  * will be released by call sfi_put_table() later
220  *
221  * This two cases are from two different functions with two different
222  * sections and causes section mismatch warning. So use __ref to tell
223  * modpost not to make any noise.
224  *
225  * Return value:
226  * NULL: when can't find a table matching the key
227  * ERR_PTR(error): error value
228  * virt table address: when a matched table is found
229  */
230 struct sfi_table_header *
232 {
233  struct sfi_table_header *th;
234  void *ret = NULL;
235 
236  th = sfi_map_table(pa);
237  if (!th)
238  return ERR_PTR(-ENOMEM);
239 
240  if (!key->sig) {
241  sfi_print_table_header(pa, th);
242  if (sfi_verify_table(th))
243  ret = ERR_PTR(-EINVAL);
244  } else {
245  if (!sfi_table_check_key(th, key))
246  return th; /* Success */
247  }
248 
249  sfi_unmap_table(th);
250  return ret;
251 }
252 
253 /*
254  * sfi_get_table()
255  *
256  * Search SYST for the specified table with the signature in
257  * the key, and return the mapped table
258  */
260 {
261  struct sfi_table_header *th;
262  u32 tbl_cnt, i;
263 
264  tbl_cnt = SFI_GET_NUM_ENTRIES(syst_va, u64);
265  for (i = 0; i < tbl_cnt; i++) {
266  th = sfi_check_table(syst_va->pentry[i], key);
267  if (!IS_ERR(th) && th)
268  return th;
269  }
270 
271  return NULL;
272 }
273 
275 {
276  sfi_unmap_table(th);
277 }
278 
279 /* Find table with signature, run handler on it */
281  sfi_table_handler handler)
282 {
283  struct sfi_table_header *table = NULL;
284  struct sfi_table_key key;
285  int ret = -EINVAL;
286 
287  if (sfi_disabled || !handler || !signature)
288  goto exit;
289 
290  key.sig = signature;
291  key.oem_id = oem_id;
293 
294  table = sfi_get_table(&key);
295  if (!table)
296  goto exit;
297 
298  ret = handler(table);
299  sfi_put_table(table);
300 exit:
301  return ret;
302 }
304 
305 /*
306  * sfi_parse_syst()
307  * Checksum all the tables in SYST and print their headers
308  *
309  * success: set syst_va, return 0
310  */
311 static int __init sfi_parse_syst(void)
312 {
313  struct sfi_table_key key = SFI_ANY_KEY;
314  int tbl_cnt, i;
315  void *ret;
316 
317  syst_va = sfi_map_memory(syst_pa, sizeof(struct sfi_table_simple));
318  if (!syst_va)
319  return -ENOMEM;
320 
321  tbl_cnt = SFI_GET_NUM_ENTRIES(syst_va, u64);
322  for (i = 0; i < tbl_cnt; i++) {
323  ret = sfi_check_table(syst_va->pentry[i], &key);
324  if (IS_ERR(ret))
325  return PTR_ERR(ret);
326  }
327 
328  return 0;
329 }
330 
331 /*
332  * The OS finds the System Table by searching 16-byte boundaries between
333  * physical address 0x000E0000 and 0x000FFFFF. The OS shall search this region
334  * starting at the low address and shall stop searching when the 1st valid SFI
335  * System Table is found.
336  *
337  * success: set syst_pa, return 0
338  * fail: return -1
339  */
340 static __init int sfi_find_syst(void)
341 {
342  unsigned long offset, len;
343  void *start;
344 
346  start = sfi_map_memory(SFI_SYST_SEARCH_BEGIN, len);
347  if (!start)
348  return -1;
349 
350  for (offset = 0; offset < len; offset += 16) {
351  struct sfi_table_header *syst_hdr;
352 
353  syst_hdr = start + offset;
354  if (strncmp(syst_hdr->sig, SFI_SIG_SYST,
356  continue;
357 
358  if (syst_hdr->len > PAGE_SIZE)
359  continue;
360 
361  sfi_print_table_header(SFI_SYST_SEARCH_BEGIN + offset,
362  syst_hdr);
363 
364  if (sfi_verify_table(syst_hdr))
365  continue;
366 
367  /*
368  * Enforce SFI spec mandate that SYST reside within a page.
369  */
370  if (!ON_SAME_PAGE(syst_pa, syst_pa + syst_hdr->len)) {
371  pr_info("SYST 0x%llx + 0x%x crosses page\n",
372  syst_pa, syst_hdr->len);
373  continue;
374  }
375 
376  /* Success */
377  syst_pa = SFI_SYST_SEARCH_BEGIN + offset;
378  sfi_unmap_memory(start, len);
379  return 0;
380  }
381 
382  sfi_unmap_memory(start, len);
383  return -1;
384 }
385 
386 static struct kobject *sfi_kobj;
387 static struct kobject *tables_kobj;
388 
389 static ssize_t sfi_table_show(struct file *filp, struct kobject *kobj,
390  struct bin_attribute *bin_attr, char *buf,
391  loff_t offset, size_t count)
392 {
393  struct sfi_table_attr *tbl_attr =
394  container_of(bin_attr, struct sfi_table_attr, attr);
395  struct sfi_table_header *th = NULL;
396  struct sfi_table_key key;
397  ssize_t cnt;
398 
399  key.sig = tbl_attr->name;
400  key.oem_id = NULL;
401  key.oem_table_id = NULL;
402 
403  if (strncmp(SFI_SIG_SYST, tbl_attr->name, SFI_SIGNATURE_SIZE)) {
404  th = sfi_get_table(&key);
405  if (!th)
406  return 0;
407 
408  cnt = memory_read_from_buffer(buf, count, &offset,
409  th, th->len);
410  sfi_put_table(th);
411  } else
412  cnt = memory_read_from_buffer(buf, count, &offset,
413  syst_va, syst_va->header.len);
414 
415  return cnt;
416 }
417 
419 {
420  struct sfi_table_attr *tbl_attr;
421  struct sfi_table_header *th;
422  int ret;
423 
424  tbl_attr = kzalloc(sizeof(struct sfi_table_attr), GFP_KERNEL);
425  if (!tbl_attr)
426  return NULL;
427 
428  th = sfi_map_table(pa);
429  if (!th || !th->sig[0]) {
430  kfree(tbl_attr);
431  return NULL;
432  }
433 
434  sysfs_attr_init(&tbl_attr->attr.attr);
435  memcpy(tbl_attr->name, th->sig, SFI_SIGNATURE_SIZE);
436 
437  tbl_attr->attr.size = 0;
438  tbl_attr->attr.read = sfi_table_show;
439  tbl_attr->attr.attr.name = tbl_attr->name;
440  tbl_attr->attr.attr.mode = 0400;
441 
442  ret = sysfs_create_bin_file(tables_kobj,
443  &tbl_attr->attr);
444  if (ret) {
445  kfree(tbl_attr);
446  tbl_attr = NULL;
447  }
448 
449  sfi_unmap_table(th);
450  return tbl_attr;
451 }
452 
453 static int __init sfi_sysfs_init(void)
454 {
455  int tbl_cnt, i;
456 
457  if (sfi_disabled)
458  return 0;
459 
460  sfi_kobj = kobject_create_and_add("sfi", firmware_kobj);
461  if (!sfi_kobj)
462  return 0;
463 
464  tables_kobj = kobject_create_and_add("tables", sfi_kobj);
465  if (!tables_kobj) {
466  kobject_put(sfi_kobj);
467  return 0;
468  }
469 
470  sfi_sysfs_install_table(syst_pa);
471 
472  tbl_cnt = SFI_GET_NUM_ENTRIES(syst_va, u64);
473 
474  for (i = 0; i < tbl_cnt; i++)
475  sfi_sysfs_install_table(syst_va->pentry[i]);
476 
478  kobject_uevent(sfi_kobj, KOBJ_ADD);
479  kobject_uevent(tables_kobj, KOBJ_ADD);
480  pr_info("SFI sysfs interfaces init success\n");
481  return 0;
482 }
483 
484 void __init sfi_init(void)
485 {
486  if (!acpi_disabled)
487  disable_sfi();
488 
489  if (sfi_disabled)
490  return;
491 
492  pr_info("Simple Firmware Interface v0.81 http://simplefirmware.org\n");
493 
494  if (sfi_find_syst() || sfi_parse_syst() || sfi_platform_init())
495  disable_sfi();
496 
497  return;
498 }
499 
501 {
502  int length;
503 
504  if (sfi_disabled)
505  return;
506 
507  length = syst_va->header.len;
508  sfi_unmap_memory(syst_va, sizeof(struct sfi_table_simple));
509 
510  /* Use ioremap now after it is ready */
511  sfi_use_ioremap = 1;
512  syst_va = sfi_map_memory(syst_pa, length);
513 
514  sfi_acpi_init();
515 }
516 
517 /*
518  * The reason we put it here because we need wait till the /sys/firmware
519  * is setup, then our interface can be registered in /sys/firmware/sfi
520  */
521 core_initcall(sfi_sysfs_init);