1 /** @file
2   Legacy BIOS Platform support
3 
4   Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
5 
6   This program and the accompanying materials are
7   licensed and made available under the terms and conditions of the BSD License
8   which accompanies this distribution.  The full text of the license may be found at
9   http://opensource.org/licenses/bsd-license.php
10 
11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include "LegacyPlatform.h"
17 
18 EFI_SETUP_BBS_MAP mSetupBbsMap[] = {
19   { 1, 2,     1, 1 },     // ATA HardDrive
20   { 2, 3,     1, 1 },     // ATAPI CDROM
21   { 3, 0x80,  2, 0 },     // PXE
22   { 4, 1,     0, 6 },     // USB Floppy
23   { 4, 2,     0, 6 },     // USB HDD
24   { 4, 3,     0, 6 },     // USB CD
25   { 4, 1,     0, 0 },     // USB ZIP Bugbug since Class/SubClass code is uninitialized
26   { 4, 2,     0, 0 }      // USB ZIP Bugbug since Class/SubClass code is uninitialized
27 };
28 
29 //
30 // Global variables for System ROMs
31 //
32 #define SYSTEM_ROM_FILE_GUID \
33 { 0x1547B4F3, 0x3E8A, 0x4FEF, { 0x81, 0xC8, 0x32, 0x8E, 0xD6, 0x47, 0xAB, 0x1A } }
34 
35 #define NULL_ROM_FILE_GUID \
36 { 0x00000000, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }
37 
38 SYSTEM_ROM_TABLE mSystemRomTable[] = {
39   { SYSTEM_ROM_FILE_GUID,  1 },
40   { NULL_ROM_FILE_GUID,    0 }
41 };
42 
43 EFI_HANDLE  mVgaHandles[0x20];
44 EFI_HANDLE  mDiskHandles[0x20];
45 EFI_HANDLE  mIsaHandles[0x20];
46 
47 EFI_LEGACY_IRQ_PRIORITY_TABLE_ENTRY IrqPriorityTable[MAX_IRQ_PRIORITY_ENTRIES] = {
48   {0x0B,0},
49   {0x09,0},
50   {0x0A,0},
51   {0x05,0},
52   {0x07,0},
53   {0x00,0},
54   {0x00,0}
55 };
56 
57 //
58 // PIRQ Table
59 // - Slot numbering will be used to update the bus number and determine bridge
60 //   to check to get bus number.  The Slot number - 1 is an index into a decode
61 //   table to get the bridge information.
62 //
63 EFI_LEGACY_PIRQ_TABLE PirqTableHead = {
64   {
65     EFI_LEGACY_PIRQ_TABLE_SIGNATURE, // UINT32  Signature
66     0x00,             // UINT8   MinorVersion
67     0x01,             // UINT8   MajorVersion
68     0x0000,           // UINT16  TableSize
69     0x00,             // UINT8   Bus
70     0x08,             // UINT8   DevFun
71     0x0000,           // UINT16  PciOnlyIrq
72     0x8086,           // UINT16  CompatibleVid
73     0x122e,           // UINT16  CompatibleDid
74     0x00000000,       // UINT32  Miniport
75     {                 // UINT8   Reserved[11]
76       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
77       0x00, 0x00, 0x00
78     },
79     0x00,             // UINT8   Checksum
80   },
81   {
82     //           -- Pin 1 --   -- Pin 2 --   -- Pin 3 --   -- Pin 4 --
83     // Bus  Dev   Reg   Map     Reg   Map     Reg   Map     Reg   Map
84     //
85     {0x00,0x08,{{0x60,0xDEB8},{0x61,0xDEB8},{0x62,0xDEB8},{0x63,0xDEB8}},0x00,0x00},
86     {0x00,0x10,{{0x61,0xDEB8},{0x62,0xDEB8},{0x63,0xDEB8},{0x60,0xDEB8}},0x01,0x00},
87     {0x00,0x18,{{0x62,0xDEB8},{0x63,0xDEB8},{0x60,0xDEB8},{0x61,0xDEB8}},0x02,0x00},
88     {0x00,0x20,{{0x63,0xDEB8},{0x60,0xDEB8},{0x61,0xDEB8},{0x62,0xDEB8}},0x03,0x00},
89     {0x00,0x28,{{0x60,0xDEB8},{0x61,0xDEB8},{0x62,0xDEB8},{0x63,0xDEB8}},0x04,0x00},
90     {0x00,0x30,{{0x61,0xDEB8},{0x62,0xDEB8},{0x63,0xDEB8},{0x60,0xDEB8}},0x05,0x00},
91   }
92 };
93 
94 LEGACY_BIOS_PLATFORM_INSTANCE       mPrivateData;
95 EFI_HANDLE                          mImageHandle = NULL;
96 
97 /**
98   Return the handles and assorted information for the specified PCI Class code
99 
100   @param[in]     PciClasses    Array of PCI_CLASS_RECORD to find terminated with ClassCode 0xff
101   @param[in,out] DeviceTable   Table to place handles etc in.
102   @param[in,out] DeviceIndex   Number of devices found
103   @param[in]     DeviceFlags   FALSE if a valid legacy ROM is required, TRUE otherwise.
104 
105   @retval EFI_SUCCESS     One or more devices found
106   @retval EFI_NOT_FOUND   No device found
107 
108 **/
109 EFI_STATUS
FindAllDeviceTypes(IN PCI_CLASS_RECORD * PciClasses,IN OUT DEVICE_STRUCTURE * DeviceTable,IN OUT UINT16 * DeviceIndex,IN BOOLEAN DeviceFlags)110 FindAllDeviceTypes (
111   IN       PCI_CLASS_RECORD      *PciClasses,
112   IN OUT   DEVICE_STRUCTURE      *DeviceTable,
113   IN OUT   UINT16                *DeviceIndex,
114   IN       BOOLEAN               DeviceFlags
115   )
116 {
117   UINTN                       HandleCount;
118   EFI_HANDLE                  *HandleBuffer;
119   UINTN                       Index;
120   UINTN                       StartIndex;
121   PCI_TYPE00                  PciConfigHeader;
122   EFI_PCI_IO_PROTOCOL         *PciIo;
123   EFI_LEGACY_BIOS_PROTOCOL    *LegacyBios;
124   UINTN                       Flags;
125   EFI_STATUS                  Status;
126   UINTN                       Index2;
127 
128   //
129   // Get legacy BIOS protocol as it is required to deal with Option ROMs.
130   //
131   StartIndex = *DeviceIndex;
132   Status = gBS->LocateProtocol (
133                   &gEfiLegacyBiosProtocolGuid,
134                   NULL,
135                   (VOID**)&LegacyBios
136                   );
137   ASSERT_EFI_ERROR (Status);
138 
139   //
140   // Get all PCI handles and check them to generate a list of matching devices.
141   //
142   gBS->LocateHandleBuffer (
143          ByProtocol,
144          &gEfiPciIoProtocolGuid,
145          NULL,
146          &HandleCount,
147          &HandleBuffer
148          );
149   for (Index = 0; Index < HandleCount; Index++) {
150     gBS->HandleProtocol (
151            HandleBuffer[Index],
152            &gEfiPciIoProtocolGuid,
153            (VOID**)&PciIo
154            );
155     PciIo->Pci.Read (
156                  PciIo,
157                  EfiPciIoWidthUint32,
158                  0,
159                  sizeof (PciConfigHeader) / sizeof (UINT32),
160                  &PciConfigHeader
161                  );
162     for (Index2 = 0; PciClasses[Index2].Class != 0xff; Index2++) {
163         if ((PciConfigHeader.Hdr.ClassCode[2] == PciClasses[Index2].Class) &&
164             (PciConfigHeader.Hdr.ClassCode[1] == PciClasses[Index2].SubClass)) {
165         LegacyBios->CheckPciRom (
166                       LegacyBios,
167                       HandleBuffer[Index],
168                       NULL,
169                       NULL,
170                       &Flags
171                       );
172 
173         //
174         // Verify that results of OPROM check match request.
175         // The two valid requests are:
176         //   DeviceFlags = 0 require a valid legacy ROM
177         //   DeviceFlags = 1 require either no ROM or a valid legacy ROM
178         //
179         if (
180             ((DeviceFlags != 0) && (Flags == NO_ROM)) ||
181             ((Flags & (ROM_FOUND | VALID_LEGACY_ROM)) == (ROM_FOUND | VALID_LEGACY_ROM))
182            ) {
183           DeviceTable->Handle = HandleBuffer[Index];
184           DeviceTable->Vid    = PciConfigHeader.Hdr.VendorId;
185           DeviceTable->Did    = PciConfigHeader.Hdr.DeviceId;
186           DeviceTable->SvId   = PciConfigHeader.Device.SubsystemVendorID;
187           DeviceTable->SysId  = PciConfigHeader.Device.SubsystemID;
188           ++ *DeviceIndex;
189           DeviceTable++;
190         }
191       }
192     }
193   }
194 
195   //
196   // Free any allocated buffers
197   //
198   gBS->FreePool (HandleBuffer);
199 
200   if (*DeviceIndex != StartIndex) {
201     return EFI_SUCCESS;
202   } else {
203     return EFI_NOT_FOUND;
204   }
205 }
206 
207 /**
208   Load and initialize the Legacy BIOS SMM handler.
209 
210   @param  This                   The protocol instance pointer.
211   @param  EfiToLegacy16BootTable A pointer to Legacy16 boot table.
212 
213   @retval EFI_SUCCESS           SMM code loaded.
214   @retval EFI_DEVICE_ERROR      SMM code failed to load
215 
216 **/
217 EFI_STATUS
218 EFIAPI
SmmInit(IN EFI_LEGACY_BIOS_PLATFORM_PROTOCOL * This,IN VOID * EfiToLegacy16BootTable)219 SmmInit (
220   IN  EFI_LEGACY_BIOS_PLATFORM_PROTOCOL           *This,
221   IN  VOID                                        *EfiToLegacy16BootTable
222   )
223 {
224   return EFI_SUCCESS;
225 }
226 
227 /**
228   Finds the device path that should be used as the primary display adapter.
229 
230   @param  VgaHandle - The handle of the video device
231 
232 **/
233 VOID
GetSelectedVgaDeviceInfo(OUT EFI_HANDLE * VgaHandle)234 GetSelectedVgaDeviceInfo (
235   OUT EFI_HANDLE                *VgaHandle
236   )
237 {
238   EFI_STATUS                Status;
239   UINTN                     HandleCount;
240   EFI_HANDLE                *HandleBuffer;
241   UINTN                     Index;
242   EFI_PCI_IO_PROTOCOL       *PciIo;
243   PCI_TYPE00                Pci;
244   UINT8                     MinBus;
245   UINT8                     MaxBus;
246   UINTN                     Segment;
247   UINTN                     Bus;
248   UINTN                     Device;
249   UINTN                     Function;
250   UINTN                     SelectedAddress;
251   UINTN                     CurrentAddress;
252 
253   //
254   // Initialize return to 'not found' state
255   //
256   *VgaHandle = NULL;
257 
258   //
259   // Initialize variable states.  Ths is important for selecting the VGA device
260   // if multiple devices exist behind a single bridge.
261   //
262   HandleCount = 0;
263   HandleBuffer = NULL;
264   SelectedAddress = PCI_LIB_ADDRESS(0xff, 0x1f, 0x7, 0);
265 
266   //
267   // The bus range to search for a VGA device in.
268   //
269   MinBus = MaxBus = 0;
270 
271   //
272   // Start to check all the pci io to find all possible VGA device
273   //
274   HandleCount = 0;
275   HandleBuffer = NULL;
276   Status = gBS->LocateHandleBuffer (
277                   ByProtocol,
278                   &gEfiPciIoProtocolGuid,
279                   NULL,
280                   &HandleCount,
281                   &HandleBuffer
282                   );
283   if (EFI_ERROR (Status)) {
284     return;
285   }
286 
287   for (Index = 0; Index < HandleCount; Index++) {
288     Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID**)&PciIo);
289     if (!EFI_ERROR (Status)) {
290       //
291       // Detemine if this is in the correct bus range.
292       //
293       Status = PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function);
294       if (EFI_ERROR(Status) || (Bus < MinBus || Bus > MaxBus)) {
295         continue;
296       }
297 
298       //
299       // Read device information.
300       //
301       Status = PciIo->Pci.Read (
302                         PciIo,
303                         EfiPciIoWidthUint32,
304                         0,
305                         sizeof (Pci) / sizeof (UINT32),
306                         &Pci
307                         );
308       if (EFI_ERROR (Status)) {
309         continue;
310       }
311 
312       //
313       // Make sure the device is a VGA device.
314       //
315       if (!IS_PCI_VGA (&Pci)) {
316         continue;
317       }
318       DEBUG ((EFI_D_INFO,
319         "PCI VGA: 0x%04x:0x%04x\n",
320         Pci.Hdr.VendorId,
321         Pci.Hdr.DeviceId
322         ));
323 
324       //
325       // Currently we use the lowest numbered bus/device/function if multiple
326       // devices are found in the target bus range.
327       //
328       CurrentAddress = PCI_LIB_ADDRESS(Bus, Device, Function, 0);
329       if (CurrentAddress < SelectedAddress) {
330         SelectedAddress = CurrentAddress;
331         *VgaHandle = HandleBuffer[Index];
332       }
333     }
334   }
335 
336   FreePool (HandleBuffer);
337 }
338 
339 
340 /**
341   Returns a buffer of handles for the requested subfunction.
342 
343   @param  This                  The protocol instance pointer.
344   @param  Mode                  Specifies what handle to return. See EFI_GET_PLATFORM_HANDLE_MODE enum.
345   @param  Type                  Mode specific. See EFI_GET_PLATFORM_HANDLE_MODE enum.
346   @param  HandleBuffer          Mode specific. See EFI_GET_PLATFORM_HANDLE_MODE enum.
347   @param  HandleCount           Mode specific. See EFI_GET_PLATFORM_HANDLE_MODE enum.
348   @param  AdditionalData        Mode specific. See EFI_GET_PLATFORM_HANDLE_MODE enum.
349 
350   @retval EFI_SUCCESS           Handle is valid.
351   @retval EFI_UNSUPPORTED       Mode is not supported on the platform.
352   @retval EFI_NOT_FOUND         Handle is not known.
353 
354 **/
355 EFI_STATUS
356 EFIAPI
GetPlatformHandle(IN EFI_LEGACY_BIOS_PLATFORM_PROTOCOL * This,IN EFI_GET_PLATFORM_HANDLE_MODE Mode,IN UINT16 Type,OUT EFI_HANDLE ** HandleBuffer,OUT UINTN * HandleCount,OUT VOID ** AdditionalData OPTIONAL)357 GetPlatformHandle (
358   IN  EFI_LEGACY_BIOS_PLATFORM_PROTOCOL           *This,
359   IN  EFI_GET_PLATFORM_HANDLE_MODE                Mode,
360   IN  UINT16                                      Type,
361   OUT EFI_HANDLE                                  **HandleBuffer,
362   OUT UINTN                                       *HandleCount,
363   OUT VOID                                        **AdditionalData OPTIONAL
364   )
365 {
366   DEVICE_STRUCTURE    LocalDevice[0x40];
367   UINT32              LocalIndex;
368   UINT32              Index;
369   DEVICE_STRUCTURE    TempDevice;
370   EFI_STATUS          Status;
371   EFI_PCI_IO_PROTOCOL *PciIo;
372   UINTN               Segment;
373   UINTN               Bus;
374   UINTN               Device;
375   UINTN               Function;
376   HDD_INFO            *HddInfo;
377   PCI_TYPE00          PciConfigHeader;
378   UINT32              HddIndex;
379   EFI_HANDLE          IdeHandle;
380   EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;
381   PCI_CLASS_RECORD    ClassLists[10];
382   UINTN               PriorityIndex;
383 
384   static BOOLEAN      bConnected = FALSE;
385 
386   LocalIndex  = 0x00;
387   HddInfo     = NULL;
388   HddIndex    = 0;
389 
390   Status = gBS->LocateProtocol (
391                   &gEfiLegacyBiosProtocolGuid,
392                   NULL,
393                   (VOID**)&LegacyBios
394                   );
395 
396   //
397   // Process mode specific operations
398   //
399   switch (Mode) {
400     case EfiGetPlatformVgaHandle:
401       //
402       // Get the handle for the currently selected VGA device.
403       //
404       GetSelectedVgaDeviceInfo (&mVgaHandles[0]);
405       *HandleBuffer = &mVgaHandles[0];
406       *HandleCount  = (mVgaHandles[0] != NULL) ? 1 : 0;
407       return EFI_SUCCESS;
408     case EfiGetPlatformIdeHandle:
409       IdeHandle  = NULL;
410       if (AdditionalData != NULL) {
411         HddInfo = (HDD_INFO *) *AdditionalData;
412       }
413 
414       //
415       // Locate all found block io devices
416       //
417       ClassLists[0].Class    = PCI_CLASS_MASS_STORAGE;
418       ClassLists[0].SubClass = PCI_CLASS_MASS_STORAGE_SCSI;
419       ClassLists[1].Class    = PCI_CLASS_MASS_STORAGE;
420       ClassLists[1].SubClass = PCI_CLASS_MASS_STORAGE_IDE;
421       ClassLists[2].Class    = PCI_CLASS_MASS_STORAGE;
422       ClassLists[2].SubClass = PCI_CLASS_MASS_STORAGE_RAID;
423       ClassLists[3].Class    = PCI_CLASS_MASS_STORAGE;
424       ClassLists[3].SubClass = PCI_CLASS_MASS_STORAGE_SATADPA;
425       ClassLists[4].Class    = 0xff;
426       FindAllDeviceTypes (ClassLists, LocalDevice, (UINT16 *) &LocalIndex, TRUE);
427       if (LocalIndex == 0) {
428         return EFI_NOT_FOUND;
429       }
430 
431       //
432       // Make sure all IDE controllers are connected. This is necessary
433       // in NO_CONFIG_CHANGE boot path to ensure IDE controller is correctly
434       // initialized and all IDE drives are enumerated
435       //
436       if (!bConnected) {
437         for (Index = 0; Index < LocalIndex; Index++) {
438           gBS->ConnectController (LocalDevice[Index].Handle, NULL, NULL, TRUE);
439         }
440       }
441 
442       //
443       // Locate onboard controllers.
444       //
445       for (Index = 0; Index < LocalIndex; Index++) {
446         if (LocalDevice[Index].Vid == V_INTEL_VENDOR_ID) {
447           if (LocalDevice[Index].Did == V_PIIX4_IDE_DEVICE_ID) {
448             IdeHandle = LocalDevice[Index].Handle;
449           }
450         }
451       }
452 
453       //
454       // Set the IDE contorller as primary devices.
455       //
456       PriorityIndex = 0;
457       for (Index = 0; Index < LocalIndex; Index++) {
458         if (LocalDevice[Index].Handle == IdeHandle && PriorityIndex == 0) {
459           TempDevice = LocalDevice[PriorityIndex];
460           LocalDevice[PriorityIndex] = LocalDevice[Index];
461           LocalDevice[Index] = TempDevice;
462           PriorityIndex++;
463           break;
464         }
465       }
466 
467       //
468       // Copy over handles and update return values.
469       //
470       for (Index = 0; Index < LocalIndex; Index++) {
471         mDiskHandles[Index] = LocalDevice[Index].Handle;
472       }
473       *HandleBuffer = &mDiskHandles[0];
474       *HandleCount  = LocalIndex;
475 
476       //
477       // We have connected all IDE controllers once. No more needed
478       //
479       bConnected = TRUE;
480 
481       //
482       // Log all onboard controllers.
483       //
484       for (Index = 0; (Index < LocalIndex) && (AdditionalData != NULL); Index++) {
485         if ((LocalDevice[Index].Handle != NULL) &&
486             (LocalDevice[Index].Handle == IdeHandle)) {
487           Status = gBS->HandleProtocol (
488                           LocalDevice[Index].Handle,
489                           &gEfiPciIoProtocolGuid,
490                           (VOID **) &PciIo
491                           );
492           PciIo->Pci.Read (
493                        PciIo,
494                        EfiPciIoWidthUint32,
495                        0,
496                        sizeof (PciConfigHeader) / sizeof (UINT32),
497                        &PciConfigHeader
498                        );
499           if (!EFI_ERROR (Status)) {
500             PciIo->GetLocation (
501                      PciIo,
502                      &Segment,
503                      &Bus,
504                      &Device,
505                      &Function
506                      );
507 
508             //
509             // Be sure to only fill out correct information based on platform
510             // configureation.
511             //
512             HddInfo[HddIndex].Status        |= HDD_PRIMARY;
513             HddInfo[HddIndex].Bus           = (UINT32)Bus;
514             HddInfo[HddIndex].Device        = (UINT32)Device;
515             HddInfo[HddIndex].Function      = (UINT32)Function;
516             HddInfo[HddIndex + 1].Status    |= HDD_SECONDARY;
517             HddInfo[HddIndex + 1].Bus       = (UINT32)Bus;
518             HddInfo[HddIndex + 1].Device    = (UINT32)Device;
519             HddInfo[HddIndex + 1].Function  = (UINT32)Function;
520 
521             //
522             // Primary controller data
523             //
524             if ((PciConfigHeader.Hdr.ClassCode[0] & 0x01) != 0) {
525               HddInfo[HddIndex].CommandBaseAddress =
526                 (UINT16)(PciConfigHeader.Device.Bar[0] & 0xfffc);
527               HddInfo[HddIndex].ControlBaseAddress =
528                 (UINT16)((PciConfigHeader.Device.Bar[1] & 0xfffc)+2);
529               HddInfo[HddIndex].BusMasterAddress =
530                 (UINT16)(PciConfigHeader.Device.Bar[4] & 0xfffc);
531               HddInfo[HddIndex].HddIrq = PciConfigHeader.Device.InterruptLine;
532             } else {
533               HddInfo[HddIndex].HddIrq = 14;
534               HddInfo[HddIndex].CommandBaseAddress = 0x1f0;
535               HddInfo[HddIndex].ControlBaseAddress = 0x3f6;
536               HddInfo[HddIndex].BusMasterAddress = 0;
537             }
538             HddIndex++;
539 
540             //
541             // Secondary controller data
542             //
543             if ((PciConfigHeader.Hdr.ClassCode[0] & 0x04) != 0) {
544               HddInfo[HddIndex].CommandBaseAddress =
545                 (UINT16)(PciConfigHeader.Device.Bar[2] & 0xfffc);
546               HddInfo[HddIndex].ControlBaseAddress =
547                 (UINT16)((PciConfigHeader.Device.Bar[3] & 0xfffc)+2);
548               HddInfo[HddIndex].BusMasterAddress =
549                 (UINT16)(HddInfo[HddIndex].BusMasterAddress + 8);
550               HddInfo[HddIndex].HddIrq = PciConfigHeader.Device.InterruptLine;
551             } else {
552               HddInfo[HddIndex].HddIrq = 15;
553               HddInfo[HddIndex].CommandBaseAddress = 0x170;
554               HddInfo[HddIndex].ControlBaseAddress = 0x376;
555               HddInfo[HddIndex].BusMasterAddress = 0;
556             }
557             HddIndex++;
558           }
559         }
560       }
561       return EFI_SUCCESS;
562     case EfiGetPlatformIsaBusHandle:
563       ClassLists[0].Class    = (UINT8) PCI_CLASS_BRIDGE;
564       ClassLists[0].SubClass = (UINT8) PCI_CLASS_BRIDGE_ISA_PDECODE;
565       ClassLists[1].Class    = (UINT8) PCI_CLASS_BRIDGE;
566       ClassLists[1].SubClass = (UINT8) PCI_CLASS_BRIDGE_ISA;
567       ClassLists[2].Class    = 0xff;
568 
569       //
570       // Locate all found block io devices
571       //
572       FindAllDeviceTypes (ClassLists, LocalDevice, (UINT16 *) (&LocalIndex), TRUE);
573       if (LocalIndex == 0) {
574         return EFI_NOT_FOUND;
575       }
576 
577       //
578       // Find our ISA bridge.
579       //
580       for (Index = 0; Index < LocalIndex; Index++) {
581         if (LocalDevice[Index].Vid == V_INTEL_VENDOR_ID) {
582           TempDevice          = LocalDevice[0];
583           LocalDevice[0]      = LocalDevice[Index];
584           LocalDevice[Index]  = TempDevice;
585         }
586       }
587 
588       //
589       // Perform copy and update return values.
590       //
591       for (Index = 0; Index < LocalIndex; Index++) {
592         mIsaHandles[Index] = LocalDevice[Index].Handle;
593       }
594       *HandleBuffer = &mIsaHandles[0];
595       *HandleCount  = LocalIndex;
596       return EFI_SUCCESS;
597     case EfiGetPlatformUsbHandle:
598     default:
599       return EFI_UNSUPPORTED;
600   };
601 }
602 
603 /**
604   Allows platform to perform any required action after a LegacyBios operation.
605   Invokes the specific sub function specified by Mode.
606 
607   @param  This                  The protocol instance pointer.
608   @param  Mode                  Specifies what handle to return. See EFI_GET_PLATFORM_HOOK_MODE enum.
609   @param  Type                  Mode specific.  See EFI_GET_PLATFORM_HOOK_MODE enum.
610   @param  DeviceHandle          Mode specific.  See EFI_GET_PLATFORM_HOOK_MODE enum.
611   @param  ShadowAddress         Mode specific.  See EFI_GET_PLATFORM_HOOK_MODE enum.
612   @param  Compatibility16Table  Mode specific.  See EFI_GET_PLATFORM_HOOK_MODE enum.
613   @param  AdditionalData        Mode specific.  See EFI_GET_PLATFORM_HOOK_MODE enum.
614 
615   @retval EFI_SUCCESS           The operation performed successfully. Mode specific.
616   @retval EFI_UNSUPPORTED       Mode is not supported on the platform.
617 
618 **/
619 EFI_STATUS
620 EFIAPI
PlatformHooks(IN EFI_LEGACY_BIOS_PLATFORM_PROTOCOL * This,IN EFI_GET_PLATFORM_HOOK_MODE Mode,IN UINT16 Type,OUT EFI_HANDLE DeviceHandle,OPTIONAL IN OUT UINTN * Shadowaddress,OPTIONAL IN EFI_COMPATIBILITY16_TABLE * Compatibility16Table,OPTIONAL OUT VOID ** AdditionalData OPTIONAL)621 PlatformHooks (
622   IN       EFI_LEGACY_BIOS_PLATFORM_PROTOCOL     *This,
623   IN       EFI_GET_PLATFORM_HOOK_MODE            Mode,
624   IN       UINT16                                Type,
625      OUT   EFI_HANDLE                            DeviceHandle, OPTIONAL
626   IN OUT   UINTN                                 *Shadowaddress, OPTIONAL
627   IN       EFI_COMPATIBILITY16_TABLE             *Compatibility16Table, OPTIONAL
628      OUT   VOID                                  **AdditionalData OPTIONAL
629   )
630 {
631   EFI_IA32_REGISTER_SET     Regs;
632   EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;
633   EFI_STATUS                Status;
634 
635   switch (Mode) {
636     case EfiPlatformHookPrepareToScanRom:
637       Status = gBS->LocateProtocol (
638                       &gEfiLegacyBiosProtocolGuid,
639                       NULL,
640                       (VOID**)&LegacyBios
641                       );
642 
643       //
644       // Set the 80x25 Text VGA Mode
645       //
646       Regs.H.AH = 0x00;
647       Regs.H.AL = 0x03;
648       Status = LegacyBios->Int86 (LegacyBios, 0x10, &Regs);
649       return Status;
650     case EfiPlatformHookShadowServiceRoms:
651       return EFI_SUCCESS;
652     case EfiPlatformHookAfterRomInit:
653     default:
654       return EFI_UNSUPPORTED;
655   };
656 }
657 
658 /**
659   Returns information associated with PCI IRQ routing.
660   This function returns the following information associated with PCI IRQ routing:
661     * An IRQ routing table and number of entries in the table.
662     * The $PIR table and its size.
663     * A list of PCI IRQs and the priority order to assign them.
664 
665   @param  This                    The protocol instance pointer.
666   @param  RoutingTable            The pointer to PCI IRQ Routing table.
667                                   This location is the $PIR table minus the header.
668   @param  RoutingTableEntries     The number of entries in table.
669   @param  LocalPirqTable          $PIR table.
670   @param  PirqTableSize           $PIR table size.
671   @param  LocalIrqPriorityTable   A list of interrupts in priority order to assign.
672   @param  IrqPriorityTableEntries The number of entries in the priority table.
673 
674   @retval EFI_SUCCESS           Data was successfully returned.
675 
676 **/
677 EFI_STATUS
678 EFIAPI
GetRoutingTable(IN EFI_LEGACY_BIOS_PLATFORM_PROTOCOL * This,OUT VOID ** RoutingTable,OUT UINTN * RoutingTableEntries,OUT VOID ** LocalPirqTable,OPTIONAL OUT UINTN * PirqTableSize,OPTIONAL OUT VOID ** LocalIrqPriorityTable,OPTIONAL OUT UINTN * IrqPriorityTableEntries OPTIONAL)679 GetRoutingTable (
680   IN  EFI_LEGACY_BIOS_PLATFORM_PROTOCOL           *This,
681   OUT VOID                                        **RoutingTable,
682   OUT UINTN                                       *RoutingTableEntries,
683   OUT VOID                                        **LocalPirqTable, OPTIONAL
684   OUT UINTN                                       *PirqTableSize, OPTIONAL
685   OUT VOID                                        **LocalIrqPriorityTable, OPTIONAL
686   OUT UINTN                                       *IrqPriorityTableEntries OPTIONAL
687   )
688 {
689   UINT16                        PTableSize;
690   UINT32                        Index;
691   UINT8                         Bus;
692   UINT8                         Device;
693   UINT8                         Function;
694   UINT8                         Checksum;
695   UINT8                         *Ptr;
696   EFI_STATUS                    Status;
697   EFI_LEGACY_INTERRUPT_PROTOCOL *LegacyInterrupt;
698 
699   Checksum = 0;
700 
701   if (LocalPirqTable != NULL) {
702     PTableSize = sizeof (EFI_LEGACY_PIRQ_TABLE_HEADER) +
703                  sizeof (EFI_LEGACY_IRQ_ROUTING_ENTRY) * MAX_IRQ_ROUTING_ENTRIES;
704 
705     Status = gBS->LocateProtocol (
706                     &gEfiLegacyInterruptProtocolGuid,
707                     NULL,
708                     (VOID**)&LegacyInterrupt
709                     );
710     ASSERT_EFI_ERROR (Status);
711     LegacyInterrupt->GetLocation (
712                        LegacyInterrupt,
713                        &Bus,
714                        &Device,
715                        &Function
716                        );
717 
718     //
719     // Update fields in $PIR table header
720     //
721     PirqTableHead.PirqTable.TableSize = PTableSize;
722     PirqTableHead.PirqTable.Bus       = Bus;
723     PirqTableHead.PirqTable.DevFun    = (UINT8) ((Device << 3) + Function);
724     Ptr = (UINT8 *) (&PirqTableHead);
725 
726     //
727     // Calculate checksum.
728     //
729     for (Index = 0; Index < PTableSize; Index++) {
730       Checksum = (UINT8) (Checksum + (UINT8) *Ptr);
731       Ptr += 1;
732     }
733     Checksum                          = (UINT8) (0x00 - Checksum);
734     PirqTableHead.PirqTable.Checksum  = Checksum;
735 
736     //
737     // Update return values.
738     //
739     *LocalPirqTable                   = (VOID *) (&PirqTableHead);
740     *PirqTableSize                    = PTableSize;
741   }
742 
743   //
744   // More items to return.
745   //
746   *RoutingTable         = PirqTableHead.IrqRoutingEntry;
747   *RoutingTableEntries  = MAX_IRQ_ROUTING_ENTRIES;
748   if (LocalIrqPriorityTable != NULL) {
749     *LocalIrqPriorityTable    = IrqPriorityTable;
750     *IrqPriorityTableEntries  = MAX_IRQ_PRIORITY_ENTRIES;
751   }
752 
753   return EFI_SUCCESS;
754 }
755 
756 /**
757   Finds the binary data or other platform information.
758 
759   @param  This                  The protocol instance pointer.
760   @param  Mode                  Specifies what data to return. See See EFI_GET_PLATFORM_INFO_MODE enum.
761   @param  Table                 Mode specific.  See EFI_GET_PLATFORM_INFO_MODE enum.
762   @param  TableSize             Mode specific.  See EFI_GET_PLATFORM_INFO_MODE enum.
763   @param  Location              Mode specific.  See EFI_GET_PLATFORM_INFO_MODE enum.
764   @param  Alignment             Mode specific.  See EFI_GET_PLATFORM_INFO_MODE enum.
765   @param  LegacySegment         Mode specific.  See EFI_GET_PLATFORM_INFO_MODE enum.
766   @param  LegacyOffset          Mode specific.  See EFI_GET_PLATFORM_INFO_MODE enum.
767 
768   @retval EFI_SUCCESS           Data returned successfully.
769   @retval EFI_UNSUPPORTED       Mode is not supported on the platform.
770   @retval EFI_NOT_FOUND         Binary image or table not found.
771 
772 **/
773 EFI_STATUS
774 EFIAPI
GetPlatformInfo(IN EFI_LEGACY_BIOS_PLATFORM_PROTOCOL * This,IN EFI_GET_PLATFORM_INFO_MODE Mode,OUT VOID ** Table,OUT UINTN * TableSize,OUT UINTN * Location,OUT UINTN * Alignment,IN UINT16 LegacySegment,IN UINT16 LegacyOffset)775 GetPlatformInfo (
776   IN  EFI_LEGACY_BIOS_PLATFORM_PROTOCOL           *This,
777   IN  EFI_GET_PLATFORM_INFO_MODE                  Mode,
778   OUT VOID                                        **Table,
779   OUT UINTN                                       *TableSize,
780   OUT UINTN                                       *Location,
781   OUT UINTN                                       *Alignment,
782   IN  UINT16                                      LegacySegment,
783   IN  UINT16                                      LegacyOffset
784   )
785 {
786   EFI_STATUS                    Status;
787   UINTN                         Index;
788 
789   switch (Mode) {
790     case EfiGetPlatformBinarySystemRom:
791       //
792       // Loop through table of System rom descriptions
793       //
794       for (Index = 0; mSystemRomTable[Index].Valid != 0; Index++) {
795         Status = GetSectionFromFv (
796                    &mSystemRomTable[Index].FileName,
797                    EFI_SECTION_RAW,
798                    0,
799                    Table,
800                    (UINTN *) TableSize
801                    );
802         if (EFI_ERROR (Status)) {
803           continue;
804         }
805         return EFI_SUCCESS;
806       }
807 
808       return EFI_NOT_FOUND;
809     case EfiGetPlatformBinaryOem16Data:
810     case EfiGetPlatformBinaryMpTable:
811     case EfiGetPlatformBinaryOemIntData:
812     case EfiGetPlatformBinaryOem32Data:
813     case EfiGetPlatformBinaryTpmBinary:
814     case EfiGetPlatformPciExpressBase:
815     default:
816       return EFI_UNSUPPORTED;
817   };
818 }
819 
820 /**
821   Translates the given PIRQ accounting for bridge.
822   This function translates the given PIRQ back through all buses, if required,
823   and returns the true PIRQ and associated IRQ.
824 
825   @param  This                  The protocol instance pointer.
826   @param  PciBus                The PCI bus number for this device.
827   @param  PciDevice             The PCI device number for this device.
828   @param  PciFunction           The PCI function number for this device.
829   @param  Pirq                  Input is PIRQ reported by device, and output is true PIRQ.
830   @param  PciIrq                The IRQ already assigned to the PIRQ, or the IRQ to be
831                                 assigned to the PIRQ.
832 
833   @retval EFI_SUCCESS           The PIRQ was translated.
834 
835 **/
836 EFI_STATUS
837 EFIAPI
TranslatePirq(IN EFI_LEGACY_BIOS_PLATFORM_PROTOCOL * This,IN UINTN PciBus,IN UINTN PciDevice,IN UINTN PciFunction,IN OUT UINT8 * Pirq,OUT UINT8 * PciIrq)838 TranslatePirq (
839   IN        EFI_LEGACY_BIOS_PLATFORM_PROTOCOL           *This,
840   IN        UINTN                                       PciBus,
841   IN        UINTN                                       PciDevice,
842   IN        UINTN                                       PciFunction,
843   IN  OUT   UINT8                                       *Pirq,
844       OUT   UINT8                                       *PciIrq
845   )
846 {
847   EFI_LEGACY_INTERRUPT_PROTOCOL      *LegacyInterrupt;
848   EFI_STATUS                         Status;
849   UINTN                              Index;
850   UINTN                              Index1;
851   UINT8                              LocalPirq;
852   UINT8                              PirqData;
853   UINT8                              MatchData;
854 
855   Status = gBS->LocateProtocol (
856                   &gEfiLegacyInterruptProtocolGuid,
857                   NULL,
858                   (VOID**)&LegacyInterrupt
859                   );
860   ASSERT_EFI_ERROR (Status);
861   LocalPirq = (UINT8) (*Pirq);
862 
863   for (Index = 0; Index < MAX_IRQ_ROUTING_ENTRIES; Index++) {
864     if ((PirqTableHead.IrqRoutingEntry[Index].Bus == PciBus) &&
865         (PirqTableHead.IrqRoutingEntry[Index].Device == PciDevice)) {
866       LocalPirq = (UINT8) (PirqTableHead.IrqRoutingEntry[Index].PirqEntry[LocalPirq].Pirq & 0x0f);
867       if (LocalPirq > 4) {
868         LocalPirq -= 4;
869       }
870 
871       LegacyInterrupt->ReadPirq (LegacyInterrupt, LocalPirq, &PirqData);
872       MatchData = PCI_UNUSED;
873       while (PirqData == 0) {
874         for (Index1 = 0; Index1 < MAX_IRQ_PRIORITY_ENTRIES; Index1++) {
875           if ((IrqPriorityTable[Index1].Used == MatchData) &&
876               (IrqPriorityTable[Index1].Irq != 0)) {
877             PirqData = IrqPriorityTable[Index1].Irq;
878             IrqPriorityTable[Index1].Used = 0xff;
879             LegacyInterrupt->WritePirq (
880                                LegacyInterrupt,
881                                LocalPirq,
882                                PirqData
883                                );
884             break;
885           }
886         }
887 
888         if (PirqData == 0) {
889 
890           //
891           // No unused interrpts, so start reusing them.
892           //
893           MatchData = (UINT8) (~MatchData);
894         }
895       }
896 
897       *PciIrq = PirqData;
898       *Pirq   = LocalPirq;
899     }
900   }
901 
902   return EFI_SUCCESS;
903 }
904 
905 
906 /**
907   Attempt to legacy boot the BootOption. If the EFI contexted has been
908   compromised this function will not return.
909 
910   @param  This                   The protocol instance pointer.
911   @param  BbsDevicePath          The EFI Device Path from BootXXXX variable.
912   @param  BbsTable               The Internal BBS table.
913   @param  LoadOptionSize         The size of LoadOption in size.
914   @param  LoadOption             The LoadOption from BootXXXX variable
915   @param  EfiToLegacy16BootTable A pointer to BootTable structure
916 
917   @retval EFI_SUCCESS           Ready to boot.
918 
919 **/
920 EFI_STATUS
921 EFIAPI
PrepareToBoot(IN EFI_LEGACY_BIOS_PLATFORM_PROTOCOL * This,IN BBS_BBS_DEVICE_PATH * BbsDevicePath,IN VOID * BbsTable,IN UINT32 LoadOptionsSize,IN VOID * LoadOptions,IN VOID * EfiToLegacy16BootTable)922 PrepareToBoot (
923   IN  EFI_LEGACY_BIOS_PLATFORM_PROTOCOL           *This,
924   IN  BBS_BBS_DEVICE_PATH                         *BbsDevicePath,
925   IN  VOID                                        *BbsTable,
926   IN  UINT32                                      LoadOptionsSize,
927   IN  VOID                                        *LoadOptions,
928   IN  VOID                                        *EfiToLegacy16BootTable
929   )
930 {
931   BBS_TABLE                           *LocalBbsTable;
932   EFI_TO_COMPATIBILITY16_BOOT_TABLE   *Legacy16BootTable;
933   DEVICE_PRODUCER_DATA_HEADER         *SioPtr;
934   UINT16                              DevicePathType;
935   UINT16                              Index;
936   UINT16                              Priority;
937 
938   //
939   // Initialize values
940   //
941   Priority = 0;
942   Legacy16BootTable = (EFI_TO_COMPATIBILITY16_BOOT_TABLE*) EfiToLegacy16BootTable;
943 
944   //
945   // Set how Gate A20 is gated by hardware
946   //
947   SioPtr                  = &Legacy16BootTable->SioData;
948   SioPtr->Flags.A20Kybd   = 1;
949   SioPtr->Flags.A20Port90 = 1;
950   SioPtr->MousePresent    = 1;
951 
952   LocalBbsTable           = BbsTable;
953 
954   //
955   // There are 2 cases that must be covered.
956   // Case 1: Booting to a legacy OS - BbsDevicePath is non-NULL.
957   // Case 2: Booting to an EFI aware OS - BbsDevicePath is NULL.
958   //         We need to perform the PrepareToBoot function to assign
959   //         drive numbers to HDD devices to allow the shell or EFI
960   //         to access them.
961   //
962   if (BbsDevicePath != NULL) {
963     DevicePathType = BbsDevicePath->DeviceType;
964   } else {
965     DevicePathType = BBS_HARDDISK;
966   }
967 
968   //
969   // Skip the boot devices where priority is set by BDS and set the next one
970   //
971   for (Index = 0; Index < Legacy16BootTable->NumberBbsEntries; Index++) {
972     if ((LocalBbsTable[Index].BootPriority != BBS_UNPRIORITIZED_ENTRY) &&
973         (LocalBbsTable[Index].BootPriority != BBS_IGNORE_ENTRY) &&
974         (LocalBbsTable[Index].BootPriority != BBS_LOWEST_PRIORITY) &&
975         (Priority <= LocalBbsTable[Index].BootPriority)) {
976       Priority = (UINT16) (LocalBbsTable[Index].BootPriority + 1);
977     }
978   }
979 
980   switch (DevicePathType) {
981     case BBS_FLOPPY:
982     case BBS_HARDDISK:
983     case BBS_CDROM:
984     case BBS_EMBED_NETWORK:
985       for (Index = 0; Index < Legacy16BootTable->NumberBbsEntries; Index++) {
986         if ((LocalBbsTable[Index].BootPriority == BBS_UNPRIORITIZED_ENTRY) &&
987             (LocalBbsTable[Index].DeviceType == DevicePathType)) {
988           LocalBbsTable[Index].BootPriority = Priority;
989           ++Priority;
990         }
991       }
992       break;
993     case BBS_BEV_DEVICE:
994       for (Index = 0; Index < Legacy16BootTable->NumberBbsEntries; Index++) {
995         if ((LocalBbsTable[Index].BootPriority == BBS_UNPRIORITIZED_ENTRY) &&
996             (LocalBbsTable[Index].Class == 01) &&
997             (LocalBbsTable[Index].SubClass == 01)) {
998           LocalBbsTable[Index].BootPriority = Priority;
999           ++Priority;
1000         }
1001       }
1002       break;
1003     case BBS_USB:
1004     case BBS_PCMCIA:
1005     case BBS_UNKNOWN:
1006     default:
1007       break;
1008   };
1009 
1010   //
1011   // Set priority for rest of devices
1012   //
1013   for (Index = 0; Index < Legacy16BootTable->NumberBbsEntries; Index++) {
1014     if (LocalBbsTable[Index].BootPriority == BBS_UNPRIORITIZED_ENTRY) {
1015       LocalBbsTable[Index].BootPriority = Priority;
1016       ++Priority;
1017     }
1018   }
1019 
1020   return EFI_SUCCESS;
1021 }
1022 
1023 
1024 /**
1025   Initialize Legacy Platform support
1026 
1027   @retval EFI_SUCCESS   Successfully initialized
1028 
1029 **/
1030 EFI_STATUS
LegacyBiosPlatformInstall(VOID)1031 LegacyBiosPlatformInstall (
1032   VOID
1033   )
1034 {
1035   EFI_STATUS                           Status;
1036   LEGACY_BIOS_PLATFORM_INSTANCE        *Private;
1037 
1038   mImageHandle = gImageHandle;
1039   Private = &mPrivateData;
1040 
1041   //
1042   // Grab a copy of all the protocols we depend on.
1043   //
1044   Private->Signature = LEGACY_BIOS_PLATFORM_INSTANCE_SIGNATURE;
1045   Private->LegacyBiosPlatform.GetPlatformInfo   = GetPlatformInfo;
1046   Private->LegacyBiosPlatform.GetPlatformHandle = GetPlatformHandle;
1047   Private->LegacyBiosPlatform.SmmInit           = SmmInit;
1048   Private->LegacyBiosPlatform.PlatformHooks     = PlatformHooks;
1049   Private->LegacyBiosPlatform.GetRoutingTable   = GetRoutingTable;
1050   Private->LegacyBiosPlatform.TranslatePirq     = TranslatePirq;
1051   Private->LegacyBiosPlatform.PrepareToBoot     = PrepareToBoot;
1052   Private->ImageHandle = gImageHandle;
1053 
1054   //
1055   // Make a new handle and install the protocol
1056   //
1057   Private->Handle = NULL;
1058   Status = gBS->InstallProtocolInterface (
1059                   &Private->Handle,
1060                   &gEfiLegacyBiosPlatformProtocolGuid,
1061                   EFI_NATIVE_INTERFACE,
1062                   &Private->LegacyBiosPlatform
1063                   );
1064   return Status;
1065 }
1066 
1067