cache.c

来自「Next BIOS Source code : Extensible Firmw」· C语言 代码 · 共 614 行 · 第 1/2 页

C
614
字号
  WorkingBufferSize = BufferSize;

  PageNo = (UINTN) DriverLibDivU64x32 (Offset, Vol->CachePageSize, &UnderRun);
 
  Length = Vol->CachePageSize - UnderRun;

  Status = EFI_SUCCESS;
  
  if (UnderRun != 0) {
    //
    // Offset starts in the middle of a page, so read the entire page
    //
    Status = FatGetCacheBuffer (Vol, PageNo, &Cache);
    
    if (EFI_ERROR (Status)) {
      goto Done;
    }
    
    if (Length > BufferSize) {
      Length = BufferSize;
    }

    EfiCopyMem (WorkingBuffer, Cache->Data + UnderRun, Length);
    
    if (Length == BufferSize) {
      goto Done;
    }	
    
    WorkingBuffer += Length;
    WorkingBufferSize  -= Length;
    
    PageNo += 1;
  }

  OverRunPageNo = PageNo + 
            (UINTN) DriverLibDivU64x32 (WorkingBufferSize, Vol->CachePageSize, &OverRun);

    if (WorkingBufferSize >= Vol->CachePageSize) {
    //
    // If the DiskIo maps directly to a BlkIo device do the read
    //
    if (OverRun != 0) {
      WorkingBufferSize -= OverRun;
    }

    Status = Vol->DiskIo->ReadDisk (
                                    Vol->DiskIo, 
                                    Vol->MediaId, 
                                    DriverLibMultU64x32 (PageNo, Vol->CachePageSize),
                                    WorkingBufferSize, 
                                    WorkingBuffer
                                   );
    if (!Vol->Valid) {
      Status = EFI_MEDIA_CHANGED;
      goto Done;
    }    

    WorkingBuffer += WorkingBufferSize;
  } 


  if (OverRun != 0) {
    //
    // Last read is not a complete page
    //
    Status = FatGetCacheBuffer (Vol, OverRunPageNo, &Cache);
    
    if (EFI_ERROR (Status)) {
      goto Done;
    }

    EfiCopyMem (WorkingBuffer, Cache->Data, OverRun);    
  }

Done:
  return Status;
}



EFI_STATUS
FatDiskIoWriteVolume (
  IN FAT_VOLUME         *Vol,
  IN UINT64             Offset,
  IN UINTN              BufferSize,
  IN VOID               *Buffer
  )
/*++
   
  Routine Description:

    Write BufferSize bytes from Offset into Buffer.

    Writes may require a read modify write to support writes that are not 
    aligned on page boundaries. There are three cases:
    
      UnderRun - The first byte is not on a page boundary or the write request
                 is less than a page in length. Read modify write is required.

      Aligned  - A write of N contiguous pages.

      OverRun  - The last byte is not on a page boundary. Read modified write 
                 required.

  Arguments:
    Vol        - FAT file system volume.
    Offset     - The starting byte offset to read from.
    BufferSize - Size of Buffer.
    Buffer     - Buffer containing read data.

  Returns:
    EFI_SUCCESS           - The data was written correctly to the device.
    EFI_WRITE_PROTECTED   - The device can not be written to.
    EFI_DEVICE_ERROR      - The device reported an error while performing the 
                            write.
    EFI_NO_MEDIA          - There is no media in the device.
    EFI_MEDIA_CHNAGED     - The MediaId does not matched the current device.
    EFI_INVALID_PARAMETER - The write request contains device addresses that are
                            not valid for the device.

--*/
{
  EFI_STATUS    Status;
  UINTN         PageNo;
  UINTN         OverRunPageNo;
  UINTN         UnderRun;
  UINTN         OverRun;
  UINTN         WorkingBufferSize;
  UINT8         *WorkingBuffer;
  UINTN         Length;
  CACHE_BUFFER  *Cache;

  if (Vol->BlkIo->Media->ReadOnly) {
    return EFI_WRITE_PROTECTED;
  }

  if (Vol->BlkIo->Media->MediaId != Vol->MediaId) {
    return EFI_MEDIA_CHANGED;
  }

  if (!Vol->Valid) {
    return EFI_MEDIA_CHANGED;
  }

  WorkingBuffer = Buffer;
  WorkingBufferSize = BufferSize;

  PageNo = (UINTN) DriverLibDivU64x32 (Offset, Vol->CachePageSize, &UnderRun);
 
  Length = Vol->CachePageSize - UnderRun;

  Status = EFI_SUCCESS;
  
  if (UnderRun != 0) {
    //
    // Offset starts in the middle of a page,
    // so read modify write to the entire page
    //
    Status = FatGetCacheBuffer (Vol, PageNo, &Cache);
    
    if (EFI_ERROR (Status)) {
      goto Done;
    }
    
    if (Length > BufferSize) {
      Length = BufferSize;
    }

    EfiCopyMem (Cache->Data + UnderRun, WorkingBuffer, Length);
  
    //
    // Do not need to write to disk directly, instead, only need
    // to set cache entry to dirty. Dirty cache entry will be written
    // back to disk when it is flushed.
    //
    Cache->Dirty = TRUE;
    
    if (Length == BufferSize) {
      goto Done;	
    }

    WorkingBuffer += Length;
    WorkingBufferSize  -= Length;

    PageNo += 1;
  }


  OverRunPageNo = PageNo + 
            (UINTN) DriverLibDivU64x32 (WorkingBufferSize, Vol->CachePageSize, &OverRun);

  if (WorkingBufferSize >= Vol->CachePageSize) {
    //
    // If the DiskIo maps directly to a BlkIo device do the write
    //
    if (OverRun != 0) {
      WorkingBufferSize -= OverRun;
    }

    Status = Vol->DiskIo->WriteDisk (
                                      Vol->DiskIo, 
                                      Vol->MediaId, 
                                      DriverLibMultU64x32 (PageNo, Vol->CachePageSize),
                                      WorkingBufferSize, 
                                      WorkingBuffer
                                    );
    if (!Vol->Valid) {
      Status = EFI_MEDIA_CHANGED;
      goto Done;
    }
    
    WorkingBuffer += WorkingBufferSize;

    //
    // If this write over laps a read buffer it must be flushed
    //
    FatCacheFlushRange (Vol, PageNo, OverRunPageNo);    
  } 

  if (OverRun != 0) {
    //
    // Last bit is not a complete block, so do a read modify write
    //
    Status = FatGetCacheBuffer (Vol, OverRunPageNo, &Cache);
    
    if (EFI_ERROR (Status)) {
      goto Done;
    }

    EfiCopyMem (Cache->Data, WorkingBuffer, OverRun);    

    //
    // Do not need to write to disk directly, instead, only need
    // to set cache entry to dirty. Dirty cache entry will be written
    // back to disk when it is flushed.
    //
    Cache->Dirty = TRUE;
  }

Done:
  return Status;
}


EFI_STATUS
FatVolumeFlushCache (
  IN FAT_VOLUME         *Vol
  )
/*++
   
  Routine Description:

  Arguments:
    Vol        - FAT file system volume.

  Returns:
    EFI_STATUS
    
--*/
{
  EFI_STATUS Status;
  UINTN   Index;
  EFI_TPL EntryTpl;
  
  Status = EFI_SUCCESS;
  
  if (Vol->Valid == FALSE) {
    return EFI_MEDIA_CHANGED;
  }

  //
  // Make Cache Update a critical section
  //
  EntryTpl = gBS->RaiseTPL (EFI_TPL_NOTIFY);

  for (Index = 0; Index < FAT_CACHE_SIZE; Index++) {
    if (Vol->Cache[Index].Valid == TRUE) {
      if (Vol->Cache[Index].Dirty == TRUE) {
        //
        // Write back all Dirty cache entries to disk
        //
        Status = Vol->DiskIo->WriteDisk (
                      Vol->DiskIo, 
                      Vol->MediaId, 
                      DriverLibMultU64x32 (Vol->Cache[Index].PageNo, Vol->CachePageSize), 
                      Vol->CachePageSize, 
                      Vol->Cache[Index].Data
                    );
        if (EFI_ERROR (Status)) {
          Vol->Cache[Index].Valid = FALSE;
          gBS->RestoreTPL (EntryTpl);
          return Status;
        }

        Vol->Cache[Index].Dirty = FALSE;
      }
    }
  }
  
  //
  // Exit Cache Update critical section
  //
  gBS->RestoreTPL (EntryTpl);
  
  return Status;
}

⌨️ 快捷键说明

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