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 + -
显示快捷键?