EFIAPI EFI_STATUS BootMonFsReadDirectory ( IN EFI_FILE_PROTOCOL *This, IN OUT UINTN *BufferSize, OUT VOID *Buffer ) { BOOTMON_FS_INSTANCE *Instance; BOOTMON_FS_FILE *RootFile; BOOTMON_FS_FILE *File; EFI_FILE_INFO *Info; UINTN NameSize; UINTN ResultSize; EFI_STATUS Status; UINTN Index; RootFile = BOOTMON_FS_FILE_FROM_FILE_THIS (This); if (RootFile == NULL) { return EFI_INVALID_PARAMETER; } Instance = RootFile->Instance; Status = BootMonGetFileFromPosition (Instance, RootFile->Position, &File); if (EFI_ERROR (Status)) { // No more file *BufferSize = 0; return EFI_SUCCESS; } NameSize = AsciiStrLen (File->HwDescription.Footer.Filename) + 1; ResultSize = SIZE_OF_EFI_FILE_INFO + (NameSize * sizeof (CHAR16)); if (*BufferSize < ResultSize) { *BufferSize = ResultSize; return EFI_BUFFER_TOO_SMALL; } // Zero out the structure Info = Buffer; ZeroMem (Info, ResultSize); // Fill in the structure Info->Size = ResultSize; Info->FileSize = BootMonFsGetImageLength (File); Info->PhysicalSize = BootMonFsGetPhysicalSize (File); for (Index = 0; Index < NameSize; Index++) { Info->FileName[Index] = File->HwDescription.Footer.Filename[Index]; } *BufferSize = ResultSize; RootFile->Position++; return EFI_SUCCESS; }
EFI_STATUS GetFileInfo ( IN BOOTMON_FS_INSTANCE *Instance, IN BOOTMON_FS_FILE *File, IN OUT UINTN *BufferSize, OUT VOID *Buffer ) { EFI_FILE_INFO *Info; UINTN ResultSize; UINTN NameSize; UINTN Index; if (File == Instance->RootFile) { NameSize = 0; ResultSize = SIZE_OF_EFI_FILE_INFO + sizeof (CHAR16); } else { NameSize = AsciiStrLen (File->HwDescription.Footer.Filename) + 1; ResultSize = SIZE_OF_EFI_FILE_INFO + (NameSize * sizeof (CHAR16)); } if (*BufferSize < ResultSize) { *BufferSize = ResultSize; return EFI_BUFFER_TOO_SMALL; } Info = Buffer; // Zero out the structure ZeroMem (Info, ResultSize); // Fill in the structure Info->Size = ResultSize; if (File == Instance->RootFile) { Info->Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY; Info->FileName[0] = L'\0'; } else { Info->FileSize = BootMonFsGetImageLength (File); Info->PhysicalSize = BootMonFsGetPhysicalSize (File); for (Index = 0; Index < NameSize; Index++) { Info->FileName[Index] = File->HwDescription.Footer.Filename[Index]; } } *BufferSize = ResultSize; return EFI_SUCCESS; }
EFIAPI EFI_STATUS BootMonFsFlushFile ( IN EFI_FILE_PROTOCOL *This ) { EFI_STATUS Status; BOOTMON_FS_INSTANCE *Instance; LIST_ENTRY *RegionToFlushLink; BOOTMON_FS_FILE *File; BOOTMON_FS_FILE *NextFile; BOOTMON_FS_FILE_REGION *Region; LIST_ENTRY *FileLink; UINTN CurrentPhysicalSize; UINTN BlockSize; UINT64 FileStart; UINT64 FileEnd; UINT64 RegionStart; UINT64 RegionEnd; UINT64 NewFileSize; UINT64 EndOfAppendSpace; BOOLEAN HasSpace; EFI_DISK_IO_PROTOCOL *DiskIo; EFI_BLOCK_IO_PROTOCOL *BlockIo; Status = EFI_SUCCESS; FileStart = 0; File = BOOTMON_FS_FILE_FROM_FILE_THIS (This); if (File == NULL) { return EFI_INVALID_PARAMETER; } // Check if the file needs to be flushed if (!BootMonFsFileNeedFlush (File)) { return Status; } Instance = File->Instance; BlockIo = Instance->BlockIo; DiskIo = Instance->DiskIo; BlockSize = BlockIo->Media->BlockSize; // If the file doesn't exist then find a space for it if (File->HwDescription.RegionCount == 0) { Status = BootMonFsFindSpaceForNewFile (File, &FileStart); // FileStart has changed so we need to recompute RegionEnd if (EFI_ERROR (Status)) { return Status; } } else { FileStart = File->HwDescription.BlockStart * BlockSize; } // FileEnd is the NOR address of the end of the file's data FileEnd = FileStart + BootMonFsGetImageLength (File); for (RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink); !IsNull (&File->RegionToFlushLink, RegionToFlushLink); RegionToFlushLink = GetNextNode (&File->RegionToFlushLink, RegionToFlushLink) ) { Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink; // RegionStart and RegionEnd are the the intended NOR address of the // start and end of the region RegionStart = FileStart + Region->Offset; RegionEnd = RegionStart + Region->Size; if (RegionEnd < FileEnd) { // Handle regions representing edits to existing portions of the file // Write the region data straight into the file Status = DiskIo->WriteDisk (DiskIo, BlockIo->Media->MediaId, RegionStart, Region->Size, Region->Buffer ); if (EFI_ERROR (Status)) { return Status; } } else { // Handle regions representing appends to the file // // Note: Since seeking past the end of the file with SetPosition() is // valid, it's possible there will be a gap between the current end of // the file and the beginning of the new region. Since the UEFI spec // says nothing about this case (except "a subsequent write would grow // the file"), we just leave garbage in the gap. // Check if there is space to append the new region HasSpace = FALSE; NewFileSize = (RegionEnd - FileStart) + sizeof (HW_IMAGE_DESCRIPTION); CurrentPhysicalSize = BootMonFsGetPhysicalSize (File); if (NewFileSize <= CurrentPhysicalSize) { HasSpace = TRUE; } else { // Get the File Description for the next file FileLink = GetNextNode (&Instance->RootFile->Link, &File->Link); if (!IsNull (&Instance->RootFile->Link, FileLink)) { NextFile = BOOTMON_FS_FILE_FROM_LINK_THIS (FileLink); // If there is space between the beginning of the current file and the // beginning of the next file then use it EndOfAppendSpace = NextFile->HwDescription.BlockStart * BlockSize; } else { // We are flushing the last file. EndOfAppendSpace = (BlockIo->Media->LastBlock + 1) * BlockSize; } if (EndOfAppendSpace - FileStart >= NewFileSize) { HasSpace = TRUE; } } if (HasSpace == TRUE) { Status = FlushAppendRegion (File, Region, NewFileSize, FileStart); if (EFI_ERROR (Status)) { return Status; } } else { // There isn't a space for the file. // Options here are to move the file or fragment it. However as files // may represent boot images at fixed positions, these options will // break booting if the bootloader doesn't use BootMonFs to find the // image. return EFI_VOLUME_FULL; } } } FreeFileRegions (File); // Flush DiskIo Buffers (see UEFI Spec 12.7 - DiskIo buffers are flushed by // calling FlushBlocks on the same device's BlockIo). BlockIo->FlushBlocks (BlockIo); return Status; }