acpi.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. /*++
  2. Copyright (c) 2014 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. acpi.c
  9. Abstract:
  10. This module implements ACPI table support for the UEFI firmware on PC/AT
  11. BIOS machines.
  12. Author:
  13. Evan Green 26-Mar-2014
  14. Environment:
  15. Firmware
  16. --*/
  17. //
  18. // ------------------------------------------------------------------- Includes
  19. //
  20. #include <minoca/lib/types.h>
  21. #include <minoca/fw/acpitabs.h>
  22. #include <minoca/fw/smbios.h>
  23. #include <uefifw.h>
  24. #include "biosfw.h"
  25. //
  26. // ---------------------------------------------------------------- Definitions
  27. //
  28. //
  29. // Define the physical address where the EBDA (Extended BIOS Data Area) address
  30. // is stored.
  31. //
  32. #define EBDA_POINTER_ADDRESS 0x40E
  33. //
  34. // Define the address and length of the space to search for the RSDP.
  35. //
  36. #define RSDP_SEARCH_ADDRESS (PVOID)0xE0000
  37. #define RSDP_SEARCH_LENGTH 0x20000
  38. //
  39. // Define the search parameters for the SMBIOS table.
  40. //
  41. #define SMBIOS_SEARCH_START 0xF0000
  42. #define SMBIOS_SEARCH_END 0x100000
  43. #define SMBIOS_SEARCH_INCREMENT 0x10
  44. //
  45. // ------------------------------------------------------ Data Type Definitions
  46. //
  47. //
  48. // ----------------------------------------------- Internal Function Prototypes
  49. //
  50. PVOID
  51. EfipPcatSearchForRsdp (
  52. PVOID Address,
  53. ULONGLONG Length
  54. );
  55. BOOLEAN
  56. EfipPcatChecksumTable (
  57. VOID *Address,
  58. UINT32 Length
  59. );
  60. PVOID
  61. EfipPcatFindSmbiosTable (
  62. VOID
  63. );
  64. //
  65. // -------------------------------------------------------------------- Globals
  66. //
  67. //
  68. // Save a pointer to the RSDP.
  69. //
  70. VOID *EfiRsdpPointer;
  71. extern EFI_GUID EfiSmbiosTableGuid;
  72. //
  73. // ------------------------------------------------------------------ Functions
  74. //
  75. VOID *
  76. EfipPcatFindRsdp (
  77. VOID
  78. )
  79. /*++
  80. Routine Description:
  81. This routine attempts to find the ACPI RSDP table pointer on a PC-AT
  82. compatible system. It looks in the first 1k of the EBDA (Extended BIOS Data
  83. Area), as well as between the ranges 0xE0000 and 0xFFFFF. This routine
  84. must be run in physical mode.
  85. Arguments:
  86. None.
  87. Return Value:
  88. Returns a pointer to the RSDP table on success.
  89. NULL on failure.
  90. --*/
  91. {
  92. UINT16 *EbdaLocationPointer;
  93. PVOID EbdaPointer;
  94. PVOID RsdpPointer;
  95. //
  96. // Locate the EBDA, whose address is written into a specific offset.
  97. //
  98. EbdaLocationPointer = (UINT16 *)EBDA_POINTER_ADDRESS;
  99. EbdaPointer = (VOID *)(UINTN)*EbdaLocationPointer;
  100. //
  101. // Search the first 1k of the EBDA for the RSDP pointer.
  102. //
  103. RsdpPointer = EfipPcatSearchForRsdp(EbdaPointer, 1024);
  104. if (RsdpPointer != NULL) {
  105. return RsdpPointer;
  106. }
  107. //
  108. // Search the hardcoded range from 0xE0000 to 0xFFFFF.
  109. //
  110. RsdpPointer = EfipPcatSearchForRsdp(RSDP_SEARCH_ADDRESS,
  111. RSDP_SEARCH_LENGTH);
  112. if (RsdpPointer != NULL) {
  113. return RsdpPointer;
  114. }
  115. return NULL;
  116. }
  117. EFI_STATUS
  118. EfipPcatInstallRsdp (
  119. VOID
  120. )
  121. /*++
  122. Routine Description:
  123. This routine installs the RSDP pointer as a configuration table in EFI.
  124. Arguments:
  125. None.
  126. Return Value:
  127. EFI status.
  128. --*/
  129. {
  130. EFI_GUID *Guid;
  131. PRSDP Rsdp;
  132. EFI_STATUS Status;
  133. Rsdp = EfiRsdpPointer;
  134. if (Rsdp == NULL) {
  135. Rsdp = EfipPcatFindRsdp();
  136. }
  137. if (Rsdp == NULL) {
  138. return EFI_UNSUPPORTED;
  139. }
  140. if (Rsdp->Revision >= ACPI_20_RSDP_REVISION) {
  141. Guid = &EfiAcpiTableGuid;
  142. } else {
  143. Guid = &EfiAcpiTable1Guid;
  144. }
  145. Status = EfiInstallConfigurationTable(Guid, Rsdp);
  146. return Status;
  147. }
  148. EFI_STATUS
  149. EfipPcatInstallSmbios (
  150. VOID
  151. )
  152. /*++
  153. Routine Description:
  154. This routine installs the SMBIOS entry point structure as a configuration
  155. table in EFI.
  156. Arguments:
  157. None.
  158. Return Value:
  159. EFI status.
  160. --*/
  161. {
  162. PSMBIOS_ENTRY_POINT SmbiosTable;
  163. EFI_STATUS Status;
  164. SmbiosTable = EfipPcatFindSmbiosTable();
  165. if (SmbiosTable == NULL) {
  166. return EFI_SUCCESS;
  167. }
  168. Status = EfiInstallConfigurationTable(&EfiSmbiosTableGuid, SmbiosTable);
  169. return Status;
  170. }
  171. //
  172. // --------------------------------------------------------- Internal Functions
  173. //
  174. PVOID
  175. EfipPcatFindSmbiosTable (
  176. VOID
  177. )
  178. /*++
  179. Routine Description:
  180. This routine attempts to find the SMBIOS table entry point structure.
  181. Arguments:
  182. None.
  183. Return Value:
  184. Returns a pointer to the SMBIOS entry point structure on success.
  185. NULL on failure.
  186. --*/
  187. {
  188. UINTN CompareIndex;
  189. PVOID Intermediate;
  190. UCHAR Length;
  191. BOOL Match;
  192. ULONG Offset;
  193. PSMBIOS_ENTRY_POINT Table;
  194. //
  195. // On PC/AT systems, the SMBIOS table entry point resides somewhere between
  196. // 0xF0000 and 0x100000, aligned to a 16 byte boundary.
  197. //
  198. Table = (PSMBIOS_ENTRY_POINT)SMBIOS_SEARCH_START;
  199. while (Table < (PSMBIOS_ENTRY_POINT)SMBIOS_SEARCH_END) {
  200. if (Table->AnchorString == SMBIOS_ANCHOR_STRING_VALUE) {
  201. Length = Table->EntryPointLength;
  202. //
  203. // Check the checksum.
  204. //
  205. if (EfipPcatChecksumTable(Table, Length) != FALSE) {
  206. //
  207. // Also verify and checksum the second part of the table.
  208. //
  209. Match = TRUE;
  210. for (CompareIndex = 0;
  211. CompareIndex < SMBIOS_INTERMEDIATE_ANCHOR_SIZE;
  212. CompareIndex += 1) {
  213. if (Table->IntermediateAnchor[CompareIndex] !=
  214. SMBIOS_INTERMEDIATE_ANCHOR[CompareIndex]) {
  215. Match = FALSE;
  216. break;
  217. }
  218. }
  219. if (Match != FALSE) {
  220. Offset = OFFSET_OF(SMBIOS_ENTRY_POINT, IntermediateAnchor);
  221. Length = sizeof(SMBIOS_ENTRY_POINT) - Offset;
  222. Intermediate = (((PVOID)Table) + Offset);
  223. //
  224. // If this also checksums, then the table really is here.
  225. //
  226. if (EfipPcatChecksumTable(Intermediate, Length) != FALSE) {
  227. return Table;
  228. }
  229. }
  230. }
  231. }
  232. //
  233. // Move up 16 bytes to the next candidate position.
  234. //
  235. Table = (PSMBIOS_ENTRY_POINT)(((PVOID)Table) + SMBIOS_SEARCH_INCREMENT);
  236. }
  237. return NULL;
  238. }
  239. VOID *
  240. EfipPcatSearchForRsdp (
  241. VOID *Address,
  242. UINT64 Length
  243. )
  244. /*++
  245. Routine Description:
  246. This routine searches the given range for the RSDP table.
  247. Arguments:
  248. Address - Supplies the starting address to search for the RSDP. This
  249. address must be 16 byte aligned.
  250. Length - Supplies the number of bytes to search.
  251. Return Value:
  252. Returns a pointer to the RSDP table on success.
  253. NULL on failure.
  254. --*/
  255. {
  256. UINT64 *CurrentAddress;
  257. BOOLEAN GoodChecksum;
  258. CurrentAddress = Address;
  259. while (Length >= sizeof(UINT64)) {
  260. if (*CurrentAddress == RSDP_SIGNATURE) {
  261. GoodChecksum = EfipPcatChecksumTable(CurrentAddress,
  262. RSDP_CHECKSUM_SIZE);
  263. if (GoodChecksum != FALSE) {
  264. return CurrentAddress;
  265. }
  266. }
  267. //
  268. // Advance by 16 bytes.
  269. //
  270. CurrentAddress = (UINT64 *)((UINT8 *)CurrentAddress + 16);
  271. }
  272. return NULL;
  273. }
  274. BOOLEAN
  275. EfipPcatChecksumTable (
  276. VOID *Address,
  277. UINT32 Length
  278. )
  279. /*++
  280. Routine Description:
  281. This routine sums all of the bytes in a given table to determine if its
  282. checksum is correct. The checksum is set such that all the bytes in the
  283. table sum to a value of 0.
  284. Arguments:
  285. Address - Supplies the address of the table to checksum.
  286. Length - Supplies the length of the table, in bytes.
  287. Return Value:
  288. TRUE if all bytes in the table correctly sum to 0.
  289. FALSE if the bytes don't properly sum to 0.
  290. --*/
  291. {
  292. UINT8 *CurrentByte;
  293. UINT8 Sum;
  294. CurrentByte = Address;
  295. Sum = 0;
  296. while (Length != 0) {
  297. Sum += *CurrentByte;
  298. CurrentByte += 1;
  299. Length -= 1;
  300. }
  301. if (Sum == 0) {
  302. return TRUE;
  303. }
  304. return FALSE;
  305. }