OvmfPkg/QemuKernelLoaderFsDxe: rework direct kernel boot filesystem

Split KERNEL_BLOB struct into two:

 * One (KERNEL_BLOB_ITEMS) static array describing how to load (unnamed)
   blobs from fw_cfg.
 * And one (KERNEL_BLOB) dynamically allocated linked list carrying the
   data blobs for the pseudo filesystem.

Also add some debug logging.  Prefix most functions with 'QemuKernel'
for consistency and easier log file grepping.  Add some small helper
functions.

This refactoring prepares for loading blobs in other ways.
No (intentional) change in filesystem protocol behavior.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
Gerd Hoffmann 2025-01-14 17:36:39 +01:00 committed by Ard Biesheuvel
parent 139cbb266b
commit 459f5ffa24
1 changed files with 206 additions and 141 deletions

View File

@ -31,13 +31,6 @@
//
// Static data that hosts the fw_cfg blobs and serves file requests.
//
typedef enum {
KernelBlobTypeKernel,
KernelBlobTypeInitrd,
KernelBlobTypeCommandLine,
KernelBlobTypeMax
} KERNEL_BLOB_TYPE;
typedef struct {
CONST CHAR16 Name[8];
struct {
@ -45,11 +38,17 @@ typedef struct {
FIRMWARE_CONFIG_ITEM CONST DataKey;
UINT32 Size;
} FwCfgItem[2];
UINT32 Size;
UINT8 *Data;
} KERNEL_BLOB;
} KERNEL_BLOB_ITEMS;
STATIC KERNEL_BLOB mKernelBlob[KernelBlobTypeMax] = {
typedef struct KERNEL_BLOB KERNEL_BLOB;
struct KERNEL_BLOB {
CHAR16 Name[8];
UINT32 Size;
UINT8 *Data;
KERNEL_BLOB *Next;
};
STATIC KERNEL_BLOB_ITEMS mKernelBlobItems[] = {
{
L"kernel",
{
@ -69,7 +68,9 @@ STATIC KERNEL_BLOB mKernelBlob[KernelBlobTypeMax] = {
}
};
STATIC UINT64 mTotalBlobBytes;
STATIC KERNEL_BLOB *mKernelBlobs;
STATIC UINT64 mKernelBlobCount;
STATIC UINT64 mTotalBlobBytes;
//
// Device path for the handle that incorporates our "EFI stub filesystem".
@ -117,7 +118,7 @@ STATIC EFI_TIME mInitTime;
typedef struct {
UINT64 Signature; // Carries STUB_FILE_SIG.
KERNEL_BLOB_TYPE BlobType; // Index into mKernelBlob. KernelBlobTypeMax
KERNEL_BLOB *Blob; // Index into mKernelBlob. KernelBlobTypeMax
// denotes the root directory of the filesystem.
UINT64 Position; // Byte position for regular files;
@ -177,7 +178,7 @@ typedef struct {
STATIC
EFI_STATUS
EFIAPI
StubFileOpen (
QemuKernelStubFileOpen (
IN EFI_FILE_PROTOCOL *This,
OUT EFI_FILE_PROTOCOL **NewHandle,
IN CHAR16 *FileName,
@ -196,7 +197,7 @@ StubFileOpen (
STATIC
EFI_STATUS
EFIAPI
StubFileClose (
QemuKernelStubFileClose (
IN EFI_FILE_PROTOCOL *This
)
{
@ -219,7 +220,7 @@ StubFileClose (
STATIC
EFI_STATUS
EFIAPI
StubFileDelete (
QemuKernelStubFileDelete (
IN EFI_FILE_PROTOCOL *This
)
{
@ -229,18 +230,17 @@ StubFileDelete (
/**
Helper function that formats an EFI_FILE_INFO structure into the
user-allocated buffer, for any valid KERNEL_BLOB_TYPE value (including
KernelBlobTypeMax, which stands for the root directory).
user-allocated buffer, for any valid KERNEL_BLOB (including NULL,
which stands for the root directory).
The interface follows the EFI_FILE_GET_INFO -- and for directories, the
EFI_FILE_READ -- interfaces.
@param[in] BlobType The KERNEL_BLOB_TYPE value identifying the fw_cfg
@param[in] Blob The KERNEL_BLOB identifying the fw_cfg
blob backing the STUB_FILE that information is
being requested about. If BlobType equals
KernelBlobTypeMax, then information will be
provided about the root directory of the
filesystem.
being requested about. If Blob is NULL,
then information will be provided about the root
directory of the filesystem.
@param[in,out] BufferSize On input, the size of Buffer. On output, the
amount of data returned in Buffer. In both cases,
@ -257,10 +257,10 @@ StubFileDelete (
**/
STATIC
EFI_STATUS
ConvertKernelBlobTypeToFileInfo (
IN KERNEL_BLOB_TYPE BlobType,
IN OUT UINTN *BufferSize,
OUT VOID *Buffer
QemuKernelBlobTypeToFileInfo (
IN KERNEL_BLOB *Blob,
IN OUT UINTN *BufferSize,
OUT VOID *Buffer
)
{
CONST CHAR16 *Name;
@ -272,17 +272,16 @@ ConvertKernelBlobTypeToFileInfo (
EFI_FILE_INFO *FileInfo;
UINTN OriginalBufferSize;
if (BlobType == KernelBlobTypeMax) {
if (Blob == NULL) {
//
// getting file info about the root directory
//
DEBUG ((DEBUG_INFO, "%a: file info: directory\n", __func__));
Name = L"\\";
FileSize = KernelBlobTypeMax;
FileSize = mKernelBlobCount;
Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY;
} else {
CONST KERNEL_BLOB *Blob;
Blob = &mKernelBlob[BlobType];
DEBUG ((DEBUG_INFO, "%a: file info: \"%s\"\n", __func__, Blob->Name));
Name = Blob->Name;
FileSize = Blob->Size;
Attribute = EFI_FILE_READ_ONLY;
@ -312,6 +311,23 @@ ConvertKernelBlobTypeToFileInfo (
return EFI_SUCCESS;
}
STATIC
KERNEL_BLOB *
FindKernelBlob (
CHAR16 *FileName
)
{
KERNEL_BLOB *Blob;
for (Blob = mKernelBlobs; Blob != NULL; Blob = Blob->Next) {
if (StrCmp (FileName, Blob->Name) == 0) {
return Blob;
}
}
return NULL;
}
/**
Reads data from a file, or continues scanning a directory.
@ -349,25 +365,25 @@ ConvertKernelBlobTypeToFileInfo (
STATIC
EFI_STATUS
EFIAPI
StubFileRead (
QemuKernelStubFileRead (
IN EFI_FILE_PROTOCOL *This,
IN OUT UINTN *BufferSize,
OUT VOID *Buffer
)
{
STUB_FILE *StubFile;
CONST KERNEL_BLOB *Blob;
UINT64 Left;
STUB_FILE *StubFile;
KERNEL_BLOB *Blob;
UINT64 Left, Pos;
StubFile = STUB_FILE_FROM_FILE (This);
//
// Scanning the root directory?
//
if (StubFile->BlobType == KernelBlobTypeMax) {
if (StubFile->Blob == NULL) {
EFI_STATUS Status;
if (StubFile->Position == KernelBlobTypeMax) {
if (StubFile->Position == mKernelBlobCount) {
//
// Scanning complete.
//
@ -375,8 +391,16 @@ StubFileRead (
return EFI_SUCCESS;
}
Status = ConvertKernelBlobTypeToFileInfo (
(KERNEL_BLOB_TYPE)StubFile->Position,
for (Pos = 0, Blob = mKernelBlobs;
Pos < StubFile->Position;
Pos++, Blob = Blob->Next)
{
}
DEBUG ((DEBUG_INFO, "%a: file list: #%d \"%s\"\n", __func__, Pos, Blob->Name));
Status = QemuKernelBlobTypeToFileInfo (
Blob,
BufferSize,
Buffer
);
@ -391,7 +415,7 @@ StubFileRead (
//
// Reading a file.
//
Blob = &mKernelBlob[StubFile->BlobType];
Blob = StubFile->Blob;
if (StubFile->Position > Blob->Size) {
return EFI_DEVICE_ERROR;
}
@ -402,6 +426,7 @@ StubFileRead (
}
if (Blob->Data != NULL) {
DEBUG ((DEBUG_INFO, "%a: file read: \"%s\", %d bytes\n", __func__, Blob->Name, *BufferSize));
CopyMem (Buffer, Blob->Data + StubFile->Position, *BufferSize);
}
@ -435,7 +460,7 @@ StubFileRead (
STATIC
EFI_STATUS
EFIAPI
StubFileWrite (
QemuKernelStubFileWrite (
IN EFI_FILE_PROTOCOL *This,
IN OUT UINTN *BufferSize,
IN VOID *Buffer
@ -444,7 +469,7 @@ StubFileWrite (
STUB_FILE *StubFile;
StubFile = STUB_FILE_FROM_FILE (This);
return (StubFile->BlobType == KernelBlobTypeMax) ?
return (StubFile->Blob == NULL) ?
EFI_UNSUPPORTED :
EFI_WRITE_PROTECTED;
}
@ -466,7 +491,7 @@ StubFileWrite (
STATIC
EFI_STATUS
EFIAPI
StubFileGetPosition (
QemuKernelStubFileGetPosition (
IN EFI_FILE_PROTOCOL *This,
OUT UINT64 *Position
)
@ -474,7 +499,7 @@ StubFileGetPosition (
STUB_FILE *StubFile;
StubFile = STUB_FILE_FROM_FILE (This);
if (StubFile->BlobType == KernelBlobTypeMax) {
if (StubFile->Blob == NULL) {
return EFI_UNSUPPORTED;
}
@ -501,7 +526,7 @@ StubFileGetPosition (
STATIC
EFI_STATUS
EFIAPI
StubFileSetPosition (
QemuKernelStubFileSetPosition (
IN EFI_FILE_PROTOCOL *This,
IN UINT64 Position
)
@ -511,7 +536,7 @@ StubFileSetPosition (
StubFile = STUB_FILE_FROM_FILE (This);
if (StubFile->BlobType == KernelBlobTypeMax) {
if (StubFile->Blob == NULL) {
if (Position == 0) {
//
// rewinding a directory scan is allowed
@ -526,7 +551,7 @@ StubFileSetPosition (
//
// regular file seek
//
Blob = &mKernelBlob[StubFile->BlobType];
Blob = StubFile->Blob;
if (Position == MAX_UINT64) {
//
// seek to end
@ -583,7 +608,7 @@ StubFileSetPosition (
STATIC
EFI_STATUS
EFIAPI
StubFileGetInfo (
QemuKernelStubFileGetInfo (
IN EFI_FILE_PROTOCOL *This,
IN EFI_GUID *InformationType,
IN OUT UINTN *BufferSize,
@ -596,8 +621,8 @@ StubFileGetInfo (
StubFile = STUB_FILE_FROM_FILE (This);
if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
return ConvertKernelBlobTypeToFileInfo (
StubFile->BlobType,
return QemuKernelBlobTypeToFileInfo (
StubFile->Blob,
BufferSize,
Buffer
);
@ -685,7 +710,7 @@ StubFileGetInfo (
STATIC
EFI_STATUS
EFIAPI
StubFileSetInfo (
QemuKernelStubFileSetInfo (
IN EFI_FILE_PROTOCOL *This,
IN EFI_GUID *InformationType,
IN UINTN BufferSize,
@ -712,7 +737,7 @@ StubFileSetInfo (
STATIC
EFI_STATUS
EFIAPI
StubFileFlush (
QemuKernelStubFileFlush (
IN EFI_FILE_PROTOCOL *This
)
{
@ -724,16 +749,16 @@ StubFileFlush (
//
STATIC CONST EFI_FILE_PROTOCOL mEfiFileProtocolTemplate = {
EFI_FILE_PROTOCOL_REVISION, // revision 1
StubFileOpen,
StubFileClose,
StubFileDelete,
StubFileRead,
StubFileWrite,
StubFileGetPosition,
StubFileSetPosition,
StubFileGetInfo,
StubFileSetInfo,
StubFileFlush,
QemuKernelStubFileOpen,
QemuKernelStubFileClose,
QemuKernelStubFileDelete,
QemuKernelStubFileRead,
QemuKernelStubFileWrite,
QemuKernelStubFileGetPosition,
QemuKernelStubFileSetPosition,
QemuKernelStubFileGetInfo,
QemuKernelStubFileSetInfo,
QemuKernelStubFileFlush,
NULL, // OpenEx, revision 2
NULL, // ReadEx, revision 2
NULL, // WriteEx, revision 2
@ -743,7 +768,7 @@ STATIC CONST EFI_FILE_PROTOCOL mEfiFileProtocolTemplate = {
STATIC
EFI_STATUS
EFIAPI
StubFileOpen (
QemuKernelStubFileOpen (
IN EFI_FILE_PROTOCOL *This,
OUT EFI_FILE_PROTOCOL **NewHandle,
IN CHAR16 *FileName,
@ -752,7 +777,7 @@ StubFileOpen (
)
{
CONST STUB_FILE *StubFile;
UINTN BlobType;
KERNEL_BLOB *Blob;
STUB_FILE *NewStubFile;
//
@ -774,21 +799,20 @@ StubFileOpen (
// Only the root directory supports opening files in it.
//
StubFile = STUB_FILE_FROM_FILE (This);
if (StubFile->BlobType != KernelBlobTypeMax) {
if (StubFile->Blob != NULL) {
return EFI_UNSUPPORTED;
}
//
// Locate the file.
//
for (BlobType = 0; BlobType < KernelBlobTypeMax; ++BlobType) {
if (StrCmp (FileName, mKernelBlob[BlobType].Name) == 0) {
break;
}
}
Blob = FindKernelBlob (FileName);
if (BlobType == KernelBlobTypeMax) {
if (Blob == NULL) {
DEBUG ((DEBUG_INFO, "%a: file not found: \"%s\"\n", __func__, FileName));
return EFI_NOT_FOUND;
} else {
DEBUG ((DEBUG_INFO, "%a: file opened: \"%s\"\n", __func__, FileName));
}
//
@ -800,7 +824,7 @@ StubFileOpen (
}
NewStubFile->Signature = STUB_FILE_SIG;
NewStubFile->BlobType = (KERNEL_BLOB_TYPE)BlobType;
NewStubFile->Blob = Blob;
NewStubFile->Position = 0;
CopyMem (
&NewStubFile->File,
@ -842,7 +866,7 @@ StubFileOpen (
STATIC
EFI_STATUS
EFIAPI
StubFileSystemOpenVolume (
QemuKernelStubFileSystemOpenVolume (
IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
OUT EFI_FILE_PROTOCOL **Root
)
@ -855,7 +879,7 @@ StubFileSystemOpenVolume (
}
StubFile->Signature = STUB_FILE_SIG;
StubFile->BlobType = KernelBlobTypeMax;
StubFile->Blob = NULL;
StubFile->Position = 0;
CopyMem (
&StubFile->File,
@ -869,13 +893,13 @@ StubFileSystemOpenVolume (
STATIC CONST EFI_SIMPLE_FILE_SYSTEM_PROTOCOL mFileSystem = {
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,
StubFileSystemOpenVolume
QemuKernelStubFileSystemOpenVolume
};
STATIC
EFI_STATUS
EFIAPI
InitrdLoadFile2 (
QemuKernelInitrdLoadFile2 (
IN EFI_LOAD_FILE2_PROTOCOL *This,
IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
IN BOOLEAN BootPolicy,
@ -883,8 +907,11 @@ InitrdLoadFile2 (
OUT VOID *Buffer OPTIONAL
)
{
CONST KERNEL_BLOB *InitrdBlob = &mKernelBlob[KernelBlobTypeInitrd];
KERNEL_BLOB *InitrdBlob;
DEBUG ((DEBUG_INFO, "%a: initrd read\n", __func__));
InitrdBlob = FindKernelBlob (L"initrd");
ASSERT (InitrdBlob != NULL);
ASSERT (InitrdBlob->Size > 0);
if (BootPolicy) {
@ -913,17 +940,33 @@ InitrdLoadFile2 (
}
STATIC CONST EFI_LOAD_FILE2_PROTOCOL mInitrdLoadFile2 = {
InitrdLoadFile2,
QemuKernelInitrdLoadFile2,
};
//
// Utility functions.
//
STATIC VOID
QemuKernelChunkedRead (
UINT8 *Dest,
UINT32 Bytes
)
{
UINT32 Chunk;
while (Bytes > 0) {
Chunk = (Bytes < SIZE_1MB) ? Bytes : SIZE_1MB;
QemuFwCfgReadBytes (Chunk, Dest);
Bytes -= Chunk;
Dest += Chunk;
}
}
/**
Populate a blob in mKernelBlob.
param[in,out] Blob Pointer to the KERNEL_BLOB element in mKernelBlob that is
param[in,out] Blob Pointer to the KERNEL_BLOB_ITEMS that is
to be filled from fw_cfg.
@retval EFI_SUCCESS Blob has been populated. If fw_cfg reported a
@ -934,35 +977,46 @@ STATIC CONST EFI_LOAD_FILE2_PROTOCOL mInitrdLoadFile2 = {
**/
STATIC
EFI_STATUS
FetchBlob (
IN OUT KERNEL_BLOB *Blob
QemuKernelFetchBlob (
IN KERNEL_BLOB_ITEMS *BlobItems
)
{
UINT32 Left;
UINTN Idx;
UINT8 *ChunkData;
UINT32 Size;
UINTN Idx;
UINT8 *ChunkData;
KERNEL_BLOB *Blob;
EFI_STATUS Status;
//
// Read blob size.
//
Blob->Size = 0;
for (Idx = 0; Idx < ARRAY_SIZE (Blob->FwCfgItem); Idx++) {
if (Blob->FwCfgItem[Idx].SizeKey == 0) {
for (Size = 0, Idx = 0; Idx < ARRAY_SIZE (BlobItems->FwCfgItem); Idx++) {
if (BlobItems->FwCfgItem[Idx].SizeKey == 0) {
break;
}
QemuFwCfgSelectItem (Blob->FwCfgItem[Idx].SizeKey);
Blob->FwCfgItem[Idx].Size = QemuFwCfgRead32 ();
Blob->Size += Blob->FwCfgItem[Idx].Size;
QemuFwCfgSelectItem (BlobItems->FwCfgItem[Idx].SizeKey);
BlobItems->FwCfgItem[Idx].Size = QemuFwCfgRead32 ();
Size += BlobItems->FwCfgItem[Idx].Size;
}
if (Blob->Size == 0) {
if (Size == 0) {
return EFI_SUCCESS;
}
Blob = AllocatePool (sizeof (*Blob));
if (Blob->Data == NULL) {
return EFI_OUT_OF_RESOURCES;
}
ZeroMem (Blob, sizeof (*Blob));
//
// Read blob.
//
Status = StrCpyS (Blob->Name, sizeof (Blob->Name), BlobItems->Name);
ASSERT (!EFI_ERROR (Status));
Blob->Size = Size;
Blob->Data = AllocatePool (Blob->Size);
if (Blob->Data == NULL) {
DEBUG ((
@ -972,6 +1026,7 @@ FetchBlob (
(INT64)Blob->Size,
Blob->Name
));
FreePool (Blob);
return EFI_OUT_OF_RESOURCES;
}
@ -984,36 +1039,50 @@ FetchBlob (
));
ChunkData = Blob->Data;
for (Idx = 0; Idx < ARRAY_SIZE (Blob->FwCfgItem); Idx++) {
if (Blob->FwCfgItem[Idx].DataKey == 0) {
for (Idx = 0; Idx < ARRAY_SIZE (BlobItems->FwCfgItem); Idx++) {
if (BlobItems->FwCfgItem[Idx].DataKey == 0) {
break;
}
QemuFwCfgSelectItem (Blob->FwCfgItem[Idx].DataKey);
Left = Blob->FwCfgItem[Idx].Size;
while (Left > 0) {
UINT32 Chunk;
Chunk = (Left < SIZE_1MB) ? Left : SIZE_1MB;
QemuFwCfgReadBytes (Chunk, ChunkData + Blob->FwCfgItem[Idx].Size - Left);
Left -= Chunk;
DEBUG ((
DEBUG_VERBOSE,
"%a: %Ld bytes remaining for \"%s\" (%d)\n",
__func__,
(INT64)Left,
Blob->Name,
(INT32)Idx
));
}
ChunkData += Blob->FwCfgItem[Idx].Size;
QemuFwCfgSelectItem (BlobItems->FwCfgItem[Idx].DataKey);
QemuKernelChunkedRead (ChunkData, BlobItems->FwCfgItem[Idx].Size);
ChunkData += BlobItems->FwCfgItem[Idx].Size;
}
Blob->Next = mKernelBlobs;
mKernelBlobs = Blob;
mKernelBlobCount++;
mTotalBlobBytes += Blob->Size;
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
QemuKernelVerifyBlob (
CHAR16 *FileName,
EFI_STATUS FetchStatus
)
{
KERNEL_BLOB *Blob;
EFI_STATUS Status;
if ((StrCmp (FileName, L"kernel") != 0) &&
(StrCmp (FileName, L"initrd") != 0) &&
(StrCmp (FileName, L"cmdline") != 0))
{
return EFI_SUCCESS;
}
Blob = FindKernelBlob (FileName);
Status = VerifyBlob (
FileName,
Blob ? Blob->Data : NULL,
Blob ? Blob->Size : 0,
FetchStatus
);
return Status;
}
//
// The entry point of the feature.
//
@ -1038,13 +1107,13 @@ QemuKernelLoaderFsDxeEntrypoint (
IN EFI_SYSTEM_TABLE *SystemTable
)
{
UINTN BlobType;
KERNEL_BLOB *CurrentBlob;
KERNEL_BLOB *KernelBlob;
EFI_STATUS Status;
EFI_STATUS FetchStatus;
EFI_HANDLE FileSystemHandle;
EFI_HANDLE InitrdLoadFile2Handle;
UINTN BlobIdx;
KERNEL_BLOB_ITEMS *BlobItems;
KERNEL_BLOB *Blob;
EFI_STATUS Status;
EFI_STATUS FetchStatus;
EFI_HANDLE FileSystemHandle;
EFI_HANDLE InitrdLoadFile2Handle;
if (!QemuFwCfgIsAvailable ()) {
return EFI_NOT_FOUND;
@ -1059,26 +1128,22 @@ QemuKernelLoaderFsDxeEntrypoint (
//
// Fetch all blobs.
//
for (BlobType = 0; BlobType < KernelBlobTypeMax; ++BlobType) {
CurrentBlob = &mKernelBlob[BlobType];
FetchStatus = FetchBlob (CurrentBlob);
for (BlobIdx = 0; BlobIdx < ARRAY_SIZE (mKernelBlobItems); ++BlobIdx) {
BlobItems = &mKernelBlobItems[BlobIdx];
FetchStatus = QemuKernelFetchBlob (BlobItems);
Status = VerifyBlob (
CurrentBlob->Name,
CurrentBlob->Data,
CurrentBlob->Size,
Status = QemuKernelVerifyBlob (
(CHAR16 *)BlobItems->Name,
FetchStatus
);
if (EFI_ERROR (Status)) {
goto FreeBlobs;
}
mTotalBlobBytes += CurrentBlob->Size;
}
KernelBlob = &mKernelBlob[KernelBlobTypeKernel];
if (KernelBlob->Data == NULL) {
Blob = FindKernelBlob (L"kernel");
if (Blob == NULL) {
DEBUG ((DEBUG_INFO, "%a: no kernel present -> quit\n", __func__));
Status = EFI_NOT_FOUND;
goto FreeBlobs;
}
@ -1106,7 +1171,9 @@ QemuKernelLoaderFsDxeEntrypoint (
goto FreeBlobs;
}
if (KernelBlob[KernelBlobTypeInitrd].Size > 0) {
Blob = FindKernelBlob (L"initrd");
if (Blob != NULL) {
DEBUG ((DEBUG_INFO, "%a: initrd setup\n", __func__));
InitrdLoadFile2Handle = NULL;
Status = gBS->InstallMultipleProtocolInterfaces (
&InitrdLoadFile2Handle,
@ -1141,13 +1208,11 @@ UninstallFileSystemHandle:
ASSERT_EFI_ERROR (Status);
FreeBlobs:
while (BlobType > 0) {
CurrentBlob = &mKernelBlob[--BlobType];
if (CurrentBlob->Data != NULL) {
FreePool (CurrentBlob->Data);
CurrentBlob->Size = 0;
CurrentBlob->Data = NULL;
}
while (mKernelBlobs != NULL) {
Blob = mKernelBlobs;
mKernelBlobs = Blob->Next;
FreePool (Blob->Data);
FreePool (Blob);
}
return Status;