]> git.proxmox.com Git - mirror_edk2.git/blame - DuetPkg/FvbRuntimeService/FWBlockService.c
Update the copyright notice format
[mirror_edk2.git] / DuetPkg / FvbRuntimeService / FWBlockService.c
CommitLineData
9071550e 1/**@file\r
b1f700a8
HT
2Copyright (c) 2007 - 2009, Intel Corporation. All rights reserved.<BR>\r
3This program and the accompanying materials \r
9071550e 4are licensed and made available under the terms and conditions of the BSD License \r
5which accompanies this distribution. The full text of the license may be found at \r
6http://opensource.org/licenses/bsd-license.php \r
7 \r
8THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
9WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
10\r
11Module Name:\r
12\r
13 FWBlockService.c\r
14 \r
15Abstract:\r
16\r
17Revision History\r
18\r
19**/\r
20#include "FWBlockService.h"\r
21#include "EfiFlashMap.h"\r
22#include "FileIo.h"\r
23#include "FlashLayout.h"\r
24\r
25ESAL_FWB_GLOBAL *mFvbModuleGlobal;\r
26VOID *mSFSRegistration;\r
27#define TRY_ASSIGN(var, value) if(var != NULL) {*var = value;}\r
28\r
29EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = {\r
30 FVB_DEVICE_SIGNATURE,\r
31 {\r
32 {\r
33 {\r
34 HARDWARE_DEVICE_PATH,\r
35 HW_MEMMAP_DP,\r
36 {\r
37 sizeof (MEMMAP_DEVICE_PATH),\r
38 0\r
39 }\r
40 },\r
41 EfiMemoryMappedIO,\r
42 0,\r
43 0,\r
44 },\r
45 {\r
46 END_DEVICE_PATH_TYPE,\r
47 END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
48 {\r
49 sizeof (EFI_DEVICE_PATH_PROTOCOL),\r
50 0\r
51 }\r
52 }\r
53 },\r
54 0,\r
55 {\r
56 FvbProtocolGetAttributes,\r
57 FvbProtocolSetAttributes,\r
58 FvbProtocolGetPhysicalAddress,\r
59 FvbProtocolGetBlockSize,\r
60 FvbProtocolRead,\r
61 FvbProtocolWrite,\r
62 FvbProtocolEraseBlocks,\r
63 NULL\r
9071550e 64 }\r
65};\r
66\r
67\r
68EFI_STATUS\r
69FlashFdWrite (\r
70 IN UINTN Address,\r
71 IN EFI_FW_VOL_INSTANCE *FwhInstance,\r
72 IN OUT UINTN *NumBytes,\r
73 IN UINT8 *Buffer\r
74 )\r
75/*++\r
76\r
77Routine Description:\r
78 Writes specified number of bytes from the input buffer to the address\r
79\r
80Arguments:\r
81\r
82Returns: \r
83\r
84--*/\r
85{\r
b0b961c8 86 EFI_STATUS Status;\r
87 EFI_FILE_PROTOCOL *File;\r
88 UINTN FileOffset;\r
89 UINTN BufferForFile;\r
90 UINTN Length;\r
9071550e 91\r
92 Status = EFI_SUCCESS;\r
93 CopyMem ((VOID *) Address, Buffer, *NumBytes);\r
94\r
95 if (!EfiAtRuntime () && (FwhInstance->Device != NULL)) {\r
96 Status = FileOpen (FwhInstance->Device, FwhInstance->MappedFile, &File, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE);\r
97 ASSERT_EFI_ERROR (Status);\r
98 if (!EFI_ERROR (Status)) {\r
99 if (Address - FwhInstance->FvBase[FVB_PHYSICAL] < FwhInstance->Offset) {\r
100 FileOffset = 0;\r
101 BufferForFile = FwhInstance->FvBase[FVB_PHYSICAL] + FwhInstance->Offset;\r
102 Length = *NumBytes - (FwhInstance->Offset - (Address - FwhInstance->FvBase[FVB_PHYSICAL]));\r
103 } else {\r
104 FileOffset = Address - FwhInstance->FvBase[FVB_PHYSICAL] - FwhInstance->Offset;\r
105 BufferForFile = Address;\r
106 Length = *NumBytes;\r
107 }\r
108 \r
109 Status = FileWrite (File, FileOffset, BufferForFile, Length);\r
110 ASSERT_EFI_ERROR (Status);\r
111 FileClose (File);\r
112 }\r
113 }\r
114 return Status;\r
115}\r
116\r
117EFI_STATUS\r
118FlashFdErase (\r
119 IN UINTN Address,\r
120 IN EFI_FW_VOL_INSTANCE *FwhInstance,\r
121 IN UINTN LbaLength\r
122 )\r
123/*++\r
124\r
125Routine Description:\r
126 Erase a certain block from address LbaWriteAddress\r
127\r
128Arguments:\r
129\r
130Returns: \r
131\r
132--*/\r
133{\r
b0b961c8 134 EFI_STATUS Status;\r
135 EFI_FILE_PROTOCOL *File;\r
136 UINTN FileOffset;\r
137 UINTN BufferForFile;\r
138 UINTN Length;\r
9071550e 139\r
140 Status = EFI_SUCCESS;\r
141\r
142 SetMem ((VOID *)Address, LbaLength, 0xff);\r
143\r
144 if (!EfiAtRuntime () && (FwhInstance->Device != NULL)) {\r
145 Status = FileOpen (FwhInstance->Device, FwhInstance->MappedFile, &File, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE);\r
146 ASSERT_EFI_ERROR (Status);\r
147 if (!EFI_ERROR (Status)) {\r
148 if (Address - FwhInstance->FvBase[FVB_PHYSICAL] < FwhInstance->Offset) {\r
149 FileOffset = 0;\r
150 BufferForFile = FwhInstance->FvBase[FVB_PHYSICAL] + FwhInstance->Offset;\r
151 Length = LbaLength - (FwhInstance->Offset - (Address - FwhInstance->FvBase[FVB_PHYSICAL]));\r
152 } else {\r
153 FileOffset = Address - FwhInstance->FvBase[FVB_PHYSICAL] - FwhInstance->Offset;\r
154 BufferForFile = Address;\r
155 Length = LbaLength;\r
156 }\r
157 \r
158 Status = FileWrite (File, FileOffset, BufferForFile, Length);\r
159 ASSERT_EFI_ERROR (Status);\r
160 FileClose (File);\r
161 }\r
162 }\r
163 return Status;\r
164}\r
165\r
166VOID\r
167EFIAPI\r
168FvbVirtualddressChangeEvent (\r
169 IN EFI_EVENT Event,\r
170 IN VOID *Context\r
171 )\r
172/*++\r
173\r
174Routine Description:\r
175\r
176 Fixup internal data so that EFI and SAL can be call in virtual mode.\r
177 Call the passed in Child Notify event and convert the mFvbModuleGlobal\r
178 date items to there virtual address.\r
179\r
180 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data\r
181 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common \r
182 instance data.\r
183\r
184Arguments:\r
185\r
186 (Standard EFI notify event - EFI_EVENT_NOTIFY)\r
187\r
188Returns: \r
189\r
190 None\r
191\r
192--*/\r
193{\r
194 EFI_FW_VOL_INSTANCE *FwhInstance;\r
195 UINTN Index;\r
196\r
197 EfiConvertPointer (0, (VOID **) &mFvbModuleGlobal->FvInstance[FVB_VIRTUAL]);\r
198\r
199 //\r
200 // Convert the base address of all the instances\r
201 //\r
202 Index = 0;\r
203 FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];\r
204 while (Index < mFvbModuleGlobal->NumFv) {\r
205 EfiConvertPointer (0, (VOID **) &FwhInstance->FvBase[FVB_VIRTUAL]);\r
206 FwhInstance = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhInstance) + FwhInstance->VolumeHeader.HeaderLength\r
207 + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)));\r
208 Index++;\r
209 }\r
210\r
211 EfiConvertPointer (0, (VOID **) &mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL]);\r
212 EfiConvertPointer (0, (VOID **) &mFvbModuleGlobal);\r
213}\r
214\r
215EFI_STATUS\r
216GetFvbInstance (\r
217 IN UINTN Instance,\r
218 IN ESAL_FWB_GLOBAL *Global,\r
219 OUT EFI_FW_VOL_INSTANCE **FwhInstance,\r
220 IN BOOLEAN Virtual\r
221 )\r
222/*++\r
223\r
224Routine Description:\r
225 Retrieves the physical address of a memory mapped FV\r
226\r
227Arguments:\r
228 Instance - The FV instance whose base address is going to be\r
229 returned\r
230 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
231 instance data\r
232 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure\r
233 Virtual - Whether CPU is in virtual or physical mode\r
234\r
235Returns: \r
236 EFI_SUCCESS - Successfully returns\r
237 EFI_INVALID_PARAMETER - Instance not found\r
238\r
239--*/\r
240{\r
241 EFI_FW_VOL_INSTANCE *FwhRecord;\r
242\r
243 if (Instance >= Global->NumFv) {\r
244 return EFI_INVALID_PARAMETER;\r
245 }\r
246 //\r
247 // Find the right instance of the FVB private data\r
248 //\r
249 FwhRecord = Global->FvInstance[Virtual];\r
250 while (Instance > 0) {\r
251 FwhRecord = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhRecord) + FwhRecord->VolumeHeader.HeaderLength \r
252 + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)));\r
253 Instance--;\r
254 }\r
255\r
256 *FwhInstance = FwhRecord;\r
257\r
258 return EFI_SUCCESS;\r
259}\r
260\r
261EFI_STATUS\r
262FvbGetPhysicalAddress (\r
263 IN UINTN Instance,\r
264 OUT EFI_PHYSICAL_ADDRESS *Address,\r
265 IN ESAL_FWB_GLOBAL *Global,\r
266 IN BOOLEAN Virtual\r
267 )\r
268/*++\r
269\r
270Routine Description:\r
271 Retrieves the physical address of a memory mapped FV\r
272\r
273Arguments:\r
274 Instance - The FV instance whose base address is going to be\r
275 returned\r
276 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS \r
277 that on successful return, contains the base address\r
278 of the firmware volume. \r
279 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
280 instance data\r
281 Virtual - Whether CPU is in virtual or physical mode\r
282\r
283Returns: \r
284 EFI_SUCCESS - Successfully returns\r
285 EFI_INVALID_PARAMETER - Instance not found\r
286\r
287--*/\r
288{\r
289 EFI_FW_VOL_INSTANCE *FwhInstance;\r
290 EFI_STATUS Status;\r
291\r
292 //\r
293 // Find the right instance of the FVB private data\r
294 //\r
295 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
296 ASSERT_EFI_ERROR (Status);\r
297 *Address = FwhInstance->FvBase[Virtual];\r
298\r
299 return EFI_SUCCESS;\r
300}\r
301\r
302EFI_STATUS\r
303FvbGetVolumeAttributes (\r
304 IN UINTN Instance,\r
8ee3a199 305 OUT EFI_FVB_ATTRIBUTES_2 *Attributes,\r
9071550e 306 IN ESAL_FWB_GLOBAL *Global,\r
307 IN BOOLEAN Virtual\r
308 )\r
309/*++\r
310\r
311Routine Description:\r
312 Retrieves attributes, insures positive polarity of attribute bits, returns\r
313 resulting attributes in output parameter\r
314\r
315Arguments:\r
316 Instance - The FV instance whose attributes is going to be \r
317 returned\r
318 Attributes - Output buffer which contains attributes\r
319 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
320 instance data\r
321 Virtual - Whether CPU is in virtual or physical mode\r
322\r
323Returns: \r
324 EFI_SUCCESS - Successfully returns\r
325 EFI_INVALID_PARAMETER - Instance not found\r
326\r
327--*/\r
328{\r
329 EFI_FW_VOL_INSTANCE *FwhInstance;\r
330 EFI_STATUS Status;\r
331\r
332 //\r
333 // Find the right instance of the FVB private data\r
334 //\r
335 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
336 ASSERT_EFI_ERROR (Status);\r
337 *Attributes = FwhInstance->VolumeHeader.Attributes;\r
338\r
339 return EFI_SUCCESS;\r
340}\r
341\r
342EFI_STATUS\r
343FvbGetLbaAddress (\r
344 IN UINTN Instance,\r
345 IN EFI_LBA Lba,\r
346 OUT UINTN *LbaAddress OPTIONAL,\r
347 OUT UINTN *LbaLength OPTIONAL,\r
348 OUT UINTN *NumOfBlocks OPTIONAL,\r
349 IN ESAL_FWB_GLOBAL *Global,\r
350 IN BOOLEAN Virtual\r
351 )\r
352/*++\r
353\r
354Routine Description:\r
355 Retrieves the starting address of an LBA in an FV\r
356\r
357Arguments:\r
358 Instance - The FV instance which the Lba belongs to\r
359 Lba - The logical block address\r
360 LbaAddress - On output, contains the physical starting address\r
361 of the Lba for writing\r
362 LbaLength - On output, contains the length of the block\r
363 NumOfBlocks - A pointer to a caller allocated UINTN in which the\r
364 number of consecutive blocks starting with Lba is\r
365 returned. All blocks in this range have a size of\r
366 BlockSize\r
367 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
368 instance data\r
369 Virtual - Whether CPU is in virtual or physical mode\r
370\r
371Returns: \r
372 EFI_SUCCESS - Successfully returns\r
373 EFI_INVALID_PARAMETER - Instance not found\r
374\r
375--*/\r
376{\r
377 UINT32 NumBlocks;\r
378 UINT32 BlockLength;\r
379 UINTN Offset;\r
380 EFI_LBA StartLba;\r
381 EFI_LBA NextLba;\r
382 EFI_FW_VOL_INSTANCE *FwhInstance;\r
383 EFI_FV_BLOCK_MAP_ENTRY *BlockMap;\r
384 EFI_STATUS Status;\r
385\r
386 //\r
387 // Find the right instance of the FVB private data\r
388 //\r
389 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
390 ASSERT_EFI_ERROR (Status);\r
391\r
392 StartLba = 0;\r
393 Offset = 0;\r
394 BlockMap = &(FwhInstance->VolumeHeader.BlockMap[0]);\r
395\r
396 //\r
397 // Parse the blockmap of the FV to find which map entry the Lba belongs to\r
398 //\r
399 while (TRUE) {\r
400 NumBlocks = BlockMap->NumBlocks;\r
401 BlockLength = BlockMap->Length;\r
402\r
403 if (NumBlocks == 0 || BlockLength == 0) {\r
404 return EFI_INVALID_PARAMETER;\r
405 }\r
406\r
407 NextLba = StartLba + NumBlocks;\r
408\r
409 //\r
410 // The map entry found\r
411 //\r
412 if (Lba >= StartLba && Lba < NextLba) {\r
413 Offset = Offset + (UINTN) MultU64x32 ((Lba - StartLba), BlockLength);\r
414\r
415 if (LbaAddress) {\r
416 *LbaAddress = FwhInstance->FvBase[Virtual] + Offset;\r
417 }\r
418\r
419 if (LbaLength) {\r
420 *LbaLength = BlockLength;\r
421 }\r
422\r
423 if (NumOfBlocks) {\r
424 *NumOfBlocks = (UINTN) (NextLba - Lba);\r
425 }\r
426\r
427 return EFI_SUCCESS;\r
428 }\r
429\r
430 StartLba = NextLba;\r
431 Offset = Offset + NumBlocks * BlockLength;\r
432 BlockMap++;\r
433 }\r
434}\r
435\r
436EFI_STATUS\r
437FvbReadBlock (\r
438 IN UINTN Instance,\r
439 IN EFI_LBA Lba,\r
440 IN UINTN BlockOffset,\r
441 IN OUT UINTN *NumBytes,\r
442 IN UINT8 *Buffer,\r
443 IN ESAL_FWB_GLOBAL *Global,\r
444 IN BOOLEAN Virtual\r
445 )\r
446/*++\r
447\r
448Routine Description:\r
449 Reads specified number of bytes into a buffer from the specified block\r
450\r
451Arguments:\r
452 Instance - The FV instance to be read from\r
453 Lba - The logical block address to be read from\r
454 BlockOffset - Offset into the block at which to begin reading\r
455 NumBytes - Pointer that on input contains the total size of\r
456 the buffer. On output, it contains the total number\r
457 of bytes read\r
458 Buffer - Pointer to a caller allocated buffer that will be\r
459 used to hold the data read\r
460 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
461 instance data\r
462 Virtual - Whether CPU is in virtual or physical mode\r
463\r
464Returns: \r
465 EFI_SUCCESS - The firmware volume was read successfully and \r
466 contents are in Buffer\r
467 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,\r
468 NumBytes contains the total number of bytes returned\r
469 in Buffer\r
470 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state\r
471 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
472 could not be read\r
473 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL\r
474\r
475--*/\r
476{\r
8ee3a199 477 EFI_FVB_ATTRIBUTES_2 Attributes;\r
478 UINTN LbaAddress;\r
479 UINTN LbaLength;\r
480 EFI_STATUS Status;\r
9071550e 481\r
482 //\r
483 // Check for invalid conditions\r
484 //\r
485 if ((NumBytes == NULL) || (Buffer == NULL)) {\r
486 return EFI_INVALID_PARAMETER;\r
487 }\r
488\r
489 if (*NumBytes == 0) {\r
490 return EFI_INVALID_PARAMETER;\r
491 }\r
492\r
493 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);\r
494 if (EFI_ERROR (Status)) {\r
495 return Status;\r
496 }\r
497 //\r
498 // Check if the FV is read enabled\r
499 //\r
500 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);\r
501\r
502 if ((Attributes & EFI_FVB2_READ_STATUS) == 0) {\r
503 return EFI_ACCESS_DENIED;\r
504 }\r
505 //\r
506 // Perform boundary checks and adjust NumBytes\r
507 //\r
508 if (BlockOffset > LbaLength) {\r
509 return EFI_INVALID_PARAMETER;\r
510 }\r
511\r
512 if (LbaLength < (*NumBytes + BlockOffset)) {\r
513 *NumBytes = (UINT32) (LbaLength - BlockOffset);\r
514 Status = EFI_BAD_BUFFER_SIZE;\r
515 }\r
516\r
517 CopyMem (Buffer, (VOID *) (LbaAddress + BlockOffset), (UINTN) *NumBytes);\r
518\r
519 return Status;\r
520}\r
521EFI_STATUS\r
522FvbWriteBlock (\r
523 IN UINTN Instance,\r
524 IN EFI_LBA Lba,\r
525 IN UINTN BlockOffset,\r
526 IN OUT UINTN *NumBytes,\r
527 IN UINT8 *Buffer,\r
528 IN ESAL_FWB_GLOBAL *Global,\r
529 IN BOOLEAN Virtual\r
530 )\r
531/*++\r
532\r
533Routine Description:\r
534 Writes specified number of bytes from the input buffer to the block\r
535\r
536Arguments:\r
537 Instance - The FV instance to be written to\r
538 Lba - The starting logical block index to write to\r
539 BlockOffset - Offset into the block at which to begin writing\r
540 NumBytes - Pointer that on input contains the total size of\r
541 the buffer. On output, it contains the total number\r
542 of bytes actually written\r
543 Buffer - Pointer to a caller allocated buffer that contains\r
544 the source for the write\r
545 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
546 instance data\r
547 Virtual - Whether CPU is in virtual or physical mode\r
548\r
549Returns: \r
550 EFI_SUCCESS - The firmware volume was written successfully\r
551 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,\r
552 NumBytes contains the total number of bytes\r
553 actually written\r
554 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
555 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
556 could not be written\r
557 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL\r
558\r
559--*/\r
560{\r
8ee3a199 561 EFI_FVB_ATTRIBUTES_2 Attributes;\r
562 UINTN LbaAddress;\r
563 UINTN LbaLength;\r
564 EFI_FW_VOL_INSTANCE *FwhInstance;\r
565 EFI_STATUS Status;\r
566 EFI_STATUS ReturnStatus;\r
9071550e 567\r
568 //\r
569 // Find the right instance of the FVB private data\r
570 //\r
571 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
572 ASSERT_EFI_ERROR (Status);\r
573\r
574 //\r
575 // Writes are enabled in the init routine itself\r
576 //\r
577 if (!FwhInstance->WriteEnabled) {\r
578 return EFI_ACCESS_DENIED;\r
579 }\r
580 //\r
581 // Check for invalid conditions\r
582 //\r
583 if ((NumBytes == NULL) || (Buffer == NULL)) {\r
584 return EFI_INVALID_PARAMETER;\r
585 }\r
586\r
587 if (*NumBytes == 0) {\r
588 return EFI_INVALID_PARAMETER;\r
589 }\r
590\r
591 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);\r
592 if (EFI_ERROR (Status)) {\r
593 return Status;\r
594 }\r
595 //\r
596 // Check if the FV is write enabled\r
597 //\r
598 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);\r
599\r
600 if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {\r
601 return EFI_ACCESS_DENIED;\r
602 }\r
603 //\r
604 // Perform boundary checks and adjust NumBytes\r
605 //\r
606 if (BlockOffset > LbaLength) {\r
607 return EFI_INVALID_PARAMETER;\r
608 }\r
609\r
610 if (LbaLength < (*NumBytes + BlockOffset)) {\r
611 *NumBytes = (UINT32) (LbaLength - BlockOffset);\r
612 Status = EFI_BAD_BUFFER_SIZE;\r
613 }\r
614\r
615 ReturnStatus = FlashFdWrite (\r
616 LbaAddress + BlockOffset,\r
617 FwhInstance,\r
618 NumBytes,\r
619 Buffer\r
620 );\r
621 if (EFI_ERROR (ReturnStatus)) {\r
622 return ReturnStatus;\r
623 }\r
624\r
625 return Status;\r
626}\r
627\r
628EFI_STATUS\r
629FvbEraseBlock (\r
630 IN UINTN Instance,\r
631 IN EFI_LBA Lba,\r
632 IN ESAL_FWB_GLOBAL *Global,\r
633 IN BOOLEAN Virtual\r
634 )\r
635/*++\r
636\r
637Routine Description:\r
638 Erases and initializes a firmware volume block\r
639\r
640Arguments:\r
641 Instance - The FV instance to be erased\r
642 Lba - The logical block index to be erased\r
643 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
644 instance data\r
645 Virtual - Whether CPU is in virtual or physical mode\r
646\r
647Returns: \r
648 EFI_SUCCESS - The erase request was successfully completed\r
649 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
650 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
651 could not be written. Firmware device may have been\r
652 partially erased\r
653 EFI_INVALID_PARAMETER - Instance not found\r
654\r
655--*/\r
656{\r
657\r
8ee3a199 658 EFI_FVB_ATTRIBUTES_2 Attributes;\r
659 UINTN LbaAddress;\r
660 EFI_FW_VOL_INSTANCE *FwhInstance;\r
661 UINTN LbaLength;\r
662 EFI_STATUS Status;\r
9071550e 663\r
664 //\r
665 // Find the right instance of the FVB private data\r
666 //\r
667 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
668 ASSERT_EFI_ERROR (Status);\r
669\r
670 //\r
671 // Writes are enabled in the init routine itself\r
672 //\r
673 if (!FwhInstance->WriteEnabled) {\r
674 return EFI_ACCESS_DENIED;\r
675 }\r
676 //\r
677 // Check if the FV is write enabled\r
678 //\r
679 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);\r
680\r
681 if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {\r
682 return EFI_ACCESS_DENIED;\r
683 }\r
684 //\r
685 // Get the starting address of the block for erase. For debug reasons,\r
686 // LbaWriteAddress may not be the same as LbaAddress.\r
687 //\r
688 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);\r
689 if (EFI_ERROR (Status)) {\r
690 return Status;\r
691 }\r
692\r
693 return FlashFdErase (\r
694 LbaAddress,\r
695 FwhInstance,\r
696 LbaLength\r
697 );\r
698}\r
699\r
9071550e 700EFI_STATUS\r
701FvbSetVolumeAttributes (\r
702 IN UINTN Instance,\r
8ee3a199 703 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes,\r
9071550e 704 IN ESAL_FWB_GLOBAL *Global,\r
705 IN BOOLEAN Virtual\r
706 )\r
707/*++\r
708\r
709Routine Description:\r
710 Modifies the current settings of the firmware volume according to the \r
711 input parameter, and returns the new setting of the volume\r
712\r
713Arguments:\r
714 Instance - The FV instance whose attributes is going to be \r
715 modified\r
8ee3a199 716 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2 \r
9071550e 717 containing the desired firmware volume settings.\r
718 On successful return, it contains the new settings\r
719 of the firmware volume\r
720 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
721 instance data\r
722 Virtual - Whether CPU is in virtual or physical mode\r
723\r
724Returns: \r
725 EFI_SUCCESS - Successfully returns\r
726 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified\r
727 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are\r
728 in conflict with the capabilities as declared in the\r
729 firmware volume header\r
730\r
731--*/\r
732{\r
8ee3a199 733 EFI_FW_VOL_INSTANCE *FwhInstance;\r
734 EFI_FVB_ATTRIBUTES_2 OldAttributes;\r
735 EFI_FVB_ATTRIBUTES_2 *AttribPtr;\r
736 UINT32 Capabilities;\r
737 UINT32 OldStatus;\r
738 UINT32 NewStatus;\r
739 EFI_STATUS Status;\r
9071550e 740\r
741 //\r
742 // Find the right instance of the FVB private data\r
743 //\r
744 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
745 ASSERT_EFI_ERROR (Status);\r
746\r
8ee3a199 747 AttribPtr = (EFI_FVB_ATTRIBUTES_2 *) &(FwhInstance->VolumeHeader.Attributes);\r
9071550e 748 OldAttributes = *AttribPtr;\r
749 Capabilities = OldAttributes & EFI_FVB2_CAPABILITIES;\r
750 OldStatus = OldAttributes & EFI_FVB2_STATUS;\r
751 NewStatus = *Attributes & EFI_FVB2_STATUS;\r
752\r
753 //\r
754 // If firmware volume is locked, no status bit can be updated\r
755 //\r
756 if (OldAttributes & EFI_FVB2_LOCK_STATUS) {\r
757 if (OldStatus ^ NewStatus) {\r
758 return EFI_ACCESS_DENIED;\r
759 }\r
760 }\r
761 //\r
762 // Test read disable\r
763 //\r
764 if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {\r
765 if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {\r
766 return EFI_INVALID_PARAMETER;\r
767 }\r
768 }\r
769 //\r
770 // Test read enable\r
771 //\r
772 if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {\r
773 if (NewStatus & EFI_FVB2_READ_STATUS) {\r
774 return EFI_INVALID_PARAMETER;\r
775 }\r
776 }\r
777 //\r
778 // Test write disable\r
779 //\r
780 if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {\r
781 if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {\r
782 return EFI_INVALID_PARAMETER;\r
783 }\r
784 }\r
785 //\r
786 // Test write enable\r
787 //\r
788 if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {\r
789 if (NewStatus & EFI_FVB2_WRITE_STATUS) {\r
790 return EFI_INVALID_PARAMETER;\r
791 }\r
792 }\r
793 //\r
794 // Test lock\r
795 //\r
796 if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {\r
797 if (NewStatus & EFI_FVB2_LOCK_STATUS) {\r
798 return EFI_INVALID_PARAMETER;\r
799 }\r
800 }\r
801\r
802 *AttribPtr = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));\r
803 *AttribPtr = (*AttribPtr) | NewStatus;\r
804 *Attributes = *AttribPtr;\r
805\r
806 return EFI_SUCCESS;\r
807}\r
808//\r
809// FVB protocol APIs\r
810//\r
811EFI_STATUS\r
812EFIAPI\r
813FvbProtocolGetPhysicalAddress (\r
814 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
815 OUT EFI_PHYSICAL_ADDRESS *Address\r
816 )\r
817/*++\r
818\r
819Routine Description:\r
820\r
821 Retrieves the physical address of the device.\r
822\r
823Arguments:\r
824\r
825 This - Calling context\r
826 Address - Output buffer containing the address.\r
827\r
828Returns:\r
829\r
830Returns: \r
831 EFI_SUCCESS - Successfully returns\r
832\r
833--*/\r
834{\r
835 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
836\r
837 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
838\r
839 return FvbGetPhysicalAddress (FvbDevice->Instance, Address, mFvbModuleGlobal, EfiGoneVirtual ());\r
840}\r
841\r
842EFI_STATUS\r
843EFIAPI\r
844FvbProtocolGetBlockSize (\r
845 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
846 IN EFI_LBA Lba,\r
847 OUT UINTN *BlockSize,\r
848 OUT UINTN *NumOfBlocks\r
849 )\r
850/*++\r
851\r
852Routine Description:\r
853 Retrieve the size of a logical block\r
854\r
855Arguments:\r
856 This - Calling context\r
857 Lba - Indicates which block to return the size for.\r
858 BlockSize - A pointer to a caller allocated UINTN in which\r
859 the size of the block is returned\r
860 NumOfBlocks - a pointer to a caller allocated UINTN in which the\r
861 number of consecutive blocks starting with Lba is\r
862 returned. All blocks in this range have a size of\r
863 BlockSize\r
864\r
865Returns: \r
866 EFI_SUCCESS - The firmware volume was read successfully and \r
867 contents are in 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 return FvbGetLbaAddress (\r
876 FvbDevice->Instance,\r
877 Lba,\r
878 NULL,\r
879 BlockSize,\r
880 NumOfBlocks,\r
881 mFvbModuleGlobal,\r
882 EfiGoneVirtual ()\r
883 );\r
884}\r
885\r
886EFI_STATUS\r
887EFIAPI\r
888FvbProtocolGetAttributes (\r
889 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
8ee3a199 890 OUT EFI_FVB_ATTRIBUTES_2 *Attributes\r
9071550e 891 )\r
892/*++\r
893\r
894Routine Description:\r
895 Retrieves Volume attributes. No polarity translations are done.\r
896\r
897Arguments:\r
898 This - Calling context\r
899 Attributes - output buffer which contains attributes\r
900\r
901Returns: \r
902 EFI_SUCCESS - Successfully returns\r
903\r
904--*/\r
905{\r
906 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
907\r
908 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
909\r
910 return FvbGetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());\r
911}\r
912\r
913EFI_STATUS\r
914EFIAPI\r
915FvbProtocolSetAttributes (\r
916 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
8ee3a199 917 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes\r
9071550e 918 )\r
919/*++\r
920\r
921Routine Description:\r
922 Sets Volume attributes. No polarity translations are done.\r
923\r
924Arguments:\r
925 This - Calling context\r
926 Attributes - output buffer which contains attributes\r
927\r
928Returns: \r
929 EFI_SUCCESS - Successfully returns\r
930\r
931--*/\r
932{\r
933 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
934\r
935 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
936\r
937 return FvbSetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());\r
938}\r
939\r
940EFI_STATUS\r
941EFIAPI\r
942FvbProtocolEraseBlocks (\r
943 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
944 ... \r
945 )\r
946/*++\r
947\r
948Routine Description:\r
949\r
950 The EraseBlock() function erases one or more blocks as denoted by the \r
951 variable argument list. The entire parameter list of blocks must be verified\r
952 prior to erasing any blocks. If a block is requested that does not exist \r
953 within the associated firmware volume (it has a larger index than the last \r
954 block of the firmware volume), the EraseBlock() function must return\r
955 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.\r
956\r
957Arguments:\r
958 This - Calling context\r
959 ... - Starting LBA followed by Number of Lba to erase. \r
960 a -1 to terminate the list.\r
961\r
962Returns: \r
963 EFI_SUCCESS - The erase request was successfully completed\r
964 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
965 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
966 could not be written. Firmware device may have been\r
967 partially erased\r
968\r
969--*/\r
970{\r
971 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
972 EFI_FW_VOL_INSTANCE *FwhInstance;\r
973 UINTN NumOfBlocks;\r
974 VA_LIST args;\r
975 EFI_LBA StartingLba;\r
976 UINTN NumOfLba;\r
977 EFI_STATUS Status;\r
978\r
979 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
980\r
981 Status = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal, &FwhInstance, EfiGoneVirtual ());\r
982 ASSERT_EFI_ERROR (Status);\r
983\r
984 NumOfBlocks = FwhInstance->NumOfBlocks;\r
985\r
986 VA_START (args, This);\r
987\r
988 do {\r
989 StartingLba = VA_ARG (args, EFI_LBA);\r
990 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {\r
991 break;\r
992 }\r
993\r
994 NumOfLba = VA_ARG (args, UINT32);\r
995\r
996 //\r
997 // Check input parameters\r
998 //\r
999 if ((NumOfLba == 0) || ((StartingLba + NumOfLba) > NumOfBlocks)) {\r
1000 VA_END (args);\r
1001 return EFI_INVALID_PARAMETER;\r
1002 }\r
1003 } while (1);\r
1004\r
1005 VA_END (args);\r
1006\r
1007 VA_START (args, This);\r
1008 do {\r
1009 StartingLba = VA_ARG (args, EFI_LBA);\r
1010 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {\r
1011 break;\r
1012 }\r
1013\r
1014 NumOfLba = VA_ARG (args, UINT32);\r
1015\r
1016 while (NumOfLba > 0) {\r
1017 Status = FvbEraseBlock (FvbDevice->Instance, StartingLba, mFvbModuleGlobal, EfiGoneVirtual ());\r
1018 if (EFI_ERROR (Status)) {\r
1019 VA_END (args);\r
1020 return Status;\r
1021 }\r
1022\r
1023 StartingLba++;\r
1024 NumOfLba--;\r
1025 }\r
1026\r
1027 } while (1);\r
1028\r
1029 VA_END (args);\r
1030\r
1031 return EFI_SUCCESS;\r
1032}\r
1033\r
1034EFI_STATUS\r
1035EFIAPI\r
1036FvbProtocolWrite (\r
1037 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
1038 IN EFI_LBA Lba,\r
1039 IN UINTN Offset,\r
1040 IN OUT UINTN *NumBytes,\r
1041 IN UINT8 *Buffer\r
1042 )\r
1043/*++\r
1044\r
1045Routine Description:\r
1046\r
1047 Writes data beginning at Lba:Offset from FV. The write terminates either\r
1048 when *NumBytes of data have been written, or when a block boundary is\r
1049 reached. *NumBytes is updated to reflect the actual number of bytes\r
1050 written. The write opertion does not include erase. This routine will\r
1051 attempt to write only the specified bytes. If the writes do not stick,\r
1052 it will return an error.\r
1053\r
1054Arguments:\r
1055 This - Calling context\r
1056 Lba - Block in which to begin write\r
1057 Offset - Offset in the block at which to begin write\r
1058 NumBytes - On input, indicates the requested write size. On\r
1059 output, indicates the actual number of bytes written\r
1060 Buffer - Buffer containing source data for the write.\r
1061\r
1062Returns: \r
1063 EFI_SUCCESS - The firmware volume was written successfully\r
1064 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,\r
1065 NumBytes contains the total number of bytes\r
1066 actually written\r
1067 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
1068 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
1069 could not be written\r
1070 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL\r
1071\r
1072--*/\r
1073{\r
1074\r
1075 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1076\r
1077 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1078\r
1079 return FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());\r
1080}\r
1081\r
1082EFI_STATUS\r
1083EFIAPI\r
1084FvbProtocolRead (\r
1085 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
1086 IN EFI_LBA Lba,\r
1087 IN UINTN Offset,\r
1088 IN OUT UINTN *NumBytes,\r
1089 IN UINT8 *Buffer\r
1090 )\r
1091/*++\r
1092\r
1093Routine Description:\r
1094\r
1095 Reads data beginning at Lba:Offset from FV. The Read terminates either\r
1096 when *NumBytes of data have been read, or when a block boundary is\r
1097 reached. *NumBytes is updated to reflect the actual number of bytes\r
1098 written. The write opertion does not include erase. This routine will\r
1099 attempt to write only the specified bytes. If the writes do not stick,\r
1100 it will return an error.\r
1101\r
1102Arguments:\r
1103 This - Calling context\r
1104 Lba - Block in which to begin Read\r
1105 Offset - Offset in the block at which to begin Read\r
1106 NumBytes - On input, indicates the requested write size. On\r
1107 output, indicates the actual number of bytes Read\r
1108 Buffer - Buffer containing source data for the Read.\r
1109\r
1110Returns: \r
1111 EFI_SUCCESS - The firmware volume was read successfully and \r
1112 contents are in Buffer\r
1113 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,\r
1114 NumBytes contains the total number of bytes returned\r
1115 in Buffer\r
1116 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state\r
1117 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
1118 could not be read\r
1119 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL\r
1120\r
1121--*/\r
1122{\r
1123\r
1124 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1125\r
1126 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1127\r
1128 return FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());\r
1129}\r
9071550e 1130\r
9071550e 1131EFI_STATUS\r
1132ValidateFvHeader (\r
1133 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader\r
1134 )\r
1135/*++\r
1136\r
1137Routine Description:\r
1138 Check the integrity of firmware volume header\r
1139\r
1140Arguments:\r
1141 FwVolHeader - A pointer to a firmware volume header\r
1142\r
1143Returns: \r
1144 EFI_SUCCESS - The firmware volume is consistent\r
1145 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV\r
1146\r
1147--*/\r
1148{\r
1149 UINT16 *Ptr;\r
1150 UINT16 HeaderLength;\r
1151 UINT16 Checksum;\r
1152\r
1153 //\r
1154 // Verify the header revision, header signature, length\r
1155 // Length of FvBlock cannot be 2**64-1\r
1156 // HeaderLength cannot be an odd number\r
1157 //\r
1158 if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||\r
1159 (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||\r
1160 (FwVolHeader->FvLength == ((UINTN) -1)) ||\r
1161 ((FwVolHeader->HeaderLength & 0x01) != 0)\r
1162 ) {\r
1163 return EFI_NOT_FOUND;\r
1164 }\r
1165 //\r
1166 // Verify the header checksum\r
1167 //\r
1168 HeaderLength = (UINT16) (FwVolHeader->HeaderLength / 2);\r
1169 Ptr = (UINT16 *) FwVolHeader;\r
1170 Checksum = 0;\r
1171 while (HeaderLength > 0) {\r
1172 Checksum = Checksum + (*Ptr);\r
1173 HeaderLength--;\r
1174 Ptr++;\r
1175 }\r
1176\r
1177 if (Checksum != 0) {\r
1178 return EFI_NOT_FOUND;\r
1179 }\r
1180\r
1181 return EFI_SUCCESS;\r
1182}\r
1183\r
1184\r
1185EFI_STATUS\r
1186GetFvbHeader (\r
eb16e240 1187 IN OUT EFI_PEI_HOB_POINTERS *HobList,\r
9071550e 1188 OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader,\r
1189 OUT EFI_PHYSICAL_ADDRESS *BaseAddress OPTIONAL,\r
1190 OUT UINT32 *VolumeId OPTIONAL,\r
1191 OUT CHAR16 **MappedFile OPTIONAL,\r
1192 OUT UINT32 *ActuralSize OPTIONAL,\r
1193 OUT UINT32 *Offset OPTIONAL,\r
1194 OUT BOOLEAN *WriteBack OPTIONAL\r
1195 )\r
1196{\r
1197 EFI_STATUS Status;\r
9071550e 1198 EFI_FLASH_MAP_FS_ENTRY_DATA *FlashMapEntry;\r
1199 EFI_FLASH_SUBAREA_ENTRY *FlashMapSubEntry;\r
1200\r
1201 Status = EFI_SUCCESS;\r
1202 *FwVolHeader = NULL;\r
1203 TRY_ASSIGN (WriteBack, FALSE);\r
1204\r
eb16e240 1205 DEBUG ((EFI_D_INFO, "Hob start is 0x%x\n", (UINTN)(*HobList).Raw));\r
1206 (*HobList).Raw = GetNextGuidHob (&gEfiFlashMapHobGuid, (*HobList).Raw);\r
1207 if ((*HobList).Raw == NULL) {\r
9071550e 1208 return EFI_NOT_FOUND;\r
1209 }\r
1210\r
eb16e240 1211 FlashMapEntry = (EFI_FLASH_MAP_FS_ENTRY_DATA *) GET_GUID_HOB_DATA ((*HobList).Guid);\r
9071550e 1212 FlashMapSubEntry = &FlashMapEntry->Entries[0];\r
eb16e240 1213 \r
9071550e 1214 //\r
1215 // Check if it is a "FVB" area\r
1216 //\r
1217 if (!CompareGuid (&FlashMapSubEntry->FileSystem, &gEfiFirmwareVolumeBlockProtocolGuid)) {\r
1218 return Status;\r
1219 }\r
1220 //\r
1221 // Check if it is a "real" flash\r
1222 //\r
1223 if (FlashMapSubEntry->Attributes != (EFI_FLASH_AREA_FV | EFI_FLASH_AREA_MEMMAPPED_FV)) {\r
1224 return Status;\r
1225 }\r
1226\r
1227 TRY_ASSIGN (BaseAddress, FlashMapSubEntry->Base);\r
1228\r
1229 //\r
1230 // Cast buffer to FLASH_AREA_INFO to get extra information related to the special FVB driver\r
1231 //\r
1232 TRY_ASSIGN (VolumeId, FlashMapEntry->VolumeId);\r
1233 TRY_ASSIGN (ActuralSize, FlashMapEntry->ActuralSize);\r
1234 TRY_ASSIGN (MappedFile, ((CHAR16 *) FlashMapEntry->FilePath));\r
1235 TRY_ASSIGN (Offset, FlashMapEntry->Offset);\r
1236\r
1237 DEBUG ((\r
be768885 1238 EFI_D_INFO, \r
9071550e 1239 "FlashMap HOB: BaseAddress = 0x%x, Length = 0x%x, ActuralLength = 0x%x, Offset = 0x%x\n", \r
1240 (UINTN) FlashMapSubEntry->Base, (UINTN) FlashMapSubEntry->Length, \r
1241 (UINTN) FlashMapEntry->ActuralSize, (UINTN) FlashMapEntry->Offset\r
1242 ));\r
1243 DEBUG ((\r
be768885 1244 EFI_D_INFO,\r
9071550e 1245 "FlashMap HOB: VolumeId = 0x%lx, MappedFile = %s\n",\r
1246 (UINTN) FlashMapEntry->VolumeId, (UINTN) FlashMapEntry->FilePath\r
1247 ));\r
1248 *FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (FlashMapSubEntry->Base);\r
1249 Status = ValidateFvHeader (*FwVolHeader);\r
1250 if (EFI_ERROR (Status)) {\r
1251 //\r
1252 // Get FvbInfo\r
1253 //\r
1254 TRY_ASSIGN (WriteBack, TRUE);\r
1255 Status = GetFvbInfo (FlashMapSubEntry->Length, FwVolHeader);\r
1256 DEBUG ((EFI_D_ERROR, "Fvb: FV header invalid, GetFvbInfo - %r\n", Status));\r
1257 ASSERT_EFI_ERROR (Status);\r
1258 }\r
1259\r
1260 return EFI_SUCCESS;\r
1261}\r
1262\r
9071550e 1263VOID\r
1264EFIAPI\r
1265OnSimpleFileSystemInstall (\r
1266 IN EFI_EVENT Event,\r
1267 IN VOID *Context\r
1268 )\r
1269{\r
1270 EFI_STATUS Status;\r
1271 UINTN HandleSize;\r
1272 EFI_HANDLE Handle;\r
1273 UINTN Instance;\r
1274 EFI_DEVICE_PATH_PROTOCOL *Device;\r
b0b961c8 1275 EFI_FILE_PROTOCOL *File;\r
9071550e 1276 EFI_FW_VOL_INSTANCE *FwhInstance;\r
1277 while (TRUE) {\r
1278 HandleSize = sizeof (EFI_HANDLE);\r
1279 Status = gBS->LocateHandle (\r
1280 ByRegisterNotify,\r
1281 NULL,\r
1282 mSFSRegistration,\r
1283 &HandleSize,\r
1284 &Handle\r
1285 );\r
1286 if (Status == EFI_NOT_FOUND) {\r
1287 break;\r
1288 }\r
1289 DEBUG ((EFI_D_ERROR, "Fwh: New FileSystem Installed!\n"));\r
1290 ASSERT_EFI_ERROR (Status);\r
1291 //\r
1292 // Check if this is the storage we care about, and store it in FwhInstance\r
1293 //\r
1294 for (Instance = 0; Instance < mFvbModuleGlobal->NumFv; ++Instance) {\r
1295 Status = GetFvbInstance (Instance, mFvbModuleGlobal, &FwhInstance, FALSE);\r
1296 ASSERT_EFI_ERROR (Status);\r
1297\r
1298 if (FwhInstance->MappedFile[0] == L'\0') {\r
1299 //\r
1300 // The instance of FVB isn't mapped to file.\r
1301 //\r
1302 continue;\r
1303 }\r
1304\r
1305 if ((FwhInstance->Device != NULL) && \r
1306 !EFI_ERROR (CheckStoreExists (FwhInstance->Device))\r
1307 ) {\r
1308 //\r
1309 // The instance of FVB has already associated to a device\r
1310 // and the device is not removed from system.\r
1311 //\r
1312 DEBUG ((\r
1313 EFI_D_ERROR, "Fwh: MappedFile FVB (0x%x:0x%x) - Already mapped, Skip!\n", \r
1314 (UINTN) FwhInstance->FvBase[FVB_PHYSICAL],\r
1315 (UINTN) FwhInstance->Offset\r
1316 ));\r
1317 continue;\r
1318 }\r
1319\r
1320 Status = CheckStore (Handle, FwhInstance->VolumeId, &Device);\r
1321 if (!EFI_ERROR (Status)) {\r
1322 //\r
1323 // Write back memory content to file\r
1324 //\r
1325 Status = FileOpen (Device, FwhInstance->MappedFile, &File, EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ | EFI_FILE_MODE_CREATE);\r
1326 ASSERT_EFI_ERROR (Status); \r
1327 if (!EFI_ERROR (Status)) {\r
1328 DEBUG ((\r
1329 EFI_D_ERROR, "Fwh: MappedFile FVB (0x%x:0x%x) - Write back to mapped file!\n", \r
1330 (UINTN) FwhInstance->FvBase[FVB_PHYSICAL],\r
1331 (UINTN) FwhInstance->Offset\r
1332 ));\r
1333 Status = FileWrite (\r
1334 File, \r
1335 0, \r
1336 FwhInstance->FvBase[FVB_PHYSICAL] + FwhInstance->Offset, \r
1337 FwhInstance->ActuralSize - FwhInstance->Offset\r
1338 );\r
1339 ASSERT_EFI_ERROR (Status); \r
1340 if (!EFI_ERROR (Status)) {\r
1341 if (FwhInstance->Device != NULL) {\r
1342 gBS->FreePool (FwhInstance->Device);\r
1343 }\r
1344 FwhInstance->Device = Device;\r
1345 DEBUG ((\r
1346 EFI_D_ERROR, "Fwh: MappedFile FVB (0x%x:0x%x) - Mapped!\n",\r
1347 (UINTN) FwhInstance->FvBase[FVB_PHYSICAL],\r
1348 (UINTN) FwhInstance->Offset\r
1349 ));\r
1350 }\r
1351 FileClose (File);\r
1352 }\r
1353 }\r
1354 }\r
1355 }\r
1356}\r
1357\r
9071550e 1358VOID\r
1359FvbInstallSfsNotify (\r
1360 VOID\r
1361)\r
1362{\r
1363 EFI_STATUS Status;\r
1364 EFI_EVENT Event;\r
1365\r
1366 Status = gBS->CreateEvent (\r
e53a6ea9 1367 EVT_NOTIFY_SIGNAL,\r
9071550e 1368 TPL_CALLBACK,\r
1369 OnSimpleFileSystemInstall,\r
1370 NULL,\r
1371 &Event\r
1372 );\r
1373 ASSERT_EFI_ERROR (Status);\r
1374\r
1375 Status = gBS->RegisterProtocolNotify (\r
1376 &gEfiSimpleFileSystemProtocolGuid,\r
1377 Event,\r
1378 &mSFSRegistration\r
1379 );\r
1380 ASSERT_EFI_ERROR (Status);\r
1381}\r
1382\r
1383\r
1384EFI_STATUS\r
1385EFIAPI\r
1386FvbInitialize (\r
1387 IN EFI_HANDLE ImageHandle,\r
1388 IN EFI_SYSTEM_TABLE *SystemTable\r
1389 )\r
1390/*++\r
1391\r
1392Routine Description:\r
1393 This function does common initialization for FVB services\r
1394\r
1395Arguments:\r
1396\r
1397Returns:\r
1398\r
1399--*/\r
1400{\r
1401 EFI_STATUS Status;\r
1402 EFI_FW_VOL_INSTANCE *FwhInstance;\r
1403 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
eb16e240 1404 EFI_PEI_HOB_POINTERS FirmwareVolumeHobList;\r
9071550e 1405 UINT32 BufferSize;\r
1406 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;\r
1407 UINTN LbaAddress;\r
1408 EFI_HANDLE FwbHandle;\r
1409 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1410 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFwbInterface;\r
1411 EFI_DEVICE_PATH_PROTOCOL *TempFwbDevicePath;\r
1412 FV_DEVICE_PATH TempFvbDevicePathData;\r
1413 UINT32 MaxLbaSize;\r
1414 EFI_PHYSICAL_ADDRESS BaseAddress;\r
1415 UINT32 VolumeId;\r
1416 CHAR16 *MappedFile;\r
1417 UINT32 ActuralSize;\r
1418 UINT32 Offset;\r
1419 BOOLEAN WriteBack;\r
1420 UINTN NumOfBlocks;\r
1421 UINTN HeaderLength;\r
1422 BOOLEAN InstallSfsNotify;\r
1423\r
9071550e 1424 HeaderLength = 0;\r
1425 InstallSfsNotify = FALSE;\r
1426\r
1427 //\r
1428 // Allocate runtime services data for global variable, which contains\r
1429 // the private data of all firmware volume block instances\r
1430 //\r
1431 Status = gBS->AllocatePool (\r
1432 EfiRuntimeServicesData,\r
1433 sizeof (ESAL_FWB_GLOBAL),\r
1434 &mFvbModuleGlobal\r
1435 );\r
1436 ASSERT_EFI_ERROR (Status);\r
1437 //\r
1438 // Calculate the total size for all firmware volume block instances\r
1439 //\r
1440 BufferSize = 0;\r
eb16e240 1441 FirmwareVolumeHobList.Raw = GetHobList();\r
9071550e 1442 do {\r
1443 Status = GetFvbHeader (&FirmwareVolumeHobList, &FwVolHeader, NULL, NULL, NULL, NULL, NULL, NULL);\r
1444 if (EFI_ERROR (Status)) {\r
1445 break;\r
1446 }\r
eb16e240 1447 FirmwareVolumeHobList.Raw = GET_NEXT_HOB (FirmwareVolumeHobList);\r
9071550e 1448\r
1449 if (FwVolHeader) {\r
1450 BufferSize += (FwVolHeader->HeaderLength + sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER));\r
1451 }\r
1452 } while (TRUE);\r
1453\r
1454 //\r
1455 // Only need to allocate once. There is only one copy of physical memory for\r
1456 // the private data of each FV instance. But in virtual mode or in physical\r
1457 // mode, the address of the the physical memory may be different.\r
1458 //\r
1459 Status = gBS->AllocatePool (\r
1460 EfiRuntimeServicesData,\r
1461 BufferSize,\r
1462 &mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]\r
1463 );\r
1464 ASSERT_EFI_ERROR (Status);\r
1465\r
1466 //\r
1467 // Make a virtual copy of the FvInstance pointer.\r
1468 //\r
1469 FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];\r
1470 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance;\r
1471\r
eb16e240 1472 mFvbModuleGlobal->NumFv = 0;\r
1473 FirmwareVolumeHobList.Raw = GetHobList();\r
1474 MaxLbaSize = 0;\r
9071550e 1475\r
1476 //\r
1477 // Fill in the private data of each firmware volume block instance\r
1478 //\r
1479 do {\r
1480 Status = GetFvbHeader (\r
1481 &FirmwareVolumeHobList, &FwVolHeader, \r
1482 &BaseAddress, &VolumeId, &MappedFile, &ActuralSize, &Offset,\r
1483 &WriteBack\r
1484 );\r
1485 if (EFI_ERROR (Status)) {\r
1486 break;\r
1487 }\r
eb16e240 1488 FirmwareVolumeHobList.Raw = GET_NEXT_HOB (FirmwareVolumeHobList);\r
9071550e 1489\r
1490 if (!FwVolHeader) {\r
1491 continue;\r
1492 }\r
be768885 1493 \r
9071550e 1494 CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength);\r
1495 FwVolHeader = &(FwhInstance->VolumeHeader);\r
1496\r
1497 FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress;\r
1498 FwhInstance->FvBase[FVB_VIRTUAL] = (UINTN) BaseAddress;\r
1499 FwhInstance->Device = NULL;\r
1500 FwhInstance->Offset = Offset;\r
1501\r
1502 if (*MappedFile != '\0') {\r
1503 FwhInstance->VolumeId = VolumeId;\r
1504 FwhInstance->ActuralSize = ActuralSize;\r
1505 StrCpy (FwhInstance->MappedFile, MappedFile);\r
1506\r
1507 InstallSfsNotify = TRUE;\r
1508 } else {\r
1509 FwhInstance->VolumeId = (UINT32) -1;\r
1510 FwhInstance->ActuralSize = (UINT32) -1;\r
1511 FwhInstance->MappedFile[0] = L'\0';\r
1512 }\r
1513 \r
be768885 1514 DEBUG ((EFI_D_INFO, "FirmVolume Found! BaseAddress=0x%lx, VolumeId=0x%x, MappedFile=%s, Size=0x%x\n",\r
1515 (UINTN) BaseAddress, VolumeId, MappedFile, ActuralSize));\r
9071550e 1516 //\r
1517 // We may expose readonly FVB in future.\r
1518 //\r
be768885 1519 FwhInstance->WriteEnabled = TRUE; // Ken: Why enable write?\r
9071550e 1520 EfiInitializeLock (&(FwhInstance->FvbDevLock), TPL_HIGH_LEVEL);\r
1521\r
1522 LbaAddress = (UINTN) FwhInstance->FvBase[0];\r
1523 NumOfBlocks = 0;\r
1524\r
1525 if (FwhInstance->WriteEnabled) {\r
1526 for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {\r
1527\r
1528 LbaAddress += PtrBlockMapEntry->NumBlocks * PtrBlockMapEntry->Length;\r
1529 //\r
1530 // Get the maximum size of a block. The size will be used to allocate\r
1531 // buffer for Scratch space, the intermediate buffer for FVB extension\r
1532 // protocol\r
1533 //\r
1534 if (MaxLbaSize < PtrBlockMapEntry->Length) {\r
1535 MaxLbaSize = PtrBlockMapEntry->Length;\r
1536 }\r
1537\r
1538 NumOfBlocks += PtrBlockMapEntry->NumBlocks;\r
1539 }\r
1540 //\r
1541 // Write back a healthy FV header\r
1542 //\r
1543 if (WriteBack) {\r
1544 Status = FlashFdErase (\r
1545 (UINTN) FwhInstance->FvBase[0],\r
1546 FwhInstance,\r
1547 FwVolHeader->BlockMap->Length\r
1548 );\r
1549\r
1550 HeaderLength = (UINTN) FwVolHeader->HeaderLength;\r
1551\r
1552 Status = FlashFdWrite (\r
1553 (UINTN) FwhInstance->FvBase[0],\r
1554 FwhInstance,\r
1555 (UINTN *) &HeaderLength,\r
1556 (UINT8 *) FwVolHeader\r
1557 );\r
1558\r
1559 FwVolHeader->HeaderLength = (UINT16) HeaderLength;\r
1560\r
1561 DEBUG ((EFI_D_ERROR, "Fvb (0x%x): FV header invalid, write back - %r\n", (UINTN) FwhInstance->FvBase[0], Status));\r
1562 }\r
1563 }\r
1564 //\r
1565 // The total number of blocks in the FV.\r
1566 //\r
1567 FwhInstance->NumOfBlocks = NumOfBlocks;\r
1568\r
1569 //\r
1570 // Add a FVB Protocol Instance\r
1571 //\r
1572 Status = gBS->AllocatePool (\r
1573 EfiRuntimeServicesData,\r
1574 sizeof (EFI_FW_VOL_BLOCK_DEVICE),\r
1575 &FvbDevice\r
1576 );\r
1577 ASSERT_EFI_ERROR (Status);\r
1578\r
1579 CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE));\r
1580\r
1581 FvbDevice->Instance = mFvbModuleGlobal->NumFv;\r
1582 mFvbModuleGlobal->NumFv++;\r
1583\r
1584 //\r
1585 // Set up the devicepath\r
1586 //\r
1587 FvbDevice->DevicePath.MemMapDevPath.StartingAddress = BaseAddress;\r
1588 FvbDevice->DevicePath.MemMapDevPath.EndingAddress = BaseAddress + (FwVolHeader->FvLength - 1);\r
1589\r
1590 //\r
1591 // Find a handle with a matching device path that has supports FW Block protocol\r
1592 //\r
1593 TempFwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &TempFvbDevicePathData;\r
1594 CopyMem (TempFwbDevicePath, &FvbDevice->DevicePath, sizeof (FV_DEVICE_PATH));\r
1595 Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &TempFwbDevicePath, &FwbHandle);\r
1596 if (EFI_ERROR (Status)) {\r
1597 //\r
1598 // LocateDevicePath fails so install a new interface and device path\r
1599 //\r
1600 FwbHandle = NULL;\r
1601 Status = gBS->InstallMultipleProtocolInterfaces (\r
1602 &FwbHandle,\r
1603 &gEfiFirmwareVolumeBlockProtocolGuid,\r
1604 &FvbDevice->FwVolBlockInstance,\r
1605 &gEfiDevicePathProtocolGuid,\r
1606 &FvbDevice->DevicePath,\r
1607 NULL\r
1608 );\r
1609 ASSERT_EFI_ERROR (Status);\r
8e1ac15a 1610 } else if (IsDevicePathEnd (TempFwbDevicePath)) {\r
9071550e 1611 //\r
1612 // Device allready exists, so reinstall the FVB protocol\r
1613 //\r
1614 Status = gBS->HandleProtocol (\r
1615 FwbHandle,\r
1616 &gEfiFirmwareVolumeBlockProtocolGuid,\r
1617 &OldFwbInterface\r
1618 );\r
1619 ASSERT_EFI_ERROR (Status);\r
1620\r
1621 Status = gBS->ReinstallProtocolInterface (\r
1622 FwbHandle,\r
1623 &gEfiFirmwareVolumeBlockProtocolGuid,\r
1624 OldFwbInterface,\r
1625 &FvbDevice->FwVolBlockInstance\r
1626 );\r
1627 ASSERT_EFI_ERROR (Status);\r
1628\r
1629 } else {\r
1630 //\r
1631 // There was a FVB protocol on an End Device Path node\r
1632 //\r
1633 ASSERT (FALSE);\r
1634 }\r
9071550e 1635\r
1636 FwhInstance = (EFI_FW_VOL_INSTANCE *)\r
1637 (\r
1638 (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +\r
1639 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))\r
1640 );\r
1641 } while (TRUE);\r
1642\r
1643 //\r
1644 // Allocate for scratch space, an intermediate buffer for FVB extention\r
1645 //\r
1646 Status = gBS->AllocatePool (\r
1647 EfiRuntimeServicesData,\r
1648 MaxLbaSize,\r
1649 &mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL]\r
1650 );\r
1651 ASSERT_EFI_ERROR (Status);\r
1652\r
1653 mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL] = mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL];\r
1654\r
1655 if (InstallSfsNotify) {\r
1656 FvbInstallSfsNotify ();\r
1657 }\r
1658 return EFI_SUCCESS;\r
1659}\r