smbios.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  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. smbios.c
  9. Abstract:
  10. This module implements support for adding SMBIOS tables to the firmware.
  11. Author:
  12. Evan Green 7-May-2014
  13. Environment:
  14. Firmware
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include "ueficore.h"
  20. #include <minoca/fw/smbios.h>
  21. //
  22. // ---------------------------------------------------------------- Definitions
  23. //
  24. //
  25. // ------------------------------------------------------ Data Type Definitions
  26. //
  27. //
  28. // ----------------------------------------------- Internal Function Prototypes
  29. //
  30. VOID
  31. EfipSmbiosChecksumTable (
  32. VOID *Buffer,
  33. UINTN Size,
  34. UINTN ChecksumOffset
  35. );
  36. //
  37. // -------------------------------------------------------------------- Globals
  38. //
  39. //
  40. // Store a pointer to the SMBIOS entry point structure.
  41. //
  42. VOID *EfiSmbiosEntryPoint;
  43. UINTN EfiSmbiosAllocationSize;
  44. UINTN EfiSmbiosPageCount;
  45. EFI_GUID EfiSmbiosTableGuid = EFI_SMBIOS_TABLE_GUID;
  46. SMBIOS_ENTRY_POINT EfiSmbiosEntryPointTemplate = {
  47. SMBIOS_ANCHOR_STRING_VALUE,
  48. 0,
  49. 0x1F,
  50. 2,
  51. 8,
  52. 0,
  53. 0,
  54. {0},
  55. {'_', 'D', 'M', 'I', '_'},
  56. 0,
  57. 0,
  58. 0,
  59. 0,
  60. 0x28
  61. };
  62. //
  63. // ------------------------------------------------------------------ Functions
  64. //
  65. EFIAPI
  66. EFI_STATUS
  67. EfiSmbiosDriverEntry (
  68. EFI_HANDLE ImageHandle,
  69. EFI_SYSTEM_TABLE *SystemTable
  70. )
  71. /*++
  72. Routine Description:
  73. This routine is the entry point into the SMBIOS driver.
  74. Arguments:
  75. ImageHandle - Supplies the driver image handle.
  76. SystemTable - Supplies a pointer to the EFI system table.
  77. Return Value:
  78. EFI status code.
  79. --*/
  80. {
  81. return EFI_SUCCESS;
  82. }
  83. EFIAPI
  84. EFI_STATUS
  85. EfiSmbiosAddStructure (
  86. VOID *Table,
  87. ...
  88. )
  89. /*++
  90. Routine Description:
  91. This routine adds an SMBIOS structure to the SMBIOS table.
  92. Arguments:
  93. Table - Supplies a pointer to the table to add. A copy of this data will be
  94. made. The length of the table must be correctly filled in.
  95. ... - Supplies an array of pointers to strings to add to the end of the
  96. table. This list must be terminated with a NULL.
  97. Return Value:
  98. EFI_SUCCESS on success.
  99. EFI_INSUFFICIENT_RESOURCES if a memory allocation failed.
  100. --*/
  101. {
  102. EFI_PHYSICAL_ADDRESS Allocation;
  103. UINTN AllocationSize;
  104. CHAR8 *Argument;
  105. VA_LIST ArgumentList;
  106. UINTN ChecksumOffset;
  107. CHAR8 *CurrentPointer;
  108. PSMBIOS_ENTRY_POINT EntryPoint;
  109. UINTN Offset;
  110. UINTN PageCount;
  111. EFI_STATUS Status;
  112. UINTN StringLength;
  113. UINTN StringsLength;
  114. UINTN StructureSize;
  115. PSMBIOS_HEADER TableHeader;
  116. //
  117. // Loop through the arguments once to count the string lengths.
  118. //
  119. StringsLength = 1;
  120. VA_START(ArgumentList, Table);
  121. Argument = VA_ARG(ArgumentList, CHAR8 *);
  122. while (Argument != NULL) {
  123. StringsLength += RtlStringLength(Argument) + 1;
  124. Argument = VA_ARG(ArgumentList, CHAR8 *);
  125. }
  126. VA_END(ArgumentList);
  127. if (StringsLength < 2) {
  128. StringsLength = 2;
  129. }
  130. //
  131. // Compute the total length of the new table.
  132. //
  133. TableHeader = Table;
  134. StructureSize = TableHeader->Length + StringsLength;
  135. AllocationSize = EfiSmbiosAllocationSize + StructureSize;
  136. if (EfiSmbiosAllocationSize == 0) {
  137. AllocationSize += sizeof(SMBIOS_ENTRY_POINT);
  138. }
  139. PageCount = EFI_SIZE_TO_PAGES(AllocationSize);
  140. //
  141. // Allocate more pages if needed.
  142. //
  143. if (PageCount > EfiSmbiosPageCount) {
  144. Status = EfiAllocatePages(AllocateAnyPages,
  145. EfiACPIReclaimMemory,
  146. PageCount,
  147. &Allocation);
  148. if (EFI_ERROR(Status)) {
  149. return Status;
  150. }
  151. //
  152. // If this is the first table, copy the template over.
  153. //
  154. if (EfiSmbiosAllocationSize == 0) {
  155. EfiCopyMem((VOID *)(UINTN)Allocation,
  156. &EfiSmbiosEntryPointTemplate,
  157. sizeof(SMBIOS_ENTRY_POINT));
  158. EfipSmbiosChecksumTable(
  159. (VOID *)(UINTN)Allocation,
  160. EfiSmbiosEntryPointTemplate.EntryPointLength,
  161. OFFSET_OF(SMBIOS_ENTRY_POINT, Checksum));
  162. EfiSmbiosAllocationSize = sizeof(SMBIOS_ENTRY_POINT);
  163. //
  164. // Copy the existing tables, and free the old memory.
  165. //
  166. } else {
  167. EfiCopyMem((VOID *)(UINTN)Allocation,
  168. EfiSmbiosEntryPoint,
  169. EfiSmbiosAllocationSize);
  170. EfiFreePages((EFI_PHYSICAL_ADDRESS)(UINTN)EfiSmbiosEntryPoint,
  171. EfiSmbiosPageCount);
  172. }
  173. EfiSmbiosEntryPoint = (VOID *)(UINTN)Allocation;
  174. EfiSmbiosPageCount = PageCount;
  175. //
  176. // Install the new table.
  177. //
  178. Status = EfiInstallConfigurationTable(&EfiSmbiosTableGuid,
  179. EfiSmbiosEntryPoint);
  180. if (EFI_ERROR(Status)) {
  181. return Status;
  182. }
  183. }
  184. //
  185. // Copy the new structure onto the end.
  186. //
  187. RtlCopyMemory(EfiSmbiosEntryPoint + EfiSmbiosAllocationSize,
  188. TableHeader,
  189. TableHeader->Length);
  190. StringsLength = 0;
  191. CurrentPointer = EfiSmbiosEntryPoint +
  192. EfiSmbiosAllocationSize +
  193. TableHeader->Length;
  194. VA_START(ArgumentList, Table);
  195. Argument = VA_ARG(ArgumentList, CHAR8 *);
  196. while (Argument != NULL) {
  197. StringLength = RtlStringLength(Argument) + 1;
  198. EfiCopyMem(CurrentPointer, Argument, StringLength);
  199. StringsLength += StringLength;
  200. CurrentPointer += StringLength;
  201. Argument = VA_ARG(ArgumentList, CHAR8 *);
  202. }
  203. VA_END(ArgumentList);
  204. *CurrentPointer = '\0';
  205. CurrentPointer += 1;
  206. StringsLength += 1;
  207. if (StringsLength < 2) {
  208. *CurrentPointer = '\0';
  209. StringsLength += 1;
  210. }
  211. //
  212. // Update the header.
  213. //
  214. EfiSmbiosAllocationSize += StructureSize;
  215. EntryPoint = EfiSmbiosEntryPoint;
  216. EntryPoint->NumberOfStructures += 1;
  217. if (EntryPoint->MaxStructureSize < StructureSize) {
  218. EntryPoint->MaxStructureSize = StructureSize;
  219. }
  220. EntryPoint->StructureTableLength = EfiSmbiosAllocationSize -
  221. sizeof(SMBIOS_ENTRY_POINT);
  222. EntryPoint->StructureTableAddress =
  223. (UINT32)(UINTN)(EfiSmbiosEntryPoint +
  224. sizeof(SMBIOS_ENTRY_POINT));
  225. Offset = OFFSET_OF(SMBIOS_ENTRY_POINT, IntermediateAnchor);
  226. ChecksumOffset = OFFSET_OF(SMBIOS_ENTRY_POINT, IntermediateChecksum) -
  227. Offset;
  228. EfipSmbiosChecksumTable(EfiSmbiosEntryPoint + Offset,
  229. sizeof(SMBIOS_ENTRY_POINT) - Offset,
  230. ChecksumOffset);
  231. return EFI_SUCCESS;
  232. }
  233. //
  234. // --------------------------------------------------------- Internal Functions
  235. //
  236. VOID
  237. EfipSmbiosChecksumTable (
  238. VOID *Buffer,
  239. UINTN Size,
  240. UINTN ChecksumOffset
  241. )
  242. /*++
  243. Routine Description:
  244. This routine checksums the SMBIOS entry point.
  245. Arguments:
  246. Buffer - Supplies a pointer to the table to checksum.
  247. Size - Supplies the size of the table in bytes.
  248. ChecksumOffset - Supplies the offset of the 8 bit checksum field.
  249. Return Value:
  250. None.
  251. --*/
  252. {
  253. UINT8 *Pointer;
  254. UINT8 Sum;
  255. Sum = 0;
  256. Pointer = Buffer;
  257. Pointer[ChecksumOffset] = 0;
  258. while (Size != 0) {
  259. Sum = (UINT8)(Sum + *Pointer);
  260. Pointer += 1;
  261. Size -= 1;
  262. }
  263. Pointer = Buffer;
  264. Pointer[ChecksumOffset] = (UINT8)(0xFF - Sum + 1);
  265. return;
  266. }