2 Helper Routines that use a PXE-enabled NIC option ROM.
4 Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "BiosSnp16.h"
12 #define TO_SEGMENT(x) ((UINT16) (RShiftU64 ((UINT32)(UINTN) (x), 4) & 0xF000))
13 #define TO_OFFSET(x) ((UINT16) ((UINT32)(UINTN) (x) & 0xFFFF))
14 #define PARAGRAPH_SIZE 0x10
15 #define IVT_BASE 0x00000000
19 UINT16 Signature
; ///< 0xaa55
20 UINT8 ROMlength
; ///< size of this ROM in 512 byte blocks
21 UINT8 InitEntryPoint
[4]; ///< a jump to the initialization routine
22 UINT8 Reserved
[0xf]; ///< various
23 UINT16 PxeRomIdOffset
; ///< offset of UNDI, $BC$, or BUSD ROM ID structure
24 UINT16 PcirHeaderOffset
; ///< offset of PCI Expansion Header
25 UINT16 PnpHeaderOffset
; ///< offset of Plug and Play Expansion Header
29 UINT32 CachedVectorAddress
[0x100];
32 Cache Interrupt verctor address converted from IVT number.
34 @param VectorNumber IVT number
36 @retval EFI_SUCCESS Success to operation.
45 Address
= (UINT32
*) ((UINTN
) IVT_BASE
+ VectorNumber
* 4);
46 CachedVectorAddress
[VectorNumber
] = *Address
;
51 Get interrupt vector address according to IVT number.
53 @param VectorNumber Given IVT number
55 @return cached interrupt vector address.
58 RestoreCachedVectorAddress (
64 Address
= (UINT32
*) ((UINTN
) IVT_BASE
+ VectorNumber
* 4);
65 *Address
= CachedVectorAddress
[VectorNumber
];
70 Print Undi loader table.
72 @param UndiLoaderStructure Point to Undi Loader table structure.
76 Print_Undi_Loader_Table (
77 VOID
*UndiLoaderStructure
80 UNDI_LOADER_T
*DisplayPointer
;
82 DisplayPointer
= (UNDI_LOADER_T
*) UndiLoaderStructure
;
84 DEBUG ((DEBUG_NET
, "Before Parsing the table contents, the table itself lives\n"));
85 DEBUG ((DEBUG_NET
, "\tat the address 0x%X\n\r", (UINT32
)(UINTN
) UndiLoaderStructure
));
87 DEBUG ((DEBUG_NET
, "\n\rStatus = 0x%X\n\r", DisplayPointer
->Status
));
88 DEBUG ((DEBUG_NET
, "\t_AX_= 0x%X\n\r", DisplayPointer
->Ax
));
89 DEBUG ((DEBUG_NET
, "\t_BX_= 0x%X\n\r", DisplayPointer
->Bx
));
90 DEBUG ((DEBUG_NET
, "\t_DX_= 0x%X\n\r", DisplayPointer
->Dx
));
91 DEBUG ((DEBUG_NET
, "\t_DI_= 0x%X\n\r", DisplayPointer
->Di
));
92 DEBUG ((DEBUG_NET
, "\t_ES_= 0x%X\n\r", DisplayPointer
->Es
));
93 DEBUG ((DEBUG_NET
, "\tUNDI_DS= 0x%X\n\r", DisplayPointer
->Undi_Ds
));
94 DEBUG ((DEBUG_NET
, "\tUNDI_CS= 0x%X\n\r", DisplayPointer
->Undi_Cs
));
95 DEBUG ((DEBUG_NET
, "\tPXEptr:SEG= 0x%X\n\r", (UINT16
) DisplayPointer
->PXEptr
.Segment
));
96 DEBUG ((DEBUG_NET
, "\tPXEptr:OFF= 0x%X\n\r", (UINT16
) DisplayPointer
->PXEptr
.Offset
));
97 DEBUG ((DEBUG_NET
, "\tPXENVptr:SEG= 0x%X\n\r", (UINT16
) DisplayPointer
->PXENVptr
.Segment
));
98 DEBUG ((DEBUG_NET
, "\tPXENVptr:OFF= 0x%X\n\r", (UINT16
) DisplayPointer
->PXENVptr
.Offset
));
102 Simple table dumper. The ROMID table is necessary in order to effect
103 the "Early UNDI" trick. Herein, the UNDI layer can be loaded in the
104 pre-boot phase without having to download a Network Boot Program
105 across the wire. It is required in the implementation in that we
108 @param RomIDStructure Point to RomID structure.
113 IN VOID
*RomIDStructure
116 UNDI_ROMID_T
*DisplayPointer
;
118 DisplayPointer
= (UNDI_ROMID_T
*) RomIDStructure
;
120 DEBUG ((DEBUG_NET
, "Before Parsing the table contents, the table itself lives\n"));
121 DEBUG ((DEBUG_NET
, "\tat the address 0x%X\n\r", (UINT32
)(UINTN
) RomIDStructure
));
125 "\n\rROMID %c%c%c%c\n\r",
126 DisplayPointer
->Signature
[0],
127 DisplayPointer
->Signature
[1],
128 DisplayPointer
->Signature
[2],
129 DisplayPointer
->Signature
[3])
134 "Length of this structure in bytes = 0x%X\n\r",
135 DisplayPointer
->StructLength
)
139 "Use to make byte checksum of this structure == zero is = 0x%X\n\r",
140 DisplayPointer
->StructCksum
)
144 "Structure format revision number= 0x%X\n\r",
145 DisplayPointer
->StructRev
)
149 "API Revision number = 0x%X 0x%X 0x%X\n\r",
150 DisplayPointer
->UNDI_Rev
[0],
151 DisplayPointer
->UNDI_Rev
[1],
152 DisplayPointer
->UNDI_Rev
[2])
156 "Offset of UNDI loader routine in the option ROM image= 0x%X\n\r",
157 DisplayPointer
->UNDI_Loader
)
159 DEBUG ((DEBUG_NET
, "From the data above, the absolute entry point of the UNDI loader is\n\r"));
162 "\tat address 0x%X\n\r",
163 (UINT32
) (DisplayPointer
->UNDI_Loader
+ ((UINT32
) (UINTN
)(DisplayPointer
- 0x20) & 0xFFFF0)))
165 DEBUG ((DEBUG_NET
, "Minimum stack segment size, in bytes,\n\r"));
168 "needed to load and run the UNDI= 0x%X \n\r",
169 DisplayPointer
->StackSize
)
173 "UNDI runtime code and data = 0x%X\n\r",
174 DisplayPointer
->DataSize
)
178 "Segment size = 0x%X\n\r",
179 DisplayPointer
->CodeSize
)
183 "\n\rBus Type = %c%c%c%c\n\r",
184 DisplayPointer
->BusType
[0],
185 DisplayPointer
->BusType
[1],
186 DisplayPointer
->BusType
[2],
187 DisplayPointer
->BusType
[3])
194 @param PxeTable Point to PXE table structure
202 PXE_T
*DisplayPointer
;
206 DisplayPointer
= (PXE_T
*) PxeTable
;
207 Dptr
= (UINT8
*) PxeTable
;
209 DEBUG ((DEBUG_NET
, "This is the PXE table at address 0x%X\n\r", PxeTable
));
211 DEBUG ((DEBUG_NET
, "A dump of the 0x%X bytes is:\n\r", sizeof (PXE_T
)));
213 for (Index
= 0; Index
< sizeof (PXE_T
); Index
++) {
214 if ((Index
% 0x10) == 0) {
215 DEBUG ((DEBUG_NET
, "\t\n\r"));
218 DEBUG ((DEBUG_NET
, " 0x%X ", *Dptr
++));
221 DEBUG ((DEBUG_NET
, "\n\r"));
224 "\n\rPXE %c%c%c%c%c%c\n\r",
225 DisplayPointer
->Signature
[0],
226 DisplayPointer
->Signature
[1],
227 DisplayPointer
->Signature
[2],
228 DisplayPointer
->Signature
[3])
232 "Length of this structure in bytes = 0x%X\n\r",
233 DisplayPointer
->StructLength
)
237 "Use to make byte checksum of this structure == zero is = 0x%X\n\r",
238 DisplayPointer
->StructCksum
)
242 "Structure format revision number = 0x%X\n\r",
243 DisplayPointer
->StructRev
)
247 "Must be zero, is equal to 0x%X\n\r",
248 DisplayPointer
->Reserved1
)
252 "Far pointer to UNDI ROMID = 0x%X\n\r",
253 (UINT32
) (DisplayPointer
->Undi
.Segment
<< 0x4 | DisplayPointer
->Undi
.Offset
))
257 "Far pointer to base-code ROMID = 0x%X\n\r",
258 (UINT32
) ((DisplayPointer
->Base
.Segment
<< 0x04) | DisplayPointer
->Base
.Offset
))
260 DEBUG ((DEBUG_NET
, "16bit stack segment API entry point. This will be seg:off in \n\r"));
263 "real mode and sel:off in 16:16 protected mode = 0x%X:0x%X\n\r",
264 DisplayPointer
->EntryPointSP
.Segment
,
265 DisplayPointer
->EntryPointSP
.Offset
)
268 DEBUG ((DEBUG_NET
, "\n\tNOTE to the implementer\n\tThis is the entry to use for call-ins\n\r"));
270 DEBUG ((DEBUG_NET
, "32bit stack Segment API entry point. This will be sel:off. \n\r"));
273 "In real mode, sel == 0 = 0x%X:0x%X\n\r",
274 DisplayPointer
->EntryPointESP
.Segment
,
275 DisplayPointer
->EntryPointESP
.Offset
)
279 "Reserved2 value, must be zero, is equal to 0x%X\n\r",
280 DisplayPointer
->Reserved2
)
284 "Number of segment descriptors in this structur = 0x%X\n\r",
285 (UINT8
) DisplayPointer
->SegDescCnt
)
289 "First segment descriptor in GDT assigned to PXE = 0x%X\n\r",
290 (UINT16
) DisplayPointer
->FirstSelector
)
294 "The Stack is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
295 (UINT16
) DisplayPointer
->Stack
.Seg_Addr
,
296 (UINT32
) DisplayPointer
->Stack
.Phy_Addr
,
297 (UINT16
) DisplayPointer
->Stack
.Seg_Size
)
301 "The UNDIData is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
302 (UINT16
) DisplayPointer
->UNDIData
.Seg_Addr
,
303 (UINT32
) DisplayPointer
->UNDIData
.Phy_Addr
,
304 (UINT16
) DisplayPointer
->UNDIData
.Seg_Size
)
308 "The UNDICodeWrite is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
309 (UINT16
) DisplayPointer
->UNDICode
.Seg_Addr
,
310 (UINT32
) DisplayPointer
->UNDICode
.Phy_Addr
,
311 (UINT16
) DisplayPointer
->UNDICode
.Seg_Size
)
315 "The Stack is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
316 (UINT16
) DisplayPointer
->UNDICodeWrite
.Seg_Addr
,
317 (UINT32
) DisplayPointer
->UNDICodeWrite
.Phy_Addr
,
318 (UINT16
) DisplayPointer
->UNDICodeWrite
.Seg_Size
)
322 "The BC_Data is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
323 (UINT16
) DisplayPointer
->BC_Data
.Seg_Addr
,
324 (UINT32
) DisplayPointer
->BC_Data
.Phy_Addr
,
325 (UINT16
) DisplayPointer
->BC_Data
.Seg_Size
)
329 "The BC_Code is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
330 (UINT16
) DisplayPointer
->BC_Code
.Seg_Addr
,
331 (UINT32
) DisplayPointer
->BC_Code
.Phy_Addr
,
332 (UINT16
) DisplayPointer
->BC_Code
.Seg_Size
)
336 "The BC_CodeWrite is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
337 (UINT16
) DisplayPointer
->BC_CodeWrite
.Seg_Addr
,
338 (UINT32
) DisplayPointer
->BC_CodeWrite
.Phy_Addr
,
339 (UINT16
) DisplayPointer
->BC_CodeWrite
.Seg_Size
)
346 @param PxenvTable Point to PXENV
354 PXENV_T
*DisplayPointer
;
356 DisplayPointer
= (PXENV_T
*) PxenvTable
;
360 "\n\rPXENV+ %c%c%c%c%c%c\n\r",
361 DisplayPointer
->Signature
[0],
362 DisplayPointer
->Signature
[1],
363 DisplayPointer
->Signature
[2],
364 DisplayPointer
->Signature
[3],
365 DisplayPointer
->Signature
[4],
366 DisplayPointer
->Signature
[5])
371 "PXE version number. \n\r\tLSB is minor version. \n\r\tMSB is major version = 0x%X\n\r",
372 DisplayPointer
->Version
)
376 "Length of PXE-2.0 Entry Point structure in bytes = 0x%X\n\r",
377 DisplayPointer
->StructLength
)
379 DEBUG ((DEBUG_NET
, "Used to make structure checksum equal zero is now = 0x%X\n\r", DisplayPointer
->StructCksum
));
380 DEBUG ((DEBUG_NET
, "Real mode API entry point segment:Offset. = 0x%X\n\r", DisplayPointer
->RMEntry
));
381 DEBUG ((DEBUG_NET
, "Protected mode API entry point = 0x%X\n\r", DisplayPointer
->PMEntryOff
));
382 DEBUG ((DEBUG_NET
, " segment:Offset. This will always be zero. \n\r"));
383 DEBUG ((DEBUG_NET
, "Protected mode API calls = 0x%X\n\r", DisplayPointer
->PMEntrySeg
));
384 DEBUG ((DEBUG_NET
, "Real mode stack segment = 0x%X\n\r", DisplayPointer
->StackSeg
));
385 DEBUG ((DEBUG_NET
, "Stack segment size in bytes = 0x%X\n\r", DisplayPointer
->StackSize
));
386 DEBUG ((DEBUG_NET
, "Real mode base-code code segment = 0x%X\n\r", DisplayPointer
->BaseCodeSeg
));
387 DEBUG ((DEBUG_NET
, "Base-code code segment size = 0x%X\n\r", DisplayPointer
->BaseCodeSize
));
388 DEBUG ((DEBUG_NET
, "Real mode base-code data segment = 0x%X\n\r", DisplayPointer
->BaseDataSeg
));
389 DEBUG ((DEBUG_NET
, "Base-code data segment size = 0x%X\n\r", DisplayPointer
->BaseDataSize
));
393 "UNDI code segment size in bytes = 0x%X\n\r",
394 DisplayPointer
->UNDICodeSize
)
398 "Real mode segment:Offset pointer \n\r\tto PXE Runtime ID structure, address = 0x%X\n\r",
399 DisplayPointer
->RuntimePtr
)
404 "From above, we have a linear address of 0x%X\n\r",
407 ((UINT32
)(UINTN
)(DisplayPointer
->RuntimePtr
) & 0xFFFF) +
408 (((UINT32
)(UINTN
)(DisplayPointer
->RuntimePtr
) & 0xFFFF0000) >> 12)
415 #define OPTION_ROM_PTR ((OPTION_ROM_HEADER *) RomAddress)
418 If available, launch the BaseCode from a NIC option ROM.
419 This should install the !PXE and PXENV+ structures in memory for
423 @param SimpleNetworkDevice Simple network device instance
424 @param RomAddress The ROM base address for NIC rom.
426 @retval EFI_NOT_FOUND The check sum does not match
427 @retval EFI_NOT_FOUND Rom ID offset is wrong
428 @retval EFI_NOT_FOUND No Rom ID structure is found
432 EFI_SIMPLE_NETWORK_DEV
*SimpleNetworkDevice
,
437 EFI_IA32_REGISTER_SET InOutRegs
;
438 UNDI_ROMID_T
*RomIdTableAddress
;
439 UNDI_LOADER_T
*UndiLoaderTable
;
441 UINT16
*StackPointer
;
452 DEBUG ((DEBUG_NET
, "\n\r\n\rCheck for the UNDI ROMID Signature\n\r"));
455 // paranoia - check structures for validity
457 RomLength
= OPTION_ROM_PTR
->ROMlength
<< 9;
458 if (CalculateSum8 ((UINT8
*) RomAddress
, RomLength
) != 0) {
459 DEBUG ((DEBUG_ERROR
, "ROM Header Checksum Error\n\r"));
460 return EFI_NOT_FOUND
;
463 RomIdTableAddress
= (UNDI_ROMID_T
*) (RomAddress
+ OPTION_ROM_PTR
->PxeRomIdOffset
);
465 if (((UINT32
)OPTION_ROM_PTR
->PxeRomIdOffset
+ RomIdTableAddress
->StructLength
) > RomLength
) {
466 DEBUG ((DEBUG_ERROR
, "ROM ID Offset Error\n\r"));
467 return EFI_NOT_FOUND
;
470 // see if this is a header for an UNDI ROM ID structure (vs. a $BC$ or BUSD type)
472 if (CompareMem (RomIdTableAddress
->Signature
, UNDI_ROMID_SIG
, sizeof RomIdTableAddress
->Signature
) != 0) {
473 DEBUG ((DEBUG_ERROR
, "No ROM ID Structure found....\n\r"));
474 return EFI_NOT_FOUND
;
476 // its not - keep looking
480 if (CalculateSum8 ((UINT8
*) RomIdTableAddress
, RomIdTableAddress
->StructLength
) != 0) {
481 DEBUG ((DEBUG_ERROR
, "ROM ID Checksum Error\n\r"));
482 return EFI_NOT_FOUND
;
485 Print_ROMID_Table (RomIdTableAddress
);
489 "The ROM ID is located at 0x%X\n\r",
495 "With an UNDI Loader located at 0x%X\n\r",
496 RomAddress
+ RomIdTableAddress
->UNDI_Loader
)
500 // found an UNDI ROM ID structure
502 SimpleNetworkDevice
->Nii
.ImageAddr
= RomAddress
;
503 SimpleNetworkDevice
->Nii
.ImageSize
= RomLength
;
504 SimpleNetworkDevice
->Nii
.MajorVer
= RomIdTableAddress
->UNDI_Rev
[2];
505 SimpleNetworkDevice
->Nii
.MinorVer
= RomIdTableAddress
->UNDI_Rev
[1];
507 DEBUG ((DEBUG_NET
, "Allocate area for the UNDI_LOADER_T structure\n\r"));
509 // Allocate 1 page below 1MB to put real mode thunk code in
511 // Undi Loader Table is a PXE Specification prescribed data structure
512 // that is used to transfer information into and out of the Undi layer.
513 // Note how it must be located below 1 MB.
515 SimpleNetworkDevice
->UndiLoaderTablePages
= EFI_SIZE_TO_PAGES (PARAGRAPH_SIZE
+ sizeof (UNDI_LOADER_T
));
516 Status
= BiosSnp16AllocatePagesBelowOneMb (
517 SimpleNetworkDevice
->UndiLoaderTablePages
,
518 &SimpleNetworkDevice
->UndiLoaderTable
520 if (EFI_ERROR (Status
)) {
521 DEBUG ((DEBUG_ERROR
, "We had a failure in AllocatePages, status code = 0x%X\n", Status
));
522 return EFI_OUT_OF_RESOURCES
;
525 UndiLoaderTable
= SimpleNetworkDevice
->UndiLoaderTable
;
527 DEBUG ((DEBUG_NET
, "Allocate area for the real-mode stack whose sole purpose\n\r"));
528 DEBUG ((DEBUG_NET
, "in life right now is to store a SEG:OFFSET combo pair that\n\r"));
529 DEBUG ((DEBUG_NET
, "points to an Undi_Loader_t table structure\n\r"));
532 Status
= gBS
->AllocatePool (EfiLoaderData
, Size
, &Buffer
);
533 if (EFI_ERROR (Status
)) {
537 // Now we want to put a pointer to the Under Loader Table in our MemPage
538 // Buffer. This will be the argument stack for the call into the Undi Loader
540 StackPointer
= (UINT16
*) Buffer
;
541 *StackPointer
++ = TO_OFFSET (UndiLoaderTable
);
545 *StackPointer
++ = TO_SEGMENT (UndiLoaderTable
);
549 StackPointer
= (UINT16
*) Buffer
;
551 // reset the stack pointer
555 "After the fixups, the stack pointer is 0x%X\n\r",
556 (UINT64
)(UINTN
) StackPointer
)
560 // Allocate memory for the Deployed UNDI.
561 // The UNDI is essentially telling us how much space it needs, and
562 // it is up to the EFI driver to allocate sufficient, boot-time
563 // persistent resources for the call
565 SimpleNetworkDevice
->DestinationDataSegmentPages
= EFI_SIZE_TO_PAGES (RomIdTableAddress
->DataSize
);
566 Status
= BiosSnp16AllocatePagesBelowOneMb (
567 SimpleNetworkDevice
->DestinationDataSegmentPages
,
568 &SimpleNetworkDevice
->DestinationDataSegment
570 if (EFI_ERROR (Status
)) {
571 DEBUG ((DEBUG_ERROR
, "We had a failure in AllocatePages, status code = 0x%X\n", Status
));
575 UndiLoaderTable
->Undi_Ds
= (UINT16
) ((UINTN
) SimpleNetworkDevice
->DestinationDataSegment
>> 4);
578 // Allocate memory for the Deployed UNDI stack
579 // The UNDI is essentially telling us how much space it needs, and
580 // it is up to the EFI driver to allocate sufficient, boot-time
581 // persistent resources for the call
583 SimpleNetworkDevice
->DestinationStackSegmentPages
= EFI_SIZE_TO_PAGES (RomIdTableAddress
->StackSize
);
584 Status
= BiosSnp16AllocatePagesBelowOneMb (
585 SimpleNetworkDevice
->DestinationStackSegmentPages
,
586 &SimpleNetworkDevice
->DestinationStackSegment
588 if (EFI_ERROR (Status
)) {
589 DEBUG ((DEBUG_ERROR
, "We had a failure in AllocatePages, status code = 0x%X\n", Status
));
593 // Allocate memory for the Deployed UNDI.
594 // The UNDI is essentially telling us how much space it needs, and
595 // it is up to the EFI driver to allocate sufficient, boot-time
596 // persistent resources for the call
598 SimpleNetworkDevice
->DestinationCodeSegmentPages
= EFI_SIZE_TO_PAGES (RomIdTableAddress
->CodeSize
);
599 Status
= BiosSnp16AllocatePagesBelowOneMb (
600 SimpleNetworkDevice
->DestinationCodeSegmentPages
,
601 &SimpleNetworkDevice
->DestinationCodeSegment
603 if (EFI_ERROR (Status
)) {
604 DEBUG ((DEBUG_ERROR
, "We had a failure in AllocatePages, status code = 0x%X\n", Status
));
608 UndiLoaderTable
->Undi_Cs
= (UINT16
) ((UINTN
) SimpleNetworkDevice
->DestinationCodeSegment
>> 4);
611 // these are in the Input and Output Parameter to be sent to the UNDI Loader code
613 UndiLoaderTable
->Status
= 0xAA55;
615 // -------------------- Changed by Michael_Huang@3Com.com -----------------
616 // UndiLoaderTable->_AX is AX value when UNDI ROM is initialized by BIOS, it is the PCI bus device
617 // function of the NIC. Please refer to PXE Spec for detail info.
619 // UndiLoaderTable->Ax = 0x0;
620 // -----------------------------------------------------------------------
622 SimpleNetworkDevice
->PciIo
->GetLocation (
623 SimpleNetworkDevice
->PciIo
,
629 UndiLoaderTable
->Ax
= (UINT16
) ((Bus
<< 0x8) | (Device
<< 0x3) | (Function
));
630 UndiLoaderTable
->Bx
= 0x0;
631 UndiLoaderTable
->Dx
= 0x0;
632 UndiLoaderTable
->Di
= 0x0;
633 UndiLoaderTable
->Es
= 0x0;
636 // set these OUT values to zero in order to ensure that
637 // uninitialized memory is not mistaken for display data
639 UndiLoaderTable
->PXEptr
.Offset
= 0;
640 UndiLoaderTable
->PXEptr
.Segment
= 0;
641 UndiLoaderTable
->PXENVptr
.Segment
= 0;
642 UndiLoaderTable
->PXENVptr
.Offset
= 0;
646 "The NIC is located at Bus 0x%X, Device 0x%X, Function 0x%X\n\r",
653 // These are the values that set up the ACTUAL IA32 machine state, whether in
654 // Real16 in EFI32 or the IVE for IA64
655 // register values are unused except for CS:IP and SS:SP
669 DEBUG ((DEBUG_NET
, "The way this game works is that the SS:SP +4 should point\n\r"));
670 DEBUG ((DEBUG_NET
, "to the contents of the UndiLoaderTable\n\r"));
673 "The Undi Loader Table is at address = 0x%X\n\r",
674 (UINT32
)(UINTN
) UndiLoaderTable
)
678 "The segment and offsets are 0x%X and 0x%X, resp\n",
679 TO_SEGMENT (UndiLoaderTable
),
680 TO_OFFSET (UndiLoaderTable
))
685 "The Linear Address of the UNDI Loader entry is 0x%X\n",
686 RomAddress
+ RomIdTableAddress
->UNDI_Loader
)
691 "The Address offset of the UNDI Loader entry is 0x%X\n",
692 RomIdTableAddress
->UNDI_Loader
)
695 DEBUG ((DEBUG_NET
, "Before the call, we have...\n\r"));
696 Print_Undi_Loader_Table (UndiLoaderTable
);
698 Segment
= ((UINT16
) (RShiftU64 (RomAddress
, 4) & 0xFFFF));
699 DEBUG ((DEBUG_NET
, "The Segment of the call is 0x%X\n\r", Segment
));
702 // make the call into the UNDI Code
704 DEBUG ((DEBUG_INIT
, "Make the call into the UNDI code now\n\r"));
706 DEBUG ((DEBUG_NET
, "\nThe 20-BIt address of the Call, and the location \n\r"));
707 DEBUG ((DEBUG_NET
, "\twhere we should be able to set a breakpoint is \n\r"));
710 "\t\t0x%X, from SEG:OFF 0x%X:0x%X\n\r\n\r",
711 Segment
* 0x10 + RomIdTableAddress
->UNDI_Loader
,
713 RomIdTableAddress
->UNDI_Loader
)
716 ThunkFailed
= SimpleNetworkDevice
->LegacyBios
->FarCall86 (
717 SimpleNetworkDevice
->LegacyBios
,
718 Segment
, // Input segment
719 (UINT16
) RomIdTableAddress
->UNDI_Loader
, // Offset
720 &InOutRegs
, // Ptr to Regs
721 Buffer
, // Reference to Stack
722 Size
// Size of the Stack
730 "The return code UndiLoaderTable->Status is = 0x%X\n\r",
731 UndiLoaderTable
->Status
)
735 "This error code should match eax, which is = 0x%X\n\r",
739 if ((UndiLoaderTable
->Status
!= 0) || (InOutRegs
.X
.AX
!= PXENV_EXIT_SUCCESS
)) {
740 DEBUG ((DEBUG_NET
, "LaunchBaseCode exits with error, RomAddress = 0x%X\n\r", RomAddress
));
744 DEBUG ((DEBUG_NET
, "Now returned from the UNDI code\n\r"));
746 DEBUG ((DEBUG_NET
, "After the call, we have...\n\r"));
747 Print_Undi_Loader_Table (UndiLoaderTable
);
749 DEBUG ((DEBUG_NET
, "Display the PXENV+ and !PXE tables exported by NIC\n\r"));
750 Print_PXENV_Table ((VOID
*)(((UINTN
)UndiLoaderTable
->PXENVptr
.Segment
<< 4) | UndiLoaderTable
->PXENVptr
.Offset
));
751 Print_PXE_Table ((VOID
*)(((UINTN
)UndiLoaderTable
->PXEptr
.Segment
<< 4) + UndiLoaderTable
->PXEptr
.Offset
));
753 Pxe
= (PXE_T
*)(((UINTN
)UndiLoaderTable
->PXEptr
.Segment
<< 4) + UndiLoaderTable
->PXEptr
.Offset
);
754 SimpleNetworkDevice
->Nii
.Id
= (UINT64
)(UINTN
) Pxe
;
756 gBS
->FreePool (Buffer
);
759 // paranoia - make sure a valid !PXE structure
761 if (CompareMem (Pxe
->Signature
, PXE_SIG
, sizeof Pxe
->Signature
) != 0) {
762 DEBUG ((DEBUG_ERROR
, "!PXE Structure not found....\n\r"));
763 return EFI_NOT_FOUND
;
765 // its not - keep looking
769 if (CalculateSum8 ((UINT8
*) Pxe
, Pxe
->StructLength
) != 0) {
770 DEBUG ((DEBUG_ERROR
, "!PXE Checksum Error\n\r"));
771 return EFI_NOT_FOUND
;
774 if (Pxe
->StructLength
< (UINT8
*) &Pxe
->FirstSelector
- (UINT8
*) Pxe
->Signature
) {
775 DEBUG ((DEBUG_ERROR
, "!PXE Length Error\n\r"));
776 return EFI_NOT_FOUND
;
779 if ((((UINTN
) Pxe
->Undi
.Segment
) << 4) + Pxe
->Undi
.Offset
!= (UINTN
) RomIdTableAddress
) {
780 DEBUG ((DEBUG_ERROR
, "!PXE RomId Address Error\n\r"));
781 return EFI_NOT_FOUND
;
784 // This is the magic to bind the global PXE interface
785 // This dirtiness is for non-protocol shrouded access
787 SimpleNetworkDevice
->PxeEntrySegment
= Pxe
->EntryPointSP
.Segment
;
789 if (SimpleNetworkDevice
->PxeEntrySegment
== 0) {
790 DEBUG ((DEBUG_ERROR
, "!PXE EntryPointSP segment Error\n\r"));
791 return EFI_NOT_FOUND
;
794 SimpleNetworkDevice
->PxeEntryOffset
= Pxe
->EntryPointSP
.Offset
;
798 DEBUG_NET
, "The entry point is 0x%X:0x%X\n\r", SimpleNetworkDevice
->PxeEntrySegment
, SimpleNetworkDevice
->
807 Effect the Far Call into the PXE Layer
809 Note: When using a 32-bit stack segment do not push 32-bit words onto the stack. The PXE API
810 services will not work, unless there are three 16-bit parameters pushed onto the stack.
811 push DS ;Far pointer to parameter structure
812 push offset pxe_data_call_struct ;is pushed onto stack.
813 push Index ;UINT16 is pushed onto stack.
814 call dword ptr (s_PXE ptr es:[di]).EntryPointSP
815 add sp, 6 ;Caller cleans up stack.
817 @param SimpleNetworkDevice Device instance for simple network
818 @param Table Point to parameter/retun value table for legacy far call
819 @param TableSize The size of parameter/return value table
820 @param CallIndex The index of legacy call.
826 EFI_SIMPLE_NETWORK_DEV
*SimpleNetworkDevice
,
833 EFI_IA32_REGISTER_SET InOutRegs
;
837 VOID
*MemPageAddress
;
841 DEBUG ((DEBUG_NET
, "MakePxeCall(CallIndex = %02x, Table = %X, TableSize = %d)\n", CallIndex
, Table
, TableSize
));
843 if (SimpleNetworkDevice
->PxeEntrySegment
== 0 && SimpleNetworkDevice
->PxeEntryOffset
== 0) {
844 return EFI_DEVICE_ERROR
;
847 Status
= EFI_SUCCESS
;
850 // Allocate a transient data structure for the argument table
851 // This table needs to have the input XXX_t structure copied into here.
852 // The PXE UNDI can only grab this table when it's below one-MB, and
853 // this implementation will not try to push this table on the stack
854 // (although this is a possible optimization path since EFI always allocates
855 // 4K as a minimum page size...............)
857 Status
= BiosSnp16AllocatePagesBelowOneMb (
858 TableSize
/ EFI_PAGE_SIZE
+ 1,
861 if (EFI_ERROR (Status
)) {
862 DEBUG ((DEBUG_ERROR
, "We had a failure in AllocatePages, status code = 0x%X\n", Status
));
866 // Copy the > 1MB pool table to a sub-1MB buffer
868 CopyMem (MemPageAddress
, Table
, TableSize
);
871 // Allocate space for IA-32 register context
873 ZeroMem (&InOutRegs
, sizeof (InOutRegs
));
874 InOutRegs
.X
.ES
= SimpleNetworkDevice
->PxeEntrySegment
;
875 InOutRegs
.X
.DI
= SimpleNetworkDevice
->PxeEntryOffset
;
878 // The game here is to build the stack which will subsequently
879 // get copied down below 1 MB by the FarCall primitive.
880 // This is now our working stack
883 Status
= gBS
->AllocatePool (
884 EfiRuntimeServicesData
,
888 if (EFI_ERROR (Status
)) {
892 BPtr
= (UINT16
*) Buffer
;
897 *BPtr
++ = TO_OFFSET (MemPageAddress
);
898 *BPtr
++ = TO_SEGMENT (MemPageAddress
);
900 DEBUG ((DEBUG_NET
, "State before FarCall86\n"));
901 DEBUG ((DEBUG_NET
, "The Buffer is at 0x%X\n\r", Buffer
));
902 BPtr
= (UINT16
*) Buffer
;
903 DEBUG ((DEBUG_NET
, " Buffer = %04X %04X %04X", *BPtr
, *(BPtr
+ 1), *(BPtr
+ 2)));
904 DEBUG ((DEBUG_NET
, " MemPage = "));
905 for (Index
= 0; Index
< TableSize
; Index
++) {
906 DEBUG ((DEBUG_NET
, " %02x", *((UINT8
*) MemPageAddress
+ Index
)));
909 DEBUG ((DEBUG_NET
, "\n"));
911 ThunkFailed
= SimpleNetworkDevice
->LegacyBios
->FarCall86 (
912 SimpleNetworkDevice
->LegacyBios
,
913 SimpleNetworkDevice
->PxeEntrySegment
, // Input segment
914 SimpleNetworkDevice
->PxeEntryOffset
,
915 &InOutRegs
, // Ptr to Regs
916 Buffer
, // Reference to Stack
917 6 // Size of the Stack
923 DEBUG ((DEBUG_NET
, "State after FarCall86\n"));
924 DEBUG ((DEBUG_NET
, "The Buffer is at 0x%X\n\r", Buffer
));
925 BPtr
= (UINT16
*) Buffer
;
926 DEBUG ((DEBUG_NET
, " Buffer = %04X %04X %04X", *BPtr
, *(BPtr
+ 1), *(BPtr
+ 2)));
927 DEBUG ((DEBUG_NET
, " MemPage = "));
928 for (Index
= 0; Index
< TableSize
; Index
++) {
929 DEBUG ((DEBUG_NET
, " %02x", *((UINT8
*) MemPageAddress
+ Index
)));
932 DEBUG ((DEBUG_NET
, "\n"));
935 // Copy the sub 1MB table to > 1MB table
937 CopyMem (Table
, MemPageAddress
, TableSize
);
940 // For PXE UNDI call, AX contains the return status.
941 // Convert the PXE UNDI Status to EFI_STATUS type
943 if (InOutRegs
.X
.AX
== PXENV_EXIT_SUCCESS
) {
944 Status
= EFI_SUCCESS
;
946 Status
= EFI_DEVICE_ERROR
;
951 gBS
->FreePool (Buffer
);
952 gBS
->FreePages ((EFI_PHYSICAL_ADDRESS
) (UINTN
) MemPageAddress
, TableSize
/ EFI_PAGE_SIZE
+ 1);