SpiFvbServiceCommon.c 31 KB

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