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