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