acpi.c 8.0 KB

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