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