This source file includes following definitions.
- sfi_map_memory
- sfi_unmap_memory
- sfi_print_table_header
- sfi_verify_table
- sfi_map_table
- sfi_unmap_table
- sfi_table_check_key
- sfi_check_table
- sfi_get_table
- sfi_put_table
- sfi_table_parse
- sfi_parse_syst
- sfi_find_syst
- sfi_table_show
- sfi_sysfs_install_table
- sfi_sysfs_init
- sfi_init
- sfi_init_late
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 
  11 
  12 
  13 
  14 
  15 
  16 
  17 
  18 
  19 
  20 
  21 
  22 
  23 
  24 
  25 
  26 
  27 
  28 
  29 
  30 
  31 
  32 
  33 
  34 
  35 
  36 
  37 
  38 
  39 
  40 
  41 
  42 
  43 
  44 
  45 
  46 
  47 
  48 
  49 
  50 
  51 
  52 
  53 
  54 
  55 
  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 
  89 
  90 
  91 
  92 
  93 static u32 sfi_use_memremap __read_mostly;
  94 
  95 
  96 
  97 
  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 
 132 
 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         
 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 
 160 
 161 
 162 
 163 
 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          
 176         if (TABLE_ON_PAGE(th, th, th->len))
 177                 return th;
 178 
 179         
 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 
 189 
 190 
 191 
 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 
 216 
 217 
 218 
 219 
 220 
 221 
 222 
 223 
 224 
 225 
 226 
 227 
 228 
 229 
 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;      
 248         }
 249 
 250         sfi_unmap_table(th);
 251         return ret;
 252 }
 253 
 254 
 255 
 256 
 257 
 258 
 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 
 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 
 308 
 309 
 310 
 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 
 334 
 335 
 336 
 337 
 338 
 339 
 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 
 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                 
 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         
 512         sfi_use_memremap = 1;
 513         syst_va = sfi_map_memory(syst_pa, length);
 514 
 515         sfi_acpi_init();
 516 }
 517 
 518 
 519 
 520 
 521 
 522 core_initcall(sfi_sysfs_init);