| /** @file | |
| Legacy BIOS Platform support | |
| Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials are | |
| licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include "LegacyPlatform.h" | |
| EFI_SETUP_BBS_MAP mSetupBbsMap[] = { | |
| { 1, 2, 1, 1 }, // ATA HardDrive | |
| { 2, 3, 1, 1 }, // ATAPI CDROM | |
| { 3, 0x80, 2, 0 }, // PXE | |
| { 4, 1, 0, 6 }, // USB Floppy | |
| { 4, 2, 0, 6 }, // USB HDD | |
| { 4, 3, 0, 6 }, // USB CD | |
| { 4, 1, 0, 0 }, // USB ZIP Bugbug since Class/SubClass code is uninitialized | |
| { 4, 2, 0, 0 } // USB ZIP Bugbug since Class/SubClass code is uninitialized | |
| }; | |
| // | |
| // Global variables for System ROMs | |
| // | |
| #define SYSTEM_ROM_FILE_GUID \ | |
| { 0x1547B4F3, 0x3E8A, 0x4FEF, { 0x81, 0xC8, 0x32, 0x8E, 0xD6, 0x47, 0xAB, 0x1A } } | |
| #define NULL_ROM_FILE_GUID \ | |
| { 0x00000000, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } | |
| SYSTEM_ROM_TABLE mSystemRomTable[] = { | |
| { SYSTEM_ROM_FILE_GUID, 1 }, | |
| { NULL_ROM_FILE_GUID, 0 } | |
| }; | |
| EFI_HANDLE mVgaHandles[0x20]; | |
| EFI_HANDLE mDiskHandles[0x20]; | |
| EFI_HANDLE mIsaHandles[0x20]; | |
| EFI_LEGACY_IRQ_PRIORITY_TABLE_ENTRY IrqPriorityTable[MAX_IRQ_PRIORITY_ENTRIES] = { | |
| {0x0B,0}, | |
| {0x09,0}, | |
| {0x0A,0}, | |
| {0x05,0}, | |
| {0x07,0}, | |
| {0x00,0}, | |
| {0x00,0} | |
| }; | |
| // | |
| // PIRQ Table | |
| // - Slot numbering will be used to update the bus number and determine bridge | |
| // to check to get bus number. The Slot number - 1 is an index into a decode | |
| // table to get the bridge information. | |
| // | |
| EFI_LEGACY_PIRQ_TABLE PirqTableHead = { | |
| { | |
| EFI_LEGACY_PIRQ_TABLE_SIGNATURE, // UINT32 Signature | |
| 0x00, // UINT8 MinorVersion | |
| 0x01, // UINT8 MajorVersion | |
| 0x0000, // UINT16 TableSize | |
| 0x00, // UINT8 Bus | |
| 0x08, // UINT8 DevFun | |
| 0x0000, // UINT16 PciOnlyIrq | |
| 0x8086, // UINT16 CompatibleVid | |
| 0x122e, // UINT16 CompatibleDid | |
| 0x00000000, // UINT32 Miniport | |
| { // UINT8 Reserved[11] | |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 0x00, 0x00, 0x00 | |
| }, | |
| 0x00, // UINT8 Checksum | |
| }, | |
| { | |
| // -- Pin 1 -- -- Pin 2 -- -- Pin 3 -- -- Pin 4 -- | |
| // Bus Dev Reg Map Reg Map Reg Map Reg Map | |
| // | |
| {0x00,0x08,{{0x60,0xDEB8},{0x61,0xDEB8},{0x62,0xDEB8},{0x63,0xDEB8}},0x00,0x00}, | |
| {0x00,0x10,{{0x61,0xDEB8},{0x62,0xDEB8},{0x63,0xDEB8},{0x60,0xDEB8}},0x01,0x00}, | |
| {0x00,0x18,{{0x62,0xDEB8},{0x63,0xDEB8},{0x60,0xDEB8},{0x61,0xDEB8}},0x02,0x00}, | |
| {0x00,0x20,{{0x63,0xDEB8},{0x60,0xDEB8},{0x61,0xDEB8},{0x62,0xDEB8}},0x03,0x00}, | |
| {0x00,0x28,{{0x60,0xDEB8},{0x61,0xDEB8},{0x62,0xDEB8},{0x63,0xDEB8}},0x04,0x00}, | |
| {0x00,0x30,{{0x61,0xDEB8},{0x62,0xDEB8},{0x63,0xDEB8},{0x60,0xDEB8}},0x05,0x00}, | |
| } | |
| }; | |
| LEGACY_BIOS_PLATFORM_INSTANCE mPrivateData; | |
| EFI_HANDLE mImageHandle = NULL; | |
| /** | |
| Return the handles and assorted information for the specified PCI Class code | |
| @param[in] PciClasses Array of PCI_CLASS_RECORD to find terminated with ClassCode 0xff | |
| @param[in,out] DeviceTable Table to place handles etc in. | |
| @param[in,out] DeviceIndex Number of devices found | |
| @param[in] DeviceFlags FALSE if a valid legacy ROM is required, TRUE otherwise. | |
| @retval EFI_SUCCESS One or more devices found | |
| @retval EFI_NOT_FOUND No device found | |
| **/ | |
| EFI_STATUS | |
| FindAllDeviceTypes ( | |
| IN PCI_CLASS_RECORD *PciClasses, | |
| IN OUT DEVICE_STRUCTURE *DeviceTable, | |
| IN OUT UINT16 *DeviceIndex, | |
| IN BOOLEAN DeviceFlags | |
| ) | |
| { | |
| UINTN HandleCount; | |
| EFI_HANDLE *HandleBuffer; | |
| UINTN Index; | |
| UINTN StartIndex; | |
| PCI_TYPE00 PciConfigHeader; | |
| EFI_PCI_IO_PROTOCOL *PciIo; | |
| EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; | |
| UINTN Flags; | |
| EFI_STATUS Status; | |
| UINTN Index2; | |
| // | |
| // Get legacy BIOS protocol as it is required to deal with Option ROMs. | |
| // | |
| StartIndex = *DeviceIndex; | |
| Status = gBS->LocateProtocol ( | |
| &gEfiLegacyBiosProtocolGuid, | |
| NULL, | |
| (VOID**)&LegacyBios | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| // | |
| // Get all PCI handles and check them to generate a list of matching devices. | |
| // | |
| gBS->LocateHandleBuffer ( | |
| ByProtocol, | |
| &gEfiPciIoProtocolGuid, | |
| NULL, | |
| &HandleCount, | |
| &HandleBuffer | |
| ); | |
| for (Index = 0; Index < HandleCount; Index++) { | |
| gBS->HandleProtocol ( | |
| HandleBuffer[Index], | |
| &gEfiPciIoProtocolGuid, | |
| (VOID**)&PciIo | |
| ); | |
| PciIo->Pci.Read ( | |
| PciIo, | |
| EfiPciIoWidthUint32, | |
| 0, | |
| sizeof (PciConfigHeader) / sizeof (UINT32), | |
| &PciConfigHeader | |
| ); | |
| for (Index2 = 0; PciClasses[Index2].Class != 0xff; Index2++) { | |
| if ((PciConfigHeader.Hdr.ClassCode[2] == PciClasses[Index2].Class) && | |
| (PciConfigHeader.Hdr.ClassCode[1] == PciClasses[Index2].SubClass)) { | |
| LegacyBios->CheckPciRom ( | |
| LegacyBios, | |
| HandleBuffer[Index], | |
| NULL, | |
| NULL, | |
| &Flags | |
| ); | |
| // | |
| // Verify that results of OPROM check match request. | |
| // The two valid requests are: | |
| // DeviceFlags = 0 require a valid legacy ROM | |
| // DeviceFlags = 1 require either no ROM or a valid legacy ROM | |
| // | |
| if ( | |
| ((DeviceFlags != 0) && (Flags == NO_ROM)) || | |
| ((Flags & (ROM_FOUND | VALID_LEGACY_ROM)) == (ROM_FOUND | VALID_LEGACY_ROM)) | |
| ) { | |
| DeviceTable->Handle = HandleBuffer[Index]; | |
| DeviceTable->Vid = PciConfigHeader.Hdr.VendorId; | |
| DeviceTable->Did = PciConfigHeader.Hdr.DeviceId; | |
| DeviceTable->SvId = PciConfigHeader.Device.SubsystemVendorID; | |
| DeviceTable->SysId = PciConfigHeader.Device.SubsystemID; | |
| ++ *DeviceIndex; | |
| DeviceTable++; | |
| } | |
| } | |
| } | |
| } | |
| // | |
| // Free any allocated buffers | |
| // | |
| gBS->FreePool (HandleBuffer); | |
| if (*DeviceIndex != StartIndex) { | |
| return EFI_SUCCESS; | |
| } else { | |
| return EFI_NOT_FOUND; | |
| } | |
| } | |
| /** | |
| Load and initialize the Legacy BIOS SMM handler. | |
| @param This The protocol instance pointer. | |
| @param EfiToLegacy16BootTable A pointer to Legacy16 boot table. | |
| @retval EFI_SUCCESS SMM code loaded. | |
| @retval EFI_DEVICE_ERROR SMM code failed to load | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SmmInit ( | |
| IN EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *This, | |
| IN VOID *EfiToLegacy16BootTable | |
| ) | |
| { | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Finds the device path that should be used as the primary display adapter. | |
| @param VgaHandle - The handle of the video device | |
| **/ | |
| VOID | |
| GetSelectedVgaDeviceInfo ( | |
| OUT EFI_HANDLE *VgaHandle | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN HandleCount; | |
| EFI_HANDLE *HandleBuffer; | |
| UINTN Index; | |
| EFI_PCI_IO_PROTOCOL *PciIo; | |
| PCI_TYPE00 Pci; | |
| UINT8 MinBus; | |
| UINT8 MaxBus; | |
| UINTN Segment; | |
| UINTN Bus; | |
| UINTN Device; | |
| UINTN Function; | |
| UINTN SelectedAddress; | |
| UINTN CurrentAddress; | |
| // | |
| // Initialize return to 'not found' state | |
| // | |
| *VgaHandle = NULL; | |
| // | |
| // Initialize variable states. Ths is important for selecting the VGA device | |
| // if multiple devices exist behind a single bridge. | |
| // | |
| HandleCount = 0; | |
| HandleBuffer = NULL; | |
| SelectedAddress = PCI_LIB_ADDRESS(0xff, 0x1f, 0x7, 0); | |
| // | |
| // The bus range to search for a VGA device in. | |
| // | |
| MinBus = MaxBus = 0; | |
| // | |
| // Start to check all the pci io to find all possible VGA device | |
| // | |
| HandleCount = 0; | |
| HandleBuffer = NULL; | |
| Status = gBS->LocateHandleBuffer ( | |
| ByProtocol, | |
| &gEfiPciIoProtocolGuid, | |
| NULL, | |
| &HandleCount, | |
| &HandleBuffer | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return; | |
| } | |
| for (Index = 0; Index < HandleCount; Index++) { | |
| Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiPciIoProtocolGuid, (VOID**)&PciIo); | |
| if (!EFI_ERROR (Status)) { | |
| // | |
| // Detemine if this is in the correct bus range. | |
| // | |
| Status = PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function); | |
| if (EFI_ERROR(Status) || (Bus < MinBus || Bus > MaxBus)) { | |
| continue; | |
| } | |
| // | |
| // Read device information. | |
| // | |
| Status = PciIo->Pci.Read ( | |
| PciIo, | |
| EfiPciIoWidthUint32, | |
| 0, | |
| sizeof (Pci) / sizeof (UINT32), | |
| &Pci | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| continue; | |
| } | |
| // | |
| // Make sure the device is a VGA device. | |
| // | |
| if (!IS_PCI_VGA (&Pci)) { | |
| continue; | |
| } | |
| DEBUG ((EFI_D_INFO, | |
| "PCI VGA: 0x%04x:0x%04x\n", | |
| Pci.Hdr.VendorId, | |
| Pci.Hdr.DeviceId | |
| )); | |
| // | |
| // Currently we use the lowest numbered bus/device/function if multiple | |
| // devices are found in the target bus range. | |
| // | |
| CurrentAddress = PCI_LIB_ADDRESS(Bus, Device, Function, 0); | |
| if (CurrentAddress < SelectedAddress) { | |
| SelectedAddress = CurrentAddress; | |
| *VgaHandle = HandleBuffer[Index]; | |
| } | |
| } | |
| } | |
| FreePool (HandleBuffer); | |
| } | |
| /** | |
| Returns a buffer of handles for the requested subfunction. | |
| @param This The protocol instance pointer. | |
| @param Mode Specifies what handle to return. See EFI_GET_PLATFORM_HANDLE_MODE enum. | |
| @param Type Mode specific. See EFI_GET_PLATFORM_HANDLE_MODE enum. | |
| @param HandleBuffer Mode specific. See EFI_GET_PLATFORM_HANDLE_MODE enum. | |
| @param HandleCount Mode specific. See EFI_GET_PLATFORM_HANDLE_MODE enum. | |
| @param AdditionalData Mode specific. See EFI_GET_PLATFORM_HANDLE_MODE enum. | |
| @retval EFI_SUCCESS Handle is valid. | |
| @retval EFI_UNSUPPORTED Mode is not supported on the platform. | |
| @retval EFI_NOT_FOUND Handle is not known. | |
| **/ | |
| EFI_STATUS | |
| 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 | |
| ) | |
| { | |
| DEVICE_STRUCTURE LocalDevice[0x40]; | |
| UINT32 LocalIndex; | |
| UINT32 Index; | |
| DEVICE_STRUCTURE TempDevice; | |
| EFI_STATUS Status; | |
| EFI_PCI_IO_PROTOCOL *PciIo; | |
| UINTN Segment; | |
| UINTN Bus; | |
| UINTN Device; | |
| UINTN Function; | |
| HDD_INFO *HddInfo; | |
| PCI_TYPE00 PciConfigHeader; | |
| UINT32 HddIndex; | |
| EFI_HANDLE IdeHandle; | |
| EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; | |
| PCI_CLASS_RECORD ClassLists[10]; | |
| UINTN PriorityIndex; | |
| static BOOLEAN bConnected = FALSE; | |
| LocalIndex = 0x00; | |
| HddInfo = NULL; | |
| HddIndex = 0; | |
| Status = gBS->LocateProtocol ( | |
| &gEfiLegacyBiosProtocolGuid, | |
| NULL, | |
| (VOID**)&LegacyBios | |
| ); | |
| // | |
| // Process mode specific operations | |
| // | |
| switch (Mode) { | |
| case EfiGetPlatformVgaHandle: | |
| // | |
| // Get the handle for the currently selected VGA device. | |
| // | |
| GetSelectedVgaDeviceInfo (&mVgaHandles[0]); | |
| *HandleBuffer = &mVgaHandles[0]; | |
| *HandleCount = (mVgaHandles[0] != NULL) ? 1 : 0; | |
| return EFI_SUCCESS; | |
| case EfiGetPlatformIdeHandle: | |
| IdeHandle = NULL; | |
| if (AdditionalData != NULL) { | |
| HddInfo = (HDD_INFO *) *AdditionalData; | |
| } | |
| // | |
| // Locate all found block io devices | |
| // | |
| ClassLists[0].Class = PCI_CLASS_MASS_STORAGE; | |
| ClassLists[0].SubClass = PCI_CLASS_MASS_STORAGE_SCSI; | |
| ClassLists[1].Class = PCI_CLASS_MASS_STORAGE; | |
| ClassLists[1].SubClass = PCI_CLASS_MASS_STORAGE_IDE; | |
| ClassLists[2].Class = PCI_CLASS_MASS_STORAGE; | |
| ClassLists[2].SubClass = PCI_CLASS_MASS_STORAGE_RAID; | |
| ClassLists[3].Class = PCI_CLASS_MASS_STORAGE; | |
| ClassLists[3].SubClass = PCI_CLASS_MASS_STORAGE_SATADPA; | |
| ClassLists[4].Class = 0xff; | |
| FindAllDeviceTypes (ClassLists, LocalDevice, (UINT16 *) &LocalIndex, TRUE); | |
| if (LocalIndex == 0) { | |
| return EFI_NOT_FOUND; | |
| } | |
| // | |
| // Make sure all IDE controllers are connected. This is necessary | |
| // in NO_CONFIG_CHANGE boot path to ensure IDE controller is correctly | |
| // initialized and all IDE drives are enumerated | |
| // | |
| if (!bConnected) { | |
| for (Index = 0; Index < LocalIndex; Index++) { | |
| gBS->ConnectController (LocalDevice[Index].Handle, NULL, NULL, TRUE); | |
| } | |
| } | |
| // | |
| // Locate onboard controllers. | |
| // | |
| for (Index = 0; Index < LocalIndex; Index++) { | |
| if (LocalDevice[Index].Vid == V_INTEL_VENDOR_ID) { | |
| if (LocalDevice[Index].Did == V_PIIX4_IDE_DEVICE_ID) { | |
| IdeHandle = LocalDevice[Index].Handle; | |
| } | |
| } | |
| } | |
| // | |
| // Set the IDE contorller as primary devices. | |
| // | |
| PriorityIndex = 0; | |
| for (Index = 0; Index < LocalIndex; Index++) { | |
| if (LocalDevice[Index].Handle == IdeHandle && PriorityIndex == 0) { | |
| TempDevice = LocalDevice[PriorityIndex]; | |
| LocalDevice[PriorityIndex] = LocalDevice[Index]; | |
| LocalDevice[Index] = TempDevice; | |
| PriorityIndex++; | |
| break; | |
| } | |
| } | |
| // | |
| // Copy over handles and update return values. | |
| // | |
| for (Index = 0; Index < LocalIndex; Index++) { | |
| mDiskHandles[Index] = LocalDevice[Index].Handle; | |
| } | |
| *HandleBuffer = &mDiskHandles[0]; | |
| *HandleCount = LocalIndex; | |
| // | |
| // We have connected all IDE controllers once. No more needed | |
| // | |
| bConnected = TRUE; | |
| // | |
| // Log all onboard controllers. | |
| // | |
| for (Index = 0; (Index < LocalIndex) && (AdditionalData != NULL); Index++) { | |
| if ((LocalDevice[Index].Handle != NULL) && | |
| (LocalDevice[Index].Handle == IdeHandle)) { | |
| Status = gBS->HandleProtocol ( | |
| LocalDevice[Index].Handle, | |
| &gEfiPciIoProtocolGuid, | |
| (VOID **) &PciIo | |
| ); | |
| PciIo->Pci.Read ( | |
| PciIo, | |
| EfiPciIoWidthUint32, | |
| 0, | |
| sizeof (PciConfigHeader) / sizeof (UINT32), | |
| &PciConfigHeader | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| PciIo->GetLocation ( | |
| PciIo, | |
| &Segment, | |
| &Bus, | |
| &Device, | |
| &Function | |
| ); | |
| // | |
| // Be sure to only fill out correct information based on platform | |
| // configureation. | |
| // | |
| HddInfo[HddIndex].Status |= HDD_PRIMARY; | |
| HddInfo[HddIndex].Bus = (UINT32)Bus; | |
| HddInfo[HddIndex].Device = (UINT32)Device; | |
| HddInfo[HddIndex].Function = (UINT32)Function; | |
| HddInfo[HddIndex + 1].Status |= HDD_SECONDARY; | |
| HddInfo[HddIndex + 1].Bus = (UINT32)Bus; | |
| HddInfo[HddIndex + 1].Device = (UINT32)Device; | |
| HddInfo[HddIndex + 1].Function = (UINT32)Function; | |
| // | |
| // Primary controller data | |
| // | |
| if ((PciConfigHeader.Hdr.ClassCode[0] & 0x01) != 0) { | |
| HddInfo[HddIndex].CommandBaseAddress = | |
| (UINT16)(PciConfigHeader.Device.Bar[0] & 0xfffc); | |
| HddInfo[HddIndex].ControlBaseAddress = | |
| (UINT16)((PciConfigHeader.Device.Bar[1] & 0xfffc)+2); | |
| HddInfo[HddIndex].BusMasterAddress = | |
| (UINT16)(PciConfigHeader.Device.Bar[4] & 0xfffc); | |
| HddInfo[HddIndex].HddIrq = PciConfigHeader.Device.InterruptLine; | |
| } else { | |
| HddInfo[HddIndex].HddIrq = 14; | |
| HddInfo[HddIndex].CommandBaseAddress = 0x1f0; | |
| HddInfo[HddIndex].ControlBaseAddress = 0x3f6; | |
| HddInfo[HddIndex].BusMasterAddress = 0; | |
| } | |
| HddIndex++; | |
| // | |
| // Secondary controller data | |
| // | |
| if ((PciConfigHeader.Hdr.ClassCode[0] & 0x04) != 0) { | |
| HddInfo[HddIndex].CommandBaseAddress = | |
| (UINT16)(PciConfigHeader.Device.Bar[2] & 0xfffc); | |
| HddInfo[HddIndex].ControlBaseAddress = | |
| (UINT16)((PciConfigHeader.Device.Bar[3] & 0xfffc)+2); | |
| HddInfo[HddIndex].BusMasterAddress = | |
| (UINT16)(HddInfo[HddIndex].BusMasterAddress + 8); | |
| HddInfo[HddIndex].HddIrq = PciConfigHeader.Device.InterruptLine; | |
| } else { | |
| HddInfo[HddIndex].HddIrq = 15; | |
| HddInfo[HddIndex].CommandBaseAddress = 0x170; | |
| HddInfo[HddIndex].ControlBaseAddress = 0x376; | |
| HddInfo[HddIndex].BusMasterAddress = 0; | |
| } | |
| HddIndex++; | |
| } | |
| } | |
| } | |
| return EFI_SUCCESS; | |
| case EfiGetPlatformIsaBusHandle: | |
| ClassLists[0].Class = (UINT8) PCI_CLASS_BRIDGE; | |
| ClassLists[0].SubClass = (UINT8) PCI_CLASS_BRIDGE_ISA_PDECODE; | |
| ClassLists[1].Class = (UINT8) PCI_CLASS_BRIDGE; | |
| ClassLists[1].SubClass = (UINT8) PCI_CLASS_BRIDGE_ISA; | |
| ClassLists[2].Class = 0xff; | |
| // | |
| // Locate all found block io devices | |
| // | |
| FindAllDeviceTypes (ClassLists, LocalDevice, (UINT16 *) (&LocalIndex), TRUE); | |
| if (LocalIndex == 0) { | |
| return EFI_NOT_FOUND; | |
| } | |
| // | |
| // Find our ISA bridge. | |
| // | |
| for (Index = 0; Index < LocalIndex; Index++) { | |
| if (LocalDevice[Index].Vid == V_INTEL_VENDOR_ID) { | |
| TempDevice = LocalDevice[0]; | |
| LocalDevice[0] = LocalDevice[Index]; | |
| LocalDevice[Index] = TempDevice; | |
| } | |
| } | |
| // | |
| // Perform copy and update return values. | |
| // | |
| for (Index = 0; Index < LocalIndex; Index++) { | |
| mIsaHandles[Index] = LocalDevice[Index].Handle; | |
| } | |
| *HandleBuffer = &mIsaHandles[0]; | |
| *HandleCount = LocalIndex; | |
| return EFI_SUCCESS; | |
| case EfiGetPlatformUsbHandle: | |
| default: | |
| return EFI_UNSUPPORTED; | |
| }; | |
| } | |
| /** | |
| Allows platform to perform any required action after a LegacyBios operation. | |
| Invokes the specific sub function specified by Mode. | |
| @param This The protocol instance pointer. | |
| @param Mode Specifies what handle to return. See EFI_GET_PLATFORM_HOOK_MODE enum. | |
| @param Type Mode specific. See EFI_GET_PLATFORM_HOOK_MODE enum. | |
| @param DeviceHandle Mode specific. See EFI_GET_PLATFORM_HOOK_MODE enum. | |
| @param ShadowAddress Mode specific. See EFI_GET_PLATFORM_HOOK_MODE enum. | |
| @param Compatibility16Table Mode specific. See EFI_GET_PLATFORM_HOOK_MODE enum. | |
| @param AdditionalData Mode specific. See EFI_GET_PLATFORM_HOOK_MODE enum. | |
| @retval EFI_SUCCESS The operation performed successfully. Mode specific. | |
| @retval EFI_UNSUPPORTED Mode is not supported on the platform. | |
| **/ | |
| EFI_STATUS | |
| 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 | |
| ) | |
| { | |
| EFI_IA32_REGISTER_SET Regs; | |
| EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; | |
| EFI_STATUS Status; | |
| switch (Mode) { | |
| case EfiPlatformHookPrepareToScanRom: | |
| Status = gBS->LocateProtocol ( | |
| &gEfiLegacyBiosProtocolGuid, | |
| NULL, | |
| (VOID**)&LegacyBios | |
| ); | |
| // | |
| // Set the 80x25 Text VGA Mode | |
| // | |
| Regs.H.AH = 0x00; | |
| Regs.H.AL = 0x03; | |
| Status = LegacyBios->Int86 (LegacyBios, 0x10, &Regs); | |
| return Status; | |
| case EfiPlatformHookShadowServiceRoms: | |
| return EFI_SUCCESS; | |
| case EfiPlatformHookAfterRomInit: | |
| default: | |
| return EFI_UNSUPPORTED; | |
| }; | |
| } | |
| /** | |
| Returns information associated with PCI IRQ routing. | |
| This function returns the following information associated with PCI IRQ routing: | |
| * An IRQ routing table and number of entries in the table. | |
| * The $PIR table and its size. | |
| * A list of PCI IRQs and the priority order to assign them. | |
| @param This The protocol instance pointer. | |
| @param RoutingTable The pointer to PCI IRQ Routing table. | |
| This location is the $PIR table minus the header. | |
| @param RoutingTableEntries The number of entries in table. | |
| @param LocalPirqTable $PIR table. | |
| @param PirqTableSize $PIR table size. | |
| @param LocalIrqPriorityTable A list of interrupts in priority order to assign. | |
| @param IrqPriorityTableEntries The number of entries in the priority table. | |
| @retval EFI_SUCCESS Data was successfully returned. | |
| **/ | |
| EFI_STATUS | |
| 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 | |
| ) | |
| { | |
| UINT16 PTableSize; | |
| UINT32 Index; | |
| UINT8 Bus; | |
| UINT8 Device; | |
| UINT8 Function; | |
| UINT8 Checksum; | |
| UINT8 *Ptr; | |
| EFI_STATUS Status; | |
| EFI_LEGACY_INTERRUPT_PROTOCOL *LegacyInterrupt; | |
| Checksum = 0; | |
| if (LocalPirqTable != NULL) { | |
| PTableSize = sizeof (EFI_LEGACY_PIRQ_TABLE_HEADER) + | |
| sizeof (EFI_LEGACY_IRQ_ROUTING_ENTRY) * MAX_IRQ_ROUTING_ENTRIES; | |
| Status = gBS->LocateProtocol ( | |
| &gEfiLegacyInterruptProtocolGuid, | |
| NULL, | |
| (VOID**)&LegacyInterrupt | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| LegacyInterrupt->GetLocation ( | |
| LegacyInterrupt, | |
| &Bus, | |
| &Device, | |
| &Function | |
| ); | |
| // | |
| // Update fields in $PIR table header | |
| // | |
| PirqTableHead.PirqTable.TableSize = PTableSize; | |
| PirqTableHead.PirqTable.Bus = Bus; | |
| PirqTableHead.PirqTable.DevFun = (UINT8) ((Device << 3) + Function); | |
| Ptr = (UINT8 *) (&PirqTableHead); | |
| // | |
| // Calculate checksum. | |
| // | |
| for (Index = 0; Index < PTableSize; Index++) { | |
| Checksum = (UINT8) (Checksum + (UINT8) *Ptr); | |
| Ptr += 1; | |
| } | |
| Checksum = (UINT8) (0x00 - Checksum); | |
| PirqTableHead.PirqTable.Checksum = Checksum; | |
| // | |
| // Update return values. | |
| // | |
| *LocalPirqTable = (VOID *) (&PirqTableHead); | |
| *PirqTableSize = PTableSize; | |
| } | |
| // | |
| // More items to return. | |
| // | |
| *RoutingTable = PirqTableHead.IrqRoutingEntry; | |
| *RoutingTableEntries = MAX_IRQ_ROUTING_ENTRIES; | |
| if (LocalIrqPriorityTable != NULL) { | |
| *LocalIrqPriorityTable = IrqPriorityTable; | |
| *IrqPriorityTableEntries = MAX_IRQ_PRIORITY_ENTRIES; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Finds the binary data or other platform information. | |
| @param This The protocol instance pointer. | |
| @param Mode Specifies what data to return. See See EFI_GET_PLATFORM_INFO_MODE enum. | |
| @param Table Mode specific. See EFI_GET_PLATFORM_INFO_MODE enum. | |
| @param TableSize Mode specific. See EFI_GET_PLATFORM_INFO_MODE enum. | |
| @param Location Mode specific. See EFI_GET_PLATFORM_INFO_MODE enum. | |
| @param Alignment Mode specific. See EFI_GET_PLATFORM_INFO_MODE enum. | |
| @param LegacySegment Mode specific. See EFI_GET_PLATFORM_INFO_MODE enum. | |
| @param LegacyOffset Mode specific. See EFI_GET_PLATFORM_INFO_MODE enum. | |
| @retval EFI_SUCCESS Data returned successfully. | |
| @retval EFI_UNSUPPORTED Mode is not supported on the platform. | |
| @retval EFI_NOT_FOUND Binary image or table not found. | |
| **/ | |
| EFI_STATUS | |
| 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 | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN Index; | |
| switch (Mode) { | |
| case EfiGetPlatformBinarySystemRom: | |
| // | |
| // Loop through table of System rom descriptions | |
| // | |
| for (Index = 0; mSystemRomTable[Index].Valid != 0; Index++) { | |
| Status = GetSectionFromFv ( | |
| &mSystemRomTable[Index].FileName, | |
| EFI_SECTION_RAW, | |
| 0, | |
| Table, | |
| (UINTN *) TableSize | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| continue; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| return EFI_NOT_FOUND; | |
| case EfiGetPlatformBinaryOem16Data: | |
| case EfiGetPlatformBinaryMpTable: | |
| case EfiGetPlatformBinaryOemIntData: | |
| case EfiGetPlatformBinaryOem32Data: | |
| case EfiGetPlatformBinaryTpmBinary: | |
| case EfiGetPlatformPciExpressBase: | |
| default: | |
| return EFI_UNSUPPORTED; | |
| }; | |
| } | |
| /** | |
| Translates the given PIRQ accounting for bridge. | |
| This function translates the given PIRQ back through all buses, if required, | |
| and returns the true PIRQ and associated IRQ. | |
| @param This The protocol instance pointer. | |
| @param PciBus The PCI bus number for this device. | |
| @param PciDevice The PCI device number for this device. | |
| @param PciFunction The PCI function number for this device. | |
| @param Pirq Input is PIRQ reported by device, and output is true PIRQ. | |
| @param PciIrq The IRQ already assigned to the PIRQ, or the IRQ to be | |
| assigned to the PIRQ. | |
| @retval EFI_SUCCESS The PIRQ was translated. | |
| **/ | |
| EFI_STATUS | |
| 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 | |
| ) | |
| { | |
| EFI_LEGACY_INTERRUPT_PROTOCOL *LegacyInterrupt; | |
| EFI_STATUS Status; | |
| UINTN Index; | |
| UINTN Index1; | |
| UINT8 LocalPirq; | |
| UINT8 PirqData; | |
| UINT8 MatchData; | |
| Status = gBS->LocateProtocol ( | |
| &gEfiLegacyInterruptProtocolGuid, | |
| NULL, | |
| (VOID**)&LegacyInterrupt | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| LocalPirq = (UINT8) (*Pirq); | |
| for (Index = 0; Index < MAX_IRQ_ROUTING_ENTRIES; Index++) { | |
| if ((PirqTableHead.IrqRoutingEntry[Index].Bus == PciBus) && | |
| (PirqTableHead.IrqRoutingEntry[Index].Device == PciDevice)) { | |
| LocalPirq = (UINT8) (PirqTableHead.IrqRoutingEntry[Index].PirqEntry[LocalPirq].Pirq & 0x0f); | |
| if (LocalPirq > 4) { | |
| LocalPirq -= 4; | |
| } | |
| LegacyInterrupt->ReadPirq (LegacyInterrupt, LocalPirq, &PirqData); | |
| MatchData = PCI_UNUSED; | |
| while (PirqData == 0) { | |
| for (Index1 = 0; Index1 < MAX_IRQ_PRIORITY_ENTRIES; Index1++) { | |
| if ((IrqPriorityTable[Index1].Used == MatchData) && | |
| (IrqPriorityTable[Index1].Irq != 0)) { | |
| PirqData = IrqPriorityTable[Index1].Irq; | |
| IrqPriorityTable[Index1].Used = 0xff; | |
| LegacyInterrupt->WritePirq ( | |
| LegacyInterrupt, | |
| LocalPirq, | |
| PirqData | |
| ); | |
| break; | |
| } | |
| } | |
| if (PirqData == 0) { | |
| // | |
| // No unused interrpts, so start reusing them. | |
| // | |
| MatchData = (UINT8) (~MatchData); | |
| } | |
| } | |
| *PciIrq = PirqData; | |
| *Pirq = LocalPirq; | |
| } | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Attempt to legacy boot the BootOption. If the EFI contexted has been | |
| compromised this function will not return. | |
| @param This The protocol instance pointer. | |
| @param BbsDevicePath The EFI Device Path from BootXXXX variable. | |
| @param BbsTable The Internal BBS table. | |
| @param LoadOptionSize The size of LoadOption in size. | |
| @param LoadOption The LoadOption from BootXXXX variable | |
| @param EfiToLegacy16BootTable A pointer to BootTable structure | |
| @retval EFI_SUCCESS Ready to boot. | |
| **/ | |
| EFI_STATUS | |
| 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 | |
| ) | |
| { | |
| BBS_TABLE *LocalBbsTable; | |
| EFI_TO_COMPATIBILITY16_BOOT_TABLE *Legacy16BootTable; | |
| DEVICE_PRODUCER_DATA_HEADER *SioPtr; | |
| UINT16 DevicePathType; | |
| UINT16 Index; | |
| UINT16 Priority; | |
| // | |
| // Initialize values | |
| // | |
| Priority = 0; | |
| Legacy16BootTable = (EFI_TO_COMPATIBILITY16_BOOT_TABLE*) EfiToLegacy16BootTable; | |
| // | |
| // Set how Gate A20 is gated by hardware | |
| // | |
| SioPtr = &Legacy16BootTable->SioData; | |
| SioPtr->Flags.A20Kybd = 1; | |
| SioPtr->Flags.A20Port90 = 1; | |
| SioPtr->MousePresent = 1; | |
| LocalBbsTable = BbsTable; | |
| // | |
| // There are 2 cases that must be covered. | |
| // Case 1: Booting to a legacy OS - BbsDevicePath is non-NULL. | |
| // Case 2: Booting to an EFI aware OS - BbsDevicePath is NULL. | |
| // We need to perform the PrepareToBoot function to assign | |
| // drive numbers to HDD devices to allow the shell or EFI | |
| // to access them. | |
| // | |
| if (BbsDevicePath != NULL) { | |
| DevicePathType = BbsDevicePath->DeviceType; | |
| } else { | |
| DevicePathType = BBS_HARDDISK; | |
| } | |
| // | |
| // Skip the boot devices where priority is set by BDS and set the next one | |
| // | |
| for (Index = 0; Index < Legacy16BootTable->NumberBbsEntries; Index++) { | |
| if ((LocalBbsTable[Index].BootPriority != BBS_UNPRIORITIZED_ENTRY) && | |
| (LocalBbsTable[Index].BootPriority != BBS_IGNORE_ENTRY) && | |
| (LocalBbsTable[Index].BootPriority != BBS_LOWEST_PRIORITY) && | |
| (Priority <= LocalBbsTable[Index].BootPriority)) { | |
| Priority = (UINT16) (LocalBbsTable[Index].BootPriority + 1); | |
| } | |
| } | |
| switch (DevicePathType) { | |
| case BBS_FLOPPY: | |
| case BBS_HARDDISK: | |
| case BBS_CDROM: | |
| case BBS_EMBED_NETWORK: | |
| for (Index = 0; Index < Legacy16BootTable->NumberBbsEntries; Index++) { | |
| if ((LocalBbsTable[Index].BootPriority == BBS_UNPRIORITIZED_ENTRY) && | |
| (LocalBbsTable[Index].DeviceType == DevicePathType)) { | |
| LocalBbsTable[Index].BootPriority = Priority; | |
| ++Priority; | |
| } | |
| } | |
| break; | |
| case BBS_BEV_DEVICE: | |
| for (Index = 0; Index < Legacy16BootTable->NumberBbsEntries; Index++) { | |
| if ((LocalBbsTable[Index].BootPriority == BBS_UNPRIORITIZED_ENTRY) && | |
| (LocalBbsTable[Index].Class == 01) && | |
| (LocalBbsTable[Index].SubClass == 01)) { | |
| LocalBbsTable[Index].BootPriority = Priority; | |
| ++Priority; | |
| } | |
| } | |
| break; | |
| case BBS_USB: | |
| case BBS_PCMCIA: | |
| case BBS_UNKNOWN: | |
| default: | |
| break; | |
| }; | |
| // | |
| // Set priority for rest of devices | |
| // | |
| for (Index = 0; Index < Legacy16BootTable->NumberBbsEntries; Index++) { | |
| if (LocalBbsTable[Index].BootPriority == BBS_UNPRIORITIZED_ENTRY) { | |
| LocalBbsTable[Index].BootPriority = Priority; | |
| ++Priority; | |
| } | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Initialize Legacy Platform support | |
| @retval EFI_SUCCESS Successfully initialized | |
| **/ | |
| EFI_STATUS | |
| LegacyBiosPlatformInstall ( | |
| VOID | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| LEGACY_BIOS_PLATFORM_INSTANCE *Private; | |
| mImageHandle = gImageHandle; | |
| Private = &mPrivateData; | |
| // | |
| // Grab a copy of all the protocols we depend on. | |
| // | |
| Private->Signature = LEGACY_BIOS_PLATFORM_INSTANCE_SIGNATURE; | |
| Private->LegacyBiosPlatform.GetPlatformInfo = GetPlatformInfo; | |
| Private->LegacyBiosPlatform.GetPlatformHandle = GetPlatformHandle; | |
| Private->LegacyBiosPlatform.SmmInit = SmmInit; | |
| Private->LegacyBiosPlatform.PlatformHooks = PlatformHooks; | |
| Private->LegacyBiosPlatform.GetRoutingTable = GetRoutingTable; | |
| Private->LegacyBiosPlatform.TranslatePirq = TranslatePirq; | |
| Private->LegacyBiosPlatform.PrepareToBoot = PrepareToBoot; | |
| Private->ImageHandle = gImageHandle; | |
| // | |
| // Make a new handle and install the protocol | |
| // | |
| Private->Handle = NULL; | |
| Status = gBS->InstallProtocolInterface ( | |
| &Private->Handle, | |
| &gEfiLegacyBiosPlatformProtocolGuid, | |
| EFI_NATIVE_INTERFACE, | |
| &Private->LegacyBiosPlatform | |
| ); | |
| return Status; | |
| } | |