cpuio.c

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

C
799
字号
    //
    // If the NT32 Passthrough has forced a HostBridgeInit
    //
    if (gHostBridgeInit) {
      if (gReadPending) {
        //
        // We found an access to our device
        //
        EFI_BREAKPOINT ();
        gWinNtThunk->DeviceIoControl (
                      gDeviceHandle,    // Handle to device
                      IOCTL_IO_READ,    // IO Control code to use
                      &Address,         // Address to communicate to driver
                      sizeof (UINT32),  // Length of buffer in bytes.
                      &Result,          // In Buffer to fill in by kernel driver.
                      sizeof (UINT16),  // Length of buffer in bytes.
                      &ReturnedLength,  // Bytes placed in In buffer.
                      NULL              // NULL means wait till op. completes.
                      );
        gReadPending = FALSE;
      } else {
        Result = 0xFFFF;
      }
    }

    *Buffer.ui16 = (UINT16) Result;
    break;

  case EfiCpuIoWidthUint32:
    //
    // If the NT32 Passthrough has forced a HostBridgeInit
    //
    if (gHostBridgeInit) {
      if (gReadPending) {
        //
        // We found an access to our device
        //
        EFI_BREAKPOINT ();
        gWinNtThunk->DeviceIoControl (
                      gDeviceHandle,    // Handle to device
                      IOCTL_IO_READ,    // IO Control code to use
                      &Address,         // Address to communicate to driver
                      sizeof (UINT32),  // Length of buffer in bytes.
                      &Result,          // In Buffer to fill in by kernel driver.
                      sizeof (UINT32),  // Length of buffer in bytes.
                      &ReturnedLength,  // Bytes placed in In buffer.
                      NULL              // NULL means wait till op. completes.
                      );
        gReadPending = FALSE;
      } else {
        Result = 0xFFFF;
      }
    }

    *Buffer.ui32 = Result;
    break;

  default:
    return EFI_INVALID_PARAMETER;
  }

  return EFI_SUCCESS;
}

EFI_STATUS
EFIAPI
CpuIoServiceWrite (
  IN EFI_CPU_IO_PROTOCOL                *This,
  IN  EFI_CPU_IO_PROTOCOL_WIDTH         Width,
  IN  UINT64                            UserAddress,
  IN  UINTN                             Count,
  IN  OUT VOID                          *UserBuffer
  )
/*++

Routine Description:

  
  This is the service that implements the I/O Write

Arguments:

  Pointer to an instance of the CPU I/O Protocol
  Width of the Memory Access
  Address of the I/O access
  Count of the number of accesses to perform
  Pointer to the buffer to read or write from I/O space

Returns:

  Status

  Status
  EFI_SUCCESS             - The data was read from or written to the EFI System.
  EFI_INVALID_PARAMETER   - Width is invalid for this EFI System.
  EFI_INVALID_PARAMETER   - Buffer is NULL.
  EFI_UNSUPPORTED         - The Buffer is not aligned for the given Width.
  EFI_UNSUPPORTED         - The address range specified by Address, Width, and 
                            Count is not valid for this EFI System.

--*/
// TODO:    This - add argument and description to function comment
// TODO:    UserAddress - add argument and description to function comment
// TODO:    UserBuffer - add argument and description to function comment
{
  UINTN       Address;
  EFI_STATUS  Status;
  UINTN       InStride;
  UINTN       OutStride;
  PTR         Buffer;
  LONG        ReturnedLength;
  UINT32      Result;

  if (!UserBuffer) {
    return EFI_INVALID_PARAMETER;
  }

  Address     = (UINTN) UserAddress;
  Buffer.buf  = (UINT8 *) UserBuffer;

  if (Width >= EfiCpuIoWidthMaximum) {
    return EFI_INVALID_PARAMETER;
  }

  Status = CpuIoCheckAddressRange (Width, Address, Count, UserBuffer, IA32_MAX_IO_ADDRESS);
  if (EFI_ERROR (Status)) {
    return Status;
  }

  InStride  = 1 << (Width & 0x03);
  OutStride = InStride;
  if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) {
    InStride = 0;
  }

  if (Width >= EfiCpuIoWidthFillUint8 && Width <= EfiCpuIoWidthFillUint64) {
    OutStride = 0;
  }

  Width         = Width & 0x03;

  gReadPending  = FALSE;
  //
  // NT32PASSTHRU: Thunk into our I/O routine to talk to the kernel driver IOCTL
  //               I/O such as write CF8->80000000, Read CFC etc......  Bit 31    = Enable PCI Config Access
  //                                                                    Bit 24-30 = Reserved must be zero (segment?)
  //                                                                    Bit 16-23 = Bus (0-255)
  //                                                                    Bit 11-15 = Device (0-31)
  //                                                                    Bit 8-10  = Function (0-7)
  //                                                                    Bit 2-7   = Target dword (0-63) (yields 256 bytes of access)
  //                                                                    Bit 0-1   = Zero's)
  //
  switch (Width) {
  case EfiCpuIoWidthUint8:
    //
    // If the NT32 Passthrough has forced a HostBridgeInit and if the request is from a device
    // on a given Bus/Device location.  Mask off the remaining functions
    //
    if (gHostBridgeInit) {
      if ((*(UINT32 *) Buffer.ui32 & 0xFFFFFF00) == *((UINT32 *) &gConfigData)) {
        Result = *Buffer.ui8;

        //
        // We found an access to our device
        //
        EFI_BREAKPOINT ();
        gWinNtThunk->DeviceIoControl (
                      gDeviceHandle,    // Handle to device
                      IOCTL_IO_WRITE,   // IO Control code to use
                      &Address,         // Address to communicate to driver
                      sizeof (UINT32),  // Length of buffer in bytes.
                      &Result,          // In Buffer to fill in by kernel driver.
                      sizeof (UINT8),   // Length of buffer in bytes.
                      &ReturnedLength,  // Bytes placed in In buffer.
                      NULL              // NULL means wait till op. completes.
                      );
        gReadPending = TRUE;
        return EFI_SUCCESS;
      }
    }
    break;

  case EfiCpuIoWidthUint16:
    //
    // If the NT32 Passthrough has forced a HostBridgeInit and if the request is from a device
    // on a given Bus/Device location.  Mask off the remaining functions
    //
    if (gHostBridgeInit) {
      if ((*(UINT32 *) Buffer.ui32 & 0xFFFFFF00) == *((UINT32 *) &gConfigData)) {
        Result = *Buffer.ui16;

        //
        // We found an access to our device
        //
        EFI_BREAKPOINT ();
        gWinNtThunk->DeviceIoControl (
                      gDeviceHandle,    // Handle to device
                      IOCTL_IO_WRITE,   // IO Control code to use
                      &Address,         // Address to communicate to driver
                      sizeof (UINT32),  // Length of buffer in bytes.
                      &Result,          // In Buffer to fill in by kernel driver.
                      sizeof (UINT16),  // Length of buffer in bytes.
                      &ReturnedLength,  // Bytes placed in In buffer.
                      NULL              // NULL means wait till op. completes.
                      );
        gReadPending = TRUE;
        return EFI_SUCCESS;
      }
    }
    break;

  case EfiCpuIoWidthUint32:
    //
    // If the NT32 Passthrough has forced a HostBridgeInit and if the request is from a device
    // on a given Bus/Device location.  Mask off the remaining functions
    //
    if (gHostBridgeInit) {
      if ((*(UINT32 *) Buffer.ui32 & 0xFFFFFF00) == *((UINT32 *) &gConfigData)) {
        Result = *Buffer.ui32;

        //
        // We found an access to our device
        //
        EFI_BREAKPOINT ();
        gWinNtThunk->DeviceIoControl (
                      gDeviceHandle,    // Handle to device
                      IOCTL_IO_WRITE,   // IO Control code to use
                      &Address,         // Address to communicate to driver
                      sizeof (UINT32),  // Length of buffer in bytes.
                      &Result,          // In Buffer to fill in by kernel driver.
                      sizeof (UINT32),  // Length of buffer in bytes.
                      &ReturnedLength,  // Bytes placed in In buffer.
                      NULL              // NULL means wait till op. completes.
                      );
        gReadPending = TRUE;
        return EFI_SUCCESS;
      }
    }
    break;

  default:
    return EFI_INVALID_PARAMETER;
  }

  return EFI_SUCCESS;
}

VOID
EFIAPI
CpuIoVirtualAddressChangeEvent (
  IN EFI_EVENT        Event,
  IN VOID             *Context
  )
/*++

Routine Description:
  Fixup Private data with new virtual addresses. All the member functions need
  to be converted to virtual mode.

Arguments:
  (Standard EFI Event - EFI_EVENT_NOTIFY)

Returns:

--*/
// TODO:    Context - add argument and description to function comment
{
}

EFI_STATUS
CpuIoCheckAddressRange (
  IN  EFI_CPU_IO_PROTOCOL_WIDTH         Width,
  IN  UINT64                            Address,
  IN  UINTN                             Count,
  IN  VOID                              *Buffer,
  IN  UINT64                            Limit
  )
/*++

Routine Description:

  TODO: Add function description

Arguments:

  Width   - TODO: add argument description
  Address - TODO: add argument description
  Count   - TODO: add argument description
  Buffer  - TODO: add argument description
  Limit   - TODO: add argument description

Returns:

  EFI_UNSUPPORTED - TODO: Add description for return value
  EFI_UNSUPPORTED - TODO: Add description for return value
  EFI_UNSUPPORTED - TODO: Add description for return value
  EFI_SUCCESS - TODO: Add description for return value

--*/
{
  UINTN AlignMask;

  if (Address > Limit) {
    return EFI_UNSUPPORTED;
  }

  //
  // For FiFo type, the target address won't increase during the access, so treat count as 1
  //
  if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) {
    Count = 1;
  }

  Width = Width & 0x03;
  if (Address - 1 + (1 << Width) * Count > Limit) {
    return EFI_UNSUPPORTED;
  }

  AlignMask = (1 << Width) - 1;
  if ((UINTN) Buffer & AlignMask) {
    return EFI_UNSUPPORTED;
  }

  return EFI_SUCCESS;
}

EFI_STATUS
EFIAPI
CpuIoInitialize (
  IN EFI_HANDLE                            ImageHandle,
  IN EFI_SYSTEM_TABLE                      *SystemTable
  )
/*++

Routine Description:

  Initialize the state information for the CPU I/O Protocol

Arguments:

  ImageHandle of the loaded driver
  Pointer to the System Table

Returns:

  Status

  EFI_SUCCESS           - Protocol successfully installed
  EFI_OUT_OF_RESOURCES  - cannot allocate protocol data structure

--*/
// TODO:    SystemTable - add argument and description to function comment
{
  EFI_STATUS          Status;
  UINTN               NumHandles;
  EFI_HANDLE          *HandleBuffer;
  UINTN               Index;
  EFI_CPU_IO_PROTOCOL *OldCpuIoProtocol;

  //
  // Initialize the library
  //
  DxeInitializeDriverLib (ImageHandle, SystemTable);

  mCpuIoProtocol.Mem.Read   = CpuMemoryServiceRead;
  mCpuIoProtocol.Mem.Write  = CpuMemoryServiceWrite;
  mCpuIoProtocol.Io.Read    = CpuIoServiceRead;
  mCpuIoProtocol.Io.Write   = CpuIoServiceWrite;

  Status = gBS->LocateHandleBuffer (
                  ByProtocol,
                  &gEfiCpuIoProtocolGuid,
                  NULL,
                  &NumHandles,
                  &HandleBuffer
                  );

  if (Status == EFI_SUCCESS) {
    for (Index = 0; Index < NumHandles; Index++) {
      Status = gBS->HandleProtocol (
                      HandleBuffer[Index],
                      &gEfiCpuIoProtocolGuid,
                      (VOID **) &OldCpuIoProtocol
                      );
      if (Status == EFI_SUCCESS) {
        gBS->ReinstallProtocolInterface (
              HandleBuffer[Index],
              &gEfiCpuIoProtocolGuid,
              OldCpuIoProtocol,
              &mCpuIoProtocol
              );
      }
    }
  }

  ASSERT_EFI_ERROR (Status);
  return Status;
}

⌨️ 快捷键说明

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