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