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