ftwlite.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 971 行 · 第 1/3 页

C
971
字号
  EfiInitializeDriverLib (ImageHandle, SystemTable);

  //
  // Allocate Private data of this driver,
  // INCLUDING THE FtwWorkSpace[FTW_WORK_SPACE_SIZE].
  //
  FtwLiteDevice = NULL;
  FtwLiteDevice = EfiLibAllocatePool (sizeof (EFI_FTW_LITE_DEVICE) + FTW_WORK_SPACE_SIZE);
  if (FtwLiteDevice != NULL) {
    Status = EFI_SUCCESS;
  } else {
    Status = EFI_OUT_OF_RESOURCES;
  }

  ASSERT_EFI_ERROR (Status);

  EfiZeroMem (FtwLiteDevice, sizeof (EFI_FTW_LITE_DEVICE));
  FtwLiteDevice->Signature = FTW_LITE_DEVICE_SIGNATURE;

  //
  // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.
  //
  FtwLiteDevice->FtwWorkSpace     = (UINT8 *) (FtwLiteDevice + 1);
  FtwLiteDevice->FtwWorkSpaceSize = FTW_WORK_SPACE_SIZE;
  EfiSetMem (
    FtwLiteDevice->FtwWorkSpace,
    FtwLiteDevice->FtwWorkSpaceSize,
    FTW_ERASED_BYTE
    );
  FtwLiteDevice->FtwWorkSpaceHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) FtwLiteDevice->FtwWorkSpace;

  FtwLiteDevice->FtwLastRecord      = NULL;

  //
  // Get EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL protocol Boot Firmware Device,
  // Using this protocol to access the working block and spare block
  //
  Status = EfiLibGetSystemConfigurationTable (&gEfiHobListGuid, &HobList);
  ASSERT_EFI_ERROR (Status);

  FtwLiteDevice->SpareAreaLength  = 0;
  FtwLiteDevice->WorkSpaceLength  = 0;
  for (;;) {
    Status = GetNextGuidHob (&HobList, &gEfiFlashMapHobGuid, &Buffer, NULL);
    if (EFI_ERROR (Status)) {
      break;
    }

    FlashMapEntry = (EFI_FLASH_MAP_ENTRY_DATA *) Buffer;

    //
    // Get the FTW work space Flash Map SUB area
    //
    if ((FlashMapEntry->AreaType == EFI_FLASH_AREA_FTW_STATE) && (FlashMapEntry->NumEntries == 1)) {
      FtwLiteDevice->WorkSpaceAddress = FlashMapEntry->Entries[0].Base;
      FtwLiteDevice->WorkSpaceLength  = (UINTN) FlashMapEntry->Entries[0].Length;
    }
    //
    // Get the FTW backup SUB area
    //
    if ((FlashMapEntry->AreaType == EFI_FLASH_AREA_FTW_BACKUP) && (FlashMapEntry->NumEntries == 1)) {
      FtwLiteDevice->SpareAreaAddress = FlashMapEntry->Entries[0].Base;
      FtwLiteDevice->SpareAreaLength  = (UINTN) FlashMapEntry->Entries[0].Length;
    }
  }

  ASSERT ((FtwLiteDevice->WorkSpaceLength != 0) && (FtwLiteDevice->SpareAreaLength != 0));

  //
  // Locate FVB protocol
  //
  Status = gBS->LocateHandleBuffer (
                  ByProtocol,
                  &gEfiFirmwareVolumeBlockProtocolGuid,
                  NULL,
                  &HandleCount,
                  &HandleBuffer
                  );
  ASSERT_EFI_ERROR (Status);

  ASSERT (HandleCount > 0);

  FtwLiteDevice->FtwFvBlock       = NULL;
  FtwLiteDevice->FtwBackupFvb     = NULL;
  FtwLiteDevice->FtwWorkSpaceLba  = (EFI_LBA) (-1);
  FtwLiteDevice->FtwSpareLba      = (EFI_LBA) (-1);
  for (Index = 0; Index < HandleCount; Index += 1) {
    Status = gBS->HandleProtocol (
                    HandleBuffer[Index],
                    &gEfiFirmwareVolumeBlockProtocolGuid,
                    (VOID **) &Fvb
                    );
    ASSERT_EFI_ERROR (Status);

    Status = Fvb->GetPhysicalAddress (Fvb, &BaseAddress);
    if (EFI_ERROR (Status)) {
      continue;
    }

    FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) BaseAddress);

    if ((FtwLiteDevice->WorkSpaceAddress >= BaseAddress) &&
        (FtwLiteDevice->WorkSpaceAddress < (BaseAddress + FwVolHeader->FvLength))
        ) {
      FtwLiteDevice->FtwFvBlock = Fvb;
      //
      // To get the LBA of work space
      //
      if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
        //
        // FV may have multiple types of BlockLength
        //
        FvbMapEntry = &FwVolHeader->FvBlockMap[0];
        while (!((FvbMapEntry->NumBlocks == 0) && (FvbMapEntry->BlockLength == 0))) {
          for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
            if (FtwLiteDevice->WorkSpaceAddress < (BaseAddress + FvbMapEntry->BlockLength * LbaIndex)) {
              FtwLiteDevice->FtwWorkSpaceLba = LbaIndex - 1;
              //
              // Get the Work space size and Base(Offset)
              //
              FtwLiteDevice->FtwWorkSpaceSize = FtwLiteDevice->WorkSpaceLength;
              FtwLiteDevice->FtwWorkSpaceBase = (UINTN) (FtwLiteDevice->WorkSpaceAddress - (BaseAddress + FvbMapEntry->BlockLength * (LbaIndex - 1)));
              break;
            }
          }
          //
          // end for
          //
          FvbMapEntry++;
        }
        //
        // end while
        //
      }
    }

    if ((FtwLiteDevice->SpareAreaAddress >= BaseAddress) &&
        (FtwLiteDevice->SpareAreaAddress < (BaseAddress + FwVolHeader->FvLength))
        ) {
      FtwLiteDevice->FtwBackupFvb = Fvb;
      //
      // To get the LBA of spare
      //
      if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
        //
        // FV may have multiple types of BlockLength
        //
        FvbMapEntry = &FwVolHeader->FvBlockMap[0];
        while (!((FvbMapEntry->NumBlocks == 0) && (FvbMapEntry->BlockLength == 0))) {
          for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
            if (FtwLiteDevice->SpareAreaAddress < (BaseAddress + FvbMapEntry->BlockLength * LbaIndex)) {
              //
              // Get the NumberOfSpareBlock and SizeOfSpareBlock
              //
              FtwLiteDevice->FtwSpareLba        = LbaIndex - 1;
              FtwLiteDevice->SizeOfSpareBlock   = FvbMapEntry->BlockLength;
              FtwLiteDevice->NumberOfSpareBlock = FtwLiteDevice->SpareAreaLength / FtwLiteDevice->SizeOfSpareBlock;
              //
              // Check the range of spare area to make sure that it's in FV range
              //
              ASSERT ((FtwLiteDevice->FtwSpareLba + FtwLiteDevice->NumberOfSpareBlock) <= FvbMapEntry->NumBlocks);
              break;
            }
          }

          FvbMapEntry++;
        }
        //
        // end while
        //
      }
    }
  }
  //
  // Calculate the start LBA of working block. Working block is an area which
  // contains working space in its last block and has the same size as spare
  // block, unless there are not enough blocks before the block that contains
  // working space.
  //
  FtwLiteDevice->FtwWorkBlockLba = FtwLiteDevice->FtwWorkSpaceLba - FtwLiteDevice->NumberOfSpareBlock + 1;
  if ((INT64) (FtwLiteDevice->FtwWorkBlockLba) < 0) {
    FtwLiteDevice->FtwWorkBlockLba = 0;
  }

  if ((FtwLiteDevice->FtwWorkSpaceLba == (EFI_LBA) (-1)) ||
      (FtwLiteDevice->FtwSpareLba == (EFI_LBA) (-1))
      ) {
    DEBUG ((EFI_D_ERROR, "FtwLite: Working or spare FVB not ready\n"));
    return EFI_ABORTED;
  }
  //
  // Refresh workspace data from working block
  //
  Status = WorkSpaceRefresh (FtwLiteDevice);
  ASSERT_EFI_ERROR (Status);

  //
  // If the working block workspace is not valid, try the spare block
  //
  if (!IsValidWorkSpace (FtwLiteDevice->FtwWorkSpaceHeader)) {
    DEBUG ((EFI_D_FTW_LITE, "FtwLite: Workspace invalid, read from backup\n"));
    //
    // Read from spare block
    //
    Length = FtwLiteDevice->FtwWorkSpaceSize;
    WorkSpaceLbaOffset = FtwLiteDevice->FtwWorkSpaceLba - FtwLiteDevice->FtwWorkBlockLba;
    Status = FtwLiteDevice->FtwBackupFvb->Read (
                                            FtwLiteDevice->FtwBackupFvb,
                           FtwLiteDevice->FtwSpareLba + WorkSpaceLbaOffset,
                                            FtwLiteDevice->FtwWorkSpaceBase,
                                            &Length,
                                            FtwLiteDevice->FtwWorkSpace
                                            );
    ASSERT_EFI_ERROR (Status);

    //
    // If spare block is valid, then replace working block content.
    //
    if (IsValidWorkSpace (FtwLiteDevice->FtwWorkSpaceHeader)) {
      Status = FlushSpareBlockToWorkingBlock (FtwLiteDevice);
      DEBUG ((EFI_D_FTW_LITE, "FtwLite: Restart working block in Init() - %r\n", Status));
      ASSERT_EFI_ERROR (Status);

      FtwAbort (FtwLiteDevice);
      //
      // Refresh work space.
      //
      Status = WorkSpaceRefresh (FtwLiteDevice);
      if (EFI_ERROR (Status)) {
        return EFI_ABORTED;
      }
    } else {
      DEBUG ((EFI_D_FTW_LITE, "FtwLite: Both are invalid, init workspace\n"));
      //
      // If both are invalid, then initialize work space.
      //
      EfiSetMem (
        FtwLiteDevice->FtwWorkSpace,
        FtwLiteDevice->FtwWorkSpaceSize,
        FTW_ERASED_BYTE
        );
      InitWorkSpaceHeader (FtwLiteDevice->FtwWorkSpaceHeader);
      //
      // Write to work space on the working block
      //
      Length = FtwLiteDevice->FtwWorkSpaceSize;
      Status = FtwLiteDevice->FtwFvBlock->Write (
                                            FtwLiteDevice->FtwFvBlock,
                                            FtwLiteDevice->FtwWorkSpaceLba,
                                            FtwLiteDevice->FtwWorkSpaceBase,
                                            &Length,
                                            FtwLiteDevice->FtwWorkSpace
                                            );
      if (EFI_ERROR (Status)) {
        return EFI_ABORTED;
      }
    }
  }
  //
  // Hook the protocol API
  //
  FtwLiteDevice->FtwLiteInstance.Write = FtwLiteWrite;

  //
  // Install protocol interface
  //
  Status = gBS->InstallProtocolInterface (
                  &FtwLiteDevice->Handle,
                  &gEfiFaultTolerantWriteLiteProtocolGuid,
                  EFI_NATIVE_INTERFACE,
                  &FtwLiteDevice->FtwLiteInstance
                  );
  if (EFI_ERROR (Status)) {
    return EFI_ABORTED;
  }
  //
  // If (!SpareCompleted)  THEN  Abort to rollback.
  //
  if ((FtwLiteDevice->FtwLastRecord->WriteAllocated == FTW_VALID_STATE) &&
      (FtwLiteDevice->FtwLastRecord->SpareCompleted != FTW_VALID_STATE)
      ) {
    DEBUG ((EFI_D_FTW_LITE, "FtwLite: Init.. record not SpareCompleted, abort()\n"));
    FtwAbort (FtwLiteDevice);
  }
  //
  // if (SpareCompleted) THEN  Restart to fault tolerant write.
  //
  if ((FtwLiteDevice->FtwLastRecord->SpareCompleted == FTW_VALID_STATE) &&
      (FtwLiteDevice->FtwLastRecord->WriteCompleted != FTW_VALID_STATE)
      ) {

    Status = FtwRestart (FtwLiteDevice);
    DEBUG ((EFI_D_FTW_LITE, "FtwLite: Restart last write - %r\n", Status));
    if (EFI_ERROR (Status)) {
      return Status;
    }
  }
  //
  // To check the workspace buffer behind last records is EMPTY or not.
  // If it's not EMPTY, FTW_LITE also need to call reclaim().
  //
  Record  = FtwLiteDevice->FtwLastRecord;
  Offset  = (UINT8 *) Record - FtwLiteDevice->FtwWorkSpace;
  if (FtwLiteDevice->FtwWorkSpace[Offset] != FTW_ERASED_BYTE) {
    Offset += WRITE_TOTAL_SIZE;
  }

  if (!IsErasedFlashBuffer (
        FTW_ERASE_POLARITY,
        FtwLiteDevice->FtwWorkSpace + Offset,
        FtwLiteDevice->FtwWorkSpaceSize - Offset
        )) {
    DEBUG ((EFI_D_FTW_LITE, "FtwLite: Workspace is dirty, call reclaim...\n"));
    Status = FtwReclaimWorkSpace (FtwLiteDevice);
    if (EFI_ERROR (Status)) {
      DEBUG ((EFI_D_FTW_LITE, "FtwLite: Workspace reclaim - %r\n", Status));
      return EFI_ABORTED;
    }
  }

  return EFI_SUCCESS;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?