decode.c

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

C
1,665
字号
/*++

Copyright (c) 2004, 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:
    decode.c

Abstract:

Revision history:

--*/

// TODO: fix comment to add: Module Name: DECODE.C
#include "undi32.h"

#if UNDI_DEBUG
extern VOID (*break_pt) ();
#endif

#pragma data_seg("rtdata")

//
// Global variables defined outside this file
//
extern PXE_SW_UNDI  *pxe    = 0;  // !pxe structure
extern PXE_SW_UNDI  *pxe_31 = 0;  // !pxe structure for 3.1 drivers
extern UNDI32_DEV   *UNDI32DeviceList[MAX_NIC_INTERFACES];

//
// Global variables defined in this file
//
UNDI_CALL_TABLE api_table[PXE_OPCODE_LAST_VALID+1] = { \
  {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,0, (UINT16)(ANY_STATE),UNDI_GetState },\
  {(UINT16)(DONT_CHECK),PXE_DBSIZE_NOT_USED,0,(UINT16)(ANY_STATE),UNDI_Start },\
  {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,0,MUST_BE_STARTED,UNDI_Stop },\
  {PXE_CPBSIZE_NOT_USED,sizeof(PXE_DB_GET_INIT_INFO),0,MUST_BE_STARTED, UNDI_GetInitInfo },\
  {PXE_CPBSIZE_NOT_USED,sizeof(PXE_DB_GET_CONFIG_INFO),0,MUST_BE_STARTED, UNDI_GetConfigInfo },\
  {sizeof(PXE_CPB_INITIALIZE),(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK),MUST_BE_STARTED,UNDI_Initialize },\
  {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED,UNDI_Reset },\
  {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,0, MUST_BE_INITIALIZED,UNDI_Shutdown },\
  {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED,UNDI_Interrupt },\
  {(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_RecFilter },\
  {(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_StnAddr },\
  {PXE_CPBSIZE_NOT_USED, (UINT16)(DONT_CHECK), (UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_Statistics },\
  {sizeof(PXE_CPB_MCAST_IP_TO_MAC),sizeof(PXE_DB_MCAST_IP_TO_MAC), (UINT16)(DONT_CHECK),MUST_BE_INITIALIZED, UNDI_ip2mac },\
  {(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_NVData },\
  {PXE_CPBSIZE_NOT_USED,(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_Status },\
  {(UINT16)(DONT_CHECK),PXE_DBSIZE_NOT_USED,(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_FillHeader },\
  {(UINT16)(DONT_CHECK),PXE_DBSIZE_NOT_USED,(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_Transmit },\
  {sizeof(PXE_CPB_RECEIVE),sizeof(PXE_DB_RECEIVE),0,MUST_BE_INITIALIZED, UNDI_Receive } \
};

//
// end of global variables
//

VOID
UNDI_GetState (
  IN  PXE_CDB           *CdbPtr,
  IN  NIC_DATA_INSTANCE *AdapterInfo
  )
/*++

Routine Description:
  This routine determines the operational state of the UNDI.  It updates the state flags in the
  Command Descriptor Block based on information derived from the AdapterInfo instance data.

  To ensure the command has completed successfully, CdbPtr->StatCode will contain the result of
  the command execution.

  The CdbPtr->StatFlags will contain a STOPPED, STARTED, or INITIALIZED state once the command
  has successfully completed.

  Keep in mind the AdapterInfo->State is the active state of the adapter (based on software
  interrogation), and the CdbPtr->StateFlags is the passed back information that is reflected
  to the caller of the UNDI API.

Arguments:
  CdbPtr            - Pointer to the command descriptor block.
  AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..

Returns:
  None

--*/
{
  CdbPtr->StatFlags |= AdapterInfo->State;
  return ;
}

VOID
UNDI_Start (
  IN  PXE_CDB           *CdbPtr,
  IN  NIC_DATA_INSTANCE *AdapterInfo
  )
/*++

Routine Description:
  This routine is used to change the operational state of the UNDI from stopped to started.
  It will do this as long as the adapter's state is PXE_STATFLAGS_GET_STATE_STOPPED, otherwise
  the CdbPtr->StatFlags will reflect a command failure, and the CdbPtr->StatCode will reflect the
  UNDI as having already been started.

  This routine is modified to reflect the undi 1.1 specification changes. The
  changes in the spec are mainly in the callback routines, the new spec adds
  3 more callbacks and a unique id.
  Since this UNDI supports both old and new undi specifications,
  The NIC's data structure is filled in with the callback routines (depending
  on the version) pointed to in the caller's CpbPtr.  This seeds the Delay,
  Virt2Phys, Block, and Mem_IO for old and new versions and Map_Mem, UnMap_Mem
  and Sync_Mem routines and a unique id variable for the new version.
  This is the function which an external entity (SNP, O/S, etc) would call
  to provide it's I/O abstraction to the UNDI.

  It's final action is to change the AdapterInfo->State to PXE_STATFLAGS_GET_STATE_STARTED.

Arguments:
  CdbPtr            - Pointer to the command descriptor block.
  AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..

Returns:
  None

--*/
{
  PXE_CPB_START     *CpbPtr;
  PXE_CPB_START_31  *CpbPtr_31;

  //
  // check if it is already started.
  //
  if (AdapterInfo->State != PXE_STATFLAGS_GET_STATE_STOPPED) {
    CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
    CdbPtr->StatCode  = PXE_STATCODE_ALREADY_STARTED;
    return ;
  }

  if (CdbPtr->CPBsize != sizeof(PXE_CPB_START) &&
      CdbPtr->CPBsize != sizeof(PXE_CPB_START_31)) {

    CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
    CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;
    return ;
  }

  CpbPtr    = (PXE_CPB_START *) (UINTN) (CdbPtr->CPBaddr);
  CpbPtr_31 = (PXE_CPB_START_31 *) (UINTN) (CdbPtr->CPBaddr);

  if (AdapterInfo->VersionFlag == 0x30) {
    AdapterInfo->Delay_30     = (bsptr_30) (UINTN) CpbPtr->Delay;
    AdapterInfo->Virt2Phys_30 = (virtphys_30) (UINTN) CpbPtr->Virt2Phys;
    AdapterInfo->Block_30     = (block_30) (UINTN) CpbPtr->Block;
    //
    // patch for old buggy 3.0 code:
    // In EFI1.0 undi used to provide the full (absolute) I/O address to the
    // i/o calls and SNP used to provide a callback that used GlobalIoFncs and
    // everything worked fine! In EFI 1.1, UNDI is not using the full
    // i/o or memory address to access the device, The base values for the i/o
    // and memory address is abstracted by the device specific PciIoFncs and
    // UNDI only uses the offset values. Since UNDI3.0 cannot provide any
    // identification to SNP, SNP cannot use nic specific PciIoFncs callback!
    //
    // To fix this and make undi3.0 work with SNP in EFI1.1 we
    // use a TmpMemIo function that is defined in init.c
    // This breaks the runtime driver feature of undi, but what to do
    // if we have to provide the 3.0 compatibility (including the 3.0 bugs)
    //
    // This TmpMemIo function also takes a UniqueId parameter
    // (as in undi3.1 design) and so initialize the UniqueId as well here
    // Note: AdapterInfo->Mem_Io_30 is just filled for consistency with other
    // parameters but never used, we only use Mem_Io field in the In/Out routines
    // inside e100b.c.
    //
    AdapterInfo->Mem_Io_30  = (mem_io_30) (UINTN) CpbPtr->Mem_IO;
    AdapterInfo->Mem_Io     = (mem_io) (UINTN) TmpMemIo;
    AdapterInfo->Unique_ID  = (UINT64) AdapterInfo;

  } else {
    AdapterInfo->Delay      = (bsptr) (UINTN) CpbPtr_31->Delay;
    AdapterInfo->Virt2Phys  = (virtphys) (UINTN) CpbPtr_31->Virt2Phys;
    AdapterInfo->Block      = (block) (UINTN) CpbPtr_31->Block;
    AdapterInfo->Mem_Io     = (mem_io) (UINTN) CpbPtr_31->Mem_IO;

    AdapterInfo->Map_Mem    = (map_mem) (UINTN) CpbPtr_31->Map_Mem;
    AdapterInfo->UnMap_Mem  = (unmap_mem) (UINTN) CpbPtr_31->UnMap_Mem;
    AdapterInfo->Sync_Mem   = (sync_mem) (UINTN) CpbPtr_31->Sync_Mem;
    AdapterInfo->Unique_ID  = CpbPtr_31->Unique_ID;
  }

  AdapterInfo->State = PXE_STATFLAGS_GET_STATE_STARTED;

  return ;
}

VOID
UNDI_Stop (
  IN  PXE_CDB           *CdbPtr,
  IN  NIC_DATA_INSTANCE *AdapterInfo
  )
/*++

Routine Description:
  This routine is used to change the operational state of the UNDI from started to stopped.
  It will not do this if the adapter's state is PXE_STATFLAGS_GET_STATE_INITIALIZED, otherwise
  the CdbPtr->StatFlags will reflect a command failure, and the CdbPtr->StatCode will reflect the
  UNDI as having already not been shut down.

  The NIC's data structure will have the Delay, Virt2Phys, and Block, pointers zero'd out..

  It's final action is to change the AdapterInfo->State to PXE_STATFLAGS_GET_STATE_STOPPED.

Arguments:
  CdbPtr            - Pointer to the command descriptor block.
  AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..

Returns:
  None

--*/
{
  if (AdapterInfo->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
    CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
    CdbPtr->StatCode  = PXE_STATCODE_NOT_SHUTDOWN;
    return ;
  }

  AdapterInfo->Delay_30     = 0;
  AdapterInfo->Virt2Phys_30 = 0;
  AdapterInfo->Block_30     = 0;

  AdapterInfo->Delay        = 0;
  AdapterInfo->Virt2Phys    = 0;
  AdapterInfo->Block        = 0;

  AdapterInfo->Map_Mem      = 0;
  AdapterInfo->UnMap_Mem    = 0;
  AdapterInfo->Sync_Mem     = 0;

  AdapterInfo->State        = PXE_STATFLAGS_GET_STATE_STOPPED;

  return ;
}

VOID
UNDI_GetInitInfo (
  IN  PXE_CDB           *CdbPtr,
  IN  NIC_DATA_INSTANCE *AdapterInfo
  )
/*++

Routine Description:
  This routine is used to retrieve the initialization information that is needed by drivers and
  applications to initialize the UNDI.  This will fill in data in the Data Block structure that is
  pointed to by the caller's CdbPtr->DBaddr.  The fields filled in are as follows:

  MemoryRequired, FrameDataLen, LinkSpeeds[0-3], NvCount, NvWidth, MediaHeaderLen, HWaddrLen,
  MCastFilterCnt, TxBufCnt, TxBufSize, RxBufCnt, RxBufSize, IFtype, Duplex, and LoopBack.

  In addition, the CdbPtr->StatFlags ORs in that this NIC supports cable detection.  (APRIORI knowledge)

Arguments:
  CdbPtr            - Pointer to the command descriptor block.
  AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..

Returns:
  None

--*/
{
  PXE_DB_GET_INIT_INFO  *DbPtr;

  DbPtr = (PXE_DB_GET_INIT_INFO *) (UINTN) (CdbPtr->DBaddr);

  DbPtr->MemoryRequired = MEMORY_NEEDED;
  DbPtr->FrameDataLen = PXE_MAX_TXRX_UNIT_ETHER;
  DbPtr->LinkSpeeds[0] = 10;
  DbPtr->LinkSpeeds[1] = 100;
  DbPtr->LinkSpeeds[2] = DbPtr->LinkSpeeds[3] = 0;
  DbPtr->NvCount = MAX_EEPROM_LEN;
  DbPtr->NvWidth = 4;
  DbPtr->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;
  DbPtr->HWaddrLen = PXE_HWADDR_LEN_ETHER;
  DbPtr->MCastFilterCnt = MAX_MCAST_ADDRESS_CNT;

  DbPtr->TxBufCnt = TX_BUFFER_COUNT;
  DbPtr->TxBufSize = sizeof (TxCB);
  DbPtr->RxBufCnt = RX_BUFFER_COUNT;
  DbPtr->RxBufSize = sizeof (RxFD);

  DbPtr->IFtype = PXE_IFTYPE_ETHERNET;
  DbPtr->Duplex = PXE_DUPLEX_ENABLE_FULL_SUPPORTED |
                  PXE_DUPLEX_FORCE_FULL_SUPPORTED;
  DbPtr->LoopBack = PXE_LOOPBACK_INTERNAL_SUPPORTED |
                    PXE_LOOPBACK_EXTERNAL_SUPPORTED;

  CdbPtr->StatFlags |= PXE_STATFLAGS_CABLE_DETECT_SUPPORTED;
  return ;
}

VOID
UNDI_GetConfigInfo (
  IN  PXE_CDB           *CdbPtr,
  IN  NIC_DATA_INSTANCE *AdapterInfo
  )
/*++

Routine Description:
  This routine is used to retrieve the configuration information about the NIC being controlled by
  this driver.  This will fill in data in the Data Block structure that is pointed to by the caller's CdbPtr->DBaddr.
  The fields filled in are as follows:

  DbPtr->pci.BusType, DbPtr->pci.Bus, DbPtr->pci.Device, and DbPtr->pci.

  In addition, the DbPtr->pci.Config.Dword[0-63] grabs a copy of this NIC's PCI configuration space.

Arguments:
  CdbPtr            - Pointer to the command descriptor block.
  AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..

Returns:
  None

--*/
{
  UINT16                  Index;
  PXE_DB_GET_CONFIG_INFO  *DbPtr;

  DbPtr               = (PXE_DB_GET_CONFIG_INFO *) (UINTN) (CdbPtr->DBaddr);

  DbPtr->pci.BusType  = PXE_BUSTYPE_PCI;
  DbPtr->pci.Bus      = AdapterInfo->Bus;
  DbPtr->pci.Device   = AdapterInfo->Device;
  DbPtr->pci.Function = AdapterInfo->Function;

  for (Index = 0; Index < MAX_PCI_CONFIG_LEN; Index++) {
    DbPtr->pci.Config.Dword[Index] = AdapterInfo->Config[Index];
  }

  return ;
}

VOID
UNDI_Initialize (
  IN  PXE_CDB       *CdbPtr,
  NIC_DATA_INSTANCE *AdapterInfo
  )
/*++

Routine Description:
  This routine resets the network adapter and initializes the UNDI using the parameters supplied in
  the CPB.  This command must be issued before the network adapter can be setup to transmit and
  receive packets.

  Once the memory requirements of the UNDI are obtained by using the GetInitInfo command, a block
  of non-swappable memory may need to be allocated.  The address of this memory must be passed to
  UNDI during the Initialize in the CPB.  This memory is used primarily for transmit and receive buffers.

  The fields CableDetect, LinkSpeed, Duplex, LoopBack, MemoryPtr, and MemoryLength are set with information
  that was passed in the CPB and the NIC is initialized.

  If the NIC initialization fails, the CdbPtr->StatFlags are updated with PXE_STATFLAGS_COMMAND_FAILED
  Otherwise, AdapterInfo->State is updated with PXE_STATFLAGS_GET_STATE_INITIALIZED showing the state of
  the UNDI is now initialized.

Arguments:
  CdbPtr            - Pointer to the command descriptor block.
  AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..

Returns:
  None

--*/
{
  PXE_CPB_INITIALIZE  *CpbPtr;
  PXE_DB_INITIALIZE   *DbPtr;

  if ((CdbPtr->OpFlags != PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) &&
      (CdbPtr->OpFlags != PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE)) {
    CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
    CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;
    return ;
  }

  //
  // check if it is already initialized
  //
  if (AdapterInfo->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {
    CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
    CdbPtr->StatCode  = PXE_STATCODE_ALREADY_INITIALIZED;
    return ;
  }

  CpbPtr  = (PXE_CPB_INITIALIZE *) (UINTN) CdbPtr->CPBaddr;
  DbPtr   = (PXE_DB_INITIALIZE *) (UINTN) CdbPtr->DBaddr;

  if (CpbPtr->MemoryLength < (UINT32) MEMORY_NEEDED) {
    CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
    CdbPtr->StatCode  = PXE_STATCODE_INVALID_CPB;
    return ;
  }

  //
  // default behaviour is to detect the cable, if the 3rd param is 1,
  // do not do that
  //
  AdapterInfo->CableDetect = (UINT8) ((CdbPtr->OpFlags == (UINT16) PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE) ? (UINT8) 0 : (UINT8) 1);
  AdapterInfo->LinkSpeedReq = (UINT16) CpbPtr->LinkSpeed;
  AdapterInfo->DuplexReq    = CpbPtr->Duplex;
  AdapterInfo->LoopBack     = CpbPtr->LoopBack;

⌨️ 快捷键说明

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