fvsect.c 27 KB

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