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