FvbService.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089
  1. /** @file
  2. Firmware Volume Block Driver to provide FVB service.
  3. Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include "FvbService.h"
  7. //
  8. // Global variable for this FVB driver which contains
  9. // the private data of all firmware volume block instances
  10. //
  11. FWB_GLOBAL mFvbModuleGlobal;
  12. FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate = {
  13. {
  14. {
  15. HARDWARE_DEVICE_PATH,
  16. HW_MEMMAP_DP,
  17. {
  18. (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
  19. (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)
  20. }
  21. },
  22. EfiMemoryMappedIO,
  23. (EFI_PHYSICAL_ADDRESS)0,
  24. (EFI_PHYSICAL_ADDRESS)0,
  25. },
  26. {
  27. END_DEVICE_PATH_TYPE,
  28. END_ENTIRE_DEVICE_PATH_SUBTYPE,
  29. {
  30. END_DEVICE_PATH_LENGTH,
  31. 0
  32. }
  33. }
  34. };
  35. FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate = {
  36. {
  37. {
  38. MEDIA_DEVICE_PATH,
  39. MEDIA_PIWG_FW_VOL_DP,
  40. {
  41. (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)),
  42. (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8)
  43. }
  44. },
  45. { 0 }
  46. },
  47. {
  48. END_DEVICE_PATH_TYPE,
  49. END_ENTIRE_DEVICE_PATH_SUBTYPE,
  50. {
  51. END_DEVICE_PATH_LENGTH,
  52. 0
  53. }
  54. }
  55. };
  56. EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = {
  57. FVB_DEVICE_SIGNATURE,
  58. NULL,
  59. 0, // Instance
  60. {
  61. FvbProtocolGetAttributes,
  62. FvbProtocolSetAttributes,
  63. FvbProtocolGetPhysicalAddress,
  64. FvbProtocolGetBlockSize,
  65. FvbProtocolRead,
  66. FvbProtocolWrite,
  67. FvbProtocolEraseBlocks,
  68. NULL
  69. } // FwVolBlockInstance
  70. };
  71. /**
  72. Get the pointer to EFI_FW_VOL_INSTANCE from the buffer pointed
  73. by mFvbModuleGlobal.FvInstance based on a index.
  74. Each EFI_FW_VOL_INSTANCE is with variable length as
  75. we have a block map at the end of the EFI_FIRMWARE_VOLUME_HEADER.
  76. @param[in] Instance The index of the EFI_FW_VOL_INSTANCE.
  77. @return A pointer to EFI_FW_VOL_INSTANCE.
  78. **/
  79. EFI_FW_VOL_INSTANCE *
  80. GetFvbInstance (
  81. IN UINTN Instance
  82. )
  83. {
  84. EFI_FW_VOL_INSTANCE *FwhRecord;
  85. if ( Instance >= mFvbModuleGlobal.NumFv ) {
  86. ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
  87. return NULL;
  88. }
  89. //
  90. // Find the right instance of the FVB private data
  91. //
  92. FwhRecord = mFvbModuleGlobal.FvInstance;
  93. while ( Instance > 0 ) {
  94. FwhRecord = (EFI_FW_VOL_INSTANCE *)((UINTN)((UINT8 *)FwhRecord) +
  95. FwhRecord->VolumeHeader.HeaderLength +
  96. (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)));
  97. Instance--;
  98. }
  99. return FwhRecord;
  100. }
  101. /**
  102. Get the EFI_FVB_ATTRIBUTES_2 of a FV.
  103. @param[in] Instance The index of the EFI_FW_VOL_INSTANCE.
  104. @retval EFI_FVB_ATTRIBUTES_2 of the FV identified by Instance.
  105. **/
  106. STATIC
  107. EFI_FVB_ATTRIBUTES_2
  108. FvbGetVolumeAttributes (
  109. IN UINTN Instance
  110. )
  111. {
  112. EFI_FW_VOL_INSTANCE *FwInstance;
  113. FwInstance = GetFvbInstance (Instance);
  114. ASSERT (FwInstance != NULL);
  115. if (FwInstance == NULL) {
  116. return 0;
  117. }
  118. return FwInstance->VolumeHeader.Attributes;
  119. }
  120. /**
  121. Retrieves the starting address of an LBA in an FV. It also
  122. return a few other attribut of the FV.
  123. @param[in] Instance The index of the EFI_FW_VOL_INSTANCE.
  124. @param[in] Lba The logical block address
  125. @param[out] LbaAddress On output, contains the physical starting address
  126. of the Lba
  127. @param[out] LbaLength On output, contains the length of the block
  128. @param[out] NumOfBlocks A pointer to a caller allocated UINTN in which the
  129. number of consecutive blocks starting with Lba is
  130. returned. All blocks in this range have a size of
  131. BlockSize
  132. @retval EFI_SUCCESS Successfully returns
  133. @retval EFI_INVALID_PARAMETER Instance not found
  134. **/
  135. STATIC
  136. EFI_STATUS
  137. FvbGetLbaAddress (
  138. IN UINTN Instance,
  139. IN EFI_LBA Lba,
  140. OUT UINTN *LbaAddress,
  141. OUT UINTN *LbaLength,
  142. OUT UINTN *NumOfBlocks
  143. )
  144. {
  145. UINT32 NumBlocks;
  146. UINT32 BlockLength;
  147. UINTN Offset;
  148. EFI_LBA StartLba;
  149. EFI_LBA NextLba;
  150. EFI_FW_VOL_INSTANCE *FwhInstance;
  151. EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
  152. //
  153. // Find the right instance of the FVB private data
  154. //
  155. FwhInstance = GetFvbInstance (Instance);
  156. if (FwhInstance == NULL) {
  157. return EFI_INVALID_PARAMETER;
  158. }
  159. StartLba = 0;
  160. Offset = 0;
  161. BlockMap = &FwhInstance->VolumeHeader.BlockMap[0];
  162. ASSERT (BlockMap != NULL);
  163. //
  164. // Parse the blockmap of the FV to find which map entry the Lba belongs to
  165. //
  166. while (TRUE) {
  167. if ( BlockMap != NULL) {
  168. NumBlocks = BlockMap->NumBlocks;
  169. BlockLength = BlockMap->Length;
  170. }
  171. if ((NumBlocks == 0) || (BlockLength == 0)) {
  172. return EFI_INVALID_PARAMETER;
  173. }
  174. NextLba = StartLba + NumBlocks;
  175. //
  176. // The map entry found
  177. //
  178. if ((Lba >= StartLba) && (Lba < NextLba)) {
  179. Offset = Offset + (UINTN)MultU64x32 ((Lba - StartLba), BlockLength);
  180. if (LbaAddress != NULL) {
  181. *LbaAddress = FwhInstance->FvBase + Offset;
  182. }
  183. if (LbaLength != NULL) {
  184. *LbaLength = BlockLength;
  185. }
  186. if (NumOfBlocks != NULL) {
  187. *NumOfBlocks = (UINTN)(NextLba - Lba);
  188. }
  189. return EFI_SUCCESS;
  190. }
  191. StartLba = NextLba;
  192. Offset = Offset + NumBlocks * BlockLength;
  193. BlockMap++;
  194. }
  195. }
  196. /**
  197. Reads specified number of bytes into a buffer from the specified block
  198. @param[in] Instance The FV instance to be read from
  199. @param[in] Lba The logical block address to be read from
  200. @param[in] BlockOffset Offset into the block at which to begin reading
  201. @param[in, out] NumBytes Pointer that on input contains the total size of
  202. the buffer. On output, it contains the total number
  203. of bytes read
  204. @param[in] Buffer Pointer to a caller allocated buffer that will be
  205. used to hold the data read
  206. @retval EFI_SUCCESS The firmware volume was read successfully and
  207. contents are in Buffer
  208. @retval EFI_BAD_BUFFER_SIZE Read attempted across a LBA boundary. On output,
  209. NumBytes contains the total number of bytes returned
  210. in Buffer
  211. @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state
  212. @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
  213. could not be read
  214. @retval EFI_INVALID_PARAMETER Instance not found, or NumBytes, Buffer are NULL
  215. **/
  216. STATIC
  217. EFI_STATUS
  218. FvbReadBlock (
  219. IN UINTN Instance,
  220. IN EFI_LBA Lba,
  221. IN UINTN BlockOffset,
  222. IN OUT UINTN *NumBytes,
  223. IN UINT8 *Buffer
  224. )
  225. {
  226. EFI_FVB_ATTRIBUTES_2 Attributes;
  227. UINTN LbaAddress;
  228. UINTN LbaLength;
  229. EFI_STATUS Status;
  230. EFI_STATUS ReadStatus;
  231. if ((NumBytes == NULL) || (Buffer == NULL)) {
  232. return (EFI_INVALID_PARAMETER);
  233. }
  234. if (*NumBytes == 0) {
  235. return (EFI_INVALID_PARAMETER);
  236. }
  237. Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL);
  238. if (EFI_ERROR (Status)) {
  239. return Status;
  240. }
  241. Attributes = FvbGetVolumeAttributes (Instance);
  242. if ((Attributes & EFI_FVB2_READ_STATUS) == 0) {
  243. return (EFI_ACCESS_DENIED);
  244. }
  245. if (BlockOffset > LbaLength) {
  246. return (EFI_INVALID_PARAMETER);
  247. }
  248. if (LbaLength < (*NumBytes + BlockOffset)) {
  249. *NumBytes = (UINT32)(LbaLength - BlockOffset);
  250. Status = EFI_BAD_BUFFER_SIZE;
  251. }
  252. ReadStatus = LibFvbFlashDeviceRead (LbaAddress + BlockOffset, NumBytes, Buffer);
  253. if (EFI_ERROR (ReadStatus)) {
  254. return ReadStatus;
  255. }
  256. return Status;
  257. }
  258. /**
  259. Writes specified number of bytes from the input buffer to the block
  260. @param[in] Instance The FV instance to be written to
  261. @param[in] Lba The starting logical block index to write to
  262. @param[in] BlockOffset Offset into the block at which to begin writing
  263. @param[in, out] NumBytes Pointer that on input contains the total size of
  264. the buffer. On output, it contains the total number
  265. of bytes actually written
  266. @param[in] Buffer Pointer to a caller allocated buffer that contains
  267. the source for the write
  268. @retval EFI_SUCCESS The firmware volume was written successfully
  269. @retval EFI_BAD_BUFFER_SIZE Write attempted across a LBA boundary. On output,
  270. NumBytes contains the total number of bytes
  271. actually written
  272. @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state
  273. @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
  274. could not be written
  275. @retval EFI_INVALID_PARAMETER Instance not found, or NumBytes, Buffer are NULL
  276. **/
  277. EFI_STATUS
  278. FvbWriteBlock (
  279. IN UINTN Instance,
  280. IN EFI_LBA Lba,
  281. IN UINTN BlockOffset,
  282. IN OUT UINTN *NumBytes,
  283. IN UINT8 *Buffer
  284. )
  285. {
  286. EFI_FVB_ATTRIBUTES_2 Attributes;
  287. UINTN LbaAddress;
  288. UINTN LbaLength;
  289. EFI_STATUS Status;
  290. if ((NumBytes == NULL) || (Buffer == NULL)) {
  291. return (EFI_INVALID_PARAMETER);
  292. }
  293. if (*NumBytes == 0) {
  294. return (EFI_INVALID_PARAMETER);
  295. }
  296. Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL);
  297. if (EFI_ERROR (Status)) {
  298. return Status;
  299. }
  300. //
  301. // Check if the FV is write enabled
  302. //
  303. Attributes = FvbGetVolumeAttributes (Instance);
  304. if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
  305. return EFI_ACCESS_DENIED;
  306. }
  307. //
  308. // Perform boundary checks and adjust NumBytes
  309. //
  310. if (BlockOffset > LbaLength) {
  311. return EFI_INVALID_PARAMETER;
  312. }
  313. if ( LbaLength < (*NumBytes + BlockOffset)) {
  314. DEBUG ((
  315. DEBUG_ERROR,
  316. "FvWriteBlock: Reducing Numbytes from 0x%x to 0x%x\n",
  317. *NumBytes,
  318. (UINT32)(LbaLength - BlockOffset)
  319. ));
  320. *NumBytes = (UINT32)(LbaLength - BlockOffset);
  321. return EFI_BAD_BUFFER_SIZE;
  322. }
  323. LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, FALSE);
  324. Status = LibFvbFlashDeviceWrite (LbaAddress + BlockOffset, NumBytes, Buffer);
  325. LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, TRUE);
  326. WriteBackInvalidateDataCacheRange ((VOID *)(LbaAddress + BlockOffset), *NumBytes);
  327. return Status;
  328. }
  329. /**
  330. Erases and initializes a firmware volume block
  331. @param[in] Instance The FV instance to be erased
  332. @param[in] Lba The logical block index to be erased
  333. @retval EFI_SUCCESS The erase request was successfully completed
  334. @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state
  335. @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
  336. could not be written. Firmware device may have been
  337. partially erased
  338. @retval EFI_INVALID_PARAMETER Instance not found
  339. **/
  340. EFI_STATUS
  341. FvbEraseBlock (
  342. IN UINTN Instance,
  343. IN EFI_LBA Lba
  344. )
  345. {
  346. EFI_FVB_ATTRIBUTES_2 Attributes;
  347. UINTN LbaAddress;
  348. UINTN LbaLength;
  349. EFI_STATUS Status;
  350. //
  351. // Check if the FV is write enabled
  352. //
  353. Attributes = FvbGetVolumeAttributes (Instance);
  354. if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
  355. return (EFI_ACCESS_DENIED);
  356. }
  357. //
  358. // Get the starting address of the block for erase.
  359. //
  360. Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL);
  361. if (EFI_ERROR (Status)) {
  362. return Status;
  363. }
  364. LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, FALSE);
  365. Status = LibFvbFlashDeviceBlockErase (LbaAddress, LbaLength);
  366. LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, TRUE);
  367. WriteBackInvalidateDataCacheRange ((VOID *)LbaAddress, LbaLength);
  368. return Status;
  369. }
  370. /**
  371. Modifies the current settings of the firmware volume according to the
  372. input parameter, and returns the new setting of the volume
  373. @param[in] Instance The FV instance whose attributes is going to be
  374. modified
  375. @param[in, out] Attributes On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
  376. containing the desired firmware volume settings.
  377. On successful return, it contains the new settings
  378. of the firmware volume
  379. @retval EFI_SUCCESS Successfully returns
  380. @retval EFI_ACCESS_DENIED The volume setting is locked and cannot be modified
  381. @retval EFI_INVALID_PARAMETER Instance not found, or The attributes requested are
  382. in conflict with the capabilities as declared in the
  383. firmware volume header
  384. **/
  385. STATIC
  386. EFI_STATUS
  387. FvbSetVolumeAttributes (
  388. IN UINTN Instance,
  389. IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
  390. )
  391. {
  392. EFI_FW_VOL_INSTANCE *FwhInstance;
  393. EFI_FVB_ATTRIBUTES_2 OldAttributes;
  394. EFI_FVB_ATTRIBUTES_2 *AttribPtr;
  395. EFI_FVB_ATTRIBUTES_2 UnchangedAttributes;
  396. UINT32 Capabilities;
  397. UINT32 OldStatus;
  398. UINT32 NewStatus;
  399. //
  400. // Find the right instance of the FVB private data
  401. //
  402. FwhInstance = GetFvbInstance (Instance);
  403. if (FwhInstance == NULL) {
  404. return EFI_INVALID_PARAMETER;
  405. }
  406. AttribPtr = (EFI_FVB_ATTRIBUTES_2 *)&(FwhInstance->VolumeHeader.Attributes);
  407. ASSERT (AttribPtr != NULL);
  408. if ( AttribPtr == NULL) {
  409. return EFI_INVALID_PARAMETER;
  410. }
  411. OldAttributes = *AttribPtr;
  412. Capabilities = OldAttributes & EFI_FVB2_CAPABILITIES;
  413. OldStatus = OldAttributes & EFI_FVB2_STATUS;
  414. NewStatus = *Attributes & EFI_FVB2_STATUS;
  415. UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP | \
  416. EFI_FVB2_READ_ENABLED_CAP | \
  417. EFI_FVB2_WRITE_DISABLED_CAP | \
  418. EFI_FVB2_WRITE_ENABLED_CAP | \
  419. EFI_FVB2_LOCK_CAP | \
  420. EFI_FVB2_STICKY_WRITE | \
  421. EFI_FVB2_MEMORY_MAPPED | \
  422. EFI_FVB2_ERASE_POLARITY | \
  423. EFI_FVB2_READ_LOCK_CAP | \
  424. EFI_FVB2_WRITE_LOCK_CAP | \
  425. EFI_FVB2_ALIGNMENT;
  426. //
  427. // Some attributes of FV is read only can *not* be set
  428. //
  429. if ((OldAttributes & UnchangedAttributes) ^ (*Attributes & UnchangedAttributes)) {
  430. return EFI_INVALID_PARAMETER;
  431. }
  432. //
  433. // If firmware volume is locked, no status bit can be updated
  434. //
  435. if ((OldAttributes & EFI_FVB2_LOCK_STATUS) != 0) {
  436. if ((OldStatus ^ NewStatus) != 0) {
  437. return EFI_ACCESS_DENIED;
  438. }
  439. }
  440. //
  441. // Test read disable
  442. //
  443. if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
  444. if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
  445. return EFI_INVALID_PARAMETER;
  446. }
  447. }
  448. //
  449. // Test read enable
  450. //
  451. if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
  452. if ((NewStatus & EFI_FVB2_READ_STATUS) != 0) {
  453. return EFI_INVALID_PARAMETER;
  454. }
  455. }
  456. //
  457. // Test write disable
  458. //
  459. if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
  460. if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
  461. return EFI_INVALID_PARAMETER;
  462. }
  463. }
  464. //
  465. // Test write enable
  466. //
  467. if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
  468. if ((NewStatus & EFI_FVB2_WRITE_STATUS) != 0) {
  469. return EFI_INVALID_PARAMETER;
  470. }
  471. }
  472. //
  473. // Test lock
  474. //
  475. if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
  476. if ((NewStatus & EFI_FVB2_LOCK_STATUS) != 0) {
  477. return EFI_INVALID_PARAMETER;
  478. }
  479. }
  480. *AttribPtr = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
  481. *AttribPtr = (*AttribPtr) | NewStatus;
  482. *Attributes = *AttribPtr;
  483. return EFI_SUCCESS;
  484. }
  485. /**
  486. Retrieves the physical address of the device.
  487. @param[in] This A pointer to EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL.
  488. @param[out] Address Output buffer containing the address.
  489. @retval EFI_SUCCESS The function always return successfully.
  490. @retval EFI_INVALID_PARAMETER Instance not found.
  491. **/
  492. EFI_STATUS
  493. EFIAPI
  494. FvbProtocolGetPhysicalAddress (
  495. IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
  496. OUT EFI_PHYSICAL_ADDRESS *Address
  497. )
  498. {
  499. EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
  500. EFI_FW_VOL_INSTANCE *FwhInstance;
  501. FvbDevice = FVB_DEVICE_FROM_THIS (This);
  502. FwhInstance = GetFvbInstance (FvbDevice->Instance);
  503. if (FwhInstance == NULL) {
  504. return EFI_INVALID_PARAMETER;
  505. }
  506. *Address = FwhInstance->FvBase;
  507. return EFI_SUCCESS;
  508. }
  509. /**
  510. Retrieve the size of a logical block
  511. @param[in] This Calling context
  512. @param[in] Lba Indicates which block to return the size for.
  513. @param[out] BlockSize A pointer to a caller allocated UINTN in which
  514. the size of the block is returned
  515. @param[out] NumOfBlocks A pointer to a caller allocated UINTN in which the
  516. number of consecutive blocks starting with Lba is
  517. returned. All blocks in this range have a size of
  518. BlockSize
  519. @retval EFI_SUCCESS The function always return successfully.
  520. **/
  521. EFI_STATUS
  522. EFIAPI
  523. FvbProtocolGetBlockSize (
  524. IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
  525. IN EFI_LBA Lba,
  526. OUT UINTN *BlockSize,
  527. OUT UINTN *NumOfBlocks
  528. )
  529. {
  530. EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
  531. FvbDevice = FVB_DEVICE_FROM_THIS (This);
  532. return FvbGetLbaAddress (FvbDevice->Instance, Lba, NULL, BlockSize, NumOfBlocks);
  533. }
  534. /**
  535. Retrieves Volume attributes. No polarity translations are done.
  536. @param[in] This Calling context
  537. @param[out] Attributes Output buffer which contains attributes
  538. @retval EFI_SUCCESS The function always return successfully.
  539. **/
  540. EFI_STATUS
  541. EFIAPI
  542. FvbProtocolGetAttributes (
  543. IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
  544. OUT EFI_FVB_ATTRIBUTES_2 *Attributes
  545. )
  546. {
  547. EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
  548. FvbDevice = FVB_DEVICE_FROM_THIS (This);
  549. *Attributes = FvbGetVolumeAttributes (FvbDevice->Instance);
  550. return EFI_SUCCESS;
  551. }
  552. /**
  553. Sets Volume attributes. No polarity translations are done.
  554. @param[in] This Calling context
  555. @param[in, out] Attributes Output buffer which contains attributes
  556. @retval EFI_SUCCESS The function always return successfully.
  557. **/
  558. EFI_STATUS
  559. EFIAPI
  560. FvbProtocolSetAttributes (
  561. IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
  562. IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
  563. )
  564. {
  565. EFI_STATUS Status;
  566. EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
  567. FvbDevice = FVB_DEVICE_FROM_THIS (This);
  568. Status = FvbSetVolumeAttributes (FvbDevice->Instance, Attributes);
  569. return Status;
  570. }
  571. /**
  572. This function erases one or more blocks as denoted by the
  573. variable argument list. The entire parameter list of blocks must be verified
  574. prior to erasing any blocks. If a block is requested that does not exist
  575. within the associated firmware volume (it has a larger index than the last
  576. block of the firmware volume), the EraseBlock() function must return
  577. EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
  578. @param[in] This Calling context
  579. @param[in] ... Starting LBA followed by Number of Lba to erase.
  580. a -1 to terminate the list.
  581. @retval EFI_SUCCESS The erase request was successfully completed
  582. @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state
  583. @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
  584. could not be written. Firmware device may have been
  585. partially erased
  586. **/
  587. EFI_STATUS
  588. EFIAPI
  589. FvbProtocolEraseBlocks (
  590. IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
  591. ...
  592. )
  593. {
  594. EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
  595. EFI_FW_VOL_INSTANCE *FwhInstance;
  596. UINTN NumOfBlocks;
  597. VA_LIST args;
  598. EFI_LBA StartingLba;
  599. UINTN NumOfLba;
  600. EFI_STATUS Status;
  601. FvbDevice = FVB_DEVICE_FROM_THIS (This);
  602. FwhInstance = GetFvbInstance (FvbDevice->Instance);
  603. if (FwhInstance == NULL) {
  604. return EFI_OUT_OF_RESOURCES;
  605. }
  606. NumOfBlocks = FwhInstance->NumOfBlocks;
  607. VA_START (args, This);
  608. do {
  609. StartingLba = VA_ARG (args, EFI_LBA);
  610. if ( StartingLba == EFI_LBA_LIST_TERMINATOR ) {
  611. break;
  612. }
  613. NumOfLba = VA_ARG (args, UINT32);
  614. //
  615. // Check input parameters
  616. //
  617. if (NumOfLba == 0) {
  618. VA_END (args);
  619. return EFI_INVALID_PARAMETER;
  620. }
  621. if ((StartingLba + NumOfLba) > NumOfBlocks ) {
  622. return EFI_INVALID_PARAMETER;
  623. }
  624. } while (1);
  625. VA_END (args);
  626. VA_START (args, This);
  627. do {
  628. StartingLba = VA_ARG (args, EFI_LBA);
  629. if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
  630. break;
  631. }
  632. NumOfLba = VA_ARG (args, UINT32);
  633. while ( NumOfLba > 0 ) {
  634. Status = FvbEraseBlock (FvbDevice->Instance, StartingLba);
  635. if ( EFI_ERROR (Status)) {
  636. VA_END (args);
  637. return Status;
  638. }
  639. StartingLba++;
  640. NumOfLba--;
  641. }
  642. } while (1);
  643. VA_END (args);
  644. return EFI_SUCCESS;
  645. }
  646. /**
  647. Writes data beginning at Lba:Offset from FV. The write terminates either
  648. when *NumBytes of data have been written, or when a block boundary is
  649. reached. *NumBytes is updated to reflect the actual number of bytes
  650. written. The write opertion does not include erase. This routine will
  651. attempt to write only the specified bytes. If the writes do not stick,
  652. it will return an error.
  653. @param[in] This Calling context
  654. @param[in] Lba Block in which to begin write
  655. @param[in] Offset Offset in the block at which to begin write
  656. @param[in,out] NumBytes On input, indicates the requested write size. On
  657. output, indicates the actual number of bytes written
  658. @param[in] Buffer Buffer containing source data for the write.
  659. @retval EFI_SUCCESS The firmware volume was written successfully
  660. @retval EFI_BAD_BUFFER_SIZE Write attempted across a LBA boundary. On output,
  661. NumBytes contains the total number of bytes
  662. actually written
  663. @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state
  664. @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
  665. could not be written
  666. @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL
  667. **/
  668. EFI_STATUS
  669. EFIAPI
  670. FvbProtocolWrite (
  671. IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
  672. IN EFI_LBA Lba,
  673. IN UINTN Offset,
  674. IN OUT UINTN *NumBytes,
  675. IN UINT8 *Buffer
  676. )
  677. {
  678. EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
  679. EFI_STATUS Status;
  680. FvbDevice = FVB_DEVICE_FROM_THIS (This);
  681. Status = FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer);
  682. DEBUG ((
  683. DEBUG_VERBOSE,
  684. "FvbWrite: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x Status:%r\n",
  685. Lba,
  686. Offset,
  687. *NumBytes,
  688. Buffer,
  689. Status
  690. ));
  691. return Status;
  692. }
  693. /**
  694. Reads data beginning at Lba:Offset from FV. The Read terminates either
  695. when *NumBytes of data have been read, or when a block boundary is
  696. reached. *NumBytes is updated to reflect the actual number of bytes
  697. written. The write opertion does not include erase. This routine will
  698. attempt to write only the specified bytes. If the writes do not stick,
  699. it will return an error.
  700. @param[in] This Calling context
  701. @param[in] Lba Block in which to begin write
  702. @param[in] Offset Offset in the block at which to begin write
  703. @param[in,out] NumBytes On input, indicates the requested write size. On
  704. output, indicates the actual number of bytes written
  705. @param[out] Buffer Buffer containing source data for the write.
  706. Returns:
  707. @retval EFI_SUCCESS The firmware volume was read successfully and
  708. contents are in Buffer
  709. @retval EFI_BAD_BUFFER_SIZE Read attempted across a LBA boundary. On output,
  710. NumBytes contains the total number of bytes returned
  711. in Buffer
  712. @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state
  713. @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
  714. could not be read
  715. @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL
  716. **/
  717. EFI_STATUS
  718. EFIAPI
  719. FvbProtocolRead (
  720. IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
  721. IN EFI_LBA Lba,
  722. IN UINTN Offset,
  723. IN OUT UINTN *NumBytes,
  724. OUT UINT8 *Buffer
  725. )
  726. {
  727. EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
  728. EFI_STATUS Status;
  729. FvbDevice = FVB_DEVICE_FROM_THIS (This);
  730. Status = FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer);
  731. DEBUG ((
  732. DEBUG_VERBOSE,
  733. "FvbRead: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x, Status:%r\n",
  734. Lba,
  735. Offset,
  736. *NumBytes,
  737. Buffer,
  738. Status
  739. ));
  740. return Status;
  741. }
  742. /**
  743. Check the integrity of firmware volume header in FvBase
  744. @param[in] FvBase A pointer to firmware volume base address.
  745. @retval TRUE The firmware volume is consistent
  746. @retval FALSE The firmware volume has corrupted.
  747. **/
  748. BOOLEAN
  749. IsFvHeaderValid (
  750. IN EFI_PHYSICAL_ADDRESS FvBase
  751. )
  752. {
  753. UINT16 Sum;
  754. EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
  755. FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvBase;
  756. if (FvBase == PcdGet32 (PcdFlashNvStorageVariableBase)) {
  757. if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid, sizeof (EFI_GUID)) != 0 ) {
  758. DEBUG ((DEBUG_INFO, " --FileSystemGuid not match: %g\n", &FwVolHeader->FileSystemGuid));
  759. return FALSE;
  760. }
  761. } else {
  762. if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem2Guid, sizeof (EFI_GUID)) != 0 ) {
  763. DEBUG ((DEBUG_INFO, " --not expected guid.\n"));
  764. return FALSE;
  765. }
  766. }
  767. if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||
  768. (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||
  769. (FwVolHeader->FvLength == ((UINTN)-1)) ||
  770. ((FwVolHeader->HeaderLength & 0x01) != 0))
  771. {
  772. DEBUG ((DEBUG_INFO, " -- >Revision = 0x%x, Signature = 0x%x\n", FwVolHeader->Revision, FwVolHeader->Signature));
  773. DEBUG ((DEBUG_INFO, " -- >FvLength = 0x%lx, HeaderLength = 0x%x\n", FwVolHeader->FvLength, FwVolHeader->HeaderLength));
  774. return FALSE;
  775. }
  776. Sum = CalculateSum16 ((UINT16 *)FwVolHeader, FwVolHeader->HeaderLength);
  777. if (Sum != 0) {
  778. DEBUG ((DEBUG_INFO, "error: checksum: 0x%04X (expect 0x0)\n", Sum));
  779. return FALSE;
  780. }
  781. return TRUE;
  782. }
  783. /**
  784. Get intial variable data.
  785. @param[out] VarData Valid variable data.
  786. @param[out] VarSize Valid variable size.
  787. @retval RETURN_SUCCESS Successfully found initial variable data.
  788. @retval RETURN_NOT_FOUND Failed to find the variable data file from FV.
  789. @retval EFI_INVALID_PARAMETER VarData or VarSize is null.
  790. **/
  791. EFI_STATUS
  792. GetInitialVariableData (
  793. OUT VOID **VarData,
  794. OUT UINTN *VarSize
  795. )
  796. {
  797. EFI_STATUS Status;
  798. VOID *ImageData;
  799. UINTN ImageSize;
  800. EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
  801. VARIABLE_STORE_HEADER *VariableStore;
  802. AUTHENTICATED_VARIABLE_HEADER *Variable;
  803. UINTN VariableSize;
  804. UINTN VarEndAddr;
  805. if ((VarData == NULL) || (VarSize == NULL)) {
  806. return EFI_INVALID_PARAMETER;
  807. }
  808. Status = GetSectionFromAnyFv (PcdGetPtr (PcdNvsDataFile), EFI_SECTION_RAW, 0, &ImageData, &ImageSize);
  809. if (EFI_ERROR (Status)) {
  810. return Status;
  811. }
  812. FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)ImageData;
  813. VariableStore = (VARIABLE_STORE_HEADER *)((UINT8 *)ImageData + FvHeader->HeaderLength);
  814. VarEndAddr = (UINTN)VariableStore + VariableStore->Size;
  815. Variable = (AUTHENTICATED_VARIABLE_HEADER *)HEADER_ALIGN (VariableStore + 1);
  816. *VarData = (VOID *)Variable;
  817. while (((UINTN)Variable < VarEndAddr)) {
  818. if (Variable->StartId != VARIABLE_DATA) {
  819. break;
  820. }
  821. VariableSize = sizeof (AUTHENTICATED_VARIABLE_HEADER) + Variable->DataSize + Variable->NameSize;
  822. Variable = (AUTHENTICATED_VARIABLE_HEADER *)HEADER_ALIGN ((UINTN)Variable + VariableSize);
  823. }
  824. *VarSize = (UINTN)Variable - HEADER_ALIGN (VariableStore + 1);
  825. return EFI_SUCCESS;
  826. }
  827. /**
  828. The function does the necessary initialization work for
  829. Firmware Volume Block Driver.
  830. @retval EFI_SUCCESS This funtion always return EFI_SUCCESS.
  831. It will ASSERT on errors.
  832. **/
  833. EFI_STATUS
  834. FvbInitialize (
  835. VOID
  836. )
  837. {
  838. EFI_FW_VOL_INSTANCE *FwVolInstance;
  839. EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
  840. EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
  841. EFI_PHYSICAL_ADDRESS BaseAddress;
  842. UINTN WriteAddr;
  843. EFI_STATUS Status;
  844. UINTN BufferSize;
  845. UINTN Length;
  846. VARIABLE_STORE_HEADER VariableStore;
  847. VOID *VarData;
  848. InitVariableStore ();
  849. BaseAddress = PcdGet32 (PcdFlashNvStorageVariableBase);
  850. FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)BaseAddress;
  851. //
  852. // Check FV header and variable store header
  853. //
  854. if (!IsFvHeaderValid (BaseAddress)) {
  855. //
  856. // Write back a healthy FV header
  857. //
  858. DEBUG ((DEBUG_ERROR, "Fvb: Writing back a healthy FV header: 0x%lx\n", BaseAddress));
  859. FvHeader = GetFvHeaderTemplate ();
  860. LibFvbFlashDeviceBlockLock ((UINTN)BaseAddress, FvHeader->BlockMap->Length, FALSE);
  861. Status = LibFvbFlashDeviceBlockErase ((UINTN)BaseAddress, FvHeader->BlockMap->Length);
  862. ASSERT_EFI_ERROR (Status);
  863. Length = FvHeader->HeaderLength;
  864. WriteAddr = (UINTN)BaseAddress;
  865. Status = LibFvbFlashDeviceWrite (WriteAddr, &Length, (UINT8 *)FvHeader);
  866. WriteAddr += Length;
  867. ASSERT_EFI_ERROR (Status);
  868. //
  869. // Write back variable store header
  870. //
  871. VariableStore.Size = PcdGet32 (PcdFlashNvStorageVariableSize) - FvHeader->HeaderLength;
  872. VariableStore.Format = VARIABLE_STORE_FORMATTED;
  873. VariableStore.State = VARIABLE_STORE_HEALTHY;
  874. CopyGuid (&VariableStore.Signature, &gEfiAuthenticatedVariableGuid);
  875. BufferSize = sizeof (VARIABLE_STORE_HEADER);
  876. Status = LibFvbFlashDeviceWrite (WriteAddr, &BufferSize, (UINT8 *)&VariableStore);
  877. WriteAddr += BufferSize;
  878. ASSERT_EFI_ERROR (Status);
  879. //
  880. // Write initial variable data if found
  881. //
  882. Status = GetInitialVariableData (&VarData, &Length);
  883. if (!EFI_ERROR (Status)) {
  884. Status = LibFvbFlashDeviceWrite (WriteAddr, &Length, (UINT8 *)VarData);
  885. ASSERT_EFI_ERROR (Status);
  886. }
  887. LibFvbFlashDeviceBlockLock ((UINTN)BaseAddress, FvHeader->BlockMap->Length, TRUE);
  888. WriteBackInvalidateDataCacheRange ((VOID *)(UINTN)BaseAddress, FvHeader->BlockMap->Length);
  889. }
  890. //
  891. // Create a new FW volume instance for NVS variable
  892. //
  893. BufferSize = FvHeader->HeaderLength + sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER);
  894. FwVolInstance = (EFI_FW_VOL_INSTANCE *)AllocateRuntimeZeroPool (BufferSize);
  895. if (FwVolInstance == NULL) {
  896. return EFI_OUT_OF_RESOURCES;
  897. }
  898. FwVolInstance->FvBase = (UINTN)BaseAddress;
  899. CopyMem (&FwVolInstance->VolumeHeader, FvHeader, FvHeader->HeaderLength);
  900. //
  901. // Process the block map for each FV. Assume it has same block size.
  902. //
  903. FwVolInstance->NumOfBlocks = 0;
  904. FvHeader = &FwVolInstance->VolumeHeader;
  905. for (BlockMap = FvHeader->BlockMap; BlockMap->NumBlocks != 0; BlockMap++) {
  906. FwVolInstance->NumOfBlocks += BlockMap->NumBlocks;
  907. }
  908. //
  909. // Add a FVB Protocol Instance
  910. //
  911. Status = InstallFvbProtocol (FwVolInstance, mFvbModuleGlobal.NumFv);
  912. mFvbModuleGlobal.NumFv++;
  913. mFvbModuleGlobal.FvInstance = FwVolInstance;
  914. return Status;
  915. }