smbios.c 7.7 KB

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