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