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