FvbSmmDxe.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944
  1. /** @file
  2. Implement the Firmware Volume Block (FVB) services based on SMM FVB
  3. module and install FVB protocol.
  4. Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved. <BR>
  5. SPDX-License-Identifier: BSD-2-Clause-Patent
  6. **/
  7. #include "FvbSmmDxe.h"
  8. EFI_HANDLE mHandle = NULL;
  9. EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL;
  10. //
  11. // Template structure used when installing FVB protocol.
  12. //
  13. EFI_FVB_DEVICE mFvbDeviceTemplate = {
  14. FVB_DEVICE_SIGNATURE,
  15. NULL,
  16. {
  17. FvbGetAttributes,
  18. FvbSetAttributes,
  19. FvbGetPhysicalAddress,
  20. FvbGetBlockSize,
  21. FvbRead,
  22. FvbWrite,
  23. FvbEraseBlocks,
  24. NULL
  25. },
  26. NULL
  27. };
  28. FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate = {
  29. {
  30. {
  31. HARDWARE_DEVICE_PATH,
  32. HW_MEMMAP_DP,
  33. {
  34. (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
  35. (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)
  36. }
  37. },
  38. EfiMemoryMappedIO,
  39. (EFI_PHYSICAL_ADDRESS) 0,
  40. (EFI_PHYSICAL_ADDRESS) 0,
  41. },
  42. {
  43. END_DEVICE_PATH_TYPE,
  44. END_ENTIRE_DEVICE_PATH_SUBTYPE,
  45. {
  46. END_DEVICE_PATH_LENGTH,
  47. 0
  48. }
  49. }
  50. };
  51. FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate = {
  52. {
  53. {
  54. MEDIA_DEVICE_PATH,
  55. MEDIA_PIWG_FW_VOL_DP,
  56. {
  57. (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)),
  58. (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8)
  59. }
  60. },
  61. { 0 }
  62. },
  63. {
  64. END_DEVICE_PATH_TYPE,
  65. END_ENTIRE_DEVICE_PATH_SUBTYPE,
  66. {
  67. END_DEVICE_PATH_LENGTH,
  68. 0
  69. }
  70. }
  71. };
  72. /**
  73. Initialize the communicate buffer using DataSize and Function.
  74. The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +
  75. DataSize.
  76. @param[out] CommunicateBuffer The communicate buffer. Caller should free it after use.
  77. @param[out] DataPtr Points to the data in the communicate buffer. Caller should not free it.
  78. @param[in] DataSize The payload size.
  79. @param[in] Function The function number used to initialize the communicate header.
  80. @retval EFI_INVALID_PARAMETER The data size is too big.
  81. @retval EFI_SUCCESS Find the specified variable.
  82. **/
  83. EFI_STATUS
  84. InitCommunicateBuffer (
  85. OUT VOID **CommunicateBuffer,
  86. OUT VOID **DataPtr,
  87. IN UINTN DataSize,
  88. IN UINTN Function
  89. )
  90. {
  91. EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
  92. SMM_FVB_COMMUNICATE_FUNCTION_HEADER *SmmFvbFunctionHeader;
  93. //
  94. // The whole buffer size: SMM_COMMUNICATE_HEADER_SIZE + SMM_FVB_COMMUNICATE_HEADER_SIZE + DataSize.
  95. //
  96. SmmCommunicateHeader = AllocatePool (DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_FVB_COMMUNICATE_HEADER_SIZE);
  97. ASSERT (SmmCommunicateHeader != NULL);
  98. //
  99. // Prepare data buffer.
  100. //
  101. CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmFirmwareVolumeBlockProtocolGuid);
  102. SmmCommunicateHeader->MessageLength = DataSize + SMM_FVB_COMMUNICATE_HEADER_SIZE;
  103. SmmFvbFunctionHeader = (SMM_FVB_COMMUNICATE_FUNCTION_HEADER *) SmmCommunicateHeader->Data;
  104. SmmFvbFunctionHeader->Function = Function;
  105. *CommunicateBuffer = SmmCommunicateHeader;
  106. *DataPtr = SmmFvbFunctionHeader->Data;
  107. return EFI_SUCCESS;
  108. }
  109. /**
  110. Send the data in communicate buffer to SMM.
  111. @param[out] SmmCommunicateHeader The communicate buffer.
  112. @param[in] DataSize The payload size.
  113. **/
  114. EFI_STATUS
  115. SendCommunicateBuffer (
  116. IN EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader,
  117. IN UINTN DataSize
  118. )
  119. {
  120. EFI_STATUS Status;
  121. UINTN CommSize;
  122. SMM_FVB_COMMUNICATE_FUNCTION_HEADER *SmmFvbFunctionHeader;
  123. CommSize = DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_FVB_COMMUNICATE_HEADER_SIZE;
  124. Status = mSmmCommunication->Communicate (
  125. mSmmCommunication,
  126. SmmCommunicateHeader,
  127. &CommSize
  128. );
  129. ASSERT_EFI_ERROR (Status);
  130. SmmFvbFunctionHeader = (SMM_FVB_COMMUNICATE_FUNCTION_HEADER *) SmmCommunicateHeader->Data;
  131. return SmmFvbFunctionHeader->ReturnStatus;
  132. }
  133. /**
  134. This function retrieves the attributes and current settings of the block.
  135. @param[in] This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
  136. @param[out] Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the attributes
  137. and current settings are returned. Type EFI_FVB_ATTRIBUTES_2
  138. is defined in EFI_FIRMWARE_VOLUME_HEADER.
  139. @retval EFI_SUCCESS The firmware volume attributes were returned.
  140. @retval EFI_INVALID_PARAMETER Attributes is NULL.
  141. **/
  142. EFI_STATUS
  143. EFIAPI
  144. FvbGetAttributes (
  145. IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
  146. OUT EFI_FVB_ATTRIBUTES_2 *Attributes
  147. )
  148. {
  149. EFI_STATUS Status;
  150. UINTN PayloadSize;
  151. EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
  152. SMM_FVB_ATTRIBUTES_HEADER *SmmFvbAttributesHeader;
  153. EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb;
  154. EFI_FVB_DEVICE *FvbDevice;
  155. if (Attributes == NULL) {
  156. return EFI_INVALID_PARAMETER;
  157. }
  158. FvbDevice = FVB_DEVICE_FROM_THIS (This);
  159. SmmFvb = FvbDevice->SmmFvbInstance;
  160. //
  161. // Initialize the communicate buffer.
  162. //
  163. PayloadSize = sizeof (SMM_FVB_ATTRIBUTES_HEADER);
  164. Status = InitCommunicateBuffer (
  165. (VOID **)&SmmCommunicateHeader,
  166. (VOID **)&SmmFvbAttributesHeader,
  167. PayloadSize,
  168. EFI_FUNCTION_GET_ATTRIBUTES
  169. );
  170. if (EFI_ERROR (Status)) {
  171. return Status;
  172. }
  173. SmmFvbAttributesHeader->SmmFvb = SmmFvb;
  174. SmmFvbAttributesHeader->Attributes = 0;
  175. //
  176. // Send data to SMM.
  177. //
  178. Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);
  179. //
  180. // Get data from SMM.
  181. //
  182. *Attributes = SmmFvbAttributesHeader->Attributes;
  183. FreePool (SmmCommunicateHeader);
  184. return Status;
  185. }
  186. /**
  187. Sets Volume attributes. No polarity translations are done.
  188. @param[in] This Calling context.
  189. @param[out] Attributes Output buffer which contains attributes.
  190. @retval EFI_SUCCESS Set the Attributes successfully.
  191. @retval EFI_INVALID_PARAMETER Attributes is NULL.
  192. **/
  193. EFI_STATUS
  194. EFIAPI
  195. FvbSetAttributes (
  196. IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
  197. IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
  198. )
  199. {
  200. EFI_STATUS Status;
  201. UINTN PayloadSize;
  202. EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
  203. SMM_FVB_ATTRIBUTES_HEADER *SmmFvbAttributesHeader;
  204. EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb;
  205. EFI_FVB_DEVICE *FvbDevice;
  206. if (Attributes == NULL) {
  207. return EFI_INVALID_PARAMETER;
  208. }
  209. FvbDevice = FVB_DEVICE_FROM_THIS (This);
  210. SmmFvb = FvbDevice->SmmFvbInstance;
  211. //
  212. // Initialize the communicate buffer.
  213. //
  214. PayloadSize = sizeof (SMM_FVB_ATTRIBUTES_HEADER);
  215. Status = InitCommunicateBuffer (
  216. (VOID **)&SmmCommunicateHeader,
  217. (VOID **)&SmmFvbAttributesHeader,
  218. PayloadSize,
  219. EFI_FUNCTION_SET_ATTRIBUTES
  220. );
  221. if (EFI_ERROR (Status)) {
  222. return Status;
  223. }
  224. SmmFvbAttributesHeader->SmmFvb = SmmFvb;
  225. SmmFvbAttributesHeader->Attributes = *Attributes;
  226. //
  227. // Send data to SMM.
  228. //
  229. Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);
  230. //
  231. // Get data from SMM.
  232. //
  233. *Attributes = SmmFvbAttributesHeader->Attributes;
  234. FreePool (SmmCommunicateHeader);
  235. return Status;
  236. }
  237. /**
  238. Retrieves the physical address of the FVB instance.
  239. @param[in] SmmFvb A pointer to EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL.
  240. @param[out] Address Output buffer containing the address.
  241. @retval EFI_SUCCESS Get the address successfully.
  242. @retval Others Failed to get address.
  243. **/
  244. EFI_STATUS
  245. GetPhysicalAddress (
  246. IN EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb,
  247. OUT EFI_PHYSICAL_ADDRESS *Address
  248. )
  249. {
  250. EFI_STATUS Status;
  251. UINTN PayloadSize;
  252. EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
  253. SMM_FVB_PHYSICAL_ADDRESS_HEADER *SmmFvbPhysicalAddressHeader;
  254. //
  255. // Initialize the communicate buffer.
  256. //
  257. PayloadSize = sizeof (SMM_FVB_PHYSICAL_ADDRESS_HEADER);
  258. Status = InitCommunicateBuffer (
  259. (VOID **)&SmmCommunicateHeader,
  260. (VOID **)&SmmFvbPhysicalAddressHeader,
  261. PayloadSize,
  262. EFI_FUNCTION_GET_PHYSICAL_ADDRESS
  263. );
  264. if (EFI_ERROR (Status)) {
  265. return Status;
  266. }
  267. SmmFvbPhysicalAddressHeader->SmmFvb = SmmFvb;
  268. SmmFvbPhysicalAddressHeader->Address = 0;
  269. //
  270. // Send data to SMM.
  271. //
  272. Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);
  273. //
  274. // Get data from SMM.
  275. //
  276. *Address = SmmFvbPhysicalAddressHeader->Address;
  277. FreePool (SmmCommunicateHeader);
  278. return Status;
  279. }
  280. /**
  281. Retrieves the physical address of the FVB instance.
  282. @param[in] This A pointer to EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL.
  283. @param[out] Address Output buffer containing the address.
  284. @retval EFI_SUCCESS Get the address successfully.
  285. @retval Others Failed to get the address.
  286. **/
  287. EFI_STATUS
  288. EFIAPI
  289. FvbGetPhysicalAddress (
  290. IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
  291. OUT EFI_PHYSICAL_ADDRESS *Address
  292. )
  293. {
  294. EFI_STATUS Status;
  295. EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb;
  296. EFI_FVB_DEVICE *FvbDevice;
  297. if (Address == NULL) {
  298. return EFI_INVALID_PARAMETER;
  299. }
  300. FvbDevice = FVB_DEVICE_FROM_THIS (This);
  301. SmmFvb = FvbDevice->SmmFvbInstance;
  302. Status = GetPhysicalAddress (SmmFvb, Address);
  303. return Status;
  304. }
  305. /**
  306. Retrieve the size of a logical block.
  307. @param[in] This Calling context.
  308. @param[in] Lba Indicates which block to return the size for.
  309. @param[out] BlockSize A pointer to a caller allocated UINTN in which
  310. the size of the block is returned.
  311. @param[out] NumOfBlocks A pointer to a caller allocated UINTN in which the
  312. number of consecutive blocks starting with Lba is
  313. returned. All blocks in this range have a size of
  314. BlockSize.
  315. @retval EFI_SUCCESS Get BlockSize and NumOfBlocks successfully.
  316. @retval EFI_INVALID_PARAMETER BlockSize or NumOfBlocks are NULL.
  317. **/
  318. EFI_STATUS
  319. EFIAPI
  320. FvbGetBlockSize (
  321. IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
  322. IN EFI_LBA Lba,
  323. OUT UINTN *BlockSize,
  324. OUT UINTN *NumOfBlocks
  325. )
  326. {
  327. EFI_STATUS Status;
  328. UINTN PayloadSize;
  329. EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
  330. SMM_FVB_BLOCK_SIZE_HEADER *SmmFvbBlockSizeHeader;
  331. EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb;
  332. EFI_FVB_DEVICE *FvbDevice;
  333. if ((BlockSize == NULL) || (NumOfBlocks == NULL)) {
  334. return EFI_INVALID_PARAMETER;
  335. }
  336. FvbDevice = FVB_DEVICE_FROM_THIS (This);
  337. SmmFvb = FvbDevice->SmmFvbInstance;
  338. //
  339. // Initialize the communicate buffer.
  340. //
  341. PayloadSize = sizeof (SMM_FVB_BLOCK_SIZE_HEADER);
  342. Status = InitCommunicateBuffer (
  343. (VOID **)&SmmCommunicateHeader,
  344. (VOID **)&SmmFvbBlockSizeHeader,
  345. PayloadSize,
  346. EFI_FUNCTION_GET_BLOCK_SIZE
  347. );
  348. if (EFI_ERROR (Status)) {
  349. return Status;
  350. }
  351. SmmFvbBlockSizeHeader->SmmFvb = SmmFvb;
  352. SmmFvbBlockSizeHeader->Lba = Lba;
  353. //
  354. // Send data to SMM.
  355. //
  356. Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);
  357. //
  358. // Get data from SMM.
  359. //
  360. *BlockSize = SmmFvbBlockSizeHeader->BlockSize;
  361. *NumOfBlocks = SmmFvbBlockSizeHeader->NumOfBlocks;
  362. FreePool (SmmCommunicateHeader);
  363. return Status;
  364. }
  365. /**
  366. Reads data beginning at Lba:Offset from FV. The Read terminates either
  367. when *NumBytes of data have been read, or when a block boundary is
  368. reached. *NumBytes is updated to reflect the actual number of bytes
  369. written. The write opertion does not include erase. This routine will
  370. attempt to write only the specified bytes. If the writes do not stick,
  371. it will return an error.
  372. @param[in] This Calling context
  373. @param[in] Lba Block in which to begin write
  374. @param[in] Offset Offset in the block at which to begin write
  375. @param[in,out] NumBytes On input, indicates the requested write size. On
  376. output, indicates the actual number of bytes written
  377. @param[in] Buffer Buffer containing source data for the write.
  378. @retval EFI_SUCCESS The firmware volume was read successfully and
  379. contents are in Buffer.
  380. @retval EFI_BAD_BUFFER_SIZE Read attempted across a LBA boundary. On output,
  381. NumBytes contains the total number of bytes returned
  382. in Buffer.
  383. @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state
  384. @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
  385. could not be read.
  386. @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL.
  387. **/
  388. EFI_STATUS
  389. EFIAPI
  390. FvbRead (
  391. IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
  392. IN EFI_LBA Lba,
  393. IN UINTN Offset,
  394. IN OUT UINTN *NumBytes,
  395. OUT UINT8 *Buffer
  396. )
  397. {
  398. EFI_STATUS Status;
  399. UINTN PayloadSize;
  400. EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
  401. SMM_FVB_READ_WRITE_HEADER *SmmFvbReadWriteHeader;
  402. EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb;
  403. EFI_FVB_DEVICE *FvbDevice;
  404. if ((NumBytes == NULL) || (Buffer == NULL)) {
  405. return EFI_INVALID_PARAMETER;
  406. }
  407. FvbDevice = FVB_DEVICE_FROM_THIS (This);
  408. SmmFvb = FvbDevice->SmmFvbInstance;
  409. //
  410. // Initialize the communicate buffer.
  411. //
  412. PayloadSize = sizeof (SMM_FVB_READ_WRITE_HEADER) + *NumBytes;
  413. Status = InitCommunicateBuffer (
  414. (VOID **)&SmmCommunicateHeader,
  415. (VOID **)&SmmFvbReadWriteHeader,
  416. PayloadSize, EFI_FUNCTION_READ
  417. );
  418. if (EFI_ERROR (Status)) {
  419. return Status;
  420. }
  421. SmmFvbReadWriteHeader->SmmFvb = SmmFvb;
  422. SmmFvbReadWriteHeader->Lba = Lba;
  423. SmmFvbReadWriteHeader->Offset = Offset;
  424. SmmFvbReadWriteHeader->NumBytes = *NumBytes;
  425. //
  426. // Send data to SMM.
  427. //
  428. Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);
  429. //
  430. // Get data from SMM.
  431. //
  432. *NumBytes = SmmFvbReadWriteHeader->NumBytes;
  433. if (!EFI_ERROR (Status)) {
  434. CopyMem (Buffer, (UINT8 *)(SmmFvbReadWriteHeader + 1), *NumBytes);
  435. }
  436. FreePool (SmmCommunicateHeader);
  437. return Status;
  438. }
  439. /**
  440. Writes data beginning at Lba:Offset from FV. The write terminates either
  441. when *NumBytes of data have been written, or when a block boundary is
  442. reached. *NumBytes is updated to reflect the actual number of bytes
  443. written. The write opertion does not include erase. This routine will
  444. attempt to write only the specified bytes. If the writes do not stick,
  445. it will return an error.
  446. @param[in] This Calling context.
  447. @param[in] Lba Block in which to begin write.
  448. @param[in] Offset Offset in the block at which to begin write.
  449. @param[in,out] NumBytes On input, indicates the requested write size. On
  450. output, indicates the actual number of bytes written.
  451. @param[in] Buffer Buffer containing source data for the write.
  452. @retval EFI_SUCCESS The firmware volume was written successfully.
  453. @retval EFI_BAD_BUFFER_SIZE Write attempted across a LBA boundary. On output,
  454. NumBytes contains the total number of bytes
  455. actually written.
  456. @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state.
  457. @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
  458. could not be written.
  459. @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL.
  460. **/
  461. EFI_STATUS
  462. EFIAPI
  463. FvbWrite (
  464. IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
  465. IN EFI_LBA Lba,
  466. IN UINTN Offset,
  467. IN OUT UINTN *NumBytes,
  468. IN UINT8 *Buffer
  469. )
  470. {
  471. EFI_STATUS Status;
  472. UINTN PayloadSize;
  473. EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
  474. SMM_FVB_READ_WRITE_HEADER *SmmFvbReadWriteHeader;
  475. EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb;
  476. EFI_FVB_DEVICE *FvbDevice;
  477. if ((NumBytes == NULL) || (Buffer == NULL)) {
  478. return EFI_INVALID_PARAMETER;
  479. }
  480. FvbDevice = FVB_DEVICE_FROM_THIS (This);
  481. SmmFvb = FvbDevice->SmmFvbInstance;
  482. //
  483. // Initialize the communicate buffer.
  484. //
  485. PayloadSize = sizeof (SMM_FVB_READ_WRITE_HEADER) + *NumBytes;
  486. Status = InitCommunicateBuffer (
  487. (VOID **)&SmmCommunicateHeader,
  488. (VOID **)&SmmFvbReadWriteHeader,
  489. PayloadSize,
  490. EFI_FUNCTION_WRITE
  491. );
  492. if (EFI_ERROR (Status)) {
  493. return Status;
  494. }
  495. SmmFvbReadWriteHeader->SmmFvb = SmmFvb;
  496. SmmFvbReadWriteHeader->Lba = Lba;
  497. SmmFvbReadWriteHeader->Offset = Offset;
  498. SmmFvbReadWriteHeader->NumBytes = *NumBytes;
  499. CopyMem ((UINT8 *)(SmmFvbReadWriteHeader + 1), Buffer, *NumBytes);
  500. //
  501. // Send data to SMM.
  502. //
  503. Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);
  504. //
  505. // Get data from SMM.
  506. //
  507. *NumBytes = SmmFvbReadWriteHeader->NumBytes;
  508. FreePool (SmmCommunicateHeader);
  509. return Status;
  510. }
  511. /**
  512. The EraseBlock() function erases NumOfLba blocks started from StartingLba.
  513. @param[in] This Calling context.
  514. @param[in] StartingLba Starting LBA followed to erase.
  515. @param[in] NumOfLba Number of block to erase.
  516. @retval EFI_SUCCESS The erase request was successfully completed.
  517. @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state.
  518. @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
  519. could not be written. Firmware device may have been
  520. partially erased.
  521. **/
  522. EFI_STATUS
  523. EraseBlock (
  524. IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
  525. IN EFI_LBA StartingLba,
  526. IN UINTN NumOfLba
  527. )
  528. {
  529. EFI_STATUS Status;
  530. UINTN PayloadSize;
  531. EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
  532. SMM_FVB_BLOCKS_HEADER *SmmFvbBlocksHeader;
  533. EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb;
  534. EFI_FVB_DEVICE *FvbDevice;
  535. FvbDevice = FVB_DEVICE_FROM_THIS (This);
  536. SmmFvb = FvbDevice->SmmFvbInstance;
  537. //
  538. // Initialize the communicate buffer.
  539. //
  540. PayloadSize = sizeof (SMM_FVB_BLOCKS_HEADER);
  541. Status = InitCommunicateBuffer (
  542. (VOID **)&SmmCommunicateHeader,
  543. (VOID **)&SmmFvbBlocksHeader,
  544. PayloadSize,
  545. EFI_FUNCTION_ERASE_BLOCKS
  546. );
  547. if (EFI_ERROR (Status)) {
  548. return Status;
  549. }
  550. SmmFvbBlocksHeader->SmmFvb = SmmFvb;
  551. SmmFvbBlocksHeader->StartLba = StartingLba;
  552. SmmFvbBlocksHeader->NumOfLba = NumOfLba;
  553. //
  554. // Send data to SMM.
  555. //
  556. Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize);
  557. //
  558. // Get data from SMM.
  559. //
  560. FreePool (SmmCommunicateHeader);
  561. return Status;
  562. }
  563. /**
  564. The EraseBlocks() function erases one or more blocks as denoted by the
  565. variable argument list. The entire parameter list of blocks must be verified
  566. prior to erasing any blocks. If a block is requested that does not exist
  567. within the associated firmware volume (it has a larger index than the last
  568. block of the firmware volume), the EraseBlock() function must return
  569. EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
  570. @param[in] This Calling context/
  571. @param[in] ... Starting LBA followed by Number of Lba to erase.
  572. a -1 to terminate the list.
  573. /
  574. @retval EFI_SUCCESS The erase request was successfully completed
  575. @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state/
  576. @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
  577. could not be written. Firmware device may have been
  578. partially erased/
  579. **/
  580. EFI_STATUS
  581. EFIAPI
  582. FvbEraseBlocks (
  583. IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
  584. ...
  585. )
  586. {
  587. EFI_STATUS Status;
  588. VA_LIST Marker;
  589. EFI_LBA StartingLba;
  590. UINTN NumOfLba;
  591. Status = EFI_SUCCESS;
  592. //
  593. // Check the parameter.
  594. //
  595. VA_START (Marker, This);
  596. do {
  597. StartingLba = VA_ARG (Marker, EFI_LBA);
  598. if (StartingLba == EFI_LBA_LIST_TERMINATOR ) {
  599. break;
  600. }
  601. NumOfLba = VA_ARG (Marker, UINTN);
  602. if (NumOfLba == 0) {
  603. return EFI_INVALID_PARAMETER;
  604. }
  605. } while ( 1 );
  606. VA_END (Marker);
  607. //
  608. // Erase the blocks.
  609. //
  610. VA_START (Marker, This);
  611. do {
  612. StartingLba = VA_ARG (Marker, EFI_LBA);
  613. if (StartingLba == EFI_LBA_LIST_TERMINATOR ) {
  614. break;
  615. }
  616. NumOfLba = VA_ARG (Marker, UINTN);
  617. Status = EraseBlock (This, StartingLba, NumOfLba);
  618. if (EFI_ERROR (Status)) {
  619. break;
  620. }
  621. } while ( 1 );
  622. VA_END (Marker);
  623. return Status;
  624. }
  625. /**
  626. Install the FVB protocol which based on SMM FVB protocol.
  627. @param[in] SmmFvb The SMM FVB protocol.
  628. **/
  629. VOID
  630. InstallFvb (
  631. IN EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb
  632. )
  633. {
  634. EFI_STATUS Status;
  635. EFI_HANDLE FvbHandle;
  636. EFI_FVB_DEVICE *FvbDevice;
  637. EFI_FIRMWARE_VOLUME_HEADER *VolumeHeader;
  638. EFI_PHYSICAL_ADDRESS Address;
  639. EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFvbInterface;
  640. FvbDevice = AllocateRuntimeCopyPool (sizeof (EFI_FVB_DEVICE), &mFvbDeviceTemplate);
  641. ASSERT (FvbDevice != NULL);
  642. FvbDevice->SmmFvbInstance = SmmFvb;
  643. Status = gBS->LocateProtocol (
  644. &gEfiSmmCommunicationProtocolGuid,
  645. NULL,
  646. (VOID **) &mSmmCommunication
  647. );
  648. ASSERT_EFI_ERROR (Status);
  649. Status = GetPhysicalAddress (SmmFvb, &Address);
  650. ASSERT_EFI_ERROR (Status);
  651. VolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN)Address;
  652. //
  653. // Set up the devicepath.
  654. //
  655. if (VolumeHeader->ExtHeaderOffset == 0) {
  656. //
  657. // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH.
  658. //
  659. FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateRuntimeCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH), &mFvMemmapDevicePathTemplate);
  660. ((FV_MEMMAP_DEVICE_PATH *) FvbDevice->DevicePath)->MemMapDevPath.StartingAddress = (UINTN)Address;
  661. ((FV_MEMMAP_DEVICE_PATH *) FvbDevice->DevicePath)->MemMapDevPath.EndingAddress = (UINTN)Address + VolumeHeader->FvLength - 1;
  662. } else {
  663. FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateRuntimeCopyPool (sizeof (FV_PIWG_DEVICE_PATH), &mFvPIWGDevicePathTemplate);
  664. CopyGuid (
  665. &((FV_PIWG_DEVICE_PATH *)FvbDevice->DevicePath)->FvDevPath.FvName,
  666. (GUID *)(UINTN)((UINTN)Address + VolumeHeader->ExtHeaderOffset)
  667. );
  668. }
  669. //
  670. // Find a handle with a matching device path that has supports FW Block protocol.
  671. //
  672. Status = gBS->LocateDevicePath (
  673. &gEfiFirmwareVolumeBlockProtocolGuid,
  674. &FvbDevice->DevicePath,
  675. &FvbHandle
  676. );
  677. if (EFI_ERROR (Status) ) {
  678. //
  679. // LocateDevicePath fails so install a new interface and device path.
  680. //
  681. FvbHandle = NULL;
  682. Status = gBS->InstallMultipleProtocolInterfaces (
  683. &FvbHandle,
  684. &gEfiFirmwareVolumeBlockProtocolGuid,
  685. &FvbDevice->FvbInstance,
  686. &gEfiDevicePathProtocolGuid,
  687. FvbDevice->DevicePath,
  688. NULL
  689. );
  690. ASSERT_EFI_ERROR (Status);
  691. } else if (IsDevicePathEnd (FvbDevice->DevicePath)) {
  692. //
  693. // Device allready exists, so reinstall the FVB protocol.
  694. //
  695. Status = gBS->HandleProtocol (
  696. FvbHandle,
  697. &gEfiFirmwareVolumeBlockProtocolGuid,
  698. (VOID **) &OldFvbInterface
  699. );
  700. ASSERT_EFI_ERROR (Status);
  701. Status = gBS->ReinstallProtocolInterface (
  702. FvbHandle,
  703. &gEfiFirmwareVolumeBlockProtocolGuid,
  704. OldFvbInterface,
  705. &FvbDevice->FvbInstance
  706. );
  707. ASSERT_EFI_ERROR (Status);
  708. } else {
  709. //
  710. // There was a FVB protocol on an End Device Path node.
  711. //
  712. ASSERT (FALSE);
  713. }
  714. }
  715. /**
  716. SMM Firmware Volume Block Protocol notification event handler.
  717. Discover NV Variable Store and install Variable Write Arch Protocol.
  718. @param[in] Event Event whose notification function is being invoked.
  719. @param[in] Context Pointer to the notification function's context.
  720. **/
  721. VOID
  722. EFIAPI
  723. SmmFvbReady (
  724. IN EFI_EVENT Event,
  725. IN VOID *Context
  726. )
  727. {
  728. EFI_STATUS Status;
  729. EFI_HANDLE *HandleBuffer;
  730. UINTN HandleCount;
  731. UINTN Index;
  732. EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb;
  733. //
  734. // Locate all handles of Smm Fvb protocol.
  735. //
  736. Status = gBS->LocateHandleBuffer (
  737. ByProtocol,
  738. &gEfiSmmFirmwareVolumeBlockProtocolGuid,
  739. NULL,
  740. &HandleCount,
  741. &HandleBuffer
  742. );
  743. if (EFI_ERROR (Status)) {
  744. return ;
  745. }
  746. //
  747. // Install FVB protocol.
  748. //
  749. for (Index = 0; Index < HandleCount; Index++) {
  750. SmmFvb = NULL;
  751. Status = gBS->HandleProtocol (
  752. HandleBuffer[Index],
  753. &gEfiSmmFirmwareVolumeBlockProtocolGuid,
  754. (VOID **) &SmmFvb
  755. );
  756. if (EFI_ERROR (Status)) {
  757. break;
  758. }
  759. InstallFvb (SmmFvb);
  760. }
  761. FreePool (HandleBuffer);
  762. }
  763. /**
  764. The driver entry point for Firmware Volume Block Driver.
  765. The function does the necessary initialization work
  766. Firmware Volume Block Driver.
  767. @param[in] ImageHandle The firmware allocated handle for the UEFI image.
  768. @param[in] SystemTable A pointer to the EFI system table.
  769. @retval EFI_SUCCESS This funtion always return EFI_SUCCESS.
  770. It will ASSERT on errors.
  771. **/
  772. EFI_STATUS
  773. EFIAPI
  774. FvbSmmDxeInitialize (
  775. IN EFI_HANDLE ImageHandle,
  776. IN EFI_SYSTEM_TABLE *SystemTable
  777. )
  778. {
  779. VOID *SmmFvbRegistration;
  780. //
  781. // Smm FVB driver is ready.
  782. //
  783. EfiCreateProtocolNotifyEvent (
  784. &gEfiSmmFirmwareVolumeBlockProtocolGuid,
  785. TPL_CALLBACK,
  786. SmmFvbReady,
  787. NULL,
  788. &SmmFvbRegistration
  789. );
  790. return EFI_SUCCESS;
  791. }