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