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