1/** @file
2
3Copyright (c) 2006 - 2015, 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  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**/
1377EFI_STATUS
1378EFIAPI
1379LegacyBiosPrepareToBootEfi (
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***/
1414EFI_STATUS
1415EFIAPI
1416LegacyBiosBootUnconventionalDevice (
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**/
1577EFI_STATUS
1578EFIAPI
1579LegacyBiosLegacyBoot (
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**/
1605EFI_ACPI_MEMORY_TYPE
1606EfiMemoryTypeToE820Type (
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**/
1659EFI_STATUS
1660LegacyBiosBuildE820 (
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**/
1961EFI_STATUS
1962LegacyBiosCompleteBdaBeforeBoot (
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**/
2040EFI_STATUS
2041EFIAPI
2042LegacyBiosUpdateKeyboardLedStatus (
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**/
2089EFI_STATUS
2090LegacyBiosCompleteStandardCmosBeforeBoot (
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**/
2158EFI_STATUS
2159RelocateImageUnder4GIfNeeded (
2160  IN EFI_HANDLE           ImageHandle,
2161  IN EFI_SYSTEM_TABLE     *SystemTable
2162  )
2163{
2164  return EFI_SUCCESS;
2165}
2166