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