]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Misc.c
IntelFrameworkModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / IntelFrameworkModulePkg / Csm / BiosThunk / Snp16Dxe / Misc.c
1 /** @file
2 Helper Routines that use a PXE-enabled NIC option ROM.
3
4 Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "BiosSnp16.h"
11
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
16
17 #pragma pack(1)
18 typedef struct {
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
26 } OPTION_ROM_HEADER;
27 #pragma pack()
28
29 UINT32 CachedVectorAddress[0x100];
30
31 /**
32 Cache Interrupt verctor address converted from IVT number.
33
34 @param VectorNumber IVT number
35
36 @retval EFI_SUCCESS Success to operation.
37 **/
38 EFI_STATUS
39 CacheVectorAddress (
40 UINT8 VectorNumber
41 )
42 {
43 UINT32 *Address;
44
45 Address = (UINT32 *) ((UINTN) IVT_BASE + VectorNumber * 4);
46 CachedVectorAddress[VectorNumber] = *Address;
47 return EFI_SUCCESS;
48 }
49
50 /**
51 Get interrupt vector address according to IVT number.
52
53 @param VectorNumber Given IVT number
54
55 @return cached interrupt vector address.
56 **/
57 EFI_STATUS
58 RestoreCachedVectorAddress (
59 UINT8 VectorNumber
60 )
61 {
62 UINT32 *Address;
63
64 Address = (UINT32 *) ((UINTN) IVT_BASE + VectorNumber * 4);
65 *Address = CachedVectorAddress[VectorNumber];
66 return EFI_SUCCESS;
67 }
68
69 /**
70 Print Undi loader table.
71
72 @param UndiLoaderStructure Point to Undi Loader table structure.
73
74 **/
75 VOID
76 Print_Undi_Loader_Table (
77 VOID *UndiLoaderStructure
78 )
79 {
80 UNDI_LOADER_T *DisplayPointer;
81
82 DisplayPointer = (UNDI_LOADER_T *) UndiLoaderStructure;
83
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));
86
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));
99 }
100
101 /**
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
106 are not using PXE.
107
108 @param RomIDStructure Point to RomID structure.
109
110 **/
111 VOID
112 Print_ROMID_Table (
113 IN VOID *RomIDStructure
114 )
115 {
116 UNDI_ROMID_T *DisplayPointer;
117
118 DisplayPointer = (UNDI_ROMID_T *) RomIDStructure;
119
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));
122
123 DEBUG (
124 (DEBUG_NET,
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])
130 );
131
132 DEBUG (
133 (DEBUG_NET,
134 "Length of this structure in bytes = 0x%X\n\r",
135 DisplayPointer->StructLength)
136 );
137 DEBUG (
138 (DEBUG_NET,
139 "Use to make byte checksum of this structure == zero is = 0x%X\n\r",
140 DisplayPointer->StructCksum)
141 );
142 DEBUG (
143 (DEBUG_NET,
144 "Structure format revision number= 0x%X\n\r",
145 DisplayPointer->StructRev)
146 );
147 DEBUG (
148 (DEBUG_NET,
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])
153 );
154 DEBUG (
155 (DEBUG_NET,
156 "Offset of UNDI loader routine in the option ROM image= 0x%X\n\r",
157 DisplayPointer->UNDI_Loader)
158 );
159 DEBUG ((DEBUG_NET, "From the data above, the absolute entry point of the UNDI loader is\n\r"));
160 DEBUG (
161 (DEBUG_NET,
162 "\tat address 0x%X\n\r",
163 (UINT32) (DisplayPointer->UNDI_Loader + ((UINT32) (UINTN)(DisplayPointer - 0x20) & 0xFFFF0)))
164 );
165 DEBUG ((DEBUG_NET, "Minimum stack segment size, in bytes,\n\r"));
166 DEBUG (
167 (DEBUG_NET,
168 "needed to load and run the UNDI= 0x%X \n\r",
169 DisplayPointer->StackSize)
170 );
171 DEBUG (
172 (DEBUG_NET,
173 "UNDI runtime code and data = 0x%X\n\r",
174 DisplayPointer->DataSize)
175 );
176 DEBUG (
177 (DEBUG_NET,
178 "Segment size = 0x%X\n\r",
179 DisplayPointer->CodeSize)
180 );
181 DEBUG (
182 (DEBUG_NET,
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])
188 );
189 }
190
191 /**
192 Print PXE table.
193
194 @param PxeTable Point to PXE table structure
195
196 **/
197 VOID
198 Print_PXE_Table (
199 IN VOID* PxeTable
200 )
201 {
202 PXE_T *DisplayPointer;
203 UINTN Index;
204 UINT8 *Dptr;
205
206 DisplayPointer = (PXE_T *) PxeTable;
207 Dptr = (UINT8 *) PxeTable;
208
209 DEBUG ((DEBUG_NET, "This is the PXE table at address 0x%X\n\r", PxeTable));
210
211 DEBUG ((DEBUG_NET, "A dump of the 0x%X bytes is:\n\r", sizeof (PXE_T)));
212
213 for (Index = 0; Index < sizeof (PXE_T); Index++) {
214 if ((Index % 0x10) == 0) {
215 DEBUG ((DEBUG_NET, "\t\n\r"));
216 }
217
218 DEBUG ((DEBUG_NET, " 0x%X ", *Dptr++));
219 }
220
221 DEBUG ((DEBUG_NET, "\n\r"));
222 DEBUG (
223 (DEBUG_NET,
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])
229 );
230 DEBUG (
231 (DEBUG_NET,
232 "Length of this structure in bytes = 0x%X\n\r",
233 DisplayPointer->StructLength)
234 );
235 DEBUG (
236 (DEBUG_NET,
237 "Use to make byte checksum of this structure == zero is = 0x%X\n\r",
238 DisplayPointer->StructCksum)
239 );
240 DEBUG (
241 (DEBUG_NET,
242 "Structure format revision number = 0x%X\n\r",
243 DisplayPointer->StructRev)
244 );
245 DEBUG (
246 (DEBUG_NET,
247 "Must be zero, is equal to 0x%X\n\r",
248 DisplayPointer->Reserved1)
249 );
250 DEBUG (
251 (DEBUG_NET,
252 "Far pointer to UNDI ROMID = 0x%X\n\r",
253 (UINT32) (DisplayPointer->Undi.Segment << 0x4 | DisplayPointer->Undi.Offset))
254 );
255 DEBUG (
256 (DEBUG_NET,
257 "Far pointer to base-code ROMID = 0x%X\n\r",
258 (UINT32) ((DisplayPointer->Base.Segment << 0x04) | DisplayPointer->Base.Offset))
259 );
260 DEBUG ((DEBUG_NET, "16bit stack segment API entry point. This will be seg:off in \n\r"));
261 DEBUG (
262 (DEBUG_NET,
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)
266 );
267
268 DEBUG ((DEBUG_NET, "\n\tNOTE to the implementer\n\tThis is the entry to use for call-ins\n\r"));
269
270 DEBUG ((DEBUG_NET, "32bit stack Segment API entry point. This will be sel:off. \n\r"));
271 DEBUG (
272 (DEBUG_NET,
273 "In real mode, sel == 0 = 0x%X:0x%X\n\r",
274 DisplayPointer->EntryPointESP.Segment,
275 DisplayPointer->EntryPointESP.Offset)
276 );
277 DEBUG (
278 (DEBUG_NET,
279 "Reserved2 value, must be zero, is equal to 0x%X\n\r",
280 DisplayPointer->Reserved2)
281 );
282 DEBUG (
283 (DEBUG_NET,
284 "Number of segment descriptors in this structur = 0x%X\n\r",
285 (UINT8) DisplayPointer->SegDescCnt)
286 );
287 DEBUG (
288 (DEBUG_NET,
289 "First segment descriptor in GDT assigned to PXE = 0x%X\n\r",
290 (UINT16) DisplayPointer->FirstSelector)
291 );
292 DEBUG (
293 (DEBUG_NET,
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)
298 );
299 DEBUG (
300 (DEBUG_NET,
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)
305 );
306 DEBUG (
307 (DEBUG_NET,
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)
312 );
313 DEBUG (
314 (DEBUG_NET,
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)
319 );
320 DEBUG (
321 (DEBUG_NET,
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)
326 );
327 DEBUG (
328 (DEBUG_NET,
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)
333 );
334 DEBUG (
335 (DEBUG_NET,
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)
340 );
341 }
342
343 /**
344 Print PXENV table.
345
346 @param PxenvTable Point to PXENV
347
348 **/
349 VOID
350 Print_PXENV_Table (
351 IN VOID *PxenvTable
352 )
353 {
354 PXENV_T *DisplayPointer;
355
356 DisplayPointer = (PXENV_T *) PxenvTable;
357
358 DEBUG (
359 (DEBUG_NET,
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])
367 );
368
369 DEBUG (
370 (DEBUG_NET,
371 "PXE version number. \n\r\tLSB is minor version. \n\r\tMSB is major version = 0x%X\n\r",
372 DisplayPointer->Version)
373 );
374 DEBUG (
375 (DEBUG_NET,
376 "Length of PXE-2.0 Entry Point structure in bytes = 0x%X\n\r",
377 DisplayPointer->StructLength)
378 );
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));
390
391 DEBUG (
392 (DEBUG_NET,
393 "UNDI code segment size in bytes = 0x%X\n\r",
394 DisplayPointer->UNDICodeSize)
395 );
396 DEBUG (
397 (DEBUG_NET,
398 "Real mode segment:Offset pointer \n\r\tto PXE Runtime ID structure, address = 0x%X\n\r",
399 DisplayPointer->RuntimePtr)
400 );
401 DEBUG (
402 (
403 DEBUG_NET,
404 "From above, we have a linear address of 0x%X\n\r",
405 (UINT32)
406 (
407 ((UINT32)(UINTN)(DisplayPointer->RuntimePtr) & 0xFFFF) +
408 (((UINT32)(UINTN)(DisplayPointer->RuntimePtr) & 0xFFFF0000) >> 12)
409 )
410 )
411 );
412 }
413
414
415 #define OPTION_ROM_PTR ((OPTION_ROM_HEADER *) RomAddress)
416
417 /**
418 If available, launch the BaseCode from a NIC option ROM.
419 This should install the !PXE and PXENV+ structures in memory for
420 subsequent use.
421
422
423 @param SimpleNetworkDevice Simple network device instance
424 @param RomAddress The ROM base address for NIC rom.
425
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
429 **/
430 EFI_STATUS
431 LaunchBaseCode (
432 EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
433 UINTN RomAddress
434 )
435 {
436 EFI_STATUS Status;
437 EFI_IA32_REGISTER_SET InOutRegs;
438 UNDI_ROMID_T *RomIdTableAddress;
439 UNDI_LOADER_T *UndiLoaderTable;
440 UINT16 Segment;
441 UINT16 *StackPointer;
442 VOID *Buffer;
443 UINTN Size;
444 PXE_T *Pxe;
445 UINT32 RomLength;
446 UINTN PciSegment;
447 UINTN Bus;
448 UINTN Device;
449 UINTN Function;
450 BOOLEAN ThunkFailed;
451
452 DEBUG ((DEBUG_NET, "\n\r\n\rCheck for the UNDI ROMID Signature\n\r"));
453
454 //
455 // paranoia - check structures for validity
456 //
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;
461 }
462
463 RomIdTableAddress = (UNDI_ROMID_T *) (RomAddress + OPTION_ROM_PTR->PxeRomIdOffset);
464
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;
468 }
469 //
470 // see if this is a header for an UNDI ROM ID structure (vs. a $BC$ or BUSD type)
471 //
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;
475 //
476 // its not - keep looking
477 //
478 }
479
480 if (CalculateSum8 ((UINT8 *) RomIdTableAddress, RomIdTableAddress->StructLength) != 0) {
481 DEBUG ((DEBUG_ERROR, "ROM ID Checksum Error\n\r"));
482 return EFI_NOT_FOUND;
483 }
484
485 Print_ROMID_Table (RomIdTableAddress);
486
487 DEBUG (
488 (DEBUG_NET,
489 "The ROM ID is located at 0x%X\n\r",
490 RomIdTableAddress)
491 );
492
493 DEBUG (
494 (DEBUG_NET,
495 "With an UNDI Loader located at 0x%X\n\r",
496 RomAddress + RomIdTableAddress->UNDI_Loader)
497 );
498
499 //
500 // found an UNDI ROM ID structure
501 //
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];
506
507 DEBUG ((DEBUG_NET, "Allocate area for the UNDI_LOADER_T structure\n\r"));
508 //
509 // Allocate 1 page below 1MB to put real mode thunk code in
510 //
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.
514 //
515 SimpleNetworkDevice->UndiLoaderTablePages = EFI_SIZE_TO_PAGES (PARAGRAPH_SIZE + sizeof (UNDI_LOADER_T));
516 Status = BiosSnp16AllocatePagesBelowOneMb (
517 SimpleNetworkDevice->UndiLoaderTablePages,
518 &SimpleNetworkDevice->UndiLoaderTable
519 );
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;
523 }
524
525 UndiLoaderTable = SimpleNetworkDevice->UndiLoaderTable;
526
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"));
530
531 Size = 0x100;
532 Status = gBS->AllocatePool (EfiLoaderData, Size, &Buffer);
533 if (EFI_ERROR (Status)) {
534 return Status;
535 }
536 //
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
539 //
540 StackPointer = (UINT16 *) Buffer;
541 *StackPointer++ = TO_OFFSET (UndiLoaderTable);
542 //
543 // push the OFFSET
544 //
545 *StackPointer++ = TO_SEGMENT (UndiLoaderTable);
546 //
547 // push the SEGMENT
548 //
549 StackPointer = (UINT16 *) Buffer;
550 //
551 // reset the stack pointer
552 //
553 DEBUG (
554 (DEBUG_NET,
555 "After the fixups, the stack pointer is 0x%X\n\r",
556 (UINT64)(UINTN) StackPointer)
557 );
558
559 //
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
564 //
565 SimpleNetworkDevice->DestinationDataSegmentPages = EFI_SIZE_TO_PAGES (RomIdTableAddress->DataSize);
566 Status = BiosSnp16AllocatePagesBelowOneMb (
567 SimpleNetworkDevice->DestinationDataSegmentPages,
568 &SimpleNetworkDevice->DestinationDataSegment
569 );
570 if (EFI_ERROR (Status)) {
571 DEBUG ((DEBUG_ERROR, "We had a failure in AllocatePages, status code = 0x%X\n", Status));
572 return Status;
573 }
574
575 UndiLoaderTable->Undi_Ds = (UINT16) ((UINTN) SimpleNetworkDevice->DestinationDataSegment >> 4);
576
577 //
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
582 //
583 SimpleNetworkDevice->DestinationStackSegmentPages = EFI_SIZE_TO_PAGES (RomIdTableAddress->StackSize);
584 Status = BiosSnp16AllocatePagesBelowOneMb (
585 SimpleNetworkDevice->DestinationStackSegmentPages,
586 &SimpleNetworkDevice->DestinationStackSegment
587 );
588 if (EFI_ERROR (Status)) {
589 DEBUG ((DEBUG_ERROR, "We had a failure in AllocatePages, status code = 0x%X\n", Status));
590 return Status;
591 }
592 //
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
597 //
598 SimpleNetworkDevice->DestinationCodeSegmentPages = EFI_SIZE_TO_PAGES (RomIdTableAddress->CodeSize);
599 Status = BiosSnp16AllocatePagesBelowOneMb (
600 SimpleNetworkDevice->DestinationCodeSegmentPages,
601 &SimpleNetworkDevice->DestinationCodeSegment
602 );
603 if (EFI_ERROR (Status)) {
604 DEBUG ((DEBUG_ERROR, "We had a failure in AllocatePages, status code = 0x%X\n", Status));
605 return Status;
606 }
607
608 UndiLoaderTable->Undi_Cs = (UINT16) ((UINTN) SimpleNetworkDevice->DestinationCodeSegment >> 4);
609
610 //
611 // these are in the Input and Output Parameter to be sent to the UNDI Loader code
612 //
613 UndiLoaderTable->Status = 0xAA55;
614 //
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.
618 // old code is:
619 // UndiLoaderTable->Ax = 0x0;
620 // -----------------------------------------------------------------------
621 //
622 SimpleNetworkDevice->PciIo->GetLocation (
623 SimpleNetworkDevice->PciIo,
624 &PciSegment,
625 &Bus,
626 &Device,
627 &Function
628 );
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;
634
635 //
636 // set these OUT values to zero in order to ensure that
637 // uninitialized memory is not mistaken for display data
638 //
639 UndiLoaderTable->PXEptr.Offset = 0;
640 UndiLoaderTable->PXEptr.Segment = 0;
641 UndiLoaderTable->PXENVptr.Segment = 0;
642 UndiLoaderTable->PXENVptr.Offset = 0;
643
644 DEBUG (
645 (DEBUG_INIT,
646 "The NIC is located at Bus 0x%X, Device 0x%X, Function 0x%X\n\r",
647 Bus,
648 Device,
649 Function)
650 );
651
652 //
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
656 //
657 InOutRegs.X.AX = 0;
658 InOutRegs.X.BX = 0;
659 InOutRegs.X.CX = 0;
660 InOutRegs.X.DX = 0;
661 InOutRegs.X.SI = 0;
662 InOutRegs.X.DI = 0;
663 InOutRegs.X.BP = 0;
664 InOutRegs.X.DS = 0;
665 InOutRegs.X.ES = 0;
666 //
667 // just to be clean
668 //
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"));
671 DEBUG (
672 (DEBUG_NET,
673 "The Undi Loader Table is at address = 0x%X\n\r",
674 (UINT32)(UINTN) UndiLoaderTable)
675 );
676 DEBUG (
677 (DEBUG_NET,
678 "The segment and offsets are 0x%X and 0x%X, resp\n",
679 TO_SEGMENT (UndiLoaderTable),
680 TO_OFFSET (UndiLoaderTable))
681 );
682
683 DEBUG (
684 (DEBUG_NET,
685 "The Linear Address of the UNDI Loader entry is 0x%X\n",
686 RomAddress + RomIdTableAddress->UNDI_Loader)
687 );
688
689 DEBUG (
690 (DEBUG_NET,
691 "The Address offset of the UNDI Loader entry is 0x%X\n",
692 RomIdTableAddress->UNDI_Loader)
693 );
694
695 DEBUG ((DEBUG_NET, "Before the call, we have...\n\r"));
696 Print_Undi_Loader_Table (UndiLoaderTable);
697
698 Segment = ((UINT16) (RShiftU64 (RomAddress, 4) & 0xFFFF));
699 DEBUG ((DEBUG_NET, "The Segment of the call is 0x%X\n\r", Segment));
700
701 //
702 // make the call into the UNDI Code
703 //
704 DEBUG ((DEBUG_INIT, "Make the call into the UNDI code now\n\r"));
705
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"));
708 DEBUG (
709 (DEBUG_NET,
710 "\t\t0x%X, from SEG:OFF 0x%X:0x%X\n\r\n\r",
711 Segment * 0x10 + RomIdTableAddress->UNDI_Loader,
712 Segment,
713 RomIdTableAddress->UNDI_Loader)
714 );
715
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
723 );
724 if (ThunkFailed) {
725 return EFI_ABORTED;
726 }
727
728 DEBUG (
729 (DEBUG_NET,
730 "The return code UndiLoaderTable->Status is = 0x%X\n\r",
731 UndiLoaderTable->Status)
732 );
733 DEBUG (
734 (DEBUG_NET,
735 "This error code should match eax, which is = 0x%X\n\r",
736 InOutRegs.X.AX)
737 );
738
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));
741 return EFI_ABORTED;
742 }
743
744 DEBUG ((DEBUG_NET, "Now returned from the UNDI code\n\r"));
745
746 DEBUG ((DEBUG_NET, "After the call, we have...\n\r"));
747 Print_Undi_Loader_Table (UndiLoaderTable);
748
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));
752
753 Pxe = (PXE_T *)(((UINTN)UndiLoaderTable->PXEptr.Segment << 4) + UndiLoaderTable->PXEptr.Offset);
754 SimpleNetworkDevice->Nii.Id = (UINT64)(UINTN) Pxe;
755
756 gBS->FreePool (Buffer);
757
758 //
759 // paranoia - make sure a valid !PXE structure
760 //
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;
764 //
765 // its not - keep looking
766 //
767 }
768
769 if (CalculateSum8 ((UINT8 *) Pxe, Pxe->StructLength) != 0) {
770 DEBUG ((DEBUG_ERROR, "!PXE Checksum Error\n\r"));
771 return EFI_NOT_FOUND;
772 }
773
774 if (Pxe->StructLength < (UINT8 *) &Pxe->FirstSelector - (UINT8 *) Pxe->Signature) {
775 DEBUG ((DEBUG_ERROR, "!PXE Length Error\n\r"));
776 return EFI_NOT_FOUND;
777 }
778
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;
782 }
783 //
784 // This is the magic to bind the global PXE interface
785 // This dirtiness is for non-protocol shrouded access
786 //
787 SimpleNetworkDevice->PxeEntrySegment = Pxe->EntryPointSP.Segment;
788
789 if (SimpleNetworkDevice->PxeEntrySegment == 0) {
790 DEBUG ((DEBUG_ERROR, "!PXE EntryPointSP segment Error\n\r"));
791 return EFI_NOT_FOUND;
792 }
793
794 SimpleNetworkDevice->PxeEntryOffset = Pxe->EntryPointSP.Offset;
795
796 DEBUG (
797 (
798 DEBUG_NET, "The entry point is 0x%X:0x%X\n\r", SimpleNetworkDevice->PxeEntrySegment, SimpleNetworkDevice->
799 PxeEntryOffset
800 )
801 );
802
803 return EFI_SUCCESS;
804 }
805
806 /**
807 Effect the Far Call into the PXE Layer
808
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.
816
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.
821
822 @return EFI_STATUS
823 **/
824 EFI_STATUS
825 MakePxeCall (
826 EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
827 IN OUT VOID *Table,
828 IN UINTN TableSize,
829 IN UINT16 CallIndex
830 )
831 {
832 EFI_STATUS Status;
833 EFI_IA32_REGISTER_SET InOutRegs;
834 UINT16 *BPtr;
835 VOID *Buffer;
836 UINTN Size;
837 VOID *MemPageAddress;
838 UINTN Index;
839 BOOLEAN ThunkFailed;
840
841 DEBUG ((DEBUG_NET, "MakePxeCall(CallIndex = %02x, Table = %X, TableSize = %d)\n", CallIndex, Table, TableSize));
842
843 if (SimpleNetworkDevice->PxeEntrySegment == 0 && SimpleNetworkDevice->PxeEntryOffset == 0) {
844 return EFI_DEVICE_ERROR;
845 }
846
847 Status = EFI_SUCCESS;
848
849 //
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...............)
856 //
857 Status = BiosSnp16AllocatePagesBelowOneMb (
858 TableSize / EFI_PAGE_SIZE + 1,
859 &MemPageAddress
860 );
861 if (EFI_ERROR (Status)) {
862 DEBUG ((DEBUG_ERROR, "We had a failure in AllocatePages, status code = 0x%X\n", Status));
863 return Status;
864 }
865 //
866 // Copy the > 1MB pool table to a sub-1MB buffer
867 //
868 CopyMem (MemPageAddress, Table, TableSize);
869
870 //
871 // Allocate space for IA-32 register context
872 //
873 ZeroMem (&InOutRegs, sizeof (InOutRegs));
874 InOutRegs.X.ES = SimpleNetworkDevice->PxeEntrySegment;
875 InOutRegs.X.DI = SimpleNetworkDevice->PxeEntryOffset;
876
877 //
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
881 //
882 Size = 6;
883 Status = gBS->AllocatePool (
884 EfiRuntimeServicesData,
885 Size,
886 &Buffer
887 );
888 if (EFI_ERROR (Status)) {
889 return Status;
890 }
891
892 BPtr = (UINT16 *) Buffer;
893 *BPtr++ = CallIndex;
894 //
895 // SP + 2
896 //
897 *BPtr++ = TO_OFFSET (MemPageAddress);
898 *BPtr++ = TO_SEGMENT (MemPageAddress);
899
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)));
907 }
908
909 DEBUG ((DEBUG_NET, "\n"));
910
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
918 );
919 if (ThunkFailed) {
920 return EFI_ABORTED;
921 }
922
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)));
930 }
931
932 DEBUG ((DEBUG_NET, "\n"));
933
934 //
935 // Copy the sub 1MB table to > 1MB table
936 //
937 CopyMem (Table, MemPageAddress, TableSize);
938
939 //
940 // For PXE UNDI call, AX contains the return status.
941 // Convert the PXE UNDI Status to EFI_STATUS type
942 //
943 if (InOutRegs.X.AX == PXENV_EXIT_SUCCESS) {
944 Status = EFI_SUCCESS;
945 } else {
946 Status = EFI_DEVICE_ERROR;
947 }
948 //
949 // Clean up house
950 //
951 gBS->FreePool (Buffer);
952 gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) MemPageAddress, TableSize / EFI_PAGE_SIZE + 1);
953
954 return Status;
955 }