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