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