]> git.proxmox.com Git - mirror_edk2.git/blame - Vlv2TbltDevicePkg/FvbRuntimeDxe/FvbService.c
Vlv2TbltDevicePkg: fix ASSERT_EFI_ERROR() typos
[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
359 EFI_FW_VOL_INSTANCE *FwhInstance;\r
360 EFI_STATUS Status;\r
361 EFI_STATUS Status1;\r
362\r
363 FwhInstance = GetFvbInstance (Instance);\r
364\r
365 if ( (NumBytes == NULL) || (Buffer == NULL)) {\r
366 return (EFI_INVALID_PARAMETER);\r
367 }\r
368 if (*NumBytes == 0) {\r
369 return (EFI_INVALID_PARAMETER);\r
370 }\r
371\r
372 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL);\r
373 if (EFI_ERROR(Status)) {\r
374 return Status;\r
375 }\r
376\r
377 //\r
378 // Check if the FV is write enabled.\r
379 //\r
380 Attributes = FvbGetVolumeAttributes (Instance);\r
381 if ( (Attributes & EFI_FVB2_WRITE_STATUS) == 0) {\r
382 return (EFI_ACCESS_DENIED);\r
383 }\r
384\r
385 //\r
386 // Perform boundary checks and adjust NumBytes.\r
387 //\r
388 if (BlockOffset > LbaLength) {\r
389 return (EFI_INVALID_PARAMETER);\r
390 }\r
391\r
392 if ( LbaLength < ( *NumBytes + BlockOffset ) ) {\r
393 DEBUG ((EFI_D_ERROR,\r
394 "FvWriteBlock: Reducing Numbytes from 0x%x to 0x%x\n",\r
395 *NumBytes,\r
396 (UINT32)(LbaLength-BlockOffset))\r
397 );\r
398 *NumBytes = (UINT32) (LbaLength - BlockOffset);\r
399 Status = EFI_BAD_BUFFER_SIZE;\r
400 }\r
401\r
402 LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, FALSE);\r
403\r
404 Status1 = LibFvbFlashDeviceWrite (LbaAddress + BlockOffset, NumBytes, Buffer);\r
405\r
406 LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, TRUE);\r
407 WriteBackInvalidateDataCacheRange ((VOID *) (LbaAddress + BlockOffset), *NumBytes);\r
408\r
409 if ( EFI_ERROR (Status1) ) {\r
410 return Status1;\r
411 }\r
412\r
413 return Status;\r
414}\r
415\r
416\r
417/**\r
418 Erases and initializes a firmware volume block.\r
419\r
420 @param[in] Instance The FV instance to be erased.\r
421 @param[in] Lba The logical block index to be erased.\r
422\r
423 @retval EFI_SUCCESS The erase request was successfully completed.\r
424 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state.\r
425 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and\r
426 could not be written. Firmware device may have been\r
427 partially erased.\r
428 @retval EFI_INVALID_PARAMETER Instance not found.\r
429\r
430**/\r
431EFI_STATUS\r
432FvbEraseBlock (\r
433 IN UINTN Instance,\r
434 IN EFI_LBA Lba\r
435 )\r
436{\r
437 EFI_FVB_ATTRIBUTES_2 Attributes;\r
438 UINTN LbaAddress;\r
439 EFI_FW_VOL_INSTANCE *FwhInstance;\r
440 UINTN LbaLength;\r
441 EFI_STATUS Status;\r
442\r
443 //\r
444 // Find the right instance of the FVB private data.\r
445 //\r
446 FwhInstance = GetFvbInstance (Instance);\r
447\r
448 //\r
449 // Check if the FV is write enabled.\r
450 //\r
451 Attributes = FvbGetVolumeAttributes (Instance);\r
452\r
453 if( (Attributes & EFI_FVB2_WRITE_STATUS) == 0) {\r
454 return (EFI_ACCESS_DENIED);\r
455 }\r
456\r
457 //\r
458 // Get the starting address of the block for erase.\r
459 //\r
460 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL);\r
461 if (EFI_ERROR(Status)) {\r
462 return Status;\r
463 }\r
464\r
465 LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, FALSE);\r
466\r
467 Status = LibFvbFlashDeviceBlockErase (LbaAddress, LbaLength);\r
468\r
469 LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, TRUE);\r
470\r
471 WriteBackInvalidateDataCacheRange ((VOID *) LbaAddress, LbaLength);\r
472\r
473 return Status;\r
474}\r
475\r
476\r
477/**\r
478 Modifies the current settings of the firmware volume according to the\r
479 input parameter, and returns the new setting of the volume.\r
480\r
481 @param[in] Instance The FV instance whose attributes is going to be\r
482 modified.\r
483 @param[in] Attributes On input, it is a pointer to EFI_FVB_ATTRIBUTES_2\r
484 containing the desired firmware volume settings.\r
485 On successful return, it contains the new settings\r
486 of the firmware volume.\r
487\r
488 @retval EFI_SUCCESS Successfully returns.\r
489 @retval EFI_ACCESS_DENIED The volume setting is locked and cannot be modified.\r
490 @retval EFI_INVALID_PARAMETER Instance not found, or The attributes requested are\r
491 in conflict with the capabilities as declared in the\r
492 firmware volume header.\r
493\r
494**/\r
495STATIC\r
496EFI_STATUS\r
497FvbSetVolumeAttributes (\r
498 IN UINTN Instance,\r
499 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes\r
500 )\r
501{\r
502 EFI_FW_VOL_INSTANCE *FwhInstance = NULL;\r
503 EFI_FVB_ATTRIBUTES_2 OldAttributes = 0;\r
504 EFI_FVB_ATTRIBUTES_2 *AttribPtr = NULL;\r
505 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes;\r
506 UINT32 Capabilities;\r
507 UINT32 OldStatus, NewStatus;\r
508\r
509 //\r
510 // Find the right instance of the FVB private data.\r
511 //\r
512 FwhInstance = GetFvbInstance (Instance);\r
513\r
514 AttribPtr = (EFI_FVB_ATTRIBUTES_2 *) & (FwhInstance->VolumeHeader.Attributes);\r
ba53301f 515 ASSERT (AttribPtr != NULL);\r
3cbfba02
DW
516\r
517 if ( AttribPtr != NULL) {\r
518 OldAttributes = *AttribPtr;\r
519 }\r
520\r
521 Capabilities = OldAttributes & EFI_FVB2_CAPABILITIES;\r
522 OldStatus = OldAttributes & EFI_FVB2_STATUS;\r
523 NewStatus = *Attributes & EFI_FVB2_STATUS;\r
524\r
525 UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP | \\r
526 EFI_FVB2_READ_ENABLED_CAP | \\r
527 EFI_FVB2_WRITE_DISABLED_CAP | \\r
528 EFI_FVB2_WRITE_ENABLED_CAP | \\r
529 EFI_FVB2_LOCK_CAP | \\r
530 EFI_FVB2_STICKY_WRITE | \\r
531 EFI_FVB2_MEMORY_MAPPED | \\r
532 EFI_FVB2_ERASE_POLARITY | \\r
533 EFI_FVB2_READ_LOCK_CAP | \\r
534 EFI_FVB2_WRITE_LOCK_CAP | \\r
535 EFI_FVB2_ALIGNMENT;\r
536\r
537 //\r
538 // Some attributes of FV is read only can *not* be set.\r
539 //\r
540 if ((OldAttributes & UnchangedAttributes) ^ (*Attributes & UnchangedAttributes)) {\r
541 return EFI_INVALID_PARAMETER;\r
542 }\r
543\r
544 //\r
545 // If firmware volume is locked, no status bit can be updated.\r
546 //\r
547 if ( OldAttributes & EFI_FVB2_LOCK_STATUS ) {\r
548 if ( OldStatus ^ NewStatus ) {\r
549 return EFI_ACCESS_DENIED;\r
550 }\r
551 }\r
552\r
553 //\r
554 // Test read disable.\r
555 //\r
556 if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {\r
557 if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {\r
558 return EFI_INVALID_PARAMETER;\r
559 }\r
560 }\r
561\r
562 //\r
563 // Test read enable.\r
564 //\r
565 if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {\r
566 if (NewStatus & EFI_FVB2_READ_STATUS) {\r
567 return EFI_INVALID_PARAMETER;\r
568 }\r
569 }\r
570\r
571 //\r
572 // Test write disable.\r
573 //\r
574 if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {\r
575 if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {\r
576 return EFI_INVALID_PARAMETER;\r
577 }\r
578 }\r
579\r
580 //\r
581 // Test write enable.\r
582 //\r
583 if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {\r
584 if (NewStatus & EFI_FVB2_WRITE_STATUS) {\r
585 return EFI_INVALID_PARAMETER;\r
586 }\r
587 }\r
588\r
589 //\r
590 // Test lock.\r
591 //\r
592 if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {\r
593 if (NewStatus & EFI_FVB2_LOCK_STATUS) {\r
594 return EFI_INVALID_PARAMETER;\r
595 }\r
596 }\r
597\r
598 *AttribPtr = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));\r
599 *AttribPtr = (*AttribPtr) | NewStatus;\r
600 *Attributes = *AttribPtr;\r
601\r
602 return EFI_SUCCESS;\r
603}\r
604\r
605//\r
606// FVB protocol APIs.\r
607//\r
608/**\r
609 Retrieves the physical address of the device.\r
610\r
611 @param[in] This A pointer to EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL.\r
612 @param[out] Address Output buffer containing the address.\r
613\r
614 retval EFI_SUCCESS The function always return successfully.\r
615\r
616**/\r
617EFI_STATUS\r
618EFIAPI\r
619FvbProtocolGetPhysicalAddress (\r
620 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
621 OUT EFI_PHYSICAL_ADDRESS *Address\r
622 )\r
623{\r
624 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
625 EFI_FW_VOL_INSTANCE *FvInstance;\r
626\r
627 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
628 FvInstance = GetFvbInstance(FvbDevice->Instance);\r
629\r
630 if (FvInstance != NULL) {\r
631 *Address = FvInstance->FvBase;\r
632 }\r
633\r
634 return EFI_SUCCESS;\r
635}\r
636\r
637\r
638/**\r
639 Retrieve the size of a logical block.\r
640\r
641 @param[in] This Calling context.\r
642 @param[in] Lba Indicates which block to return the size for.\r
643 @param[out] BlockSize A pointer to a caller allocated UINTN in which\r
644 the size of the block is returned.\r
645 @param[out] NumOfBlocks A pointer to a caller allocated UINTN in which the\r
646 number of consecutive blocks starting with Lba is\r
647 returned. All blocks in this range have a size of\r
648 BlockSize.\r
649\r
650 @retval EFI_SUCCESS The function always return successfully.\r
651\r
652**/\r
653EFI_STATUS\r
654EFIAPI\r
655FvbProtocolGetBlockSize (\r
656 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
657 IN EFI_LBA Lba,\r
658 OUT UINTN *BlockSize,\r
659 OUT UINTN *NumOfBlocks\r
660 )\r
661{\r
662 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
663\r
664 DEBUG((EFI_D_INFO,\r
665 "FvbProtocolGetBlockSize: Lba: 0x%lx BlockSize: 0x%x NumOfBlocks: 0x%x\n",\r
666 Lba,\r
667 BlockSize,\r
668 NumOfBlocks)\r
669 );\r
670\r
671 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
672\r
673 return FvbGetLbaAddress (\r
674 FvbDevice->Instance,\r
675 Lba,\r
676 NULL,\r
677 BlockSize,\r
678 NumOfBlocks\r
679 );\r
680}\r
681\r
682\r
683/**\r
684 Retrieves Volume attributes. No polarity translations are done.\r
685\r
686 @param[in] This Calling context.\r
687 @param[out] Attributes Output buffer which contains attributes.\r
688\r
689 @retval EFI_SUCCESS The function always return successfully.\r
690\r
691**/\r
692EFI_STATUS\r
693EFIAPI\r
694FvbProtocolGetAttributes (\r
695 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
696 OUT EFI_FVB_ATTRIBUTES_2 *Attributes\r
697 )\r
698{\r
699 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
700\r
701 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
702\r
703 *Attributes = FvbGetVolumeAttributes (FvbDevice->Instance);\r
704\r
705 DEBUG ((EFI_D_INFO,\r
706 "FvbProtocolGetAttributes: This: 0x%x Attributes: 0x%x\n",\r
707 This,\r
708 *Attributes)\r
709 );\r
710\r
711 return EFI_SUCCESS;\r
712}\r
713\r
714\r
715/**\r
716 Sets Volume attributes. No polarity translations are done.\r
717\r
718 @param[in] This Calling context.\r
719 @param[out] Attributes Output buffer which contains attributes.\r
720\r
721 @retval EFI_SUCCESS The function always return successfully.\r
722\r
723**/\r
724EFI_STATUS\r
725EFIAPI\r
726FvbProtocolSetAttributes (\r
727 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
728 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes\r
729 )\r
730{\r
731 EFI_STATUS Status;\r
732 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
733\r
734 DEBUG((EFI_D_INFO,\r
735 "FvbProtocolSetAttributes: Before SET - This: 0x%x Attributes: 0x%x\n",\r
736 This,\r
737 *Attributes)\r
738 );\r
739\r
740 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
741\r
742 Status = FvbSetVolumeAttributes (FvbDevice->Instance, Attributes);\r
743\r
744 DEBUG((EFI_D_INFO,\r
745 "FvbProtocolSetAttributes: After SET - This: 0x%x Attributes: 0x%x\n",\r
746 This,\r
747 *Attributes)\r
748 );\r
749\r
750 return Status;\r
751}\r
752\r
753\r
754/**\r
755 The EraseBlock() function erases one or more blocks as denoted by the\r
756 variable argument list. The entire parameter list of blocks must be verified\r
757 prior to erasing any blocks. If a block is requested that does not exist\r
758 within the associated firmware volume (it has a larger index than the last\r
759 block of the firmware volume), the EraseBlock() function must return\r
760 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.\r
761\r
762 @param[in] This Calling context.\r
763 @param[in] ... Starting LBA followed by Number of Lba to erase.\r
764 a -1 to terminate the list.\r
765\r
766 @retval EFI_SUCCESS The erase request was successfully completed.\r
767 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state.\r
768 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and\r
769 could not be written. Firmware device may have been\r
770 partially erased.\r
771\r
772**/\r
773EFI_STATUS\r
774EFIAPI\r
775FvbProtocolEraseBlocks (\r
776 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
777 ...\r
778 )\r
779{\r
780 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
781 EFI_FW_VOL_INSTANCE *FwhInstance;\r
782 UINTN NumOfBlocks = 0;\r
783 VA_LIST args;\r
784 EFI_LBA StartingLba;\r
785 UINTN NumOfLba;\r
786 EFI_STATUS Status;\r
787\r
788 DEBUG((EFI_D_INFO, "FvbProtocolEraseBlocks: \n"));\r
789 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
790\r
791 FwhInstance = GetFvbInstance (FvbDevice->Instance);\r
792\r
793 if (FwhInstance != NULL) {\r
794 NumOfBlocks = FwhInstance->NumOfBlocks;\r
795 }\r
796\r
797 VA_START (args, This);\r
798\r
799 do {\r
800 StartingLba = VA_ARG (args, EFI_LBA);\r
801 if ( StartingLba == EFI_LBA_LIST_TERMINATOR ) {\r
802 break;\r
803 }\r
804\r
805 NumOfLba = VA_ARG (args, UINT32);\r
806\r
807 //\r
808 // Check input parameters.\r
809 //\r
810 if (NumOfLba == 0) {\r
811 VA_END (args);\r
812 return EFI_INVALID_PARAMETER;\r
813 }\r
814\r
815 if ( ( StartingLba + NumOfLba ) > NumOfBlocks ) {\r
816 return EFI_INVALID_PARAMETER;\r
817 }\r
818 } while ( 1 );\r
819\r
820 VA_END (args);\r
821\r
822 VA_START (args, This);\r
823 do {\r
824 StartingLba = VA_ARG (args, EFI_LBA);\r
825 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {\r
826 break;\r
827 }\r
828\r
829 NumOfLba = VA_ARG (args, UINT32);\r
830\r
831 while ( NumOfLba > 0 ) {\r
832 Status = FvbEraseBlock (FvbDevice->Instance, StartingLba);\r
833 if ( EFI_ERROR(Status)) {\r
834 VA_END (args);\r
835 return Status;\r
836 }\r
837 StartingLba ++;\r
838 NumOfLba --;\r
839 }\r
840\r
841 } while ( 1 );\r
842\r
843 VA_END (args);\r
844\r
845 return EFI_SUCCESS;\r
846}\r
847\r
848\r
849/**\r
850 Writes data beginning at Lba:Offset from FV. The write terminates either\r
851 when *NumBytes of data have been written, or when a block boundary is\r
852 reached. *NumBytes is updated to reflect the actual number of bytes\r
853 written. The write opertion does not include erase. This routine will\r
854 attempt to write only the specified bytes. If the writes do not stick,\r
855 it will return an error.\r
856\r
857 @param[in] This Calling context.\r
858 @param[in] Lba Block in which to begin write.\r
859 @param[in] Offset Offset in the block at which to begin write.\r
860 @param[in,out] NumBytes On input, indicates the requested write size. On\r
861 output, indicates the actual number of bytes written\r
862 @param[in] Buffer Buffer containing source data for the write.\r
863\r
864 @retval EFI_SUCCESS The firmware volume was written successfully.\r
865 @retval EFI_BAD_BUFFER_SIZE Write attempted across a LBA boundary. On output,\r
866 NumBytes contains the total number of bytes\r
867 actually written.\r
868 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state.\r
869 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and\r
870 could not be written.\r
871 @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL.\r
872\r
873**/\r
874EFI_STATUS\r
875EFIAPI\r
876FvbProtocolWrite (\r
877 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
878 IN EFI_LBA Lba,\r
879 IN UINTN Offset,\r
880 IN OUT UINTN *NumBytes,\r
881 IN UINT8 *Buffer\r
882 )\r
883{\r
884\r
885 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
886\r
887 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
888\r
889 DEBUG((EFI_D_INFO,\r
890 "FvbProtocolWrite: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x\n",\r
891 Lba,\r
892 Offset,\r
893 *NumBytes,\r
894 Buffer)\r
895 );\r
896\r
897 return FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer);\r
898}\r
899\r
900\r
901/**\r
902 Reads data beginning at Lba:Offset from FV. The Read terminates either\r
903 when *NumBytes of data have been read, or when a block boundary is\r
904 reached. *NumBytes is updated to reflect the actual number of bytes\r
905 written. The write opertion does not include erase. This routine will\r
906 attempt to write only the specified bytes. If the writes do not stick,\r
907 it will return an error.\r
908\r
909 @param[in] This Calling context.\r
910 @param[in] Lba Block in which to begin write.\r
911 @param[in] Offset Offset in the block at which to begin write\r
912 @param[in,out] NumBytes On input, indicates the requested write size. On\r
913 output, indicates the actual number of bytes written.\r
914 @param[in] Buffer Buffer containing source data for the write.\r
915\r
916\r
917Returns:\r
918 @retval EFI_SUCCESS The firmware volume was read successfully and\r
919 contents are in Buffer.\r
920 @retval EFI_BAD_BUFFER_SIZE Read attempted across a LBA boundary. On output,\r
921 NumBytes contains the total number of bytes returned\r
922 in Buffer.\r
923 @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state\r
924 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and\r
925 could not be read.\r
926 @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL.\r
927\r
928**/\r
929EFI_STATUS\r
930EFIAPI\r
931FvbProtocolRead (\r
932 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
933 IN EFI_LBA Lba,\r
934 IN UINTN Offset,\r
935 IN OUT UINTN *NumBytes,\r
936 OUT UINT8 *Buffer\r
937 )\r
938{\r
939\r
940 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
941 EFI_STATUS Status;\r
942\r
943 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
944 Status = FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer);\r
945 DEBUG((EFI_D_INFO,\r
946 "FvbProtocolRead: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x\n",\r
947 Lba,\r
948 Offset,\r
949 *NumBytes,\r
950 Buffer)\r
951 );\r
952\r
953 return Status;\r
954}\r
955\r
956\r
957/**\r
958 Check the integrity of firmware volume header.\r
959\r
960 @param[in] FwVolHeader A pointer to a firmware volume header.\r
961\r
962 @retval TRUE The firmware volume is consistent.\r
963 @retval FALSE The firmware volume has corrupted.\r
964\r
965**/\r
966BOOLEAN\r
967IsFvHeaderValid (\r
968 IN EFI_PHYSICAL_ADDRESS FvBase,\r
969 IN CONST EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader\r
970 )\r
971{\r
972 if (FvBase == PcdGet32(PcdFlashNvStorageVariableBase)) {\r
973 if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid, sizeof(EFI_GUID)) != 0 ) {\r
974 return FALSE;\r
975 }\r
976 } else {\r
977 if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem2Guid, sizeof(EFI_GUID)) != 0 ) {\r
978 return FALSE;\r
979 }\r
980 }\r
981 if ( (FwVolHeader->Revision != EFI_FVH_REVISION) ||\r
982 (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||\r
983 (FwVolHeader->FvLength == ((UINTN) -1)) ||\r
984 ((FwVolHeader->HeaderLength & 0x01 ) !=0) ) {\r
985 return FALSE;\r
986 }\r
987\r
988 if (CalculateCheckSum16 ((UINT16 *) FwVolHeader, FwVolHeader->HeaderLength) != 0) {\r
989 return FALSE;\r
990 }\r
991\r
992 return TRUE;\r
993}\r
994\r
995\r
996/**\r
997 The function does the necessary initialization work for\r
998 Firmware Volume Block Driver.\r
999\r
1000 @retval EFI_SUCCESS This funtion always return EFI_SUCCESS.\r
1001 It will ASSERT on errors.\r
1002\r
1003**/\r
1004EFI_STATUS\r
1005FvbInitialize (\r
1006 VOID\r
1007 )\r
1008{\r
1009 EFI_FW_VOL_INSTANCE *FwhInstance;\r
1010 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
1011 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r
1012 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;\r
1013 EFI_PHYSICAL_ADDRESS BaseAddress;\r
1014 EFI_STATUS Status;\r
1015 UINTN BufferSize;\r
1016 UINTN TmpHeaderLength;\r
1017 UINTN Idx;\r
1018 UINT32 MaxLbaSize;\r
1019 BOOLEAN FvHeaderValid;\r
1020\r
1021 //\r
1022 // Calculate the total size for all firmware volume block instances.\r
1023 //\r
1024 BufferSize = 0;\r
1025 for (Idx = 0; Idx < 1; Idx++) {\r
1026 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) mPlatformFvBaseAddress[Idx];\r
1027 BufferSize += (FvHeader->HeaderLength +\r
1028 sizeof (EFI_FW_VOL_INSTANCE) -\r
1029 sizeof (EFI_FIRMWARE_VOLUME_HEADER)\r
1030 );\r
1031 }\r
1032\r
1033 mFvbModuleGlobal.FvInstance = (EFI_FW_VOL_INSTANCE *) AllocateRuntimeZeroPool (BufferSize);\r
1034 ASSERT (NULL != mFvbModuleGlobal.FvInstance);\r
1035\r
1036\r
1037 MaxLbaSize = 0;\r
1038 FwhInstance = mFvbModuleGlobal.FvInstance;\r
1039 mFvbModuleGlobal.NumFv = 0;\r
1040\r
1041 for (Idx = 0; Idx < 1; Idx++) {\r
1042 BaseAddress = mPlatformFvBaseAddress[Idx];\r
1043 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;\r
1044\r
1045 if (!IsFvHeaderValid (BaseAddress, FwVolHeader)) {\r
1046 FvHeaderValid = FALSE;\r
1047 //\r
1048 // If not valid, get FvbInfo from the information carried in\r
1049 // FVB driver.\r
1050 //\r
1051 DEBUG ((EFI_D_ERROR, "Fvb: FV header @ 0x%lx invalid\n", BaseAddress));\r
1052 Status = GetFvbInfo (BaseAddress, &FwVolHeader);\r
1053 ASSERT_EFI_ERROR(Status);\r
1054 //\r
1055 // Write back a healthy FV header.\r
1056 //\r
1057 DEBUG ((EFI_D_ERROR, "FwBlockService.c: Writing back healthy FV header\n"));\r
1058 LibFvbFlashDeviceBlockLock ((UINTN)BaseAddress, FwVolHeader->BlockMap->Length, FALSE);\r
1059\r
1060 Status = LibFvbFlashDeviceBlockErase ((UINTN)BaseAddress, FwVolHeader->BlockMap->Length);\r
1061\r
1062 TmpHeaderLength = (UINTN) FwVolHeader->HeaderLength;\r
1063 Status = LibFvbFlashDeviceWrite (\r
1064 (UINTN)BaseAddress,\r
1065 &TmpHeaderLength,\r
1066 (UINT8 *) FwVolHeader\r
1067 );\r
1068\r
1069 LibFvbFlashDeviceBlockLock ((UINTN)BaseAddress, FwVolHeader->BlockMap->Length, TRUE);\r
1070\r
1071 WriteBackInvalidateDataCacheRange (\r
1072 (VOID *) (UINTN) BaseAddress,\r
1073 FwVolHeader->BlockMap->Length\r
1074 );\r
1075\r
1076 }\r
1077\r
1078 CopyMem (&(FwhInstance->VolumeHeader), FwVolHeader, FwVolHeader->HeaderLength);\r
1079\r
1080 FwVolHeader = &(FwhInstance->VolumeHeader);\r
1081 FwhInstance->FvBase = (UINTN)BaseAddress;\r
1082\r
1083 //\r
1084 // Process the block map for each FV.\r
1085 //\r
1086 FwhInstance->NumOfBlocks = 0;\r
1087 for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {\r
1088 //\r
1089 // Get the maximum size of a block.\r
1090 //\r
1091 if (MaxLbaSize < PtrBlockMapEntry->Length) {\r
1092 MaxLbaSize = PtrBlockMapEntry->Length;\r
1093 }\r
1094 FwhInstance->NumOfBlocks += PtrBlockMapEntry->NumBlocks;\r
1095 }\r
1096\r
1097 //\r
1098 // Add a FVB Protocol Instance.\r
1099 //\r
1100 mFvbModuleGlobal.NumFv++;\r
1101 InstallFvbProtocol (FwhInstance, mFvbModuleGlobal.NumFv - 1);\r
1102\r
1103 //\r
1104 // Move on to the next FwhInstance.\r
1105 //\r
1106 FwhInstance = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhInstance) +\r
1107 FwVolHeader->HeaderLength +\r
1108 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)));\r
1109\r
1110 }\r
1111\r
1112 return EFI_SUCCESS;\r
1113}\r
1114\r