]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/FwVol/FwVol.c
move header files in MdeModulePkg\Core\Dxe except DxeMain.h into their corresponding...
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / FwVol / FwVol.c
1 /** @file
2 Firmware File System driver that produce Firmware Volume protocol.
3 Layers on top of Firmware Block protocol to produce a file abstraction
4 of FV based files.
5
6 Copyright (c) 2006 - 2008, Intel Corporation. <BR>
7 All rights reserved. This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include "DxeMain.h"
18 #include "FwVolDriver.h"
19
20
21 //
22 // Protocol notify related globals
23 //
24 VOID *gEfiFwVolBlockNotifyReg;
25 EFI_EVENT gEfiFwVolBlockEvent;
26
27 FV_DEVICE mFvDevice = {
28 FV2_DEVICE_SIGNATURE,
29 NULL,
30 NULL,
31 {
32 FvGetVolumeAttributes,
33 FvSetVolumeAttributes,
34 FvReadFile,
35 FvReadFileSection,
36 FvWriteFile,
37 FvGetNextFile,
38 sizeof (UINTN),
39 NULL,
40 FvGetVolumeInfo,
41 FvSetVolumeInfo
42 },
43 NULL,
44 NULL,
45 NULL,
46 NULL,
47 { NULL, NULL },
48 0
49 };
50
51
52 //
53 // FFS helper functions
54 //
55 /**
56 given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and
57 copy the volume header into it.
58
59 @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to
60 read the volume header
61 @param FwVolHeader Pointer to pointer to allocated buffer in which
62 the volume header is returned.
63
64 @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
65 @retval EFI_SUCCESS Successfully read volume header to the allocated
66 buffer.
67
68 **/
69 EFI_STATUS
70 GetFwVolHeader (
71 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
72 OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader
73 )
74 {
75 EFI_STATUS Status;
76 EFI_FIRMWARE_VOLUME_HEADER TempFvh;
77 UINTN FvhLength;
78 UINT8 *Buffer;
79
80
81 //
82 //Determine the real length of FV header
83 //
84 FvhLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER);
85 Status = Fvb->Read (Fvb, 0, 0, &FvhLength, (UINT8 *)&TempFvh);
86 if (EFI_ERROR (Status)) {
87 return Status;
88 }
89
90 //
91 // Allocate a buffer for the caller
92 //
93 *FwVolHeader = AllocatePool (TempFvh.HeaderLength);
94 if (*FwVolHeader == NULL) {
95 return EFI_OUT_OF_RESOURCES;
96 }
97
98 //
99 // Copy the standard header into the buffer
100 //
101 CopyMem (*FwVolHeader, &TempFvh, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
102
103 //
104 // Read the rest of the header
105 //
106 FvhLength = TempFvh.HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER);
107 Buffer = (UINT8 *)*FwVolHeader + sizeof (EFI_FIRMWARE_VOLUME_HEADER);
108 Status = Fvb->Read (Fvb, 0, sizeof (EFI_FIRMWARE_VOLUME_HEADER), &FvhLength, Buffer);
109 if (EFI_ERROR (Status)) {
110 //
111 // Read failed so free buffer
112 //
113 CoreFreePool (*FwVolHeader);
114 }
115
116 return Status;
117 }
118
119
120
121 /**
122 Free FvDevice resource when error happens
123
124 @param FvDevice pointer to the FvDevice to be freed.
125
126 **/
127 VOID
128 FreeFvDeviceResource (
129 IN FV_DEVICE *FvDevice
130 )
131 {
132 FFS_FILE_LIST_ENTRY *FfsFileEntry;
133 LIST_ENTRY *NextEntry;
134
135 //
136 // Free File List Entry
137 //
138 FfsFileEntry = (FFS_FILE_LIST_ENTRY *)FvDevice->FfsFileListHeader.ForwardLink;
139 while (&FfsFileEntry->Link != &FvDevice->FfsFileListHeader) {
140 NextEntry = (&FfsFileEntry->Link)->ForwardLink;
141
142 if (FfsFileEntry->StreamHandle != 0) {
143 //
144 // Close stream and free resources from SEP
145 //
146 CloseSectionStream (FfsFileEntry->StreamHandle);
147 }
148
149 CoreFreePool (FfsFileEntry);
150
151 FfsFileEntry = (FFS_FILE_LIST_ENTRY *) NextEntry;
152 }
153
154
155 //
156 // Free the cache
157 //
158 CoreFreePool (FvDevice->CachedFv);
159
160 //
161 // Free Volume Header
162 //
163 CoreFreePool (FvDevice->FwVolHeader);
164
165 return;
166 }
167
168
169
170 /**
171 Check if an FV is consistent and allocate cache for it.
172
173 @param FvDevice A pointer to the FvDevice to be checked.
174
175 @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
176 @retval EFI_SUCCESS FV is consistent and cache is allocated.
177 @retval EFI_VOLUME_CORRUPTED File system is corrupted.
178
179 **/
180 EFI_STATUS
181 FvCheck (
182 IN OUT FV_DEVICE *FvDevice
183 )
184 {
185 EFI_STATUS Status;
186 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
187 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
188 EFI_FVB_ATTRIBUTES_2 FvbAttributes;
189 EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
190 FFS_FILE_LIST_ENTRY *FfsFileEntry;
191 EFI_FFS_FILE_HEADER *FfsHeader;
192 UINT8 *CacheLocation;
193 UINTN LbaOffset;
194 UINTN Index;
195 EFI_LBA LbaIndex;
196 UINTN Size;
197 UINTN FileLength;
198 EFI_FFS_FILE_STATE FileState;
199 UINT8 *TopFvAddress;
200 UINTN TestLength;
201
202
203 Fvb = FvDevice->Fvb;
204 FwVolHeader = FvDevice->FwVolHeader;
205
206 Status = Fvb->GetAttributes (Fvb, &FvbAttributes);
207 if (EFI_ERROR (Status)) {
208 return Status;
209 }
210
211 //
212 // Size is the size of the FV minus the head. We have already allocated
213 // the header to check to make sure the volume is valid
214 //
215 Size = (UINTN)(FwVolHeader->FvLength - FwVolHeader->HeaderLength);
216 FvDevice->CachedFv = AllocatePool (Size);
217
218 if (FvDevice->CachedFv == NULL) {
219 return EFI_OUT_OF_RESOURCES;
220 }
221
222 //
223 // Remember a pointer to the end fo the CachedFv
224 //
225 FvDevice->EndOfCachedFv = FvDevice->CachedFv + Size;
226
227 //
228 // Copy FV minus header into memory using the block map we have all ready
229 // read into memory.
230 //
231 BlockMap = FwVolHeader->BlockMap;
232 CacheLocation = FvDevice->CachedFv;
233 LbaIndex = 0;
234 LbaOffset = FwVolHeader->HeaderLength;
235 while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {
236
237 for (Index = 0; Index < BlockMap->NumBlocks; Index ++) {
238
239 Size = BlockMap->Length;
240 if (Index == 0) {
241 //
242 // Cache does not include FV Header
243 //
244 Size -= LbaOffset;
245 }
246 Status = Fvb->Read (Fvb,
247 LbaIndex,
248 LbaOffset,
249 &Size,
250 CacheLocation
251 );
252 //
253 // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length
254 //
255 if (EFI_ERROR (Status)) {
256 goto Done;
257 }
258
259 //
260 // After we skip Fv Header always read from start of block
261 //
262 LbaOffset = 0;
263
264 LbaIndex++;
265 CacheLocation += Size;
266 }
267 BlockMap++;
268 }
269
270 //
271 // Scan to check the free space & File list
272 //
273 if ((FvbAttributes & EFI_FVB2_ERASE_POLARITY) != 0) {
274 FvDevice->ErasePolarity = 1;
275 } else {
276 FvDevice->ErasePolarity = 0;
277 }
278
279
280 //
281 // go through the whole FV cache, check the consistence of the FV.
282 // Make a linked list off all the Ffs file headers
283 //
284 Status = EFI_SUCCESS;
285 InitializeListHead (&FvDevice->FfsFileListHeader);
286
287 //
288 // Build FFS list
289 //
290 FfsHeader = (EFI_FFS_FILE_HEADER *) FvDevice->CachedFv;
291 TopFvAddress = FvDevice->EndOfCachedFv;
292 while ((UINT8 *) FfsHeader < TopFvAddress) {
293
294 TestLength = TopFvAddress - ((UINT8 *) FfsHeader);
295 if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {
296 TestLength = sizeof (EFI_FFS_FILE_HEADER);
297 }
298
299 if (IsBufferErased (FvDevice->ErasePolarity, FfsHeader, TestLength)) {
300 //
301 // We have found the free space so we are done!
302 //
303 goto Done;
304 }
305
306 if (!IsValidFfsHeader (FvDevice->ErasePolarity, FfsHeader, &FileState)) {
307 if ((FileState == EFI_FILE_HEADER_INVALID) ||
308 (FileState == EFI_FILE_HEADER_CONSTRUCTION)) {
309 FfsHeader++;
310 continue;
311 } else {
312 //
313 // File system is corrputed
314 //
315 Status = EFI_VOLUME_CORRUPTED;
316 goto Done;
317 }
318 }
319
320 if (!IsValidFfsFile (FvDevice->ErasePolarity, FfsHeader)) {
321 //
322 // File system is corrupted
323 //
324 Status = EFI_VOLUME_CORRUPTED;
325 goto Done;
326 }
327
328 //
329 // Size[3] is a three byte array, read 4 bytes and throw one away
330 //
331 FileLength = *(UINT32 *)&FfsHeader->Size[0] & 0x00FFFFFF;
332
333 FileState = GetFileState (FvDevice->ErasePolarity, FfsHeader);
334
335 //
336 // check for non-deleted file
337 //
338 if (FileState != EFI_FILE_DELETED) {
339 //
340 // Create a FFS list entry for each non-deleted file
341 //
342 FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY));
343 if (FfsFileEntry == NULL) {
344 Status = EFI_OUT_OF_RESOURCES;
345 goto Done;
346 }
347
348 FfsFileEntry->FfsHeader = FfsHeader;
349 InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);
350 }
351
352 FfsHeader = (EFI_FFS_FILE_HEADER *)(((UINT8 *)FfsHeader) + FileLength);
353
354 //
355 // Adjust pointer to the next 8-byte aligned boundry.
356 //
357 FfsHeader = (EFI_FFS_FILE_HEADER *)(((UINTN)FfsHeader + 7) & ~0x07);
358
359 }
360
361 Done:
362 if (EFI_ERROR (Status)) {
363 FreeFvDeviceResource (FvDevice);
364 }
365
366 return Status;
367 }
368
369
370
371 /**
372 This notification function is invoked when an instance of the
373 EFI_FW_VOLUME_BLOCK_PROTOCOL is produced. It layers an instance of the
374 EFI_FIRMWARE_VOLUME2_PROTOCOL on the same handle. This is the function where
375 the actual initialization of the EFI_FIRMWARE_VOLUME2_PROTOCOL is done.
376
377 @param Event The event that occured
378 @param Context For EFI compatiblity. Not used.
379
380 **/
381 VOID
382 EFIAPI
383 NotifyFwVolBlock (
384 IN EFI_EVENT Event,
385 IN VOID *Context
386 )
387 {
388 EFI_HANDLE Handle;
389 EFI_STATUS Status;
390 UINTN BufferSize;
391 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
392 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
393 FV_DEVICE *FvDevice;
394 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
395 //
396 // Examine all new handles
397 //
398 for (;;) {
399 //
400 // Get the next handle
401 //
402 BufferSize = sizeof (Handle);
403 Status = CoreLocateHandle (
404 ByRegisterNotify,
405 NULL,
406 gEfiFwVolBlockNotifyReg,
407 &BufferSize,
408 &Handle
409 );
410
411 //
412 // If not found, we're done
413 //
414 if (EFI_NOT_FOUND == Status) {
415 break;
416 }
417
418 if (EFI_ERROR (Status)) {
419 continue;
420 }
421
422 //
423 // Get the FirmwareVolumeBlock protocol on that handle
424 //
425 Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb);
426 ASSERT_EFI_ERROR (Status);
427
428
429 //
430 // Make sure the Fv Header is O.K.
431 //
432 Status = GetFwVolHeader (Fvb, &FwVolHeader);
433 if (EFI_ERROR (Status)) {
434 return;
435 }
436
437 if (!VerifyFvHeaderChecksum (FwVolHeader)) {
438 CoreFreePool (FwVolHeader);
439 continue;
440 }
441
442
443 //
444 // Check to see that the file system is indeed formatted in a way we can
445 // understand it...
446 //
447 if (!CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem2Guid)) {
448 continue;
449 }
450
451 //
452 // Check if there is an FV protocol already installed in that handle
453 //
454 Status = CoreHandleProtocol (Handle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);
455 if (!EFI_ERROR (Status)) {
456 //
457 // Update Fv to use a new Fvb
458 //
459 FvDevice = _CR (Fv, FV_DEVICE, Fv);
460 if (FvDevice->Signature == FV2_DEVICE_SIGNATURE) {
461 //
462 // Only write into our device structure if it's our device structure
463 //
464 FvDevice->Fvb = Fvb;
465 }
466
467 } else {
468 //
469 // No FwVol protocol on the handle so create a new one
470 //
471 FvDevice = AllocateCopyPool (sizeof (FV_DEVICE), &mFvDevice);
472 if (FvDevice == NULL) {
473 return;
474 }
475
476 FvDevice->Fvb = Fvb;
477 FvDevice->Handle = Handle;
478 FvDevice->FwVolHeader = FwVolHeader;
479 FvDevice->Fv.ParentHandle = Fvb->ParentHandle;
480
481 //
482 // Install an New FV protocol on the existing handle
483 //
484 Status = CoreInstallProtocolInterface (
485 &Handle,
486 &gEfiFirmwareVolume2ProtocolGuid,
487 EFI_NATIVE_INTERFACE,
488 &FvDevice->Fv
489 );
490 ASSERT_EFI_ERROR (Status);
491 }
492 }
493
494 return;
495 }
496
497
498
499 /**
500 This routine is the driver initialization entry point. It registers
501 a notification function. This notification function are responsible
502 for building the FV stack dynamically.
503
504 @param ImageHandle The image handle.
505 @param SystemTable The system table.
506
507 @retval EFI_SUCCESS Function successfully returned.
508
509 **/
510 EFI_STATUS
511 EFIAPI
512 FwVolDriverInit (
513 IN EFI_HANDLE ImageHandle,
514 IN EFI_SYSTEM_TABLE *SystemTable
515 )
516 {
517 gEfiFwVolBlockEvent = EfiCreateProtocolNotifyEvent (
518 &gEfiFirmwareVolumeBlockProtocolGuid,
519 TPL_CALLBACK,
520 NotifyFwVolBlock,
521 NULL,
522 &gEfiFwVolBlockNotifyReg
523 );
524 return EFI_SUCCESS;
525 }
526
527