ehcimem.c

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

C
775
字号
/*++

Copyright (c) 2006, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution.  The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php

THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

Module Name:

    EhciMem.c

Abstract:


Revision History
--*/

#include "Tiano.h"
#include "EfiDriverLib.h"
#include "Ehci.h"



EFI_STATUS
CreateMemoryBlock (
  IN  USB2_HC_DEV               *HcDev,
  OUT MEMORY_MANAGE_HEADER      **MemoryHeader,
  IN  UINTN                     MemoryBlockSizeInPages
  )
/*++

Routine Description:

  Use PciIo->AllocateBuffer to allocate common buffer for the memory block,
  and use PciIo->Map to map the common buffer for Bus Master Read/Write.

Arguments:

  HcDev                  - USB2_HC_DEV
  MemoryHeader           - MEMORY_MANAGE_HEADER to output
  MemoryBlockSizeInPages - MemoryBlockSizeInPages

Returns:

  EFI_SUCCESS           Success
  EFI_OUT_OF_RESOURCES  Fail for no resources
  EFI_UNSUPPORTED       Unsupported currently

--*/
{
  EFI_STATUS            Status;
  VOID                  *CommonBuffer;
  EFI_PHYSICAL_ADDRESS  MappedAddress;
  UINTN                 MemoryBlockSizeInBytes;
  VOID                  *Mapping;

  //
  // Allocate memory for MemoryHeader
  //
  *MemoryHeader = EfiLibAllocateZeroPool (sizeof (MEMORY_MANAGE_HEADER));
  if (*MemoryHeader == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }

  (*MemoryHeader)->Next = NULL;

  //
  // set Memory block size
  //
  (*MemoryHeader)->MemoryBlockSizeInBytes = EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages);

  //
  // each bit in Bit Array will manage 32 bytes memory in memory block
  //
  (*MemoryHeader)->BitArraySizeInBytes = ((*MemoryHeader)->MemoryBlockSizeInBytes / MEM_UNIT_SIZE) / 8;

  //
  // Allocate memory for BitArray
  //
  (*MemoryHeader)->BitArrayPtr = EfiLibAllocateZeroPool ((*MemoryHeader)->BitArraySizeInBytes);
  if ((*MemoryHeader)->BitArrayPtr == NULL) {
    gBS->FreePool (*MemoryHeader);
    return EFI_OUT_OF_RESOURCES;
  }

  //
  // Memory Block uses MemoryBlockSizeInPages pages,
  // and it is allocated as common buffer use.
  //
  Status = HcDev->PciIo->AllocateBuffer (
                           HcDev->PciIo,
                           AllocateAnyPages,
                           EfiBootServicesData,
                           MemoryBlockSizeInPages,
                           &CommonBuffer,
                           0
                           );
  if (EFI_ERROR (Status)) {
    gBS->FreePool ((*MemoryHeader)->BitArrayPtr);
    gBS->FreePool (*MemoryHeader);
    return EFI_OUT_OF_RESOURCES;
  }

  MemoryBlockSizeInBytes = EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages);
  Status = HcDev->PciIo->Map (
                           HcDev->PciIo,
                           EfiPciIoOperationBusMasterCommonBuffer,
                           CommonBuffer,
                           &MemoryBlockSizeInBytes,
                           &MappedAddress,
                           &Mapping
                           );
  //
  // If returned Mapped size is less than the size
  // we request,do not support.
  //
  if (EFI_ERROR (Status) || (MemoryBlockSizeInBytes != EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages))) {
    HcDev->PciIo->FreeBuffer (HcDev->PciIo, MemoryBlockSizeInPages, CommonBuffer);
    gBS->FreePool ((*MemoryHeader)->BitArrayPtr);
    gBS->FreePool (*MemoryHeader);
    return EFI_UNSUPPORTED;
  }

  //
  // Data structure involved by host controller
  // should be restricted into the same 4G
  //
  if (HcDev->Is64BitCapable != 0) {
    if (HcDev->High32BitAddr != GET_32B_TO_63B (MappedAddress)) {
    HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
      HcDev->PciIo->FreeBuffer (HcDev->PciIo, MemoryBlockSizeInPages, CommonBuffer);
      gBS->FreePool ((*MemoryHeader)->BitArrayPtr);
      gBS->FreePool (*MemoryHeader);
      return EFI_UNSUPPORTED;
  }
  }

  //
  // Set Memory block initial address
  //
  (*MemoryHeader)->MemoryBlockPtr = (UINT8 *) ((UINTN) MappedAddress);
  (*MemoryHeader)->Mapping        = Mapping;

  EfiZeroMem (
    (*MemoryHeader)->MemoryBlockPtr,
    EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages)
    );

  return EFI_SUCCESS;
}

EFI_STATUS
FreeMemoryHeader (
  IN USB2_HC_DEV               *HcDev,
  IN MEMORY_MANAGE_HEADER      *MemoryHeader
  )
/*++

Routine Description:

  Free Memory Header

Arguments:

  HcDev         - USB2_HC_DEV
  MemoryHeader  - MemoryHeader to be freed

Returns:

  EFI_SUCCESS            Success
  EFI_INVALID_PARAMETER  Parameter is error

--*/
{
  if ((MemoryHeader == NULL) || (HcDev == NULL)) {
    return EFI_INVALID_PARAMETER;
  }
  //
  // unmap the common buffer used by the memory block
  //
  HcDev->PciIo->Unmap (HcDev->PciIo, MemoryHeader->Mapping);

  //
  // free common buffer
  //
  HcDev->PciIo->FreeBuffer (
                  HcDev->PciIo,
                  EFI_SIZE_TO_PAGES (MemoryHeader->MemoryBlockSizeInBytes),
                  MemoryHeader->MemoryBlockPtr
                  );
  //
  // free bit array
  //
  gBS->FreePool (MemoryHeader->BitArrayPtr);
  //
  // free memory header
  //
  gBS->FreePool (MemoryHeader);

  return EFI_SUCCESS;
}

EFI_STATUS
EhciAllocatePool (
  IN  USB2_HC_DEV     *HcDev,
  OUT UINT8           **Pool,
  IN  UINTN           AllocSize
  )
/*++

Routine Description:

  Ehci Allocate Pool

Arguments:

  HcDev     - USB2_HC_DEV
  Pool      - Place to store pointer to the memory buffer
  AllocSize - Alloc Size

Returns:

  EFI_SUCCESS        Success
  EFI_DEVICE_ERROR   Fail

--*/
{
  MEMORY_MANAGE_HEADER  *MemoryHeader;
  MEMORY_MANAGE_HEADER  *TempHeaderPtr;
  MEMORY_MANAGE_HEADER  *NewMemoryHeader;
  UINTN                 RealAllocSize;
  UINTN                 MemoryBlockSizeInPages;
  EFI_STATUS            Status;
  EFI_TPL               OldTpl;

  *Pool         = NULL;

  MemoryHeader  = HcDev->MemoryHeader;
  ASSERT (MemoryHeader != NULL);

  OldTpl = gBS->RaiseTPL (EFI_TPL_NOTIFY + 1);

  //
  // allocate unit is 32 bytes (align on 32 byte)
  //
  if (AllocSize & (MEM_UNIT_SIZE - 1)) {
    RealAllocSize = (AllocSize / MEM_UNIT_SIZE + 1) * MEM_UNIT_SIZE;
  } else {
    RealAllocSize = AllocSize;
  }

  //
  // There may be linked MemoryHeaders.
  // To allocate a free pool in Memory blocks,
  // must search in the MemoryHeader link list
  // until enough free pool is found.
  //
  Status = EFI_NOT_FOUND;
  for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL; TempHeaderPtr = TempHeaderPtr->Next) {

    Status = AllocMemInMemoryBlock (
              TempHeaderPtr,
              Pool,
              RealAllocSize / MEM_UNIT_SIZE
              );
    if (!EFI_ERROR (Status)) {
       break;
    }
  }

  gBS->RestoreTPL (OldTpl);

  if (!EFI_ERROR (Status)) {
     EfiZeroMem (*Pool, AllocSize);
     return EFI_SUCCESS;
  }


  //
  // There is no enough memory,
  // Create a new Memory Block
  //

  //
  // if pool size is larger than NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES,
  // just allocate a large enough memory block.
  //
  if (RealAllocSize > EFI_PAGES_TO_SIZE (NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES)) {
    MemoryBlockSizeInPages = EFI_SIZE_TO_PAGES (RealAllocSize) + 1;
  } else {
    MemoryBlockSizeInPages = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES;
  }

  Status = CreateMemoryBlock (HcDev, &NewMemoryHeader, MemoryBlockSizeInPages);
  if (EFI_ERROR (Status)) {
    return Status;
  }

  OldTpl = gBS->RaiseTPL (EFI_TPL_NOTIFY + 1);


  //
  // Link the new Memory Block to the Memory Header list
  //
  InsertMemoryHeaderToList (MemoryHeader, NewMemoryHeader);

  Status = AllocMemInMemoryBlock (
             NewMemoryHeader,
             Pool,
             RealAllocSize / MEM_UNIT_SIZE
             );

  gBS->RestoreTPL (OldTpl);

  if (!EFI_ERROR (Status)) {
    EfiZeroMem (*Pool, AllocSize);
  }

  return Status;
}

VOID
EhciFreePool (
  IN USB2_HC_DEV     *HcDev,
  IN UINT8           *Pool,
  IN UINTN           AllocSize
  )
/*++

Routine Description:

  Uhci Free Pool

Arguments:

  HcDev     - USB_HC_DEV
  Pool      - Pool to free
  AllocSize - Pool size

Returns:

  VOID

--*/
{
  MEMORY_MANAGE_HEADER  *MemoryHeader;
  MEMORY_MANAGE_HEADER  *TempHeaderPtr;
  UINTN                 StartBytePos;
  UINTN                 Index;
  UINT8                 StartBitPos;
  UINT8                 Index2;
  UINTN                 Count;
  UINTN                 RealAllocSize;
  EFI_TPL               OldTpl;

  OldTpl        = gBS->RaiseTPL (EFI_TPL_NOTIFY + 1);

  MemoryHeader  = HcDev->MemoryHeader;

  //
  // allocate unit is 32 byte (align on 32 byte)
  //
  if (AllocSize & (MEM_UNIT_SIZE - 1)) {
    RealAllocSize = (AllocSize / MEM_UNIT_SIZE + 1) * MEM_UNIT_SIZE;
  } else {
    RealAllocSize = AllocSize;
  }

  //
  // scan the memory header linked list for
  // the asigned memory to free.
  //
  for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL; TempHeaderPtr = TempHeaderPtr->Next) {

    if ((Pool >= TempHeaderPtr->MemoryBlockPtr) &&
        ((Pool + RealAllocSize) <= (TempHeaderPtr->MemoryBlockPtr + TempHeaderPtr->MemoryBlockSizeInBytes))
        ) {
      //
      // Pool is in the Memory Block area,
      // find the start byte and bit in the bit array
      //
      StartBytePos  = ((Pool - TempHeaderPtr->MemoryBlockPtr) / MEM_UNIT_SIZE) / 8;
      StartBitPos   = (UINT8) (((Pool - TempHeaderPtr->MemoryBlockPtr) / MEM_UNIT_SIZE) & 0x7);

      //

⌨️ 快捷键说明

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