root/drivers/sfi/sfi_core.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sfi_map_memory
  2. sfi_unmap_memory
  3. sfi_print_table_header
  4. sfi_verify_table
  5. sfi_map_table
  6. sfi_unmap_table
  7. sfi_table_check_key
  8. sfi_check_table
  9. sfi_get_table
  10. sfi_put_table
  11. sfi_table_parse
  12. sfi_parse_syst
  13. sfi_find_syst
  14. sfi_table_show
  15. sfi_sysfs_install_table
  16. sfi_sysfs_init
  17. sfi_init
  18. sfi_init_late

   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  */
  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  * sfi_verify_table()
 132  * Sanity check table lengh, calculate checksum
 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         /* 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  */
 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  */
 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  * 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 *
 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  */
 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 /* Find table with signature, run handler on it */
 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  */
 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  */
 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 
 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         /* 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);

/* [<][>][^][v][top][bottom][index][help] */