linux/drivers/sfi/sfi_core.c
<<
>>
Prefs
   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
  81int sfi_disabled __read_mostly;
  82EXPORT_SYMBOL(sfi_disabled);
  83
  84static u64 syst_pa __read_mostly;
  85static 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 */
  93static 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 */
  99static 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
 110static 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
 121static 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 */
 134static 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 */
 165static 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 */
 193static 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
 200static 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 */
 231struct 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 */
 260struct 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
 275void 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 */
 281int 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);
 301exit:
 302        return ret;
 303}
 304EXPORT_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 */
 312static 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 */
 341static __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
 387static struct kobject *sfi_kobj;
 388static struct kobject *tables_kobj;
 389
 390static 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
 419struct 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
 454static 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
 485void __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
 501void __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 */
 522core_initcall(sfi_sysfs_init);
 523