]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Csm/LegacyBiosDxe/LegacyBootSupport.c
211750c0123b936a38b9895efaa0a156118b0838
[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.CX = (UINT16) CopySize;
932 Private->LegacyBios.FarCall86 (
933 &Private->LegacyBios,
934 Private->Legacy16Table->Compatibility16CallSegment,
935 Private->Legacy16Table->Compatibility16CallOffset,
936 &Regs,
937 NULL,
938 0
939 );
940
941 Private->Legacy16Table->E820Pointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
942 Private->Legacy16Table->E820Length = (UINT32) CopySize;
943 if (Regs.X.AX != 0) {
944 DEBUG ((EFI_D_ERROR, "Legacy16 E820 length insufficient\n"));
945 } else {
946 CopyMem (
947 (VOID *)(UINTN) Private->Legacy16Table->E820Pointer,
948 Private->E820Table,
949 CopySize
950 );
951 }
952 } else {
953 CopyMem (
954 (VOID *)(UINTN) Private->Legacy16Table->E820Pointer,
955 Private->E820Table,
956 CopySize
957 );
958 Private->Legacy16Table->E820Length = (UINT32) CopySize;
959 }
960
961 //
962 // We do not ASSERT if SmbiosTable not found. It is possbile that a platform does not produce SmbiosTable.
963 //
964 if (mReserveSmbiosEntryPoint == 0) {
965 DEBUG ((EFI_D_INFO, "Smbios table is not found!\n"));
966 }
967 CreateSmbiosTableInReservedMemory ();
968 EfiToLegacy16BootTable->SmbiosTable = (UINT32)(UINTN)mReserveSmbiosEntryPoint;
969
970 AcpiTable = NULL;
971 Status = EfiGetSystemConfigurationTable (
972 &gEfiAcpi20TableGuid,
973 &AcpiTable
974 );
975 if (EFI_ERROR (Status)) {
976 Status = EfiGetSystemConfigurationTable (
977 &gEfiAcpi10TableGuid,
978 &AcpiTable
979 );
980 }
981 //
982 // We do not ASSERT if AcpiTable not found. It is possbile that a platform does not produce AcpiTable.
983 //
984 if (AcpiTable == NULL) {
985 DEBUG ((EFI_D_INFO, "ACPI table is not found!\n"));
986 }
987 EfiToLegacy16BootTable->AcpiTable = (UINT32)(UINTN)AcpiTable;
988
989 //
990 // Get RSD Ptr table rev at offset 15 decimal
991 // Rev = 0 Length is 20 decimal
992 // Rev != 0 Length is UINT32 at offset 20 decimal
993 //
994 if (AcpiTable != NULL) {
995
996 AcpiPtr = AcpiTable;
997 if (*((UINT8 *) AcpiPtr + 15) == 0) {
998 CopySize = 20;
999 } else {
1000 AcpiPtr = ((UINT8 *) AcpiPtr + 20);
1001 CopySize = (*(UINT32 *) AcpiPtr);
1002 }
1003
1004 CopyMem (
1005 (VOID *)(UINTN) Private->Legacy16Table->AcpiRsdPtrPointer,
1006 AcpiTable,
1007 CopySize
1008 );
1009 }
1010 //
1011 // Make sure all PCI Interrupt Line register are programmed to match 8259
1012 //
1013 PciProgramAllInterruptLineRegisters (Private);
1014
1015 //
1016 // Unlock the Legacy BIOS region as PciProgramAllInterruptLineRegisters
1017 // can lock it.
1018 //
1019 Private->LegacyRegion->UnLock (
1020 Private->LegacyRegion,
1021 Private->BiosStart,
1022 Private->LegacyBiosImageSize,
1023 &Granularity
1024 );
1025
1026 //
1027 // Configure Legacy Device Magic
1028 //
1029 // Only do this code if booting legacy OS
1030 //
1031 if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
1032 UpdateSioData (Private);
1033 }
1034 //
1035 // Setup BDA and EBDA standard areas before Legacy Boot
1036 //
1037 ACCESS_PAGE0_CODE (
1038 LegacyBiosCompleteBdaBeforeBoot (Private);
1039 );
1040 LegacyBiosCompleteStandardCmosBeforeBoot (Private);
1041
1042 //
1043 // We must build IDE data, if it hasn't been done, before PciShadowRoms
1044 // to insure EFI drivers are connected.
1045 //
1046 LegacyBiosBuildIdeData (Private, &HddInfo, 1);
1047 UpdateAllIdentifyDriveData (Private);
1048
1049 //
1050 // Clear IO BAR, if IDE controller in legacy mode.
1051 //
1052 InitLegacyIdeController (IdeController);
1053
1054 //
1055 // Generate number of ticks since midnight for BDA. DOS requires this
1056 // for its time. We have to make assumptions as to how long following
1057 // code takes since after PciShadowRoms PciIo is gone. Place result in
1058 // 40:6C-6F
1059 //
1060 // Adjust value by 1 second.
1061 //
1062 gRT->GetTime (&BootTime, NULL);
1063 LocalTime = BootTime.Hour * 3600 + BootTime.Minute * 60 + BootTime.Second;
1064 LocalTime += 1;
1065
1066 //
1067 // Multiply result by 18.2 for number of ticks since midnight.
1068 // Use 182/10 to avoid floating point math.
1069 //
1070 LocalTime = (LocalTime * 182) / 10;
1071 ACCESS_PAGE0_CODE (
1072 BdaPtr = (UINT32 *) (UINTN)0x46C;
1073 *BdaPtr = LocalTime;
1074 );
1075
1076 //
1077 // Shadow PCI ROMs. We must do this near the end since this will kick
1078 // of Native EFI drivers that may be needed to collect info for Legacy16
1079 //
1080 // WARNING: PciIo is gone after this call.
1081 //
1082 PciShadowRoms (Private);
1083
1084 //
1085 // Shadow PXE base code, BIS etc.
1086 //
1087 Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xc0000, 0x40000, &Granularity);
1088 ShadowAddress = Private->OptionRom;
1089 Private->LegacyBiosPlatform->PlatformHooks (
1090 Private->LegacyBiosPlatform,
1091 EfiPlatformHookShadowServiceRoms,
1092 0,
1093 0,
1094 &ShadowAddress,
1095 Legacy16Table,
1096 NULL
1097 );
1098 Private->OptionRom = (UINT32)ShadowAddress;
1099 //
1100 // Register Legacy SMI Handler
1101 //
1102 LegacyBiosPlatform->SmmInit (
1103 LegacyBiosPlatform,
1104 EfiToLegacy16BootTable
1105 );
1106
1107 //
1108 // Let platform code know the boot options
1109 //
1110 LegacyBiosGetBbsInfo (
1111 This,
1112 &HddCount,
1113 &LocalHddInfo,
1114 &BbsCount,
1115 &LocalBbsTable
1116 );
1117
1118 DEBUG_CODE (
1119 PrintPciInterruptRegister ();
1120 PrintBbsTable (LocalBbsTable);
1121 PrintHddInfo (LocalHddInfo);
1122 );
1123 //
1124 // If drive wasn't spun up then BuildIdeData may have found new drives.
1125 // Need to update BBS boot priority.
1126 //
1127 for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) {
1128 if ((LocalHddInfo[Index].IdentifyDrive[0].Raw[0] != 0) &&
1129 (LocalBbsTable[2 * Index + 1].BootPriority == BBS_IGNORE_ENTRY)
1130 ) {
1131 LocalBbsTable[2 * Index + 1].BootPriority = BBS_UNPRIORITIZED_ENTRY;
1132 }
1133
1134 if ((LocalHddInfo[Index].IdentifyDrive[1].Raw[0] != 0) &&
1135 (LocalBbsTable[2 * Index + 2].BootPriority == BBS_IGNORE_ENTRY)
1136 ) {
1137 LocalBbsTable[2 * Index + 2].BootPriority = BBS_UNPRIORITIZED_ENTRY;
1138 }
1139 }
1140
1141 Private->LegacyRegion->UnLock (
1142 Private->LegacyRegion,
1143 0xc0000,
1144 0x40000,
1145 &Granularity
1146 );
1147
1148 LegacyBiosPlatform->PrepareToBoot (
1149 LegacyBiosPlatform,
1150 mBbsDevicePathPtr,
1151 mBbsTable,
1152 mLoadOptionsSize,
1153 mLoadOptions,
1154 (VOID *) &Private->IntThunk->EfiToLegacy16BootTable
1155 );
1156
1157 //
1158 // If no boot device return to BDS
1159 //
1160 if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
1161 for (Index = 0; Index < BbsCount; Index++){
1162 if ((LocalBbsTable[Index].BootPriority != BBS_DO_NOT_BOOT_FROM) &&
1163 (LocalBbsTable[Index].BootPriority != BBS_UNPRIORITIZED_ENTRY) &&
1164 (LocalBbsTable[Index].BootPriority != BBS_IGNORE_ENTRY)) {
1165 break;
1166 }
1167 }
1168 if (Index == BbsCount) {
1169 return EFI_DEVICE_ERROR;
1170 }
1171 }
1172 //
1173 // Let the Legacy16 code know the device path type for legacy boot
1174 //
1175 EfiToLegacy16BootTable->DevicePathType = mBbsDevicePathPtr->DeviceType;
1176
1177 //
1178 // Copy MP table, if it exists.
1179 //
1180 LegacyGetDataOrTable (This, EfiGetPlatformBinaryMpTable);
1181
1182 if (!Private->LegacyBootEntered) {
1183 //
1184 // Copy OEM INT Data, if it exists. Note: This code treats any data
1185 // as a bag of bits and knows nothing of the contents nor cares.
1186 // Contents are IBV specific.
1187 //
1188 LegacyGetDataOrTable (This, EfiGetPlatformBinaryOemIntData);
1189
1190 //
1191 // Copy OEM16 Data, if it exists.Note: This code treats any data
1192 // as a bag of bits and knows nothing of the contents nor cares.
1193 // Contents are IBV specific.
1194 //
1195 LegacyGetDataOrTable (This, EfiGetPlatformBinaryOem16Data);
1196
1197 //
1198 // Copy OEM32 Data, if it exists.Note: This code treats any data
1199 // as a bag of bits and knows nothing of the contents nor cares.
1200 // Contents are IBV specific.
1201 //
1202 LegacyGetDataOrTable (This, EfiGetPlatformBinaryOem32Data);
1203 }
1204
1205 //
1206 // Call into Legacy16 code to prepare for INT 19h
1207 //
1208 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
1209 Regs.X.AX = Legacy16PrepareToBoot;
1210
1211 //
1212 // Pass in handoff data
1213 //
1214 Regs.X.ES = NORMALIZE_EFI_SEGMENT ((UINTN)EfiToLegacy16BootTable);
1215 Regs.X.BX = NORMALIZE_EFI_OFFSET ((UINTN)EfiToLegacy16BootTable);
1216
1217 Private->LegacyBios.FarCall86 (
1218 This,
1219 Private->Legacy16CallSegment,
1220 Private->Legacy16CallOffset,
1221 &Regs,
1222 NULL,
1223 0
1224 );
1225
1226 if (Regs.X.AX != 0) {
1227 return EFI_DEVICE_ERROR;
1228 }
1229 //
1230 // Lock the Legacy BIOS region
1231 //
1232 Private->LegacyRegion->Lock (
1233 Private->LegacyRegion,
1234 0xc0000,
1235 0x40000,
1236 &Granularity
1237 );
1238
1239 if ((Private->Legacy16Table->TableLength >= OFFSET_OF (EFI_COMPATIBILITY16_TABLE, HiPermanentMemoryAddress)) &&
1240 ((Private->Legacy16Table->UmaAddress != 0) && (Private->Legacy16Table->UmaSize != 0))) {
1241 //
1242 // Here we could reduce UmaAddress down as far as Private->OptionRom, taking into
1243 // account the granularity of the access control.
1244 //
1245 DEBUG((EFI_D_INFO, "Unlocking UMB RAM region 0x%x-0x%x\n", Private->Legacy16Table->UmaAddress,
1246 Private->Legacy16Table->UmaAddress + Private->Legacy16Table->UmaSize));
1247
1248 Private->LegacyRegion->UnLock (
1249 Private->LegacyRegion,
1250 Private->Legacy16Table->UmaAddress,
1251 Private->Legacy16Table->UmaSize,
1252 &Granularity
1253 );
1254 }
1255
1256 //
1257 // Lock attributes of the Legacy Region if chipset supports
1258 //
1259 Private->LegacyRegion->BootLock (
1260 Private->LegacyRegion,
1261 0xc0000,
1262 0x40000,
1263 &Granularity
1264 );
1265
1266 //
1267 // Call into Legacy16 code to do the INT 19h
1268 //
1269 EnableAllControllers (Private);
1270 if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
1271
1272 //
1273 // Signal all the events that are waiting on EVT_SIGNAL_LEGACY_BOOT
1274 //
1275 EfiSignalEventLegacyBoot ();
1276
1277 //
1278 // Report Status Code to indicate legacy boot event was signalled
1279 //
1280 REPORT_STATUS_CODE (
1281 EFI_PROGRESS_CODE,
1282 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_LEGACY_BOOT_EVENT)
1283 );
1284
1285 DEBUG ((EFI_D_INFO, "Legacy INT19 Boot...\n"));
1286
1287 //
1288 // Disable DXE Timer while executing in real mode
1289 //
1290 Private->Timer->SetTimerPeriod (Private->Timer, 0);
1291
1292 //
1293 // Save and disable interrupt of debug timer
1294 //
1295 SaveAndSetDebugTimerInterrupt (FALSE);
1296
1297
1298 //
1299 // Put the 8259 into its legacy mode by reprogramming the vector bases
1300 //
1301 Private->Legacy8259->SetVectorBase (Private->Legacy8259, LEGACY_MODE_BASE_VECTOR_MASTER, LEGACY_MODE_BASE_VECTOR_SLAVE);
1302 //
1303 // PC History
1304 // The original PC used INT8-F for master PIC. Since these mapped over
1305 // processor exceptions TIANO moved the master PIC to INT68-6F.
1306 // We need to set these back to the Legacy16 unexpected interrupt(saved
1307 // in LegacyBios.c) since some OS see that these have values different from
1308 // what is expected and invoke them. Since the legacy OS corrupts EFI
1309 // memory, there is no handler for these interrupts and OS blows up.
1310 //
1311 // We need to save the TIANO values for the rare case that the Legacy16
1312 // code cannot boot but knows memory hasn't been destroyed.
1313 //
1314 // To compound the problem, video takes over one of these INTS and must be
1315 // be left.
1316 // @bug - determine if video hooks INT(in which case we must find new
1317 // set of TIANO vectors) or takes it over.
1318 //
1319 //
1320 ACCESS_PAGE0_CODE (
1321 BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);
1322 for (Index = 0; Index < 8; Index++) {
1323 Private->ThunkSavedInt[Index] = BaseVectorMaster[Index];
1324 if (Private->ThunkSeg == (UINT16) (BaseVectorMaster[Index] >> 16)) {
1325 BaseVectorMaster[Index] = (UINT32) (Private->BiosUnexpectedInt);
1326 }
1327 }
1328 );
1329
1330 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
1331 Regs.X.AX = Legacy16Boot;
1332
1333 Private->LegacyBios.FarCall86 (
1334 This,
1335 Private->Legacy16CallSegment,
1336 Private->Legacy16CallOffset,
1337 &Regs,
1338 NULL,
1339 0
1340 );
1341
1342 ACCESS_PAGE0_CODE (
1343 BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);
1344 for (Index = 0; Index < 8; Index++) {
1345 BaseVectorMaster[Index] = Private->ThunkSavedInt[Index];
1346 }
1347 );
1348 }
1349 Private->LegacyBootEntered = TRUE;
1350 if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
1351 //
1352 // Should never return unless never passed control to 0:7c00(first stage
1353 // OS loader) and only then if no bootable device found.
1354 //
1355 return EFI_DEVICE_ERROR;
1356 } else {
1357 //
1358 // If boot to EFI then expect to return to caller
1359 //
1360 return EFI_SUCCESS;
1361 }
1362 }
1363
1364
1365 /**
1366 Assign drive number to legacy HDD drives prior to booting an EFI
1367 aware OS so the OS can access drives without an EFI driver.
1368 Note: BBS compliant drives ARE NOT available until this call by
1369 either shell or EFI.
1370
1371 @param This Protocol instance pointer.
1372 @param BbsCount Number of BBS_TABLE structures
1373 @param BbsTable List BBS entries
1374
1375 @retval EFI_SUCCESS Drive numbers assigned
1376
1377 **/
1378 EFI_STATUS
1379 EFIAPI
1380 LegacyBiosPrepareToBootEfi (
1381 IN EFI_LEGACY_BIOS_PROTOCOL *This,
1382 OUT UINT16 *BbsCount,
1383 OUT BBS_TABLE **BbsTable
1384 )
1385 {
1386 EFI_STATUS Status;
1387 EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
1388 LEGACY_BIOS_INSTANCE *Private;
1389
1390 Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
1391 EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
1392 mBootMode = BOOT_EFI_OS;
1393 mBbsDevicePathPtr = NULL;
1394 Status = GenericLegacyBoot (This);
1395 *BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable;
1396 *BbsCount = (UINT16) (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE));
1397 return Status;
1398 }
1399
1400 /**
1401 To boot from an unconventional device like parties and/or execute HDD diagnostics.
1402
1403 @param This Protocol instance pointer.
1404 @param Attributes How to interpret the other input parameters
1405 @param BbsEntry The 0-based index into the BbsTable for the parent
1406 device.
1407 @param BeerData Pointer to the 128 bytes of ram BEER data.
1408 @param ServiceAreaData Pointer to the 64 bytes of raw Service Area data. The
1409 caller must provide a pointer to the specific Service
1410 Area and not the start all Service Areas.
1411
1412 @retval EFI_INVALID_PARAMETER if error. Does NOT return if no error.
1413
1414 ***/
1415 EFI_STATUS
1416 EFIAPI
1417 LegacyBiosBootUnconventionalDevice (
1418 IN EFI_LEGACY_BIOS_PROTOCOL *This,
1419 IN UDC_ATTRIBUTES Attributes,
1420 IN UINTN BbsEntry,
1421 IN VOID *BeerData,
1422 IN VOID *ServiceAreaData
1423 )
1424 {
1425 EFI_STATUS Status;
1426 EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
1427 LEGACY_BIOS_INSTANCE *Private;
1428 UD_TABLE *UcdTable;
1429 UINTN Index;
1430 UINT16 BootPriority;
1431 BBS_TABLE *BbsTable;
1432
1433 BootPriority = 0;
1434 Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
1435 mBootMode = BOOT_UNCONVENTIONAL_DEVICE;
1436 mBbsDevicePathPtr = &mBbsDevicePathNode;
1437 mAttributes = Attributes;
1438 mBbsEntry = BbsEntry;
1439 mBeerData = BeerData, mServiceAreaData = ServiceAreaData;
1440
1441 EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
1442
1443 //
1444 // Do input parameter checking
1445 //
1446 if ((Attributes.DirectoryServiceValidity == 0) &&
1447 (Attributes.RabcaUsedFlag == 0) &&
1448 (Attributes.ExecuteHddDiagnosticsFlag == 0)
1449 ) {
1450 return EFI_INVALID_PARAMETER;
1451 }
1452
1453 if (((Attributes.DirectoryServiceValidity != 0) && (ServiceAreaData == NULL)) ||
1454 (((Attributes.DirectoryServiceValidity | Attributes.RabcaUsedFlag) != 0) && (BeerData == NULL))
1455 ) {
1456 return EFI_INVALID_PARAMETER;
1457 }
1458
1459 UcdTable = (UD_TABLE *) AllocatePool (
1460 sizeof (UD_TABLE)
1461 );
1462 if (NULL == UcdTable) {
1463 return EFI_OUT_OF_RESOURCES;
1464 }
1465
1466 EfiToLegacy16BootTable->UnconventionalDeviceTable = (UINT32)(UINTN)UcdTable;
1467 UcdTable->Attributes = Attributes;
1468 UcdTable->BbsTableEntryNumberForParentDevice = (UINT8) BbsEntry;
1469 //
1470 // Force all existing BBS entries to DoNotBoot. This allows 16-bit CSM
1471 // to assign drive numbers but bot boot from. Only newly created entries
1472 // will be valid.
1473 //
1474 BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable;
1475 for (Index = 0; Index < EfiToLegacy16BootTable->NumberBbsEntries; Index++) {
1476 BbsTable[Index].BootPriority = BBS_DO_NOT_BOOT_FROM;
1477 }
1478 //
1479 // If parent is onboard IDE then assign controller & device number
1480 // else they are 0.
1481 //
1482 if (BbsEntry < MAX_IDE_CONTROLLER * 2) {
1483 UcdTable->DeviceNumber = (UINT8) ((BbsEntry - 1) % 2);
1484 }
1485
1486 if (BeerData != NULL) {
1487 CopyMem (
1488 (VOID *) UcdTable->BeerData,
1489 BeerData,
1490 (UINTN) 128
1491 );
1492 }
1493
1494 if (ServiceAreaData != NULL) {
1495 CopyMem (
1496 (VOID *) UcdTable->ServiceAreaData,
1497 ServiceAreaData,
1498 (UINTN) 64
1499 );
1500 }
1501 //
1502 // For each new entry do the following:
1503 // 1. Increment current number of BBS entries
1504 // 2. Copy parent entry to new entry.
1505 // 3. Zero out BootHandler Offset & segment
1506 // 4. Set appropriate device type. BEV(0x80) for HDD diagnostics
1507 // and Floppy(0x01) for PARTIES boot.
1508 // 5. Assign new priority.
1509 //
1510 if ((Attributes.ExecuteHddDiagnosticsFlag) != 0) {
1511 EfiToLegacy16BootTable->NumberBbsEntries += 1;
1512
1513 CopyMem (
1514 (VOID *) &BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority,
1515 (VOID *) &BbsTable[BbsEntry].BootPriority,
1516 sizeof (BBS_TABLE)
1517 );
1518
1519 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerOffset = 0;
1520 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerSegment = 0;
1521 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].DeviceType = 0x80;
1522
1523 UcdTable->BbsTableEntryNumberForHddDiag = (UINT8) (EfiToLegacy16BootTable->NumberBbsEntries - 1);
1524
1525 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority = BootPriority;
1526 BootPriority += 1;
1527
1528 //
1529 // Set device type as BBS_TYPE_DEV for PARTIES diagnostic
1530 //
1531 mBbsDevicePathNode.DeviceType = BBS_TYPE_BEV;
1532 }
1533
1534 if (((Attributes.DirectoryServiceValidity | Attributes.RabcaUsedFlag)) != 0) {
1535 EfiToLegacy16BootTable->NumberBbsEntries += 1;
1536 CopyMem (
1537 (VOID *) &BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority,
1538 (VOID *) &BbsTable[BbsEntry].BootPriority,
1539 sizeof (BBS_TABLE)
1540 );
1541
1542 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerOffset = 0;
1543 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerSegment = 0;
1544 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].DeviceType = 0x01;
1545 UcdTable->BbsTableEntryNumberForBoot = (UINT8) (EfiToLegacy16BootTable->NumberBbsEntries - 1);
1546 BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority = BootPriority;
1547
1548 //
1549 // Set device type as BBS_TYPE_FLOPPY for PARTIES boot as floppy
1550 //
1551 mBbsDevicePathNode.DeviceType = BBS_TYPE_FLOPPY;
1552 }
1553 //
1554 // Build the BBS Device Path for this boot selection
1555 //
1556 mBbsDevicePathNode.Header.Type = BBS_DEVICE_PATH;
1557 mBbsDevicePathNode.Header.SubType = BBS_BBS_DP;
1558 SetDevicePathNodeLength (&mBbsDevicePathNode.Header, sizeof (BBS_BBS_DEVICE_PATH));
1559 mBbsDevicePathNode.StatusFlag = 0;
1560 mBbsDevicePathNode.String[0] = 0;
1561
1562 Status = GenericLegacyBoot (This);
1563 return Status;
1564 }
1565
1566 /**
1567 Attempt to legacy boot the BootOption. If the EFI contexted has been
1568 compromised this function will not return.
1569
1570 @param This Protocol instance pointer.
1571 @param BbsDevicePath EFI Device Path from BootXXXX variable.
1572 @param LoadOptionsSize Size of LoadOption in size.
1573 @param LoadOptions LoadOption from BootXXXX variable
1574
1575 @retval EFI_SUCCESS Removable media not present
1576
1577 **/
1578 EFI_STATUS
1579 EFIAPI
1580 LegacyBiosLegacyBoot (
1581 IN EFI_LEGACY_BIOS_PROTOCOL *This,
1582 IN BBS_BBS_DEVICE_PATH *BbsDevicePath,
1583 IN UINT32 LoadOptionsSize,
1584 IN VOID *LoadOptions
1585 )
1586 {
1587 EFI_STATUS Status;
1588
1589 mBbsDevicePathPtr = BbsDevicePath;
1590 mLoadOptionsSize = LoadOptionsSize;
1591 mLoadOptions = LoadOptions;
1592 mBootMode = BOOT_LEGACY_OS;
1593 Status = GenericLegacyBoot (This);
1594
1595 return Status;
1596 }
1597
1598 /**
1599 Convert EFI Memory Type to E820 Memory Type.
1600
1601 @param Type EFI Memory Type
1602
1603 @return ACPI Memory Type for EFI Memory Type
1604
1605 **/
1606 EFI_ACPI_MEMORY_TYPE
1607 EfiMemoryTypeToE820Type (
1608 IN UINT32 Type
1609 )
1610 {
1611 switch (Type) {
1612 case EfiLoaderCode:
1613 case EfiLoaderData:
1614 case EfiBootServicesCode:
1615 case EfiBootServicesData:
1616 case EfiConventionalMemory:
1617 //
1618 // The memory of EfiRuntimeServicesCode and EfiRuntimeServicesData are
1619 // usable memory for legacy OS, because legacy OS is not aware of EFI runtime concept.
1620 // In ACPI specification, EfiRuntimeServiceCode and EfiRuntimeServiceData
1621 // should be mapped to AddressRangeReserved. This statement is for UEFI OS, not for legacy OS.
1622 //
1623 case EfiRuntimeServicesCode:
1624 case EfiRuntimeServicesData:
1625 return EfiAcpiAddressRangeMemory;
1626
1627 case EfiPersistentMemory:
1628 return EfiAddressRangePersistentMemory;
1629
1630 case EfiACPIReclaimMemory:
1631 return EfiAcpiAddressRangeACPI;
1632
1633 case EfiACPIMemoryNVS:
1634 return EfiAcpiAddressRangeNVS;
1635
1636 //
1637 // All other types map to reserved.
1638 // Adding the code just waists FLASH space.
1639 //
1640 // case EfiReservedMemoryType:
1641 // case EfiUnusableMemory:
1642 // case EfiMemoryMappedIO:
1643 // case EfiMemoryMappedIOPortSpace:
1644 // case EfiPalCode:
1645 //
1646 default:
1647 return EfiAcpiAddressRangeReserved;
1648 }
1649 }
1650
1651 /**
1652 Build the E820 table.
1653
1654 @param Private Legacy BIOS Instance data
1655 @param Size Size of E820 Table
1656
1657 @retval EFI_SUCCESS It should always work.
1658
1659 **/
1660 EFI_STATUS
1661 LegacyBiosBuildE820 (
1662 IN LEGACY_BIOS_INSTANCE *Private,
1663 OUT UINTN *Size
1664 )
1665 {
1666 EFI_STATUS Status;
1667 EFI_E820_ENTRY64 *E820Table;
1668 EFI_MEMORY_DESCRIPTOR *EfiMemoryMap;
1669 EFI_MEMORY_DESCRIPTOR *EfiMemoryMapEnd;
1670 EFI_MEMORY_DESCRIPTOR *EfiEntry;
1671 EFI_MEMORY_DESCRIPTOR *NextEfiEntry;
1672 EFI_MEMORY_DESCRIPTOR TempEfiEntry;
1673 UINTN EfiMemoryMapSize;
1674 UINTN EfiMapKey;
1675 UINTN EfiDescriptorSize;
1676 UINT32 EfiDescriptorVersion;
1677 UINTN Index;
1678 EFI_PEI_HOB_POINTERS Hob;
1679 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
1680 UINTN TempIndex;
1681 UINTN IndexSort;
1682 UINTN TempNextIndex;
1683 EFI_E820_ENTRY64 TempE820;
1684 EFI_ACPI_MEMORY_TYPE TempType;
1685 BOOLEAN ChangedFlag;
1686 UINTN Above1MIndex;
1687 UINT64 MemoryBlockLength;
1688
1689 E820Table = (EFI_E820_ENTRY64 *) Private->E820Table;
1690
1691 //
1692 // Get the EFI memory map.
1693 //
1694 EfiMemoryMapSize = 0;
1695 EfiMemoryMap = NULL;
1696 Status = gBS->GetMemoryMap (
1697 &EfiMemoryMapSize,
1698 EfiMemoryMap,
1699 &EfiMapKey,
1700 &EfiDescriptorSize,
1701 &EfiDescriptorVersion
1702 );
1703 ASSERT (Status == EFI_BUFFER_TOO_SMALL);
1704
1705 do {
1706 //
1707 // Use size returned for the AllocatePool.
1708 // We don't just multiply by 2 since the "for" loop below terminates on
1709 // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwise
1710 // we process bogus entries and create bogus E820 entries.
1711 //
1712 EfiMemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (EfiMemoryMapSize);
1713 ASSERT (EfiMemoryMap != NULL);
1714 Status = gBS->GetMemoryMap (
1715 &EfiMemoryMapSize,
1716 EfiMemoryMap,
1717 &EfiMapKey,
1718 &EfiDescriptorSize,
1719 &EfiDescriptorVersion
1720 );
1721 if (EFI_ERROR (Status)) {
1722 FreePool (EfiMemoryMap);
1723 }
1724 } while (Status == EFI_BUFFER_TOO_SMALL);
1725
1726 ASSERT_EFI_ERROR (Status);
1727
1728 //
1729 // Punch in the E820 table for memory less than 1 MB.
1730 // Assume ZeroMem () has been done on data structure.
1731 //
1732 //
1733 // First entry is 0 to (640k - EBDA)
1734 //
1735 ACCESS_PAGE0_CODE (
1736 E820Table[0].BaseAddr = 0;
1737 E820Table[0].Length = (UINT64) ((*(UINT16 *) (UINTN)0x40E) << 4);
1738 E820Table[0].Type = EfiAcpiAddressRangeMemory;
1739 );
1740
1741 //
1742 // Second entry is (640k - EBDA) to 640k
1743 //
1744 E820Table[1].BaseAddr = E820Table[0].Length;
1745 E820Table[1].Length = (UINT64) ((640 * 1024) - E820Table[0].Length);
1746 E820Table[1].Type = EfiAcpiAddressRangeReserved;
1747
1748 //
1749 // Third Entry is legacy BIOS
1750 // DO NOT CLAIM region from 0xA0000-0xDFFFF. OS can use free areas
1751 // to page in memory under 1MB.
1752 // Omit region from 0xE0000 to start of BIOS, if any. This can be
1753 // used for a multiple reasons including OPROMS.
1754 //
1755
1756 //
1757 // The CSM binary image size is not the actually size that CSM binary used,
1758 // to avoid memory corrupt, we declare the 0E0000 - 0FFFFF is used by CSM binary.
1759 //
1760 E820Table[2].BaseAddr = 0xE0000;
1761 E820Table[2].Length = 0x20000;
1762 E820Table[2].Type = EfiAcpiAddressRangeReserved;
1763
1764 Above1MIndex = 2;
1765
1766 //
1767 // Process the EFI map to produce E820 map;
1768 //
1769
1770 //
1771 // Sort memory map from low to high
1772 //
1773 EfiEntry = EfiMemoryMap;
1774 NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
1775 EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);
1776 while (EfiEntry < EfiMemoryMapEnd) {
1777 while (NextEfiEntry < EfiMemoryMapEnd) {
1778 if (EfiEntry->PhysicalStart > NextEfiEntry->PhysicalStart) {
1779 CopyMem (&TempEfiEntry, EfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
1780 CopyMem (EfiEntry, NextEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
1781 CopyMem (NextEfiEntry, &TempEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
1782 }
1783
1784 NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (NextEfiEntry, EfiDescriptorSize);
1785 }
1786
1787 EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
1788 NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
1789 }
1790
1791 EfiEntry = EfiMemoryMap;
1792 EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);
1793 for (Index = Above1MIndex; (EfiEntry < EfiMemoryMapEnd) && (Index < EFI_MAX_E820_ENTRY - 1); ) {
1794 MemoryBlockLength = (UINT64) (LShiftU64 (EfiEntry->NumberOfPages, 12));
1795 if ((EfiEntry->PhysicalStart + MemoryBlockLength) < 0x100000) {
1796 //
1797 // Skip the memory block if under 1MB
1798 //
1799 } else {
1800 if (EfiEntry->PhysicalStart < 0x100000) {
1801 //
1802 // When the memory block spans below 1MB, ensure the memory block start address is at least 1MB
1803 //
1804 MemoryBlockLength -= 0x100000 - EfiEntry->PhysicalStart;
1805 EfiEntry->PhysicalStart = 0x100000;
1806 }
1807
1808 //
1809 // Convert memory type to E820 type
1810 //
1811 TempType = EfiMemoryTypeToE820Type (EfiEntry->Type);
1812
1813 if ((E820Table[Index].Type == TempType) && (EfiEntry->PhysicalStart == (E820Table[Index].BaseAddr + E820Table[Index].Length))) {
1814 //
1815 // Grow an existing entry
1816 //
1817 E820Table[Index].Length += MemoryBlockLength;
1818 } else {
1819 //
1820 // Make a new entry
1821 //
1822 ++Index;
1823 E820Table[Index].BaseAddr = EfiEntry->PhysicalStart;
1824 E820Table[Index].Length = MemoryBlockLength;
1825 E820Table[Index].Type = TempType;
1826 }
1827 }
1828 EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
1829 }
1830
1831 FreePool (EfiMemoryMap);
1832
1833 //
1834 // Process the reserved memory map to produce E820 map ;
1835 //
1836 for (Hob.Raw = GetHobList (); !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
1837 if (Hob.Raw != NULL && GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
1838 ResourceHob = Hob.ResourceDescriptor;
1839 if (((ResourceHob->ResourceType == EFI_RESOURCE_MEMORY_MAPPED_IO) ||
1840 (ResourceHob->ResourceType == EFI_RESOURCE_FIRMWARE_DEVICE) ||
1841 (ResourceHob->ResourceType == EFI_RESOURCE_MEMORY_RESERVED) ) &&
1842 (ResourceHob->PhysicalStart > 0x100000) &&
1843 (Index < EFI_MAX_E820_ENTRY - 1)) {
1844 ++Index;
1845 E820Table[Index].BaseAddr = ResourceHob->PhysicalStart;
1846 E820Table[Index].Length = ResourceHob->ResourceLength;
1847 E820Table[Index].Type = EfiAcpiAddressRangeReserved;
1848 }
1849 }
1850 }
1851
1852 Index ++;
1853 Private->IntThunk->EfiToLegacy16InitTable.NumberE820Entries = (UINT32)Index;
1854 Private->IntThunk->EfiToLegacy16BootTable.NumberE820Entries = (UINT32)Index;
1855 Private->NumberE820Entries = (UINT32)Index;
1856 *Size = (UINTN) (Index * sizeof (EFI_E820_ENTRY64));
1857
1858 //
1859 // Sort E820Table from low to high
1860 //
1861 for (TempIndex = 0; TempIndex < Index; TempIndex++) {
1862 ChangedFlag = FALSE;
1863 for (TempNextIndex = 1; TempNextIndex < Index - TempIndex; TempNextIndex++) {
1864 if (E820Table[TempNextIndex - 1].BaseAddr > E820Table[TempNextIndex].BaseAddr) {
1865 ChangedFlag = TRUE;
1866 TempE820.BaseAddr = E820Table[TempNextIndex - 1].BaseAddr;
1867 TempE820.Length = E820Table[TempNextIndex - 1].Length;
1868 TempE820.Type = E820Table[TempNextIndex - 1].Type;
1869
1870 E820Table[TempNextIndex - 1].BaseAddr = E820Table[TempNextIndex].BaseAddr;
1871 E820Table[TempNextIndex - 1].Length = E820Table[TempNextIndex].Length;
1872 E820Table[TempNextIndex - 1].Type = E820Table[TempNextIndex].Type;
1873
1874 E820Table[TempNextIndex].BaseAddr = TempE820.BaseAddr;
1875 E820Table[TempNextIndex].Length = TempE820.Length;
1876 E820Table[TempNextIndex].Type = TempE820.Type;
1877 }
1878 }
1879
1880 if (!ChangedFlag) {
1881 break;
1882 }
1883 }
1884
1885 //
1886 // Remove the overlap range
1887 //
1888 for (TempIndex = 1; TempIndex < Index; TempIndex++) {
1889 if (E820Table[TempIndex - 1].BaseAddr <= E820Table[TempIndex].BaseAddr &&
1890 ((E820Table[TempIndex - 1].BaseAddr + E820Table[TempIndex - 1].Length) >=
1891 (E820Table[TempIndex].BaseAddr +E820Table[TempIndex].Length))) {
1892 //
1893 //Overlap range is found
1894 //
1895 ASSERT (E820Table[TempIndex - 1].Type == E820Table[TempIndex].Type);
1896
1897 if (TempIndex == Index - 1) {
1898 E820Table[TempIndex].BaseAddr = 0;
1899 E820Table[TempIndex].Length = 0;
1900 E820Table[TempIndex].Type = (EFI_ACPI_MEMORY_TYPE) 0;
1901 Index--;
1902 break;
1903 } else {
1904 for (IndexSort = TempIndex; IndexSort < Index - 1; IndexSort ++) {
1905 E820Table[IndexSort].BaseAddr = E820Table[IndexSort + 1].BaseAddr;
1906 E820Table[IndexSort].Length = E820Table[IndexSort + 1].Length;
1907 E820Table[IndexSort].Type = E820Table[IndexSort + 1].Type;
1908 }
1909 Index--;
1910 }
1911 }
1912 }
1913
1914
1915
1916 Private->IntThunk->EfiToLegacy16InitTable.NumberE820Entries = (UINT32)Index;
1917 Private->IntThunk->EfiToLegacy16BootTable.NumberE820Entries = (UINT32)Index;
1918 Private->NumberE820Entries = (UINT32)Index;
1919 *Size = (UINTN) (Index * sizeof (EFI_E820_ENTRY64));
1920
1921 //
1922 // Determine OS usable memory above 1MB
1923 //
1924 Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb = 0x0000;
1925 for (TempIndex = Above1MIndex; TempIndex < Index; TempIndex++) {
1926 if (E820Table[TempIndex].BaseAddr >= 0x100000 && E820Table[TempIndex].BaseAddr < 0x100000000ULL) { // not include above 4G memory
1927 //
1928 // ACPIReclaimMemory is also usable memory for ACPI OS, after OS dumps all ACPI tables.
1929 //
1930 if ((E820Table[TempIndex].Type == EfiAcpiAddressRangeMemory) || (E820Table[TempIndex].Type == EfiAcpiAddressRangeACPI)) {
1931 Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb += (UINT32) (E820Table[TempIndex].Length);
1932 } else {
1933 break; // break at first not normal memory, because SMM may use reserved memory.
1934 }
1935 }
1936 }
1937
1938 Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb = Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb;
1939
1940 //
1941 // Print DEBUG information
1942 //
1943 for (TempIndex = 0; TempIndex < Index; TempIndex++) {
1944 DEBUG((EFI_D_INFO, "E820[%2d]: 0x%016lx - 0x%016lx, Type = %d\n",
1945 TempIndex,
1946 E820Table[TempIndex].BaseAddr,
1947 (E820Table[TempIndex].BaseAddr + E820Table[TempIndex].Length),
1948 E820Table[TempIndex].Type
1949 ));
1950 }
1951
1952 return EFI_SUCCESS;
1953 }
1954
1955
1956 /**
1957 Fill in the standard BDA and EBDA stuff prior to legacy Boot
1958
1959 @param Private Legacy BIOS Instance data
1960
1961 @retval EFI_SUCCESS It should always work.
1962
1963 **/
1964 EFI_STATUS
1965 LegacyBiosCompleteBdaBeforeBoot (
1966 IN LEGACY_BIOS_INSTANCE *Private
1967 )
1968 {
1969 BDA_STRUC *Bda;
1970 UINT16 MachineConfig;
1971 DEVICE_PRODUCER_DATA_HEADER *SioPtr;
1972
1973 Bda = (BDA_STRUC *) ((UINTN) 0x400);
1974 MachineConfig = 0;
1975
1976 SioPtr = &(Private->IntThunk->EfiToLegacy16BootTable.SioData);
1977 Bda->Com1 = SioPtr->Serial[0].Address;
1978 Bda->Com2 = SioPtr->Serial[1].Address;
1979 Bda->Com3 = SioPtr->Serial[2].Address;
1980 Bda->Com4 = SioPtr->Serial[3].Address;
1981
1982 if (SioPtr->Serial[0].Address != 0x00) {
1983 MachineConfig += 0x200;
1984 }
1985
1986 if (SioPtr->Serial[1].Address != 0x00) {
1987 MachineConfig += 0x200;
1988 }
1989
1990 if (SioPtr->Serial[2].Address != 0x00) {
1991 MachineConfig += 0x200;
1992 }
1993
1994 if (SioPtr->Serial[3].Address != 0x00) {
1995 MachineConfig += 0x200;
1996 }
1997
1998 Bda->Lpt1 = SioPtr->Parallel[0].Address;
1999 Bda->Lpt2 = SioPtr->Parallel[1].Address;
2000 Bda->Lpt3 = SioPtr->Parallel[2].Address;
2001
2002 if (SioPtr->Parallel[0].Address != 0x00) {
2003 MachineConfig += 0x4000;
2004 }
2005
2006 if (SioPtr->Parallel[1].Address != 0x00) {
2007 MachineConfig += 0x4000;
2008 }
2009
2010 if (SioPtr->Parallel[2].Address != 0x00) {
2011 MachineConfig += 0x4000;
2012 }
2013
2014 Bda->NumberOfDrives = (UINT8) (Bda->NumberOfDrives + Private->IdeDriveCount);
2015 if (SioPtr->Floppy.NumberOfFloppy != 0x00) {
2016 MachineConfig = (UINT16) (MachineConfig + 0x01 + (SioPtr->Floppy.NumberOfFloppy - 1) * 0x40);
2017 Bda->FloppyXRate = 0x07;
2018 }
2019
2020 Bda->Lpt1_2Timeout = 0x1414;
2021 Bda->Lpt3_4Timeout = 0x1414;
2022 Bda->Com1_2Timeout = 0x0101;
2023 Bda->Com3_4Timeout = 0x0101;
2024
2025 //
2026 // Force VGA and Coprocessor, indicate 101/102 keyboard
2027 //
2028 MachineConfig = (UINT16) (MachineConfig + 0x00 + 0x02 + (SioPtr->MousePresent * 0x04));
2029 Bda->MachineConfig = MachineConfig;
2030
2031 return EFI_SUCCESS;
2032 }
2033
2034 /**
2035 Fill in the standard BDA for Keyboard LEDs
2036
2037 @param This Protocol instance pointer.
2038 @param Leds Current LED status
2039
2040 @retval EFI_SUCCESS It should always work.
2041
2042 **/
2043 EFI_STATUS
2044 EFIAPI
2045 LegacyBiosUpdateKeyboardLedStatus (
2046 IN EFI_LEGACY_BIOS_PROTOCOL *This,
2047 IN UINT8 Leds
2048 )
2049 {
2050 LEGACY_BIOS_INSTANCE *Private;
2051 BDA_STRUC *Bda;
2052 UINT8 LocalLeds;
2053 EFI_IA32_REGISTER_SET Regs;
2054
2055 Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
2056
2057 ACCESS_PAGE0_CODE (
2058 Bda = (BDA_STRUC *) ((UINTN) 0x400);
2059 LocalLeds = Leds;
2060 Bda->LedStatus = (UINT8) ((Bda->LedStatus &~0x07) | LocalLeds);
2061 LocalLeds = (UINT8) (LocalLeds << 4);
2062 Bda->ShiftStatus = (UINT8) ((Bda->ShiftStatus &~0x70) | LocalLeds);
2063 LocalLeds = (UINT8) (Leds & 0x20);
2064 Bda->KeyboardStatus = (UINT8) ((Bda->KeyboardStatus &~0x20) | LocalLeds);
2065 );
2066
2067 //
2068 // Call into Legacy16 code to allow it to do any processing
2069 //
2070 ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
2071 Regs.X.AX = Legacy16SetKeyboardLeds;
2072 Regs.H.CL = Leds;
2073
2074 Private->LegacyBios.FarCall86 (
2075 &Private->LegacyBios,
2076 Private->Legacy16Table->Compatibility16CallSegment,
2077 Private->Legacy16Table->Compatibility16CallOffset,
2078 &Regs,
2079 NULL,
2080 0
2081 );
2082
2083 return EFI_SUCCESS;
2084 }
2085
2086
2087 /**
2088 Fill in the standard CMOS stuff prior to legacy Boot
2089
2090 @param Private Legacy BIOS Instance data
2091
2092 @retval EFI_SUCCESS It should always work.
2093
2094 **/
2095 EFI_STATUS
2096 LegacyBiosCompleteStandardCmosBeforeBoot (
2097 IN LEGACY_BIOS_INSTANCE *Private
2098 )
2099 {
2100 UINT8 Bda;
2101 UINT8 Floppy;
2102 UINT32 Size;
2103
2104 //
2105 // Update CMOS locations
2106 // 10 floppy
2107 // 12,19,1A - ignore as OS don't use them and there is no standard due
2108 // to large capacity drives
2109 // CMOS 14 = BDA 40:10 plus bit 3(display enabled)
2110 //
2111 ACCESS_PAGE0_CODE (
2112 Bda = (UINT8)(*((UINT8 *)((UINTN)0x410)) | BIT3);
2113 );
2114
2115 //
2116 // Force display enabled
2117 //
2118 Floppy = 0x00;
2119 if ((Bda & BIT0) != 0) {
2120 Floppy = BIT6;
2121 }
2122
2123 //
2124 // Check if 2.88MB floppy set
2125 //
2126 if ((Bda & (BIT7 | BIT6)) != 0) {
2127 Floppy = (UINT8)(Floppy | BIT1);
2128 }
2129
2130 LegacyWriteStandardCmos (CMOS_10, Floppy);
2131 LegacyWriteStandardCmos (CMOS_14, Bda);
2132
2133 //
2134 // Force Status Register A to set rate selection bits and divider
2135 //
2136 LegacyWriteStandardCmos (CMOS_0A, 0x26);
2137
2138 //
2139 // redo memory size since it can change
2140 //
2141 Size = (15 * SIZE_1MB) >> 10;
2142 if (Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb < (15 * SIZE_1MB)) {
2143 Size = Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb >> 10;
2144 }
2145
2146 LegacyWriteStandardCmos (CMOS_17, (UINT8)(Size & 0xFF));
2147 LegacyWriteStandardCmos (CMOS_30, (UINT8)(Size & 0xFF));
2148 LegacyWriteStandardCmos (CMOS_18, (UINT8)(Size >> 8));
2149 LegacyWriteStandardCmos (CMOS_31, (UINT8)(Size >> 8));
2150
2151 LegacyCalculateWriteStandardCmosChecksum ();
2152
2153 return EFI_SUCCESS;
2154 }
2155
2156 /**
2157 Relocate this image under 4G memory for IPF.
2158
2159 @param ImageHandle Handle of driver image.
2160 @param SystemTable Pointer to system table.
2161
2162 @retval EFI_SUCCESS Image successfully relocated.
2163 @retval EFI_ABORTED Failed to relocate image.
2164
2165 **/
2166 EFI_STATUS
2167 RelocateImageUnder4GIfNeeded (
2168 IN EFI_HANDLE ImageHandle,
2169 IN EFI_SYSTEM_TABLE *SystemTable
2170 )
2171 {
2172 return EFI_SUCCESS;
2173 }