/** Stop this driver on ControllerHandle. Support stopping any child handles created by this driver. @param This Protocol instance pointer. @param ControllerHandle Handle of device to stop driver on @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of children is zero stop the entire bus driver. @param ChildHandleBuffer List of Child Handles to Stop. @retval EFI_SUCCESS This driver is removed ControllerHandle @retval other This driver was not removed from this device **/ EFI_STATUS EFIAPI PartitionDriverBindingStop ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer ) { EFI_STATUS Status; UINTN Index; EFI_BLOCK_IO_PROTOCOL *BlockIo; EFI_BLOCK_IO2_PROTOCOL *BlockIo2; BOOLEAN AllChildrenStopped; PARTITION_PRIVATE_DATA *Private; EFI_DISK_IO_PROTOCOL *DiskIo; BlockIo = NULL; BlockIo2 = NULL; Private = NULL; if (NumberOfChildren == 0) { // // Close the bus driver // gBS->CloseProtocol ( ControllerHandle, &gEfiDiskIoProtocolGuid, This->DriverBindingHandle, ControllerHandle ); // // Close Parent BlockIO2 if has. // gBS->CloseProtocol ( ControllerHandle, &gEfiDiskIo2ProtocolGuid, This->DriverBindingHandle, ControllerHandle ); gBS->CloseProtocol ( ControllerHandle, &gEfiDevicePathProtocolGuid, This->DriverBindingHandle, ControllerHandle ); return EFI_SUCCESS; } AllChildrenStopped = TRUE; for (Index = 0; Index < NumberOfChildren; Index++) { gBS->OpenProtocol ( ChildHandleBuffer[Index], &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); // // Try to locate BlockIo2. // gBS->OpenProtocol ( ChildHandleBuffer[Index], &gEfiBlockIo2ProtocolGuid, (VOID **) &BlockIo2, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo); Status = gBS->CloseProtocol ( ControllerHandle, &gEfiDiskIoProtocolGuid, This->DriverBindingHandle, ChildHandleBuffer[Index] ); // // All Software protocols have be freed from the handle so remove it. // Remove the BlockIo Protocol if has. // Remove the BlockIo2 Protocol if has. // if (BlockIo2 != NULL) { BlockIo->FlushBlocks (BlockIo); BlockIo2->FlushBlocksEx (BlockIo2, NULL); Status = gBS->UninstallMultipleProtocolInterfaces ( ChildHandleBuffer[Index], &gEfiDevicePathProtocolGuid, Private->DevicePath, &gEfiBlockIoProtocolGuid, &Private->BlockIo, &gEfiBlockIo2ProtocolGuid, &Private->BlockIo2, Private->EspGuid, NULL, NULL ); } else { BlockIo->FlushBlocks (BlockIo); Status = gBS->UninstallMultipleProtocolInterfaces ( ChildHandleBuffer[Index], &gEfiDevicePathProtocolGuid, Private->DevicePath, &gEfiBlockIoProtocolGuid, &Private->BlockIo, Private->EspGuid, NULL, NULL ); } if (EFI_ERROR (Status)) { gBS->OpenProtocol ( ControllerHandle, &gEfiDiskIoProtocolGuid, (VOID **) &DiskIo, This->DriverBindingHandle, ChildHandleBuffer[Index], EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER ); } else { FreePool (Private->DevicePath); FreePool (Private); } if (EFI_ERROR (Status)) { AllChildrenStopped = FALSE; } } if (!AllChildrenStopped) { return EFI_DEVICE_ERROR; } return EFI_SUCCESS; }
EFI_STATUS ArmFastbootPlatformFlashPartition ( IN CHAR8 *PartitionName, IN UINTN Size, IN VOID *Image ) { EFI_STATUS Status; EFI_BLOCK_IO_PROTOCOL *BlockIo; EFI_DISK_IO_PROTOCOL *DiskIo; UINT32 MediaId; UINTN PartitionSize; FASTBOOT_PARTITION_LIST *Entry; CHAR16 PartitionNameUnicode[60]; BOOLEAN PartitionFound; AsciiStrToUnicodeStr (PartitionName, PartitionNameUnicode); PartitionFound = FALSE; Entry = (FASTBOOT_PARTITION_LIST *) GetFirstNode (&(mPartitionListHead)); while (!IsNull (&mPartitionListHead, &Entry->Link)) { // Search the partition list for the partition named by PartitionName if (StrCmp (Entry->PartitionName, PartitionNameUnicode) == 0) { PartitionFound = TRUE; break; } Entry = (FASTBOOT_PARTITION_LIST *) GetNextNode (&mPartitionListHead, &(Entry)->Link); } if (!PartitionFound) { return EFI_NOT_FOUND; } Status = gBS->OpenProtocol ( Entry->PartitionHandle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo, gImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "Fastboot platform: couldn't open Block IO for flash: %r\n", Status)); return EFI_NOT_FOUND; } // Check image will fit on device PartitionSize = (BlockIo->Media->LastBlock + 1) * BlockIo->Media->BlockSize; if (PartitionSize < Size) { DEBUG ((EFI_D_ERROR, "Partition not big enough.\n")); DEBUG ((EFI_D_ERROR, "Partition Size:\t%d\nImage Size:\t%d\n", PartitionSize, Size)); return EFI_VOLUME_FULL; } MediaId = BlockIo->Media->MediaId; Status = gBS->OpenProtocol ( Entry->PartitionHandle, &gEfiDiskIoProtocolGuid, (VOID **) &DiskIo, gImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); ASSERT_EFI_ERROR (Status); Status = DiskIo->WriteDisk (DiskIo, MediaId, 0, Size, Image); if (EFI_ERROR (Status)) { return Status; } BlockIo->FlushBlocks(BlockIo); return Status; }
/** Stop this driver on ControllerHandle. Support stopping any child handles created by this driver. @param This Protocol instance pointer. @param ControllerHandle Handle of device to stop driver on @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of children is zero stop the entire bus driver. @param ChildHandleBuffer List of Child Handles to Stop. @retval EFI_SUCCESS This driver is removed ControllerHandle @retval other This driver was not removed from this device **/ EFI_STATUS EFIAPI PartitionDriverBindingStop ( IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle, IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer ) { EFI_STATUS Status; UINTN Index; EFI_BLOCK_IO_PROTOCOL *BlockIo; EFI_BLOCK_IO2_PROTOCOL *BlockIo2; BOOLEAN AllChildrenStopped; PARTITION_PRIVATE_DATA *Private; EFI_DISK_IO_PROTOCOL *DiskIo; EFI_GUID *TypeGuid; BlockIo = NULL; BlockIo2 = NULL; Private = NULL; if (NumberOfChildren == 0) { // // In the case of re-entry of the PartitionDriverBindingStop, the // NumberOfChildren may not reflect the actual number of children on the // bus driver. Hence, additional check is needed here. // if (HasChildren (ControllerHandle)) { DEBUG((EFI_D_ERROR, "PartitionDriverBindingStop: Still has child.\n")); return EFI_DEVICE_ERROR; } // // Close the bus driver // gBS->CloseProtocol ( ControllerHandle, &gEfiDiskIoProtocolGuid, This->DriverBindingHandle, ControllerHandle ); // // Close Parent BlockIO2 if has. // gBS->CloseProtocol ( ControllerHandle, &gEfiDiskIo2ProtocolGuid, This->DriverBindingHandle, ControllerHandle ); gBS->CloseProtocol ( ControllerHandle, &gEfiDevicePathProtocolGuid, This->DriverBindingHandle, ControllerHandle ); return EFI_SUCCESS; } AllChildrenStopped = TRUE; for (Index = 0; Index < NumberOfChildren; Index++) { gBS->OpenProtocol ( ChildHandleBuffer[Index], &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); // // Try to locate BlockIo2. // gBS->OpenProtocol ( ChildHandleBuffer[Index], &gEfiBlockIo2ProtocolGuid, (VOID **) &BlockIo2, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); Private = PARTITION_DEVICE_FROM_BLOCK_IO_THIS (BlockIo); if (Private->InStop) { // // If the child handle is going to be stopped again during the re-entry // of DriverBindingStop, just do nothing. // break; } Private->InStop = TRUE; BlockIo->FlushBlocks (BlockIo); if (BlockIo2 != NULL) { Status = BlockIo2->FlushBlocksEx (BlockIo2, NULL); DEBUG((EFI_D_ERROR, "PartitionDriverBindingStop: FlushBlocksEx returned with %r\n", Status)); } else { Status = EFI_SUCCESS; } gBS->CloseProtocol ( ControllerHandle, &gEfiDiskIoProtocolGuid, This->DriverBindingHandle, ChildHandleBuffer[Index] ); if (IsZeroGuid (&Private->TypeGuid)) { TypeGuid = NULL; } else { TypeGuid = &Private->TypeGuid; } // // All Software protocols have be freed from the handle so remove it. // Remove the BlockIo Protocol if has. // Remove the BlockIo2 Protocol if has. // if (BlockIo2 != NULL) { // // Some device drivers might re-install the BlockIO(2) protocols for a // media change condition. Therefore, if the FlushBlocksEx returned with // EFI_MEDIA_CHANGED, just let the BindingStop fail to avoid potential // reference of already stopped child handle. // if (Status != EFI_MEDIA_CHANGED) { Status = gBS->UninstallMultipleProtocolInterfaces ( ChildHandleBuffer[Index], &gEfiDevicePathProtocolGuid, Private->DevicePath, &gEfiBlockIoProtocolGuid, &Private->BlockIo, &gEfiBlockIo2ProtocolGuid, &Private->BlockIo2, &gEfiPartitionInfoProtocolGuid, &Private->PartitionInfo, TypeGuid, NULL, NULL ); } } else { Status = gBS->UninstallMultipleProtocolInterfaces ( ChildHandleBuffer[Index], &gEfiDevicePathProtocolGuid, Private->DevicePath, &gEfiBlockIoProtocolGuid, &Private->BlockIo, &gEfiPartitionInfoProtocolGuid, &Private->PartitionInfo, TypeGuid, NULL, NULL ); } if (EFI_ERROR (Status)) { Private->InStop = FALSE; gBS->OpenProtocol ( ControllerHandle, &gEfiDiskIoProtocolGuid, (VOID **) &DiskIo, This->DriverBindingHandle, ChildHandleBuffer[Index], EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER ); } else { FreePool (Private->DevicePath); FreePool (Private); } if (EFI_ERROR (Status)) { AllChildrenStopped = FALSE; if (Status == EFI_MEDIA_CHANGED) { break; } } } if (!AllChildrenStopped) { return EFI_DEVICE_ERROR; } return EFI_SUCCESS; }
// // TDS 5.3 // EFI_STATUS BBTestWriteBlocksFunctionAutoTest ( IN EFI_BB_TEST_PROTOCOL *This, IN VOID *ClientInterface, IN EFI_TEST_LEVEL TestLevel, IN EFI_HANDLE SupportHandle ) { EFI_STANDARD_TEST_LIBRARY_PROTOCOL *StandardLib; EFI_STATUS Status; EFI_BLOCK_IO_PROTOCOL *BlockIo; UINT32 MediaId; BOOLEAN RemovableMedia; BOOLEAN MediaPresent; BOOLEAN LogicalPartition; BOOLEAN ReadOnly; BOOLEAN WriteCaching; UINT32 BlockSize; UINT32 IoAlign; EFI_LBA LastBlock; UINTN BufferSize; UINT8 *Buffer; UINT8 *Buffer2; UINT8 *Buffer3; UINT32 BlockNumber; UINTN IndexI, IndexJ; UINTN NewBufferSize; EFI_LBA NewLba; UINTN Remainder; EFI_DEVICE_PATH_PROTOCOL *DevicePath; CHAR16 *DevicePathStr; EFI_TEST_ASSERTION AssertionTypeRead1; EFI_TEST_ASSERTION AssertionTypeRead2; EFI_TEST_ASSERTION AssertionTypeRead3; EFI_TEST_ASSERTION AssertionTypeWrite1; EFI_TEST_ASSERTION AssertionTypeWrite2; EFI_TEST_ASSERTION AssertionTypeComp1; EFI_TEST_ASSERTION AssertionTypeComp2; EFI_STATUS StatusRead1; EFI_STATUS StatusRead2; EFI_STATUS StatusRead3; EFI_STATUS StatusWrite1; EFI_STATUS StatusWrite2; UINTN CountComp1; UINTN CountComp2; // // Get the Standard Library Interface // Status = gtBS->HandleProtocol ( SupportHandle, &gEfiStandardTestLibraryGuid, &StandardLib ); if (EFI_ERROR(Status)) { StandardLib->RecordAssertion ( StandardLib, EFI_TEST_ASSERTION_FAILED, gTestGenericFailureGuid, L"BS.HandleProtocol - Handle standard test library", L"%a:%d:Status - %r", __FILE__, __LINE__, Status ); return Status; } BlockIo = (EFI_BLOCK_IO_PROTOCOL *)ClientInterface; // // Locate & record DevicePath for further investigation // LocateDevicePathFromBlockIo (BlockIo, &DevicePath, StandardLib); DevicePathStr = DevicePathToStr (DevicePath); if (DevicePathStr != NULL) { StandardLib->RecordMessage ( StandardLib, EFI_VERBOSE_LEVEL_DEFAULT, L"Current Device: %s", DevicePathStr ); Status = gtBS->FreePool (DevicePathStr); if (EFI_ERROR(Status)) { StandardLib->RecordAssertion ( StandardLib, EFI_TEST_ASSERTION_FAILED, gTestGenericFailureGuid, L"BS.FreePool - Free device path string", L"%a:%d:Status - %r", __FILE__, __LINE__, Status ); return Status; } DevicePathStr = NULL; } // // Initialize variable // MediaId = BlockIo->Media->MediaId; RemovableMedia = BlockIo->Media->RemovableMedia; MediaPresent = BlockIo->Media->MediaPresent; LogicalPartition = BlockIo->Media->LogicalPartition; ReadOnly = BlockIo->Media->ReadOnly; WriteCaching = BlockIo->Media->WriteCaching; BlockSize = BlockIo->Media->BlockSize; IoAlign = BlockIo->Media->IoAlign; LastBlock = BlockIo->Media->LastBlock; BlockNumber = (UINT32) MINIMUM(LastBlock, MAX_NUMBER_OF_READ_BLOCK_BUFFER); BufferSize = BlockNumber * BlockSize; if (BufferSize == 0) { BufferSize = 512; } // // allocate buffer // Status = gtBS->AllocatePool (EfiBootServicesData, BufferSize, &Buffer); if (EFI_ERROR(Status)) { StandardLib->RecordAssertion ( StandardLib, EFI_TEST_ASSERTION_FAILED, gTestGenericFailureGuid, L"BS.AllocatePool - Allocate buffer for testing", L"%a:%d:Status - %r", __FILE__, __LINE__, Status ); return Status; } Status = gtBS->AllocatePool (EfiBootServicesData, BufferSize, &Buffer2); if (EFI_ERROR(Status)) { StandardLib->RecordAssertion ( StandardLib, EFI_TEST_ASSERTION_FAILED, gTestGenericFailureGuid, L"BS.AllocatePool - Allocate buffer for testing", L"%a:%d:Status - %r", __FILE__, __LINE__, Status ); gtBS->FreePool (Buffer); return Status; } Status = gtBS->AllocatePool (EfiBootServicesData, BufferSize, &Buffer3); if (EFI_ERROR(Status)) { StandardLib->RecordAssertion ( StandardLib, EFI_TEST_ASSERTION_FAILED, gTestGenericFailureGuid, L"BS.AllocatePool - Allocate buffer for testing", L"%a:%d:Status - %r", __FILE__, __LINE__, Status ); gtBS->FreePool (Buffer); gtBS->FreePool (Buffer2); return Status; } // // Assertion Point 5.3.2.1 // ReadBlocks must succeed to read proper data from device with valid parameter // if ((MediaPresent == TRUE) && (ReadOnly == FALSE)) { for (IndexI = 1; IndexI < MAX_DIFFERENT_BUFFERSIZE_FOR_TEST; IndexI++) { // // prepare test data // BufferSize will range from BlockSize to MAX_DIFFERENT_BUFFERSIZE_FOR_TEST*BlockSize // NewBufferSize = IndexI * BlockSize; // //parameter verification on NewBufferSize // if (NewBufferSize > BufferSize) { break; } for (IndexJ = 0; IndexJ < 3 * MAX_DIFFERENT_LBA_FOR_TEST; IndexJ++) { // // prepare test data // if (IndexJ < MAX_DIFFERENT_LBA_FOR_TEST) { // from 1 to MAX_DIFFERENT_LBA_FOR_TEST NewLba = IndexJ; } else if (IndexJ < 2 * MAX_DIFFERENT_LBA_FOR_TEST) { // from (LastBlock - MAX_DIFFERENT_LBA_FOR_TEST - MAX_DIFFERENT_BUFFERSIZE_FOR_TEST) to (LastBlock - MAX_DIFFERENT_BUFFERSIZE_FOR_TEST) NewLba = IndexJ + LastBlock - 2 * MAX_DIFFERENT_LBA_FOR_TEST - MAX_DIFFERENT_BUFFERSIZE_FOR_TEST; } else { // from (LastBlock/2 - MAX_DIFFERENT_LBA_FOR_TEST/2) to (LastBlock/2 + MAX_DIFFERENT_LBA_FOR_TEST/2) NewLba = IndexJ - 2 * MAX_DIFFERENT_LBA_FOR_TEST + (DivU64x32 (LastBlock, 2, &Remainder) - MAX_DIFFERENT_LBA_FOR_TEST / 2); } // //parameter verification on NewLba // if (NewLba + NewBufferSize / BlockSize > LastBlock + 1) { continue; } // // To avoid the LOG information is destroied, the LOG information will // be recorded after the original data is written again. // // // Call ReadBlocks with the specified LBA and BufferSize // StatusRead1 = BlockIo->ReadBlocks ( BlockIo, MediaId, NewLba, NewBufferSize, (VOID*)Buffer ); if (EFI_ERROR(StatusRead1)) { AssertionTypeRead1 = EFI_TEST_ASSERTION_FAILED; } else { AssertionTypeRead1 = EFI_TEST_ASSERTION_PASSED; } // // Write specified buffer2 differ from buffer to the device // StatusWrite1 = BlockIo->WriteBlocks ( BlockIo, MediaId, NewLba, NewBufferSize, (VOID*)Buffer2 ); if (EFI_ERROR(StatusWrite1)) { AssertionTypeWrite1 = EFI_TEST_ASSERTION_FAILED; } else { AssertionTypeWrite1 = EFI_TEST_ASSERTION_PASSED; } // // if write-cached, then flush the data to physical device // if (WriteCaching) { BlockIo->FlushBlocks (BlockIo); } // // Read Block with same LBA and BufferSize again and save data into Buffer3 // StatusRead2 = BlockIo->ReadBlocks ( BlockIo, MediaId, NewLba, NewBufferSize, (VOID*)Buffer3 ); if (EFI_ERROR(StatusRead2)) { AssertionTypeRead2 = EFI_TEST_ASSERTION_FAILED; } else { AssertionTypeRead2 = EFI_TEST_ASSERTION_PASSED; } // // verification on Write and Read blocks on valid media // CountComp1 = VerifyBuffer (Buffer2, Buffer3, NewBufferSize); if (CountComp1 > 0) { AssertionTypeComp1 = EFI_TEST_ASSERTION_FAILED; } else { AssertionTypeComp1 = EFI_TEST_ASSERTION_PASSED; } // // Write buffer read in the first call of ReadBlocks back to the device // StatusWrite2 = BlockIo->WriteBlocks ( BlockIo, MediaId, NewLba, NewBufferSize, (VOID*)Buffer ); if (EFI_ERROR(StatusWrite2)) { AssertionTypeWrite2 = EFI_TEST_ASSERTION_FAILED; } else { AssertionTypeWrite2 = EFI_TEST_ASSERTION_PASSED; } // // if write-cached, then flush the data to physical device // if (WriteCaching) { BlockIo->FlushBlocks (BlockIo); } // // Read Block with same LBA and BufferSize again and save data into Buffer3 // StatusRead3 = BlockIo->ReadBlocks ( BlockIo, MediaId, NewLba, NewBufferSize, (VOID*)Buffer3 ); if (EFI_ERROR(StatusRead3)) { AssertionTypeRead3 = EFI_TEST_ASSERTION_FAILED; } else { AssertionTypeRead3 = EFI_TEST_ASSERTION_PASSED; } // // verification on first and last call of ReadBlocks // CountComp2 = VerifyBuffer (Buffer, Buffer3, NewBufferSize); if (CountComp2 > 0) { AssertionTypeComp2 = EFI_TEST_ASSERTION_FAILED; } else { AssertionTypeComp2 = EFI_TEST_ASSERTION_PASSED; } // // Record test results // StandardLib->RecordAssertion ( StandardLib, AssertionTypeRead1, gTestGenericFailureGuid, L"EFI_BLOCK_IO_PROTOCOL.ReadBlocks - Read Block with proper parameter from valid media", L"%a:%d:BufferSize=%d, Lba=0x%lx, Status=%r", __FILE__, __LINE__, NewBufferSize, NewLba, StatusRead1 ); StandardLib->RecordAssertion ( StandardLib, AssertionTypeWrite1, gBlockIoFunctionTestAssertionGuid009, L"EFI_BLOCK_IO_PROTOCOL.WriteBlocks - Write Block with proper parameter from valid media", L"%a:%d:BufferSize=%d, Lba=0x%lx, Status=%r", __FILE__, __LINE__, NewBufferSize, NewLba, StatusWrite1 ); StandardLib->RecordAssertion ( StandardLib, AssertionTypeRead2, gTestGenericFailureGuid, L"EFI_BLOCK_IO_PROTOCOL.ReadBlocks - Read Block with proper parameter from valid media", L"%a:%d:BufferSize=%d, Lba=0x%lx, Status=%r", __FILE__, __LINE__, NewBufferSize, NewLba, StatusRead2 ); StandardLib->RecordAssertion ( StandardLib, AssertionTypeComp1, gBlockIoFunctionTestAssertionGuid012, L"EFI_BLOCK_IO_PROTOCOL.WriteBlocks - Verification on Write and Read blocks on valid media", L"%a:%d:BufferSize=%d, Lba=0x%lx, DiffCount=%d", __FILE__, __LINE__, NewBufferSize, NewLba, CountComp1 ); StandardLib->RecordAssertion ( StandardLib, AssertionTypeWrite2, gBlockIoFunctionTestAssertionGuid013, L"EFI_BLOCK_IO_PROTOCOL.WriteBlocks - Write Block with proper parameter back to valid media ", L"%a:%d:BufferSize=%d, Lba=0x%lx, Status=%r", __FILE__, __LINE__, NewBufferSize, NewLba, StatusWrite2 ); StandardLib->RecordAssertion ( StandardLib, AssertionTypeRead3, gTestGenericFailureGuid, L"EFI_BLOCK_IO_PROTOCOL.ReadBlocks - Read Block with proper parameter from valid media", L"%a:%d:BufferSize=%d, Lba=0x%lx, Status=%r", __FILE__, __LINE__, NewBufferSize, NewLba, StatusRead3 ); StandardLib->RecordAssertion ( StandardLib, AssertionTypeComp2, gBlockIoFunctionTestAssertionGuid016, L"EFI_BLOCK_IO_PROTOCOL.WriteBlocks - Verification on Write and Read blocks on valid media", L"%a:%d:BufferSize=%d, Lba=0x%lx, DiffCount=%d", __FILE__, __LINE__, NewBufferSize, NewLba, CountComp2 ); }//end of loop of Lba - IndexJ }//end of loop of BufferSize - IndexI } // // Free resources // Status = gtBS->FreePool (Buffer3); if (EFI_ERROR(Status)) { StandardLib->RecordAssertion ( StandardLib, EFI_TEST_ASSERTION_FAILED, gTestGenericFailureGuid, L"BS.FreePool - Free buffer for testing", L"%a:%d:Status - %r", __FILE__, __LINE__, Status ); return Status; } Status = gtBS->FreePool (Buffer2); if (EFI_ERROR(Status)) { StandardLib->RecordAssertion ( StandardLib, EFI_TEST_ASSERTION_FAILED, gTestGenericFailureGuid, L"BS.FreePool - Free buffer for testing", L"%a:%d:Status - %r", __FILE__, __LINE__, Status ); return Status; } Status = gtBS->FreePool (Buffer); if (EFI_ERROR(Status)) { StandardLib->RecordAssertion ( StandardLib, EFI_TEST_ASSERTION_FAILED, gTestGenericFailureGuid, L"BS.FreePool - Free buffer for testing", L"%a:%d:Status - %r", __FILE__, __LINE__, Status ); return Status; } 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; }