sfi_core.c revision 011a606d0670196c17110b6770e39cc0865aa614
16ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/* sfi_core.c Simple Firmware Interface - core internals */ 26ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 36ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/* 46ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 56ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang This file is provided under a dual BSD/GPLv2 license. When using or 66ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang redistributing this file, you may do so under either license. 76ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 86ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang GPL LICENSE SUMMARY 96ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 106ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang Copyright(c) 2009 Intel Corporation. All rights reserved. 116ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 126ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang This program is free software; you can redistribute it and/or modify 136ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang it under the terms of version 2 of the GNU General Public License as 146ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang published by the Free Software Foundation. 156ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 166ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang This program is distributed in the hope that it will be useful, but 176ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang WITHOUT ANY WARRANTY; without even the implied warranty of 186ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 196ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang General Public License for more details. 206ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 216ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang You should have received a copy of the GNU General Public License 226ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang along with this program; if not, write to the Free Software 236ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 246ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang The full GNU General Public License is included in this distribution 256ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang in the file called LICENSE.GPL. 266ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 276ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang BSD LICENSE 286ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 296ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang Copyright(c) 2009 Intel Corporation. All rights reserved. 306ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 316ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang Redistribution and use in source and binary forms, with or without 326ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang modification, are permitted provided that the following conditions 336ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang are met: 346ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 356ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * Redistributions of source code must retain the above copyright 366ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang notice, this list of conditions and the following disclaimer. 376ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * Redistributions in binary form must reproduce the above copyright 386ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang notice, this list of conditions and the following disclaimer in 396ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang the documentation and/or other materials provided with the 406ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang distribution. 416ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * Neither the name of Intel Corporation nor the names of its 426ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang contributors may be used to endorse or promote products derived 436ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang from this software without specific prior written permission. 446ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 456ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 466ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 476ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 486ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 496ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 506ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 516ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 526ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 536ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 546ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 556ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 566ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 576ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang*/ 586ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 596ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang#define KMSG_COMPONENT "SFI" 606ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 616ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 626ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang#include <linux/bootmem.h> 636ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang#include <linux/kernel.h> 646ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang#include <linux/module.h> 656ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang#include <linux/errno.h> 666ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang#include <linux/types.h> 676ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang#include <linux/acpi.h> 686ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang#include <linux/init.h> 696ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang#include <linux/sfi.h> 706ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 716ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang#include "sfi_core.h" 726ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 736ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang#define ON_SAME_PAGE(addr1, addr2) \ 746ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang (((unsigned long)(addr1) & PAGE_MASK) == \ 756ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang ((unsigned long)(addr2) & PAGE_MASK)) 766ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang#define TABLE_ON_PAGE(page, table, size) (ON_SAME_PAGE(page, table) && \ 776ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang ON_SAME_PAGE(page, table + size)) 786ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 796ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangint sfi_disabled __read_mostly; 806ae6996a466e14bcf41618cde641a74ae03dc285Feng TangEXPORT_SYMBOL(sfi_disabled); 816ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 826ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangstatic u64 syst_pa __read_mostly; 836ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangstatic struct sfi_table_simple *syst_va __read_mostly; 846ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 856ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/* 866ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * FW creates and saves the SFI tables in memory. When these tables get 876ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * used, they may need to be mapped to virtual address space, and the mapping 886ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * can happen before or after the ioremap() is ready, so a flag is needed 896ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * to indicating this 906ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang */ 916ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangstatic u32 sfi_use_ioremap __read_mostly; 926ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 9301674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullick/* 9401674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullick * sfi_un/map_memory calls early_ioremap/iounmap which is a __init function 9501674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullick * and introduces section mismatch. So use __ref to make it calm. 9601674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullick */ 9701674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullickstatic void __iomem * __ref sfi_map_memory(u64 phys, u32 size) 986ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{ 996ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang if (!phys || !size) 1006ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang return NULL; 1016ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 1026ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang if (sfi_use_ioremap) 1036ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang return ioremap(phys, size); 1046ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang else 1056ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang return early_ioremap(phys, size); 1066ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang} 1076ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 10801674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullickstatic void __ref sfi_unmap_memory(void __iomem *virt, u32 size) 1096ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{ 1106ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang if (!virt || !size) 1116ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang return; 1126ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 1136ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang if (sfi_use_ioremap) 1146ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang iounmap(virt); 1156ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang else 1166ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang early_iounmap(virt, size); 1176ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang} 1186ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 1196ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangstatic void sfi_print_table_header(unsigned long long pa, 1206ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang struct sfi_table_header *header) 1216ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{ 1226ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang pr_info("%4.4s %llX, %04X (v%d %6.6s %8.8s)\n", 1236ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang header->sig, pa, 1246ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang header->len, header->rev, header->oem_id, 1256ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang header->oem_table_id); 1266ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang} 1276ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 1286ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/* 1296ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * sfi_verify_table() 1306ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * Sanity check table lengh, calculate checksum 1316ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang */ 132011a606d0670196c17110b6770e39cc0865aa614Arjan van de Venstatic int sfi_verify_table(struct sfi_table_header *table) 1336ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{ 1346ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 1356ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang u8 checksum = 0; 1366ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang u8 *puchar = (u8 *)table; 1376ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang u32 length = table->len; 1386ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 1396ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang /* Sanity check table length against arbitrary 1MB limit */ 1406ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang if (length > 0x100000) { 1416ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang pr_err("Invalid table length 0x%x\n", length); 1426ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang return -1; 1436ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang } 1446ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 1456ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang while (length--) 1466ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang checksum += *puchar++; 1476ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 1486ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang if (checksum) { 1496ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang pr_err("Checksum %2.2X should be %2.2X\n", 1506ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang table->csum, table->csum - checksum); 1516ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang return -1; 1526ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang } 1536ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang return 0; 1546ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang} 1556ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 1566ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/* 1576ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * sfi_map_table() 1586ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * 1596ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * Return address of mapped table 1606ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * Check for common case that we can re-use mapping to SYST, 1616ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * which requires syst_pa, syst_va to be initialized. 1626ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang */ 1636ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangstruct sfi_table_header *sfi_map_table(u64 pa) 1646ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{ 1656ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang struct sfi_table_header *th; 1666ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang u32 length; 1676ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 1686ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang if (!TABLE_ON_PAGE(syst_pa, pa, sizeof(struct sfi_table_header))) 1696ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang th = sfi_map_memory(pa, sizeof(struct sfi_table_header)); 1706ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang else 1716ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang th = (void *)syst_va + (pa - syst_pa); 1726ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 1736ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang /* If table fits on same page as its header, we are done */ 1746ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang if (TABLE_ON_PAGE(th, th, th->len)) 1756ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang return th; 1766ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 1776ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang /* Entire table does not fit on same page as SYST */ 1786ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang length = th->len; 1796ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang if (!TABLE_ON_PAGE(syst_pa, pa, sizeof(struct sfi_table_header))) 1806ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang sfi_unmap_memory(th, sizeof(struct sfi_table_header)); 1816ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 1826ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang return sfi_map_memory(pa, length); 1836ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang} 1846ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 1856ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/* 1866ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * sfi_unmap_table() 1876ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * 1886ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * Undoes effect of sfi_map_table() by unmapping table 1896ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * if it did not completely fit on same page as SYST. 1906ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang */ 1916ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangvoid sfi_unmap_table(struct sfi_table_header *th) 1926ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{ 1936ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang if (!TABLE_ON_PAGE(syst_va, th, th->len)) 1946ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang sfi_unmap_memory(th, TABLE_ON_PAGE(th, th, th->len) ? 1956ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang sizeof(*th) : th->len); 1966ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang} 1976ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 1986ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangstatic int sfi_table_check_key(struct sfi_table_header *th, 1996ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang struct sfi_table_key *key) 2006ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{ 2016ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 2026ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang if (strncmp(th->sig, key->sig, SFI_SIGNATURE_SIZE) 2036ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang || (key->oem_id && strncmp(th->oem_id, 2046ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang key->oem_id, SFI_OEM_ID_SIZE)) 2056ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang || (key->oem_table_id && strncmp(th->oem_table_id, 2066ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang key->oem_table_id, SFI_OEM_TABLE_ID_SIZE))) 2076ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang return -1; 2086ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 2096ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang return 0; 2106ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang} 2116ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 2126ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/* 2136ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * This function will be used in 2 cases: 2146ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * 1. used to enumerate and verify the tables addressed by SYST/XSDT, 2156ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * thus no signature will be given (in kernel boot phase) 2166ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * 2. used to parse one specific table, signature must exist, and 2176ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * the mapped virt address will be returned, and the virt space 2186ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * will be released by call sfi_put_table() later 2196ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * 22001674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullick * This two cases are from two different functions with two different 22101674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullick * sections and causes section mismatch warning. So use __ref to tell 22201674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullick * modpost not to make any noise. 22301674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullick * 2246ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * Return value: 2256ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * NULL: when can't find a table matching the key 2266ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * ERR_PTR(error): error value 2276ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * virt table address: when a matched table is found 2286ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang */ 22901674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullickstruct sfi_table_header * 23001674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullick __ref sfi_check_table(u64 pa, struct sfi_table_key *key) 2316ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{ 2326ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang struct sfi_table_header *th; 2336ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang void *ret = NULL; 2346ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 2356ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang th = sfi_map_table(pa); 2366ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang if (!th) 2376ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang return ERR_PTR(-ENOMEM); 2386ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 2396ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang if (!key->sig) { 2406ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang sfi_print_table_header(pa, th); 2416ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang if (sfi_verify_table(th)) 2426ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang ret = ERR_PTR(-EINVAL); 2436ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang } else { 2446ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang if (!sfi_table_check_key(th, key)) 2456ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang return th; /* Success */ 2466ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang } 2476ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 2486ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang sfi_unmap_table(th); 2496ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang return ret; 2506ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang} 2516ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 2526ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/* 2536ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * sfi_get_table() 2546ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * 2556ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * Search SYST for the specified table with the signature in 2566ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * the key, and return the mapped table 2576ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang */ 2586ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangstruct sfi_table_header *sfi_get_table(struct sfi_table_key *key) 2596ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{ 2606ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang struct sfi_table_header *th; 2616ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang u32 tbl_cnt, i; 2626ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 2636ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang tbl_cnt = SFI_GET_NUM_ENTRIES(syst_va, u64); 2646ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang for (i = 0; i < tbl_cnt; i++) { 2656ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang th = sfi_check_table(syst_va->pentry[i], key); 2666ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang if (!IS_ERR(th) && th) 2676ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang return th; 2686ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang } 2696ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 2706ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang return NULL; 2716ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang} 2726ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 2736ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangvoid sfi_put_table(struct sfi_table_header *th) 2746ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{ 2756ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang sfi_unmap_table(th); 2766ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang} 2776ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 2786ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/* Find table with signature, run handler on it */ 2796ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangint sfi_table_parse(char *signature, char *oem_id, char *oem_table_id, 2806ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang sfi_table_handler handler) 2816ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{ 2826ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang struct sfi_table_header *table = NULL; 2836ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang struct sfi_table_key key; 2846ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang int ret = -EINVAL; 2856ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 2866ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang if (sfi_disabled || !handler || !signature) 2876ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang goto exit; 2886ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 2896ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang key.sig = signature; 2906ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang key.oem_id = oem_id; 2916ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang key.oem_table_id = oem_table_id; 2926ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 2936ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang table = sfi_get_table(&key); 2946ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang if (!table) 2956ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang goto exit; 2966ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 2976ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang ret = handler(table); 2986ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang sfi_put_table(table); 2996ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangexit: 3006ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang return ret; 3016ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang} 3026ae6996a466e14bcf41618cde641a74ae03dc285Feng TangEXPORT_SYMBOL_GPL(sfi_table_parse); 3036ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 3046ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/* 3056ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * sfi_parse_syst() 3066ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * Checksum all the tables in SYST and print their headers 3076ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * 3086ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * success: set syst_va, return 0 3096ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang */ 3106ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangstatic int __init sfi_parse_syst(void) 3116ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{ 3126ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang struct sfi_table_key key = SFI_ANY_KEY; 3136ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang int tbl_cnt, i; 3146ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang void *ret; 3156ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 3166ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang syst_va = sfi_map_memory(syst_pa, sizeof(struct sfi_table_simple)); 3176ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang if (!syst_va) 3186ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang return -ENOMEM; 3196ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 3206ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang tbl_cnt = SFI_GET_NUM_ENTRIES(syst_va, u64); 3216ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang for (i = 0; i < tbl_cnt; i++) { 3226ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang ret = sfi_check_table(syst_va->pentry[i], &key); 3236ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang if (IS_ERR(ret)) 3246ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang return PTR_ERR(ret); 3256ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang } 3266ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 3276ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang return 0; 3286ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang} 3296ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 3306ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/* 3316ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * The OS finds the System Table by searching 16-byte boundaries between 3326ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * physical address 0x000E0000 and 0x000FFFFF. The OS shall search this region 3336ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * starting at the low address and shall stop searching when the 1st valid SFI 3346ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * System Table is found. 3356ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * 3366ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * success: set syst_pa, return 0 3376ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * fail: return -1 3386ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang */ 3396ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangstatic __init int sfi_find_syst(void) 3406ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{ 3416ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang unsigned long offset, len; 3426ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang void *start; 3436ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 3446ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang len = SFI_SYST_SEARCH_END - SFI_SYST_SEARCH_BEGIN; 3456ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang start = sfi_map_memory(SFI_SYST_SEARCH_BEGIN, len); 3466ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang if (!start) 3476ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang return -1; 3486ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 3496ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang for (offset = 0; offset < len; offset += 16) { 3506ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang struct sfi_table_header *syst_hdr; 3516ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 3526ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang syst_hdr = start + offset; 3536ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang if (strncmp(syst_hdr->sig, SFI_SIG_SYST, 3546ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang SFI_SIGNATURE_SIZE)) 3556ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang continue; 3566ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 3576ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang if (syst_hdr->len > PAGE_SIZE) 3586ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang continue; 3596ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 3606ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang sfi_print_table_header(SFI_SYST_SEARCH_BEGIN + offset, 3616ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang syst_hdr); 3626ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 3636ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang if (sfi_verify_table(syst_hdr)) 3646ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang continue; 3656ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 3666ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang /* 3676ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * Enforce SFI spec mandate that SYST reside within a page. 3686ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang */ 3696ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang if (!ON_SAME_PAGE(syst_pa, syst_pa + syst_hdr->len)) { 3706ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang pr_info("SYST 0x%llx + 0x%x crosses page\n", 3716ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang syst_pa, syst_hdr->len); 3726ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang continue; 3736ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang } 3746ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 3756ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang /* Success */ 3766ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang syst_pa = SFI_SYST_SEARCH_BEGIN + offset; 3776ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang sfi_unmap_memory(start, len); 3786ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang return 0; 3796ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang } 3806ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 3816ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang sfi_unmap_memory(start, len); 3826ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang return -1; 3836ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang} 3846ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 3856ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangvoid __init sfi_init(void) 3866ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{ 3876ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang if (!acpi_disabled) 3886ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang disable_sfi(); 3896ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 3906ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang if (sfi_disabled) 3916ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang return; 3926ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 3936ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang pr_info("Simple Firmware Interface v0.7 http://simplefirmware.org\n"); 3946ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 3956ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang if (sfi_find_syst() || sfi_parse_syst() || sfi_platform_init()) 3966ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang disable_sfi(); 3976ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 3986ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang return; 3996ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang} 4006ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 4016ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangvoid __init sfi_init_late(void) 4026ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{ 4036ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang int length; 4046ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 4056ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang if (sfi_disabled) 4066ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang return; 4076ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 4086ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang length = syst_va->header.len; 4096ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang sfi_unmap_memory(syst_va, sizeof(struct sfi_table_simple)); 4106ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 4116ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang /* Use ioremap now after it is ready */ 4126ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang sfi_use_ioremap = 1; 4136ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang syst_va = sfi_map_memory(syst_pa, length); 4146ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang 4156ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang sfi_acpi_init(); 4166ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang} 417