]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.c
Sync HII and Setupbrowser related header files with UEFI 2.1 spec.
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / FwVolBlock / FwVolBlock.c
CommitLineData
797a9d67 1/**@file\r
2 Firmware Volume Block protocol.. Consumes FV hobs and creates\r
3 appropriate block protocols.\r
28a00297 4\r
797a9d67 5 Also consumes NT_NON_MM_FV envinronment variable and produces appropriate\r
6 block protocols fro them also... (this is TBD)\r
7 \r
28a00297 8Copyright (c) 2006, Intel Corporation \r
9All rights reserved. This program and the accompanying materials \r
10are licensed and made available under the terms and conditions of the BSD License \r
11which accompanies this distribution. The full text of the license may be found at \r
12http://opensource.org/licenses/bsd-license.php \r
13 \r
14THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
15WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
16\r
797a9d67 17**/\r
28a00297 18\r
19#include <DxeMain.h>\r
20\r
21\r
22EFI_FW_VOL_BLOCK_DEVICE mFwVolBlock = {\r
23 FVB_DEVICE_SIGNATURE,\r
24 NULL,\r
25 {\r
26 {\r
27 {\r
28 HARDWARE_DEVICE_PATH,\r
29 HW_MEMMAP_DP,\r
30 { (UINT8)(sizeof (MEMMAP_DEVICE_PATH)), (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8) }\r
31 },\r
32 EfiMemoryMappedIO,\r
33 (EFI_PHYSICAL_ADDRESS)0,\r
34 (EFI_PHYSICAL_ADDRESS)0,\r
35 },\r
36 {\r
37 END_DEVICE_PATH_TYPE,\r
38 END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
39 { END_DEVICE_PATH_LENGTH, 0 } \r
40 },\r
41 },\r
42 {\r
43 FwVolBlockGetAttributes,\r
44 (EFI_FVB_SET_ATTRIBUTES)FwVolBlockSetAttributes,\r
45 FwVolBlockGetPhysicalAddress,\r
46 FwVolBlockGetBlockSize,\r
47 FwVolBlockReadBlock,\r
48 (EFI_FVB_WRITE)FwVolBlockWriteBlock,\r
49 (EFI_FVB_ERASE_BLOCKS)FwVolBlockEraseBlock,\r
50 NULL \r
51 },\r
52 0,\r
53 NULL,\r
54 0,\r
55 0\r
56};\r
57\r
58\r
59\r
60\r
61EFI_STATUS\r
62EFIAPI\r
63FwVolBlockGetAttributes (\r
64 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
65 OUT EFI_FVB_ATTRIBUTES *Attributes\r
66 )\r
67/*++\r
68\r
69Routine Description:\r
70 Retrieves Volume attributes. No polarity translations are done.\r
71\r
72Arguments:\r
73 This - Calling context\r
74 Attributes - output buffer which contains attributes\r
75\r
76Returns:\r
77 EFI_SUCCESS - The firmware volume attributes were returned.\r
78\r
79--*/\r
80{\r
81 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
82 \r
83 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
84\r
85 //\r
86 // Since we are read only, it's safe to get attributes data from our in-memory copy.\r
87 //\r
88 *Attributes = FvbDevice->FvbAttributes;\r
89\r
90 return EFI_SUCCESS;\r
91}\r
92\r
93\r
94EFI_STATUS\r
95EFIAPI\r
96FwVolBlockSetAttributes (\r
97 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
98 IN CONST EFI_FVB_ATTRIBUTES *Attributes\r
99 )\r
100/*++\r
101\r
102Routine Description:\r
103 Modifies the current settings of the firmware volume according to the input parameter.\r
104\r
105Arguments:\r
106 This - Calling context\r
107 Attributes - input buffer which contains attributes\r
108\r
109Returns:\r
110 EFI_SUCCESS - The firmware volume attributes were returned.\r
111 EFI_INVALID_PARAMETER - The attributes requested are in conflict with the capabilities as\r
112 declared in the firmware volume header.\r
113 EFI_UNSUPPORTED - Not supported.\r
114--*/\r
115{\r
116 return EFI_UNSUPPORTED;\r
117}\r
118\r
119\r
120EFI_STATUS\r
121EFIAPI\r
122FwVolBlockEraseBlock (\r
123 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
124 ...\r
125 )\r
126/*++\r
127\r
128Routine Description:\r
129 The EraseBlock() function erases one or more blocks as denoted by the \r
130variable argument list. The entire parameter list of blocks must be verified\r
131prior to erasing any blocks. If a block is requested that does not exist \r
132within the associated firmware volume (it has a larger index than the last \r
133block of the firmware volume), the EraseBlock() function must return\r
134EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.\r
135\r
136Arguments:\r
137 This - Calling context\r
138 ... - Starting LBA followed by Number of Lba to erase. a -1 to terminate\r
139 the list.\r
140 \r
141Returns:\r
142 EFI_SUCCESS - The erase request was successfully completed.\r
143 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state.\r
144 EFI_DEVICE_ERROR - The block device is not functioning correctly and could not be\r
145 written. The firmware device may have been partially erased.\r
146 EFI_INVALID_PARAMETER - One or more of the LBAs listed in the variable argument list do\r
147 EFI_UNSUPPORTED - Not supported.\r
148 \r
149--*/\r
150{\r
151 return EFI_UNSUPPORTED;\r
152}\r
153\r
154\r
155EFI_STATUS\r
156EFIAPI\r
157FwVolBlockReadBlock (\r
158 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
159 IN CONST EFI_LBA Lba,\r
160 IN CONST UINTN Offset,\r
161 IN OUT UINTN *NumBytes,\r
162 IN OUT UINT8 *Buffer\r
163 )\r
164/*++\r
165\r
166Routine Description:\r
167 Read the specified number of bytes from the block to the input buffer.\r
168\r
169Arguments:\r
170 This - Indicates the calling context.\r
171 Lba - The starting logical block index to read.\r
172 Offset - Offset into the block at which to begin reading.\r
173 NumBytes - Pointer to a UINT32. At entry, *NumBytes contains the\r
174 total size of the buffer. At exit, *NumBytes contains the\r
175 total number of bytes actually read.\r
176 Buffer - Pinter to a caller-allocated buffer that contains the destine\r
177 for the read. \r
178\r
179Returns: \r
180 EFI_SUCCESS - The firmware volume was read successfully.\r
181 EFI_BAD_BUFFER_SIZE - The read was attempted across an LBA boundary.\r
182 EFI_ACCESS_DENIED - Access denied.\r
183 EFI_DEVICE_ERROR - The block device is malfunctioning and could not be read.\r
184--*/\r
185{\r
186 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
187 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
188 UINT8 *LbaOffset;\r
189 UINTN LbaStart;\r
190 UINTN NumOfBytesRead;\r
191 UINTN LbaIndex;\r
192 \r
193 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
194\r
195 //\r
196 // Check if This FW can be read\r
197 //\r
797a9d67 198 if ((FvbDevice->FvbAttributes & EFI_FVB2_READ_STATUS) == 0) {\r
28a00297 199 return EFI_ACCESS_DENIED;\r
200 }\r
201 \r
202 LbaIndex = (UINTN)Lba;\r
203 if (LbaIndex >= FvbDevice->NumBlocks) {\r
204 //\r
205 // Invalid Lba, read nothing.\r
206 //\r
207 *NumBytes = 0;\r
208 return EFI_BAD_BUFFER_SIZE;\r
209 }\r
210 \r
211 if (Offset > FvbDevice->LbaCache[LbaIndex].Length) {\r
212 //\r
213 // all exceed boundry, read nothing.\r
214 //\r
215 *NumBytes = 0;\r
216 return EFI_BAD_BUFFER_SIZE;\r
217 }\r
218 \r
219 NumOfBytesRead = *NumBytes;\r
220 if (Offset + NumOfBytesRead > FvbDevice->LbaCache[LbaIndex].Length) {\r
221 //\r
222 // partial exceed boundry, read data from current postion to end.\r
223 //\r
224 NumOfBytesRead = FvbDevice->LbaCache[LbaIndex].Length - Offset;\r
225 }\r
226 \r
227 LbaStart = FvbDevice->LbaCache[LbaIndex].Base;\r
228 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)FvbDevice->BaseAddress);\r
229 LbaOffset = (UINT8 *)FwVolHeader + LbaStart + Offset;\r
230\r
231 //\r
232 // Perform read operation\r
233 //\r
234 CopyMem (Buffer, LbaOffset, NumOfBytesRead);\r
235 \r
236 if (NumOfBytesRead == *NumBytes) {\r
237 return EFI_SUCCESS;\r
238 }\r
239 \r
240 *NumBytes = NumOfBytesRead;\r
241 return EFI_BAD_BUFFER_SIZE;\r
242}\r
243 \r
244\r
245EFI_STATUS\r
246EFIAPI\r
247FwVolBlockWriteBlock (\r
248 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
249 IN EFI_LBA Lba,\r
250 IN UINTN Offset,\r
251 IN OUT UINTN *NumBytes,\r
252 IN UINT8 *Buffer\r
253 )\r
254/*++\r
255\r
256Routine Description:\r
257 Writes the specified number of bytes from the input buffer to the block.\r
258\r
259Arguments:\r
260 This - Indicates the calling context.\r
261 Lba - The starting logical block index to write to.\r
262 Offset - Offset into the block at which to begin writing.\r
263 NumBytes - Pointer to a UINT32. At entry, *NumBytes contains the\r
264 total size of the buffer. At exit, *NumBytes contains the\r
265 total number of bytes actually written.\r
266 Buffer - Pinter to a caller-allocated buffer that contains the source\r
267 for the write. \r
268\r
269Returns: \r
270 EFI_SUCCESS - The firmware volume was written successfully.\r
271 EFI_BAD_BUFFER_SIZE - The write was attempted across an LBA boundary. On output,\r
272 NumBytes contains the total number of bytes actually written.\r
273 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state.\r
274 EFI_DEVICE_ERROR - The block device is malfunctioning and could not be written.\r
275 EFI_UNSUPPORTED - Not supported.\r
276--*/\r
277{\r
278 return EFI_UNSUPPORTED;\r
279}\r
280 \r
281\r
282EFI_STATUS\r
283EFIAPI\r
284FwVolBlockGetPhysicalAddress (\r
285 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
286 OUT EFI_PHYSICAL_ADDRESS *Address\r
287 )\r
288/*++\r
289\r
290Routine Description:\r
291 Get Fvb's base address.\r
292\r
293Arguments:\r
294 This - Indicates the calling context.\r
295 Address - Fvb device base address.\r
296\r
297Returns: \r
298 EFI_SUCCESS - Successfully got Fvb's base address.\r
299 EFI_UNSUPPORTED - Not supported.\r
300--*/\r
301{\r
302 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
303 \r
304 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
305 \r
797a9d67 306 if (FvbDevice->FvbAttributes & EFI_FVB2_MEMORY_MAPPED) {\r
28a00297 307 *Address = FvbDevice->BaseAddress;\r
308 return EFI_SUCCESS;\r
309 }\r
310 \r
311 return EFI_UNSUPPORTED;\r
312}\r
313\r
314\r
315EFI_STATUS\r
316EFIAPI\r
317FwVolBlockGetBlockSize (\r
318 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
319 IN CONST EFI_LBA Lba,\r
320 IN OUT UINTN *BlockSize,\r
321 IN OUT UINTN *NumberOfBlocks\r
322 )\r
323/*++\r
324\r
325Routine Description:\r
326 Retrieves the size in bytes of a specific block within a firmware volume.\r
327\r
328Arguments:\r
329 This - Indicates the calling context.\r
330 Lba - Indicates the block for which to return the size.\r
331 BlockSize - Pointer to a caller-allocated UINTN in which the size of the\r
332 block is returned.\r
333 NumberOfBlocks - Pointer to a caller-allocated UINTN in which the number of\r
334 consecutive blocks starting with Lba is returned. All blocks\r
335 in this range have a size of BlockSize. \r
336Returns:\r
337 EFI_SUCCESS - The firmware volume base address is returned.\r
338 EFI_INVALID_PARAMETER - The requested LBA is out of range.\r
339--*/\r
340{\r
341 UINTN TotalBlocks;\r
342 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
343 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;\r
344 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
345 \r
346 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
347 \r
348 //\r
349 // Do parameter checking\r
350 //\r
351 if (Lba >= FvbDevice->NumBlocks) {\r
352 return EFI_INVALID_PARAMETER;\r
353 }\r
354 \r
355 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)FvbDevice->BaseAddress);\r
356 \r
357 PtrBlockMapEntry = FwVolHeader->BlockMap;\r
358 \r
359 //\r
360 // Search the block map for the given block\r
361 //\r
362 TotalBlocks = 0;\r
363 while ((PtrBlockMapEntry->NumBlocks != 0) || (PtrBlockMapEntry->Length !=0 )) {\r
364 TotalBlocks += PtrBlockMapEntry->NumBlocks;\r
365 if (Lba < TotalBlocks) {\r
366 //\r
367 // We find the range\r
368 //\r
369 break;\r
370 }\r
371 \r
372 PtrBlockMapEntry++;\r
373 }\r
374 \r
375 *BlockSize = PtrBlockMapEntry->Length;\r
376 *NumberOfBlocks = TotalBlocks - (UINTN)Lba;\r
377 \r
378 return EFI_SUCCESS;\r
379}\r
380\r
381\r
382EFI_STATUS\r
383ProduceFVBProtocolOnBuffer (\r
384 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
385 IN UINT64 Length,\r
386 IN EFI_HANDLE ParentHandle,\r
387 OUT EFI_HANDLE *FvProtocol OPTIONAL\r
388 )\r
389/*++\r
390\r
391Routine Description:\r
392 This routine produces a firmware volume block protocol on a given\r
393 buffer. \r
394\r
395Arguments:\r
396 BaseAddress - base address of the firmware volume image\r
397 Length - length of the firmware volume image\r
398 ParentHandle - handle of parent firmware volume, if this\r
399 image came from an FV image file in another\r
400 firmware volume (ala capsules)\r
401 FvProtocol - Firmware volume block protocol produced.\r
402 \r
403Returns:\r
404 EFI_VOLUME_CORRUPTED - Volume corrupted.\r
405 EFI_OUT_OF_RESOURCES - No enough buffer to be allocated.\r
406 EFI_SUCCESS - Successfully produced a FVB protocol on given buffer.\r
407 \r
408--*/\r
409{\r
410 EFI_STATUS Status;\r
411 EFI_FW_VOL_BLOCK_DEVICE *FvbDev;\r
412 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
413 UINTN BlockIndex;\r
414 UINTN BlockIndex2;\r
415 UINTN LinearOffset;\r
416 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;\r
417\r
418 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)BaseAddress;\r
419 //\r
420 // Validate FV Header, if not as expected, return\r
421 //\r
422 if (FwVolHeader->Signature != EFI_FVH_SIGNATURE) {\r
423 return EFI_VOLUME_CORRUPTED;\r
424 }\r
425 //\r
426 // Allocate EFI_FW_VOL_BLOCK_DEVICE \r
427 //\r
428 FvbDev = CoreAllocateCopyPool (sizeof (EFI_FW_VOL_BLOCK_DEVICE), &mFwVolBlock);\r
429 if (FvbDev == NULL) {\r
430 return EFI_OUT_OF_RESOURCES;\r
431 }\r
432\r
433 FvbDev->BaseAddress = BaseAddress;\r
434 FvbDev->FvbAttributes = FwVolHeader->Attributes;\r
435 FvbDev->FwVolBlockInstance.ParentHandle = ParentHandle;\r
436\r
437 //\r
438 // Init the block caching fields of the device\r
439 // First, count the number of blocks\r
440 //\r
441 FvbDev->NumBlocks = 0;\r
442 for (PtrBlockMapEntry = FwVolHeader->BlockMap;\r
443 PtrBlockMapEntry->NumBlocks != 0;\r
444 PtrBlockMapEntry++) {\r
445 FvbDev->NumBlocks += PtrBlockMapEntry->NumBlocks;\r
446 }\r
447 //\r
448 // Second, allocate the cache\r
449 //\r
450 FvbDev->LbaCache = CoreAllocateBootServicesPool (FvbDev->NumBlocks * sizeof (LBA_CACHE));\r
451 if (FvbDev->LbaCache == NULL) {\r
452 CoreFreePool (FvbDev);\r
453 return EFI_OUT_OF_RESOURCES;\r
454 }\r
455 //\r
456 // Last, fill in the cache with the linear address of the blocks\r
457 //\r
458 BlockIndex = 0;\r
459 LinearOffset = 0;\r
460 for (PtrBlockMapEntry = FwVolHeader->BlockMap;\r
461 PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {\r
462 for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {\r
463 FvbDev->LbaCache[BlockIndex].Base = LinearOffset;\r
464 FvbDev->LbaCache[BlockIndex].Length = PtrBlockMapEntry->Length;\r
465 LinearOffset += PtrBlockMapEntry->Length;\r
466 BlockIndex++;\r
467 }\r
468 }\r
469\r
470 //\r
471 // Set up the devicepath\r
472 //\r
473 FvbDev->DevicePath.MemMapDevPath.StartingAddress = BaseAddress;\r
474 FvbDev->DevicePath.MemMapDevPath.EndingAddress = BaseAddress + FwVolHeader->FvLength - 1;\r
475\r
476 //\r
477 //\r
478 // Attach FvVolBlock Protocol to new handle\r
479 //\r
480 Status = CoreInstallMultipleProtocolInterfaces (\r
481 &FvbDev->Handle,\r
482 &gEfiFirmwareVolumeBlockProtocolGuid, &FvbDev->FwVolBlockInstance,\r
483 &gEfiDevicePathProtocolGuid, &FvbDev->DevicePath,\r
484 &gEfiFirmwareVolumeDispatchProtocolGuid, NULL,\r
485 NULL\r
486 );\r
487\r
488 //\r
489 // If they want the handle back, set it.\r
490 //\r
491 if (FvProtocol != NULL) {\r
492 *FvProtocol = FvbDev->Handle;\r
493 }\r
494\r
495 return Status;\r
496}\r
497\r
498\r
499EFI_STATUS\r
500EFIAPI\r
501FwVolBlockDriverInit (\r
502 IN EFI_HANDLE ImageHandle,\r
503 IN EFI_SYSTEM_TABLE *SystemTable\r
504 )\r
505/*++\r
506\r
507Routine Description:\r
508 This routine is the driver initialization entry point. It initializes the\r
509 libraries, consumes FV hobs and NT_NON_MM_FV environment variable and\r
510 produces instances of FW_VOL_BLOCK_PROTOCOL as appropriate.\r
511Arguments:\r
512 ImageHandle - The image handle.\r
513 SystemTable - The system table.\r
514Returns:\r
515 EFI_SUCCESS - Successfully initialized firmware volume block driver.\r
516--*/\r
517{\r
518 EFI_PEI_HOB_POINTERS FvHob;\r
519 //\r
520 // Core Needs Firmware Volumes to function\r
521 //\r
522 FvHob.Raw = GetHobList ();\r
523 while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) {\r
524 //\r
525 // Produce an FVB protocol for it\r
526 //\r
527 ProduceFVBProtocolOnBuffer (FvHob.FirmwareVolume->BaseAddress, FvHob.FirmwareVolume->Length, NULL, NULL); \r
528 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
529 }\r
530 return EFI_SUCCESS;\r
531}\r
532\r
533\r
534EFI_STATUS\r
535CoreProcessFirmwareVolume (\r
536 IN VOID *FvHeader,\r
537 IN UINTN Size, \r
538 OUT EFI_HANDLE *FVProtocolHandle\r
539 )\r
540/*++\r
541\r
542Routine Description:\r
543 This DXE service routine is used to process a firmware volume. In\r
544 particular, it can be called by BDS to process a single firmware\r
545 volume found in a capsule. \r
546\r
547Arguments:\r
548 FvHeader - pointer to a firmware volume header\r
549 Size - the size of the buffer pointed to by FvHeader\r
550 FVProtocolHandle - the handle on which a firmware volume protocol\r
551 was produced for the firmware volume passed in.\r
552\r
553Returns:\r
554 EFI_OUT_OF_RESOURCES - if an FVB could not be produced due to lack of \r
555 system resources\r
556 EFI_VOLUME_CORRUPTED - if the volume was corrupted\r
557 EFI_SUCCESS - a firmware volume protocol was produced for the\r
558 firmware volume\r
559\r
560--*/\r
561{\r
562 VOID *Ptr;\r
563 EFI_STATUS Status;\r
564\r
565 *FVProtocolHandle = NULL;\r
566 Status = ProduceFVBProtocolOnBuffer ( \r
567 (EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader, \r
568 (UINT64)Size, \r
569 NULL, \r
570 FVProtocolHandle\r
571 );\r
572 //\r
573 // Since in our implementation we use register-protocol-notify to put a\r
574 // FV protocol on the FVB protocol handle, we can't directly verify that\r
575 // the FV protocol was produced. Therefore here we will check the handle\r
576 // and make sure an FV protocol is on it. This indicates that all went \r
577 // well. Otherwise we have to assume that the volume was corrupted \r
578 // somehow.\r
579 //\r
580 if (!EFI_ERROR(Status)) {\r
581 Ptr = NULL;\r
0c2b5da8 582 Status = CoreHandleProtocol (*FVProtocolHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Ptr);\r
28a00297 583 if (EFI_ERROR(Status) || (Ptr == NULL)) {\r
584 return EFI_VOLUME_CORRUPTED;\r
585 }\r
586 return EFI_SUCCESS;\r
587 }\r
588 return Status;\r
589}\r
590\r
591\r