]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Misc.c
IntelFrameworkModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / IntelFrameworkModulePkg / Csm / BiosThunk / Snp16Dxe / Misc.c
CommitLineData
bcecde14 1/** @file\r
2 Helper Routines that use a PXE-enabled NIC option ROM.\r
0a6f4824
LG
3\r
4Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR>\r
bcecde14 5\r
c0a00b14 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
bcecde14 7\r
8**/\r
9\r
10#include "BiosSnp16.h"\r
11\r
12#define TO_SEGMENT(x) ((UINT16) (RShiftU64 ((UINT32)(UINTN) (x), 4) & 0xF000))\r
13#define TO_OFFSET(x) ((UINT16) ((UINT32)(UINTN) (x) & 0xFFFF))\r
14#define PARAGRAPH_SIZE 0x10\r
15#define IVT_BASE 0x00000000\r
16\r
17#pragma pack(1)\r
18typedef struct {\r
19 UINT16 Signature; ///< 0xaa55\r
20 UINT8 ROMlength; ///< size of this ROM in 512 byte blocks\r
21 UINT8 InitEntryPoint[4]; ///< a jump to the initialization routine\r
22 UINT8 Reserved[0xf]; ///< various\r
23 UINT16 PxeRomIdOffset; ///< offset of UNDI, $BC$, or BUSD ROM ID structure\r
24 UINT16 PcirHeaderOffset; ///< offset of PCI Expansion Header\r
25 UINT16 PnpHeaderOffset; ///< offset of Plug and Play Expansion Header\r
26} OPTION_ROM_HEADER;\r
27#pragma pack()\r
28\r
29UINT32 CachedVectorAddress[0x100];\r
30\r
31/**\r
32 Cache Interrupt verctor address converted from IVT number.\r
33\r
34 @param VectorNumber IVT number\r
0a6f4824 35\r
bcecde14 36 @retval EFI_SUCCESS Success to operation.\r
37**/\r
38EFI_STATUS\r
39CacheVectorAddress (\r
40 UINT8 VectorNumber\r
41 )\r
42{\r
43 UINT32 *Address;\r
44\r
aa5f60ae 45 Address = (UINT32 *) ((UINTN) IVT_BASE + VectorNumber * 4);\r
bcecde14 46 CachedVectorAddress[VectorNumber] = *Address;\r
47 return EFI_SUCCESS;\r
48}\r
49\r
50/**\r
0a6f4824
LG
51 Get interrupt vector address according to IVT number.\r
52\r
bcecde14 53 @param VectorNumber Given IVT number\r
0a6f4824 54\r
bcecde14 55 @return cached interrupt vector address.\r
56**/\r
57EFI_STATUS\r
58RestoreCachedVectorAddress (\r
59 UINT8 VectorNumber\r
60 )\r
61{\r
62 UINT32 *Address;\r
63\r
aa5f60ae 64 Address = (UINT32 *) ((UINTN) IVT_BASE + VectorNumber * 4);\r
bcecde14 65 *Address = CachedVectorAddress[VectorNumber];\r
66 return EFI_SUCCESS;\r
67}\r
68\r
69/**\r
0a6f4824
LG
70 Print Undi loader table.\r
71\r
72 @param UndiLoaderStructure Point to Undi Loader table structure.\r
bcecde14 73\r
bcecde14 74**/\r
75VOID\r
76Print_Undi_Loader_Table (\r
77 VOID *UndiLoaderStructure\r
78 )\r
79{\r
80 UNDI_LOADER_T *DisplayPointer;\r
81\r
82 DisplayPointer = (UNDI_LOADER_T *) UndiLoaderStructure;\r
83\r
84 DEBUG ((DEBUG_NET, "Before Parsing the table contents, the table itself lives\n"));\r
85 DEBUG ((DEBUG_NET, "\tat the address 0x%X\n\r", (UINT32)(UINTN) UndiLoaderStructure));\r
86\r
87 DEBUG ((DEBUG_NET, "\n\rStatus = 0x%X\n\r", DisplayPointer->Status));\r
88 DEBUG ((DEBUG_NET, "\t_AX_= 0x%X\n\r", DisplayPointer->Ax));\r
89 DEBUG ((DEBUG_NET, "\t_BX_= 0x%X\n\r", DisplayPointer->Bx));\r
90 DEBUG ((DEBUG_NET, "\t_DX_= 0x%X\n\r", DisplayPointer->Dx));\r
91 DEBUG ((DEBUG_NET, "\t_DI_= 0x%X\n\r", DisplayPointer->Di));\r
92 DEBUG ((DEBUG_NET, "\t_ES_= 0x%X\n\r", DisplayPointer->Es));\r
93 DEBUG ((DEBUG_NET, "\tUNDI_DS= 0x%X\n\r", DisplayPointer->Undi_Ds));\r
94 DEBUG ((DEBUG_NET, "\tUNDI_CS= 0x%X\n\r", DisplayPointer->Undi_Cs));\r
95 DEBUG ((DEBUG_NET, "\tPXEptr:SEG= 0x%X\n\r", (UINT16) DisplayPointer->PXEptr.Segment));\r
96 DEBUG ((DEBUG_NET, "\tPXEptr:OFF= 0x%X\n\r", (UINT16) DisplayPointer->PXEptr.Offset));\r
97 DEBUG ((DEBUG_NET, "\tPXENVptr:SEG= 0x%X\n\r", (UINT16) DisplayPointer->PXENVptr.Segment));\r
98 DEBUG ((DEBUG_NET, "\tPXENVptr:OFF= 0x%X\n\r", (UINT16) DisplayPointer->PXENVptr.Offset));\r
99}\r
100\r
101/**\r
102 Simple table dumper. The ROMID table is necessary in order to effect\r
103 the "Early UNDI" trick. Herein, the UNDI layer can be loaded in the\r
0a6f4824 104 pre-boot phase without having to download a Network Boot Program\r
bcecde14 105 across the wire. It is required in the implementation in that we\r
106 are not using PXE.\r
107\r
108 @param RomIDStructure Point to RomID structure.\r
0a6f4824 109\r
bcecde14 110**/\r
111VOID\r
112Print_ROMID_Table (\r
113 IN VOID *RomIDStructure\r
114 )\r
115{\r
116 UNDI_ROMID_T *DisplayPointer;\r
117\r
118 DisplayPointer = (UNDI_ROMID_T *) RomIDStructure;\r
119\r
120 DEBUG ((DEBUG_NET, "Before Parsing the table contents, the table itself lives\n"));\r
121 DEBUG ((DEBUG_NET, "\tat the address 0x%X\n\r", (UINT32)(UINTN) RomIDStructure));\r
122\r
123 DEBUG (\r
124 (DEBUG_NET,\r
125 "\n\rROMID %c%c%c%c\n\r",\r
126 DisplayPointer->Signature[0],\r
127 DisplayPointer->Signature[1],\r
128 DisplayPointer->Signature[2],\r
129 DisplayPointer->Signature[3])\r
130 );\r
131\r
132 DEBUG (\r
133 (DEBUG_NET,\r
134 "Length of this structure in bytes = 0x%X\n\r",\r
135 DisplayPointer->StructLength)\r
136 );\r
137 DEBUG (\r
138 (DEBUG_NET,\r
139 "Use to make byte checksum of this structure == zero is = 0x%X\n\r",\r
140 DisplayPointer->StructCksum)\r
141 );\r
142 DEBUG (\r
143 (DEBUG_NET,\r
144 "Structure format revision number= 0x%X\n\r",\r
145 DisplayPointer->StructRev)\r
146 );\r
147 DEBUG (\r
148 (DEBUG_NET,\r
149 "API Revision number = 0x%X 0x%X 0x%X\n\r",\r
150 DisplayPointer->UNDI_Rev[0],\r
151 DisplayPointer->UNDI_Rev[1],\r
152 DisplayPointer->UNDI_Rev[2])\r
153 );\r
154 DEBUG (\r
155 (DEBUG_NET,\r
156 "Offset of UNDI loader routine in the option ROM image= 0x%X\n\r",\r
157 DisplayPointer->UNDI_Loader)\r
158 );\r
159 DEBUG ((DEBUG_NET, "From the data above, the absolute entry point of the UNDI loader is\n\r"));\r
160 DEBUG (\r
161 (DEBUG_NET,\r
162 "\tat address 0x%X\n\r",\r
163 (UINT32) (DisplayPointer->UNDI_Loader + ((UINT32) (UINTN)(DisplayPointer - 0x20) & 0xFFFF0)))\r
164 );\r
165 DEBUG ((DEBUG_NET, "Minimum stack segment size, in bytes,\n\r"));\r
166 DEBUG (\r
167 (DEBUG_NET,\r
168 "needed to load and run the UNDI= 0x%X \n\r",\r
169 DisplayPointer->StackSize)\r
170 );\r
171 DEBUG (\r
172 (DEBUG_NET,\r
173 "UNDI runtime code and data = 0x%X\n\r",\r
174 DisplayPointer->DataSize)\r
175 );\r
176 DEBUG (\r
177 (DEBUG_NET,\r
178 "Segment size = 0x%X\n\r",\r
179 DisplayPointer->CodeSize)\r
180 );\r
181 DEBUG (\r
182 (DEBUG_NET,\r
183 "\n\rBus Type = %c%c%c%c\n\r",\r
184 DisplayPointer->BusType[0],\r
185 DisplayPointer->BusType[1],\r
186 DisplayPointer->BusType[2],\r
187 DisplayPointer->BusType[3])\r
188 );\r
189}\r
190\r
191/**\r
192 Print PXE table.\r
193\r
194 @param PxeTable Point to PXE table structure\r
0a6f4824 195\r
bcecde14 196**/\r
197VOID\r
198Print_PXE_Table (\r
199 IN VOID* PxeTable\r
200 )\r
201{\r
202 PXE_T *DisplayPointer;\r
203 UINTN Index;\r
204 UINT8 *Dptr;\r
205\r
206 DisplayPointer = (PXE_T *) PxeTable;\r
207 Dptr = (UINT8 *) PxeTable;\r
208\r
209 DEBUG ((DEBUG_NET, "This is the PXE table at address 0x%X\n\r", PxeTable));\r
210\r
211 DEBUG ((DEBUG_NET, "A dump of the 0x%X bytes is:\n\r", sizeof (PXE_T)));\r
212\r
213 for (Index = 0; Index < sizeof (PXE_T); Index++) {\r
214 if ((Index % 0x10) == 0) {\r
215 DEBUG ((DEBUG_NET, "\t\n\r"));\r
216 }\r
217\r
218 DEBUG ((DEBUG_NET, " 0x%X ", *Dptr++));\r
219 }\r
220\r
221 DEBUG ((DEBUG_NET, "\n\r"));\r
222 DEBUG (\r
223 (DEBUG_NET,\r
224 "\n\rPXE %c%c%c%c%c%c\n\r",\r
225 DisplayPointer->Signature[0],\r
226 DisplayPointer->Signature[1],\r
227 DisplayPointer->Signature[2],\r
228 DisplayPointer->Signature[3])\r
229 );\r
230 DEBUG (\r
231 (DEBUG_NET,\r
232 "Length of this structure in bytes = 0x%X\n\r",\r
233 DisplayPointer->StructLength)\r
234 );\r
235 DEBUG (\r
236 (DEBUG_NET,\r
237 "Use to make byte checksum of this structure == zero is = 0x%X\n\r",\r
238 DisplayPointer->StructCksum)\r
239 );\r
240 DEBUG (\r
241 (DEBUG_NET,\r
242 "Structure format revision number = 0x%X\n\r",\r
243 DisplayPointer->StructRev)\r
244 );\r
245 DEBUG (\r
246 (DEBUG_NET,\r
247 "Must be zero, is equal to 0x%X\n\r",\r
248 DisplayPointer->Reserved1)\r
249 );\r
250 DEBUG (\r
251 (DEBUG_NET,\r
252 "Far pointer to UNDI ROMID = 0x%X\n\r",\r
253 (UINT32) (DisplayPointer->Undi.Segment << 0x4 | DisplayPointer->Undi.Offset))\r
254 );\r
255 DEBUG (\r
256 (DEBUG_NET,\r
257 "Far pointer to base-code ROMID = 0x%X\n\r",\r
258 (UINT32) ((DisplayPointer->Base.Segment << 0x04) | DisplayPointer->Base.Offset))\r
259 );\r
260 DEBUG ((DEBUG_NET, "16bit stack segment API entry point. This will be seg:off in \n\r"));\r
261 DEBUG (\r
262 (DEBUG_NET,\r
263 "real mode and sel:off in 16:16 protected mode = 0x%X:0x%X\n\r",\r
264 DisplayPointer->EntryPointSP.Segment,\r
265 DisplayPointer->EntryPointSP.Offset)\r
266 );\r
267\r
268 DEBUG ((DEBUG_NET, "\n\tNOTE to the implementer\n\tThis is the entry to use for call-ins\n\r"));\r
269\r
270 DEBUG ((DEBUG_NET, "32bit stack Segment API entry point. This will be sel:off. \n\r"));\r
271 DEBUG (\r
272 (DEBUG_NET,\r
273 "In real mode, sel == 0 = 0x%X:0x%X\n\r",\r
274 DisplayPointer->EntryPointESP.Segment,\r
275 DisplayPointer->EntryPointESP.Offset)\r
276 );\r
277 DEBUG (\r
278 (DEBUG_NET,\r
279 "Reserved2 value, must be zero, is equal to 0x%X\n\r",\r
280 DisplayPointer->Reserved2)\r
281 );\r
282 DEBUG (\r
283 (DEBUG_NET,\r
284 "Number of segment descriptors in this structur = 0x%X\n\r",\r
285 (UINT8) DisplayPointer->SegDescCnt)\r
286 );\r
287 DEBUG (\r
288 (DEBUG_NET,\r
289 "First segment descriptor in GDT assigned to PXE = 0x%X\n\r",\r
290 (UINT16) DisplayPointer->FirstSelector)\r
291 );\r
292 DEBUG (\r
293 (DEBUG_NET,\r
294 "The Stack is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",\r
295 (UINT16) DisplayPointer->Stack.Seg_Addr,\r
296 (UINT32) DisplayPointer->Stack.Phy_Addr,\r
297 (UINT16) DisplayPointer->Stack.Seg_Size)\r
298 );\r
299 DEBUG (\r
300 (DEBUG_NET,\r
301 "The UNDIData is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",\r
302 (UINT16) DisplayPointer->UNDIData.Seg_Addr,\r
303 (UINT32) DisplayPointer->UNDIData.Phy_Addr,\r
304 (UINT16) DisplayPointer->UNDIData.Seg_Size)\r
305 );\r
306 DEBUG (\r
307 (DEBUG_NET,\r
308 "The UNDICodeWrite is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",\r
309 (UINT16) DisplayPointer->UNDICode.Seg_Addr,\r
310 (UINT32) DisplayPointer->UNDICode.Phy_Addr,\r
311 (UINT16) DisplayPointer->UNDICode.Seg_Size)\r
312 );\r
313 DEBUG (\r
314 (DEBUG_NET,\r
315 "The Stack is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",\r
316 (UINT16) DisplayPointer->UNDICodeWrite.Seg_Addr,\r
317 (UINT32) DisplayPointer->UNDICodeWrite.Phy_Addr,\r
318 (UINT16) DisplayPointer->UNDICodeWrite.Seg_Size)\r
319 );\r
320 DEBUG (\r
321 (DEBUG_NET,\r
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",\r
323 (UINT16) DisplayPointer->BC_Data.Seg_Addr,\r
324 (UINT32) DisplayPointer->BC_Data.Phy_Addr,\r
325 (UINT16) DisplayPointer->BC_Data.Seg_Size)\r
326 );\r
327 DEBUG (\r
328 (DEBUG_NET,\r
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",\r
330 (UINT16) DisplayPointer->BC_Code.Seg_Addr,\r
331 (UINT32) DisplayPointer->BC_Code.Phy_Addr,\r
332 (UINT16) DisplayPointer->BC_Code.Seg_Size)\r
333 );\r
334 DEBUG (\r
335 (DEBUG_NET,\r
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",\r
337 (UINT16) DisplayPointer->BC_CodeWrite.Seg_Addr,\r
338 (UINT32) DisplayPointer->BC_CodeWrite.Phy_Addr,\r
339 (UINT16) DisplayPointer->BC_CodeWrite.Seg_Size)\r
340 );\r
341}\r
342\r
343/**\r
344 Print PXENV table.\r
345\r
346 @param PxenvTable Point to PXENV\r
0a6f4824 347\r
bcecde14 348**/\r
349VOID\r
350Print_PXENV_Table (\r
351 IN VOID *PxenvTable\r
352 )\r
353{\r
354 PXENV_T *DisplayPointer;\r
355\r
356 DisplayPointer = (PXENV_T *) PxenvTable;\r
357\r
358 DEBUG (\r
359 (DEBUG_NET,\r
360 "\n\rPXENV+ %c%c%c%c%c%c\n\r",\r
361 DisplayPointer->Signature[0],\r
362 DisplayPointer->Signature[1],\r
363 DisplayPointer->Signature[2],\r
364 DisplayPointer->Signature[3],\r
365 DisplayPointer->Signature[4],\r
366 DisplayPointer->Signature[5])\r
367 );\r
368\r
369 DEBUG (\r
370 (DEBUG_NET,\r
371 "PXE version number. \n\r\tLSB is minor version. \n\r\tMSB is major version = 0x%X\n\r",\r
372 DisplayPointer->Version)\r
373 );\r
374 DEBUG (\r
375 (DEBUG_NET,\r
376 "Length of PXE-2.0 Entry Point structure in bytes = 0x%X\n\r",\r
377 DisplayPointer->StructLength)\r
378 );\r
379 DEBUG ((DEBUG_NET, "Used to make structure checksum equal zero is now = 0x%X\n\r", DisplayPointer->StructCksum));\r
380 DEBUG ((DEBUG_NET, "Real mode API entry point segment:Offset. = 0x%X\n\r", DisplayPointer->RMEntry));\r
381 DEBUG ((DEBUG_NET, "Protected mode API entry point = 0x%X\n\r", DisplayPointer->PMEntryOff));\r
382 DEBUG ((DEBUG_NET, " segment:Offset. This will always be zero. \n\r"));\r
383 DEBUG ((DEBUG_NET, "Protected mode API calls = 0x%X\n\r", DisplayPointer->PMEntrySeg));\r
384 DEBUG ((DEBUG_NET, "Real mode stack segment = 0x%X\n\r", DisplayPointer->StackSeg));\r
385 DEBUG ((DEBUG_NET, "Stack segment size in bytes = 0x%X\n\r", DisplayPointer->StackSize));\r
386 DEBUG ((DEBUG_NET, "Real mode base-code code segment = 0x%X\n\r", DisplayPointer->BaseCodeSeg));\r
387 DEBUG ((DEBUG_NET, "Base-code code segment size = 0x%X\n\r", DisplayPointer->BaseCodeSize));\r
388 DEBUG ((DEBUG_NET, "Real mode base-code data segment = 0x%X\n\r", DisplayPointer->BaseDataSeg));\r
389 DEBUG ((DEBUG_NET, "Base-code data segment size = 0x%X\n\r", DisplayPointer->BaseDataSize));\r
390\r
391 DEBUG (\r
392 (DEBUG_NET,\r
393 "UNDI code segment size in bytes = 0x%X\n\r",\r
394 DisplayPointer->UNDICodeSize)\r
395 );\r
396 DEBUG (\r
397 (DEBUG_NET,\r
398 "Real mode segment:Offset pointer \n\r\tto PXE Runtime ID structure, address = 0x%X\n\r",\r
399 DisplayPointer->RuntimePtr)\r
400 );\r
401 DEBUG (\r
402 (\r
403 DEBUG_NET,\r
404 "From above, we have a linear address of 0x%X\n\r",\r
405 (UINT32)\r
406 (\r
407 ((UINT32)(UINTN)(DisplayPointer->RuntimePtr) & 0xFFFF) +\r
408 (((UINT32)(UINTN)(DisplayPointer->RuntimePtr) & 0xFFFF0000) >> 12)\r
409 )\r
410 )\r
411 );\r
412}\r
413\r
414\r
415#define OPTION_ROM_PTR ((OPTION_ROM_HEADER *) RomAddress)\r
416\r
417/**\r
418 If available, launch the BaseCode from a NIC option ROM.\r
419 This should install the !PXE and PXENV+ structures in memory for\r
420 subsequent use.\r
0a6f4824 421\r
bcecde14 422\r
423 @param SimpleNetworkDevice Simple network device instance\r
424 @param RomAddress The ROM base address for NIC rom.\r
0a6f4824
LG
425\r
426 @retval EFI_NOT_FOUND The check sum does not match\r
427 @retval EFI_NOT_FOUND Rom ID offset is wrong\r
428 @retval EFI_NOT_FOUND No Rom ID structure is found\r
bcecde14 429**/\r
430EFI_STATUS\r
431LaunchBaseCode (\r
432 EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,\r
433 UINTN RomAddress\r
434 )\r
435{\r
436 EFI_STATUS Status;\r
437 EFI_IA32_REGISTER_SET InOutRegs;\r
438 UNDI_ROMID_T *RomIdTableAddress;\r
439 UNDI_LOADER_T *UndiLoaderTable;\r
440 UINT16 Segment;\r
441 UINT16 *StackPointer;\r
442 VOID *Buffer;\r
443 UINTN Size;\r
444 PXE_T *Pxe;\r
445 UINT32 RomLength;\r
446 UINTN PciSegment;\r
447 UINTN Bus;\r
448 UINTN Device;\r
449 UINTN Function;\r
450 BOOLEAN ThunkFailed;\r
451\r
452 DEBUG ((DEBUG_NET, "\n\r\n\rCheck for the UNDI ROMID Signature\n\r"));\r
453\r
454 //\r
455 // paranoia - check structures for validity\r
456 //\r
457 RomLength = OPTION_ROM_PTR->ROMlength << 9;\r
458 if (CalculateSum8 ((UINT8 *) RomAddress, RomLength) != 0) {\r
459 DEBUG ((DEBUG_ERROR, "ROM Header Checksum Error\n\r"));\r
460 return EFI_NOT_FOUND;\r
461 }\r
462\r
463 RomIdTableAddress = (UNDI_ROMID_T *) (RomAddress + OPTION_ROM_PTR->PxeRomIdOffset);\r
464\r
aa5f60ae 465 if (((UINT32)OPTION_ROM_PTR->PxeRomIdOffset + RomIdTableAddress->StructLength) > RomLength) {\r
bcecde14 466 DEBUG ((DEBUG_ERROR, "ROM ID Offset Error\n\r"));\r
467 return EFI_NOT_FOUND;\r
468 }\r
469 //\r
470 // see if this is a header for an UNDI ROM ID structure (vs. a $BC$ or BUSD type)\r
471 //\r
472 if (CompareMem (RomIdTableAddress->Signature, UNDI_ROMID_SIG, sizeof RomIdTableAddress->Signature) != 0) {\r
473 DEBUG ((DEBUG_ERROR, "No ROM ID Structure found....\n\r"));\r
474 return EFI_NOT_FOUND;\r
475 //\r
476 // its not - keep looking\r
477 //\r
478 }\r
479\r
480 if (CalculateSum8 ((UINT8 *) RomIdTableAddress, RomIdTableAddress->StructLength) != 0) {\r
481 DEBUG ((DEBUG_ERROR, "ROM ID Checksum Error\n\r"));\r
482 return EFI_NOT_FOUND;\r
483 }\r
484\r
485 Print_ROMID_Table (RomIdTableAddress);\r
486\r
487 DEBUG (\r
488 (DEBUG_NET,\r
489 "The ROM ID is located at 0x%X\n\r",\r
490 RomIdTableAddress)\r
491 );\r
492\r
493 DEBUG (\r
494 (DEBUG_NET,\r
495 "With an UNDI Loader located at 0x%X\n\r",\r
496 RomAddress + RomIdTableAddress->UNDI_Loader)\r
497 );\r
498\r
499 //\r
500 // found an UNDI ROM ID structure\r
501 //\r
502 SimpleNetworkDevice->Nii.ImageAddr = RomAddress;\r
503 SimpleNetworkDevice->Nii.ImageSize = RomLength;\r
504 SimpleNetworkDevice->Nii.MajorVer = RomIdTableAddress->UNDI_Rev[2];\r
505 SimpleNetworkDevice->Nii.MinorVer = RomIdTableAddress->UNDI_Rev[1];\r
506\r
507 DEBUG ((DEBUG_NET, "Allocate area for the UNDI_LOADER_T structure\n\r"));\r
508 //\r
509 // Allocate 1 page below 1MB to put real mode thunk code in\r
510 //\r
511 // Undi Loader Table is a PXE Specification prescribed data structure\r
512 // that is used to transfer information into and out of the Undi layer.\r
513 // Note how it must be located below 1 MB.\r
514 //\r
515 SimpleNetworkDevice->UndiLoaderTablePages = EFI_SIZE_TO_PAGES (PARAGRAPH_SIZE + sizeof (UNDI_LOADER_T));\r
516 Status = BiosSnp16AllocatePagesBelowOneMb (\r
517 SimpleNetworkDevice->UndiLoaderTablePages,\r
518 &SimpleNetworkDevice->UndiLoaderTable\r
519 );\r
520 if (EFI_ERROR (Status)) {\r
521 DEBUG ((DEBUG_ERROR, "We had a failure in AllocatePages, status code = 0x%X\n", Status));\r
522 return EFI_OUT_OF_RESOURCES;\r
523 }\r
524\r
525 UndiLoaderTable = SimpleNetworkDevice->UndiLoaderTable;\r
526\r
527 DEBUG ((DEBUG_NET, "Allocate area for the real-mode stack whose sole purpose\n\r"));\r
528 DEBUG ((DEBUG_NET, "in life right now is to store a SEG:OFFSET combo pair that\n\r"));\r
529 DEBUG ((DEBUG_NET, "points to an Undi_Loader_t table structure\n\r"));\r
530\r
531 Size = 0x100;\r
532 Status = gBS->AllocatePool (EfiLoaderData, Size, &Buffer);\r
533 if (EFI_ERROR (Status)) {\r
534 return Status;\r
535 }\r
536 //\r
537 // Now we want to put a pointer to the Under Loader Table in our MemPage\r
538 // Buffer. This will be the argument stack for the call into the Undi Loader\r
539 //\r
540 StackPointer = (UINT16 *) Buffer;\r
541 *StackPointer++ = TO_OFFSET (UndiLoaderTable);\r
542 //\r
543 // push the OFFSET\r
544 //\r
545 *StackPointer++ = TO_SEGMENT (UndiLoaderTable);\r
546 //\r
547 // push the SEGMENT\r
548 //\r
549 StackPointer = (UINT16 *) Buffer;\r
550 //\r
551 // reset the stack pointer\r
552 //\r
553 DEBUG (\r
554 (DEBUG_NET,\r
555 "After the fixups, the stack pointer is 0x%X\n\r",\r
556 (UINT64)(UINTN) StackPointer)\r
557 );\r
558\r
559 //\r
560 // Allocate memory for the Deployed UNDI.\r
561 // The UNDI is essentially telling us how much space it needs, and\r
562 // it is up to the EFI driver to allocate sufficient, boot-time\r
563 // persistent resources for the call\r
564 //\r
565 SimpleNetworkDevice->DestinationDataSegmentPages = EFI_SIZE_TO_PAGES (RomIdTableAddress->DataSize);\r
566 Status = BiosSnp16AllocatePagesBelowOneMb (\r
567 SimpleNetworkDevice->DestinationDataSegmentPages,\r
568 &SimpleNetworkDevice->DestinationDataSegment\r
569 );\r
570 if (EFI_ERROR (Status)) {\r
571 DEBUG ((DEBUG_ERROR, "We had a failure in AllocatePages, status code = 0x%X\n", Status));\r
572 return Status;\r
573 }\r
574\r
575 UndiLoaderTable->Undi_Ds = (UINT16) ((UINTN) SimpleNetworkDevice->DestinationDataSegment >> 4);\r
576\r
577 //\r
578 // Allocate memory for the Deployed UNDI stack\r
579 // The UNDI is essentially telling us how much space it needs, and\r
580 // it is up to the EFI driver to allocate sufficient, boot-time\r
581 // persistent resources for the call\r
582 //\r
583 SimpleNetworkDevice->DestinationStackSegmentPages = EFI_SIZE_TO_PAGES (RomIdTableAddress->StackSize);\r
584 Status = BiosSnp16AllocatePagesBelowOneMb (\r
585 SimpleNetworkDevice->DestinationStackSegmentPages,\r
586 &SimpleNetworkDevice->DestinationStackSegment\r
587 );\r
588 if (EFI_ERROR (Status)) {\r
589 DEBUG ((DEBUG_ERROR, "We had a failure in AllocatePages, status code = 0x%X\n", Status));\r
590 return Status;\r
591 }\r
592 //\r
593 // Allocate memory for the Deployed UNDI.\r
594 // The UNDI is essentially telling us how much space it needs, and\r
595 // it is up to the EFI driver to allocate sufficient, boot-time\r
596 // persistent resources for the call\r
597 //\r
598 SimpleNetworkDevice->DestinationCodeSegmentPages = EFI_SIZE_TO_PAGES (RomIdTableAddress->CodeSize);\r
599 Status = BiosSnp16AllocatePagesBelowOneMb (\r
600 SimpleNetworkDevice->DestinationCodeSegmentPages,\r
601 &SimpleNetworkDevice->DestinationCodeSegment\r
602 );\r
603 if (EFI_ERROR (Status)) {\r
604 DEBUG ((DEBUG_ERROR, "We had a failure in AllocatePages, status code = 0x%X\n", Status));\r
605 return Status;\r
606 }\r
607\r
608 UndiLoaderTable->Undi_Cs = (UINT16) ((UINTN) SimpleNetworkDevice->DestinationCodeSegment >> 4);\r
609\r
610 //\r
611 // these are in the Input and Output Parameter to be sent to the UNDI Loader code\r
612 //\r
613 UndiLoaderTable->Status = 0xAA55;\r
614 //\r
615 // -------------------- Changed by Michael_Huang@3Com.com -----------------\r
616 // UndiLoaderTable->_AX is AX value when UNDI ROM is initialized by BIOS, it is the PCI bus device\r
617 // function of the NIC. Please refer to PXE Spec for detail info.\r
618 // old code is:\r
619 // UndiLoaderTable->Ax = 0x0;\r
620 // -----------------------------------------------------------------------\r
621 //\r
622 SimpleNetworkDevice->PciIo->GetLocation (\r
623 SimpleNetworkDevice->PciIo,\r
624 &PciSegment,\r
625 &Bus,\r
626 &Device,\r
627 &Function\r
628 );\r
629 UndiLoaderTable->Ax = (UINT16) ((Bus << 0x8) | (Device << 0x3) | (Function));\r
630 UndiLoaderTable->Bx = 0x0;\r
631 UndiLoaderTable->Dx = 0x0;\r
632 UndiLoaderTable->Di = 0x0;\r
633 UndiLoaderTable->Es = 0x0;\r
634\r
635 //\r
636 // set these OUT values to zero in order to ensure that\r
637 // uninitialized memory is not mistaken for display data\r
638 //\r
639 UndiLoaderTable->PXEptr.Offset = 0;\r
640 UndiLoaderTable->PXEptr.Segment = 0;\r
641 UndiLoaderTable->PXENVptr.Segment = 0;\r
642 UndiLoaderTable->PXENVptr.Offset = 0;\r
643\r
644 DEBUG (\r
645 (DEBUG_INIT,\r
646 "The NIC is located at Bus 0x%X, Device 0x%X, Function 0x%X\n\r",\r
647 Bus,\r
648 Device,\r
649 Function)\r
650 );\r
651\r
652 //\r
653 // These are the values that set up the ACTUAL IA32 machine state, whether in\r
654 // Real16 in EFI32 or the IVE for IA64\r
655 // register values are unused except for CS:IP and SS:SP\r
656 //\r
657 InOutRegs.X.AX = 0;\r
658 InOutRegs.X.BX = 0;\r
659 InOutRegs.X.CX = 0;\r
660 InOutRegs.X.DX = 0;\r
661 InOutRegs.X.SI = 0;\r
662 InOutRegs.X.DI = 0;\r
663 InOutRegs.X.BP = 0;\r
664 InOutRegs.X.DS = 0;\r
665 InOutRegs.X.ES = 0;\r
666 //\r
667 // just to be clean\r
668 //\r
669 DEBUG ((DEBUG_NET, "The way this game works is that the SS:SP +4 should point\n\r"));\r
670 DEBUG ((DEBUG_NET, "to the contents of the UndiLoaderTable\n\r"));\r
671 DEBUG (\r
672 (DEBUG_NET,\r
673 "The Undi Loader Table is at address = 0x%X\n\r",\r
674 (UINT32)(UINTN) UndiLoaderTable)\r
675 );\r
676 DEBUG (\r
677 (DEBUG_NET,\r
678 "The segment and offsets are 0x%X and 0x%X, resp\n",\r
679 TO_SEGMENT (UndiLoaderTable),\r
680 TO_OFFSET (UndiLoaderTable))\r
681 );\r
682\r
683 DEBUG (\r
684 (DEBUG_NET,\r
685 "The Linear Address of the UNDI Loader entry is 0x%X\n",\r
686 RomAddress + RomIdTableAddress->UNDI_Loader)\r
687 );\r
688\r
689 DEBUG (\r
690 (DEBUG_NET,\r
691 "The Address offset of the UNDI Loader entry is 0x%X\n",\r
692 RomIdTableAddress->UNDI_Loader)\r
693 );\r
694\r
695 DEBUG ((DEBUG_NET, "Before the call, we have...\n\r"));\r
696 Print_Undi_Loader_Table (UndiLoaderTable);\r
697\r
698 Segment = ((UINT16) (RShiftU64 (RomAddress, 4) & 0xFFFF));\r
699 DEBUG ((DEBUG_NET, "The Segment of the call is 0x%X\n\r", Segment));\r
700\r
701 //\r
702 // make the call into the UNDI Code\r
703 //\r
704 DEBUG ((DEBUG_INIT, "Make the call into the UNDI code now\n\r"));\r
705\r
706 DEBUG ((DEBUG_NET, "\nThe 20-BIt address of the Call, and the location \n\r"));\r
707 DEBUG ((DEBUG_NET, "\twhere we should be able to set a breakpoint is \n\r"));\r
708 DEBUG (\r
709 (DEBUG_NET,\r
710 "\t\t0x%X, from SEG:OFF 0x%X:0x%X\n\r\n\r",\r
711 Segment * 0x10 + RomIdTableAddress->UNDI_Loader,\r
712 Segment,\r
713 RomIdTableAddress->UNDI_Loader)\r
714 );\r
715\r
716 ThunkFailed = SimpleNetworkDevice->LegacyBios->FarCall86 (\r
717 SimpleNetworkDevice->LegacyBios,\r
718 Segment, // Input segment\r
719 (UINT16) RomIdTableAddress->UNDI_Loader, // Offset\r
720 &InOutRegs, // Ptr to Regs\r
721 Buffer, // Reference to Stack\r
722 Size // Size of the Stack\r
723 );\r
724 if (ThunkFailed) {\r
725 return EFI_ABORTED;\r
726 }\r
727\r
728 DEBUG (\r
729 (DEBUG_NET,\r
730 "The return code UndiLoaderTable->Status is = 0x%X\n\r",\r
731 UndiLoaderTable->Status)\r
732 );\r
733 DEBUG (\r
734 (DEBUG_NET,\r
735 "This error code should match eax, which is = 0x%X\n\r",\r
736 InOutRegs.X.AX)\r
737 );\r
738\r
9f6c5db2
EL
739 if ((UndiLoaderTable->Status != 0) || (InOutRegs.X.AX != PXENV_EXIT_SUCCESS)) {\r
740 DEBUG ((DEBUG_NET, "LaunchBaseCode exits with error, RomAddress = 0x%X\n\r", RomAddress));\r
741 return EFI_ABORTED;\r
742 }\r
743\r
bcecde14 744 DEBUG ((DEBUG_NET, "Now returned from the UNDI code\n\r"));\r
745\r
746 DEBUG ((DEBUG_NET, "After the call, we have...\n\r"));\r
747 Print_Undi_Loader_Table (UndiLoaderTable);\r
748\r
749 DEBUG ((DEBUG_NET, "Display the PXENV+ and !PXE tables exported by NIC\n\r"));\r
aa5f60ae
HW
750 Print_PXENV_Table ((VOID *)(((UINTN)UndiLoaderTable->PXENVptr.Segment << 4) | UndiLoaderTable->PXENVptr.Offset));\r
751 Print_PXE_Table ((VOID *)(((UINTN)UndiLoaderTable->PXEptr.Segment << 4) + UndiLoaderTable->PXEptr.Offset));\r
bcecde14 752\r
aa5f60ae 753 Pxe = (PXE_T *)(((UINTN)UndiLoaderTable->PXEptr.Segment << 4) + UndiLoaderTable->PXEptr.Offset);\r
bcecde14 754 SimpleNetworkDevice->Nii.Id = (UINT64)(UINTN) Pxe;\r
755\r
9f6c5db2
EL
756 gBS->FreePool (Buffer);\r
757\r
bcecde14 758 //\r
bcecde14 759 // paranoia - make sure a valid !PXE structure\r
760 //\r
761 if (CompareMem (Pxe->Signature, PXE_SIG, sizeof Pxe->Signature) != 0) {\r
762 DEBUG ((DEBUG_ERROR, "!PXE Structure not found....\n\r"));\r
763 return EFI_NOT_FOUND;\r
764 //\r
765 // its not - keep looking\r
766 //\r
767 }\r
768\r
769 if (CalculateSum8 ((UINT8 *) Pxe, Pxe->StructLength) != 0) {\r
770 DEBUG ((DEBUG_ERROR, "!PXE Checksum Error\n\r"));\r
771 return EFI_NOT_FOUND;\r
772 }\r
773\r
774 if (Pxe->StructLength < (UINT8 *) &Pxe->FirstSelector - (UINT8 *) Pxe->Signature) {\r
775 DEBUG ((DEBUG_ERROR, "!PXE Length Error\n\r"));\r
776 return EFI_NOT_FOUND;\r
777 }\r
778\r
779 if ((((UINTN) Pxe->Undi.Segment) << 4) + Pxe->Undi.Offset != (UINTN) RomIdTableAddress) {\r
780 DEBUG ((DEBUG_ERROR, "!PXE RomId Address Error\n\r"));\r
781 return EFI_NOT_FOUND;\r
782 }\r
783 //\r
784 // This is the magic to bind the global PXE interface\r
785 // This dirtiness is for non-protocol shrouded access\r
786 //\r
787 SimpleNetworkDevice->PxeEntrySegment = Pxe->EntryPointSP.Segment;\r
788\r
789 if (SimpleNetworkDevice->PxeEntrySegment == 0) {\r
790 DEBUG ((DEBUG_ERROR, "!PXE EntryPointSP segment Error\n\r"));\r
791 return EFI_NOT_FOUND;\r
792 }\r
793\r
794 SimpleNetworkDevice->PxeEntryOffset = Pxe->EntryPointSP.Offset;\r
795\r
796 DEBUG (\r
797 (\r
798 DEBUG_NET, "The entry point is 0x%X:0x%X\n\r", SimpleNetworkDevice->PxeEntrySegment, SimpleNetworkDevice->\r
799 PxeEntryOffset\r
800 )\r
801 );\r
802\r
803 return EFI_SUCCESS;\r
804}\r
805\r
806/**\r
807 Effect the Far Call into the PXE Layer\r
808\r
809 Note: When using a 32-bit stack segment do not push 32-bit words onto the stack. The PXE API\r
810 services will not work, unless there are three 16-bit parameters pushed onto the stack.\r
811 push DS ;Far pointer to parameter structure\r
812 push offset pxe_data_call_struct ;is pushed onto stack.\r
813 push Index ;UINT16 is pushed onto stack.\r
814 call dword ptr (s_PXE ptr es:[di]).EntryPointSP\r
0a6f4824 815 add sp, 6 ;Caller cleans up stack.\r
bcecde14 816\r
817 @param SimpleNetworkDevice Device instance for simple network\r
818 @param Table Point to parameter/retun value table for legacy far call\r
70d3fe9d 819 @param TableSize The size of parameter/return value table\r
bcecde14 820 @param CallIndex The index of legacy call.\r
0a6f4824
LG
821\r
822 @return EFI_STATUS\r
bcecde14 823**/\r
824EFI_STATUS\r
825MakePxeCall (\r
826 EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,\r
827 IN OUT VOID *Table,\r
828 IN UINTN TableSize,\r
829 IN UINT16 CallIndex\r
830 )\r
831{\r
832 EFI_STATUS Status;\r
833 EFI_IA32_REGISTER_SET InOutRegs;\r
834 UINT16 *BPtr;\r
835 VOID *Buffer;\r
836 UINTN Size;\r
837 VOID *MemPageAddress;\r
838 UINTN Index;\r
839 BOOLEAN ThunkFailed;\r
840\r
841 DEBUG ((DEBUG_NET, "MakePxeCall(CallIndex = %02x, Table = %X, TableSize = %d)\n", CallIndex, Table, TableSize));\r
842\r
843 if (SimpleNetworkDevice->PxeEntrySegment == 0 && SimpleNetworkDevice->PxeEntryOffset == 0) {\r
844 return EFI_DEVICE_ERROR;\r
845 }\r
846\r
847 Status = EFI_SUCCESS;\r
848\r
849 //\r
850 // Allocate a transient data structure for the argument table\r
851 // This table needs to have the input XXX_t structure copied into here.\r
852 // The PXE UNDI can only grab this table when it's below one-MB, and\r
853 // this implementation will not try to push this table on the stack\r
854 // (although this is a possible optimization path since EFI always allocates\r
855 // 4K as a minimum page size...............)\r
856 //\r
857 Status = BiosSnp16AllocatePagesBelowOneMb (\r
858 TableSize / EFI_PAGE_SIZE + 1,\r
859 &MemPageAddress\r
860 );\r
861 if (EFI_ERROR (Status)) {\r
862 DEBUG ((DEBUG_ERROR, "We had a failure in AllocatePages, status code = 0x%X\n", Status));\r
863 return Status;\r
864 }\r
865 //\r
866 // Copy the > 1MB pool table to a sub-1MB buffer\r
867 //\r
868 CopyMem (MemPageAddress, Table, TableSize);\r
869\r
870 //\r
871 // Allocate space for IA-32 register context\r
872 //\r
873 ZeroMem (&InOutRegs, sizeof (InOutRegs));\r
874 InOutRegs.X.ES = SimpleNetworkDevice->PxeEntrySegment;\r
875 InOutRegs.X.DI = SimpleNetworkDevice->PxeEntryOffset;\r
876\r
877 //\r
878 // The game here is to build the stack which will subsequently\r
879 // get copied down below 1 MB by the FarCall primitive.\r
880 // This is now our working stack\r
881 //\r
882 Size = 6;\r
883 Status = gBS->AllocatePool (\r
884 EfiRuntimeServicesData,\r
885 Size,\r
886 &Buffer\r
887 );\r
888 if (EFI_ERROR (Status)) {\r
889 return Status;\r
890 }\r
891\r
892 BPtr = (UINT16 *) Buffer;\r
893 *BPtr++ = CallIndex;\r
894 //\r
895 // SP + 2\r
896 //\r
897 *BPtr++ = TO_OFFSET (MemPageAddress);\r
898 *BPtr++ = TO_SEGMENT (MemPageAddress);\r
899\r
900 DEBUG ((DEBUG_NET, "State before FarCall86\n"));\r
901 DEBUG ((DEBUG_NET, "The Buffer is at 0x%X\n\r", Buffer));\r
902 BPtr = (UINT16 *) Buffer;\r
903 DEBUG ((DEBUG_NET, " Buffer = %04X %04X %04X", *BPtr, *(BPtr + 1), *(BPtr + 2)));\r
904 DEBUG ((DEBUG_NET, " MemPage = "));\r
905 for (Index = 0; Index < TableSize; Index++) {\r
906 DEBUG ((DEBUG_NET, " %02x", *((UINT8 *) MemPageAddress + Index)));\r
907 }\r
908\r
909 DEBUG ((DEBUG_NET, "\n"));\r
910\r
911 ThunkFailed = SimpleNetworkDevice->LegacyBios->FarCall86 (\r
912 SimpleNetworkDevice->LegacyBios,\r
913 SimpleNetworkDevice->PxeEntrySegment, // Input segment\r
914 SimpleNetworkDevice->PxeEntryOffset,\r
915 &InOutRegs, // Ptr to Regs\r
916 Buffer, // Reference to Stack\r
917 6 // Size of the Stack\r
918 );\r
919 if (ThunkFailed) {\r
920 return EFI_ABORTED;\r
921 }\r
922\r
923 DEBUG ((DEBUG_NET, "State after FarCall86\n"));\r
924 DEBUG ((DEBUG_NET, "The Buffer is at 0x%X\n\r", Buffer));\r
925 BPtr = (UINT16 *) Buffer;\r
926 DEBUG ((DEBUG_NET, " Buffer = %04X %04X %04X", *BPtr, *(BPtr + 1), *(BPtr + 2)));\r
927 DEBUG ((DEBUG_NET, " MemPage = "));\r
928 for (Index = 0; Index < TableSize; Index++) {\r
929 DEBUG ((DEBUG_NET, " %02x", *((UINT8 *) MemPageAddress + Index)));\r
930 }\r
931\r
932 DEBUG ((DEBUG_NET, "\n"));\r
933\r
934 //\r
935 // Copy the sub 1MB table to > 1MB table\r
936 //\r
937 CopyMem (Table, MemPageAddress, TableSize);\r
938\r
939 //\r
940 // For PXE UNDI call, AX contains the return status.\r
941 // Convert the PXE UNDI Status to EFI_STATUS type\r
942 //\r
943 if (InOutRegs.X.AX == PXENV_EXIT_SUCCESS) {\r
944 Status = EFI_SUCCESS;\r
945 } else {\r
946 Status = EFI_DEVICE_ERROR;\r
947 }\r
948 //\r
949 // Clean up house\r
950 //\r
951 gBS->FreePool (Buffer);\r
952 gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) MemPageAddress, TableSize / EFI_PAGE_SIZE + 1);\r
953\r
954 return Status;\r
955}\r