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
PrintBbsTable(IN BBS_TABLE * BbsTable)41 PrintBbsTable (
42   IN BBS_TABLE *BbsTable
43   )
44 {
45   UINT16 Index;
46   UINT16 SubIndex;
47   CHAR8  *String;
48 
49   DEBUG ((DEBUG_INFO, "\n"));
50   DEBUG ((DEBUG_INFO, " NO  Prio bb/dd/ff cl/sc Type Stat segm:offs mfgs:mfgo dess:deso\n"));
51   DEBUG ((DEBUG_INFO, "=================================================================\n"));
52   for (Index = 0; Index < MAX_BBS_ENTRIES; Index++) {
53     //
54     // Filter
55     //
56     if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {
57       continue;
58     }
59 
60     DEBUG ((
61       DEBUG_INFO,
62       " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x",
63       (UINTN) Index,
64       (UINTN) BbsTable[Index].BootPriority,
65       (UINTN) BbsTable[Index].Bus,
66       (UINTN) BbsTable[Index].Device,
67       (UINTN) BbsTable[Index].Function,
68       (UINTN) BbsTable[Index].Class,
69       (UINTN) BbsTable[Index].SubClass,
70       (UINTN) BbsTable[Index].DeviceType,
71       (UINTN) * (UINT16 *) &BbsTable[Index].StatusFlags
72       ));
73     DEBUG ((
74       DEBUG_INFO,
75       " %04x:%04x %04x:%04x %04x:%04x",
76       (UINTN) BbsTable[Index].BootHandlerSegment,
77       (UINTN) BbsTable[Index].BootHandlerOffset,
78       (UINTN) BbsTable[Index].MfgStringSegment,
79       (UINTN) BbsTable[Index].MfgStringOffset,
80       (UINTN) BbsTable[Index].DescStringSegment,
81       (UINTN) BbsTable[Index].DescStringOffset
82       ));
83 
84     //
85     // Print DescString
86     //
87     String = (CHAR8 *)(((UINTN)BbsTable[Index].DescStringSegment << 4) + BbsTable[Index].DescStringOffset);
88     if (String != NULL) {
89       DEBUG ((DEBUG_INFO," ("));
90       for (SubIndex = 0; String[SubIndex] != 0; SubIndex++) {
91         DEBUG ((DEBUG_INFO, "%c", String[SubIndex]));
92       }
93       DEBUG ((DEBUG_INFO,")"));
94     }
95     DEBUG ((DEBUG_INFO,"\n"));
96   }
97 
98   DEBUG ((DEBUG_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
PrintHddInfo(IN HDD_INFO * HddInfo)111 PrintHddInfo (
112   IN HDD_INFO *HddInfo
113   )
114 {
115   UINTN Index;
116 
117   DEBUG ((DEBUG_INFO, "\n"));
118   for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) {
119     DEBUG ((DEBUG_INFO, "Index - %04x\n", Index));
120     DEBUG ((DEBUG_INFO, "  Status    - %04x\n", (UINTN)HddInfo[Index].Status));
121     DEBUG ((DEBUG_INFO, "  B/D/F     - %02x/%02x/%02x\n", (UINTN)HddInfo[Index].Bus, (UINTN)HddInfo[Index].Device, (UINTN)HddInfo[Index].Function));
122     DEBUG ((DEBUG_INFO, "  Command   - %04x\n", HddInfo[Index].CommandBaseAddress));
123     DEBUG ((DEBUG_INFO, "  Control   - %04x\n", HddInfo[Index].ControlBaseAddress));
124     DEBUG ((DEBUG_INFO, "  BusMaster - %04x\n", HddInfo[Index].BusMasterAddress));
125     DEBUG ((DEBUG_INFO, "  HddIrq    - %02x\n", HddInfo[Index].HddIrq));
126     DEBUG ((DEBUG_INFO, "  IdentifyDrive[0].Raw[0] - %x\n", HddInfo[Index].IdentifyDrive[0].Raw[0]));
127     DEBUG ((DEBUG_INFO, "  IdentifyDrive[1].Raw[0] - %x\n", HddInfo[Index].IdentifyDrive[1].Raw[0]));
128   }
129 
130   DEBUG ((DEBUG_INFO, "\n"));
131 
132   return ;
133 }
134 
135 /**
136   Print the PCI Interrupt Line and Interrupt Pin registers.
137 **/
138 VOID
PrintPciInterruptRegister(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 ((DEBUG_INFO, "\n"));
167   DEBUG ((DEBUG_INFO, " bb/dd/ff interrupt line interrupt pin\n"));
168   DEBUG ((DEBUG_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 ((DEBUG_INFO, " %02x/%02x/%02x 0x%02x           0x%02x\n",
191               Bus, Device, Function, Interrupt[0], Interrupt[1]));
192     }
193   }
194   DEBUG ((DEBUG_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
UpdateSioData(IN LEGACY_BIOS_INSTANCE * Private)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
CalculateIdentifyDriveChecksum(IN UINT8 * IdentifyDriveData,OUT UINT8 * Checksum)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
UpdateIdentifyDriveData(IN UINT8 * IdentifyDriveData)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
UpdateAllIdentifyDriveData(IN LEGACY_BIOS_INSTANCE * Private)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
EnableIdeController(IN LEGACY_BIOS_INSTANCE * Private)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
EnableAllControllers(IN LEGACY_BIOS_INSTANCE * Private)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
LegacyGetDataOrTable(IN EFI_LEGACY_BIOS_PROTOCOL * This,IN EFI_GET_PLATFORM_INFO_MODE Id)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 ((DEBUG_INFO, "LegacyGetDataOrTable - ID: %x, %r\n", (UINTN)Id, Status));
671         DEBUG ((DEBUG_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 ((DEBUG_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 ((DEBUG_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 ((DEBUG_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 ((DEBUG_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 ((DEBUG_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
CreateSmbiosTableInReservedMemory(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
GenericLegacyBoot(IN EFI_LEGACY_BIOS_PROTOCOL * This)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 ((DEBUG_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 ((DEBUG_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 possible that a platform does not produce SmbiosTable.
966   //
967   if (mReserveSmbiosEntryPoint == 0) {
968     DEBUG ((DEBUG_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 possible that a platform does not produce AcpiTable.
986   //
987   if (AcpiTable == NULL) {
988     DEBUG ((DEBUG_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((DEBUG_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 ((DEBUG_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
LegacyBiosPrepareToBootEfi(IN EFI_LEGACY_BIOS_PROTOCOL * This,OUT UINT16 * BbsCount,OUT BBS_TABLE ** BbsTable)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
LegacyBiosBootUnconventionalDevice(IN EFI_LEGACY_BIOS_PROTOCOL * This,IN UDC_ATTRIBUTES Attributes,IN UINTN BbsEntry,IN VOID * BeerData,IN VOID * ServiceAreaData)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
LegacyBiosLegacyBoot(IN EFI_LEGACY_BIOS_PROTOCOL * This,IN BBS_BBS_DEVICE_PATH * BbsDevicePath,IN UINT32 LoadOptionsSize,IN VOID * LoadOptions)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
EfiMemoryTypeToE820Type(IN UINT32 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
LegacyBiosBuildE820(IN LEGACY_BIOS_INSTANCE * Private,OUT UINTN * Size)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((DEBUG_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
LegacyBiosCompleteBdaBeforeBoot(IN LEGACY_BIOS_INSTANCE * Private)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
LegacyBiosUpdateKeyboardLedStatus(IN EFI_LEGACY_BIOS_PROTOCOL * This,IN UINT8 Leds)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
LegacyBiosCompleteStandardCmosBeforeBoot(IN LEGACY_BIOS_INSTANCE * Private)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
RelocateImageUnder4GIfNeeded(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)2170 RelocateImageUnder4GIfNeeded (
2171   IN EFI_HANDLE           ImageHandle,
2172   IN EFI_SYSTEM_TABLE     *SystemTable
2173   )
2174 {
2175   return EFI_SUCCESS;
2176 }
2177