misc.c

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

C
724
字号
  SimpleNetworkDevice->NII.ImageSize = RomLength;
  SimpleNetworkDevice->NII.MajorVer  = RomIdTableAddress->UNDI_Rev[2];
  SimpleNetworkDevice->NII.MinorVer  = RomIdTableAddress->UNDI_Rev[1];

  DEBUG ((EFI_D_NET,"Allocate area for the UNDI_Loader_t structure\n\r"));
  //
  // Allocate 1 page below 1MB to put real mode thunk code in
  //

  // Undi Loader Table is a PXE Specification prescribed data structure
  // that is used to transfer information into and out of the Undi layer.
  // Note how it must be located below 1 MB.
  SimpleNetworkDevice->UndiLoaderTablePages = EFI_SIZE_TO_PAGES (PARAGRAPH_SIZE + sizeof(UNDI_Loader_t));
  Status = BiosSnp16AllocatePagesBelowOneMb (
             SimpleNetworkDevice->UndiLoaderTablePages,
             &SimpleNetworkDevice->UndiLoaderTable
             );
  if (EFI_ERROR (Status)) {
    DEBUG ((EFI_D_ERROR,"We had a failure in AllocatePages, status code = 0x%X\n", Status));
  }

  UndiLoaderTable = SimpleNetworkDevice->UndiLoaderTable;

  DEBUG ((EFI_D_NET,"Allocate area for the real-mode stack whose sole purpose\n\r"));
  DEBUG ((EFI_D_NET,"in life right now is to store a SEG:OFFSET combo pair that\n\r"));
  DEBUG ((EFI_D_NET,"points to an Undi_Loader_t table structure\n\r"));

  Size = 0x100;
  gBS->AllocatePool(EfiLoaderData, Size, &Buffer);

  // Now we want to put a pointer to the Under Loader Table in our MemPage
  // Buffer.  This will be the argument stack for the call into the Undi Loader

  StackPointer    = (UINT16*)Buffer;
  *StackPointer++ = TO_OFFSET(UndiLoaderTable);   // push the OFFSET 
  *StackPointer++ = TO_SEGMENT(UndiLoaderTable);  // push the SEGMENT
  StackPointer    = (UINT16*)Buffer;  // reset the stack pointer
  
  DEBUG ((EFI_D_NET,"After the fixups, the stack pointer is 0x%X\n\r",
      (UINT64) StackPointer));

  // Allocate memory for the Deployed UNDI.
  // The UNDI is essentially telling us how much space it needs, and
  // it is up to the EFI driver to allocate sufficient, boot-time
  // persistent resources for the call
  SimpleNetworkDevice->DestinationDataSegmentPages = EFI_SIZE_TO_PAGES(RomIdTableAddress->DataSize);
  Status = BiosSnp16AllocatePagesBelowOneMb (
             SimpleNetworkDevice->DestinationDataSegmentPages,
             &SimpleNetworkDevice->DestinationDataSegment
             );
  if (EFI_ERROR (Status) )  {
    DEBUG ((EFI_D_ERROR,"We had a failure in AllocatePages, status code = 0x%X\n", Status));
    return Status;
  }
  UndiLoaderTable->UNDI_DS = (UINT16)((UINTN)SimpleNetworkDevice->DestinationDataSegment >> 4);

  // Allocate memory for the Deployed UNDI stack
  // The UNDI is essentially telling us how much space it needs, and
  // it is up to the EFI driver to allocate sufficient, boot-time
  // persistent resources for the call
  SimpleNetworkDevice->DestinationStackSegmentPages = EFI_SIZE_TO_PAGES(RomIdTableAddress->StackSize);
  Status = BiosSnp16AllocatePagesBelowOneMb (
             SimpleNetworkDevice->DestinationStackSegmentPages,
             &SimpleNetworkDevice->DestinationStackSegment
             );
  if (EFI_ERROR (Status) )  {
    DEBUG ((EFI_D_ERROR,"We had a failure in AllocatePages, status code = 0x%X\n", Status));
    return Status;
  }

  // Allocate memory for the Deployed UNDI.
  // The UNDI is essentially telling us how much space it needs, and
  // it is up to the EFI driver to allocate sufficient, boot-time
  // persistent resources for the call
  SimpleNetworkDevice->DestinationCodeSegmentPages = EFI_SIZE_TO_PAGES (RomIdTableAddress->CodeSize);
  Status = BiosSnp16AllocatePagesBelowOneMb (
             SimpleNetworkDevice->DestinationCodeSegmentPages,
             &SimpleNetworkDevice->DestinationCodeSegment
             );
  if (EFI_ERROR (Status) )  {
    DEBUG ((EFI_D_ERROR,"We had a failure in AllocatePages, status code = 0x%X\n", Status));
    return Status;
  }
  UndiLoaderTable->UNDI_CS = (UINT16)((UINTN)SimpleNetworkDevice->DestinationCodeSegment >> 4);

  // these are in the Input and Output Parameter to be sent to the UNDI Loader code
  UndiLoaderTable->Status     = 0xAA55;   
  //-------------------- Changed by Michael_Huang@3Com.com ----------------- 
  //UndiLoaderTable->_AX is AX value when UNDI ROM is initialized by BIOS, it is the PCI bus device 
  //function of the NIC. Please refer to PXE Spec for detail info.
  //old code is:
  //UndiLoaderTable->_AX_       = 0x0;  
  //-----------------------------------------------------------------------

  SimpleNetworkDevice->PciIo->GetLocation (
                                SimpleNetworkDevice->PciIo,
                                &PciSegment,
                                &Bus,
                                &Device,
                                &Function
                                );
  UndiLoaderTable->_AX_       = (UINT16)((Bus << 0x8) | (Device << 0x3) | (Function));
  UndiLoaderTable->_BX_       = 0x0;  
  UndiLoaderTable->_DX_       = 0x0;  
  UndiLoaderTable->_DI_       = 0x0;  
  UndiLoaderTable->_ES_       = 0x0;      

  // set these OUT values to zero in order to ensure that 
  // uninitialized memory is not mistaken for display data
  UndiLoaderTable->PXEptr.offset      = 0;
  UndiLoaderTable->PXEptr.segment     = 0;
  UndiLoaderTable->PXENVptr.segment   = 0;  
  UndiLoaderTable->PXENVptr.offset    = 0;

  DEBUG ((EFI_D_INIT, "The NIC is located at Bus 0x%X, Device 0x%X, Function 0x%X\n\r",
          Bus,
          Device,
          Function));
   
  // These are the values that set up the ACTUAL IA32 machine state, whether in 
  // Real16 in EFI32 or the IVE for IA64
  // register values are unused except for CS:IP and SS:SP

  InOutRegs.x.AX = 0;
  InOutRegs.x.BX = 0;
  InOutRegs.x.CX = 0;
  InOutRegs.x.DX = 0;
  InOutRegs.x.SI = 0;
  InOutRegs.x.DI = 0;
  InOutRegs.x.BP = 0;
  InOutRegs.x.DS = 0;
  InOutRegs.x.ES = 0;     // just to be clean
  
  DEBUG ((EFI_D_NET,"The way this game works is that the SS:SP +4 should point\n\r"));
  DEBUG ((EFI_D_NET,"to the contents of the UndiLoaderTable\n\r"));
  DEBUG ((EFI_D_NET,"The Undi Loader Table is at address = 0x%X\n\r",
      (UINT32) UndiLoaderTable));
  DEBUG ((EFI_D_NET,"The segment and offsets are 0x%X and 0x%X, resp\n",
      TO_SEGMENT(UndiLoaderTable), 
      TO_OFFSET(UndiLoaderTable)
      ));

  DEBUG ((EFI_D_NET,"The Linear Address of the UNDI Loader entry is 0x%X\n",
      RomAddress+RomIdTableAddress->UNDI_Loader));

  DEBUG ((EFI_D_NET,"The Address offset of the UNDI Loader entry is 0x%X\n",
      RomIdTableAddress->UNDI_Loader));

  DEBUG ((EFI_D_NET,"Before the call, we have...\n\r"));
  Print_Undi_Loader_Table(UndiLoaderTable);
  
  Segment = ((UINT16) (DriverLibRShiftU64 (RomAddress, 4) & 0xFFFF)); 
  DEBUG ((EFI_D_NET,"The Segment of the call is 0x%X\n\r", Segment));

  // make the call into the UNDI Code
  DEBUG ((EFI_D_INIT,"Make the call into the UNDI code now\n\r"));

  DEBUG ((EFI_D_NET, "\nThe 20-BIt address of the Call, and the location \n\r"));
  DEBUG ((EFI_D_NET, "\twhere we should be able to set a breakpoint is \n\r"));
  DEBUG ((EFI_D_NET, "\t\t0x%X, from SEG:OFF 0x%X:0x%X\n\r\n\r",
    Segment * 0x10 + RomIdTableAddress->UNDI_Loader,
    Segment,
    RomIdTableAddress->UNDI_Loader));

  Status = FarCall86 (            
             Segment,                                        // Input segment 
             (UINT16) RomIdTableAddress->UNDI_Loader,        // Offset        
             &InOutRegs,                                     // Ptr to Regs
             Buffer,                                         // Reference to Stack
             Size                                            // Size of the Stack
             );

  DEBUG ((EFI_D_NET, "The return code UndiLoaderTable->Status is = 0x%X\n\r",
    UndiLoaderTable->Status));
  DEBUG ((EFI_D_NET, "This error code should match eax, which is = 0x%X\n\r",
    InOutRegs.x.AX));

  DEBUG ((EFI_D_NET,"Now returned from the UNDI code\n\r"));

  DEBUG ((EFI_D_NET,"After the call, we have...\n\r"));
  Print_Undi_Loader_Table(UndiLoaderTable);

  DEBUG ((EFI_D_NET,"Display the PXENV+ and !PXE tables exported by NIC\n\r"));
  Print_PXENV_Table ((VOID*)((UndiLoaderTable->PXENVptr.segment << 4 )
                      | UndiLoaderTable->PXENVptr.offset));
  Print_PXE_Table   ((VOID*)((UndiLoaderTable->PXEptr.segment << 4) 
                      + UndiLoaderTable->PXEptr.offset ));

  SimpleNetworkDevice->NII.ID = (UINT64)(pPxe  = (PXE_t *)((UndiLoaderTable->PXEptr.segment << 4) + UndiLoaderTable->PXEptr.offset ));

//  gBS->FreePool (Buffer);

  // paranoia - make sure a valid !PXE structure
  if (EfiCompareMem(pPxe->Signature, PXE_SIG, sizeof pPxe->Signature)) {
    DEBUG ((EFI_D_ERROR,"!PXE Structure not found....\n\r"));
    return EFI_NOT_FOUND;       // its not - keep looking
  }

  if (CheckSum((UINT8 *)pPxe, pPxe->StructLength)) {
    DEBUG ((EFI_D_ERROR,"!PXE Checksum Error\n\r"));
    return EFI_NOT_FOUND;
  }

  if (pPxe->StructLength < (UINT8 *)&pPxe->FirstSelector - (UINT8 *)pPxe->Signature) {
    DEBUG ((EFI_D_ERROR,"!PXE Length Error\n\r"));
    return EFI_NOT_FOUND;
  }

  if ((((UINTN)pPxe->UNDI.segment) << 4) + pPxe->UNDI.offset != (UINTN)RomIdTableAddress) {
    DEBUG ((EFI_D_ERROR,"!PXE RomId Address Error\n\r"));
    return EFI_NOT_FOUND;
  }

  // This is the magic to bind the global PXE interface
  // This dirtiness is for non-protocol shrouded access

  SimpleNetworkDevice->PxeEntrySegment = pPxe->EntryPointSP.segment;

  if (!SimpleNetworkDevice->PxeEntrySegment) {
    DEBUG ((EFI_D_ERROR,"!PXE EntryPointSP segment Error\n\r"));
    return EFI_NOT_FOUND;
  }

  SimpleNetworkDevice->PxeEntryOffset  = pPxe->EntryPointSP.offset;

  DEBUG ((EFI_D_NET, "The entry point is 0x%X:0x%X\n\r", SimpleNetworkDevice->PxeEntrySegment,SimpleNetworkDevice->PxeEntryOffset));

  return EFI_SUCCESS;
}

EFI_STATUS
MakePxeCall (
	EFI_SIMPLE_NETWORK_DEV  *SimpleNetworkDevice,
  IN OUT VOID             *pTable,
  IN UINTN                TableSize,
  IN UINT16               CallIndex
  )
/*++
  MakePxeCall

  Effect the Far Call into the PXE Layer

  Note: When using a 32-bit stack segment do not push 32-bit words onto the stack. The PXE API
  services will not work, unless there are three 16-bit parameters pushed onto the stack.
      push DS                                 ;Far pointer to parameter structure
      push offset pxe_data_call_struct        ;is pushed onto stack.
      push Index                              ;UINT16 is pushed onto stack.
      call dword ptr (s_PXE ptr es:[di]).EntryPointSP
      add sp, 6 ;Caller cleans up stack.
--*/
{
  EFI_STATUS          Status;
  IA32_RegisterSet_t  InOutRegs;
  UINT16              *BPtr;
  VOID                *Buffer;
  UINTN               Size;
  VOID                *MemPageAddress;
  UINTN               Index;

  DEBUG((EFI_D_NET,"MakePxeCall(CallIndex = %02x, pTable = %X, TableSize = %d)\n",CallIndex,pTable,TableSize)); 

  if (SimpleNetworkDevice->PxeEntrySegment == 0 && SimpleNetworkDevice->PxeEntryOffset == 0) {
    return EFI_DEVICE_ERROR;
  }
  
  Status = EFI_SUCCESS;

  // Allocate a transient data structure for the argument table
  // This table needs to have the input XXX_t structure copied into here.
  // The PXE UNDI can only grab this table when it's below one-MB, and
  // this implementation will not try to push this table on the stack
  // (although this is a possible optimization path since EFI always allocates
  // 4K as a minimum page size...............)

  Status = BiosSnp16AllocatePagesBelowOneMb (
             TableSize / EFI_PAGE_SIZE + 1,
             &MemPageAddress
             );
  if (EFI_ERROR (Status) )  {
    DEBUG ((EFI_D_ERROR,"We had a failure in AllocatePages, status code = 0x%X\n", Status));
    return Status;
  }

  //
  // Copy the > 1MB pool table to a sub-1MB buffer
  //
  EfiCopyMem (MemPageAddress, pTable, TableSize);

  //
  // Allocate space for IA-32 register context
  //
  EfiZeroMem (&InOutRegs, sizeof (InOutRegs));
  InOutRegs.x.ES = SimpleNetworkDevice->PxeEntrySegment;
  InOutRegs.x.DI = SimpleNetworkDevice->PxeEntryOffset;

  // The game here is to build the stack which will subsequently
  // get copied down below 1 MB by the FarCall primitive.  
  // This is now our working stack
  Size = 6;
  Status = gBS->AllocatePool(
                  EfiRuntimeServicesData,
                  Size,
                  &Buffer
                  );
  
  BPtr = (UINT16*) Buffer;
  *BPtr ++ = CallIndex;       // SP + 2
  *BPtr ++ = TO_OFFSET  (MemPageAddress);
  *BPtr ++ = TO_SEGMENT (MemPageAddress);

  DEBUG((EFI_D_NET,"State before FarCall86\n"));
  DEBUG((EFI_D_NET,"The Buffer is at 0x%X\n\r", Buffer));
  BPtr = (UINT16*) Buffer;
  DEBUG((EFI_D_NET,"  Buffer  = %04X %04X %04X",*BPtr,*(BPtr+1),*(BPtr+2)));
  DEBUG((EFI_D_NET,"  MemPage = "));
  for(Index=0;Index<TableSize;Index++) {
    DEBUG((EFI_D_NET," %02x",*((UINT8 *)MemPageAddress + Index)));
  }
  DEBUG((EFI_D_NET,"\n"));

  Status = FarCall86 (            
             SimpleNetworkDevice->PxeEntrySegment,  // Input segment 
             SimpleNetworkDevice->PxeEntryOffset,
             &InOutRegs,                            // Ptr to Regs
             Buffer,                                // Reference to Stack
             6                                      // Size of the Stack
             );

  DEBUG((EFI_D_NET,"State after FarCall86\n"));
  DEBUG((EFI_D_NET,"The Buffer is at 0x%X\n\r", Buffer));
  BPtr = (UINT16*) Buffer;
  DEBUG((EFI_D_NET,"  Buffer  = %04X %04X %04X",*BPtr,*(BPtr+1),*(BPtr+2)));
  DEBUG((EFI_D_NET,"  MemPage = "));
  for(Index=0;Index<TableSize;Index++) {
    DEBUG((EFI_D_NET," %02x",*((UINT8 *)MemPageAddress + Index)));
  }
  DEBUG((EFI_D_NET,"\n"));

  //
  // Copy the sub 1MB table to > 1MB table
  //
  EfiCopyMem (pTable, MemPageAddress, TableSize);

  //
  // For PXE UNDI call, AX contains the return status.
  // Convert the PXE UNDI Status to EFI_STATUS type
  //
  if (InOutRegs.x.AX == PXENV_EXIT_SUCCESS) {
    Status = EFI_SUCCESS;
  } else {
    Status = EFI_DEVICE_ERROR;
  }

  //
  // Clean up house
  //
  gBS->FreePool (Buffer);
  gBS->FreePages ((EFI_PHYSICAL_ADDRESS)MemPageAddress, TableSize / EFI_PAGE_SIZE + 1);

  return Status;
}

⌨️ 快捷键说明

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