1
0

fvsect.c 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121
  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. fvsect.c
  9. Abstract:
  10. This module implements section extraction support for UEFI firmware
  11. volumes.
  12. Author:
  13. Evan Green 11-Mar-2014
  14. Environment:
  15. Firmware
  16. --*/
  17. //
  18. // ------------------------------------------------------------------- Includes
  19. //
  20. #include "ueficore.h"
  21. #include "fwvolp.h"
  22. //
  23. // ---------------------------------------------------------------- Definitions
  24. //
  25. #define EFI_SECTION_STREAM_NODE_MAGIC 0x6D727453 // 'mrtS'
  26. #define EFI_SECTION_STREAM_CHILD_MAGIC 0x72745343 // 'rtSC'
  27. #define NULL_STREAM_HANDLE 0
  28. //
  29. // ------------------------------------------------------ Data Type Definitions
  30. //
  31. /*++
  32. Structure Description:
  33. This structure defines EFI firmware volume section stream data.
  34. Members:
  35. Magic - Stores the magic value EFI_SECTION_STREAM_CHILD_MAGIC.
  36. ListEntry - Stores pointers to the next and previous child nodes in the
  37. stream.
  38. Type - Stores the type of child section.
  39. Size - Stores the size of the child section.
  40. OffsetInStream - Stores the offset from the beginning of the stream base to
  41. the section header in the stream.
  42. EncapsulatedStreamHandle - Stores 0 if the section is not an
  43. encapsulating section. Otherwise, it contains the stream handle of the
  44. encapsulated stream. This handle is always produced any time an
  45. encapsulating child is encountered, irrespective of whether or not the
  46. encapsulated stream is processed further.
  47. EncapsulationGuid - Stores the GUID of the encapsulation protocol.
  48. Event - Stores the event used to register for notification of the
  49. GUIDed extraction protocol arrival.
  50. --*/
  51. typedef struct _EFI_SECTION_CHILD_NODE {
  52. ULONG Magic;
  53. LIST_ENTRY ListEntry;
  54. UINT32 Type;
  55. UINT32 Size;
  56. UINT32 OffsetInStream;
  57. UINTN EncapsulatedStreamHandle;
  58. EFI_GUID *EncapsulationGuid;
  59. EFI_EVENT Event;
  60. } EFI_SECTION_CHILD_NODE, *PEFI_SECTION_CHILD_NODE;
  61. /*++
  62. Structure Description:
  63. This structure defines EFI firmware volume section stream data.
  64. Members:
  65. Magic - Stores the magic value EFI_SECTION_STREAM_NODE_MAGIC.
  66. ListEntry - Stores pointers to the next and previous stream nodes in the
  67. global list.
  68. StreamHandle - Stores the stream handle value.
  69. StreamBuffer - Stores a pointer to the stream data.
  70. StreamLength - Stores the size of the stream data in bytes.
  71. ChildList - Stores the list of child sections.
  72. AuthenticationStatus - Stores the authentication status for GUIDed
  73. extractions.
  74. --*/
  75. typedef struct _EFI_SECTION_STREAM_NODE {
  76. ULONG Magic;
  77. LIST_ENTRY ListEntry;
  78. UINTN StreamHandle;
  79. UINT8 *StreamBuffer;
  80. UINTN StreamLength;
  81. LIST_ENTRY ChildList;
  82. UINT32 AuthenticationStatus;
  83. } EFI_SECTION_STREAM_NODE, *PEFI_SECTION_STREAM_NODE;
  84. //
  85. // ----------------------------------------------- Internal Function Prototypes
  86. //
  87. EFIAPI
  88. EFI_STATUS
  89. EfipFvOpenSectionStream (
  90. UINTN SectionStreamLength,
  91. VOID *SectionStream,
  92. BOOLEAN AllocateBuffer,
  93. UINT32 AuthenticationStatus,
  94. UINTN *SectionStreamHandle
  95. );
  96. EFI_STATUS
  97. EfipFvCreateChildNode (
  98. PEFI_SECTION_STREAM_NODE Stream,
  99. UINT32 ChildOffset,
  100. PEFI_SECTION_CHILD_NODE *ChildNode
  101. );
  102. EFI_STATUS
  103. EfipFvFindChildNode (
  104. PEFI_SECTION_STREAM_NODE SourceStream,
  105. EFI_SECTION_TYPE SearchType,
  106. UINTN *SectionInstance,
  107. EFI_GUID *SectionDefinitionGuid,
  108. PEFI_SECTION_CHILD_NODE *FoundChild,
  109. PEFI_SECTION_STREAM_NODE *FoundStream,
  110. UINT32 *AuthenticationStatus
  111. );
  112. BOOLEAN
  113. EfipFvIsValidSectionStream (
  114. VOID *SectionStream,
  115. UINTN SectionStreamLength
  116. );
  117. EFI_STATUS
  118. EfipFvFindStreamNode (
  119. UINTN SearchHandle,
  120. PEFI_SECTION_STREAM_NODE *FoundStream
  121. );
  122. BOOLEAN
  123. EfipFvChildIsType (
  124. PEFI_SECTION_STREAM_NODE Stream,
  125. PEFI_SECTION_CHILD_NODE Child,
  126. EFI_SECTION_TYPE SearchType,
  127. EFI_GUID *SectionDefinitionGuid
  128. );
  129. VOID
  130. EfipFvFreeChildNode (
  131. PEFI_SECTION_CHILD_NODE ChildNode
  132. );
  133. //
  134. // -------------------------------------------------------------------- Globals
  135. //
  136. LIST_ENTRY EfiStreamRoot;
  137. //
  138. // ------------------------------------------------------------------ Functions
  139. //
  140. EFIAPI
  141. EFI_STATUS
  142. EfiFvInitializeSectionExtraction (
  143. EFI_HANDLE ImageHandle,
  144. EFI_SYSTEM_TABLE *SystemTable
  145. )
  146. /*++
  147. Routine Description:
  148. This routine initializes the section extraction support for firmware
  149. volumes.
  150. Arguments:
  151. ImageHandle - Supplies a pointer to the image handle.
  152. SystemTable - Supplies a pointer to the EFI system table.
  153. Return Value:
  154. EFI status code.
  155. --*/
  156. {
  157. INITIALIZE_LIST_HEAD(&EfiStreamRoot);
  158. return EFI_SUCCESS;
  159. }
  160. EFIAPI
  161. EFI_STATUS
  162. EfiFvOpenSectionStream (
  163. UINTN SectionStreamLength,
  164. VOID *SectionStream,
  165. UINTN *SectionStreamHandle
  166. )
  167. /*++
  168. Routine Description:
  169. This routine creates and returns a new section stream handle to represent
  170. a new section stream.
  171. Arguments:
  172. SectionStreamLength - Supplies the size in bytes of the section stream.
  173. SectionStream - Supplies the section stream.
  174. SectionStreamHandle - Supplies a pointer where a handle to the stream will
  175. be returned.
  176. Return Value:
  177. EFI_SUCCESS on success.
  178. EFI_OUT_OF_RESOURCES if memory allocation failed.
  179. EFI_INVALID_PARAMETER if the section stream does not end noincidentally to
  180. the end of the previous section.
  181. --*/
  182. {
  183. EFI_STATUS Status;
  184. if (EfipFvIsValidSectionStream(SectionStream, SectionStreamLength) ==
  185. FALSE) {
  186. return EFI_INVALID_PARAMETER;
  187. }
  188. Status = EfipFvOpenSectionStream(SectionStreamLength,
  189. SectionStream,
  190. TRUE,
  191. 0,
  192. SectionStreamHandle);
  193. return Status;
  194. }
  195. EFIAPI
  196. EFI_STATUS
  197. EfiFvCloseSectionStream (
  198. UINTN StreamHandle
  199. )
  200. /*++
  201. Routine Description:
  202. This routine closes an open section stream handle.
  203. Arguments:
  204. StreamHandle - Supplies the stream handle previously returned.
  205. Return Value:
  206. EFI status code.
  207. --*/
  208. {
  209. PEFI_SECTION_CHILD_NODE ChildNode;
  210. EFI_TPL OldTpl;
  211. EFI_STATUS Status;
  212. PEFI_SECTION_STREAM_NODE StreamNode;
  213. OldTpl = EfiCoreRaiseTpl(TPL_NOTIFY);
  214. Status = EfipFvFindStreamNode(StreamHandle, &StreamNode);
  215. if (!EFI_ERROR(Status)) {
  216. LIST_REMOVE(&(StreamNode->ListEntry));
  217. while (LIST_EMPTY(&(StreamNode->ChildList)) == FALSE) {
  218. ChildNode = LIST_VALUE(StreamNode->ChildList.Next,
  219. EFI_SECTION_CHILD_NODE,
  220. ListEntry);
  221. EfipFvFreeChildNode(ChildNode);
  222. }
  223. EfiCoreFreePool(StreamNode->StreamBuffer);
  224. EfiCoreFreePool(StreamNode);
  225. Status = EFI_SUCCESS;
  226. } else {
  227. Status = EFI_INVALID_PARAMETER;
  228. }
  229. EfiCoreRestoreTpl(OldTpl);
  230. return Status;
  231. }
  232. EFIAPI
  233. EFI_STATUS
  234. EfiFvGetSection (
  235. UINTN SectionStreamHandle,
  236. EFI_SECTION_TYPE *SectionType,
  237. EFI_GUID *SectionDefinitionGuid,
  238. UINTN SectionInstance,
  239. VOID **Buffer,
  240. UINTN *BufferSize,
  241. UINT32 *AuthenticationStatus,
  242. BOOLEAN IsFfs3Fv
  243. )
  244. /*++
  245. Routine Description:
  246. This routine reads a section from a given section stream.
  247. Arguments:
  248. SectionStreamHandle - Supplies the stream handle of the stream to get the
  249. section from.
  250. SectionType - Supplies a pointer that on input contains the type of section
  251. to search for. On output, this will return the type of the section
  252. found.
  253. SectionDefinitionGuid - Supplies a pointer to the GUID of the section to
  254. search for if the section type indicates EFI_SECTION_GUID_DEFINED.
  255. SectionInstance - Supplies the instance of the requested section to
  256. return.
  257. Buffer - Supplies a pointer to a buffer value. If the value of the buffer
  258. is NULL, then the buffer is callee-allocated. If it is not NULL, then
  259. the supplied buffer is used.
  260. BufferSize - Supplies a pointer that on input contains the size of the
  261. buffer, if supplied. On output, the size of the section will be
  262. returned.
  263. AuthenticationStatus - Supplies a pointer where the authentication status
  264. will be returned.
  265. IsFfs3Fv - Supplies a boolean indicating if the firmware file system is
  266. version 3 (TRUE) or version 2 (FALSE).
  267. Return Value:
  268. EFI_SUCCESS on success.
  269. EFI_PROTOCOL_ERROR if a GUIDed section was encountered but no extraction
  270. protocol was found.
  271. EFI_NOT_FOUND if an error occurred while parsing the section stream, or the
  272. requested section does not exist.
  273. EFI_OUT_OF_RESOURCES on allocation failure.
  274. EFI_INVALID_PARAMETER if the given section stream handle does not exist.
  275. EFI_WARN_TOO_SMALL if a buffer value was supplied but it was not big enough
  276. to hold the requested section.
  277. --*/
  278. {
  279. PEFI_SECTION_CHILD_NODE ChildNode;
  280. PEFI_SECTION_STREAM_NODE ChildStreamNode;
  281. UINT8 *CopyBuffer;
  282. UINTN CopySize;
  283. UINT32 ExtractedAuthenticationStatus;
  284. UINTN Instance;
  285. EFI_TPL OldTpl;
  286. EFI_COMMON_SECTION_HEADER *Section;
  287. UINTN SectionSize;
  288. EFI_STATUS Status;
  289. PEFI_SECTION_STREAM_NODE StreamNode;
  290. OldTpl = EfiCoreRaiseTpl(TPL_NOTIFY);
  291. Instance = SectionInstance + 1;
  292. Status = EfipFvFindStreamNode(SectionStreamHandle, &StreamNode);
  293. if (EFI_ERROR(Status)) {
  294. Status = EFI_INVALID_PARAMETER;
  295. goto FvGetSectionEnd;
  296. }
  297. //
  298. // Locate and return the appropriate section. If the section type is NULL,
  299. // return the whole stream.
  300. //
  301. if (SectionType == NULL) {
  302. CopySize = StreamNode->StreamLength;
  303. CopyBuffer = StreamNode->StreamBuffer;
  304. *AuthenticationStatus = StreamNode->AuthenticationStatus;
  305. } else {
  306. Status = EfipFvFindChildNode(StreamNode,
  307. *SectionType,
  308. &Instance,
  309. SectionDefinitionGuid,
  310. &ChildNode,
  311. &ChildStreamNode,
  312. &ExtractedAuthenticationStatus);
  313. if (EFI_ERROR(Status)) {
  314. goto FvGetSectionEnd;
  315. }
  316. Section = (EFI_COMMON_SECTION_HEADER *)(ChildStreamNode->StreamBuffer +
  317. ChildNode->OffsetInStream);
  318. if (EFI_IS_SECTION2(Section)) {
  319. ASSERT(EFI_SECTION2_SIZE(Section) > 0x00FFFFFF);
  320. if (IsFfs3Fv == FALSE) {
  321. RtlDebugPrint("Error: FFS3 section in FFS2 volume.\n");
  322. Status = EFI_NOT_FOUND;
  323. goto FvGetSectionEnd;
  324. }
  325. CopySize = EFI_SECTION2_SIZE(Section) -
  326. sizeof(EFI_COMMON_SECTION_HEADER2);
  327. CopyBuffer = (UINT8 *)Section + sizeof(EFI_COMMON_SECTION_HEADER2);
  328. } else {
  329. CopySize = EFI_SECTION_SIZE(Section) -
  330. sizeof(EFI_COMMON_SECTION_HEADER);
  331. CopyBuffer = (UINT8 *)Section + sizeof(EFI_COMMON_SECTION_HEADER);
  332. }
  333. *AuthenticationStatus = ExtractedAuthenticationStatus;
  334. }
  335. SectionSize = CopySize;
  336. if (*Buffer != NULL) {
  337. if (*BufferSize < CopySize) {
  338. Status = EFI_WARN_BUFFER_TOO_SMALL;
  339. CopySize = *BufferSize;
  340. }
  341. } else {
  342. *Buffer = EfiCoreAllocateBootPool(CopySize);
  343. if (*Buffer == NULL) {
  344. Status = EFI_OUT_OF_RESOURCES;
  345. goto FvGetSectionEnd;
  346. }
  347. }
  348. EfiCoreCopyMemory(*Buffer, CopyBuffer, CopySize);
  349. *BufferSize = SectionSize;
  350. FvGetSectionEnd:
  351. EfiCoreRestoreTpl(OldTpl);
  352. return Status;
  353. }
  354. //
  355. // --------------------------------------------------------- Internal Functions
  356. //
  357. EFIAPI
  358. EFI_STATUS
  359. EfipFvOpenSectionStream (
  360. UINTN SectionStreamLength,
  361. VOID *SectionStream,
  362. BOOLEAN AllocateBuffer,
  363. UINT32 AuthenticationStatus,
  364. UINTN *SectionStreamHandle
  365. )
  366. /*++
  367. Routine Description:
  368. This routine creates and returns a new section stream handle to represent
  369. a new section stream.
  370. Arguments:
  371. SectionStreamLength - Supplies the size in bytes of the section stream.
  372. SectionStream - Supplies the section stream.
  373. AllocateBuffer - Supplies a boolean indicating whether to copy the stream
  374. buffer (TRUE) or use the buffer in-place (FALSE).
  375. AuthenticationStatus - Supplies the authentication status.
  376. SectionStreamHandle - Supplies a pointer where a handle to the stream will
  377. be returned.
  378. Return Value:
  379. EFI_SUCCESS on success.
  380. EFI_OUT_OF_RESOURCES if memory allocation failed.
  381. EFI_INVALID_PARAMETER if the section stream does not end noincidentally to
  382. the end of the previous section.
  383. --*/
  384. {
  385. PEFI_SECTION_STREAM_NODE NewStream;
  386. EFI_TPL OldTpl;
  387. NewStream = EfiCoreAllocateBootPool(sizeof(EFI_SECTION_STREAM_NODE));
  388. if (NewStream == NULL) {
  389. return EFI_OUT_OF_RESOURCES;
  390. }
  391. EfiCoreSetMemory(NewStream, sizeof(EFI_SECTION_STREAM_NODE), 0);
  392. if (AllocateBuffer != FALSE) {
  393. if (SectionStreamLength > 0) {
  394. NewStream->StreamBuffer =
  395. EfiCoreAllocateBootPool(SectionStreamLength);
  396. if (NewStream->StreamBuffer == NULL) {
  397. EfiCoreFreePool(NewStream);
  398. return EFI_OUT_OF_RESOURCES;
  399. }
  400. EfiCoreCopyMemory(NewStream->StreamBuffer,
  401. SectionStream,
  402. SectionStreamLength);
  403. }
  404. //
  405. // The caller supplied the buffer, use it directly.
  406. //
  407. } else {
  408. NewStream->StreamBuffer = SectionStream;
  409. }
  410. NewStream->Magic = EFI_SECTION_STREAM_NODE_MAGIC;
  411. NewStream->StreamHandle = (UINTN)NewStream;
  412. NewStream->StreamLength = SectionStreamLength;
  413. INITIALIZE_LIST_HEAD(&(NewStream->ChildList));
  414. NewStream->AuthenticationStatus = AuthenticationStatus;
  415. //
  416. // Add this shiny new stream to the list.
  417. //
  418. OldTpl = EfiCoreRaiseTpl(TPL_NOTIFY);
  419. INSERT_BEFORE(&(NewStream->ListEntry), &EfiStreamRoot);
  420. EfiCoreRestoreTpl(OldTpl);
  421. *SectionStreamHandle = NewStream->StreamHandle;
  422. return EFI_SUCCESS;
  423. }
  424. EFI_STATUS
  425. EfipFvCreateChildNode (
  426. PEFI_SECTION_STREAM_NODE Stream,
  427. UINT32 ChildOffset,
  428. PEFI_SECTION_CHILD_NODE *ChildNode
  429. )
  430. /*++
  431. Routine Description:
  432. This routine parses and creates a new child node.
  433. Arguments:
  434. Stream - Supplies a pointer to the stream to parse.
  435. ChildOffset - Supplies the offset within the stream to parse from.
  436. ChildNode - Supplies a pointer where a pointer to the newly created child
  437. will be returned.
  438. Return Value:
  439. EFI_SUCCESS on success.
  440. EFI_PROTOCOL_ERROR if the GUIDed extraction protocol needed does not
  441. exist.
  442. --*/
  443. {
  444. PEFI_SECTION_CHILD_NODE Node;
  445. EFI_COMMON_SECTION_HEADER *SectionHeader;
  446. EFI_STATUS Status;
  447. SectionHeader = (EFI_COMMON_SECTION_HEADER *)(Stream->StreamBuffer +
  448. ChildOffset);
  449. *ChildNode = EfiCoreAllocateBootPool(sizeof(EFI_SECTION_CHILD_NODE));
  450. if (*ChildNode == NULL) {
  451. return EFI_OUT_OF_RESOURCES;
  452. }
  453. Node = *ChildNode;
  454. EfiCoreSetMemory(Node, sizeof(EFI_SECTION_CHILD_NODE), 0);
  455. Node->Magic = EFI_SECTION_STREAM_CHILD_MAGIC;
  456. Node->Type = SectionHeader->Elements.Type;
  457. if (EFI_IS_SECTION2(SectionHeader)) {
  458. Node->Size = EFI_SECTION2_SIZE(SectionHeader);
  459. } else {
  460. Node->Size = EFI_SECTION_SIZE(SectionHeader);
  461. }
  462. Node->OffsetInStream = ChildOffset;
  463. Node->EncapsulatedStreamHandle = NULL_STREAM_HANDLE;
  464. Node->EncapsulationGuid = NULL;
  465. switch (Node->Type) {
  466. //
  467. // Handle compressed encapsulation sections.
  468. //
  469. case EFI_SECTION_COMPRESSION:
  470. Status = EFI_SUCCESS;
  471. break;
  472. //
  473. // Handle GUIDed encapsulation sections.
  474. //
  475. case EFI_SECTION_GUID_DEFINED:
  476. Status = EFI_SUCCESS;
  477. break;
  478. //
  479. // No processing is needed on leaf nodes.
  480. //
  481. default:
  482. Status = EFI_SUCCESS;
  483. break;
  484. }
  485. INSERT_BEFORE(&(Node->ListEntry), &(Stream->ChildList));
  486. return Status;
  487. }
  488. EFI_STATUS
  489. EfipFvFindChildNode (
  490. PEFI_SECTION_STREAM_NODE SourceStream,
  491. EFI_SECTION_TYPE SearchType,
  492. UINTN *SectionInstance,
  493. EFI_GUID *SectionDefinitionGuid,
  494. PEFI_SECTION_CHILD_NODE *FoundChild,
  495. PEFI_SECTION_STREAM_NODE *FoundStream,
  496. UINT32 *AuthenticationStatus
  497. )
  498. /*++
  499. Routine Description:
  500. This routine recursively searches for and builds the section stream
  501. database looking for the requested section.
  502. Arguments:
  503. SourceStream - Supplies a pointer to the stream to search.
  504. SearchType - Supplies the type of section to search for.
  505. SectionInstance - Supplies a pointer to the section instance to find. This
  506. is an in/out parameter to handle recursion.
  507. SectionDefinitionGuid - Supplies a pointer where the GUID of the section
  508. will be returned.
  509. FoundChild - Supplies a pointer where the child node will be returned on
  510. success.
  511. FoundStream - Supplies a pointer where the stream corresponding with the
  512. child will be returned on success.
  513. AuthenticationStatus - Supplies a pointer to the authentication status.
  514. Return Value:
  515. EFI_SUCCESS on success.
  516. EFI_NOT_FOUND if the requested child node does not exist.
  517. EFI_PROTOCOL_ERROR if a required GUIDed section extraction protocol does
  518. not exist.
  519. --*/
  520. {
  521. PEFI_SECTION_CHILD_NODE CurrentChildNode;
  522. VOID *EncapsulatedStream;
  523. EFI_STATUS ErrorStatus;
  524. BOOLEAN Match;
  525. UINT32 NextChildOffset;
  526. PEFI_SECTION_CHILD_NODE RecursedChildNode;
  527. PEFI_SECTION_STREAM_NODE RecursedFoundStream;
  528. EFI_STATUS Status;
  529. CurrentChildNode = NULL;
  530. ErrorStatus = EFI_NOT_FOUND;
  531. if (SourceStream->StreamLength == 0) {
  532. return EFI_NOT_FOUND;
  533. }
  534. //
  535. // If the stream exists but not child nodes have been parsed out yet, then
  536. // extract the first child.
  537. //
  538. if ((LIST_EMPTY(&(SourceStream->ChildList)) != FALSE) &&
  539. (SourceStream->StreamLength >= sizeof(EFI_COMMON_SECTION_HEADER))) {
  540. Status = EfipFvCreateChildNode(SourceStream, 0, &CurrentChildNode);
  541. if (EFI_ERROR(Status)) {
  542. return Status;
  543. }
  544. }
  545. //
  546. // At least one child has been parsed out of the section stream. So walk
  547. // through the sections that have already been parsed out looking for the
  548. // requested section. If necessary, continue parsing section stream and
  549. // adding children until either the requested section is found, or the
  550. // stream ends.
  551. //
  552. CurrentChildNode = LIST_VALUE(SourceStream->ChildList.Next,
  553. EFI_SECTION_CHILD_NODE,
  554. ListEntry);
  555. while (TRUE) {
  556. ASSERT((CurrentChildNode != NULL) &&
  557. (CurrentChildNode->Magic == EFI_SECTION_STREAM_CHILD_MAGIC));
  558. Match = EfipFvChildIsType(SourceStream,
  559. CurrentChildNode,
  560. SearchType,
  561. SectionDefinitionGuid);
  562. if (Match != FALSE) {
  563. *SectionInstance -= 1;
  564. if (*SectionInstance == 0) {
  565. *FoundChild = CurrentChildNode;
  566. *FoundStream = SourceStream;
  567. *AuthenticationStatus = SourceStream->AuthenticationStatus;
  568. return EFI_SUCCESS;
  569. }
  570. }
  571. //
  572. // If the current node is an encapsulating node, recurse into it.
  573. //
  574. if (CurrentChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {
  575. EncapsulatedStream =
  576. (VOID *)(CurrentChildNode->EncapsulatedStreamHandle);
  577. Status = EfipFvFindChildNode(
  578. (PEFI_SECTION_STREAM_NODE)EncapsulatedStream,
  579. SearchType,
  580. SectionInstance,
  581. SectionDefinitionGuid,
  582. &RecursedChildNode,
  583. &RecursedFoundStream,
  584. AuthenticationStatus);
  585. //
  586. // If the recursion was not successful, save the error code and
  587. // continue to find the requested child node in the rest of the
  588. // stream.
  589. //
  590. if (*SectionInstance == 0) {
  591. ASSERT(!EFI_ERROR(Status));
  592. *FoundChild = RecursedChildNode;
  593. *FoundStream = RecursedFoundStream;
  594. return Status;
  595. } else {
  596. ErrorStatus = Status;
  597. }
  598. //
  599. // If the node type is GUIDed, but the node has no encapsulating data,
  600. // node data should not be parsed because a required GUIDed section
  601. // extraction protocol does not exist.
  602. //
  603. } else if ((CurrentChildNode->Type == EFI_SECTION_GUID_DEFINED) &&
  604. (SearchType != EFI_SECTION_GUID_DEFINED)) {
  605. ErrorStatus = EFI_PROTOCOL_ERROR;
  606. }
  607. //
  608. // If there are more parsed nodes, go look through them.
  609. //
  610. if (CurrentChildNode->ListEntry.Next != &(SourceStream->ChildList)) {
  611. CurrentChildNode = LIST_VALUE(CurrentChildNode->ListEntry.Next,
  612. EFI_SECTION_CHILD_NODE,
  613. ListEntry);
  614. //
  615. // This is the end of the list of parsed nodes. See if there's any more
  616. // data and continue parsing out more children if there is.
  617. //
  618. } else {
  619. NextChildOffset = CurrentChildNode->OffsetInStream +
  620. CurrentChildNode->Size;
  621. NextChildOffset = ALIGN_VALUE(NextChildOffset, 4);
  622. if (NextChildOffset <=
  623. (SourceStream->StreamLength -
  624. sizeof(EFI_COMMON_SECTION_HEADER))) {
  625. Status = EfipFvCreateChildNode(SourceStream,
  626. NextChildOffset,
  627. &CurrentChildNode);
  628. if (EFI_ERROR(Status)) {
  629. return Status;
  630. }
  631. } else {
  632. ASSERT(EFI_ERROR(ErrorStatus));
  633. return ErrorStatus;
  634. }
  635. }
  636. }
  637. //
  638. // Execution should never actually get here.
  639. //
  640. ASSERT(FALSE);
  641. return EFI_NOT_FOUND;
  642. }
  643. BOOLEAN
  644. EfipFvIsValidSectionStream (
  645. VOID *SectionStream,
  646. UINTN SectionStreamLength
  647. )
  648. /*++
  649. Routine Description:
  650. This routine determines whether or not a stream is valid.
  651. Arguments:
  652. SectionStream - Supplies the section stream to check.
  653. SectionStreamLength - Supplies the size in bytes of the section stream.
  654. Return Value:
  655. TRUE if the section stream is valid.
  656. FALSE if the section stream is invalid.
  657. --*/
  658. {
  659. EFI_COMMON_SECTION_HEADER *NextSectionHeader;
  660. EFI_COMMON_SECTION_HEADER *SectionHeader;
  661. UINTN SectionLength;
  662. UINTN TotalLength;
  663. TotalLength = 0;
  664. SectionHeader = (EFI_COMMON_SECTION_HEADER *)SectionStream;
  665. while (TotalLength < SectionStreamLength) {
  666. if (EFI_IS_SECTION2(SectionHeader)) {
  667. SectionLength = EFI_SECTION2_SIZE(SectionHeader);
  668. } else {
  669. SectionLength = EFI_SECTION_SIZE(SectionHeader);
  670. }
  671. TotalLength += SectionLength;
  672. if (TotalLength == SectionStreamLength) {
  673. return TRUE;
  674. }
  675. //
  676. // Move to the next byte following the section, and figure out where
  677. // the next section begins.
  678. //
  679. SectionHeader = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)SectionHeader +
  680. SectionLength);
  681. NextSectionHeader = ALIGN_POINTER(SectionHeader, 4);
  682. TotalLength += (UINTN)NextSectionHeader - (UINTN)SectionHeader;
  683. SectionHeader = NextSectionHeader;
  684. }
  685. ASSERT(FALSE);
  686. return FALSE;
  687. }
  688. EFI_STATUS
  689. EfipFvFindStreamNode (
  690. UINTN SearchHandle,
  691. PEFI_SECTION_STREAM_NODE *FoundStream
  692. )
  693. /*++
  694. Routine Description:
  695. This routine finds the stream matching the given handle. This routine
  696. assumes the TPL has already been raised.
  697. Arguments:
  698. SearchHandle - Supplies the handle to search for.
  699. FoundStream - Supplies a pointer where a pointer to the stream will be
  700. returned on success.
  701. Return Value:
  702. EFI_SUCCESS on success.
  703. EFI_NOT_FOUND if a stream matching the given handle was not found.
  704. --*/
  705. {
  706. PLIST_ENTRY CurrentEntry;
  707. PEFI_SECTION_STREAM_NODE Node;
  708. CurrentEntry = EfiStreamRoot.Next;
  709. while (CurrentEntry != &EfiStreamRoot) {
  710. Node = LIST_VALUE(CurrentEntry, EFI_SECTION_STREAM_NODE, ListEntry);
  711. ASSERT(Node->Magic == EFI_SECTION_STREAM_NODE_MAGIC);
  712. if (Node->StreamHandle == SearchHandle) {
  713. *FoundStream = Node;
  714. return EFI_SUCCESS;
  715. }
  716. CurrentEntry = CurrentEntry->Next;
  717. }
  718. *FoundStream = NULL;
  719. return EFI_NOT_FOUND;
  720. }
  721. BOOLEAN
  722. EfipFvChildIsType (
  723. PEFI_SECTION_STREAM_NODE Stream,
  724. PEFI_SECTION_CHILD_NODE Child,
  725. EFI_SECTION_TYPE SearchType,
  726. EFI_GUID *SectionDefinitionGuid
  727. )
  728. /*++
  729. Routine Description:
  730. This routine determines if the given input stream and child matches the
  731. input type.
  732. Arguments:
  733. Stream - Supplies a pointer to the section stream associated with the child.
  734. Child - Supplies a pointer to the child to check.
  735. SearchType - Supplies the type of section to check for.
  736. SectionDefinitionGuid - Supplies the GUID to check against if the search
  737. type is EFI_SECTION_GUID_DEFINED.
  738. Return Value:
  739. TRUE if the section matches the parameters.
  740. FALSE if the section does not match.
  741. --*/
  742. {
  743. EFI_GUID_DEFINED_SECTION *GuidedSection;
  744. EFI_GUID_DEFINED_SECTION2 *GuidedSection2;
  745. EFI_GUID *SectionGuid;
  746. if (SearchType == EFI_SECTION_ALL) {
  747. return TRUE;
  748. }
  749. if (SearchType != Child->Type) {
  750. return FALSE;
  751. }
  752. if ((SearchType != EFI_SECTION_GUID_DEFINED) ||
  753. (SectionDefinitionGuid == NULL)) {
  754. return TRUE;
  755. }
  756. GuidedSection = (EFI_GUID_DEFINED_SECTION *)(Stream->StreamBuffer +
  757. Child->OffsetInStream);
  758. if (EFI_IS_SECTION2(GuidedSection)) {
  759. GuidedSection2 = (EFI_GUID_DEFINED_SECTION2 *)GuidedSection;
  760. SectionGuid = &(GuidedSection2->SectionDefinitionGuid);
  761. } else {
  762. SectionGuid = &(GuidedSection->SectionDefinitionGuid);
  763. }
  764. if (EfiCoreCompareGuids(SectionGuid, SectionDefinitionGuid) != FALSE) {
  765. return TRUE;
  766. }
  767. return FALSE;
  768. }
  769. VOID
  770. EfipFvFreeChildNode (
  771. PEFI_SECTION_CHILD_NODE ChildNode
  772. )
  773. /*++
  774. Routine Description:
  775. This routine destroys a firmware volume section child node.
  776. Arguments:
  777. ChildNode - Supplies the child node to destroy.
  778. Return Value:
  779. None.
  780. --*/
  781. {
  782. ASSERT(ChildNode->Magic == EFI_SECTION_STREAM_CHILD_MAGIC);
  783. LIST_REMOVE(&(ChildNode->ListEntry));
  784. if (ChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {
  785. EfiFvCloseSectionStream(ChildNode->EncapsulatedStreamHandle);
  786. }
  787. if (ChildNode->Event != NULL) {
  788. EfiCloseEvent(ChildNode->Event);
  789. }
  790. ChildNode->Magic = 0;
  791. EfiCoreFreePool(ChildNode);
  792. return;
  793. }