LegacyBootSupport.c revision b68237300a036c59dcb1231708e64e12fd2f734f
1/** @file
2
3Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
4
5This program and the accompanying materials
6are licensed and made available under the terms and conditions
7of the BSD License which accompanies this distribution.  The
8full text of the license may be found at
9http://opensource.org/licenses/bsd-license.php
10
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12WITHOUT 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
23UINT32              mLoadOptionsSize    = 0;
24UINTN               mBootMode           = BOOT_LEGACY_OS;
25VOID                *mLoadOptions       = NULL;
26BBS_BBS_DEVICE_PATH *mBbsDevicePathPtr  = NULL;
27BBS_BBS_DEVICE_PATH mBbsDevicePathNode;
28UDC_ATTRIBUTES      mAttributes         = { 0, 0, 0, 0 };
29UINTN               mBbsEntry           = 0;
30VOID                *mBeerData          = NULL;
31VOID                *mServiceAreaData   = NULL;
32UINT64              mLowWater           = 0xffffffffffffffffULL;
33
34extern BBS_TABLE           *mBbsTable;
35
36extern VOID                  *mRuntimeSmbiosEntryPoint;
37extern EFI_PHYSICAL_ADDRESS  mReserveSmbiosEntryPoint;
38extern EFI_PHYSICAL_ADDRESS  mStructureTableAddress;
39
40/**
41  Print the BBS Table.
42
43  @param BbsTable   The BBS table.
44
45
46**/
47VOID
48PrintBbsTable (
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**/
117VOID
118PrintHddInfo (
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**/
145VOID
146PrintPciInterruptRegister (
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**/
214VOID
215UpdateIdentifyDriveData (
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**/
227EFI_STATUS
228UpdateSioData (
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**/
368EFI_STATUS
369CalculateIdentifyDriveChecksum (
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**/
398VOID
399UpdateIdentifyDriveData (
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**/
465VOID
466UpdateAllIdentifyDriveData (
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**/
497VOID
498EnableIdeController (
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**/
540VOID
541EnableAllControllers (
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**/
635EFI_STATUS
636LegacyGetDataOrTable (
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**/
788VOID
789CreateSmbiosTableInReservedMemory (
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**/
853EFI_STATUS
854GenericLegacyBoot (
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  // Lock attributes of the Legacy Region if chipset supports
1243  //
1244  Private->LegacyRegion->BootLock (
1245                           Private->LegacyRegion,
1246                           0xc0000,
1247                           0x40000,
1248                           &Granularity
1249                           );
1250
1251  //
1252  // Call into Legacy16 code to do the INT 19h
1253  //
1254  EnableAllControllers (Private);
1255  if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
1256    //
1257    // Report Status Code to indicate legacy boot event will be signalled
1258    //
1259    REPORT_STATUS_CODE (
1260      EFI_PROGRESS_CODE,
1261      (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_LEGACY_BOOT_EVENT)
1262      );
1263
1264    //
1265    // Signal all the events that are waiting on EVT_SIGNAL_LEGACY_BOOT
1266    //
1267    EfiSignalEventLegacyBoot ();
1268    DEBUG ((EFI_D_INFO, "Legacy INT19 Boot...\n"));
1269
1270    //
1271    // Disable DXE Timer while executing in real mode
1272    //
1273    Private->Timer->SetTimerPeriod (Private->Timer, 0);
1274
1275    //
1276    // Save and disable interrupt of debug timer
1277    //
1278    SaveAndSetDebugTimerInterrupt (FALSE);
1279
1280
1281    //
1282    // Put the 8259 into its legacy mode by reprogramming the vector bases
1283    //
1284    Private->Legacy8259->SetVectorBase (Private->Legacy8259, LEGACY_MODE_BASE_VECTOR_MASTER, LEGACY_MODE_BASE_VECTOR_SLAVE);
1285    //
1286    // PC History
1287    //   The original PC used INT8-F for master PIC. Since these mapped over
1288    //   processor exceptions TIANO moved the master PIC to INT68-6F.
1289    // We need to set these back to the Legacy16 unexpected interrupt(saved
1290    // in LegacyBios.c) since some OS see that these have values different from
1291    // what is expected and invoke them. Since the legacy OS corrupts EFI
1292    // memory, there is no handler for these interrupts and OS blows up.
1293    //
1294    // We need to save the TIANO values for the rare case that the Legacy16
1295    // code cannot boot but knows memory hasn't been destroyed.
1296    //
1297    // To compound the problem, video takes over one of these INTS and must be
1298    // be left.
1299    // @bug - determine if video hooks INT(in which case we must find new
1300    //          set of TIANO vectors) or takes it over.
1301    //
1302    //
1303    BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);
1304    for (Index = 0; Index < 8; Index++) {
1305      Private->ThunkSavedInt[Index] = BaseVectorMaster[Index];
1306      if (Private->ThunkSeg == (UINT16) (BaseVectorMaster[Index] >> 16)) {
1307        BaseVectorMaster[Index] = (UINT32) (Private->BiosUnexpectedInt);
1308      }
1309    }
1310
1311    ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
1312    Regs.X.AX = Legacy16Boot;
1313
1314    Private->LegacyBios.FarCall86 (
1315      This,
1316      Private->Legacy16CallSegment,
1317      Private->Legacy16CallOffset,
1318      &Regs,
1319      NULL,
1320      0
1321      );
1322
1323    BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);
1324    for (Index = 0; Index < 8; Index++) {
1325      BaseVectorMaster[Index] = Private->ThunkSavedInt[Index];
1326    }
1327  }
1328  Private->LegacyBootEntered = TRUE;
1329  if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
1330    //
1331    // Should never return unless never passed control to 0:7c00(first stage
1332    // OS loader) and only then if no bootable device found.
1333    //
1334    return EFI_DEVICE_ERROR;
1335  } else {
1336    //
1337    // If boot to EFI then expect to return to caller
1338    //
1339    return EFI_SUCCESS;
1340  }
1341}
1342
1343
1344/**
1345  Assign drive number to legacy HDD drives prior to booting an EFI
1346  aware OS so the OS can access drives without an EFI driver.
1347  Note: BBS compliant drives ARE NOT available until this call by
1348  either shell or EFI.
1349
1350  @param  This                    Protocol instance pointer.
1351  @param  BbsCount                Number of BBS_TABLE structures
1352  @param  BbsTable                List BBS entries
1353
1354  @retval EFI_SUCCESS             Drive numbers assigned
1355
1356**/
1357EFI_STATUS
1358EFIAPI
1359LegacyBiosPrepareToBootEfi (
1360  IN EFI_LEGACY_BIOS_PROTOCOL         *This,
1361  OUT UINT16                          *BbsCount,
1362  OUT BBS_TABLE                       **BbsTable
1363  )
1364{
1365  EFI_STATUS                        Status;
1366  EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
1367  LEGACY_BIOS_INSTANCE              *Private;
1368
1369  Private                 = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
1370  EfiToLegacy16BootTable  = &Private->IntThunk->EfiToLegacy16BootTable;
1371  mBootMode               = BOOT_EFI_OS;
1372  mBbsDevicePathPtr       = NULL;
1373  Status                  = GenericLegacyBoot (This);
1374  *BbsTable               = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable;
1375  *BbsCount               = (UINT16) (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE));
1376  return Status;
1377}
1378
1379/**
1380  To boot from an unconventional device like parties and/or execute HDD diagnostics.
1381
1382  @param  This            Protocol instance pointer.
1383  @param  Attributes      How to interpret the other input parameters
1384  @param  BbsEntry        The 0-based index into the BbsTable for the parent
1385                          device.
1386  @param  BeerData        Pointer to the 128 bytes of ram BEER data.
1387  @param  ServiceAreaData Pointer to the 64 bytes of raw Service Area data. The
1388                          caller must provide a pointer to the specific Service
1389                          Area and not the start all Service Areas.
1390
1391  @retval EFI_INVALID_PARAMETER if error. Does NOT return if no error.
1392
1393***/
1394EFI_STATUS
1395EFIAPI
1396LegacyBiosBootUnconventionalDevice (
1397  IN EFI_LEGACY_BIOS_PROTOCOL         *This,
1398  IN UDC_ATTRIBUTES                   Attributes,
1399  IN UINTN                            BbsEntry,
1400  IN VOID                             *BeerData,
1401  IN VOID                             *ServiceAreaData
1402  )
1403{
1404  EFI_STATUS                        Status;
1405  EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
1406  LEGACY_BIOS_INSTANCE              *Private;
1407  UD_TABLE                          *UcdTable;
1408  UINTN                             Index;
1409  UINT16                            BootPriority;
1410  BBS_TABLE                         *BbsTable;
1411
1412  BootPriority = 0;
1413  Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
1414  mBootMode = BOOT_UNCONVENTIONAL_DEVICE;
1415  mBbsDevicePathPtr = &mBbsDevicePathNode;
1416  mAttributes = Attributes;
1417  mBbsEntry = BbsEntry;
1418  mBeerData = BeerData, mServiceAreaData = ServiceAreaData;
1419
1420  EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
1421
1422  //
1423  // Do input parameter checking
1424  //
1425  if ((Attributes.DirectoryServiceValidity == 0) &&
1426      (Attributes.RabcaUsedFlag == 0) &&
1427      (Attributes.ExecuteHddDiagnosticsFlag == 0)
1428      ) {
1429    return EFI_INVALID_PARAMETER;
1430  }
1431
1432  if (((Attributes.DirectoryServiceValidity != 0) && (ServiceAreaData == NULL)) ||
1433      (((Attributes.DirectoryServiceValidity | Attributes.RabcaUsedFlag) != 0) && (BeerData == NULL))
1434      ) {
1435    return EFI_INVALID_PARAMETER;
1436  }
1437
1438  UcdTable = (UD_TABLE *) AllocatePool (
1439														sizeof (UD_TABLE)
1440														);
1441  if (NULL == UcdTable) {
1442    return EFI_OUT_OF_RESOURCES;
1443  }
1444
1445  EfiToLegacy16BootTable->UnconventionalDeviceTable = (UINT32)(UINTN)UcdTable;
1446  UcdTable->Attributes = Attributes;
1447  UcdTable->BbsTableEntryNumberForParentDevice = (UINT8) BbsEntry;
1448  //
1449  // Force all existing BBS entries to DoNotBoot. This allows 16-bit CSM
1450  // to assign drive numbers but bot boot from. Only newly created entries
1451  // will be valid.
1452  //
1453  BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable;
1454  for (Index = 0; Index < EfiToLegacy16BootTable->NumberBbsEntries; Index++) {
1455    BbsTable[Index].BootPriority = BBS_DO_NOT_BOOT_FROM;
1456  }
1457  //
1458  // If parent is onboard IDE then assign controller & device number
1459  // else they are 0.
1460  //
1461  if (BbsEntry < MAX_IDE_CONTROLLER * 2) {
1462    UcdTable->DeviceNumber = (UINT8) ((BbsEntry - 1) % 2);
1463  }
1464
1465  if (BeerData != NULL) {
1466    CopyMem (
1467      (VOID *) UcdTable->BeerData,
1468      BeerData,
1469      (UINTN) 128
1470      );
1471  }
1472
1473  if (ServiceAreaData != NULL) {
1474    CopyMem (
1475      (VOID *) UcdTable->ServiceAreaData,
1476      ServiceAreaData,
1477      (UINTN) 64
1478      );
1479  }
1480  //
1481  // For each new entry do the following:
1482  //   1. Increment current number of BBS entries
1483  //   2. Copy parent entry to new entry.
1484  //   3. Zero out BootHandler Offset & segment
1485  //   4. Set appropriate device type. BEV(0x80) for HDD diagnostics
1486  //      and Floppy(0x01) for PARTIES boot.
1487  //   5. Assign new priority.
1488  //
1489  if ((Attributes.ExecuteHddDiagnosticsFlag) != 0) {
1490    EfiToLegacy16BootTable->NumberBbsEntries += 1;
1491
1492    CopyMem (
1493      (VOID *) &BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority,
1494      (VOID *) &BbsTable[BbsEntry].BootPriority,
1495      sizeof (BBS_TABLE)
1496      );
1497
1498    BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerOffset  = 0;
1499    BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerSegment = 0;
1500    BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].DeviceType         = 0x80;
1501
1502    UcdTable->BbsTableEntryNumberForHddDiag = (UINT8) (EfiToLegacy16BootTable->NumberBbsEntries - 1);
1503
1504    BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority = BootPriority;
1505    BootPriority += 1;
1506
1507    //
1508    // Set device type as BBS_TYPE_DEV for PARTIES diagnostic
1509    //
1510    mBbsDevicePathNode.DeviceType = BBS_TYPE_BEV;
1511  }
1512
1513  if (((Attributes.DirectoryServiceValidity | Attributes.RabcaUsedFlag)) != 0) {
1514    EfiToLegacy16BootTable->NumberBbsEntries += 1;
1515    CopyMem (
1516      (VOID *) &BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority,
1517      (VOID *) &BbsTable[BbsEntry].BootPriority,
1518      sizeof (BBS_TABLE)
1519      );
1520
1521    BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerOffset  = 0;
1522    BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerSegment = 0;
1523    BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].DeviceType         = 0x01;
1524    UcdTable->BbsTableEntryNumberForBoot = (UINT8) (EfiToLegacy16BootTable->NumberBbsEntries - 1);
1525    BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority = BootPriority;
1526
1527    //
1528    // Set device type as BBS_TYPE_FLOPPY for PARTIES boot as floppy
1529    //
1530    mBbsDevicePathNode.DeviceType = BBS_TYPE_FLOPPY;
1531  }
1532  //
1533  // Build the BBS Device Path for this boot selection
1534  //
1535  mBbsDevicePathNode.Header.Type    = BBS_DEVICE_PATH;
1536  mBbsDevicePathNode.Header.SubType = BBS_BBS_DP;
1537  SetDevicePathNodeLength (&mBbsDevicePathNode.Header, sizeof (BBS_BBS_DEVICE_PATH));
1538  mBbsDevicePathNode.StatusFlag = 0;
1539  mBbsDevicePathNode.String[0]  = 0;
1540
1541  Status                        = GenericLegacyBoot (This);
1542  return Status;
1543}
1544
1545/**
1546  Attempt to legacy boot the BootOption. If the EFI contexted has been
1547  compromised this function will not return.
1548
1549  @param  This             Protocol instance pointer.
1550  @param  BbsDevicePath    EFI Device Path from BootXXXX variable.
1551  @param  LoadOptionsSize  Size of LoadOption in size.
1552  @param  LoadOptions      LoadOption from BootXXXX variable
1553
1554  @retval EFI_SUCCESS      Removable media not present
1555
1556**/
1557EFI_STATUS
1558EFIAPI
1559LegacyBiosLegacyBoot (
1560  IN EFI_LEGACY_BIOS_PROTOCOL           *This,
1561  IN  BBS_BBS_DEVICE_PATH               *BbsDevicePath,
1562  IN  UINT32                            LoadOptionsSize,
1563  IN  VOID                              *LoadOptions
1564  )
1565{
1566  EFI_STATUS  Status;
1567
1568  mBbsDevicePathPtr = BbsDevicePath;
1569  mLoadOptionsSize  = LoadOptionsSize;
1570  mLoadOptions      = LoadOptions;
1571  mBootMode         = BOOT_LEGACY_OS;
1572  Status            = GenericLegacyBoot (This);
1573
1574  return Status;
1575}
1576
1577/**
1578  Convert EFI Memory Type to E820 Memory Type.
1579
1580  @param  Type  EFI Memory Type
1581
1582  @return ACPI Memory Type for EFI Memory Type
1583
1584**/
1585EFI_ACPI_MEMORY_TYPE
1586EfiMemoryTypeToE820Type (
1587  IN  UINT32    Type
1588  )
1589{
1590  switch (Type) {
1591  case EfiLoaderCode:
1592  case EfiLoaderData:
1593  case EfiBootServicesCode:
1594  case EfiBootServicesData:
1595  case EfiConventionalMemory:
1596  case EfiRuntimeServicesCode:
1597  case EfiRuntimeServicesData:
1598    return EfiAcpiAddressRangeMemory;
1599
1600  case EfiACPIReclaimMemory:
1601    return EfiAcpiAddressRangeACPI;
1602
1603  case EfiACPIMemoryNVS:
1604    return EfiAcpiAddressRangeNVS;
1605
1606  //
1607  // All other types map to reserved.
1608  // Adding the code just waists FLASH space.
1609  //
1610  //  case  EfiReservedMemoryType:
1611  //  case  EfiUnusableMemory:
1612  //  case  EfiMemoryMappedIO:
1613  //  case  EfiMemoryMappedIOPortSpace:
1614  //  case  EfiPalCode:
1615  //
1616  default:
1617    return EfiAcpiAddressRangeReserved;
1618  }
1619}
1620
1621/**
1622  Build the E820 table.
1623
1624  @param  Private  Legacy BIOS Instance data
1625  @param  Size     Size of E820 Table
1626
1627  @retval EFI_SUCCESS  It should always work.
1628
1629**/
1630EFI_STATUS
1631LegacyBiosBuildE820 (
1632  IN  LEGACY_BIOS_INSTANCE    *Private,
1633  OUT UINTN                   *Size
1634  )
1635{
1636  EFI_STATUS                  Status;
1637  EFI_E820_ENTRY64            *E820Table;
1638  EFI_MEMORY_DESCRIPTOR       *EfiMemoryMap;
1639  EFI_MEMORY_DESCRIPTOR       *EfiMemoryMapEnd;
1640  EFI_MEMORY_DESCRIPTOR       *EfiEntry;
1641  EFI_MEMORY_DESCRIPTOR       *NextEfiEntry;
1642  EFI_MEMORY_DESCRIPTOR       TempEfiEntry;
1643  UINTN                       EfiMemoryMapSize;
1644  UINTN                       EfiMapKey;
1645  UINTN                       EfiDescriptorSize;
1646  UINT32                      EfiDescriptorVersion;
1647  UINTN                       Index;
1648  EFI_PEI_HOB_POINTERS        Hob;
1649  EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
1650  UINTN                       TempIndex;
1651  UINTN                       IndexSort;
1652  UINTN                       TempNextIndex;
1653  EFI_E820_ENTRY64            TempE820;
1654  EFI_ACPI_MEMORY_TYPE        TempType;
1655  BOOLEAN                     ChangedFlag;
1656  UINTN                       Above1MIndex;
1657  UINT64                      MemoryBlockLength;
1658
1659  E820Table = (EFI_E820_ENTRY64 *) Private->E820Table;
1660
1661  //
1662  // Get the EFI memory map.
1663  //
1664  EfiMemoryMapSize  = 0;
1665  EfiMemoryMap      = NULL;
1666  Status = gBS->GetMemoryMap (
1667                  &EfiMemoryMapSize,
1668                  EfiMemoryMap,
1669                  &EfiMapKey,
1670                  &EfiDescriptorSize,
1671                  &EfiDescriptorVersion
1672                  );
1673  ASSERT (Status == EFI_BUFFER_TOO_SMALL);
1674
1675  do {
1676    //
1677    // Use size returned back plus 1 descriptor for the AllocatePool.
1678    // We don't just multiply by 2 since the "for" loop below terminates on
1679    // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwize
1680    // we process bogus entries and create bogus E820 entries.
1681    //
1682    EfiMemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (EfiMemoryMapSize);
1683    ASSERT (EfiMemoryMap != NULL);
1684    Status = gBS->GetMemoryMap (
1685                    &EfiMemoryMapSize,
1686                    EfiMemoryMap,
1687                    &EfiMapKey,
1688                    &EfiDescriptorSize,
1689                    &EfiDescriptorVersion
1690                    );
1691    if (EFI_ERROR (Status)) {
1692      FreePool (EfiMemoryMap);
1693    }
1694  } while (Status == EFI_BUFFER_TOO_SMALL);
1695
1696  ASSERT_EFI_ERROR (Status);
1697
1698  //
1699  // Punch in the E820 table for memory less than 1 MB.
1700  // Assume ZeroMem () has been done on data structure.
1701  //
1702  //
1703  // First entry is 0 to (640k - EBDA)
1704  //
1705  E820Table[0].BaseAddr  = 0;
1706  E820Table[0].Length    = (UINT64) ((*(UINT16 *) (UINTN)0x40E) << 4);
1707  E820Table[0].Type      = EfiAcpiAddressRangeMemory;
1708
1709  //
1710  // Second entry is (640k - EBDA) to 640k
1711  //
1712  E820Table[1].BaseAddr  = E820Table[0].Length;
1713  E820Table[1].Length    = (UINT64) ((640 * 1024) - E820Table[0].Length);
1714  E820Table[1].Type      = EfiAcpiAddressRangeReserved;
1715
1716  //
1717  // Third Entry is legacy BIOS
1718  // DO NOT CLAIM region from 0xA0000-0xDFFFF. OS can use free areas
1719  // to page in memory under 1MB.
1720  // Omit region from 0xE0000 to start of BIOS, if any. This can be
1721  // used for a multiple reasons including OPROMS.
1722  //
1723
1724  //
1725  // The CSM binary image size is not the actually size that CSM binary used,
1726  // to avoid memory corrupt, we declare the 0E0000 - 0FFFFF is used by CSM binary.
1727  //
1728  E820Table[2].BaseAddr  = 0xE0000;
1729  E820Table[2].Length    = 0x20000;
1730  E820Table[2].Type      = EfiAcpiAddressRangeReserved;
1731
1732  Above1MIndex = 2;
1733
1734  //
1735  // Process the EFI map to produce E820 map;
1736  //
1737
1738  //
1739  // Sort memory map from low to high
1740  //
1741  EfiEntry        = EfiMemoryMap;
1742  NextEfiEntry    = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
1743  EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);
1744  while (EfiEntry < EfiMemoryMapEnd) {
1745    while (NextEfiEntry < EfiMemoryMapEnd) {
1746      if (EfiEntry->PhysicalStart > NextEfiEntry->PhysicalStart) {
1747        CopyMem (&TempEfiEntry, EfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
1748        CopyMem (EfiEntry, NextEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
1749        CopyMem (NextEfiEntry, &TempEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
1750      }
1751
1752      NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (NextEfiEntry, EfiDescriptorSize);
1753    }
1754
1755    EfiEntry      = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
1756    NextEfiEntry  = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
1757  }
1758
1759  EfiEntry        = EfiMemoryMap;
1760  EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);
1761  for (Index = Above1MIndex; (EfiEntry < EfiMemoryMapEnd) && (Index < EFI_MAX_E820_ENTRY - 1); ) {
1762    MemoryBlockLength = (UINT64) (LShiftU64 (EfiEntry->NumberOfPages, 12));
1763    if ((EfiEntry->PhysicalStart + MemoryBlockLength) < 0x100000) {
1764      //
1765      // Skip the memory block is under 1MB
1766      //
1767    } else {
1768      if (EfiEntry->PhysicalStart < 0x100000) {
1769        //
1770        // When the memory block spans below 1MB, ensure the memory block start address is at least 1MB
1771        //
1772        MemoryBlockLength       -= 0x100000 - EfiEntry->PhysicalStart;
1773        EfiEntry->PhysicalStart =  0x100000;
1774      }
1775
1776      //
1777      // Convert memory type to E820 type
1778      //
1779      TempType = EfiMemoryTypeToE820Type (EfiEntry->Type);
1780
1781      if ((E820Table[Index].Type == TempType) && (EfiEntry->PhysicalStart == (E820Table[Index].BaseAddr + E820Table[Index].Length))) {
1782        //
1783        // Grow an existing entry
1784        //
1785        E820Table[Index].Length += MemoryBlockLength;
1786      } else {
1787        //
1788        // Make a new entry
1789        //
1790        ++Index;
1791        E820Table[Index].BaseAddr  = EfiEntry->PhysicalStart;
1792        E820Table[Index].Length    = MemoryBlockLength;
1793        E820Table[Index].Type      = TempType;
1794      }
1795    }
1796    EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
1797  }
1798
1799  FreePool (EfiMemoryMap);
1800
1801  //
1802  // Process the reserved memory map to produce E820 map ;
1803  //
1804  for (Hob.Raw = GetHobList (); !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
1805    if (Hob.Raw != NULL && GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
1806      ResourceHob = Hob.ResourceDescriptor;
1807      if (((ResourceHob->ResourceType == EFI_RESOURCE_MEMORY_MAPPED_IO) ||
1808          (ResourceHob->ResourceType == EFI_RESOURCE_FIRMWARE_DEVICE)  ||
1809          (ResourceHob->ResourceType == EFI_RESOURCE_MEMORY_RESERVED)    ) &&
1810          (ResourceHob->PhysicalStart > 0x100000) &&
1811          (Index < EFI_MAX_E820_ENTRY - 1)) {
1812        ++Index;
1813        E820Table[Index].BaseAddr  = ResourceHob->PhysicalStart;
1814        E820Table[Index].Length    = ResourceHob->ResourceLength;
1815        E820Table[Index].Type      = EfiAcpiAddressRangeReserved;
1816      }
1817    }
1818  }
1819
1820  Index ++;
1821  Private->IntThunk->EfiToLegacy16InitTable.NumberE820Entries = (UINT32)Index;
1822  Private->IntThunk->EfiToLegacy16BootTable.NumberE820Entries = (UINT32)Index;
1823  Private->NumberE820Entries = (UINT32)Index;
1824  *Size = (UINTN) (Index * sizeof (EFI_E820_ENTRY64));
1825
1826  //
1827  // Sort E820Table from low to high
1828  //
1829  for (TempIndex = 0; TempIndex < Index; TempIndex++) {
1830    ChangedFlag = FALSE;
1831    for (TempNextIndex = 1; TempNextIndex < Index - TempIndex; TempNextIndex++) {
1832      if (E820Table[TempNextIndex - 1].BaseAddr > E820Table[TempNextIndex].BaseAddr) {
1833        ChangedFlag                       = TRUE;
1834        TempE820.BaseAddr                 = E820Table[TempNextIndex - 1].BaseAddr;
1835        TempE820.Length                   = E820Table[TempNextIndex - 1].Length;
1836        TempE820.Type                     = E820Table[TempNextIndex - 1].Type;
1837
1838        E820Table[TempNextIndex - 1].BaseAddr  = E820Table[TempNextIndex].BaseAddr;
1839        E820Table[TempNextIndex - 1].Length    = E820Table[TempNextIndex].Length;
1840        E820Table[TempNextIndex - 1].Type      = E820Table[TempNextIndex].Type;
1841
1842        E820Table[TempNextIndex].BaseAddr      = TempE820.BaseAddr;
1843        E820Table[TempNextIndex].Length        = TempE820.Length;
1844        E820Table[TempNextIndex].Type          = TempE820.Type;
1845      }
1846    }
1847
1848    if (!ChangedFlag) {
1849      break;
1850    }
1851  }
1852
1853  //
1854  // Remove the overlap range
1855  //
1856  for (TempIndex = 1; TempIndex < Index; TempIndex++) {
1857    if (E820Table[TempIndex - 1].BaseAddr <= E820Table[TempIndex].BaseAddr &&
1858        ((E820Table[TempIndex - 1].BaseAddr + E820Table[TempIndex - 1].Length) >=
1859         (E820Table[TempIndex].BaseAddr +E820Table[TempIndex].Length))) {
1860        //
1861        //Overlap range is found
1862        //
1863        ASSERT (E820Table[TempIndex - 1].Type == E820Table[TempIndex].Type);
1864
1865        if (TempIndex == Index - 1) {
1866          E820Table[TempIndex].BaseAddr = 0;
1867          E820Table[TempIndex].Length   = 0;
1868          E820Table[TempIndex].Type     = (EFI_ACPI_MEMORY_TYPE) 0;
1869          Index--;
1870          break;
1871        } else {
1872          for (IndexSort = TempIndex; IndexSort < Index - 1; IndexSort ++) {
1873            E820Table[IndexSort].BaseAddr = E820Table[IndexSort + 1].BaseAddr;
1874            E820Table[IndexSort].Length   = E820Table[IndexSort + 1].Length;
1875            E820Table[IndexSort].Type     = E820Table[IndexSort + 1].Type;
1876          }
1877          Index--;
1878       }
1879    }
1880  }
1881
1882
1883
1884  Private->IntThunk->EfiToLegacy16InitTable.NumberE820Entries = (UINT32)Index;
1885  Private->IntThunk->EfiToLegacy16BootTable.NumberE820Entries = (UINT32)Index;
1886  Private->NumberE820Entries = (UINT32)Index;
1887  *Size = (UINTN) (Index * sizeof (EFI_E820_ENTRY64));
1888
1889  //
1890  // Determine OS usable memory above 1Mb
1891  //
1892  Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb = 0x0000;
1893  for (TempIndex = Above1MIndex; TempIndex < Index; TempIndex++) {
1894    if (E820Table[TempIndex].BaseAddr >= 0x100000 && E820Table[TempIndex].BaseAddr < 0x100000000ULL) { // not include above 4G memory
1895      //
1896      // ACPIReclaimMemory is also usable memory for ACPI OS, after OS dumps all ACPI tables.
1897      //
1898      if ((E820Table[TempIndex].Type == EfiAcpiAddressRangeMemory) || (E820Table[TempIndex].Type == EfiAcpiAddressRangeACPI)) {
1899        Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb += (UINT32) (E820Table[TempIndex].Length);
1900      } else {
1901        break; // break at first not normal memory, because SMM may use reserved memory.
1902      }
1903    }
1904  }
1905
1906  Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb = Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb;
1907
1908  //
1909  // Print DEBUG information
1910  //
1911  for (TempIndex = 0; TempIndex < Index; TempIndex++) {
1912    DEBUG((EFI_D_INFO, "E820[%2d]: 0x%16lx ---- 0x%16lx, Type = 0x%x \n",
1913      TempIndex,
1914      E820Table[TempIndex].BaseAddr,
1915      (E820Table[TempIndex].BaseAddr + E820Table[TempIndex].Length),
1916      E820Table[TempIndex].Type
1917      ));
1918  }
1919
1920  return EFI_SUCCESS;
1921}
1922
1923
1924/**
1925  Fill in the standard BDA and EBDA stuff prior to legacy Boot
1926
1927  @param  Private      Legacy BIOS Instance data
1928
1929  @retval EFI_SUCCESS  It should always work.
1930
1931**/
1932EFI_STATUS
1933LegacyBiosCompleteBdaBeforeBoot (
1934  IN  LEGACY_BIOS_INSTANCE    *Private
1935  )
1936{
1937  BDA_STRUC                   *Bda;
1938  UINT16                      MachineConfig;
1939  DEVICE_PRODUCER_DATA_HEADER *SioPtr;
1940
1941  Bda           = (BDA_STRUC *) ((UINTN) 0x400);
1942  MachineConfig = 0;
1943
1944  SioPtr        = &(Private->IntThunk->EfiToLegacy16BootTable.SioData);
1945  Bda->Com1     = SioPtr->Serial[0].Address;
1946  Bda->Com2     = SioPtr->Serial[1].Address;
1947  Bda->Com3     = SioPtr->Serial[2].Address;
1948  Bda->Com4     = SioPtr->Serial[3].Address;
1949
1950  if (SioPtr->Serial[0].Address != 0x00) {
1951    MachineConfig += 0x200;
1952  }
1953
1954  if (SioPtr->Serial[1].Address != 0x00) {
1955    MachineConfig += 0x200;
1956  }
1957
1958  if (SioPtr->Serial[2].Address != 0x00) {
1959    MachineConfig += 0x200;
1960  }
1961
1962  if (SioPtr->Serial[3].Address != 0x00) {
1963    MachineConfig += 0x200;
1964  }
1965
1966  Bda->Lpt1 = SioPtr->Parallel[0].Address;
1967  Bda->Lpt2 = SioPtr->Parallel[1].Address;
1968  Bda->Lpt3 = SioPtr->Parallel[2].Address;
1969
1970  if (SioPtr->Parallel[0].Address != 0x00) {
1971    MachineConfig += 0x4000;
1972  }
1973
1974  if (SioPtr->Parallel[1].Address != 0x00) {
1975    MachineConfig += 0x4000;
1976  }
1977
1978  if (SioPtr->Parallel[2].Address != 0x00) {
1979    MachineConfig += 0x4000;
1980  }
1981
1982  Bda->NumberOfDrives = (UINT8) (Bda->NumberOfDrives + Private->IdeDriveCount);
1983  if (SioPtr->Floppy.NumberOfFloppy != 0x00) {
1984    MachineConfig     = (UINT16) (MachineConfig + 0x01 + (SioPtr->Floppy.NumberOfFloppy - 1) * 0x40);
1985    Bda->FloppyXRate  = 0x07;
1986  }
1987
1988  Bda->Lpt1_2Timeout  = 0x1414;
1989  Bda->Lpt3_4Timeout  = 0x1414;
1990  Bda->Com1_2Timeout  = 0x0101;
1991  Bda->Com3_4Timeout  = 0x0101;
1992
1993  //
1994  // Force VGA and Coprocessor, indicate 101/102 keyboard
1995  //
1996  MachineConfig       = (UINT16) (MachineConfig + 0x00 + 0x02 + (SioPtr->MousePresent * 0x04));
1997  Bda->MachineConfig  = MachineConfig;
1998
1999  return EFI_SUCCESS;
2000}
2001
2002/**
2003  Fill in the standard BDA for Keyboard LEDs
2004
2005  @param  This         Protocol instance pointer.
2006  @param  Leds         Current LED status
2007
2008  @retval EFI_SUCCESS  It should always work.
2009
2010**/
2011EFI_STATUS
2012EFIAPI
2013LegacyBiosUpdateKeyboardLedStatus (
2014  IN EFI_LEGACY_BIOS_PROTOCOL           *This,
2015  IN  UINT8                             Leds
2016  )
2017{
2018  LEGACY_BIOS_INSTANCE  *Private;
2019  BDA_STRUC             *Bda;
2020  UINT8                 LocalLeds;
2021  EFI_IA32_REGISTER_SET Regs;
2022
2023  Bda                 = (BDA_STRUC *) ((UINTN) 0x400);
2024
2025  Private             = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
2026  LocalLeds           = Leds;
2027  Bda->LedStatus      = (UINT8) ((Bda->LedStatus &~0x07) | LocalLeds);
2028  LocalLeds           = (UINT8) (LocalLeds << 4);
2029  Bda->ShiftStatus    = (UINT8) ((Bda->ShiftStatus &~0x70) | LocalLeds);
2030  LocalLeds           = (UINT8) (Leds & 0x20);
2031  Bda->KeyboardStatus = (UINT8) ((Bda->KeyboardStatus &~0x20) | LocalLeds);
2032  //
2033  // Call into Legacy16 code to allow it to do any processing
2034  //
2035  ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
2036  Regs.X.AX = Legacy16SetKeyboardLeds;
2037  Regs.H.CL = Leds;
2038
2039  Private->LegacyBios.FarCall86 (
2040    &Private->LegacyBios,
2041    Private->Legacy16Table->Compatibility16CallSegment,
2042    Private->Legacy16Table->Compatibility16CallOffset,
2043    &Regs,
2044    NULL,
2045    0
2046    );
2047
2048  return EFI_SUCCESS;
2049}
2050
2051
2052/**
2053  Fill in the standard CMOS stuff prior to legacy Boot
2054
2055  @param  Private      Legacy BIOS Instance data
2056
2057  @retval EFI_SUCCESS  It should always work.
2058
2059**/
2060EFI_STATUS
2061LegacyBiosCompleteStandardCmosBeforeBoot (
2062  IN  LEGACY_BIOS_INSTANCE    *Private
2063  )
2064{
2065  UINT8   Bda;
2066  UINT8   Floppy;
2067  UINT32  Size;
2068
2069  //
2070  // Update CMOS locations
2071  // 10 floppy
2072  // 12,19,1A - ignore as OS don't use them and there is no standard due
2073  //            to large capacity drives
2074  // CMOS 14 = BDA 40:10 plus bit 3(display enabled)
2075  //
2076  Bda = (UINT8)(*((UINT8 *)((UINTN)0x410)) | BIT3);
2077
2078  //
2079  // Force display enabled
2080  //
2081  Floppy = 0x00;
2082  if ((Bda & BIT0) != 0) {
2083    Floppy = BIT6;
2084  }
2085
2086  //
2087  // Check if 2.88MB floppy set
2088  //
2089  if ((Bda & (BIT7 | BIT6)) != 0) {
2090    Floppy = (UINT8)(Floppy | BIT1);
2091  }
2092
2093  LegacyWriteStandardCmos (CMOS_10, Floppy);
2094  LegacyWriteStandardCmos (CMOS_14, Bda);
2095
2096  //
2097  // Force Status Register A to set rate selection bits and divider
2098  //
2099  LegacyWriteStandardCmos (CMOS_0A, 0x26);
2100
2101  //
2102  // redo memory size since it can change
2103  //
2104  Size = 15 * SIZE_1MB;
2105  if (Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb < (15 * SIZE_1MB)) {
2106    Size  = Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb >> 10;
2107  }
2108
2109  LegacyWriteStandardCmos (CMOS_17, (UINT8)(Size & 0xFF));
2110  LegacyWriteStandardCmos (CMOS_30, (UINT8)(Size & 0xFF));
2111  LegacyWriteStandardCmos (CMOS_18, (UINT8)(Size >> 8));
2112  LegacyWriteStandardCmos (CMOS_31, (UINT8)(Size >> 8));
2113
2114  LegacyCalculateWriteStandardCmosChecksum ();
2115
2116  return EFI_SUCCESS;
2117}
2118
2119/**
2120  Relocate this image under 4G memory for IPF.
2121
2122  @param  ImageHandle  Handle of driver image.
2123  @param  SystemTable  Pointer to system table.
2124
2125  @retval EFI_SUCCESS  Image successfully relocated.
2126  @retval EFI_ABORTED  Failed to relocate image.
2127
2128**/
2129EFI_STATUS
2130RelocateImageUnder4GIfNeeded (
2131  IN EFI_HANDLE           ImageHandle,
2132  IN EFI_SYSTEM_TABLE     *SystemTable
2133  )
2134{
2135  return EFI_SUCCESS;
2136}
2137