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