sfi.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (c) 2015 Google, Inc
  4. * Written by Simon Glass <sjg@chromium.org>
  5. */
  6. /*
  7. * Intel Simple Firmware Interface (SFI)
  8. *
  9. * Yet another way to pass information to the Linux kernel.
  10. *
  11. * See https://simplefirmware.org/ for details
  12. */
  13. #include <common.h>
  14. #include <cpu.h>
  15. #include <dm.h>
  16. #include <asm/cpu.h>
  17. #include <asm/ioapic.h>
  18. #include <asm/sfi.h>
  19. #include <asm/tables.h>
  20. #include <dm/uclass-internal.h>
  21. struct table_info {
  22. u32 base;
  23. int ptr;
  24. u32 entry_start;
  25. u64 table[SFI_TABLE_MAX_ENTRIES];
  26. int count;
  27. };
  28. static void *get_entry_start(struct table_info *tab)
  29. {
  30. if (tab->count == SFI_TABLE_MAX_ENTRIES)
  31. return NULL;
  32. tab->entry_start = tab->base + tab->ptr;
  33. tab->table[tab->count] = tab->entry_start;
  34. tab->entry_start += sizeof(struct sfi_table_header);
  35. return (void *)(uintptr_t)tab->entry_start;
  36. }
  37. static void finish_table(struct table_info *tab, const char *sig, void *entry)
  38. {
  39. struct sfi_table_header *hdr;
  40. hdr = (struct sfi_table_header *)(uintptr_t)(tab->base + tab->ptr);
  41. strcpy(hdr->sig, sig);
  42. hdr->len = sizeof(*hdr) + ((ulong)entry - tab->entry_start);
  43. hdr->rev = 1;
  44. strncpy(hdr->oem_id, "U-Boot", SFI_OEM_ID_SIZE);
  45. strncpy(hdr->oem_table_id, "Table v1", SFI_OEM_TABLE_ID_SIZE);
  46. hdr->csum = 0;
  47. hdr->csum = table_compute_checksum(hdr, hdr->len);
  48. tab->ptr += hdr->len;
  49. tab->ptr = ALIGN(tab->ptr, 16);
  50. tab->count++;
  51. }
  52. static int sfi_write_system_header(struct table_info *tab)
  53. {
  54. u64 *entry = get_entry_start(tab);
  55. int i;
  56. if (!entry)
  57. return -ENOSPC;
  58. for (i = 0; i < tab->count; i++)
  59. *entry++ = tab->table[i];
  60. finish_table(tab, SFI_SIG_SYST, entry);
  61. return 0;
  62. }
  63. static int sfi_write_cpus(struct table_info *tab)
  64. {
  65. struct sfi_cpu_table_entry *entry = get_entry_start(tab);
  66. struct udevice *dev;
  67. int count = 0;
  68. if (!entry)
  69. return -ENOSPC;
  70. for (uclass_find_first_device(UCLASS_CPU, &dev);
  71. dev;
  72. uclass_find_next_device(&dev)) {
  73. struct cpu_platdata *plat = dev_get_parent_plat(dev);
  74. if (!device_active(dev))
  75. continue;
  76. entry->apic_id = plat->cpu_id;
  77. entry++;
  78. count++;
  79. }
  80. /* Omit the table if there is only one CPU */
  81. if (count > 1)
  82. finish_table(tab, SFI_SIG_CPUS, entry);
  83. return 0;
  84. }
  85. static int sfi_write_apic(struct table_info *tab)
  86. {
  87. struct sfi_apic_table_entry *entry = get_entry_start(tab);
  88. if (!entry)
  89. return -ENOSPC;
  90. entry->phys_addr = IO_APIC_ADDR;
  91. entry++;
  92. finish_table(tab, SFI_SIG_APIC, entry);
  93. return 0;
  94. }
  95. static int sfi_write_xsdt(struct table_info *tab)
  96. {
  97. struct sfi_xsdt_header *entry = get_entry_start(tab);
  98. if (!entry)
  99. return -ENOSPC;
  100. entry->oem_revision = 1;
  101. entry->creator_id = 1;
  102. entry->creator_revision = 1;
  103. entry++;
  104. finish_table(tab, SFI_SIG_XSDT, entry);
  105. return 0;
  106. }
  107. ulong write_sfi_table(ulong base)
  108. {
  109. struct table_info table;
  110. table.base = base;
  111. table.ptr = 0;
  112. table.count = 0;
  113. sfi_write_cpus(&table);
  114. sfi_write_apic(&table);
  115. /*
  116. * The SFI specification marks the XSDT table as option, but Linux 4.0
  117. * crashes on start-up when it is not provided.
  118. */
  119. sfi_write_xsdt(&table);
  120. /* Finally, write out the system header which points to the others */
  121. sfi_write_system_header(&table);
  122. return base + table.ptr;
  123. }