]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBootSupport.c
Print PCI Interrupt Line/Interrupt Pin registers before booting legacy OS.
[mirror_edk2.git] / IntelFrameworkModulePkg / Csm / LegacyBiosDxe / LegacyBootSupport.c
CommitLineData
bcecde14 1/** @file\r
2\r
3Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
4\r
5This program and the accompanying materials\r
6are licensed and made available under the terms and conditions\r
7of the BSD License which accompanies this distribution. The\r
8full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "LegacyBiosInterface.h"\r
17#include <IndustryStandard/Pci.h>\r
18\r
19#define BOOT_LEGACY_OS 0\r
20#define BOOT_EFI_OS 1\r
21#define BOOT_UNCONVENTIONAL_DEVICE 2\r
22\r
23UINT32 mLoadOptionsSize = 0;\r
24UINTN mBootMode = BOOT_LEGACY_OS;\r
25VOID *mLoadOptions = NULL;\r
26BBS_BBS_DEVICE_PATH *mBbsDevicePathPtr = NULL;\r
27BBS_BBS_DEVICE_PATH mBbsDevicePathNode;\r
28UDC_ATTRIBUTES mAttributes = { 0, 0, 0, 0 };\r
29UINTN mBbsEntry = 0;\r
30VOID *mBeerData = NULL;\r
31VOID *mServiceAreaData = NULL;\r
32UINT64 mLowWater = 0xffffffffffffffffULL;\r
33\r
34extern BBS_TABLE *mBbsTable;\r
35\r
36/**\r
37 Print the BBS Table.\r
38\r
39 @param BbsTable The BBS table.\r
40\r
41\r
42**/\r
43VOID\r
44PrintBbsTable (\r
45 IN BBS_TABLE *BbsTable\r
46 )\r
47{\r
48 UINT16 Index;\r
49 UINT16 SubIndex;\r
50 CHAR8 *String;\r
51\r
52 DEBUG ((EFI_D_INFO, "\n"));\r
53 DEBUG ((EFI_D_INFO, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs mfgs:mfgo dess:deso\n"));\r
54 DEBUG ((EFI_D_INFO, "=================================================================\n"));\r
55 for (Index = 0; Index < MAX_BBS_ENTRIES; Index++) {\r
56 //\r
57 // Filter\r
58 //\r
59 if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {\r
60 continue;\r
61 }\r
62\r
63 DEBUG ((\r
64 EFI_D_INFO,\r
65 " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x",\r
66 (UINTN) Index,\r
67 (UINTN) BbsTable[Index].BootPriority,\r
68 (UINTN) BbsTable[Index].Bus,\r
69 (UINTN) BbsTable[Index].Device,\r
70 (UINTN) BbsTable[Index].Function,\r
71 (UINTN) BbsTable[Index].Class,\r
72 (UINTN) BbsTable[Index].SubClass,\r
73 (UINTN) BbsTable[Index].DeviceType,\r
74 (UINTN) * (UINT16 *) &BbsTable[Index].StatusFlags\r
75 ));\r
76 DEBUG ((\r
77 EFI_D_INFO,\r
78 " %04x:%04x %04x:%04x %04x:%04x",\r
79 (UINTN) BbsTable[Index].BootHandlerSegment,\r
80 (UINTN) BbsTable[Index].BootHandlerOffset,\r
81 (UINTN) BbsTable[Index].MfgStringSegment,\r
82 (UINTN) BbsTable[Index].MfgStringOffset,\r
83 (UINTN) BbsTable[Index].DescStringSegment,\r
84 (UINTN) BbsTable[Index].DescStringOffset\r
85 ));\r
86\r
87 //\r
88 // Print DescString\r
89 //\r
90 String = (CHAR8 *)(UINTN)((BbsTable[Index].DescStringSegment << 4) + BbsTable[Index].DescStringOffset);\r
91 if (String != NULL) {\r
92 DEBUG ((EFI_D_INFO," ("));\r
93 for (SubIndex = 0; String[SubIndex] != 0; SubIndex++) {\r
94 DEBUG ((EFI_D_INFO, "%c", String[SubIndex]));\r
95 }\r
96 DEBUG ((EFI_D_INFO,")"));\r
97 }\r
98 DEBUG ((EFI_D_INFO,"\n"));\r
99 }\r
100\r
101 DEBUG ((EFI_D_INFO, "\n"));\r
102\r
103 return ;\r
104}\r
105\r
106/**\r
107 Print the BBS Table.\r
108\r
109 @param HddInfo The HddInfo table.\r
110\r
111\r
112**/\r
113VOID\r
114PrintHddInfo (\r
115 IN HDD_INFO *HddInfo\r
116 )\r
117{\r
118 UINTN Index;\r
119\r
120 DEBUG ((EFI_D_INFO, "\n"));\r
121 for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) {\r
122 DEBUG ((EFI_D_INFO, "Index - %04x\n", Index));\r
123 DEBUG ((EFI_D_INFO, " Status - %04x\n", (UINTN)HddInfo[Index].Status));\r
124 DEBUG ((EFI_D_INFO, " B/D/F - %02x/%02x/%02x\n", (UINTN)HddInfo[Index].Bus, (UINTN)HddInfo[Index].Device, (UINTN)HddInfo[Index].Function));\r
125 DEBUG ((EFI_D_INFO, " Command - %04x\n", HddInfo[Index].CommandBaseAddress));\r
126 DEBUG ((EFI_D_INFO, " Control - %04x\n", HddInfo[Index].ControlBaseAddress));\r
127 DEBUG ((EFI_D_INFO, " BusMaster - %04x\n", HddInfo[Index].BusMasterAddress));\r
128 DEBUG ((EFI_D_INFO, " HddIrq - %02x\n", HddInfo[Index].HddIrq));\r
129 DEBUG ((EFI_D_INFO, " IdentifyDrive[0].Raw[0] - %x\n", HddInfo[Index].IdentifyDrive[0].Raw[0]));\r
130 DEBUG ((EFI_D_INFO, " IdentifyDrive[1].Raw[0] - %x\n", HddInfo[Index].IdentifyDrive[1].Raw[0]));\r
131 }\r
132\r
133 DEBUG ((EFI_D_INFO, "\n"));\r
134\r
135 return ;\r
136}\r
137\r
7dad86fc
RN
138/**\r
139 Print the PCI Interrupt Line and Interrupt Pin registers.\r
140**/\r
141VOID\r
142PrintPciInterruptRegister (\r
143 VOID\r
144 )\r
145{\r
146 EFI_STATUS Status;\r
147 UINTN Index;\r
148 EFI_HANDLE *Handles;\r
149 UINTN HandleNum;\r
150 EFI_PCI_IO_PROTOCOL *PciIo;\r
151 UINT8 Interrupt[2];\r
152 UINTN Segment;\r
153 UINTN Bus;\r
154 UINTN Device;\r
155 UINTN Function;\r
156\r
157 gBS->LocateHandleBuffer (\r
158 ByProtocol,\r
159 &gEfiPciIoProtocolGuid,\r
160 NULL,\r
161 &HandleNum,\r
162 &Handles\r
163 );\r
164\r
165 Bus = 0;\r
166 Device = 0;\r
167 Function = 0;\r
168\r
169 DEBUG ((EFI_D_INFO, "\n"));\r
170 DEBUG ((EFI_D_INFO, " bb/dd/ff interrupt line interrupt pin\n"));\r
171 DEBUG ((EFI_D_INFO, "======================================\n"));\r
172 for (Index = 0; Index < HandleNum; Index++) {\r
173 Status = gBS->HandleProtocol (Handles[Index], &gEfiPciIoProtocolGuid, (VOID **) &PciIo);\r
174 if (!EFI_ERROR (Status)) {\r
175 Status = PciIo->Pci.Read (\r
176 PciIo,\r
177 EfiPciIoWidthUint8,\r
178 PCI_INT_LINE_OFFSET,\r
179 2,\r
180 Interrupt\r
181 );\r
182 }\r
183 if (!EFI_ERROR (Status)) {\r
184 Status = PciIo->GetLocation (\r
185 PciIo,\r
186 &Segment,\r
187 &Bus,\r
188 &Device,\r
189 &Function\r
190 );\r
191 }\r
192 if (!EFI_ERROR (Status)) {\r
193 DEBUG ((EFI_D_INFO, " %02x/%02x/%02x 0x%02x 0x%02x\n",\r
194 Bus, Device, Function, Interrupt[0], Interrupt[1]));\r
195 }\r
196 }\r
197 DEBUG ((EFI_D_INFO, "\n"));\r
198\r
199 if (Handles != NULL) {\r
200 FreePool (Handles);\r
201 }\r
202}\r
203\r
bcecde14 204/**\r
205 Identify drive data must be updated to actual parameters before boot.\r
206\r
207 @param IdentifyDriveData ATA Identify Data\r
208\r
209**/\r
210VOID\r
211UpdateIdentifyDriveData (\r
212 IN UINT8 *IdentifyDriveData\r
213 );\r
214\r
215/**\r
216 Update SIO data.\r
217\r
218 @param Private Legacy BIOS Instance data\r
219\r
220 @retval EFI_SUCCESS Removable media not present\r
221\r
222**/\r
223EFI_STATUS\r
224UpdateSioData (\r
225 IN LEGACY_BIOS_INSTANCE *Private\r
226 )\r
227{\r
228 EFI_STATUS Status;\r
229 UINTN Index;\r
230 UINTN Index1;\r
231 UINT8 LegacyInterrupts[16];\r
232 EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable;\r
233 UINTN RoutingTableEntries;\r
234 EFI_LEGACY_IRQ_PRIORITY_TABLE_ENTRY *IrqPriorityTable;\r
235 UINTN NumberPriorityEntries;\r
236 EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;\r
237 UINT8 HddIrq;\r
238 UINT16 LegacyInt;\r
239 UINT16 LegMask;\r
240 UINT32 Register;\r
241 UINTN HandleCount;\r
242 EFI_HANDLE *HandleBuffer;\r
243 EFI_ISA_IO_PROTOCOL *IsaIo;\r
244\r
245 LegacyInt = 0;\r
246 HandleBuffer = NULL;\r
247\r
248 EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;\r
249 LegacyBiosBuildSioData (Private);\r
250 SetMem (LegacyInterrupts, sizeof (LegacyInterrupts), 0);\r
251\r
252 //\r
253 // Create list of legacy interrupts.\r
254 //\r
255 for (Index = 0; Index < 4; Index++) {\r
256 LegacyInterrupts[Index] = EfiToLegacy16BootTable->SioData.Serial[Index].Irq;\r
257 }\r
258\r
259 for (Index = 4; Index < 7; Index++) {\r
260 LegacyInterrupts[Index] = EfiToLegacy16BootTable->SioData.Parallel[Index - 4].Irq;\r
261 }\r
262\r
263 LegacyInterrupts[7] = EfiToLegacy16BootTable->SioData.Floppy.Irq;\r
264\r
265 //\r
266 // Get Legacy Hdd IRQs. If native mode treat as PCI\r
267 //\r
268 for (Index = 0; Index < 2; Index++) {\r
269 HddIrq = EfiToLegacy16BootTable->HddInfo[Index].HddIrq;\r
270 if ((HddIrq != 0) && ((HddIrq == 15) || (HddIrq == 14))) {\r
271 LegacyInterrupts[Index + 8] = HddIrq;\r
272 }\r
273 }\r
274\r
275 Private->LegacyBiosPlatform->GetRoutingTable (\r
276 Private->LegacyBiosPlatform,\r
277 (VOID *) &RoutingTable,\r
278 &RoutingTableEntries,\r
279 NULL,\r
280 NULL,\r
281 (VOID **) &IrqPriorityTable,\r
282 &NumberPriorityEntries\r
283 );\r
284 //\r
285 // Remove legacy interrupts from the list of PCI interrupts available.\r
286 //\r
287 for (Index = 0; Index <= 0x0b; Index++) {\r
288 for (Index1 = 0; Index1 <= NumberPriorityEntries; Index1++) {\r
289 if (LegacyInterrupts[Index] != 0) {\r
290 LegacyInt = (UINT16) (LegacyInt | (1 << LegacyInterrupts[Index]));\r
291 if (LegacyInterrupts[Index] == IrqPriorityTable[Index1].Irq) {\r
292 IrqPriorityTable[Index1].Used = LEGACY_USED;\r
293 }\r
294 }\r
295 }\r
296 }\r
297\r
298 Private->Legacy8259->GetMask (\r
299 Private->Legacy8259,\r
300 &LegMask,\r
301 NULL,\r
302 NULL,\r
303 NULL\r
304 );\r
305\r
306 //\r
307 // Set SIO interrupts and disable mouse. Let mouse driver\r
308 // re-enable it.\r
309 //\r
310 LegMask = (UINT16) ((LegMask &~LegacyInt) | 0x1000);\r
311 Private->Legacy8259->SetMask (\r
312 Private->Legacy8259,\r
313 &LegMask,\r
314 NULL,\r
315 NULL,\r
316 NULL\r
317 );\r
318\r
319 //\r
320 // Disable mouse in keyboard controller\r
321 //\r
322 Register = 0xA7;\r
323 Status = gBS->LocateHandleBuffer (\r
324 ByProtocol,\r
325 &gEfiIsaIoProtocolGuid,\r
326 NULL,\r
327 &HandleCount,\r
328 &HandleBuffer\r
329 );\r
330 if (EFI_ERROR (Status)) {\r
331 return Status;\r
332 }\r
333\r
334 for (Index = 0; Index < HandleCount; Index++) {\r
335 Status = gBS->HandleProtocol (\r
336 HandleBuffer[Index],\r
337 &gEfiIsaIoProtocolGuid,\r
338 (VOID **) &IsaIo\r
339 );\r
340 ASSERT_EFI_ERROR (Status);\r
341 IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, 0x64, 1, &Register);\r
342\r
343 }\r
344\r
345 if (HandleBuffer != NULL) {\r
346 FreePool (HandleBuffer);\r
347 }\r
348\r
349 return EFI_SUCCESS;\r
350\r
351}\r
352\r
353/**\r
354 Identify drive data must be updated to actual parameters before boot.\r
355 This requires updating the checksum, if it exists.\r
356\r
357 @param IdentifyDriveData ATA Identify Data\r
358 @param Checksum checksum of the ATA Identify Data\r
359\r
360 @retval EFI_SUCCESS checksum calculated\r
361 @retval EFI_SECURITY_VIOLATION IdentifyData invalid\r
362\r
363**/\r
364EFI_STATUS\r
365CalculateIdentifyDriveChecksum (\r
366 IN UINT8 *IdentifyDriveData,\r
367 OUT UINT8 *Checksum\r
368 )\r
369{\r
370 UINTN Index;\r
371 UINT8 LocalChecksum;\r
372 LocalChecksum = 0;\r
373 *Checksum = 0;\r
374 if (IdentifyDriveData[510] != 0xA5) {\r
375 return EFI_SECURITY_VIOLATION;\r
376 }\r
377\r
378 for (Index = 0; Index < 512; Index++) {\r
379 LocalChecksum = (UINT8) (LocalChecksum + IdentifyDriveData[Index]);\r
380 }\r
381\r
382 *Checksum = LocalChecksum;\r
383 return EFI_SUCCESS;\r
384}\r
385\r
386\r
387/**\r
388 Identify drive data must be updated to actual parameters before boot.\r
389\r
390 @param IdentifyDriveData ATA Identify Data\r
391\r
392\r
393**/\r
394VOID\r
395UpdateIdentifyDriveData (\r
396 IN UINT8 *IdentifyDriveData\r
397 )\r
398{\r
399 UINT16 NumberCylinders;\r
400 UINT16 NumberHeads;\r
401 UINT16 NumberSectorsTrack;\r
402 UINT32 CapacityInSectors;\r
403 UINT8 OriginalChecksum;\r
404 UINT8 FinalChecksum;\r
405 EFI_STATUS Status;\r
406 ATAPI_IDENTIFY *ReadInfo;\r
407\r
408 //\r
409 // Status indicates if Integrity byte is correct. Checksum should be\r
410 // 0 if valid.\r
411 //\r
412 ReadInfo = (ATAPI_IDENTIFY *) IdentifyDriveData;\r
413 Status = CalculateIdentifyDriveChecksum (IdentifyDriveData, &OriginalChecksum);\r
414 if (OriginalChecksum != 0) {\r
415 Status = EFI_SECURITY_VIOLATION;\r
416 }\r
417 //\r
418 // If NumberCylinders = 0 then do data(Controller present but don drive attached).\r
419 //\r
420 NumberCylinders = ReadInfo->Raw[1];\r
421 if (NumberCylinders != 0) {\r
422 ReadInfo->Raw[54] = NumberCylinders;\r
423\r
424 NumberHeads = ReadInfo->Raw[3];\r
425 ReadInfo->Raw[55] = NumberHeads;\r
426\r
427 NumberSectorsTrack = ReadInfo->Raw[6];\r
428 ReadInfo->Raw[56] = NumberSectorsTrack;\r
429\r
430 //\r
431 // Copy Multisector info and set valid bit.\r
432 //\r
433 ReadInfo->Raw[59] = (UINT16) (ReadInfo->Raw[47] + 0x100);\r
434 CapacityInSectors = (UINT32) ((UINT32) (NumberCylinders) * (UINT32) (NumberHeads) * (UINT32) (NumberSectorsTrack));\r
435 ReadInfo->Raw[57] = (UINT16) (CapacityInSectors >> 16);\r
436 ReadInfo->Raw[58] = (UINT16) (CapacityInSectors & 0xffff);\r
437 if (Status == EFI_SUCCESS) {\r
438 //\r
439 // Forece checksum byte to 0 and get new checksum.\r
440 //\r
441 ReadInfo->Raw[255] &= 0xff;\r
442 CalculateIdentifyDriveChecksum (IdentifyDriveData, &FinalChecksum);\r
443\r
444 //\r
445 // Force new checksum such that sum is 0.\r
446 //\r
447 FinalChecksum = (UINT8) ((UINT8)0 - FinalChecksum);\r
448 ReadInfo->Raw[255] = (UINT16) (ReadInfo->Raw[255] | (FinalChecksum << 8));\r
449 }\r
450 }\r
451}\r
452\r
453/**\r
454 Identify drive data must be updated to actual parameters before boot.\r
455 Do for all drives.\r
456\r
457 @param Private Legacy BIOS Instance data\r
458\r
459\r
460**/\r
461VOID\r
462UpdateAllIdentifyDriveData (\r
463 IN LEGACY_BIOS_INSTANCE *Private\r
464 )\r
465{\r
466 UINTN Index;\r
467 HDD_INFO *HddInfo;\r
468\r
469 HddInfo = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo[0];\r
470\r
471 for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) {\r
472 //\r
473 // Each controller can have 2 devices. Update for each device\r
474 //\r
475 if ((HddInfo[Index].Status & HDD_MASTER_IDE) != 0) {\r
476 UpdateIdentifyDriveData ((UINT8 *) (&HddInfo[Index].IdentifyDrive[0].Raw[0]));\r
477 }\r
478\r
479 if ((HddInfo[Index].Status & HDD_SLAVE_IDE) != 0) {\r
480 UpdateIdentifyDriveData ((UINT8 *) (&HddInfo[Index].IdentifyDrive[1].Raw[0]));\r
481 }\r
482 }\r
483}\r
484\r
485/**\r
486 Enable ide controller. This gets disabled when LegacyBoot.c is about\r
487 to run the Option ROMs.\r
488\r
489 @param Private Legacy BIOS Instance data\r
490\r
491\r
492**/\r
493VOID\r
494EnableIdeController (\r
495 IN LEGACY_BIOS_INSTANCE *Private\r
496 )\r
497{\r
498 EFI_PCI_IO_PROTOCOL *PciIo;\r
499 EFI_STATUS Status;\r
500 EFI_HANDLE IdeController;\r
501 UINT8 ByteBuffer;\r
502 UINTN HandleCount;\r
503 EFI_HANDLE *HandleBuffer;\r
504\r
505 Status = Private->LegacyBiosPlatform->GetPlatformHandle (\r
506 Private->LegacyBiosPlatform,\r
507 EfiGetPlatformIdeHandle,\r
508 0,\r
509 &HandleBuffer,\r
510 &HandleCount,\r
511 NULL\r
512 );\r
513 if (!EFI_ERROR (Status)) {\r
514 IdeController = HandleBuffer[0];\r
515 Status = gBS->HandleProtocol (\r
516 IdeController,\r
517 &gEfiPciIoProtocolGuid,\r
518 (VOID **) &PciIo\r
519 );\r
520 ByteBuffer = 0x1f;\r
521 if (!EFI_ERROR (Status)) {\r
522 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x04, 1, &ByteBuffer);\r
523 }\r
524 }\r
525}\r
526\r
527\r
528/**\r
529 Enable ide controller. This gets disabled when LegacyBoot.c is about\r
530 to run the Option ROMs.\r
531\r
532 @param Private Legacy BIOS Instance data\r
533\r
534\r
535**/\r
536VOID\r
537EnableAllControllers (\r
538 IN LEGACY_BIOS_INSTANCE *Private\r
539 )\r
540{\r
541 UINTN HandleCount;\r
542 EFI_HANDLE *HandleBuffer;\r
543 UINTN Index;\r
544 EFI_PCI_IO_PROTOCOL *PciIo;\r
545 PCI_TYPE01 PciConfigHeader;\r
546 EFI_STATUS Status;\r
547\r
548 //\r
549 //\r
550 //\r
551 EnableIdeController (Private);\r
552\r
553 //\r
554 // Assumption is table is built from low bus to high bus numbers.\r
555 //\r
556 Status = gBS->LocateHandleBuffer (\r
557 ByProtocol,\r
558 &gEfiPciIoProtocolGuid,\r
559 NULL,\r
560 &HandleCount,\r
561 &HandleBuffer\r
562 );\r
563 ASSERT_EFI_ERROR (Status);\r
564\r
565 for (Index = 0; Index < HandleCount; Index++) {\r
566 Status = gBS->HandleProtocol (\r
567 HandleBuffer[Index],\r
568 &gEfiPciIoProtocolGuid,\r
569 (VOID **) &PciIo\r
570 );\r
571 ASSERT_EFI_ERROR (Status);\r
572\r
573 PciIo->Pci.Read (\r
574 PciIo,\r
575 EfiPciIoWidthUint32,\r
576 0,\r
577 sizeof (PciConfigHeader) / sizeof (UINT32),\r
578 &PciConfigHeader\r
579 );\r
580\r
581 //\r
582 // We do not enable PPB here. This is for HotPlug Consideration.\r
583 // The Platform HotPlug Driver is responsible for Padding enough hot plug\r
584 // resources. It is also responsible for enable this bridge. If it\r
585 // does not pad it. It will cause some early Windows fail to installation.\r
586 // If the platform driver does not pad resource for PPB, PPB should be in\r
587 // un-enabled state to let Windows know that this PPB is not configured by\r
588 // BIOS. So Windows will allocate default resource for PPB.\r
589 //\r
590 // The reason for why we enable the command register is:\r
591 // The CSM will use the IO bar to detect some IRQ status, if the command\r
592 // is disabled, the IO resource will be out of scope.\r
593 // For example:\r
594 // We installed a legacy IRQ handle for a PCI IDE controller. When IRQ\r
595 // comes up, the handle will check the IO space to identify is the\r
596 // controller generated the IRQ source.\r
597 // If the IO command is not enabled, the IRQ handler will has wrong\r
598 // information. It will cause IRQ storm when the correctly IRQ handler fails\r
599 // to run.\r
600 //\r
601 if (!(IS_PCI_VGA (&PciConfigHeader) ||\r
602 IS_PCI_OLD_VGA (&PciConfigHeader) ||\r
603 IS_PCI_IDE (&PciConfigHeader) ||\r
604 IS_PCI_P2P (&PciConfigHeader) ||\r
605 IS_PCI_P2P_SUB (&PciConfigHeader) ||\r
606 IS_PCI_LPC (&PciConfigHeader) )) {\r
607\r
608 PciConfigHeader.Hdr.Command |= 0x1f;\r
609\r
610 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 4, 1, &PciConfigHeader.Hdr.Command);\r
611 }\r
612 }\r
613}\r
614\r
615/**\r
616 The following routines are identical in operation, so combine\r
617 for code compaction:\r
618 EfiGetPlatformBinaryGetMpTable\r
619 EfiGetPlatformBinaryGetOemIntData\r
620 EfiGetPlatformBinaryGetOem32Data\r
621 EfiGetPlatformBinaryGetOem16Data\r
622\r
623 @param This Protocol instance pointer.\r
624 @param Id Table/Data identifier\r
625\r
626 @retval EFI_SUCCESS Success\r
627 @retval EFI_INVALID_PARAMETER Invalid ID\r
628 @retval EFI_OUT_OF_RESOURCES no resource to get data or table\r
629\r
630**/\r
631EFI_STATUS\r
632LegacyGetDataOrTable (\r
633 IN EFI_LEGACY_BIOS_PROTOCOL *This,\r
634 IN EFI_GET_PLATFORM_INFO_MODE Id\r
635 )\r
636{\r
637 VOID *Table;\r
638 UINT32 TablePtr;\r
639 UINTN TableSize;\r
640 UINTN Alignment;\r
641 UINTN Location;\r
642 EFI_STATUS Status;\r
643 EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;\r
644 EFI_COMPATIBILITY16_TABLE *Legacy16Table;\r
645 EFI_IA32_REGISTER_SET Regs;\r
646 LEGACY_BIOS_INSTANCE *Private;\r
647\r
648 Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r
649\r
650 LegacyBiosPlatform = Private->LegacyBiosPlatform;\r
651 Legacy16Table = Private->Legacy16Table;\r
652\r
653 //\r
654 // Phase 1 - get an address allocated in 16-bit code\r
655 //\r
656 while (TRUE) {\r
657 switch (Id) {\r
658 case EfiGetPlatformBinaryMpTable:\r
659 case EfiGetPlatformBinaryOemIntData:\r
660 case EfiGetPlatformBinaryOem32Data:\r
661 case EfiGetPlatformBinaryOem16Data:\r
662 {\r
663 Status = LegacyBiosPlatform->GetPlatformInfo (\r
664 LegacyBiosPlatform,\r
665 Id,\r
666 (VOID *) &Table,\r
667 &TableSize,\r
668 &Location,\r
669 &Alignment,\r
670 0,\r
671 0\r
672 );\r
673 DEBUG ((EFI_D_INFO, "LegacyGetDataOrTable - ID: %x, %r\n", (UINTN)Id, Status));\r
674 DEBUG ((EFI_D_INFO, " Table - %x, Size - %x, Location - %x, Alignment - %x\n", (UINTN)Table, (UINTN)TableSize, (UINTN)Location, (UINTN)Alignment));\r
675 break;\r
676 }\r
677\r
678 default:\r
679 {\r
680 return EFI_INVALID_PARAMETER;\r
681 }\r
682 }\r
683\r
684 if (EFI_ERROR (Status)) {\r
685 return Status;\r
686 }\r
687\r
688 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
689 Regs.X.AX = Legacy16GetTableAddress;\r
690 Regs.X.CX = (UINT16) TableSize;\r
691 Regs.X.BX = (UINT16) Location;\r
692 Regs.X.DX = (UINT16) Alignment;\r
693 Private->LegacyBios.FarCall86 (\r
694 This,\r
695 Private->Legacy16CallSegment,\r
696 Private->Legacy16CallOffset,\r
697 &Regs,\r
698 NULL,\r
699 0\r
700 );\r
701\r
702 if (Regs.X.AX != 0) {\r
703 DEBUG ((EFI_D_ERROR, "Table ID %x length insufficient\n", Id));\r
704 return EFI_OUT_OF_RESOURCES;\r
705 } else {\r
706 break;\r
707 }\r
708 }\r
709 //\r
710 // Phase 2 Call routine second time with address to allow address adjustment\r
711 //\r
712 Status = LegacyBiosPlatform->GetPlatformInfo (\r
713 LegacyBiosPlatform,\r
714 Id,\r
715 (VOID *) &Table,\r
716 &TableSize,\r
717 &Location,\r
718 &Alignment,\r
719 Regs.X.DS,\r
720 Regs.X.BX\r
721 );\r
722 switch (Id) {\r
723 case EfiGetPlatformBinaryMpTable:\r
724 {\r
725 Legacy16Table->MpTablePtr = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);\r
726 Legacy16Table->MpTableLength = (UINT32)TableSize;\r
727 DEBUG ((EFI_D_INFO, "MP table in legacy region - %x\n", (UINTN)Legacy16Table->MpTablePtr));\r
728 break;\r
729 }\r
730\r
731 case EfiGetPlatformBinaryOemIntData:\r
732 {\r
733\r
734 Legacy16Table->OemIntSegment = Regs.X.DS;\r
735 Legacy16Table->OemIntOffset = Regs.X.BX;\r
736 DEBUG ((EFI_D_INFO, "OemInt table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->OemIntSegment, (UINTN)Legacy16Table->OemIntOffset));\r
737 break;\r
738 }\r
739\r
740 case EfiGetPlatformBinaryOem32Data:\r
741 {\r
742 Legacy16Table->Oem32Segment = Regs.X.DS;\r
743 Legacy16Table->Oem32Offset = Regs.X.BX;\r
744 DEBUG ((EFI_D_INFO, "Oem32 table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->Oem32Segment, (UINTN)Legacy16Table->Oem32Offset));\r
745 break;\r
746 }\r
747\r
748 case EfiGetPlatformBinaryOem16Data:\r
749 {\r
750 //\r
751 // Legacy16Table->Oem16Segment = Regs.X.DS;\r
752 // Legacy16Table->Oem16Offset = Regs.X.BX;\r
753 DEBUG ((EFI_D_INFO, "Oem16 table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->Oem16Segment, (UINTN)Legacy16Table->Oem16Offset));\r
754 break;\r
755 }\r
756\r
757 default:\r
758 {\r
759 return EFI_INVALID_PARAMETER;\r
760 }\r
761 }\r
762\r
763 if (EFI_ERROR (Status)) {\r
764 return Status;\r
765 }\r
766 //\r
767 // Phase 3 Copy table to final location\r
768 //\r
769 TablePtr = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);\r
770\r
771 CopyMem (\r
772 (VOID *) (UINTN)TablePtr,\r
773 Table,\r
774 TableSize\r
775 );\r
776\r
777 return EFI_SUCCESS;\r
778}\r
779\r
780\r
781/**\r
782 Assign drive number to legacy HDD drives prior to booting an EFI\r
783 aware OS so the OS can access drives without an EFI driver.\r
784 Note: BBS compliant drives ARE NOT available until this call by\r
785 either shell or EFI.\r
786\r
787 @param This Protocol instance pointer.\r
788\r
789 @retval EFI_SUCCESS Drive numbers assigned\r
790\r
791**/\r
792EFI_STATUS\r
793GenericLegacyBoot (\r
794 IN EFI_LEGACY_BIOS_PROTOCOL *This\r
795 )\r
796{\r
797 EFI_STATUS Status;\r
798 LEGACY_BIOS_INSTANCE *Private;\r
799 EFI_IA32_REGISTER_SET Regs;\r
800 EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;\r
801 EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;\r
802 UINTN CopySize;\r
803 VOID *AcpiPtr;\r
804 HDD_INFO *HddInfo;\r
805 HDD_INFO *LocalHddInfo;\r
806 UINTN Index;\r
807 EFI_COMPATIBILITY16_TABLE *Legacy16Table;\r
808 UINT32 *BdaPtr;\r
809 UINT16 HddCount;\r
810 UINT16 BbsCount;\r
811 BBS_TABLE *LocalBbsTable;\r
812 UINT32 *BaseVectorMaster;\r
813 EFI_TIME BootTime;\r
814 UINT32 LocalTime;\r
815 EFI_HANDLE IdeController;\r
816 UINTN HandleCount;\r
817 EFI_HANDLE *HandleBuffer;\r
818 VOID *SmbiosTable;\r
819 VOID *AcpiTable;\r
820 UINTN ShadowAddress;\r
821 UINT32 Granularity;\r
822 EFI_TIMER_ARCH_PROTOCOL *Timer;\r
823 UINT64 TimerPeriod;\r
824\r
825 LocalHddInfo = NULL;\r
826 HddCount = 0;\r
827 BbsCount = 0;\r
828 LocalBbsTable = NULL;\r
829 TimerPeriod = 0;\r
830\r
831 Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r
832 DEBUG_CODE (\r
833 DEBUG ((EFI_D_ERROR, "Start of legacy boot\n"));\r
834 );\r
835\r
836 Legacy16Table = Private->Legacy16Table;\r
837 EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;\r
838 HddInfo = &EfiToLegacy16BootTable->HddInfo[0];\r
839\r
840 LegacyBiosPlatform = Private->LegacyBiosPlatform;\r
841\r
842 EfiToLegacy16BootTable->MajorVersion = EFI_TO_LEGACY_MAJOR_VERSION;\r
843 EfiToLegacy16BootTable->MinorVersion = EFI_TO_LEGACY_MINOR_VERSION;\r
844\r
845 //\r
846 // Before starting the Legacy boot check the system ticker.\r
847 //\r
848 Status = gBS->LocateProtocol (\r
849 &gEfiTimerArchProtocolGuid, \r
850 NULL,\r
851 (VOID **) &Timer\r
852 );\r
853 if (EFI_ERROR (Status)) {\r
854 return Status;\r
855 }\r
856\r
857 Status = Timer->GetTimerPeriod (\r
858 Timer,\r
859 &TimerPeriod\r
860 );\r
861 if (EFI_ERROR (Status)) {\r
862 return Status;\r
863 }\r
864\r
865 if (TimerPeriod != DEFAULT_LAGACY_TIMER_TICK_DURATION) {\r
866 Status = Timer->SetTimerPeriod (\r
867 Timer, \r
868 DEFAULT_LAGACY_TIMER_TICK_DURATION\r
869 );\r
870 if (EFI_ERROR (Status)) {\r
871 return Status;\r
872 }\r
873 }\r
874 \r
875 //\r
876 // If booting to a legacy OS then force HDD drives to the appropriate\r
877 // boot mode by calling GetIdeHandle.\r
878 // A reconnect -r can force all HDDs back to native mode.\r
879 //\r
880 IdeController = NULL;\r
881 if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {\r
882 Status = LegacyBiosPlatform->GetPlatformHandle (\r
883 Private->LegacyBiosPlatform,\r
884 EfiGetPlatformIdeHandle,\r
885 0,\r
886 &HandleBuffer,\r
887 &HandleCount,\r
888 NULL\r
889 );\r
890 if (!EFI_ERROR (Status)) {\r
891 IdeController = HandleBuffer[0];\r
892 } \r
893 }\r
894 //\r
895 // Unlock the Legacy BIOS region\r
896 //\r
897 Private->LegacyRegion->UnLock (\r
898 Private->LegacyRegion,\r
899 0xE0000,\r
900 0x20000,\r
901 &Granularity\r
902 );\r
903\r
904 //\r
905 // Reconstruct the Legacy16 boot memory map\r
906 //\r
907 LegacyBiosBuildE820 (Private, &CopySize);\r
908 if (CopySize > Private->Legacy16Table->E820Length) {\r
909 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
910 Regs.X.AX = Legacy16GetTableAddress;\r
911 Regs.X.CX = (UINT16) CopySize;\r
912 Private->LegacyBios.FarCall86 (\r
913 &Private->LegacyBios,\r
914 Private->Legacy16Table->Compatibility16CallSegment,\r
915 Private->Legacy16Table->Compatibility16CallOffset,\r
916 &Regs,\r
917 NULL,\r
918 0\r
919 );\r
920\r
921 Private->Legacy16Table->E820Pointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);\r
922 Private->Legacy16Table->E820Length = (UINT32) CopySize;\r
923 if (Regs.X.AX != 0) {\r
924 DEBUG ((EFI_D_ERROR, "Legacy16 E820 length insufficient\n"));\r
925 } else {\r
926 CopyMem (\r
927 (VOID *)(UINTN) Private->Legacy16Table->E820Pointer,\r
928 Private->E820Table,\r
929 CopySize\r
930 );\r
931 }\r
932 } else {\r
933 CopyMem (\r
934 (VOID *)(UINTN) Private->Legacy16Table->E820Pointer,\r
935 Private->E820Table,\r
936 CopySize\r
937 );\r
938 Private->Legacy16Table->E820Length = (UINT32) CopySize;\r
939 }\r
940 //\r
941 // Get SMBIOS and ACPI table pointers\r
942 //\r
943 SmbiosTable = NULL;\r
944 EfiGetSystemConfigurationTable (\r
945 &gEfiSmbiosTableGuid,\r
946 &SmbiosTable\r
947 );\r
948 //\r
949 // We do not ASSERT if SmbiosTable not found. It is possbile that a platform does not produce SmbiosTable.\r
950 //\r
951 if (SmbiosTable == NULL) {\r
952 DEBUG ((EFI_D_INFO, "Smbios table is not found!\n"));\r
953 }\r
954 EfiToLegacy16BootTable->SmbiosTable = (UINT32)(UINTN)SmbiosTable;\r
955\r
956 AcpiTable = NULL;\r
957 Status = EfiGetSystemConfigurationTable (\r
958 &gEfiAcpi20TableGuid,\r
959 &AcpiTable\r
960 );\r
961 if (EFI_ERROR (Status)) {\r
962 Status = EfiGetSystemConfigurationTable (\r
963 &gEfiAcpi10TableGuid,\r
964 &AcpiTable\r
965 );\r
966 }\r
967 //\r
968 // We do not ASSERT if AcpiTable not found. It is possbile that a platform does not produce AcpiTable.\r
969 //\r
970 if (AcpiTable == NULL) {\r
971 DEBUG ((EFI_D_INFO, "ACPI table is not found!\n"));\r
972 }\r
973 EfiToLegacy16BootTable->AcpiTable = (UINT32)(UINTN)AcpiTable;\r
974\r
975 //\r
976 // Get RSD Ptr table rev at offset 15 decimal\r
977 // Rev = 0 Length is 20 decimal\r
978 // Rev != 0 Length is UINT32 at offset 20 decimal\r
979 //\r
980 if (AcpiTable != NULL) {\r
981\r
982 AcpiPtr = AcpiTable;\r
983 if (*((UINT8 *) AcpiPtr + 15) == 0) {\r
984 CopySize = 20;\r
985 } else {\r
986 AcpiPtr = ((UINT8 *) AcpiPtr + 20);\r
987 CopySize = (*(UINT32 *) AcpiPtr);\r
988 }\r
989\r
990 CopyMem (\r
991 (VOID *)(UINTN) Private->Legacy16Table->AcpiRsdPtrPointer,\r
992 AcpiTable,\r
993 CopySize\r
994 );\r
995 }\r
996 //\r
997 // Make sure all PCI Interrupt Line register are programmed to match 8259\r
998 //\r
999 PciProgramAllInterruptLineRegisters (Private);\r
1000\r
1001 //\r
1002 // Unlock the Legacy BIOS region as PciProgramAllInterruptLineRegisters\r
1003 // can lock it.\r
1004 //\r
1005 Private->LegacyRegion->UnLock (\r
1006 Private->LegacyRegion,\r
1007 Private->BiosStart,\r
1008 Private->LegacyBiosImageSize,\r
1009 &Granularity\r
1010 );\r
1011\r
1012 //\r
1013 // Configure Legacy Device Magic\r
1014 //\r
1015 // Only do this code if booting legacy OS\r
1016 //\r
1017 if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {\r
1018 UpdateSioData (Private);\r
1019 }\r
1020 //\r
1021 // Setup BDA and EBDA standard areas before Legacy Boot\r
1022 //\r
1023 LegacyBiosCompleteBdaBeforeBoot (Private);\r
1024 LegacyBiosCompleteStandardCmosBeforeBoot (Private);\r
1025\r
1026 //\r
1027 // We must build IDE data, if it hasn't been done, before PciShadowRoms\r
1028 // to insure EFI drivers are connected.\r
1029 //\r
1030 LegacyBiosBuildIdeData (Private, &HddInfo, 1);\r
1031 UpdateAllIdentifyDriveData (Private);\r
1032\r
1033 //\r
1034 // Clear IO BAR, if IDE controller in legacy mode.\r
1035 //\r
1036 InitLegacyIdeController (IdeController);\r
1037\r
1038 //\r
1039 // Generate number of ticks since midnight for BDA. DOS requires this\r
1040 // for its time. We have to make assumptions as to how long following\r
1041 // code takes since after PciShadowRoms PciIo is gone. Place result in\r
1042 // 40:6C-6F\r
1043 //\r
1044 // Adjust value by 1 second.\r
1045 //\r
1046 gRT->GetTime (&BootTime, NULL);\r
1047 LocalTime = BootTime.Hour * 3600 + BootTime.Minute * 60 + BootTime.Second;\r
1048 LocalTime += 1;\r
1049\r
1050 //\r
1051 // Multiply result by 18.2 for number of ticks since midnight.\r
1052 // Use 182/10 to avoid floating point math.\r
1053 //\r
1054 LocalTime = (LocalTime * 182) / 10;\r
1055 BdaPtr = (UINT32 *) (UINTN)0x46C;\r
1056 *BdaPtr = LocalTime;\r
1057\r
1058 //\r
1059 // Shadow PCI ROMs. We must do this near the end since this will kick\r
1060 // of Native EFI drivers that may be needed to collect info for Legacy16\r
1061 //\r
1062 // WARNING: PciIo is gone after this call.\r
1063 //\r
1064 PciShadowRoms (Private);\r
1065\r
1066 //\r
1067 // Shadow PXE base code, BIS etc.\r
1068 //\r
1069 Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xc0000, 0x40000, &Granularity);\r
1070 ShadowAddress = Private->OptionRom;\r
1071 Private->LegacyBiosPlatform->PlatformHooks (\r
1072 Private->LegacyBiosPlatform,\r
1073 EfiPlatformHookShadowServiceRoms,\r
1074 0,\r
1075 0,\r
1076 &ShadowAddress,\r
1077 Legacy16Table,\r
1078 NULL\r
1079 );\r
1080 Private->OptionRom = (UINT32)ShadowAddress;\r
1081 //\r
1082 // Register Legacy SMI Handler\r
1083 //\r
1084 LegacyBiosPlatform->SmmInit (\r
1085 LegacyBiosPlatform,\r
1086 EfiToLegacy16BootTable\r
1087 );\r
1088\r
1089 //\r
1090 // Let platform code know the boot options\r
1091 //\r
1092 LegacyBiosGetBbsInfo (\r
1093 This,\r
1094 &HddCount,\r
1095 &LocalHddInfo,\r
1096 &BbsCount,\r
1097 &LocalBbsTable\r
1098 );\r
1099\r
7dad86fc
RN
1100 DEBUG_CODE (\r
1101 PrintPciInterruptRegister ();\r
1102 PrintBbsTable (LocalBbsTable);\r
1103 PrintHddInfo (LocalHddInfo);\r
1104 );\r
bcecde14 1105 //\r
1106 // If drive wasn't spun up then BuildIdeData may have found new drives.\r
1107 // Need to update BBS boot priority.\r
1108 //\r
1109 for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) {\r
1110 if ((LocalHddInfo[Index].IdentifyDrive[0].Raw[0] != 0) &&\r
1111 (LocalBbsTable[2 * Index + 1].BootPriority == BBS_IGNORE_ENTRY)\r
1112 ) {\r
1113 LocalBbsTable[2 * Index + 1].BootPriority = BBS_UNPRIORITIZED_ENTRY;\r
1114 }\r
1115\r
1116 if ((LocalHddInfo[Index].IdentifyDrive[1].Raw[0] != 0) &&\r
1117 (LocalBbsTable[2 * Index + 2].BootPriority == BBS_IGNORE_ENTRY)\r
1118 ) {\r
1119 LocalBbsTable[2 * Index + 2].BootPriority = BBS_UNPRIORITIZED_ENTRY;\r
1120 }\r
1121 }\r
1122\r
1123 Private->LegacyRegion->UnLock (\r
1124 Private->LegacyRegion,\r
1125 0xc0000,\r
1126 0x40000,\r
1127 &Granularity\r
1128 );\r
1129\r
1130 LegacyBiosPlatform->PrepareToBoot (\r
1131 LegacyBiosPlatform,\r
1132 mBbsDevicePathPtr,\r
1133 mBbsTable,\r
1134 mLoadOptionsSize,\r
1135 mLoadOptions,\r
1136 (VOID *) &Private->IntThunk->EfiToLegacy16BootTable\r
1137 );\r
1138\r
1139 //\r
1140 // If no boot device return to BDS\r
1141 //\r
1142 if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {\r
1143 for (Index = 0; Index < BbsCount; Index++){\r
1144 if ((LocalBbsTable[Index].BootPriority != BBS_DO_NOT_BOOT_FROM) &&\r
1145 (LocalBbsTable[Index].BootPriority != BBS_UNPRIORITIZED_ENTRY) &&\r
1146 (LocalBbsTable[Index].BootPriority != BBS_IGNORE_ENTRY)) {\r
1147 break;\r
1148 }\r
1149 }\r
1150 if (Index == BbsCount) {\r
1151 return EFI_DEVICE_ERROR;\r
1152 }\r
1153 }\r
1154 //\r
1155 // Let the Legacy16 code know the device path type for legacy boot\r
1156 //\r
1157 EfiToLegacy16BootTable->DevicePathType = mBbsDevicePathPtr->DeviceType;\r
1158\r
1159 //\r
1160 // Copy MP table, if it exists.\r
1161 //\r
1162 LegacyGetDataOrTable (This, EfiGetPlatformBinaryMpTable);\r
1163\r
1164 if (!Private->LegacyBootEntered) {\r
1165 //\r
1166 // Copy OEM INT Data, if it exists. Note: This code treats any data\r
1167 // as a bag of bits and knows nothing of the contents nor cares.\r
1168 // Contents are IBV specific.\r
1169 //\r
1170 LegacyGetDataOrTable (This, EfiGetPlatformBinaryOemIntData);\r
1171\r
1172 //\r
1173 // Copy OEM16 Data, if it exists.Note: This code treats any data\r
1174 // as a bag of bits and knows nothing of the contents nor cares.\r
1175 // Contents are IBV specific.\r
1176 //\r
1177 LegacyGetDataOrTable (This, EfiGetPlatformBinaryOem16Data);\r
1178\r
1179 //\r
1180 // Copy OEM32 Data, if it exists.Note: This code treats any data\r
1181 // as a bag of bits and knows nothing of the contents nor cares.\r
1182 // Contents are IBV specific.\r
1183 //\r
1184 LegacyGetDataOrTable (This, EfiGetPlatformBinaryOem32Data);\r
1185 }\r
1186\r
1187 //\r
1188 // Call into Legacy16 code to prepare for INT 19h\r
1189 //\r
1190 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
1191 Regs.X.AX = Legacy16PrepareToBoot;\r
1192\r
1193 //\r
1194 // Pass in handoff data\r
1195 //\r
1196 Regs.X.ES = EFI_SEGMENT ((UINTN)EfiToLegacy16BootTable);\r
1197 Regs.X.BX = EFI_OFFSET ((UINTN)EfiToLegacy16BootTable);\r
1198\r
1199 Private->LegacyBios.FarCall86 (\r
1200 This,\r
1201 Private->Legacy16CallSegment,\r
1202 Private->Legacy16CallOffset,\r
1203 &Regs,\r
1204 NULL,\r
1205 0\r
1206 );\r
1207\r
1208 if (Regs.X.AX != 0) {\r
1209 return EFI_DEVICE_ERROR;\r
1210 }\r
1211 //\r
1212 // Lock the Legacy BIOS region\r
1213 //\r
1214 Private->LegacyRegion->Lock (\r
1215 Private->LegacyRegion,\r
1216 0xc0000,\r
1217 0x40000,\r
1218 &Granularity\r
1219 );\r
1220 //\r
1221 // Lock attributes of the Legacy Region if chipset supports\r
1222 //\r
1223 Private->LegacyRegion->BootLock (\r
1224 Private->LegacyRegion,\r
1225 0xc0000,\r
1226 0x40000,\r
1227 &Granularity\r
1228 );\r
1229\r
1230 //\r
1231 // Call into Legacy16 code to do the INT 19h\r
1232 //\r
1233 EnableAllControllers (Private);\r
1234 if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {\r
1235 //\r
1236 // Signal all the events that are waiting on EVT_SIGNAL_LEGACY_BOOT\r
1237 //\r
1238 EfiSignalEventLegacyBoot ();\r
1239 DEBUG ((EFI_D_INFO, "Legacy INT19 Boot...\n"));\r
1240 //\r
1241 // Raise TPL to high level to disable CPU interrupts\r
1242 //\r
1243 gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
1244\r
1245 //\r
1246 // Put the 8259 into its legacy mode by reprogramming the vector bases\r
1247 //\r
1248 Private->Legacy8259->SetVectorBase (Private->Legacy8259, LEGACY_MODE_BASE_VECTOR_MASTER, LEGACY_MODE_BASE_VECTOR_SLAVE);\r
1249 //\r
1250 // PC History\r
1251 // The original PC used INT8-F for master PIC. Since these mapped over\r
1252 // processor exceptions TIANO moved the master PIC to INT68-6F.\r
1253 // We need to set these back to the Legacy16 unexpected interrupt(saved\r
1254 // in LegacyBios.c) since some OS see that these have values different from\r
1255 // what is expected and invoke them. Since the legacy OS corrupts EFI\r
1256 // memory, there is no handler for these interrupts and OS blows up.\r
1257 //\r
1258 // We need to save the TIANO values for the rare case that the Legacy16\r
1259 // code cannot boot but knows memory hasn't been destroyed.\r
1260 //\r
1261 // To compound the problem, video takes over one of these INTS and must be\r
1262 // be left.\r
1263 // @bug - determine if video hooks INT(in which case we must find new\r
1264 // set of TIANO vectors) or takes it over.\r
1265 //\r
1266 //\r
1267 BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);\r
1268 for (Index = 0; Index < 8; Index++) {\r
1269 Private->ThunkSavedInt[Index] = BaseVectorMaster[Index];\r
1270 if (Private->ThunkSeg == (UINT16) (BaseVectorMaster[Index] >> 16)) {\r
1271 BaseVectorMaster[Index] = (UINT32) (Private->BiosUnexpectedInt);\r
1272 }\r
1273 }\r
1274\r
1275 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
1276 Regs.X.AX = Legacy16Boot;\r
1277\r
1278 Private->LegacyBios.FarCall86 (\r
1279 This,\r
1280 Private->Legacy16CallSegment,\r
1281 Private->Legacy16CallOffset,\r
1282 &Regs,\r
1283 NULL,\r
1284 0\r
1285 );\r
1286\r
1287 BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);\r
1288 for (Index = 0; Index < 8; Index++) {\r
1289 BaseVectorMaster[Index] = Private->ThunkSavedInt[Index];\r
1290 }\r
1291 }\r
1292 Private->LegacyBootEntered = TRUE;\r
1293 if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {\r
1294 //\r
1295 // Should never return unless never passed control to 0:7c00(first stage\r
1296 // OS loader) and only then if no bootable device found.\r
1297 //\r
1298 return EFI_DEVICE_ERROR;\r
1299 } else {\r
1300 //\r
1301 // If boot to EFI then expect to return to caller\r
1302 //\r
1303 return EFI_SUCCESS;\r
1304 }\r
1305}\r
1306\r
1307\r
1308/**\r
1309 Assign drive number to legacy HDD drives prior to booting an EFI\r
1310 aware OS so the OS can access drives without an EFI driver.\r
1311 Note: BBS compliant drives ARE NOT available until this call by\r
1312 either shell or EFI.\r
1313\r
1314 @param This Protocol instance pointer.\r
1315 @param BbsCount Number of BBS_TABLE structures\r
1316 @param BbsTable List BBS entries\r
1317\r
1318 @retval EFI_SUCCESS Drive numbers assigned\r
1319\r
1320**/\r
1321EFI_STATUS\r
1322EFIAPI\r
1323LegacyBiosPrepareToBootEfi (\r
1324 IN EFI_LEGACY_BIOS_PROTOCOL *This,\r
1325 OUT UINT16 *BbsCount,\r
1326 OUT BBS_TABLE **BbsTable\r
1327 )\r
1328{\r
1329 EFI_STATUS Status;\r
1330 EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;\r
1331 LEGACY_BIOS_INSTANCE *Private;\r
1332\r
1333 Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r
1334 EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;\r
1335 mBootMode = BOOT_EFI_OS;\r
1336 mBbsDevicePathPtr = NULL;\r
1337 Status = GenericLegacyBoot (This);\r
1338 *BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable;\r
1339 *BbsCount = (UINT16) (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE));\r
1340 return Status;\r
1341}\r
1342\r
1343/**\r
1344 To boot from an unconventional device like parties and/or execute HDD diagnostics.\r
1345\r
1346 @param This Protocol instance pointer.\r
1347 @param Attributes How to interpret the other input parameters\r
1348 @param BbsEntry The 0-based index into the BbsTable for the parent\r
1349 device.\r
1350 @param BeerData Pointer to the 128 bytes of ram BEER data.\r
1351 @param ServiceAreaData Pointer to the 64 bytes of raw Service Area data. The\r
1352 caller must provide a pointer to the specific Service\r
1353 Area and not the start all Service Areas.\r
1354\r
1355 @retval EFI_INVALID_PARAMETER if error. Does NOT return if no error.\r
1356\r
1357***/\r
1358EFI_STATUS\r
1359EFIAPI\r
1360LegacyBiosBootUnconventionalDevice (\r
1361 IN EFI_LEGACY_BIOS_PROTOCOL *This,\r
1362 IN UDC_ATTRIBUTES Attributes,\r
1363 IN UINTN BbsEntry,\r
1364 IN VOID *BeerData,\r
1365 IN VOID *ServiceAreaData\r
1366 )\r
1367{\r
1368 EFI_STATUS Status;\r
1369 EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;\r
1370 LEGACY_BIOS_INSTANCE *Private;\r
1371 UD_TABLE *UcdTable;\r
1372 UINTN Index;\r
1373 UINT16 BootPriority;\r
1374 BBS_TABLE *BbsTable;\r
1375\r
1376 BootPriority = 0;\r
1377 Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r
1378 mBootMode = BOOT_UNCONVENTIONAL_DEVICE;\r
1379 mBbsDevicePathPtr = &mBbsDevicePathNode;\r
1380 mAttributes = Attributes;\r
1381 mBbsEntry = BbsEntry;\r
1382 mBeerData = BeerData, mServiceAreaData = ServiceAreaData;\r
1383\r
1384 EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;\r
1385\r
1386 //\r
1387 // Do input parameter checking\r
1388 //\r
1389 if ((Attributes.DirectoryServiceValidity == 0) &&\r
1390 (Attributes.RabcaUsedFlag == 0) &&\r
1391 (Attributes.ExecuteHddDiagnosticsFlag == 0)\r
1392 ) {\r
1393 return EFI_INVALID_PARAMETER;\r
1394 }\r
1395\r
1396 if (((Attributes.DirectoryServiceValidity != 0) && (ServiceAreaData == NULL)) ||\r
1397 (((Attributes.DirectoryServiceValidity | Attributes.RabcaUsedFlag) != 0) && (BeerData == NULL))\r
1398 ) {\r
1399 return EFI_INVALID_PARAMETER;\r
1400 }\r
1401\r
1402 UcdTable = (UD_TABLE *) AllocatePool (\r
1403 sizeof (UD_TABLE)\r
1404 );\r
1405 if (NULL == UcdTable) {\r
1406 return EFI_OUT_OF_RESOURCES;\r
1407 }\r
1408\r
1409 EfiToLegacy16BootTable->UnconventionalDeviceTable = (UINT32)(UINTN)UcdTable;\r
1410 UcdTable->Attributes = Attributes;\r
1411 UcdTable->BbsTableEntryNumberForParentDevice = (UINT8) BbsEntry;\r
1412 //\r
1413 // Force all existing BBS entries to DoNotBoot. This allows 16-bit CSM\r
1414 // to assign drive numbers but bot boot from. Only newly created entries\r
1415 // will be valid.\r
1416 //\r
1417 BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable;\r
1418 for (Index = 0; Index < EfiToLegacy16BootTable->NumberBbsEntries; Index++) {\r
1419 BbsTable[Index].BootPriority = BBS_DO_NOT_BOOT_FROM;\r
1420 }\r
1421 //\r
1422 // If parent is onboard IDE then assign controller & device number\r
1423 // else they are 0.\r
1424 //\r
1425 if (BbsEntry < MAX_IDE_CONTROLLER * 2) {\r
1426 UcdTable->DeviceNumber = (UINT8) ((BbsEntry - 1) % 2);\r
1427 }\r
1428\r
1429 if (BeerData != NULL) {\r
1430 CopyMem (\r
1431 (VOID *) UcdTable->BeerData,\r
1432 BeerData,\r
1433 (UINTN) 128\r
1434 );\r
1435 }\r
1436\r
1437 if (ServiceAreaData != NULL) {\r
1438 CopyMem (\r
1439 (VOID *) UcdTable->ServiceAreaData,\r
1440 ServiceAreaData,\r
1441 (UINTN) 64\r
1442 );\r
1443 }\r
1444 //\r
1445 // For each new entry do the following:\r
1446 // 1. Increment current number of BBS entries\r
1447 // 2. Copy parent entry to new entry.\r
1448 // 3. Zero out BootHandler Offset & segment\r
1449 // 4. Set appropriate device type. BEV(0x80) for HDD diagnostics\r
1450 // and Floppy(0x01) for PARTIES boot.\r
1451 // 5. Assign new priority.\r
1452 //\r
1453 if ((Attributes.ExecuteHddDiagnosticsFlag) != 0) {\r
1454 EfiToLegacy16BootTable->NumberBbsEntries += 1;\r
1455\r
1456 CopyMem (\r
1457 (VOID *) &BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority,\r
1458 (VOID *) &BbsTable[BbsEntry].BootPriority,\r
1459 sizeof (BBS_TABLE)\r
1460 );\r
1461\r
1462 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerOffset = 0;\r
1463 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerSegment = 0;\r
1464 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].DeviceType = 0x80;\r
1465\r
1466 UcdTable->BbsTableEntryNumberForHddDiag = (UINT8) (EfiToLegacy16BootTable->NumberBbsEntries - 1);\r
1467\r
1468 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority = BootPriority;\r
1469 BootPriority += 1;\r
1470\r
1471 //\r
1472 // Set device type as BBS_TYPE_DEV for PARTIES diagnostic\r
1473 //\r
1474 mBbsDevicePathNode.DeviceType = BBS_TYPE_BEV;\r
1475 }\r
1476\r
1477 if (((Attributes.DirectoryServiceValidity | Attributes.RabcaUsedFlag)) != 0) {\r
1478 EfiToLegacy16BootTable->NumberBbsEntries += 1;\r
1479 CopyMem (\r
1480 (VOID *) &BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority,\r
1481 (VOID *) &BbsTable[BbsEntry].BootPriority,\r
1482 sizeof (BBS_TABLE)\r
1483 );\r
1484\r
1485 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerOffset = 0;\r
1486 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerSegment = 0;\r
1487 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].DeviceType = 0x01;\r
1488 UcdTable->BbsTableEntryNumberForBoot = (UINT8) (EfiToLegacy16BootTable->NumberBbsEntries - 1);\r
1489 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority = BootPriority;\r
1490\r
1491 //\r
1492 // Set device type as BBS_TYPE_FLOPPY for PARTIES boot as floppy\r
1493 //\r
1494 mBbsDevicePathNode.DeviceType = BBS_TYPE_FLOPPY;\r
1495 }\r
1496 //\r
1497 // Build the BBS Device Path for this boot selection\r
1498 //\r
1499 mBbsDevicePathNode.Header.Type = BBS_DEVICE_PATH;\r
1500 mBbsDevicePathNode.Header.SubType = BBS_BBS_DP;\r
1501 SetDevicePathNodeLength (&mBbsDevicePathNode.Header, sizeof (BBS_BBS_DEVICE_PATH));\r
1502 mBbsDevicePathNode.StatusFlag = 0;\r
1503 mBbsDevicePathNode.String[0] = 0;\r
1504\r
1505 Status = GenericLegacyBoot (This);\r
1506 return Status;\r
1507}\r
1508\r
1509/**\r
1510 Attempt to legacy boot the BootOption. If the EFI contexted has been\r
1511 compromised this function will not return.\r
1512\r
1513 @param This Protocol instance pointer.\r
1514 @param BbsDevicePath EFI Device Path from BootXXXX variable.\r
1515 @param LoadOptionsSize Size of LoadOption in size.\r
1516 @param LoadOptions LoadOption from BootXXXX variable\r
1517\r
1518 @retval EFI_SUCCESS Removable media not present\r
1519\r
1520**/\r
1521EFI_STATUS\r
1522EFIAPI\r
1523LegacyBiosLegacyBoot (\r
1524 IN EFI_LEGACY_BIOS_PROTOCOL *This,\r
1525 IN BBS_BBS_DEVICE_PATH *BbsDevicePath,\r
1526 IN UINT32 LoadOptionsSize,\r
1527 IN VOID *LoadOptions\r
1528 )\r
1529{\r
1530 EFI_STATUS Status;\r
1531\r
1532 mBbsDevicePathPtr = BbsDevicePath;\r
1533 mLoadOptionsSize = LoadOptionsSize;\r
1534 mLoadOptions = LoadOptions;\r
1535 mBootMode = BOOT_LEGACY_OS;\r
1536 Status = GenericLegacyBoot (This);\r
1537\r
1538 return Status;\r
1539}\r
1540\r
1541/**\r
1542 Convert EFI Memory Type to E820 Memory Type.\r
1543\r
1544 @param Type EFI Memory Type\r
1545\r
1546 @return ACPI Memory Type for EFI Memory Type\r
1547\r
1548**/\r
1549EFI_ACPI_MEMORY_TYPE\r
1550EfiMemoryTypeToE820Type (\r
1551 IN UINT32 Type\r
1552 )\r
1553{\r
1554 switch (Type) {\r
1555 case EfiLoaderCode:\r
1556 case EfiLoaderData:\r
1557 case EfiBootServicesCode:\r
1558 case EfiBootServicesData:\r
1559 case EfiConventionalMemory:\r
1560 case EfiRuntimeServicesCode:\r
1561 case EfiRuntimeServicesData:\r
1562 return EfiAcpiAddressRangeMemory;\r
1563\r
1564 case EfiACPIReclaimMemory:\r
1565 return EfiAcpiAddressRangeACPI;\r
1566\r
1567 case EfiACPIMemoryNVS:\r
1568 return EfiAcpiAddressRangeNVS;\r
1569\r
1570 //\r
1571 // All other types map to reserved.\r
1572 // Adding the code just waists FLASH space.\r
1573 //\r
1574 // case EfiReservedMemoryType:\r
1575 // case EfiUnusableMemory:\r
1576 // case EfiMemoryMappedIO:\r
1577 // case EfiMemoryMappedIOPortSpace:\r
1578 // case EfiPalCode:\r
1579 //\r
1580 default:\r
1581 return EfiAcpiAddressRangeReserved;\r
1582 }\r
1583}\r
1584\r
1585/**\r
1586 Build the E820 table.\r
1587\r
1588 @param Private Legacy BIOS Instance data\r
1589 @param Size Size of E820 Table\r
1590\r
1591 @retval EFI_SUCCESS It should always work.\r
1592\r
1593**/\r
1594EFI_STATUS\r
1595LegacyBiosBuildE820 (\r
1596 IN LEGACY_BIOS_INSTANCE *Private,\r
1597 OUT UINTN *Size\r
1598 )\r
1599{\r
1600 EFI_STATUS Status;\r
1601 EFI_E820_ENTRY64 *E820Table;\r
1602 EFI_MEMORY_DESCRIPTOR *EfiMemoryMap;\r
1603 EFI_MEMORY_DESCRIPTOR *EfiMemoryMapEnd;\r
1604 EFI_MEMORY_DESCRIPTOR *EfiEntry;\r
1605 EFI_MEMORY_DESCRIPTOR *NextEfiEntry;\r
1606 EFI_MEMORY_DESCRIPTOR TempEfiEntry;\r
1607 UINTN EfiMemoryMapSize;\r
1608 UINTN EfiMapKey;\r
1609 UINTN EfiDescriptorSize;\r
1610 UINT32 EfiDescriptorVersion;\r
1611 UINTN Index;\r
1612 EFI_PEI_HOB_POINTERS Hob;\r
1613 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;\r
1614 UINTN TempIndex;\r
1615 UINTN IndexSort;\r
1616 UINTN TempNextIndex;\r
1617 EFI_E820_ENTRY64 TempE820;\r
1618 EFI_ACPI_MEMORY_TYPE TempType;\r
1619 BOOLEAN ChangedFlag;\r
1620 UINTN Above1MIndex;\r
1621 UINT64 MemoryBlockLength;\r
1622\r
1623 E820Table = (EFI_E820_ENTRY64 *) Private->E820Table;\r
1624\r
1625 //\r
1626 // Get the EFI memory map.\r
1627 //\r
1628 EfiMemoryMapSize = 0;\r
1629 EfiMemoryMap = NULL;\r
1630 Status = gBS->GetMemoryMap (\r
1631 &EfiMemoryMapSize,\r
1632 EfiMemoryMap,\r
1633 &EfiMapKey,\r
1634 &EfiDescriptorSize,\r
1635 &EfiDescriptorVersion\r
1636 );\r
1637 ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
1638\r
1639 do {\r
1640 //\r
1641 // Use size returned back plus 1 descriptor for the AllocatePool.\r
1642 // We don't just multiply by 2 since the "for" loop below terminates on\r
1643 // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwize\r
1644 // we process bogus entries and create bogus E820 entries.\r
1645 //\r
1646 EfiMemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (EfiMemoryMapSize);\r
1647 ASSERT (EfiMemoryMap != NULL);\r
1648 Status = gBS->GetMemoryMap (\r
1649 &EfiMemoryMapSize,\r
1650 EfiMemoryMap,\r
1651 &EfiMapKey,\r
1652 &EfiDescriptorSize,\r
1653 &EfiDescriptorVersion\r
1654 );\r
1655 if (EFI_ERROR (Status)) {\r
1656 FreePool (EfiMemoryMap);\r
1657 }\r
1658 } while (Status == EFI_BUFFER_TOO_SMALL);\r
1659\r
1660 ASSERT_EFI_ERROR (Status);\r
1661\r
1662 //\r
1663 // Punch in the E820 table for memory less than 1 MB.\r
1664 // Assume ZeroMem () has been done on data structure.\r
1665 //\r
1666 //\r
1667 // First entry is 0 to (640k - EBDA)\r
1668 //\r
1669 E820Table[0].BaseAddr = 0;\r
1670 E820Table[0].Length = (UINT64) ((*(UINT16 *) (UINTN)0x40E) << 4);\r
1671 E820Table[0].Type = EfiAcpiAddressRangeMemory;\r
1672\r
1673 //\r
1674 // Second entry is (640k - EBDA) to 640k\r
1675 //\r
1676 E820Table[1].BaseAddr = E820Table[0].Length;\r
1677 E820Table[1].Length = (UINT64) ((640 * 1024) - E820Table[0].Length);\r
1678 E820Table[1].Type = EfiAcpiAddressRangeReserved;\r
1679\r
1680 //\r
1681 // Third Entry is legacy BIOS\r
1682 // DO NOT CLAIM region from 0xA0000-0xDFFFF. OS can use free areas\r
1683 // to page in memory under 1MB.\r
1684 // Omit region from 0xE0000 to start of BIOS, if any. This can be\r
1685 // used for a multiple reasons including OPROMS.\r
1686 //\r
1687\r
1688 //\r
1689 // The CSM binary image size is not the actually size that CSM binary used,\r
1690 // to avoid memory corrupt, we declare the 0E0000 - 0FFFFF is used by CSM binary.\r
1691 //\r
1692 E820Table[2].BaseAddr = 0xE0000;\r
1693 E820Table[2].Length = 0x20000;\r
1694 E820Table[2].Type = EfiAcpiAddressRangeReserved;\r
1695\r
1696 Above1MIndex = 2;\r
1697\r
1698 //\r
1699 // Process the EFI map to produce E820 map;\r
1700 //\r
1701\r
1702 //\r
1703 // Sort memory map from low to high\r
1704 //\r
1705 EfiEntry = EfiMemoryMap;\r
1706 NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);\r
1707 EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);\r
1708 while (EfiEntry < EfiMemoryMapEnd) {\r
1709 while (NextEfiEntry < EfiMemoryMapEnd) {\r
1710 if (EfiEntry->PhysicalStart > NextEfiEntry->PhysicalStart) {\r
1711 CopyMem (&TempEfiEntry, EfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));\r
1712 CopyMem (EfiEntry, NextEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));\r
1713 CopyMem (NextEfiEntry, &TempEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));\r
1714 }\r
1715\r
1716 NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (NextEfiEntry, EfiDescriptorSize);\r
1717 }\r
1718\r
1719 EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);\r
1720 NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);\r
1721 }\r
1722\r
1723 EfiEntry = EfiMemoryMap;\r
1724 EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);\r
1725 for (Index = Above1MIndex; (EfiEntry < EfiMemoryMapEnd) && (Index < EFI_MAX_E820_ENTRY - 1); ) {\r
1726 MemoryBlockLength = (UINT64) (LShiftU64 (EfiEntry->NumberOfPages, 12));\r
1727 if ((EfiEntry->PhysicalStart + MemoryBlockLength) < 0x100000) {\r
1728 //\r
1729 // Skip the memory block is under 1MB\r
1730 //\r
1731 } else {\r
1732 if (EfiEntry->PhysicalStart < 0x100000) {\r
1733 //\r
1734 // When the memory block spans below 1MB, ensure the memory block start address is at least 1MB\r
1735 //\r
1736 MemoryBlockLength -= 0x100000 - EfiEntry->PhysicalStart;\r
1737 EfiEntry->PhysicalStart = 0x100000;\r
1738 }\r
1739\r
1740 //\r
1741 // Convert memory type to E820 type\r
1742 //\r
1743 TempType = EfiMemoryTypeToE820Type (EfiEntry->Type);\r
1744\r
1745 if ((E820Table[Index].Type == TempType) && (EfiEntry->PhysicalStart == (E820Table[Index].BaseAddr + E820Table[Index].Length))) {\r
1746 //\r
1747 // Grow an existing entry\r
1748 //\r
1749 E820Table[Index].Length += MemoryBlockLength;\r
1750 } else {\r
1751 //\r
1752 // Make a new entry\r
1753 //\r
1754 ++Index;\r
1755 E820Table[Index].BaseAddr = EfiEntry->PhysicalStart;\r
1756 E820Table[Index].Length = MemoryBlockLength;\r
1757 E820Table[Index].Type = TempType;\r
1758 }\r
1759 }\r
1760 EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);\r
1761 }\r
1762\r
1763 FreePool (EfiMemoryMap);\r
1764\r
1765 //\r
1766 // Process the reserved memory map to produce E820 map ;\r
1767 //\r
1768 for (Hob.Raw = GetHobList (); !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {\r
1769 if (Hob.Raw != NULL && GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
1770 ResourceHob = Hob.ResourceDescriptor;\r
1771 if (((ResourceHob->ResourceType == EFI_RESOURCE_MEMORY_MAPPED_IO) ||\r
1772 (ResourceHob->ResourceType == EFI_RESOURCE_FIRMWARE_DEVICE) ||\r
1773 (ResourceHob->ResourceType == EFI_RESOURCE_MEMORY_RESERVED) ) &&\r
1774 (ResourceHob->PhysicalStart > 0x100000) &&\r
1775 (Index < EFI_MAX_E820_ENTRY - 1)) {\r
1776 ++Index;\r
1777 E820Table[Index].BaseAddr = ResourceHob->PhysicalStart;\r
1778 E820Table[Index].Length = ResourceHob->ResourceLength;\r
1779 E820Table[Index].Type = EfiAcpiAddressRangeReserved;\r
1780 }\r
1781 }\r
1782 }\r
1783\r
1784 Index ++;\r
1785 Private->IntThunk->EfiToLegacy16InitTable.NumberE820Entries = (UINT32)Index;\r
1786 Private->IntThunk->EfiToLegacy16BootTable.NumberE820Entries = (UINT32)Index;\r
1787 Private->NumberE820Entries = (UINT32)Index;\r
1788 *Size = (UINTN) (Index * sizeof (EFI_E820_ENTRY64));\r
1789\r
1790 //\r
1791 // Sort E820Table from low to high\r
1792 //\r
1793 for (TempIndex = 0; TempIndex < Index; TempIndex++) {\r
1794 ChangedFlag = FALSE;\r
1795 for (TempNextIndex = 1; TempNextIndex < Index - TempIndex; TempNextIndex++) {\r
1796 if (E820Table[TempNextIndex - 1].BaseAddr > E820Table[TempNextIndex].BaseAddr) {\r
1797 ChangedFlag = TRUE;\r
1798 TempE820.BaseAddr = E820Table[TempNextIndex - 1].BaseAddr;\r
1799 TempE820.Length = E820Table[TempNextIndex - 1].Length;\r
1800 TempE820.Type = E820Table[TempNextIndex - 1].Type;\r
1801\r
1802 E820Table[TempNextIndex - 1].BaseAddr = E820Table[TempNextIndex].BaseAddr;\r
1803 E820Table[TempNextIndex - 1].Length = E820Table[TempNextIndex].Length;\r
1804 E820Table[TempNextIndex - 1].Type = E820Table[TempNextIndex].Type;\r
1805\r
1806 E820Table[TempNextIndex].BaseAddr = TempE820.BaseAddr;\r
1807 E820Table[TempNextIndex].Length = TempE820.Length;\r
1808 E820Table[TempNextIndex].Type = TempE820.Type;\r
1809 }\r
1810 }\r
1811\r
1812 if (!ChangedFlag) {\r
1813 break;\r
1814 }\r
1815 }\r
1816\r
1817 //\r
1818 // Remove the overlap range\r
1819 //\r
1820 for (TempIndex = 1; TempIndex < Index; TempIndex++) {\r
1821 if (E820Table[TempIndex - 1].BaseAddr <= E820Table[TempIndex].BaseAddr &&\r
1822 ((E820Table[TempIndex - 1].BaseAddr + E820Table[TempIndex - 1].Length) >=\r
1823 (E820Table[TempIndex].BaseAddr +E820Table[TempIndex].Length))) {\r
1824 //\r
1825 //Overlap range is found\r
1826 //\r
1827 ASSERT (E820Table[TempIndex - 1].Type == E820Table[TempIndex].Type);\r
1828\r
1829 if (TempIndex == Index - 1) {\r
1830 E820Table[TempIndex].BaseAddr = 0;\r
1831 E820Table[TempIndex].Length = 0;\r
1832 E820Table[TempIndex].Type = (EFI_ACPI_MEMORY_TYPE) 0;\r
1833 Index--;\r
1834 break;\r
1835 } else {\r
1836 for (IndexSort = TempIndex; IndexSort < Index - 1; IndexSort ++) {\r
1837 E820Table[IndexSort].BaseAddr = E820Table[IndexSort + 1].BaseAddr;\r
1838 E820Table[IndexSort].Length = E820Table[IndexSort + 1].Length;\r
1839 E820Table[IndexSort].Type = E820Table[IndexSort + 1].Type;\r
1840 }\r
1841 Index--;\r
1842 }\r
1843 }\r
1844 }\r
1845\r
1846\r
1847\r
1848 Private->IntThunk->EfiToLegacy16InitTable.NumberE820Entries = (UINT32)Index;\r
1849 Private->IntThunk->EfiToLegacy16BootTable.NumberE820Entries = (UINT32)Index;\r
1850 Private->NumberE820Entries = (UINT32)Index;\r
1851 *Size = (UINTN) (Index * sizeof (EFI_E820_ENTRY64));\r
1852\r
1853 //\r
1854 // Determine OS usable memory above 1Mb\r
1855 //\r
1856 Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb = 0x0000;\r
1857 for (TempIndex = Above1MIndex; TempIndex < Index; TempIndex++) {\r
1858 if (E820Table[TempIndex].BaseAddr >= 0x100000 && E820Table[TempIndex].BaseAddr < 0x100000000ULL) { // not include above 4G memory\r
1859 //\r
1860 // ACPIReclaimMemory is also usable memory for ACPI OS, after OS dumps all ACPI tables.\r
1861 //\r
1862 if ((E820Table[TempIndex].Type == EfiAcpiAddressRangeMemory) || (E820Table[TempIndex].Type == EfiAcpiAddressRangeACPI)) {\r
1863 Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb += (UINT32) (E820Table[TempIndex].Length);\r
1864 } else {\r
1865 break; // break at first not normal memory, because SMM may use reserved memory.\r
1866 }\r
1867 }\r
1868 }\r
1869\r
1870 Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb = Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb;\r
1871\r
1872 //\r
1873 // Print DEBUG information\r
1874 //\r
1875 for (TempIndex = 0; TempIndex < Index; TempIndex++) {\r
1876 DEBUG((EFI_D_INFO, "E820[%2d]: 0x%16lx ---- 0x%16lx, Type = 0x%x \n",\r
1877 TempIndex,\r
1878 E820Table[TempIndex].BaseAddr,\r
1879 (E820Table[TempIndex].BaseAddr + E820Table[TempIndex].Length),\r
1880 E820Table[TempIndex].Type\r
1881 ));\r
1882 }\r
1883\r
1884 return EFI_SUCCESS;\r
1885}\r
1886\r
1887\r
1888/**\r
1889 Fill in the standard BDA and EBDA stuff prior to legacy Boot\r
1890\r
1891 @param Private Legacy BIOS Instance data\r
1892\r
1893 @retval EFI_SUCCESS It should always work.\r
1894\r
1895**/\r
1896EFI_STATUS\r
1897LegacyBiosCompleteBdaBeforeBoot (\r
1898 IN LEGACY_BIOS_INSTANCE *Private\r
1899 )\r
1900{\r
1901 BDA_STRUC *Bda;\r
1902 UINT16 MachineConfig;\r
1903 DEVICE_PRODUCER_DATA_HEADER *SioPtr;\r
1904\r
1905 Bda = (BDA_STRUC *) ((UINTN) 0x400);\r
1906 MachineConfig = 0;\r
1907\r
1908 SioPtr = &(Private->IntThunk->EfiToLegacy16BootTable.SioData);\r
1909 Bda->Com1 = SioPtr->Serial[0].Address;\r
1910 Bda->Com2 = SioPtr->Serial[1].Address;\r
1911 Bda->Com3 = SioPtr->Serial[2].Address;\r
1912 Bda->Com4 = SioPtr->Serial[3].Address;\r
1913\r
1914 if (SioPtr->Serial[0].Address != 0x00) {\r
1915 MachineConfig += 0x200;\r
1916 }\r
1917\r
1918 if (SioPtr->Serial[1].Address != 0x00) {\r
1919 MachineConfig += 0x200;\r
1920 }\r
1921\r
1922 if (SioPtr->Serial[2].Address != 0x00) {\r
1923 MachineConfig += 0x200;\r
1924 }\r
1925\r
1926 if (SioPtr->Serial[3].Address != 0x00) {\r
1927 MachineConfig += 0x200;\r
1928 }\r
1929\r
1930 Bda->Lpt1 = SioPtr->Parallel[0].Address;\r
1931 Bda->Lpt2 = SioPtr->Parallel[1].Address;\r
1932 Bda->Lpt3 = SioPtr->Parallel[2].Address;\r
1933\r
1934 if (SioPtr->Parallel[0].Address != 0x00) {\r
1935 MachineConfig += 0x4000;\r
1936 }\r
1937\r
1938 if (SioPtr->Parallel[1].Address != 0x00) {\r
1939 MachineConfig += 0x4000;\r
1940 }\r
1941\r
1942 if (SioPtr->Parallel[2].Address != 0x00) {\r
1943 MachineConfig += 0x4000;\r
1944 }\r
1945\r
1946 Bda->NumberOfDrives = (UINT8) (Bda->NumberOfDrives + Private->IdeDriveCount);\r
1947 if (SioPtr->Floppy.NumberOfFloppy != 0x00) {\r
1948 MachineConfig = (UINT16) (MachineConfig + 0x01 + (SioPtr->Floppy.NumberOfFloppy - 1) * 0x40);\r
1949 Bda->FloppyXRate = 0x07;\r
1950 }\r
1951\r
1952 Bda->Lpt1_2Timeout = 0x1414;\r
1953 Bda->Lpt3_4Timeout = 0x1414;\r
1954 Bda->Com1_2Timeout = 0x0101;\r
1955 Bda->Com3_4Timeout = 0x0101;\r
1956\r
1957 //\r
1958 // Force VGA and Coprocessor, indicate 101/102 keyboard\r
1959 //\r
1960 MachineConfig = (UINT16) (MachineConfig + 0x00 + 0x02 + (SioPtr->MousePresent * 0x04));\r
1961 Bda->MachineConfig = MachineConfig;\r
1962\r
1963 return EFI_SUCCESS;\r
1964}\r
1965\r
1966/**\r
1967 Fill in the standard BDA for Keyboard LEDs\r
1968\r
1969 @param This Protocol instance pointer.\r
1970 @param Leds Current LED status\r
1971\r
1972 @retval EFI_SUCCESS It should always work.\r
1973\r
1974**/\r
1975EFI_STATUS\r
1976EFIAPI\r
1977LegacyBiosUpdateKeyboardLedStatus (\r
1978 IN EFI_LEGACY_BIOS_PROTOCOL *This,\r
1979 IN UINT8 Leds\r
1980 )\r
1981{\r
1982 LEGACY_BIOS_INSTANCE *Private;\r
1983 BDA_STRUC *Bda;\r
1984 UINT8 LocalLeds;\r
1985 EFI_IA32_REGISTER_SET Regs;\r
1986\r
1987 Bda = (BDA_STRUC *) ((UINTN) 0x400);\r
1988\r
1989 Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r
1990 LocalLeds = Leds;\r
1991 Bda->LedStatus = (UINT8) ((Bda->LedStatus &~0x07) | LocalLeds);\r
1992 LocalLeds = (UINT8) (LocalLeds << 4);\r
1993 Bda->ShiftStatus = (UINT8) ((Bda->ShiftStatus &~0x70) | LocalLeds);\r
1994 LocalLeds = (UINT8) (Leds & 0x20);\r
1995 Bda->KeyboardStatus = (UINT8) ((Bda->KeyboardStatus &~0x20) | LocalLeds);\r
1996 //\r
1997 // Call into Legacy16 code to allow it to do any processing\r
1998 //\r
1999 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r
2000 Regs.X.AX = Legacy16SetKeyboardLeds;\r
2001 Regs.H.CL = Leds;\r
2002\r
2003 Private->LegacyBios.FarCall86 (\r
2004 &Private->LegacyBios,\r
2005 Private->Legacy16Table->Compatibility16CallSegment,\r
2006 Private->Legacy16Table->Compatibility16CallOffset,\r
2007 &Regs,\r
2008 NULL,\r
2009 0\r
2010 );\r
2011\r
2012 return EFI_SUCCESS;\r
2013}\r
2014\r
2015\r
2016/**\r
2017 Fill in the standard CMOS stuff prior to legacy Boot\r
2018\r
2019 @param Private Legacy BIOS Instance data\r
2020\r
2021 @retval EFI_SUCCESS It should always work.\r
2022\r
2023**/\r
2024EFI_STATUS\r
2025LegacyBiosCompleteStandardCmosBeforeBoot (\r
2026 IN LEGACY_BIOS_INSTANCE *Private\r
2027 )\r
2028{\r
2029 UINT8 Bda;\r
2030 UINT8 Floppy;\r
2031 UINT32 Size;\r
2032\r
2033 //\r
2034 // Update CMOS locations\r
2035 // 10 floppy\r
2036 // 12,19,1A - ignore as OS don't use them and there is no standard due\r
2037 // to large capacity drives\r
2038 // CMOS 14 = BDA 40:10 plus bit 3(display enabled)\r
2039 //\r
2040 Bda = (UINT8)(*((UINT8 *)((UINTN)0x410)) | BIT3);\r
2041\r
2042 //\r
2043 // Force display enabled\r
2044 //\r
2045 Floppy = 0x00;\r
2046 if ((Bda & BIT0) != 0) {\r
2047 Floppy = BIT6;\r
2048 }\r
2049\r
2050 //\r
2051 // Check if 2.88MB floppy set\r
2052 //\r
2053 if ((Bda & (BIT7 | BIT6)) != 0) {\r
2054 Floppy = (UINT8)(Floppy | BIT1);\r
2055 }\r
2056\r
2057 LegacyWriteStandardCmos (CMOS_10, Floppy);\r
2058 LegacyWriteStandardCmos (CMOS_14, Bda);\r
2059\r
2060 //\r
2061 // Force Status Register A to set rate selection bits and divider\r
2062 //\r
2063 LegacyWriteStandardCmos (CMOS_0A, 0x26);\r
2064\r
2065 //\r
2066 // redo memory size since it can change\r
2067 //\r
2068 Size = 15 * SIZE_1MB;\r
2069 if (Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb < (15 * SIZE_1MB)) {\r
2070 Size = Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb >> 10;\r
2071 }\r
2072\r
2073 LegacyWriteStandardCmos (CMOS_17, (UINT8)(Size & 0xFF));\r
2074 LegacyWriteStandardCmos (CMOS_30, (UINT8)(Size & 0xFF));\r
2075 LegacyWriteStandardCmos (CMOS_18, (UINT8)(Size >> 8));\r
2076 LegacyWriteStandardCmos (CMOS_31, (UINT8)(Size >> 8));\r
2077\r
2078 LegacyCalculateWriteStandardCmosChecksum ();\r
2079\r
2080 return EFI_SUCCESS;\r
2081}\r
2082\r
2083/**\r
2084 Relocate this image under 4G memory for IPF.\r
2085\r
2086 @param ImageHandle Handle of driver image.\r
2087 @param SystemTable Pointer to system table.\r
2088\r
2089 @retval EFI_SUCCESS Image successfully relocated.\r
2090 @retval EFI_ABORTED Failed to relocate image.\r
2091\r
2092**/\r
2093EFI_STATUS\r
2094RelocateImageUnder4GIfNeeded (\r
2095 IN EFI_HANDLE ImageHandle,\r
2096 IN EFI_SYSTEM_TABLE *SystemTable\r
2097 )\r
2098{\r
2099 return EFI_SUCCESS;\r
2100}\r