From b522c77bdb4538710715dd13502840a2ca8072f6 Mon Sep 17 00:00:00 2001 From: Hao A Wu Date: Wed, 15 May 2019 11:22:29 +0800 Subject: [PATCH] OvmfPkg: Copy the required CSM components from framework packages REF:https://bugzilla.tianocore.org/show_bug.cgi?id=1811 This commit copies the exact: Drivers: * VideoDxe * LegacyBiosDxe Libraries: * LegacyBootMaintUiLib * LegacyBootManagerLib Guid header files: * Legacy Bios Guid * LegacyDevOrder Guid Protocol header files: * Firmware Volume Protocol * ISA ACPI Protocol * ISA I/O Protocol * Legacy BIOS Protocol * Legacy BIOS Platform Protocol * Legacy Interrupt Protocol * VGA Mini Port Protocol Framework header files (within IntelFrameworkPkg): * FrameworkDxe.h * Framework/BootScript.h * Framework/DxeCis.h * Framework/FirmwareVolumeHeader.h * Framework/FirmwareVolumeImageFormat.h * Framework/FrameworkInternalFormRepresentation.h * Framework/Hob.h * Framework/StatusCode.h from IntelFramework[Module]Pkg to OvmfPkg/Csm/ folder. Cc: Ray Ni Cc: Jordan Justen Cc: Ard Biesheuvel Signed-off-by: Hao A Wu Reviewed-by: David Woodhouse Reviewed-by: Laszlo Ersek --- OvmfPkg/Csm/BiosThunk/VideoDxe/BiosVideo.c | 3289 +++++++++++++++++ OvmfPkg/Csm/BiosThunk/VideoDxe/BiosVideo.h | 532 +++ .../Csm/BiosThunk/VideoDxe/BiosVideoDxe.uni | 17 + .../BiosThunk/VideoDxe/BiosVideoDxeExtra.uni | 14 + .../Csm/BiosThunk/VideoDxe/ComponentName.c | 306 ++ .../BiosThunk/VideoDxe/VesaBiosExtensions.h | 459 +++ OvmfPkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf | 80 + OvmfPkg/Csm/Include/Framework/BootScript.h | 41 + OvmfPkg/Csm/Include/Framework/DxeCis.h | 170 + .../Include/Framework/FirmwareVolumeHeader.h | 79 + .../Framework/FirmwareVolumeImageFormat.h | 32 + .../FrameworkInternalFormRepresentation.h | 397 ++ OvmfPkg/Csm/Include/Framework/Hob.h | 28 + OvmfPkg/Csm/Include/Framework/StatusCode.h | 155 + OvmfPkg/Csm/Include/FrameworkDxe.h | 26 + OvmfPkg/Csm/Include/Guid/LegacyBios.h | 29 + OvmfPkg/Csm/Include/Guid/LegacyDevOrder.h | 39 + OvmfPkg/Csm/Include/Protocol/FirmwareVolume.h | 340 ++ OvmfPkg/Csm/Include/Protocol/IsaAcpi.h | 298 ++ OvmfPkg/Csm/Include/Protocol/IsaIo.h | 356 ++ OvmfPkg/Csm/Include/Protocol/LegacyBios.h | 1553 ++++++++ .../Csm/Include/Protocol/LegacyBiosPlatform.h | 755 ++++ .../Csm/Include/Protocol/LegacyInterrupt.h | 122 + OvmfPkg/Csm/Include/Protocol/VgaMiniPort.h | 88 + .../LegacyBiosDxe/IA32/InterruptTable.nasm | 63 + OvmfPkg/Csm/LegacyBiosDxe/LegacyBbs.c | 377 ++ OvmfPkg/Csm/LegacyBiosDxe/LegacyBda.c | 62 + OvmfPkg/Csm/LegacyBiosDxe/LegacyBios.c | 1214 ++++++ OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf | 131 + OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxe.uni | 16 + .../Csm/LegacyBiosDxe/LegacyBiosDxeExtra.uni | 14 + .../Csm/LegacyBiosDxe/LegacyBiosInterface.h | 1460 ++++++++ OvmfPkg/Csm/LegacyBiosDxe/LegacyBootSupport.c | 2173 +++++++++++ OvmfPkg/Csm/LegacyBiosDxe/LegacyCmos.c | 117 + OvmfPkg/Csm/LegacyBiosDxe/LegacyIde.c | 310 ++ OvmfPkg/Csm/LegacyBiosDxe/LegacyPci.c | 3083 +++++++++++++++ OvmfPkg/Csm/LegacyBiosDxe/LegacySio.c | 477 +++ OvmfPkg/Csm/LegacyBiosDxe/Thunk.c | 419 +++ .../Csm/LegacyBiosDxe/X64/InterruptTable.nasm | 64 + .../LegacyBootMaintUiLib/LegacyBootMaintUi.c | 1505 ++++++++ .../LegacyBootMaintUiLib/LegacyBootMaintUi.h | 249 ++ .../LegacyBootMaintUiLib.inf | 63 + .../LegacyBootMaintUiLib.uni | 20 + .../LegacyBootMaintUiStrings.uni | 43 + .../LegacyBootMaintUiVfr.Vfr | 67 + .../LegacyBootMaintUiVfr.h | 79 + .../LegacyBootManagerLib/InternalLegacyBm.h | 60 + OvmfPkg/Csm/LegacyBootManagerLib/LegacyBm.c | 1530 ++++++++ .../LegacyBootManagerLib.inf | 58 + .../LegacyBootManagerLib.uni | 20 + 50 files changed, 22879 insertions(+) create mode 100644 OvmfPkg/Csm/BiosThunk/VideoDxe/BiosVideo.c create mode 100644 OvmfPkg/Csm/BiosThunk/VideoDxe/BiosVideo.h create mode 100644 OvmfPkg/Csm/BiosThunk/VideoDxe/BiosVideoDxe.uni create mode 100644 OvmfPkg/Csm/BiosThunk/VideoDxe/BiosVideoDxeExtra.uni create mode 100644 OvmfPkg/Csm/BiosThunk/VideoDxe/ComponentName.c create mode 100644 OvmfPkg/Csm/BiosThunk/VideoDxe/VesaBiosExtensions.h create mode 100644 OvmfPkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf create mode 100644 OvmfPkg/Csm/Include/Framework/BootScript.h create mode 100644 OvmfPkg/Csm/Include/Framework/DxeCis.h create mode 100644 OvmfPkg/Csm/Include/Framework/FirmwareVolumeHeader.h create mode 100644 OvmfPkg/Csm/Include/Framework/FirmwareVolumeImageFormat.h create mode 100644 OvmfPkg/Csm/Include/Framework/FrameworkInternalFormRepresentation.h create mode 100644 OvmfPkg/Csm/Include/Framework/Hob.h create mode 100644 OvmfPkg/Csm/Include/Framework/StatusCode.h create mode 100644 OvmfPkg/Csm/Include/FrameworkDxe.h create mode 100644 OvmfPkg/Csm/Include/Guid/LegacyBios.h create mode 100644 OvmfPkg/Csm/Include/Guid/LegacyDevOrder.h create mode 100644 OvmfPkg/Csm/Include/Protocol/FirmwareVolume.h create mode 100644 OvmfPkg/Csm/Include/Protocol/IsaAcpi.h create mode 100644 OvmfPkg/Csm/Include/Protocol/IsaIo.h create mode 100644 OvmfPkg/Csm/Include/Protocol/LegacyBios.h create mode 100644 OvmfPkg/Csm/Include/Protocol/LegacyBiosPlatform.h create mode 100644 OvmfPkg/Csm/Include/Protocol/LegacyInterrupt.h create mode 100644 OvmfPkg/Csm/Include/Protocol/VgaMiniPort.h create mode 100644 OvmfPkg/Csm/LegacyBiosDxe/IA32/InterruptTable.nasm create mode 100644 OvmfPkg/Csm/LegacyBiosDxe/LegacyBbs.c create mode 100644 OvmfPkg/Csm/LegacyBiosDxe/LegacyBda.c create mode 100644 OvmfPkg/Csm/LegacyBiosDxe/LegacyBios.c create mode 100644 OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf create mode 100644 OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxe.uni create mode 100644 OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxeExtra.uni create mode 100644 OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosInterface.h create mode 100644 OvmfPkg/Csm/LegacyBiosDxe/LegacyBootSupport.c create mode 100644 OvmfPkg/Csm/LegacyBiosDxe/LegacyCmos.c create mode 100644 OvmfPkg/Csm/LegacyBiosDxe/LegacyIde.c create mode 100644 OvmfPkg/Csm/LegacyBiosDxe/LegacyPci.c create mode 100644 OvmfPkg/Csm/LegacyBiosDxe/LegacySio.c create mode 100644 OvmfPkg/Csm/LegacyBiosDxe/Thunk.c create mode 100644 OvmfPkg/Csm/LegacyBiosDxe/X64/InterruptTable.nasm create mode 100644 OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUi.c create mode 100644 OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUi.h create mode 100644 OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUiLib.inf create mode 100644 OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUiLib.uni create mode 100644 OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUiStrings.uni create mode 100644 OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUiVfr.Vfr create mode 100644 OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUiVfr.h create mode 100644 OvmfPkg/Csm/LegacyBootManagerLib/InternalLegacyBm.h create mode 100644 OvmfPkg/Csm/LegacyBootManagerLib/LegacyBm.c create mode 100644 OvmfPkg/Csm/LegacyBootManagerLib/LegacyBootManagerLib.inf create mode 100644 OvmfPkg/Csm/LegacyBootManagerLib/LegacyBootManagerLib.uni diff --git a/OvmfPkg/Csm/BiosThunk/VideoDxe/BiosVideo.c b/OvmfPkg/Csm/BiosThunk/VideoDxe/BiosVideo.c new file mode 100644 index 0000000000..0640656dba --- /dev/null +++ b/OvmfPkg/Csm/BiosThunk/VideoDxe/BiosVideo.c @@ -0,0 +1,3289 @@ +/** @file + ConsoleOut Routines that speak VGA. + +Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "BiosVideo.h" + +// +// EFI Driver Binding Protocol Instance +// +EFI_DRIVER_BINDING_PROTOCOL gBiosVideoDriverBinding = { + BiosVideoDriverBindingSupported, + BiosVideoDriverBindingStart, + BiosVideoDriverBindingStop, + 0x3, + NULL, + NULL +}; + +// +// Global lookup tables for VGA graphics modes +// +UINT8 mVgaLeftMaskTable[] = { 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01 }; + +UINT8 mVgaRightMaskTable[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; + +UINT8 mVgaBitMaskTable[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; + +// +// Save controller attributes during first start +// +UINT64 mOriginalPciAttributes; +BOOLEAN mPciAttributesSaved = FALSE; + +EFI_GRAPHICS_OUTPUT_BLT_PIXEL mVgaColorToGraphicsOutputColor[] = { + { 0x00, 0x00, 0x00, 0x00 }, + { 0x98, 0x00, 0x00, 0x00 }, + { 0x00, 0x98, 0x00, 0x00 }, + { 0x98, 0x98, 0x00, 0x00 }, + { 0x00, 0x00, 0x98, 0x00 }, + { 0x98, 0x00, 0x98, 0x00 }, + { 0x00, 0x98, 0x98, 0x00 }, + { 0x98, 0x98, 0x98, 0x00 }, + { 0x10, 0x10, 0x10, 0x00 }, + { 0xff, 0x10, 0x10, 0x00 }, + { 0x10, 0xff, 0x10, 0x00 }, + { 0xff, 0xff, 0x10, 0x00 }, + { 0x10, 0x10, 0xff, 0x00 }, + { 0xf0, 0x10, 0xff, 0x00 }, + { 0x10, 0xff, 0xff, 0x00 }, + { 0xff, 0xff, 0xff, 0x00 } +}; + +// +// Standard timing defined by VESA EDID +// +VESA_BIOS_EXTENSIONS_EDID_TIMING mEstablishedEdidTiming[] = { + // + // Established Timing I + // + {800, 600, 60}, + {800, 600, 56}, + {640, 480, 75}, + {640, 480, 72}, + {640, 480, 67}, + {640, 480, 60}, + {720, 400, 88}, + {720, 400, 70}, + // + // Established Timing II + // + {1280, 1024, 75}, + {1024, 768, 75}, + {1024, 768, 70}, + {1024, 768, 60}, + {1024, 768, 87}, + {832, 624, 75}, + {800, 600, 75}, + {800, 600, 72}, + // + // Established Timing III + // + {1152, 870, 75} +}; + +/** + Supported. + + @param This Pointer to driver binding protocol + @param Controller Controller handle to connect + @param RemainingDevicePath A pointer to the remaining portion of a device + path + + @retval EFI_STATUS EFI_SUCCESS:This controller can be managed by this + driver, Otherwise, this controller cannot be + managed by this driver + +**/ +EFI_STATUS +EFIAPI +BiosVideoDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + EFI_PCI_IO_PROTOCOL *PciIo; + PCI_TYPE00 Pci; + EFI_DEV_PATH *Node; + + // + // See if the Legacy BIOS Protocol is available + // + Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Open the IO Abstraction(s) needed to perform the supported test + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) { + return Status; + } + + if (Status == EFI_ALREADY_STARTED) { + // + // If VgaMiniPort protocol is installed, EFI_ALREADY_STARTED indicates failure, + // because VgaMiniPort protocol is installed on controller handle directly. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiVgaMiniPortProtocolGuid, + NULL, + NULL, + NULL, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + return EFI_ALREADY_STARTED; + } + } + // + // See if this is a PCI Graphics Controller by looking at the Command register and + // Class Code Register + // + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint32, + 0, + sizeof (Pci) / sizeof (UINT32), + &Pci + ); + if (EFI_ERROR (Status)) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + Status = EFI_UNSUPPORTED; + if (Pci.Hdr.ClassCode[2] == 0x03 || (Pci.Hdr.ClassCode[2] == 0x00 && Pci.Hdr.ClassCode[1] == 0x01)) { + + Status = EFI_SUCCESS; + // + // If this is a graphics controller, + // go further check RemainingDevicePath validation + // + if (RemainingDevicePath != NULL) { + Node = (EFI_DEV_PATH *) RemainingDevicePath; + // + // Check if RemainingDevicePath is the End of Device Path Node, + // if yes, return EFI_SUCCESS + // + if (!IsDevicePathEnd (Node)) { + // + // If RemainingDevicePath isn't the End of Device Path Node, + // check its validation + // + if (Node->DevPath.Type != ACPI_DEVICE_PATH || + Node->DevPath.SubType != ACPI_ADR_DP || + DevicePathNodeLength(&Node->DevPath) < sizeof(ACPI_ADR_DEVICE_PATH)) { + Status = EFI_UNSUPPORTED; + } + } + } + } + +Done: + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; +} + + +/** + Install Graphics Output Protocol onto VGA device handles. + + @param This Pointer to driver binding protocol + @param Controller Controller handle to connect + @param RemainingDevicePath A pointer to the remaining portion of a device + path + + @return EFI_STATUS + +**/ +EFI_STATUS +EFIAPI +BiosVideoDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + UINTN Flags; + UINT64 Supports; + + // + // Initialize local variables + // + PciIo = NULL; + ParentDevicePath = NULL; + + // + // + // See if the Legacy BIOS Protocol is available + // + Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Prepare for status code + // + Status = gBS->HandleProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &ParentDevicePath + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Open the IO Abstraction(s) needed + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) { + return Status; + } + + // + // Save original PCI attributes + // + if (!mPciAttributesSaved) { + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationGet, + 0, + &mOriginalPciAttributes + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + mPciAttributesSaved = TRUE; + } + + // + // Get supported PCI attributes + // + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationSupported, + 0, + &Supports + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + Supports &= (UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16); + if (Supports == 0 || Supports == (EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_PC_ENABLE, + ParentDevicePath + ); + // + // Enable the device and make sure VGA cycles are being forwarded to this VGA device + // + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationEnable, + EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | Supports, + NULL + ); + if (EFI_ERROR (Status)) { + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_RESOURCE_CONFLICT, + ParentDevicePath + ); + goto Done; + } + // + // Check to see if there is a legacy option ROM image associated with this PCI device + // + Status = LegacyBios->CheckPciRom ( + LegacyBios, + Controller, + NULL, + NULL, + &Flags + ); + if (EFI_ERROR (Status)) { + goto Done; + } + // + // Post the legacy option ROM if it is available. + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + EFI_P_PC_RESET, + ParentDevicePath + ); + Status = LegacyBios->InstallPciRom ( + LegacyBios, + Controller, + NULL, + &Flags, + NULL, + NULL, + NULL, + NULL + ); + if (EFI_ERROR (Status)) { + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_CONTROLLER_ERROR, + ParentDevicePath + ); + goto Done; + } + + if (RemainingDevicePath != NULL) { + if (IsDevicePathEnd (RemainingDevicePath) && + (FeaturePcdGet (PcdBiosVideoCheckVbeEnable) || FeaturePcdGet (PcdBiosVideoCheckVgaEnable))) { + // + // If RemainingDevicePath is the End of Device Path Node, + // don't create any child device and return EFI_SUCESS + Status = EFI_SUCCESS; + goto Done; + } + } + + // + // Create child handle and install GraphicsOutputProtocol on it + // + Status = BiosVideoChildHandleInstall ( + This, + Controller, + PciIo, + LegacyBios, + ParentDevicePath, + RemainingDevicePath + ); + +Done: + if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) { + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_PC_DISABLE, + ParentDevicePath + ); + + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_NOT_DETECTED, + ParentDevicePath + ); + if (!HasChildHandle (Controller)) { + if (mPciAttributesSaved) { + // + // Restore original PCI attributes + // + PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationSet, + mOriginalPciAttributes, + NULL + ); + } + } + // + // Release PCI I/O Protocols on the controller handle. + // + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + } + + return Status; +} + + +/** + Stop. + + @param This Pointer to driver binding protocol + @param Controller Controller handle to connect + @param NumberOfChildren Number of children handle created by this driver + @param ChildHandleBuffer Buffer containing child handle created + + @retval EFI_SUCCESS Driver disconnected successfully from controller + @retval EFI_UNSUPPORTED Cannot find BIOS_VIDEO_DEV structure + +**/ +EFI_STATUS +EFIAPI +BiosVideoDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + EFI_STATUS Status; + BOOLEAN AllChildrenStopped; + UINTN Index; + EFI_PCI_IO_PROTOCOL *PciIo; + + AllChildrenStopped = TRUE; + + if (NumberOfChildren == 0) { + // + // Close PCI I/O protocol on the controller handle + // + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return EFI_SUCCESS; + } + + for (Index = 0; Index < NumberOfChildren; Index++) { + Status = BiosVideoChildHandleUninstall (This, Controller, ChildHandleBuffer[Index]); + + if (EFI_ERROR (Status)) { + AllChildrenStopped = FALSE; + } + } + + if (!AllChildrenStopped) { + return EFI_DEVICE_ERROR; + } + + if (!HasChildHandle (Controller)) { + if (mPciAttributesSaved) { + Status = gBS->HandleProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo + ); + ASSERT_EFI_ERROR (Status); + + // + // Restore original PCI attributes + // + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationSet, + mOriginalPciAttributes, + NULL + ); + ASSERT_EFI_ERROR (Status); + } + } + + + return EFI_SUCCESS; +} + + +/** + Install child handles if the Handle supports MBR format. + + @param This Calling context. + @param ParentHandle Parent Handle + @param ParentPciIo Parent PciIo interface + @param ParentLegacyBios Parent LegacyBios interface + @param ParentDevicePath Parent Device Path + @param RemainingDevicePath Remaining Device Path + + @retval EFI_SUCCESS If a child handle was added + @retval other A child handle was not added + +**/ +EFI_STATUS +BiosVideoChildHandleInstall ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ParentHandle, + IN EFI_PCI_IO_PROTOCOL *ParentPciIo, + IN EFI_LEGACY_BIOS_PROTOCOL *ParentLegacyBios, + IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + BIOS_VIDEO_DEV *BiosVideoPrivate; + PCI_TYPE00 Pci; + ACPI_ADR_DEVICE_PATH AcpiDeviceNode; + BOOLEAN ProtocolInstalled; + + // + // Allocate the private device structure for video device + // + BiosVideoPrivate = (BIOS_VIDEO_DEV *) AllocateZeroPool ( + sizeof (BIOS_VIDEO_DEV) + ); + if (NULL == BiosVideoPrivate) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + // + // See if this is a VGA compatible controller or not + // + Status = ParentPciIo->Pci.Read ( + ParentPciIo, + EfiPciIoWidthUint32, + 0, + sizeof (Pci) / sizeof (UINT32), + &Pci + ); + if (EFI_ERROR (Status)) { + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_CONTROLLER_ERROR, + ParentDevicePath + ); + goto Done; + } + BiosVideoPrivate->VgaCompatible = FALSE; + if (Pci.Hdr.ClassCode[2] == 0x00 && Pci.Hdr.ClassCode[1] == 0x01) { + BiosVideoPrivate->VgaCompatible = TRUE; + } + + if (Pci.Hdr.ClassCode[2] == 0x03 && Pci.Hdr.ClassCode[1] == 0x00 && Pci.Hdr.ClassCode[0] == 0x00) { + BiosVideoPrivate->VgaCompatible = TRUE; + } + + if (PcdGetBool (PcdBiosVideoSetTextVgaModeEnable)) { + // + // Create EXIT_BOOT_SERIVES Event + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + BiosVideoNotifyExitBootServices, + BiosVideoPrivate, + &gEfiEventExitBootServicesGuid, + &BiosVideoPrivate->ExitBootServicesEvent + ); + if (EFI_ERROR (Status)) { + goto Done; + } + } + + // + // Initialize the child private structure + // + BiosVideoPrivate->Signature = BIOS_VIDEO_DEV_SIGNATURE; + + // + // Fill in Graphics Output specific mode structures + // + BiosVideoPrivate->HardwareNeedsStarting = TRUE; + BiosVideoPrivate->ModeData = NULL; + BiosVideoPrivate->LineBuffer = NULL; + BiosVideoPrivate->VgaFrameBuffer = NULL; + BiosVideoPrivate->VbeFrameBuffer = NULL; + + // + // Fill in the Graphics Output Protocol + // + BiosVideoPrivate->GraphicsOutput.QueryMode = BiosVideoGraphicsOutputQueryMode; + BiosVideoPrivate->GraphicsOutput.SetMode = BiosVideoGraphicsOutputSetMode; + + + // + // Allocate buffer for Graphics Output Protocol mode information + // + BiosVideoPrivate->GraphicsOutput.Mode = (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *) AllocatePool ( + sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE) + ); + if (NULL == BiosVideoPrivate->GraphicsOutput.Mode) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + BiosVideoPrivate->GraphicsOutput.Mode->Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) AllocatePool ( + sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION) + ); + if (NULL == BiosVideoPrivate->GraphicsOutput.Mode->Info) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + // + // Assume that Graphics Output Protocol will be produced until proven otherwise + // + BiosVideoPrivate->ProduceGraphicsOutput = TRUE; + + // + // Set Gop Device Path, here RemainingDevicePath will not be one End of Device Path Node. + // + if ((RemainingDevicePath == NULL) || (!IsDevicePathEnd (RemainingDevicePath))) { + if (RemainingDevicePath == NULL) { + ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH)); + AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH; + AcpiDeviceNode.Header.SubType = ACPI_ADR_DP; + AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA, 0, 0); + SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH)); + + BiosVideoPrivate->GopDevicePath = AppendDevicePathNode ( + ParentDevicePath, + (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode + ); + } else { + BiosVideoPrivate->GopDevicePath = AppendDevicePathNode (ParentDevicePath, RemainingDevicePath); + } + + // + // Creat child handle and device path protocol firstly + // + BiosVideoPrivate->Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &BiosVideoPrivate->Handle, + &gEfiDevicePathProtocolGuid, + BiosVideoPrivate->GopDevicePath, + NULL + ); + if (EFI_ERROR (Status)) { + goto Done; + } + } + + // + // Fill in the VGA Mini Port Protocol fields + // + BiosVideoPrivate->VgaMiniPort.SetMode = BiosVideoVgaMiniPortSetMode; + BiosVideoPrivate->VgaMiniPort.VgaMemoryOffset = 0xb8000; + BiosVideoPrivate->VgaMiniPort.CrtcAddressRegisterOffset = 0x3d4; + BiosVideoPrivate->VgaMiniPort.CrtcDataRegisterOffset = 0x3d5; + BiosVideoPrivate->VgaMiniPort.VgaMemoryBar = EFI_PCI_IO_PASS_THROUGH_BAR; + BiosVideoPrivate->VgaMiniPort.CrtcAddressRegisterBar = EFI_PCI_IO_PASS_THROUGH_BAR; + BiosVideoPrivate->VgaMiniPort.CrtcDataRegisterBar = EFI_PCI_IO_PASS_THROUGH_BAR; + + // + // Child handle need to consume the Legacy Bios protocol + // + BiosVideoPrivate->LegacyBios = ParentLegacyBios; + + // + // When check for VBE, PCI I/O protocol is needed, so use parent's protocol interface temporally + // + BiosVideoPrivate->PciIo = ParentPciIo; + + // + // Check for VESA BIOS Extensions for modes that are compatible with Graphics Output + // + if (FeaturePcdGet (PcdBiosVideoCheckVbeEnable)) { + Status = BiosVideoCheckForVbe (BiosVideoPrivate); + DEBUG ((EFI_D_INFO, "BiosVideoCheckForVbe - %r\n", Status)); + } else { + Status = EFI_UNSUPPORTED; + } + if (EFI_ERROR (Status)) { + // + // The VESA BIOS Extensions are not compatible with Graphics Output, so check for support + // for the standard 640x480 16 color VGA mode + // + DEBUG ((EFI_D_INFO, "VgaCompatible - %x\n", BiosVideoPrivate->VgaCompatible)); + if (BiosVideoPrivate->VgaCompatible) { + if (FeaturePcdGet (PcdBiosVideoCheckVgaEnable)) { + Status = BiosVideoCheckForVga (BiosVideoPrivate); + DEBUG ((EFI_D_INFO, "BiosVideoCheckForVga - %r\n", Status)); + } else { + Status = EFI_UNSUPPORTED; + } + } + + if (EFI_ERROR (Status)) { + // + // Free GOP mode structure if it is not freed before + // VgaMiniPort does not need this structure any more + // + if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) { + if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) { + FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info); + BiosVideoPrivate->GraphicsOutput.Mode->Info = NULL; + } + FreePool (BiosVideoPrivate->GraphicsOutput.Mode); + BiosVideoPrivate->GraphicsOutput.Mode = NULL; + } + + // + // Neither VBE nor the standard 640x480 16 color VGA mode are supported, so do + // not produce the Graphics Output protocol. Instead, produce the VGA MiniPort Protocol. + // + BiosVideoPrivate->ProduceGraphicsOutput = FALSE; + + // + // INT services are available, so on the 80x25 and 80x50 text mode are supported + // + BiosVideoPrivate->VgaMiniPort.MaxMode = 2; + } + } + + ProtocolInstalled = FALSE; + + if (BiosVideoPrivate->ProduceGraphicsOutput) { + // + // Creat child handle and install Graphics Output Protocol,EDID Discovered/Active Protocol + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &BiosVideoPrivate->Handle, + &gEfiGraphicsOutputProtocolGuid, + &BiosVideoPrivate->GraphicsOutput, + &gEfiEdidDiscoveredProtocolGuid, + &BiosVideoPrivate->EdidDiscovered, + &gEfiEdidActiveProtocolGuid, + &BiosVideoPrivate->EdidActive, + NULL + ); + + if (!EFI_ERROR (Status)) { + // + // Open the Parent Handle for the child + // + Status = gBS->OpenProtocol ( + ParentHandle, + &gEfiPciIoProtocolGuid, + (VOID **) &BiosVideoPrivate->PciIo, + This->DriverBindingHandle, + BiosVideoPrivate->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + if (EFI_ERROR (Status)) { + goto Done; + } + ProtocolInstalled = TRUE; + } + } + + if (!ProtocolInstalled) { + // + // Install VGA Mini Port Protocol + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &ParentHandle, + &gEfiVgaMiniPortProtocolGuid, + &BiosVideoPrivate->VgaMiniPort, + NULL + ); + } + +Done: + if (EFI_ERROR (Status)) { + if ((BiosVideoPrivate != NULL) && (BiosVideoPrivate->ExitBootServicesEvent != NULL)) { + gBS->CloseEvent (BiosVideoPrivate->ExitBootServicesEvent); + } + // + // Free private data structure + // + BiosVideoDeviceReleaseResource (BiosVideoPrivate); + } + + return Status; +} + + +/** + Deregister an video child handle and free resources. + + @param This Protocol instance pointer. + @param Controller Video controller handle + @param Handle Video child handle + + @return EFI_STATUS + +**/ +EFI_STATUS +BiosVideoChildHandleUninstall ( + EFI_DRIVER_BINDING_PROTOCOL *This, + EFI_HANDLE Controller, + EFI_HANDLE Handle + ) +{ + EFI_STATUS Status; + EFI_IA32_REGISTER_SET Regs; + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; + EFI_VGA_MINI_PORT_PROTOCOL *VgaMiniPort; + BIOS_VIDEO_DEV *BiosVideoPrivate; + EFI_PCI_IO_PROTOCOL *PciIo; + + BiosVideoPrivate = NULL; + GraphicsOutput = NULL; + PciIo = NULL; + Status = EFI_UNSUPPORTED; + + Status = gBS->OpenProtocol ( + Handle, + &gEfiGraphicsOutputProtocolGuid, + (VOID **) &GraphicsOutput, + This->DriverBindingHandle, + Handle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput); + } + + if (EFI_ERROR (Status)) { + Status = gBS->OpenProtocol ( + Handle, + &gEfiVgaMiniPortProtocolGuid, + (VOID **) &VgaMiniPort, + This->DriverBindingHandle, + Handle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (VgaMiniPort); + } + } + + if (BiosVideoPrivate == NULL) { + return EFI_UNSUPPORTED; + } + + // + // Set the 80x25 Text VGA Mode + // + Regs.H.AH = 0x00; + Regs.H.AL = 0x03; + BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs); + + Regs.H.AH = 0x11; + Regs.H.AL = 0x14; + Regs.H.BL = 0; + BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs); + + // + // Close PCI I/O protocol that opened by child handle + // + Status = gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Handle + ); + + // + // Uninstall protocols on child handle + // + if (BiosVideoPrivate->ProduceGraphicsOutput) { + Status = gBS->UninstallMultipleProtocolInterfaces ( + BiosVideoPrivate->Handle, + &gEfiDevicePathProtocolGuid, + BiosVideoPrivate->GopDevicePath, + &gEfiGraphicsOutputProtocolGuid, + &BiosVideoPrivate->GraphicsOutput, + &gEfiEdidDiscoveredProtocolGuid, + &BiosVideoPrivate->EdidDiscovered, + &gEfiEdidActiveProtocolGuid, + &BiosVideoPrivate->EdidActive, + NULL + ); + } + if (!BiosVideoPrivate->ProduceGraphicsOutput) { + Status = gBS->UninstallMultipleProtocolInterfaces ( + Controller, + &gEfiVgaMiniPortProtocolGuid, + &BiosVideoPrivate->VgaMiniPort, + NULL + ); + } + + if (EFI_ERROR (Status)) { + gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + return Status; + } + + if (PcdGetBool (PcdBiosVideoSetTextVgaModeEnable)) { + // + // Close EXIT_BOOT_SERIVES Event + // + gBS->CloseEvent (BiosVideoPrivate->ExitBootServicesEvent); + } + + // + // Release all allocated resources + // + BiosVideoDeviceReleaseResource (BiosVideoPrivate); + + return EFI_SUCCESS; +} + + +/** + Release resource for biso video instance. + + @param BiosVideoPrivate Video child device private data structure + +**/ +VOID +BiosVideoDeviceReleaseResource ( + BIOS_VIDEO_DEV *BiosVideoPrivate + ) +{ + if (BiosVideoPrivate == NULL) { + return ; + } + + // + // Release all the resourses occupied by the BIOS_VIDEO_DEV + // + + // + // Free VGA Frame Buffer + // + if (BiosVideoPrivate->VgaFrameBuffer != NULL) { + FreePool (BiosVideoPrivate->VgaFrameBuffer); + } + // + // Free VBE Frame Buffer + // + if (BiosVideoPrivate->VbeFrameBuffer != NULL) { + FreePool (BiosVideoPrivate->VbeFrameBuffer); + } + // + // Free line buffer + // + if (BiosVideoPrivate->LineBuffer != NULL) { + FreePool (BiosVideoPrivate->LineBuffer); + } + // + // Free mode data + // + if (BiosVideoPrivate->ModeData != NULL) { + FreePool (BiosVideoPrivate->ModeData); + } + // + // Free memory allocated below 1MB + // + if (BiosVideoPrivate->PagesBelow1MB != 0) { + gBS->FreePages (BiosVideoPrivate->PagesBelow1MB, BiosVideoPrivate->NumberOfPagesBelow1MB); + } + + if (BiosVideoPrivate->VbeSaveRestorePages != 0) { + gBS->FreePages (BiosVideoPrivate->VbeSaveRestoreBuffer, BiosVideoPrivate->VbeSaveRestorePages); + } + + // + // Free graphics output protocol occupied resource + // + if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) { + if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) { + FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info); + BiosVideoPrivate->GraphicsOutput.Mode->Info = NULL; + } + FreePool (BiosVideoPrivate->GraphicsOutput.Mode); + BiosVideoPrivate->GraphicsOutput.Mode = NULL; + } + // + // Free EDID discovered protocol occupied resource + // + if (BiosVideoPrivate->EdidDiscovered.Edid != NULL) { + FreePool (BiosVideoPrivate->EdidDiscovered.Edid); + } + // + // Free EDID active protocol occupied resource + // + if (BiosVideoPrivate->EdidActive.Edid != NULL) { + FreePool (BiosVideoPrivate->EdidActive.Edid); + } + + if (BiosVideoPrivate->GopDevicePath!= NULL) { + FreePool (BiosVideoPrivate->GopDevicePath); + } + + FreePool (BiosVideoPrivate); + + return ; +} + + +/** + Generate a search key for a specified timing data. + + @param EdidTiming Pointer to EDID timing + + @return The 32 bit unique key for search. + +**/ +UINT32 +CalculateEdidKey ( + VESA_BIOS_EXTENSIONS_EDID_TIMING *EdidTiming + ) +{ + UINT32 Key; + + // + // Be sure no conflicts for all standard timing defined by VESA. + // + Key = (EdidTiming->HorizontalResolution * 2) + EdidTiming->VerticalResolution; + return Key; +} + + +/** + Parse the Established Timing and Standard Timing in EDID data block. + + @param EdidBuffer Pointer to EDID data block + @param ValidEdidTiming Valid EDID timing information + + @retval TRUE The EDID data is valid. + @retval FALSE The EDID data is invalid. + +**/ +BOOLEAN +ParseEdidData ( + UINT8 *EdidBuffer, + VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING *ValidEdidTiming + ) +{ + UINT8 CheckSum; + UINT32 Index; + UINT32 ValidNumber; + UINT32 TimingBits; + UINT8 *BufferIndex; + UINT16 HorizontalResolution; + UINT16 VerticalResolution; + UINT8 AspectRatio; + UINT8 RefreshRate; + VESA_BIOS_EXTENSIONS_EDID_TIMING TempTiming; + VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *EdidDataBlock; + + EdidDataBlock = (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *) EdidBuffer; + + // + // Check the checksum of EDID data + // + CheckSum = 0; + for (Index = 0; Index < VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE; Index ++) { + CheckSum = (UINT8) (CheckSum + EdidBuffer[Index]); + } + if (CheckSum != 0) { + return FALSE; + } + + ValidNumber = 0; + gBS->SetMem (ValidEdidTiming, sizeof (VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING), 0); + + if ((EdidDataBlock->EstablishedTimings[0] != 0) || + (EdidDataBlock->EstablishedTimings[1] != 0) || + (EdidDataBlock->EstablishedTimings[2] != 0) + ) { + // + // Established timing data + // + TimingBits = EdidDataBlock->EstablishedTimings[0] | + (EdidDataBlock->EstablishedTimings[1] << 8) | + ((EdidDataBlock->EstablishedTimings[2] & 0x80) << 9) ; + for (Index = 0; Index < VESA_BIOS_EXTENSIONS_EDID_ESTABLISHED_TIMING_MAX_NUMBER; Index ++) { + if ((TimingBits & 0x1) != 0) { + DEBUG ((EFI_D_INFO, "Established Timing: %d x %d\n", + mEstablishedEdidTiming[Index].HorizontalResolution, mEstablishedEdidTiming[Index].VerticalResolution)); + ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&mEstablishedEdidTiming[Index]); + ValidNumber ++; + } + TimingBits = TimingBits >> 1; + } + } + + // + // Parse the standard timing data + // + BufferIndex = &EdidDataBlock->StandardTimingIdentification[0]; + for (Index = 0; Index < 8; Index ++) { + // + // Check if this is a valid Standard Timing entry + // VESA documents unused fields should be set to 01h + // + if ((BufferIndex[0] != 0x1) && (BufferIndex[1] != 0x1)){ + // + // A valid Standard Timing + // + HorizontalResolution = (UINT16) (BufferIndex[0] * 8 + 248); + AspectRatio = (UINT8) (BufferIndex[1] >> 6); + switch (AspectRatio) { + case 0: + VerticalResolution = (UINT16) (HorizontalResolution / 16 * 10); + break; + case 1: + VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3); + break; + case 2: + VerticalResolution = (UINT16) (HorizontalResolution / 5 * 4); + break; + case 3: + VerticalResolution = (UINT16) (HorizontalResolution / 16 * 9); + break; + default: + VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3); + break; + } + RefreshRate = (UINT8) ((BufferIndex[1] & 0x1f) + 60); + DEBUG ((EFI_D_INFO, "Standard Timing: %d x %d\n", HorizontalResolution, VerticalResolution)); + TempTiming.HorizontalResolution = HorizontalResolution; + TempTiming.VerticalResolution = VerticalResolution; + TempTiming.RefreshRate = RefreshRate; + ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&TempTiming); + ValidNumber ++; + } + BufferIndex += 2; + } + + // + // Parse the Detailed Timing data + // + BufferIndex = &EdidDataBlock->DetailedTimingDescriptions[0]; + for (Index = 0; Index < 4; Index ++, BufferIndex += VESA_BIOS_EXTENSIONS_DETAILED_TIMING_EACH_DESCRIPTOR_SIZE) { + if ((BufferIndex[0] == 0x0) && (BufferIndex[1] == 0x0)) { + // + // Check if this is a valid Detailed Timing Descriptor + // If first 2 bytes are zero, it is monitor descriptor other than detailed timing descriptor + // + continue; + } + // + // Calculate Horizontal and Vertical resolution + // + TempTiming.HorizontalResolution = ((UINT16)(BufferIndex[4] & 0xF0) << 4) | (BufferIndex[2]); + TempTiming.VerticalResolution = ((UINT16)(BufferIndex[7] & 0xF0) << 4) | (BufferIndex[5]); + DEBUG ((EFI_D_INFO, "Detailed Timing %d: %d x %d\n", + Index, TempTiming.HorizontalResolution, TempTiming.VerticalResolution)); + ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&TempTiming); + ValidNumber ++; + } + + ValidEdidTiming->ValidNumber = ValidNumber; + return TRUE; +} + + +/** + Search a specified Timing in all the valid EDID timings. + + @param ValidEdidTiming All valid EDID timing information. + @param EdidTiming The Timing to search for. + + @retval TRUE Found. + @retval FALSE Not found. + +**/ +BOOLEAN +SearchEdidTiming ( + VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING *ValidEdidTiming, + VESA_BIOS_EXTENSIONS_EDID_TIMING *EdidTiming + ) +{ + UINT32 Index; + UINT32 Key; + + Key = CalculateEdidKey (EdidTiming); + + for (Index = 0; Index < ValidEdidTiming->ValidNumber; Index ++) { + if (Key == ValidEdidTiming->Key[Index]) { + return TRUE; + } + } + + return FALSE; +} + +/** + Check if all video child handles have been uninstalled. + + @param Controller Video controller handle + + @return TRUE Child handles exist. + @return FALSE All video child handles have been uninstalled. + +**/ +BOOLEAN +HasChildHandle ( + IN EFI_HANDLE Controller + ) +{ + UINTN Index; + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer; + UINTN EntryCount; + BOOLEAN HasChild; + + EntryCount = 0; + HasChild = FALSE; + gBS->OpenProtocolInformation ( + Controller, + &gEfiPciIoProtocolGuid, + &OpenInfoBuffer, + &EntryCount + ); + for (Index = 0; Index < EntryCount; Index++) { + if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) { + HasChild = TRUE; + } + } + + return HasChild; +} + +/** + Check for VBE device. + + @param BiosVideoPrivate Pointer to BIOS_VIDEO_DEV structure + + @retval EFI_SUCCESS VBE device found + +**/ +EFI_STATUS +BiosVideoCheckForVbe ( + IN OUT BIOS_VIDEO_DEV *BiosVideoPrivate + ) +{ + EFI_STATUS Status; + EFI_IA32_REGISTER_SET Regs; + UINT16 *ModeNumberPtr; + UINT16 VbeModeNumber; + BOOLEAN ModeFound; + BOOLEAN EdidFound; + BIOS_VIDEO_MODE_DATA *ModeBuffer; + BIOS_VIDEO_MODE_DATA *CurrentModeData; + UINTN PreferMode; + UINTN ModeNumber; + VESA_BIOS_EXTENSIONS_EDID_TIMING Timing; + VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING ValidEdidTiming; + EFI_EDID_OVERRIDE_PROTOCOL *EdidOverride; + UINT32 EdidAttributes; + BOOLEAN EdidOverrideFound; + UINTN EdidOverrideDataSize; + UINT8 *EdidOverrideDataBlock; + UINTN EdidActiveDataSize; + UINT8 *EdidActiveDataBlock; + UINT32 HighestHorizontalResolution; + UINT32 HighestVerticalResolution; + UINTN HighestResolutionMode; + + EdidFound = TRUE; + EdidOverrideFound = FALSE; + EdidOverrideDataBlock = NULL; + EdidActiveDataSize = 0; + EdidActiveDataBlock = NULL; + HighestHorizontalResolution = 0; + HighestVerticalResolution = 0; + HighestResolutionMode = 0; + + // + // Allocate buffer under 1MB for VBE data structures + // + BiosVideoPrivate->NumberOfPagesBelow1MB = EFI_SIZE_TO_PAGES ( + sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK) + + sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK) + + sizeof (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK) + + sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK) + ); + + BiosVideoPrivate->PagesBelow1MB = 0x00100000 - 1; + + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiBootServicesData, + BiosVideoPrivate->NumberOfPagesBelow1MB, + &BiosVideoPrivate->PagesBelow1MB + ); + if (EFI_ERROR (Status)) { + return Status; + } + + ZeroMem (&ValidEdidTiming, sizeof (VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING)); + + // + // Fill in the VBE related data structures + // + BiosVideoPrivate->VbeInformationBlock = (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK *) (UINTN) (BiosVideoPrivate->PagesBelow1MB); + BiosVideoPrivate->VbeModeInformationBlock = (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK *) (BiosVideoPrivate->VbeInformationBlock + 1); + BiosVideoPrivate->VbeEdidDataBlock = (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *) (BiosVideoPrivate->VbeModeInformationBlock + 1); + BiosVideoPrivate->VbeCrtcInformationBlock = (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK *) (BiosVideoPrivate->VbeEdidDataBlock + 1); + BiosVideoPrivate->VbeSaveRestorePages = 0; + BiosVideoPrivate->VbeSaveRestoreBuffer = 0; + + // + // Test to see if the Video Adapter is compliant with VBE 3.0 + // + gBS->SetMem (&Regs, sizeof (Regs), 0); + Regs.X.AX = VESA_BIOS_EXTENSIONS_RETURN_CONTROLLER_INFORMATION; + gBS->SetMem (BiosVideoPrivate->VbeInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK), 0); + BiosVideoPrivate->VbeInformationBlock->VESASignature = VESA_BIOS_EXTENSIONS_VBE2_SIGNATURE; + Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeInformationBlock); + Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeInformationBlock); + + BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs); + + Status = EFI_DEVICE_ERROR; + + // + // See if the VESA call succeeded + // + if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) { + return Status; + } + // + // Check for 'VESA' signature + // + if (BiosVideoPrivate->VbeInformationBlock->VESASignature != VESA_BIOS_EXTENSIONS_VESA_SIGNATURE) { + return Status; + } + // + // Check to see if this is VBE 2.0 or higher + // + if (BiosVideoPrivate->VbeInformationBlock->VESAVersion < VESA_BIOS_EXTENSIONS_VERSION_2_0) { + return Status; + } + + EdidFound = FALSE; + EdidAttributes = 0xff; + EdidOverrideDataSize = 0; + + // + // Find EDID Override protocol firstly, this protocol is installed by platform if needed. + // + Status = gBS->LocateProtocol ( + &gEfiEdidOverrideProtocolGuid, + NULL, + (VOID **) &EdidOverride + ); + if (!EFI_ERROR (Status)) { + // + // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow + // + EdidOverrideDataBlock = AllocatePool (VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE * 2); + if (NULL == EdidOverrideDataBlock) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + Status = EdidOverride->GetEdid ( + EdidOverride, + BiosVideoPrivate->Handle, + &EdidAttributes, + &EdidOverrideDataSize, + (UINT8 **) &EdidOverrideDataBlock + ); + if (!EFI_ERROR (Status) && + EdidAttributes == 0 && + EdidOverrideDataSize != 0) { + // + // Succeeded to get EDID Override Data + // + EdidOverrideFound = TRUE; + } + } + + if (!EdidOverrideFound || EdidAttributes == EFI_EDID_OVERRIDE_DONT_OVERRIDE) { + // + // If EDID Override data doesn't exist or EFI_EDID_OVERRIDE_DONT_OVERRIDE returned, + // read EDID information through INT10 call + // + + gBS->SetMem (&Regs, sizeof (Regs), 0); + Regs.X.AX = VESA_BIOS_EXTENSIONS_EDID; + Regs.X.BX = 1; + Regs.X.CX = 0; + Regs.X.DX = 0; + Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeEdidDataBlock); + Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeEdidDataBlock); + + BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs); + // + // See if the VESA call succeeded + // + if (Regs.X.AX == VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) { + // + // Set EDID Discovered Data + // + BiosVideoPrivate->EdidDiscovered.SizeOfEdid = VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE; + BiosVideoPrivate->EdidDiscovered.Edid = (UINT8 *) AllocateCopyPool ( + VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE, + BiosVideoPrivate->VbeEdidDataBlock + ); + + if (NULL == BiosVideoPrivate->EdidDiscovered.Edid) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + EdidFound = TRUE; + } + } + + if (EdidFound) { + EdidActiveDataSize = VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE; + EdidActiveDataBlock = BiosVideoPrivate->EdidDiscovered.Edid; + } else if (EdidOverrideFound) { + EdidActiveDataSize = EdidOverrideDataSize; + EdidActiveDataBlock = EdidOverrideDataBlock; + EdidFound = TRUE; + } + + if (EdidFound) { + // + // Parse EDID data structure to retrieve modes supported by monitor + // + if (ParseEdidData ((UINT8 *) EdidActiveDataBlock, &ValidEdidTiming)) { + // + // Copy EDID Override Data to EDID Active Data + // + BiosVideoPrivate->EdidActive.SizeOfEdid = (UINT32) EdidActiveDataSize; + BiosVideoPrivate->EdidActive.Edid = (UINT8 *) AllocateCopyPool ( + EdidActiveDataSize, + EdidActiveDataBlock + ); + if (NULL == BiosVideoPrivate->EdidActive.Edid) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + } + } else { + BiosVideoPrivate->EdidActive.SizeOfEdid = 0; + BiosVideoPrivate->EdidActive.Edid = NULL; + EdidFound = FALSE; + } + + // + // Walk through the mode list to see if there is at least one mode the is compatible with the EDID mode + // + ModeNumberPtr = (UINT16 *) + ( + (((UINTN) BiosVideoPrivate->VbeInformationBlock->VideoModePtr & 0xffff0000) >> 12) | + ((UINTN) BiosVideoPrivate->VbeInformationBlock->VideoModePtr & 0x0000ffff) + ); + + PreferMode = 0; + ModeNumber = 0; + + // + // ModeNumberPtr may be not 16-byte aligned, so ReadUnaligned16 is used to access the buffer pointed by ModeNumberPtr. + // + for (VbeModeNumber = ReadUnaligned16 (ModeNumberPtr); + VbeModeNumber != VESA_BIOS_EXTENSIONS_END_OF_MODE_LIST; + VbeModeNumber = ReadUnaligned16 (++ModeNumberPtr)) { + // + // Make sure this is a mode number defined by the VESA VBE specification. If it isn'tm then skip this mode number. + // + if ((VbeModeNumber & VESA_BIOS_EXTENSIONS_MODE_NUMBER_VESA) == 0) { + continue; + } + // + // Get the information about the mode + // + gBS->SetMem (&Regs, sizeof (Regs), 0); + Regs.X.AX = VESA_BIOS_EXTENSIONS_RETURN_MODE_INFORMATION; + Regs.X.CX = VbeModeNumber; + gBS->SetMem (BiosVideoPrivate->VbeModeInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK), 0); + Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeModeInformationBlock); + Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeModeInformationBlock); + + BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs); + + // + // See if the call succeeded. If it didn't, then try the next mode. + // + if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) { + continue; + } + // + // See if the mode supports color. If it doesn't then try the next mode. + // + if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_COLOR) == 0) { + continue; + } + // + // See if the mode supports graphics. If it doesn't then try the next mode. + // + if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_GRAPHICS) == 0) { + continue; + } + // + // See if the mode supports a linear frame buffer. If it doesn't then try the next mode. + // + if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER) == 0) { + continue; + } + // + // See if the mode supports 32 bit color. If it doesn't then try the next mode. + // 32 bit mode can be implemented by 24 Bits Per Pixels. Also make sure the + // number of bits per pixel is a multiple of 8 or more than 32 bits per pixel + // + if (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel < 24) { + continue; + } + + if (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel > 32) { + continue; + } + + if ((BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel % 8) != 0) { + continue; + } + // + // See if the physical base pointer for the linear mode is valid. If it isn't then try the next mode. + // + if (BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr == 0) { + continue; + } + + DEBUG ((EFI_D_INFO, "Video Controller Mode 0x%x: %d x %d\n", + VbeModeNumber, BiosVideoPrivate->VbeModeInformationBlock->XResolution, BiosVideoPrivate->VbeModeInformationBlock->YResolution)); + + if (EdidFound && (ValidEdidTiming.ValidNumber > 0)) { + // + // EDID exist, check whether this mode match with any mode in EDID + // + Timing.HorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution; + Timing.VerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution; + if (!SearchEdidTiming (&ValidEdidTiming, &Timing)) { + // + // When EDID comes from INT10 call, EDID does not include 800x600, 640x480 and 1024x768, + // but INT10 can support these modes, we add them into GOP mode. + // + if ((BiosVideoPrivate->EdidDiscovered.SizeOfEdid != 0) && + !((Timing.HorizontalResolution) == 1024 && (Timing.VerticalResolution == 768)) && + !((Timing.HorizontalResolution) == 800 && (Timing.VerticalResolution == 600)) && + !((Timing.HorizontalResolution) == 640 && (Timing.VerticalResolution == 480))) { + continue; + } + } + } + + // + // Select a reasonable mode to be set for current display mode + // + ModeFound = FALSE; + + if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 1024 && + BiosVideoPrivate->VbeModeInformationBlock->YResolution == 768 + ) { + ModeFound = TRUE; + } + if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 800 && + BiosVideoPrivate->VbeModeInformationBlock->YResolution == 600 + ) { + ModeFound = TRUE; + PreferMode = ModeNumber; + } + if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 640 && + BiosVideoPrivate->VbeModeInformationBlock->YResolution == 480 + ) { + ModeFound = TRUE; + } + + if ((!EdidFound) && (!ModeFound)) { + // + // When no EDID exist, only select three possible resolutions, i.e. 1024x768, 800x600, 640x480 + // + continue; + } + + // + // Record the highest resolution mode to set later + // + if ((BiosVideoPrivate->VbeModeInformationBlock->XResolution > HighestHorizontalResolution) || + ((BiosVideoPrivate->VbeModeInformationBlock->XResolution == HighestHorizontalResolution) && + (BiosVideoPrivate->VbeModeInformationBlock->YResolution > HighestVerticalResolution))) { + HighestHorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution; + HighestVerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution; + HighestResolutionMode = ModeNumber; + } + + // + // Add mode to the list of available modes + // + ModeNumber ++; + ModeBuffer = (BIOS_VIDEO_MODE_DATA *) AllocatePool ( + ModeNumber * sizeof (BIOS_VIDEO_MODE_DATA) + ); + if (NULL == ModeBuffer) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + if (ModeNumber > 1) { + CopyMem ( + ModeBuffer, + BiosVideoPrivate->ModeData, + (ModeNumber - 1) * sizeof (BIOS_VIDEO_MODE_DATA) + ); + } + + if (BiosVideoPrivate->ModeData != NULL) { + FreePool (BiosVideoPrivate->ModeData); + } + + CurrentModeData = &ModeBuffer[ModeNumber - 1]; + CurrentModeData->VbeModeNumber = VbeModeNumber; + if (BiosVideoPrivate->VbeInformationBlock->VESAVersion >= VESA_BIOS_EXTENSIONS_VERSION_3_0) { + CurrentModeData->BytesPerScanLine = BiosVideoPrivate->VbeModeInformationBlock->LinBytesPerScanLine; + CurrentModeData->Red.Position = BiosVideoPrivate->VbeModeInformationBlock->LinRedFieldPosition; + CurrentModeData->Red.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinRedMaskSize) - 1); + CurrentModeData->Blue.Position = BiosVideoPrivate->VbeModeInformationBlock->LinBlueFieldPosition; + CurrentModeData->Blue.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinBlueMaskSize) - 1); + CurrentModeData->Green.Position = BiosVideoPrivate->VbeModeInformationBlock->LinGreenFieldPosition; + CurrentModeData->Green.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinGreenMaskSize) - 1); + CurrentModeData->Reserved.Position = BiosVideoPrivate->VbeModeInformationBlock->LinRsvdFieldPosition; + CurrentModeData->Reserved.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinRsvdMaskSize) - 1); + } else { + CurrentModeData->BytesPerScanLine = BiosVideoPrivate->VbeModeInformationBlock->BytesPerScanLine; + CurrentModeData->Red.Position = BiosVideoPrivate->VbeModeInformationBlock->RedFieldPosition; + CurrentModeData->Red.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->RedMaskSize) - 1); + CurrentModeData->Blue.Position = BiosVideoPrivate->VbeModeInformationBlock->BlueFieldPosition; + CurrentModeData->Blue.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->BlueMaskSize) - 1); + CurrentModeData->Green.Position = BiosVideoPrivate->VbeModeInformationBlock->GreenFieldPosition; + CurrentModeData->Green.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->GreenMaskSize) - 1); + CurrentModeData->Reserved.Position = BiosVideoPrivate->VbeModeInformationBlock->RsvdFieldPosition; + CurrentModeData->Reserved.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->RsvdMaskSize) - 1); + } + + CurrentModeData->PixelFormat = PixelBitMask; + if ((BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel == 32) && + (CurrentModeData->Red.Mask == 0xff) && (CurrentModeData->Green.Mask == 0xff) && (CurrentModeData->Blue.Mask == 0xff)) { + if ((CurrentModeData->Red.Position == 0) && (CurrentModeData->Green.Position == 8) && (CurrentModeData->Blue.Position == 16)) { + CurrentModeData->PixelFormat = PixelRedGreenBlueReserved8BitPerColor; + } else if ((CurrentModeData->Blue.Position == 0) && (CurrentModeData->Green.Position == 8) && (CurrentModeData->Red.Position == 16)) { + CurrentModeData->PixelFormat = PixelBlueGreenRedReserved8BitPerColor; + } + } + + CurrentModeData->PixelBitMask.RedMask = ((UINT32) CurrentModeData->Red.Mask) << CurrentModeData->Red.Position; + CurrentModeData->PixelBitMask.GreenMask = ((UINT32) CurrentModeData->Green.Mask) << CurrentModeData->Green.Position; + CurrentModeData->PixelBitMask.BlueMask = ((UINT32) CurrentModeData->Blue.Mask) << CurrentModeData->Blue.Position; + CurrentModeData->PixelBitMask.ReservedMask = ((UINT32) CurrentModeData->Reserved.Mask) << CurrentModeData->Reserved.Position; + + CurrentModeData->LinearFrameBuffer = (VOID *) (UINTN)BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr; + CurrentModeData->HorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution; + CurrentModeData->VerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution; + + CurrentModeData->BitsPerPixel = BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel; + CurrentModeData->FrameBufferSize = CurrentModeData->BytesPerScanLine * CurrentModeData->VerticalResolution; + // + // Make sure the FrameBufferSize does not exceed the max available frame buffer size reported by VEB. + // + ASSERT (CurrentModeData->FrameBufferSize <= ((UINT32)BiosVideoPrivate->VbeInformationBlock->TotalMemory * 64 * 1024)); + + BiosVideoPrivate->ModeData = ModeBuffer; + } + // + // Check to see if we found any modes that are compatible with GRAPHICS OUTPUT + // + if (ModeNumber == 0) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + + // + // Assign Gop's Blt function + // + BiosVideoPrivate->GraphicsOutput.Blt = BiosVideoGraphicsOutputVbeBlt; + + BiosVideoPrivate->GraphicsOutput.Mode->MaxMode = (UINT32) ModeNumber; + // + // Current mode is unknow till now, set it to an invalid mode. + // + BiosVideoPrivate->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER; + + // + // Find the best mode to initialize + // + if ((PcdGet32 (PcdVideoHorizontalResolution) == 0x0) || (PcdGet32 (PcdVideoVerticalResolution) == 0x0)) { + DEBUG_CODE ( + BIOS_VIDEO_MODE_DATA *ModeData; + ModeData = &BiosVideoPrivate->ModeData[HighestResolutionMode]; + DEBUG ((EFI_D_INFO, "BiosVideo set highest resolution %d x %d\n", + ModeData->HorizontalResolution, ModeData->VerticalResolution)); + ); + PreferMode = HighestResolutionMode; + } + Status = BiosVideoGraphicsOutputSetMode (&BiosVideoPrivate->GraphicsOutput, (UINT32) PreferMode); + if (EFI_ERROR (Status)) { + for (PreferMode = 0; PreferMode < ModeNumber; PreferMode ++) { + Status = BiosVideoGraphicsOutputSetMode ( + &BiosVideoPrivate->GraphicsOutput, + (UINT32) PreferMode + ); + if (!EFI_ERROR (Status)) { + break; + } + } + if (PreferMode == ModeNumber) { + // + // None mode is set successfully. + // + goto Done; + } + } + +Done: + // + // If there was an error, then free the mode structure + // + if (EFI_ERROR (Status)) { + if (BiosVideoPrivate->ModeData != NULL) { + FreePool (BiosVideoPrivate->ModeData); + BiosVideoPrivate->ModeData = NULL; + BiosVideoPrivate->MaxMode = 0; + } + if (EdidOverrideDataBlock != NULL) { + FreePool (EdidOverrideDataBlock); + } + } + + return Status; +} + + +/** + Check for VGA device. + + @param BiosVideoPrivate Pointer to BIOS_VIDEO_DEV structure + + @retval EFI_SUCCESS Standard VGA device found + +**/ +EFI_STATUS +BiosVideoCheckForVga ( + IN OUT BIOS_VIDEO_DEV *BiosVideoPrivate + ) +{ + EFI_STATUS Status; + BIOS_VIDEO_MODE_DATA *ModeBuffer; + + Status = EFI_UNSUPPORTED; + + // + // Assign Gop's Blt function + // + BiosVideoPrivate->GraphicsOutput.Blt = BiosVideoGraphicsOutputVgaBlt; + + // + // Add mode to the list of available modes + // caller should guarantee that Mode has been allocated. + // + ASSERT (BiosVideoPrivate->GraphicsOutput.Mode != NULL); + BiosVideoPrivate->GraphicsOutput.Mode->MaxMode = 1; + + ModeBuffer = (BIOS_VIDEO_MODE_DATA *) AllocatePool ( + sizeof (BIOS_VIDEO_MODE_DATA) + ); + if (NULL == ModeBuffer) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + ModeBuffer->VbeModeNumber = 0x0012; + ModeBuffer->BytesPerScanLine = 640; + ModeBuffer->LinearFrameBuffer = (VOID *) (UINTN) (0xa0000); + ModeBuffer->HorizontalResolution = 640; + ModeBuffer->VerticalResolution = 480; + ModeBuffer->PixelFormat = PixelBltOnly; + ModeBuffer->BitsPerPixel = 8; + ModeBuffer->ColorDepth = 32; + ModeBuffer->RefreshRate = 60; + + BiosVideoPrivate->ModeData = ModeBuffer; + + // + // Test to see if the Video Adapter support the 640x480 16 color mode + // + BiosVideoPrivate->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER; + Status = BiosVideoGraphicsOutputSetMode (&BiosVideoPrivate->GraphicsOutput, 0); + +Done: + // + // If there was an error, then free the mode structure + // + if (EFI_ERROR (Status)) { + if (BiosVideoPrivate->ModeData != NULL) { + FreePool (BiosVideoPrivate->ModeData); + BiosVideoPrivate->ModeData = NULL; + } + if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) { + if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) { + FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info); + BiosVideoPrivate->GraphicsOutput.Mode->Info = NULL; + } + FreePool (BiosVideoPrivate->GraphicsOutput.Mode); + BiosVideoPrivate->GraphicsOutput.Mode = NULL; + } + } + return Status; +} + +// +// Graphics Output Protocol Member Functions for VESA BIOS Extensions +// + +/** + Graphics Output protocol interface to get video mode. + + @param This Protocol instance pointer. + @param ModeNumber The mode number to return information on. + @param SizeOfInfo A pointer to the size, in bytes, of the Info + buffer. + @param Info Caller allocated buffer that returns information + about ModeNumber. + + @retval EFI_SUCCESS Mode information returned. + @retval EFI_DEVICE_ERROR A hardware error occurred trying to retrieve the + video mode. + @retval EFI_NOT_STARTED Video display is not initialized. Call SetMode () + @retval EFI_INVALID_PARAMETER One of the input args was NULL. + +**/ +EFI_STATUS +EFIAPI +BiosVideoGraphicsOutputQueryMode ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN UINT32 ModeNumber, + OUT UINTN *SizeOfInfo, + OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info + ) +{ + BIOS_VIDEO_DEV *BiosVideoPrivate; + BIOS_VIDEO_MODE_DATA *ModeData; + + BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This); + + if (BiosVideoPrivate->HardwareNeedsStarting) { + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_OUTPUT_ERROR, + BiosVideoPrivate->GopDevicePath + ); + return EFI_NOT_STARTED; + } + + if (This == NULL || Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) { + return EFI_INVALID_PARAMETER; + } + + *Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) AllocatePool ( + sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION) + ); + if (NULL == *Info) { + return EFI_OUT_OF_RESOURCES; + } + + *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); + + ModeData = &BiosVideoPrivate->ModeData[ModeNumber]; + (*Info)->Version = 0; + (*Info)->HorizontalResolution = ModeData->HorizontalResolution; + (*Info)->VerticalResolution = ModeData->VerticalResolution; + (*Info)->PixelFormat = ModeData->PixelFormat; + CopyMem (&((*Info)->PixelInformation), &(ModeData->PixelBitMask), sizeof(ModeData->PixelBitMask)); + + (*Info)->PixelsPerScanLine = (ModeData->BytesPerScanLine * 8) / ModeData->BitsPerPixel; + + return EFI_SUCCESS; +} + +/** + Worker function to set video mode. + + @param BiosVideoPrivate Instance of BIOS_VIDEO_DEV. + @param ModeData The mode data to be set. + @param DevicePath Pointer to Device Path Protocol. + + @retval EFI_SUCCESS Graphics mode was changed. + @retval EFI_DEVICE_ERROR The device had an error and could not complete the + request. + @retval EFI_UNSUPPORTED ModeNumber is not supported by this device. + +**/ +EFI_STATUS +BiosVideoSetModeWorker ( + IN BIOS_VIDEO_DEV *BiosVideoPrivate, + IN BIOS_VIDEO_MODE_DATA *ModeData, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_STATUS Status; + EFI_IA32_REGISTER_SET Regs; + + if (BiosVideoPrivate->LineBuffer != NULL) { + FreePool (BiosVideoPrivate->LineBuffer); + } + + if (BiosVideoPrivate->VgaFrameBuffer != NULL) { + FreePool (BiosVideoPrivate->VgaFrameBuffer); + } + + if (BiosVideoPrivate->VbeFrameBuffer != NULL) { + FreePool (BiosVideoPrivate->VbeFrameBuffer); + } + + BiosVideoPrivate->LineBuffer = (UINT8 *) AllocatePool ( + ModeData->BytesPerScanLine + ); + if (NULL == BiosVideoPrivate->LineBuffer) { + return EFI_OUT_OF_RESOURCES; + } + // + // Clear all registers + // + ZeroMem (&Regs, sizeof (Regs)); + + if (ModeData->VbeModeNumber < 0x100) { + // + // Allocate a working buffer for BLT operations to the VGA frame buffer + // + BiosVideoPrivate->VgaFrameBuffer = (UINT8 *) AllocatePool (4 * 480 * 80); + if (NULL == BiosVideoPrivate->VgaFrameBuffer) { + return EFI_OUT_OF_RESOURCES; + } + // + // Set VGA Mode + // + Regs.X.AX = ModeData->VbeModeNumber; + BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs); + + } else { + // + // Allocate a working buffer for BLT operations to the VBE frame buffer + // + BiosVideoPrivate->VbeFrameBuffer = + (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) AllocatePool ( + ModeData->BytesPerScanLine * ModeData->VerticalResolution + ); + if (NULL == BiosVideoPrivate->VbeFrameBuffer) { + return EFI_OUT_OF_RESOURCES; + } + // + // Set VBE mode + // + Regs.X.AX = VESA_BIOS_EXTENSIONS_SET_MODE; + Regs.X.BX = (UINT16) (ModeData->VbeModeNumber | VESA_BIOS_EXTENSIONS_MODE_NUMBER_LINEAR_FRAME_BUFFER); + ZeroMem (BiosVideoPrivate->VbeCrtcInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK)); + Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeCrtcInformationBlock); + Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeCrtcInformationBlock); + BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs); + + // + // Check to see if the call succeeded + // + if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) { + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_OUTPUT_ERROR, + DevicePath + ); + return EFI_DEVICE_ERROR; + } + // + // Initialize the state of the VbeFrameBuffer + // + Status = BiosVideoPrivate->PciIo->Mem.Read ( + BiosVideoPrivate->PciIo, + EfiPciIoWidthUint32, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) (UINTN) ModeData->LinearFrameBuffer, + (ModeData->BytesPerScanLine * ModeData->VerticalResolution) >> 2, + BiosVideoPrivate->VbeFrameBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + + return EFI_SUCCESS; +} + +/** + Graphics Output protocol interface to set video mode. + + @param This Protocol instance pointer. + @param ModeNumber The mode number to be set. + + @retval EFI_SUCCESS Graphics mode was changed. + @retval EFI_DEVICE_ERROR The device had an error and could not complete the + request. + @retval EFI_UNSUPPORTED ModeNumber is not supported by this device. + +**/ +EFI_STATUS +EFIAPI +BiosVideoGraphicsOutputSetMode ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This, + IN UINT32 ModeNumber + ) +{ + EFI_STATUS Status; + BIOS_VIDEO_DEV *BiosVideoPrivate; + BIOS_VIDEO_MODE_DATA *ModeData; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This); + + ModeData = &BiosVideoPrivate->ModeData[ModeNumber]; + + if (ModeNumber >= This->Mode->MaxMode) { + return EFI_UNSUPPORTED; + } + + if (ModeNumber == This->Mode->Mode) { + // + // Clear screen to black + // + ZeroMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + BiosVideoGraphicsOutputVbeBlt ( + This, + &Background, + EfiBltVideoFill, + 0, + 0, + 0, + 0, + ModeData->HorizontalResolution, + ModeData->VerticalResolution, + 0 + ); + return EFI_SUCCESS; + } + + Status = BiosVideoSetModeWorker (BiosVideoPrivate, ModeData, BiosVideoPrivate->GopDevicePath); + if (EFI_ERROR (Status)) { + return Status; + } + + This->Mode->Mode = ModeNumber; + This->Mode->Info->Version = 0; + This->Mode->Info->HorizontalResolution = ModeData->HorizontalResolution; + This->Mode->Info->VerticalResolution = ModeData->VerticalResolution; + This->Mode->Info->PixelFormat = ModeData->PixelFormat; + CopyMem (&(This->Mode->Info->PixelInformation), &(ModeData->PixelBitMask), sizeof (ModeData->PixelBitMask)); + This->Mode->Info->PixelsPerScanLine = (ModeData->BytesPerScanLine * 8) / ModeData->BitsPerPixel; + This->Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); + This->Mode->FrameBufferSize = ModeData->FrameBufferSize; + This->Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) ModeData->LinearFrameBuffer; + + BiosVideoPrivate->HardwareNeedsStarting = FALSE; + + return EFI_SUCCESS; +} + +/** + Update physical frame buffer, copy 4 bytes block, then copy remaining bytes. + + @param PciIo The pointer of EFI_PCI_IO_PROTOCOL + @param VbeBuffer The data to transfer to screen + @param MemAddress Physical frame buffer base address + @param DestinationX The X coordinate of the destination for BltOperation + @param DestinationY The Y coordinate of the destination for BltOperation + @param TotalBytes The total bytes of copy + @param VbePixelWidth Bytes per pixel + @param BytesPerScanLine Bytes per scan line + +**/ +VOID +CopyVideoBuffer ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 *VbeBuffer, + IN VOID *MemAddress, + IN UINTN DestinationX, + IN UINTN DestinationY, + IN UINTN TotalBytes, + IN UINT32 VbePixelWidth, + IN UINTN BytesPerScanLine + ) +{ + UINTN FrameBufferAddr; + UINTN CopyBlockNum; + UINTN RemainingBytes; + UINTN UnalignedBytes; + EFI_STATUS Status; + + FrameBufferAddr = (UINTN) MemAddress + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth; + + // + // If TotalBytes is less than 4 bytes, only start byte copy. + // + if (TotalBytes < 4) { + Status = PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) FrameBufferAddr, + TotalBytes, + VbeBuffer + ); + ASSERT_EFI_ERROR (Status); + return; + } + + // + // If VbeBuffer is not 4-byte aligned, start byte copy. + // + UnalignedBytes = (4 - ((UINTN) VbeBuffer & 0x3)) & 0x3; + + if (UnalignedBytes != 0) { + Status = PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) FrameBufferAddr, + UnalignedBytes, + VbeBuffer + ); + ASSERT_EFI_ERROR (Status); + FrameBufferAddr += UnalignedBytes; + VbeBuffer += UnalignedBytes; + } + + // + // Calculate 4-byte block count and remaining bytes. + // + CopyBlockNum = (TotalBytes - UnalignedBytes) >> 2; + RemainingBytes = (TotalBytes - UnalignedBytes) & 3; + + // + // Copy 4-byte block and remaining bytes to physical frame buffer. + // + if (CopyBlockNum != 0) { + Status = PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint32, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) FrameBufferAddr, + CopyBlockNum, + VbeBuffer + ); + ASSERT_EFI_ERROR (Status); + } + + if (RemainingBytes != 0) { + FrameBufferAddr += (CopyBlockNum << 2); + VbeBuffer += (CopyBlockNum << 2); + Status = PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) FrameBufferAddr, + RemainingBytes, + VbeBuffer + ); + ASSERT_EFI_ERROR (Status); + } +} + +/** + Worker function to block transfer for VBE device. + + @param BiosVideoPrivate Instance of BIOS_VIDEO_DEV + @param BltBuffer The data to transfer to screen + @param BltOperation The operation to perform + @param SourceX The X coordinate of the source for BltOperation + @param SourceY The Y coordinate of the source for BltOperation + @param DestinationX The X coordinate of the destination for + BltOperation + @param DestinationY The Y coordinate of the destination for + BltOperation + @param Width The width of a rectangle in the blt rectangle in + pixels + @param Height The height of a rectangle in the blt rectangle in + pixels + @param Delta Not used for EfiBltVideoFill and + EfiBltVideoToVideo operation. If a Delta of 0 is + used, the entire BltBuffer will be operated on. If + a subrectangle of the BltBuffer is used, then + Delta represents the number of bytes in a row of + the BltBuffer. + @param Mode Mode data. + + @retval EFI_INVALID_PARAMETER Invalid parameter passed in + @retval EFI_SUCCESS Blt operation success + +**/ +EFI_STATUS +BiosVideoVbeBltWorker ( + IN BIOS_VIDEO_DEV *BiosVideoPrivate, + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, + IN UINTN SourceX, + IN UINTN SourceY, + IN UINTN DestinationX, + IN UINTN DestinationY, + IN UINTN Width, + IN UINTN Height, + IN UINTN Delta, + IN BIOS_VIDEO_MODE_DATA *Mode + ) +{ + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_TPL OriginalTPL; + UINTN DstY; + UINTN SrcY; + UINTN DstX; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt; + VOID *MemAddress; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *VbeFrameBuffer; + UINTN BytesPerScanLine; + UINTN Index; + UINT8 *VbeBuffer; + UINT8 *VbeBuffer1; + UINT8 *BltUint8; + UINT32 VbePixelWidth; + UINT32 Pixel; + UINTN TotalBytes; + + PciIo = BiosVideoPrivate->PciIo; + + VbeFrameBuffer = BiosVideoPrivate->VbeFrameBuffer; + MemAddress = Mode->LinearFrameBuffer; + BytesPerScanLine = Mode->BytesPerScanLine; + VbePixelWidth = Mode->BitsPerPixel / 8; + BltUint8 = (UINT8 *) BltBuffer; + TotalBytes = Width * VbePixelWidth; + + if (((UINTN) BltOperation) >= EfiGraphicsOutputBltOperationMax) { + return EFI_INVALID_PARAMETER; + } + + if (Width == 0 || Height == 0) { + return EFI_INVALID_PARAMETER; + } + // + // We need to fill the Virtual Screen buffer with the blt data. + // The virtual screen is upside down, as the first row is the bootom row of + // the image. + // + if (BltOperation == EfiBltVideoToBltBuffer) { + // + // Video to BltBuffer: Source is Video, destination is BltBuffer + // + if (SourceY + Height > Mode->VerticalResolution) { + return EFI_INVALID_PARAMETER; + } + + if (SourceX + Width > Mode->HorizontalResolution) { + return EFI_INVALID_PARAMETER; + } + } else { + // + // BltBuffer to Video: Source is BltBuffer, destination is Video + // + if (DestinationY + Height > Mode->VerticalResolution) { + return EFI_INVALID_PARAMETER; + } + + if (DestinationX + Width > Mode->HorizontalResolution) { + return EFI_INVALID_PARAMETER; + } + } + // + // If Delta is zero, then the entire BltBuffer is being used, so Delta + // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size, + // the number of bytes in each row can be computed. + // + if (Delta == 0) { + Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL); + } + // + // We have to raise to TPL Notify, so we make an atomic write the frame buffer. + // We would not want a timer based event (Cursor, ...) to come in while we are + // doing this operation. + // + OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY); + + switch (BltOperation) { + case EfiBltVideoToBltBuffer: + for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) { + Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (BltUint8 + DstY * Delta + DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + // + // Shuffle the packed bytes in the hardware buffer to match EFI_GRAPHICS_OUTPUT_BLT_PIXEL + // + VbeBuffer = ((UINT8 *) VbeFrameBuffer + (SrcY * BytesPerScanLine + SourceX * VbePixelWidth)); + for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) { + Pixel = VbeBuffer[0] | VbeBuffer[1] << 8 | VbeBuffer[2] << 16 | VbeBuffer[3] << 24; + Blt->Red = (UINT8) ((Pixel >> Mode->Red.Position) & Mode->Red.Mask); + Blt->Blue = (UINT8) ((Pixel >> Mode->Blue.Position) & Mode->Blue.Mask); + Blt->Green = (UINT8) ((Pixel >> Mode->Green.Position) & Mode->Green.Mask); + Blt->Reserved = 0; + Blt++; + VbeBuffer += VbePixelWidth; + } + + } + break; + + case EfiBltVideoToVideo: + for (Index = 0; Index < Height; Index++) { + if (DestinationY <= SourceY) { + SrcY = SourceY + Index; + DstY = DestinationY + Index; + } else { + SrcY = SourceY + Height - Index - 1; + DstY = DestinationY + Height - Index - 1; + } + + VbeBuffer = ((UINT8 *) VbeFrameBuffer + DstY * BytesPerScanLine + DestinationX * VbePixelWidth); + VbeBuffer1 = ((UINT8 *) VbeFrameBuffer + SrcY * BytesPerScanLine + SourceX * VbePixelWidth); + + gBS->CopyMem ( + VbeBuffer, + VbeBuffer1, + TotalBytes + ); + + // + // Update physical frame buffer. + // + CopyVideoBuffer ( + PciIo, + VbeBuffer, + MemAddress, + DestinationX, + DstY, + TotalBytes, + VbePixelWidth, + BytesPerScanLine + ); + } + break; + + case EfiBltVideoFill: + VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth); + Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) BltUint8; + // + // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer + // + Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) | + ( + (Blt->Green & Mode->Green.Mask) << + Mode->Green.Position + ) | + ((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position); + + for (Index = 0; Index < Width; Index++) { + gBS->CopyMem ( + VbeBuffer, + &Pixel, + VbePixelWidth + ); + VbeBuffer += VbePixelWidth; + } + + VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth); + for (DstY = DestinationY + 1; DstY < (Height + DestinationY); DstY++) { + gBS->CopyMem ( + (VOID *) ((UINTN) VbeFrameBuffer + (DstY * BytesPerScanLine) + DestinationX * VbePixelWidth), + VbeBuffer, + TotalBytes + ); + } + + for (DstY = DestinationY; DstY < (Height + DestinationY); DstY++) { + // + // Update physical frame buffer. + // + CopyVideoBuffer ( + PciIo, + VbeBuffer, + MemAddress, + DestinationX, + DstY, + TotalBytes, + VbePixelWidth, + BytesPerScanLine + ); + } + break; + + case EfiBltBufferToVideo: + for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) { + Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (BltUint8 + (SrcY * Delta) + (SourceX) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); + VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth)); + for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) { + // + // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer + // + Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) | + ((Blt->Green & Mode->Green.Mask) << Mode->Green.Position) | + ((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position); + gBS->CopyMem ( + VbeBuffer, + &Pixel, + VbePixelWidth + ); + Blt++; + VbeBuffer += VbePixelWidth; + } + + VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth)); + + // + // Update physical frame buffer. + // + CopyVideoBuffer ( + PciIo, + VbeBuffer, + MemAddress, + DestinationX, + DstY, + TotalBytes, + VbePixelWidth, + BytesPerScanLine + ); + } + break; + + default: ; + } + + gBS->RestoreTPL (OriginalTPL); + + return EFI_SUCCESS; +} + +/** + Graphics Output protocol instance to block transfer for VBE device. + + @param This Pointer to Graphics Output protocol instance + @param BltBuffer The data to transfer to screen + @param BltOperation The operation to perform + @param SourceX The X coordinate of the source for BltOperation + @param SourceY The Y coordinate of the source for BltOperation + @param DestinationX The X coordinate of the destination for + BltOperation + @param DestinationY The Y coordinate of the destination for + BltOperation + @param Width The width of a rectangle in the blt rectangle in + pixels + @param Height The height of a rectangle in the blt rectangle in + pixels + @param Delta Not used for EfiBltVideoFill and + EfiBltVideoToVideo operation. If a Delta of 0 is + used, the entire BltBuffer will be operated on. If + a subrectangle of the BltBuffer is used, then + Delta represents the number of bytes in a row of + the BltBuffer. + + @retval EFI_INVALID_PARAMETER Invalid parameter passed in + @retval EFI_SUCCESS Blt operation success + +**/ +EFI_STATUS +EFIAPI +BiosVideoGraphicsOutputVbeBlt ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, + IN UINTN SourceX, + IN UINTN SourceY, + IN UINTN DestinationX, + IN UINTN DestinationY, + IN UINTN Width, + IN UINTN Height, + IN UINTN Delta + ) +{ + BIOS_VIDEO_DEV *BiosVideoPrivate; + BIOS_VIDEO_MODE_DATA *Mode; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This); + Mode = &BiosVideoPrivate->ModeData[This->Mode->Mode]; + + return BiosVideoVbeBltWorker ( + BiosVideoPrivate, + BltBuffer, + BltOperation, + SourceX, + SourceY, + DestinationX, + DestinationY, + Width, + Height, + Delta, + Mode + ); +} + +/** + Write graphics controller registers. + + @param PciIo Pointer to PciIo protocol instance of the + controller + @param Address Register address + @param Data Data to be written to register + + @return None + +**/ +VOID +WriteGraphicsController ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINTN Address, + IN UINTN Data + ) +{ + Address = Address | (Data << 8); + PciIo->Io.Write ( + PciIo, + EfiPciIoWidthUint16, + EFI_PCI_IO_PASS_THROUGH_BAR, + VGA_GRAPHICS_CONTROLLER_ADDRESS_REGISTER, + 1, + &Address + ); +} + + +/** + Read the four bit plane of VGA frame buffer. + + @param PciIo Pointer to PciIo protocol instance of the + controller + @param HardwareBuffer Hardware VGA frame buffer address + @param MemoryBuffer Memory buffer address + @param WidthInBytes Number of bytes in a line to read + @param Height Height of the area to read + + @return None + +**/ +VOID +VgaReadBitPlanes ( + EFI_PCI_IO_PROTOCOL *PciIo, + UINT8 *HardwareBuffer, + UINT8 *MemoryBuffer, + UINTN WidthInBytes, + UINTN Height + ) +{ + UINTN BitPlane; + UINTN Rows; + UINTN FrameBufferOffset; + UINT8 *Source; + UINT8 *Destination; + + // + // Program the Mode Register Write mode 0, Read mode 0 + // + WriteGraphicsController ( + PciIo, + VGA_GRAPHICS_CONTROLLER_MODE_REGISTER, + VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_0 + ); + + for (BitPlane = 0, FrameBufferOffset = 0; + BitPlane < VGA_NUMBER_OF_BIT_PLANES; + BitPlane++, FrameBufferOffset += VGA_BYTES_PER_BIT_PLANE + ) { + // + // Program the Read Map Select Register to select the correct bit plane + // + WriteGraphicsController ( + PciIo, + VGA_GRAPHICS_CONTROLLER_READ_MAP_SELECT_REGISTER, + BitPlane + ); + + Source = HardwareBuffer; + Destination = MemoryBuffer + FrameBufferOffset; + + for (Rows = 0; Rows < Height; Rows++, Source += VGA_BYTES_PER_SCAN_LINE, Destination += VGA_BYTES_PER_SCAN_LINE) { + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) (UINTN) Source, + WidthInBytes, + (VOID *) Destination + ); + } + } +} + + +/** + Internal routine to convert VGA color to Grahpics Output color. + + @param MemoryBuffer Buffer containing VGA color + @param CoordinateX The X coordinate of pixel on screen + @param CoordinateY The Y coordinate of pixel on screen + @param BltBuffer Buffer to contain converted Grahpics Output color + + @return None + +**/ +VOID +VgaConvertToGraphicsOutputColor ( + UINT8 *MemoryBuffer, + UINTN CoordinateX, + UINTN CoordinateY, + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer + ) +{ + UINTN Mask; + UINTN Bit; + UINTN Color; + + MemoryBuffer += ((CoordinateY << 6) + (CoordinateY << 4) + (CoordinateX >> 3)); + Mask = mVgaBitMaskTable[CoordinateX & 0x07]; + for (Bit = 0x01, Color = 0; Bit < 0x10; Bit <<= 1, MemoryBuffer += VGA_BYTES_PER_BIT_PLANE) { + if ((*MemoryBuffer & Mask) != 0) { + Color |= Bit; + } + } + + *BltBuffer = mVgaColorToGraphicsOutputColor[Color]; +} + +/** + Internal routine to convert Grahpics Output color to VGA color. + + @param BltBuffer buffer containing Grahpics Output color + + @return Converted VGA color + +**/ +UINT8 +VgaConvertColor ( + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer + ) +{ + UINT8 Color; + + Color = (UINT8) ((BltBuffer->Blue >> 7) | ((BltBuffer->Green >> 6) & 0x02) | ((BltBuffer->Red >> 5) & 0x04)); + if ((BltBuffer->Red + BltBuffer->Green + BltBuffer->Blue) > 0x180) { + Color |= 0x08; + } + + return Color; +} + + +/** + Grahpics Output protocol instance to block transfer for VGA device. + + @param This Pointer to Grahpics Output protocol instance + @param BltBuffer The data to transfer to screen + @param BltOperation The operation to perform + @param SourceX The X coordinate of the source for BltOperation + @param SourceY The Y coordinate of the source for BltOperation + @param DestinationX The X coordinate of the destination for + BltOperation + @param DestinationY The Y coordinate of the destination for + BltOperation + @param Width The width of a rectangle in the blt rectangle in + pixels + @param Height The height of a rectangle in the blt rectangle in + pixels + @param Delta Not used for EfiBltVideoFill and + EfiBltVideoToVideo operation. If a Delta of 0 is + used, the entire BltBuffer will be operated on. If + a subrectangle of the BltBuffer is used, then + Delta represents the number of bytes in a row of + the BltBuffer. + + @retval EFI_INVALID_PARAMETER Invalid parameter passed in + @retval EFI_SUCCESS Blt operation success + +**/ +EFI_STATUS +EFIAPI +BiosVideoGraphicsOutputVgaBlt ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, + IN UINTN SourceX, + IN UINTN SourceY, + IN UINTN DestinationX, + IN UINTN DestinationY, + IN UINTN Width, + IN UINTN Height, + IN UINTN Delta + ) +{ + BIOS_VIDEO_DEV *BiosVideoPrivate; + EFI_TPL OriginalTPL; + UINT8 *MemAddress; + UINTN BytesPerScanLine; + UINTN Bit; + UINTN Index; + UINTN Index1; + UINTN StartAddress; + UINTN Bytes; + UINTN Offset; + UINT8 LeftMask; + UINT8 RightMask; + UINTN Address; + UINTN AddressFix; + UINT8 *Address1; + UINT8 *SourceAddress; + UINT8 *DestinationAddress; + EFI_PCI_IO_PROTOCOL *PciIo; + UINT8 Data; + UINT8 PixelColor; + UINT8 *VgaFrameBuffer; + UINTN SourceOffset; + UINTN SourceWidth; + UINTN Rows; + UINTN Columns; + UINTN CoordinateX; + UINTN CoordinateY; + UINTN CurrentMode; + + if (This == NULL || ((UINTN) BltOperation) >= EfiGraphicsOutputBltOperationMax) { + return EFI_INVALID_PARAMETER; + } + + BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This); + + CurrentMode = This->Mode->Mode; + PciIo = BiosVideoPrivate->PciIo; + MemAddress = BiosVideoPrivate->ModeData[CurrentMode].LinearFrameBuffer; + BytesPerScanLine = BiosVideoPrivate->ModeData[CurrentMode].BytesPerScanLine >> 3; + VgaFrameBuffer = BiosVideoPrivate->VgaFrameBuffer; + + + if (Width == 0 || Height == 0) { + return EFI_INVALID_PARAMETER; + } + // + // We need to fill the Virtual Screen buffer with the blt data. + // The virtual screen is upside down, as the first row is the bootom row of + // the image. + // + if (BltOperation == EfiBltVideoToBltBuffer) { + // + // Video to BltBuffer: Source is Video, destination is BltBuffer + // + if (SourceY + Height > BiosVideoPrivate->ModeData[CurrentMode].VerticalResolution) { + return EFI_INVALID_PARAMETER; + } + + if (SourceX + Width > BiosVideoPrivate->ModeData[CurrentMode].HorizontalResolution) { + return EFI_INVALID_PARAMETER; + } + } else { + // + // BltBuffer to Video: Source is BltBuffer, destination is Video + // + if (DestinationY + Height > BiosVideoPrivate->ModeData[CurrentMode].VerticalResolution) { + return EFI_INVALID_PARAMETER; + } + + if (DestinationX + Width > BiosVideoPrivate->ModeData[CurrentMode].HorizontalResolution) { + return EFI_INVALID_PARAMETER; + } + } + // + // If Delta is zero, then the entire BltBuffer is being used, so Delta + // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size, + // the number of bytes in each row can be computed. + // + if (Delta == 0) { + Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL); + } + // + // We have to raise to TPL Notify, so we make an atomic write the frame buffer. + // We would not want a timer based event (Cursor, ...) to come in while we are + // doing this operation. + // + OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY); + + // + // Compute some values we need for VGA + // + switch (BltOperation) { + case EfiBltVideoToBltBuffer: + + SourceOffset = (SourceY << 6) + (SourceY << 4) + (SourceX >> 3); + SourceWidth = ((SourceX + Width - 1) >> 3) - (SourceX >> 3) + 1; + + // + // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer + // + VgaReadBitPlanes ( + PciIo, + MemAddress + SourceOffset, + VgaFrameBuffer + SourceOffset, + SourceWidth, + Height + ); + + // + // Convert VGA Bit Planes to a Graphics Output 32-bit color value + // + BltBuffer += (DestinationY * (Delta >> 2) + DestinationX); + for (Rows = 0, CoordinateY = SourceY; Rows < Height; Rows++, CoordinateY++, BltBuffer += (Delta >> 2)) { + for (Columns = 0, CoordinateX = SourceX; Columns < Width; Columns++, CoordinateX++, BltBuffer++) { + VgaConvertToGraphicsOutputColor (VgaFrameBuffer, CoordinateX, CoordinateY, BltBuffer); + } + + BltBuffer -= Width; + } + + break; + + case EfiBltVideoToVideo: + // + // Check for an aligned Video to Video operation + // + if ((SourceX & 0x07) == 0x00 && (DestinationX & 0x07) == 0x00 && (Width & 0x07) == 0x00) { + // + // Program the Mode Register Write mode 1, Read mode 0 + // + WriteGraphicsController ( + PciIo, + VGA_GRAPHICS_CONTROLLER_MODE_REGISTER, + VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_1 + ); + + SourceAddress = (UINT8 *) (MemAddress + (SourceY << 6) + (SourceY << 4) + (SourceX >> 3)); + DestinationAddress = (UINT8 *) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3)); + Bytes = Width >> 3; + for (Index = 0, Offset = 0; Index < Height; Index++, Offset += BytesPerScanLine) { + PciIo->CopyMem ( + PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) (UINTN) (DestinationAddress + Offset), + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) (UINTN) (SourceAddress + Offset), + Bytes + ); + } + } else { + SourceOffset = (SourceY << 6) + (SourceY << 4) + (SourceX >> 3); + SourceWidth = ((SourceX + Width - 1) >> 3) - (SourceX >> 3) + 1; + + // + // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer + // + VgaReadBitPlanes ( + PciIo, + MemAddress + SourceOffset, + VgaFrameBuffer + SourceOffset, + SourceWidth, + Height + ); + } + + break; + + case EfiBltVideoFill: + StartAddress = (UINTN) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3)); + Bytes = ((DestinationX + Width - 1) >> 3) - (DestinationX >> 3); + LeftMask = mVgaLeftMaskTable[DestinationX & 0x07]; + RightMask = mVgaRightMaskTable[(DestinationX + Width - 1) & 0x07]; + if (Bytes == 0) { + LeftMask = (UINT8) (LeftMask & RightMask); + RightMask = 0; + } + + if (LeftMask == 0xff) { + StartAddress--; + Bytes++; + LeftMask = 0; + } + + if (RightMask == 0xff) { + Bytes++; + RightMask = 0; + } + + PixelColor = VgaConvertColor (BltBuffer); + + // + // Program the Mode Register Write mode 2, Read mode 0 + // + WriteGraphicsController ( + PciIo, + VGA_GRAPHICS_CONTROLLER_MODE_REGISTER, + VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2 + ); + + // + // Program the Data Rotate/Function Select Register to replace + // + WriteGraphicsController ( + PciIo, + VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER, + VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE + ); + + if (LeftMask != 0) { + // + // Program the BitMask register with the Left column mask + // + WriteGraphicsController ( + PciIo, + VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER, + LeftMask + ); + + for (Index = 0, Address = StartAddress; Index < Height; Index++, Address += BytesPerScanLine) { + // + // Read data from the bit planes into the latches + // + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) (UINTN) Address, + 1, + &Data + ); + // + // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask + // + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) (UINTN) Address, + 1, + &PixelColor + ); + } + } + + if (Bytes > 1) { + // + // Program the BitMask register with the middle column mask of 0xff + // + WriteGraphicsController ( + PciIo, + VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER, + 0xff + ); + + for (Index = 0, Address = StartAddress + 1; Index < Height; Index++, Address += BytesPerScanLine) { + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthFillUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) (UINTN) Address, + Bytes - 1, + &PixelColor + ); + } + } + + if (RightMask != 0) { + // + // Program the BitMask register with the Right column mask + // + WriteGraphicsController ( + PciIo, + VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER, + RightMask + ); + + for (Index = 0, Address = StartAddress + Bytes; Index < Height; Index++, Address += BytesPerScanLine) { + // + // Read data from the bit planes into the latches + // + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) (UINTN) Address, + 1, + &Data + ); + // + // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask + // + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) (UINTN) Address, + 1, + &PixelColor + ); + } + } + break; + + case EfiBltBufferToVideo: + StartAddress = (UINTN) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3)); + LeftMask = mVgaBitMaskTable[DestinationX & 0x07]; + + // + // Program the Mode Register Write mode 2, Read mode 0 + // + WriteGraphicsController ( + PciIo, + VGA_GRAPHICS_CONTROLLER_MODE_REGISTER, + VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2 + ); + + // + // Program the Data Rotate/Function Select Register to replace + // + WriteGraphicsController ( + PciIo, + VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER, + VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE + ); + + for (Index = 0, Address = StartAddress; Index < Height; Index++, Address += BytesPerScanLine) { + for (Index1 = 0; Index1 < Width; Index1++) { + BiosVideoPrivate->LineBuffer[Index1] = VgaConvertColor (&BltBuffer[(SourceY + Index) * (Delta >> 2) + SourceX + Index1]); + } + AddressFix = Address; + + for (Bit = 0; Bit < 8; Bit++) { + // + // Program the BitMask register with the Left column mask + // + WriteGraphicsController ( + PciIo, + VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER, + LeftMask + ); + + for (Index1 = Bit, Address1 = (UINT8 *) AddressFix; Index1 < Width; Index1 += 8, Address1++) { + // + // Read data from the bit planes into the latches + // + PciIo->Mem.Read ( + PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) (UINTN) Address1, + 1, + &Data + ); + + PciIo->Mem.Write ( + PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + (UINT64) (UINTN) Address1, + 1, + &BiosVideoPrivate->LineBuffer[Index1] + ); + } + + LeftMask = (UINT8) (LeftMask >> 1); + if (LeftMask == 0) { + LeftMask = 0x80; + AddressFix++; + } + } + } + + break; + + default: ; + } + + gBS->RestoreTPL (OriginalTPL); + + return EFI_SUCCESS; +} + +// +// VGA Mini Port Protocol Functions +// + +/** + VgaMiniPort protocol interface to set mode. + + @param This Pointer to VgaMiniPort protocol instance + @param ModeNumber The index of the mode + + @retval EFI_UNSUPPORTED The requested mode is not supported + @retval EFI_SUCCESS The requested mode is set successfully + +**/ +EFI_STATUS +EFIAPI +BiosVideoVgaMiniPortSetMode ( + IN EFI_VGA_MINI_PORT_PROTOCOL *This, + IN UINTN ModeNumber + ) +{ + BIOS_VIDEO_DEV *BiosVideoPrivate; + EFI_IA32_REGISTER_SET Regs; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Make sure the ModeNumber is a valid value + // + if (ModeNumber >= This->MaxMode) { + return EFI_UNSUPPORTED; + } + // + // Get the device structure for this device + // + BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (This); + + switch (ModeNumber) { + case 0: + // + // Set the 80x25 Text VGA Mode + // + Regs.H.AH = 0x00; + Regs.H.AL = 0x83; + BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs); + + Regs.H.AH = 0x11; + Regs.H.AL = 0x14; + Regs.H.BL = 0; + BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs); + break; + + case 1: + // + // Set the 80x50 Text VGA Mode + // + Regs.H.AH = 0x00; + Regs.H.AL = 0x83; + BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs); + Regs.H.AH = 0x11; + Regs.H.AL = 0x12; + Regs.H.BL = 0; + BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs); + break; + + default: + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +/** + Event handler for Exit Boot Service. + + @param Event The event that be siganlled when exiting boot service. + @param Context Pointer to instance of BIOS_VIDEO_DEV. + +**/ +VOID +EFIAPI +BiosVideoNotifyExitBootServices ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + BIOS_VIDEO_DEV *BiosVideoPrivate; + EFI_IA32_REGISTER_SET Regs; + + BiosVideoPrivate = (BIOS_VIDEO_DEV *)Context; + + // + // Set the 80x25 Text VGA Mode + // + Regs.H.AH = 0x00; + Regs.H.AL = 0x03; + BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs); + + Regs.H.AH = 0x00; + Regs.H.AL = 0x83; + BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs); + + Regs.H.AH = 0x11; + Regs.H.AL = 0x04; + Regs.H.BL = 0; + BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs); +} + +/** + The user Entry Point for module UefiBiosVideo. The user code starts with this function. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +BiosVideoEntryPoint( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // + // Install driver model protocol(s). + // + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gBiosVideoDriverBinding, + ImageHandle, + &gBiosVideoComponentName, + &gBiosVideoComponentName2 + ); + ASSERT_EFI_ERROR (Status); + + // + // Install Legacy BIOS GUID to mark this driver as a BIOS Thunk Driver + // + return gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gEfiLegacyBiosGuid, + NULL, + NULL + ); +} + diff --git a/OvmfPkg/Csm/BiosThunk/VideoDxe/BiosVideo.h b/OvmfPkg/Csm/BiosThunk/VideoDxe/BiosVideo.h new file mode 100644 index 0000000000..951f4e6f76 --- /dev/null +++ b/OvmfPkg/Csm/BiosThunk/VideoDxe/BiosVideo.h @@ -0,0 +1,532 @@ +/** @file + +Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _BIOS_GRAPHICS_OUTPUT_H_ +#define _BIOS_GRAPHICS_OUTPUT_H_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "VesaBiosExtensions.h" + +// +// Packed format support: The number of bits reserved for each of the colors and the actual +// position of RGB in the frame buffer is specified in the VBE Mode information +// +typedef struct { + UINT8 Position; // Position of the color + UINT8 Mask; // The number of bits expressed as a mask +} BIOS_VIDEO_COLOR_PLACEMENT; + +// +// BIOS Graphics Output Graphical Mode Data +// +typedef struct { + UINT16 VbeModeNumber; + UINT16 BytesPerScanLine; + VOID *LinearFrameBuffer; + UINTN FrameBufferSize; + UINT32 HorizontalResolution; + UINT32 VerticalResolution; + UINT32 ColorDepth; + UINT32 RefreshRate; + UINT32 BitsPerPixel; + BIOS_VIDEO_COLOR_PLACEMENT Red; + BIOS_VIDEO_COLOR_PLACEMENT Green; + BIOS_VIDEO_COLOR_PLACEMENT Blue; + BIOS_VIDEO_COLOR_PLACEMENT Reserved; + EFI_GRAPHICS_PIXEL_FORMAT PixelFormat; + EFI_PIXEL_BITMASK PixelBitMask; +} BIOS_VIDEO_MODE_DATA; + +// +// BIOS video child handle private data Structure +// +#define BIOS_VIDEO_DEV_SIGNATURE SIGNATURE_32 ('B', 'V', 'M', 'p') + +typedef struct { + UINTN Signature; + EFI_HANDLE Handle; + + // + // Consumed Protocols + // + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + + // + // Produced Protocols + // + EFI_GRAPHICS_OUTPUT_PROTOCOL GraphicsOutput; + EFI_EDID_DISCOVERED_PROTOCOL EdidDiscovered; + EFI_EDID_ACTIVE_PROTOCOL EdidActive; + EFI_VGA_MINI_PORT_PROTOCOL VgaMiniPort; + + // + // General fields + // + BOOLEAN VgaCompatible; + BOOLEAN ProduceGraphicsOutput; + + // + // Graphics Output Protocol related fields + // + BOOLEAN HardwareNeedsStarting; + UINTN CurrentMode; + UINTN MaxMode; + BIOS_VIDEO_MODE_DATA *ModeData; + UINT8 *LineBuffer; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *VbeFrameBuffer; + UINT8 *VgaFrameBuffer; + + // + // VESA Bios Extensions related fields + // + UINTN NumberOfPagesBelow1MB; // Number of 4KB pages in PagesBelow1MB + EFI_PHYSICAL_ADDRESS PagesBelow1MB; // Buffer for all VBE Information Blocks + VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK *VbeInformationBlock; // 0x200 bytes. Must be allocated below 1MB + VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK *VbeModeInformationBlock; // 0x100 bytes. Must be allocated below 1MB + VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *VbeEdidDataBlock; // 0x80 bytes. Must be allocated below 1MB + VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK *VbeCrtcInformationBlock; // 59 bytes. Must be allocated below 1MB + UINTN VbeSaveRestorePages; // Number of 4KB pages in VbeSaveRestoreBuffer + EFI_PHYSICAL_ADDRESS VbeSaveRestoreBuffer; // Must be allocated below 1MB + // + // Status code + // + EFI_DEVICE_PATH_PROTOCOL *GopDevicePath; + + EFI_EVENT ExitBootServicesEvent; +} BIOS_VIDEO_DEV; + +#define BIOS_VIDEO_DEV_FROM_PCI_IO_THIS(a) CR (a, BIOS_VIDEO_DEV, PciIo, BIOS_VIDEO_DEV_SIGNATURE) +#define BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS(a) CR (a, BIOS_VIDEO_DEV, GraphicsOutput, BIOS_VIDEO_DEV_SIGNATURE) +#define BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS(a) CR (a, BIOS_VIDEO_DEV, VgaMiniPort, BIOS_VIDEO_DEV_SIGNATURE) + +#define GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER 0xffff + +// +// Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gBiosVideoDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gBiosVideoComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gBiosVideoComponentName2; + +// +// Driver Binding Protocol functions +// + +/** + Supported. + + @param This Pointer to driver binding protocol + @param Controller Controller handle to connect + @param RemainingDevicePath A pointer to the remaining portion of a device + path + + @retval EFI_STATUS EFI_SUCCESS:This controller can be managed by this + driver, Otherwise, this controller cannot be + managed by this driver + +**/ +EFI_STATUS +EFIAPI +BiosVideoDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + + +/** + Install Graphics Output Protocol onto VGA device handles. + + @param This Pointer to driver binding protocol + @param Controller Controller handle to connect + @param RemainingDevicePath A pointer to the remaining portion of a device + path + + @return EFI_STATUS + +**/ +EFI_STATUS +EFIAPI +BiosVideoDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + + +/** + Stop. + + @param This Pointer to driver binding protocol + @param Controller Controller handle to connect + @param NumberOfChildren Number of children handle created by this driver + @param ChildHandleBuffer Buffer containing child handle created + + @retval EFI_SUCCESS Driver disconnected successfully from controller + @retval EFI_UNSUPPORTED Cannot find BIOS_VIDEO_DEV structure + +**/ +EFI_STATUS +EFIAPI +BiosVideoDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +// +// Private worker functions +// + +/** + Check for VBE device. + + @param BiosVideoPrivate Pointer to BIOS_VIDEO_DEV structure + + @retval EFI_SUCCESS VBE device found + +**/ +EFI_STATUS +BiosVideoCheckForVbe ( + IN OUT BIOS_VIDEO_DEV *BiosVideoPrivate + ); + + +/** + Check for VGA device. + + @param BiosVideoPrivate Pointer to BIOS_VIDEO_DEV structure + + @retval EFI_SUCCESS Standard VGA device found + +**/ +EFI_STATUS +BiosVideoCheckForVga ( + IN OUT BIOS_VIDEO_DEV *BiosVideoPrivate + ); + + + + +/** + Release resource for biso video instance. + + @param BiosVideoPrivate Video child device private data structure + +**/ +VOID +BiosVideoDeviceReleaseResource ( + BIOS_VIDEO_DEV *BiosVideoPrivate + ); + +// +// BIOS Graphics Output Protocol functions +// + +/** + Graphics Output protocol interface to get video mode. + + @param This Protocol instance pointer. + @param ModeNumber The mode number to return information on. + @param SizeOfInfo A pointer to the size, in bytes, of the Info + buffer. + @param Info Caller allocated buffer that returns information + about ModeNumber. + + @retval EFI_SUCCESS Mode information returned. + @retval EFI_BUFFER_TOO_SMALL The Info buffer was too small. + @retval EFI_DEVICE_ERROR A hardware error occurred trying to retrieve the + video mode. + @retval EFI_NOT_STARTED Video display is not initialized. Call SetMode () + @retval EFI_INVALID_PARAMETER One of the input args was NULL. + +**/ +EFI_STATUS +EFIAPI +BiosVideoGraphicsOutputQueryMode ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN UINT32 ModeNumber, + OUT UINTN *SizeOfInfo, + OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info + ); + + +/** + Graphics Output protocol interface to set video mode. + + @param This Protocol instance pointer. + @param ModeNumber The mode number to be set. + + @retval EFI_SUCCESS Graphics mode was changed. + @retval EFI_DEVICE_ERROR The device had an error and could not complete the + request. + @retval EFI_UNSUPPORTED ModeNumber is not supported by this device. + +**/ +EFI_STATUS +EFIAPI +BiosVideoGraphicsOutputSetMode ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This, + IN UINT32 ModeNumber + ); + + +/** + Graphics Output protocol instance to block transfer for VBE device. + + @param This Pointer to Graphics Output protocol instance + @param BltBuffer The data to transfer to screen + @param BltOperation The operation to perform + @param SourceX The X coordinate of the source for BltOperation + @param SourceY The Y coordinate of the source for BltOperation + @param DestinationX The X coordinate of the destination for + BltOperation + @param DestinationY The Y coordinate of the destination for + BltOperation + @param Width The width of a rectangle in the blt rectangle in + pixels + @param Height The height of a rectangle in the blt rectangle in + pixels + @param Delta Not used for EfiBltVideoFill and + EfiBltVideoToVideo operation. If a Delta of 0 is + used, the entire BltBuffer will be operated on. If + a subrectangle of the BltBuffer is used, then + Delta represents the number of bytes in a row of + the BltBuffer. + + @retval EFI_INVALID_PARAMETER Invalid parameter passed in + @retval EFI_SUCCESS Blt operation success + +**/ +EFI_STATUS +EFIAPI +BiosVideoGraphicsOutputVbeBlt ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, + IN UINTN SourceX, + IN UINTN SourceY, + IN UINTN DestinationX, + IN UINTN DestinationY, + IN UINTN Width, + IN UINTN Height, + IN UINTN Delta + ); + + +/** + Grahpics Output protocol instance to block transfer for VGA device. + + @param This Pointer to Grahpics Output protocol instance + @param BltBuffer The data to transfer to screen + @param BltOperation The operation to perform + @param SourceX The X coordinate of the source for BltOperation + @param SourceY The Y coordinate of the source for BltOperation + @param DestinationX The X coordinate of the destination for + BltOperation + @param DestinationY The Y coordinate of the destination for + BltOperation + @param Width The width of a rectangle in the blt rectangle in + pixels + @param Height The height of a rectangle in the blt rectangle in + pixels + @param Delta Not used for EfiBltVideoFill and + EfiBltVideoToVideo operation. If a Delta of 0 is + used, the entire BltBuffer will be operated on. If + a subrectangle of the BltBuffer is used, then + Delta represents the number of bytes in a row of + the BltBuffer. + + @retval EFI_INVALID_PARAMETER Invalid parameter passed in + @retval EFI_SUCCESS Blt operation success + +**/ +EFI_STATUS +EFIAPI +BiosVideoGraphicsOutputVgaBlt ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL + IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation, + IN UINTN SourceX, + IN UINTN SourceY, + IN UINTN DestinationX, + IN UINTN DestinationY, + IN UINTN Width, + IN UINTN Height, + IN UINTN Delta + ); + +// +// BIOS VGA Mini Port Protocol functions +// + +/** + VgaMiniPort protocol interface to set mode. + + @param This Pointer to VgaMiniPort protocol instance + @param ModeNumber The index of the mode + + @retval EFI_UNSUPPORTED The requested mode is not supported + @retval EFI_SUCCESS The requested mode is set successfully + +**/ +EFI_STATUS +EFIAPI +BiosVideoVgaMiniPortSetMode ( + IN EFI_VGA_MINI_PORT_PROTOCOL *This, + IN UINTN ModeNumber + ); + +/** + Event handler for Exit Boot Service. + + @param Event The event that be siganlled when exiting boot service. + @param Context Pointer to instance of BIOS_VIDEO_DEV. + +**/ +VOID +EFIAPI +BiosVideoNotifyExitBootServices ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +// +// Standard VGA Definitions +// +#define VGA_HORIZONTAL_RESOLUTION 640 +#define VGA_VERTICAL_RESOLUTION 480 +#define VGA_NUMBER_OF_BIT_PLANES 4 +#define VGA_PIXELS_PER_BYTE 8 +#define VGA_BYTES_PER_SCAN_LINE (VGA_HORIZONTAL_RESOLUTION / VGA_PIXELS_PER_BYTE) +#define VGA_BYTES_PER_BIT_PLANE (VGA_VERTICAL_RESOLUTION * VGA_BYTES_PER_SCAN_LINE) + +#define VGA_GRAPHICS_CONTROLLER_ADDRESS_REGISTER 0x3ce +#define VGA_GRAPHICS_CONTROLLER_DATA_REGISTER 0x3cf + +#define VGA_GRAPHICS_CONTROLLER_SET_RESET_REGISTER 0x00 + +#define VGA_GRAPHICS_CONTROLLER_ENABLE_SET_RESET_REGISTER 0x01 + +#define VGA_GRAPHICS_CONTROLLER_COLOR_COMPARE_REGISTER 0x02 + +#define VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER 0x03 +#define VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE 0x00 +#define VGA_GRAPHICS_CONTROLLER_FUNCTION_AND 0x08 +#define VGA_GRAPHICS_CONTROLLER_FUNCTION_OR 0x10 +#define VGA_GRAPHICS_CONTROLLER_FUNCTION_XOR 0x18 + +#define VGA_GRAPHICS_CONTROLLER_READ_MAP_SELECT_REGISTER 0x04 + +#define VGA_GRAPHICS_CONTROLLER_MODE_REGISTER 0x05 +#define VGA_GRAPHICS_CONTROLLER_READ_MODE_0 0x00 +#define VGA_GRAPHICS_CONTROLLER_READ_MODE_1 0x08 +#define VGA_GRAPHICS_CONTROLLER_WRITE_MODE_0 0x00 +#define VGA_GRAPHICS_CONTROLLER_WRITE_MODE_1 0x01 +#define VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2 0x02 +#define VGA_GRAPHICS_CONTROLLER_WRITE_MODE_3 0x03 + +#define VGA_GRAPHICS_CONTROLLER_MISCELLANEOUS_REGISTER 0x06 + +#define VGA_GRAPHICS_CONTROLLER_COLOR_DONT_CARE_REGISTER 0x07 + +#define VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER 0x08 + +/** + Install child handles if the Handle supports MBR format. + + @param This Calling context. + @param ParentHandle Parent Handle + @param ParentPciIo Parent PciIo interface + @param ParentLegacyBios Parent LegacyBios interface + @param ParentDevicePath Parent Device Path + @param RemainingDevicePath Remaining Device Path + + @retval EFI_SUCCESS If a child handle was added + @retval other A child handle was not added + +**/ +EFI_STATUS +BiosVideoChildHandleInstall ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ParentHandle, + IN EFI_PCI_IO_PROTOCOL *ParentPciIo, + IN EFI_LEGACY_BIOS_PROTOCOL *ParentLegacyBios, + IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +/** + Deregister an video child handle and free resources. + + @param This Protocol instance pointer. + @param Controller Video controller handle + @param Handle Video child handle + + @return EFI_STATUS + +**/ +EFI_STATUS +BiosVideoChildHandleUninstall ( + EFI_DRIVER_BINDING_PROTOCOL *This, + EFI_HANDLE Controller, + EFI_HANDLE Handle + ); + +/** + Release resource for biso video instance. + + @param BiosVideoPrivate Video child device private data structure + +**/ +VOID +BiosVideoDeviceReleaseResource ( + BIOS_VIDEO_DEV *BiosVideoPrivate + ); + +/** + Check if all video child handles have been uninstalled. + + @param Controller Video controller handle + + @return TRUE Child handles exist. + @return FALSE All video child handles have been uninstalled. + +**/ +BOOLEAN +HasChildHandle ( + IN EFI_HANDLE Controller + ); +#endif diff --git a/OvmfPkg/Csm/BiosThunk/VideoDxe/BiosVideoDxe.uni b/OvmfPkg/Csm/BiosThunk/VideoDxe/BiosVideoDxe.uni new file mode 100644 index 0000000000..326d9de822 --- /dev/null +++ b/OvmfPkg/Csm/BiosThunk/VideoDxe/BiosVideoDxe.uni @@ -0,0 +1,17 @@ +// /** @file +// Video driver based on legacy bios. +// +// This driver by using Legacy Bios protocol service to support csm Video +// and produce Graphics Output Protocol. +// +// Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Video driver based on legacy bios" + +#string STR_MODULE_DESCRIPTION #language en-US "This driver uses the Legacy Bios protocol service to utilize the CSM Video Support and produce the Graphics Output Protocol." + diff --git a/OvmfPkg/Csm/BiosThunk/VideoDxe/BiosVideoDxeExtra.uni b/OvmfPkg/Csm/BiosThunk/VideoDxe/BiosVideoDxeExtra.uni new file mode 100644 index 0000000000..23fb8fe0b0 --- /dev/null +++ b/OvmfPkg/Csm/BiosThunk/VideoDxe/BiosVideoDxeExtra.uni @@ -0,0 +1,14 @@ +// /** @file +// BiosVideoDxe Localized Strings and Content +// +// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"Legacy Video DXE Driver" + + diff --git a/OvmfPkg/Csm/BiosThunk/VideoDxe/ComponentName.c b/OvmfPkg/Csm/BiosThunk/VideoDxe/ComponentName.c new file mode 100644 index 0000000000..dc914aa2f3 --- /dev/null +++ b/OvmfPkg/Csm/BiosThunk/VideoDxe/ComponentName.c @@ -0,0 +1,306 @@ +/** @file + +Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "BiosVideo.h" + +// +// EFI Component Name Functions +// +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +BiosVideoComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +BiosVideoComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + + +// +// EFI Component Name Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gBiosVideoComponentName = { + BiosVideoComponentNameGetDriverName, + BiosVideoComponentNameGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gBiosVideoComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) BiosVideoComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) BiosVideoComponentNameGetControllerName, + "en" +}; + + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mBiosVideoDriverNameTable[] = { + { + "eng;en", + L"BIOS[INT10] Video Driver" + }, + { + NULL, + NULL + } +}; + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +BiosVideoComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mBiosVideoDriverNameTable, + DriverName, + (BOOLEAN)(This == &gBiosVideoComponentName) + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +BiosVideoComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + return EFI_UNSUPPORTED; +} diff --git a/OvmfPkg/Csm/BiosThunk/VideoDxe/VesaBiosExtensions.h b/OvmfPkg/Csm/BiosThunk/VideoDxe/VesaBiosExtensions.h new file mode 100644 index 0000000000..dbf706179f --- /dev/null +++ b/OvmfPkg/Csm/BiosThunk/VideoDxe/VesaBiosExtensions.h @@ -0,0 +1,459 @@ +/** @file + +Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _VESA_BIOS_EXTENSIONS_H_ +#define _VESA_BIOS_EXTENSIONS_H_ + +// +// Turn on byte packing of data structures +// +#pragma pack(1) +// +// VESA BIOS Extensions status codes +// +#define VESA_BIOS_EXTENSIONS_STATUS_SUCCESS 0x004f + +// +// VESA BIOS Extensions Services +// +#define VESA_BIOS_EXTENSIONS_RETURN_CONTROLLER_INFORMATION 0x4f00 + +/*++ + + Routine Description: + Function 00 : Return Controller Information + + Arguments: + Inputs: + AX = 0x4f00 + ES:DI = Pointer to buffer to place VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK structure + Outputs: + AX = Return Status + +--*/ +#define VESA_BIOS_EXTENSIONS_RETURN_MODE_INFORMATION 0x4f01 + +/*++ + + Routine Description: + Function 01 : Return Mode Information + + Arguments: + Inputs: + AX = 0x4f01 + CX = Mode Number + ES:DI = Pointer to buffer to place VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK structure + Outputs: + AX = Return Status + +--*/ +#define VESA_BIOS_EXTENSIONS_SET_MODE 0x4f02 + +/*++ + + Routine Description: + Function 02 : Set Mode + + Arguments: + Inputs: + AX = 0x4f02 + BX = Desired mode to set + D0-D8 = Mode Number + D9-D10 = Reserved (must be 0) + D11 = 0 - Use current default refresh rate + = 1 - Use user specfieid CRTC values for refresh rate + D12-D13 = Reserved (must be 0) + D14 = 0 - Use windowed frame buffer model + = 1 - Use linear/flat frame buffer model + D15 = 0 - Clear display memory + = 1 - Don't clear display memory + ES:DI = Pointer to buffer to the VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK structure + Outputs: + AX = Return Status + +--*/ +#define VESA_BIOS_EXTENSIONS_RETURN_CURRENT_MODE 0x4f03 + +/*++ + + Routine Description: + Function 03 : Return Current Mode + + Arguments: + Inputs: + AX = 0x4f03 + Outputs: + AX = Return Status + BX = Current mode + D0-D13 = Mode Number + D14 = 0 - Windowed frame buffer model + = 1 - Linear/flat frame buffer model + D15 = 0 - Memory cleared at last mode set + = 1 - Memory not cleared at last mode set + +--*/ +#define VESA_BIOS_EXTENSIONS_SAVE_RESTORE_STATE 0x4f04 + +/*++ + + Routine Description: + Function 04 : Save/Restore State + + Arguments: + Inputs: + AX = 0x4f03 + DL = 0x00 - Return Save/Restore State buffer size + = 0x01 - Save State + = 0x02 - Restore State + CX = Requested Status + D0 = Save/Restore controller hardware state + D1 = Save/Restore BIOS data state + D2 = Save/Restore DAC state + D3 = Save/Restore Regsiter state + ES:BX = Pointer to buffer if DL=1 or DL=2 + Outputs: + AX = Return Status + BX = Number of 64 byte blocks to hold the state buffer if DL=0 + +--*/ +#define VESA_BIOS_EXTENSIONS_EDID 0x4f15 + +/*++ + + Routine Description: + Function 15 : implement VBE/DDC service + + Arguments: + Inputs: + AX = 0x4f15 + BL = 0x00 - Report VBE/DDC Capabilities + CX = 0x00 - Controller unit number (00 = primary controller) + ES:DI = Null pointer, must be 0:0 in version 1.0 + Outputs: + AX = Return Status + BH = Approx. time in seconds, rounded up, to transfer one EDID block(128 bytes) + BL = DDC level supported + D0 = 0 DDC1 not supported + = 1 DDC1 supported + D1 = 0 DDC2 not supported + = 1 DDC2 supported + D2 = 0 Screen not blanked during data transfer + = 1 Screen blanked during data transfer + + Inputs: + AX = 0x4f15 + BL = 0x01 - Read EDID + CX = 0x00 - Controller unit number (00 = primary controller) + DX = 0x00 - EDID block number + ES:DI = Pointer to buffer in which the EDID block is returned + Outputs: + AX = Return Status +--*/ + +// +// Timing data from EDID data block +// +#define VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE 128 +#define VESA_BIOS_EXTENSIONS_EDID_ESTABLISHED_TIMING_MAX_NUMBER 17 + +// +// Established Timings: 24 possible resolutions +// Standard Timings: 8 possible resolutions +// Detailed Timings: 4 possible resolutions +// +#define VESA_BIOS_EXTENSIONS_EDID_TIMING_MAX_NUMBER 36 + +// +// Timing data size for Established Timings, Standard Timings and Detailed Timings +// +#define VESA_BIOS_EXTENSIONS_ESTABLISHED_TIMING_SIZE 3 +#define VESA_BIOS_EXTENSIONS_STANDARD_TIMING_SIZE 16 +#define VESA_BIOS_EXTENSIONS_DETAILED_TIMING_EACH_DESCRIPTOR_SIZE 18 +#define VESA_BIOS_EXTENSIONS_DETAILED_TIMING_DESCRIPTOR_MAX_SIZE 72 + +typedef struct { + UINT16 HorizontalResolution; + UINT16 VerticalResolution; + UINT16 RefreshRate; +} VESA_BIOS_EXTENSIONS_EDID_TIMING; + +typedef struct { + UINT32 ValidNumber; + UINT32 Key[VESA_BIOS_EXTENSIONS_EDID_TIMING_MAX_NUMBER]; +} VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING; + +typedef struct { + UINT8 Header[8]; //EDID header "00 FF FF FF FF FF FF 00" + UINT16 ManufactureName; //EISA 3-character ID + UINT16 ProductCode; //Vendor assigned code + UINT32 SerialNumber; //32-bit serial number + UINT8 WeekOfManufacture; //Week number + UINT8 YearOfManufacture; //Year + UINT8 EdidVersion; //EDID Structure Version + UINT8 EdidRevision; //EDID Structure Revision + UINT8 VideoInputDefinition; + UINT8 MaxHorizontalImageSize; //cm + UINT8 MaxVerticalImageSize; //cm + UINT8 DisplayTransferCharacteristic; + UINT8 FeatureSupport; + UINT8 RedGreenLowBits; //Rx1 Rx0 Ry1 Ry0 Gx1 Gx0 Gy1Gy0 + UINT8 BlueWhiteLowBits; //Bx1 Bx0 By1 By0 Wx1 Wx0 Wy1 Wy0 + UINT8 RedX; //Red-x Bits 9 - 2 + UINT8 RedY; //Red-y Bits 9 - 2 + UINT8 GreenX; //Green-x Bits 9 - 2 + UINT8 GreenY; //Green-y Bits 9 - 2 + UINT8 BlueX; //Blue-x Bits 9 - 2 + UINT8 BlueY; //Blue-y Bits 9 - 2 + UINT8 WhiteX; //White-x Bits 9 - 2 + UINT8 WhiteY; //White-x Bits 9 - 2 + UINT8 EstablishedTimings[VESA_BIOS_EXTENSIONS_ESTABLISHED_TIMING_SIZE]; + UINT8 StandardTimingIdentification[VESA_BIOS_EXTENSIONS_STANDARD_TIMING_SIZE]; + UINT8 DetailedTimingDescriptions[VESA_BIOS_EXTENSIONS_DETAILED_TIMING_DESCRIPTOR_MAX_SIZE]; + UINT8 ExtensionFlag; //Number of (optional) 128-byte EDID extension blocks to follow + UINT8 Checksum; +} VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK; + +// +// Super VGA Information Block +// +typedef struct { + UINT32 VESASignature; // 'VESA' 4 byte signature + UINT16 VESAVersion; // VBE version number + UINT32 OEMStringPtr; // Pointer to OEM string + UINT32 Capabilities; // Capabilities of video card + UINT32 VideoModePtr; // Pointer to an array of 16-bit supported modes values terminated by 0xFFFF + UINT16 TotalMemory; // Number of 64kb memory blocks + UINT16 OemSoftwareRev; // VBE implementation Software revision + UINT32 OemVendorNamePtr; // VbeFarPtr to Vendor Name String + UINT32 OemProductNamePtr; // VbeFarPtr to Product Name String + UINT32 OemProductRevPtr; // VbeFarPtr to Product Revision String + UINT8 Reserved[222]; // Reserved for VBE implementation scratch area + UINT8 OemData[256]; // Data area for OEM strings. Pad to 512 byte block size +} VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK; + +// +// Super VGA Information Block VESASignature values +// +#define VESA_BIOS_EXTENSIONS_VESA_SIGNATURE SIGNATURE_32 ('V', 'E', 'S', 'A') +#define VESA_BIOS_EXTENSIONS_VBE2_SIGNATURE SIGNATURE_32 ('V', 'B', 'E', '2') + +// +// Super VGA Information Block VESAVersion values +// +#define VESA_BIOS_EXTENSIONS_VERSION_1_2 0x0102 +#define VESA_BIOS_EXTENSIONS_VERSION_2_0 0x0200 +#define VESA_BIOS_EXTENSIONS_VERSION_3_0 0x0300 + +// +// Super VGA Information Block Capabilities field bit defintions +// +#define VESA_BIOS_EXTENSIONS_CAPABILITY_8_BIT_DAC 0x01 // 0: DAC width is fixed at 6 bits/color +// 1: DAC width switchable to 8 bits/color +// +#define VESA_BIOS_EXTENSIONS_CAPABILITY_NOT_VGA 0x02 // 0: Controller is VGA compatible +// 1: Controller is not VGA compatible +// +#define VESA_BIOS_EXTENSIONS_CAPABILITY_NOT_NORMAL_RAMDAC 0x04 // 0: Normal RAMDAC operation +// 1: Use blank bit in function 9 to program RAMDAC +// +#define VESA_BIOS_EXTENSIONS_CAPABILITY_STEREOSCOPIC 0x08 // 0: No hardware stereoscopic signal support +// 1: Hardware stereoscopic signal support +// +#define VESA_BIOS_EXTENSIONS_CAPABILITY_VESA_EVC 0x10 // 0: Stero signaling supported via external VESA stereo connector +// 1: Stero signaling supported via VESA EVC connector +// +// Super VGA mode number bite field definitions +// +#define VESA_BIOS_EXTENSIONS_MODE_NUMBER_VESA 0x0100 // 0: Not a VESA defined VBE mode +// 1: A VESA defined VBE mode +// +#define VESA_BIOS_EXTENSIONS_MODE_NUMBER_REFRESH_CONTROL_USER 0x0800 // 0: Use current BIOS default referesh rate +// 1: Use the user specified CRTC values for refresh rate +// +#define VESA_BIOS_EXTENSIONS_MODE_NUMBER_LINEAR_FRAME_BUFFER 0x4000 // 0: Use a banked/windowed frame buffer +// 1: Use a linear/flat frame buffer +// +#define VESA_BIOS_EXTENSIONS_MODE_NUMBER_PRESERVE_MEMORY 0x8000 // 0: Clear display memory +// 1: Preseve display memory +// +// Super VGA Information Block mode list terminator value +// +#define VESA_BIOS_EXTENSIONS_END_OF_MODE_LIST 0xffff + +// +// Window Function +// +typedef +VOID +(*VESA_BIOS_EXTENSIONS_WINDOW_FUNCTION) ( + VOID + ); + +// +// Super VGA Mode Information Block +// +typedef struct { + // + // Manadory fields for all VESA Bios Extensions revisions + // + UINT16 ModeAttributes; // Mode attributes + UINT8 WinAAttributes; // Window A attributes + UINT8 WinBAttributes; // Window B attributes + UINT16 WinGranularity; // Window granularity in k + UINT16 WinSize; // Window size in k + UINT16 WinASegment; // Window A segment + UINT16 WinBSegment; // Window B segment + UINT32 WindowFunction; // Pointer to window function + UINT16 BytesPerScanLine; // Bytes per scanline + // + // Manadory fields for VESA Bios Extensions 1.2 and above + // + UINT16 XResolution; // Horizontal resolution + UINT16 YResolution; // Vertical resolution + UINT8 XCharSize; // Character cell width + UINT8 YCharSize; // Character cell height + UINT8 NumberOfPlanes; // Number of memory planes + UINT8 BitsPerPixel; // Bits per pixel + UINT8 NumberOfBanks; // Number of CGA style banks + UINT8 MemoryModel; // Memory model type + UINT8 BankSize; // Size of CGA style banks + UINT8 NumberOfImagePages; // Number of images pages + UINT8 Reserved1; // Reserved + UINT8 RedMaskSize; // Size of direct color red mask + UINT8 RedFieldPosition; // Bit posn of lsb of red mask + UINT8 GreenMaskSize; // Size of direct color green mask + UINT8 GreenFieldPosition; // Bit posn of lsb of green mask + UINT8 BlueMaskSize; // Size of direct color blue mask + UINT8 BlueFieldPosition; // Bit posn of lsb of blue mask + UINT8 RsvdMaskSize; // Size of direct color res mask + UINT8 RsvdFieldPosition; // Bit posn of lsb of res mask + UINT8 DirectColorModeInfo; // Direct color mode attributes + // + // Manadory fields for VESA Bios Extensions 2.0 and above + // + UINT32 PhysBasePtr; // Physical Address for flat memory frame buffer + UINT32 Reserved2; // Reserved + UINT16 Reserved3; // Reserved + // + // Manadory fields for VESA Bios Extensions 3.0 and above + // + UINT16 LinBytesPerScanLine; // Bytes/scan line for linear modes + UINT8 BnkNumberOfImagePages; // Number of images for banked modes + UINT8 LinNumberOfImagePages; // Number of images for linear modes + UINT8 LinRedMaskSize; // Size of direct color red mask (linear mode) + UINT8 LinRedFieldPosition; // Bit posiiton of lsb of red mask (linear modes) + UINT8 LinGreenMaskSize; // Size of direct color green mask (linear mode) + UINT8 LinGreenFieldPosition; // Bit posiiton of lsb of green mask (linear modes) + UINT8 LinBlueMaskSize; // Size of direct color blue mask (linear mode) + UINT8 LinBlueFieldPosition; // Bit posiiton of lsb of blue mask (linear modes) + UINT8 LinRsvdMaskSize; // Size of direct color reserved mask (linear mode) + UINT8 LinRsvdFieldPosition; // Bit posiiton of lsb of reserved mask (linear modes) + UINT32 MaxPixelClock; // Maximum pixel clock (in Hz) for graphics mode + UINT8 Pad[190]; // Pad to 256 byte block size +} VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK; + +// +// Super VGA Mode Information Block ModeAttributes field bit defintions +// +#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_HARDWARE 0x0001 // 0: Mode not supported in handware +// 1: Mode supported in handware +// +#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_TTY 0x0004 // 0: TTY Output functions not supported by BIOS +// 1: TTY Output functions supported by BIOS +// +#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_COLOR 0x0008 // 0: Monochrome mode +// 1: Color mode +// +#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_GRAPHICS 0x0010 // 0: Text mode +// 1: Graphics mode +// +#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_NOT_VGA 0x0020 // 0: VGA compatible mode +// 1: Not a VGA compatible mode +// +#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_NOT_WINDOWED 0x0040 // 0: VGA compatible windowed memory mode +// 1: Not a VGA compatible windowed memory mode +// +#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER 0x0080 // 0: No linear fram buffer mode available +// 1: Linear frame buffer mode available +// +#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_DOUBLE_SCAN 0x0100 // 0: No double scan mode available +// 1: Double scan mode available +// +#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_INTERLACED 0x0200 // 0: No interlaced mode is available +// 1: Interlaced mode is available +// +#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_NO_TRIPPLE_BUFFER 0x0400 // 0: No hardware triple buffer mode support available +// 1: Hardware triple buffer mode support available +// +#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_STEREOSCOPIC 0x0800 // 0: No hardware steroscopic display support +// 1: Hardware steroscopic display support +// +#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_DUAL_DISPLAY 0x1000 // 0: No dual display start address support +// 1: Dual display start address support +// +// Super VGA Mode Information Block WinAAttribite/WinBAttributes field bit defintions +// +#define VESA_BIOS_EXTENSIONS_WINX_ATTRIBUTE_RELOCATABLE 0x01 // 0: Single non-relocatable window only +// 1: Relocatable window(s) are supported +// +#define VESA_BIOS_EXTENSIONS_WINX_ATTRIBUTE_READABLE 0x02 // 0: Window is not readable +// 1: Window is readable +// +#define VESA_BIOS_EXTENSIONS_WINX_ATTRIBUTE_WRITABLE 0x04 // 0: Window is not writable +// 1: Window is writable +// +// Super VGA Mode Information Block DirectColorMode field bit defintions +// +#define VESA_BIOS_EXTENSIONS_DIRECT_COLOR_MODE_PROG_COLOR_RAMP 0x01 // 0: Color ram is fixed +// 1: Color ramp is programmable +// +#define VESA_BIOS_EXTENSIONS_DIRECT_COLOR_MODE_RSVD_USABLE 0x02 // 0: Bits in Rsvd field are reserved +// 1: Bits in Rsdv field are usable +// +// Super VGA Memory Models +// +typedef enum { + MemPL = 3, // Planar memory model + MemPK = 4, // Packed pixel memory model + MemRGB= 6, // Direct color RGB memory model + MemYUV= 7 // Direct color YUV memory model +} VESA_BIOS_EXTENSIONS_MEMORY_MODELS; + +// +// Super VGA CRTC Information Block +// +typedef struct { + UINT16 HorizontalTotal; // Horizontal total in pixels + UINT16 HorizontalSyncStart; // Horizontal sync start in pixels + UINT16 HorizontalSyncEnd; // Horizontal sync end in pixels + UINT16 VericalTotal; // Vertical total in pixels + UINT16 VericalSyncStart; // Vertical sync start in pixels + UINT16 VericalSyncEnd; // Vertical sync end in pixels + UINT8 Flags; // Flags (Interlaced/DoubleScan/etc). + UINT32 PixelClock; // Pixel clock in units of Hz + UINT16 RefreshRate; // Refresh rate in units of 0.01 Hz + UINT8 Reserved[40]; // Pad +} VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK; + +#define VESA_BIOS_EXTENSIONS_CRTC_FLAGS_DOUBLE_SCAN 0x01 // 0: Graphics mode is not souble scanned +// 1: Graphics mode is double scanned +// +#define VESA_BIOS_EXTENSIONS_CRTC_FLAGSINTERLACED 0x02 // 0: Graphics mode is not interlaced +// 1: Graphics mode is interlaced +// +#define VESA_BIOS_EXTENSIONS_CRTC_HORIZONTAL_SYNC_NEGATIVE 0x04 // 0: Horizontal sync polarity is positive(+) +// 0: Horizontal sync polarity is negative(-) +// +#define VESA_BIOS_EXTENSIONS_CRTC_VERITICAL_SYNC_NEGATIVE 0x08 // 0: Verical sync polarity is positive(+) +// 0: Verical sync polarity is negative(-) +// +// Turn off byte packing of data structures +// +#pragma pack() + +#endif diff --git a/OvmfPkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf b/OvmfPkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf new file mode 100644 index 0000000000..1526bc4cc2 --- /dev/null +++ b/OvmfPkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf @@ -0,0 +1,80 @@ +## @file +# Video driver based on legacy bios. +# +# This driver by using Legacy Bios protocol service to support csm Video +# and produce Graphics Output Protocol. +# +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BiosVideoDxe + MODULE_UNI_FILE = BiosVideoDxe.uni + FILE_GUID = 0B04B2ED-861C-42cd-A22F-C3AAFACCB896 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = BiosVideoEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# +# DRIVER_BINDING = gBiosVideoDriverBinding +# COMPONENT_NAME = gBiosVideoComponentName +# + +[Sources] + BiosVideo.c + BiosVideo.h + ComponentName.c + VesaBiosExtensions.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec + + +[LibraryClasses] + MemoryAllocationLib + DevicePathLib + UefiLib + UefiBootServicesTableLib + UefiDriverEntryPoint + BaseMemoryLib + ReportStatusCodeLib + DebugLib + PcdLib + + +[Guids] + gEfiLegacyBiosGuid ## PRODUCES ##GUID # Install Legacy BIOS GUID to mark this driver as a BIOS Thunk Driver + gEfiEventExitBootServicesGuid ## CONSUMES ##Event + +[Protocols] + gEfiVgaMiniPortProtocolGuid ## BY_START + gEfiEdidDiscoveredProtocolGuid ## BY_START + gEfiGraphicsOutputProtocolGuid ## BY_START + gEfiEdidActiveProtocolGuid ## BY_START + gEfiLegacyBiosProtocolGuid ## CONSUMES + gEfiPciIoProtocolGuid ## TO_START + gEfiDevicePathProtocolGuid ## TO_START + gEfiDevicePathProtocolGuid ## BY_START + gEfiEdidOverrideProtocolGuid ## SOMETIMES_CONSUMES + +[Pcd] + gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBiosVideoSetTextVgaModeEnable ## CONSUMES + gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBiosVideoCheckVbeEnable ## CONSUMES + gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBiosVideoCheckVgaEnable ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution ## SOMETIMES_CONSUMES + +[UserExtensions.TianoCore."ExtraFiles"] + BiosVideoDxeExtra.uni diff --git a/OvmfPkg/Csm/Include/Framework/BootScript.h b/OvmfPkg/Csm/Include/Framework/BootScript.h new file mode 100644 index 0000000000..cb7220c1a7 --- /dev/null +++ b/OvmfPkg/Csm/Include/Framework/BootScript.h @@ -0,0 +1,41 @@ +/** @file + This file contains the boot script defintions that are shared between the + Boot Script Executor PPI and the Boot Script Save Protocol. + +Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _BOOT_SCRIPT_H_ +#define _BOOT_SCRIPT_H_ + +#include +/// +/// The framework implementation defines follow opcode that are different from the PI specification: +/// Add FRAMEWORK_ prefix to avoid naming conflict. +/// +/// S3 Boot Script Table identifier. +/// +#define FRAMEWORK_EFI_ACPI_S3_RESUME_SCRIPT_TABLE 0x00 +/// +/// The opcode is used to add a record for memory reads of the memory location and continues when the +/// exit criteria is satisfied, or after a defined duration. +/// +#define FRAMEWORK_EFI_BOOT_SCRIPT_MEM_POLL_OPCODE 0x09 +/// +/// The opcode is used to add a record for dispatching specified arbitrary code into a specified +/// boot script table. +/// +#define FRAMEWORK_EFI_BOOT_SCRIPT_DISPATCH_2_OPCODE 0x0D +/// +/// The opcode indicates the start of the boot script table. +/// +#define FRAMEWORK_EFI_BOOT_SCRIPT_TABLE_OPCODE 0xAA +/// +/// The opcode indicates the end of the boot script table. +/// +#define FRAMEWORK_EFI_BOOT_SCRIPT_TERMINATE_OPCODE 0xFF + + +#endif diff --git a/OvmfPkg/Csm/Include/Framework/DxeCis.h b/OvmfPkg/Csm/Include/Framework/DxeCis.h new file mode 100644 index 0000000000..98a947e420 --- /dev/null +++ b/OvmfPkg/Csm/Include/Framework/DxeCis.h @@ -0,0 +1,170 @@ +/** @file + Include file for definitions in the Intel Platform Innovation Framework for EFI + Driver Execution Environment Core Interface Specification (DXE CIS) Version 0.91. + +Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _DXECIS_H_ +#define _DXECIS_H_ + +#include + +/** + Functions of this type are used with the Framework MP Services Protocol and + the SMM Services Table to execute a procedure on enabled APs. The context + the AP should use durng execution is specified by Buffer. + + @param[in] Buffer The pointer to the procedure's argument. + +**/ +typedef +VOID +(EFIAPI *FRAMEWORK_EFI_AP_PROCEDURE)( + IN VOID *Buffer + ); + +/// +/// The Framework EFI Runtime Services Table as an extension to the EFI 1.10 Runtime Services Table. +/// +typedef struct { + // + // Table header for the Framework EFI Runtime Services Table + // + EFI_TABLE_HEADER Hdr; + // + // Time services + // + EFI_GET_TIME GetTime; + EFI_SET_TIME SetTime; + EFI_GET_WAKEUP_TIME GetWakeupTime; + EFI_SET_WAKEUP_TIME SetWakeupTime; + // + // Virtual memory services + // + EFI_SET_VIRTUAL_ADDRESS_MAP SetVirtualAddressMap; + EFI_CONVERT_POINTER ConvertPointer; + // + // Variable services + // + EFI_GET_VARIABLE GetVariable; + EFI_GET_NEXT_VARIABLE_NAME GetNextVariableName; + EFI_SET_VARIABLE SetVariable; + // + // Misc + // + EFI_GET_NEXT_HIGH_MONO_COUNT GetNextHighMonotonicCount; + EFI_RESET_SYSTEM ResetSystem; + /// + /// A Framework extension to the EFI 1.10 runtime table. + /// It was moved to a protocol to avoid conflict with UEFI 2.0. + /// + EFI_REPORT_STATUS_CODE ReportStatusCode; +} FRAMEWORK_EFI_RUNTIME_SERVICES; + +/// +/// The Framework EFI Boot Services Table. Complies with the DxeCis specification. +/// +typedef struct { + /// + /// The table header for the EFI Boot Services Table. + /// + EFI_TABLE_HEADER Hdr; + + // + // Task Priority Services + // + EFI_RAISE_TPL RaiseTPL; + EFI_RESTORE_TPL RestoreTPL; + + // + // Memory Services + // + EFI_ALLOCATE_PAGES AllocatePages; + EFI_FREE_PAGES FreePages; + EFI_GET_MEMORY_MAP GetMemoryMap; + EFI_ALLOCATE_POOL AllocatePool; + EFI_FREE_POOL FreePool; + + // + // Event & Timer Services + // + EFI_CREATE_EVENT CreateEvent; + EFI_SET_TIMER SetTimer; + EFI_WAIT_FOR_EVENT WaitForEvent; + EFI_SIGNAL_EVENT SignalEvent; + EFI_CLOSE_EVENT CloseEvent; + EFI_CHECK_EVENT CheckEvent; + + // + // Protocol Handler Services + // + EFI_INSTALL_PROTOCOL_INTERFACE InstallProtocolInterface; + EFI_REINSTALL_PROTOCOL_INTERFACE ReinstallProtocolInterface; + EFI_UNINSTALL_PROTOCOL_INTERFACE UninstallProtocolInterface; + EFI_HANDLE_PROTOCOL HandleProtocol; + EFI_HANDLE_PROTOCOL PcHandleProtocol; + EFI_REGISTER_PROTOCOL_NOTIFY RegisterProtocolNotify; + EFI_LOCATE_HANDLE LocateHandle; + EFI_LOCATE_DEVICE_PATH LocateDevicePath; + EFI_INSTALL_CONFIGURATION_TABLE InstallConfigurationTable; + + // + // Image Services + // + EFI_IMAGE_LOAD LoadImage; + EFI_IMAGE_START StartImage; + EFI_EXIT Exit; + EFI_IMAGE_UNLOAD UnloadImage; + EFI_EXIT_BOOT_SERVICES ExitBootServices; + + // + // Miscellaneous Services + // + EFI_GET_NEXT_MONOTONIC_COUNT GetNextMonotonicCount; + EFI_STALL Stall; + EFI_SET_WATCHDOG_TIMER SetWatchdogTimer; + + // + // DriverSupport Services + // + EFI_CONNECT_CONTROLLER ConnectController; + EFI_DISCONNECT_CONTROLLER DisconnectController; + + // + // Open and Close Protocol Services + // + EFI_OPEN_PROTOCOL OpenProtocol; + EFI_CLOSE_PROTOCOL CloseProtocol; + EFI_OPEN_PROTOCOL_INFORMATION OpenProtocolInformation; + + // + // Library Services + // + EFI_PROTOCOLS_PER_HANDLE ProtocolsPerHandle; + EFI_LOCATE_HANDLE_BUFFER LocateHandleBuffer; + EFI_LOCATE_PROTOCOL LocateProtocol; + EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES InstallMultipleProtocolInterfaces; + EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES UninstallMultipleProtocolInterfaces; + + // + // 32-bit CRC Services + // + EFI_CALCULATE_CRC32 CalculateCrc32; + + // + // Miscellaneous Services + // + EFI_COPY_MEM CopyMem; + EFI_SET_MEM SetMem; +} FRAMEWORK_EFI_BOOT_SERVICES; + +#define EFI_EVENT_RUNTIME_CONTEXT 0x20000000 +#define EFI_EVENT_NOTIFY_SIGNAL_ALL 0x00000400 +#define EFI_EVENT_SIGNAL_READY_TO_BOOT 0x00000203 +#define EFI_EVENT_SIGNAL_LEGACY_BOOT 0x00000204 + +#endif + diff --git a/OvmfPkg/Csm/Include/Framework/FirmwareVolumeHeader.h b/OvmfPkg/Csm/Include/Framework/FirmwareVolumeHeader.h new file mode 100644 index 0000000000..e2b5a28b8b --- /dev/null +++ b/OvmfPkg/Csm/Include/Framework/FirmwareVolumeHeader.h @@ -0,0 +1,79 @@ +/** @file + Defines the data structure that is the volume header found at the beginning of + all firmware volumes that are either memory mapped or have an + associated FirmwareVolumeBlock protocol. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Revision Reference: + These definitions are from the Firmware Volume Block Spec 0.9. + +**/ + +#ifndef __EFI_FIRMWARE_VOLUME_HEADER_H__ +#define __EFI_FIRMWARE_VOLUME_HEADER_H__ + +/// +/// Firmware Volume Block Attributes bit definitions. +///@{ +#define EFI_FVB_READ_DISABLED_CAP 0x00000001 +#define EFI_FVB_READ_ENABLED_CAP 0x00000002 +#define EFI_FVB_READ_STATUS 0x00000004 + +#define EFI_FVB_WRITE_DISABLED_CAP 0x00000008 +#define EFI_FVB_WRITE_ENABLED_CAP 0x00000010 +#define EFI_FVB_WRITE_STATUS 0x00000020 + +#define EFI_FVB_LOCK_CAP 0x00000040 +#define EFI_FVB_LOCK_STATUS 0x00000080 + +#define EFI_FVB_STICKY_WRITE 0x00000200 +#define EFI_FVB_MEMORY_MAPPED 0x00000400 +#define EFI_FVB_ERASE_POLARITY 0x00000800 + +#define EFI_FVB_ALIGNMENT_CAP 0x00008000 +#define EFI_FVB_ALIGNMENT_2 0x00010000 +#define EFI_FVB_ALIGNMENT_4 0x00020000 +#define EFI_FVB_ALIGNMENT_8 0x00040000 +#define EFI_FVB_ALIGNMENT_16 0x00080000 +#define EFI_FVB_ALIGNMENT_32 0x00100000 +#define EFI_FVB_ALIGNMENT_64 0x00200000 +#define EFI_FVB_ALIGNMENT_128 0x00400000 +#define EFI_FVB_ALIGNMENT_256 0x00800000 +#define EFI_FVB_ALIGNMENT_512 0x01000000 +#define EFI_FVB_ALIGNMENT_1K 0x02000000 +#define EFI_FVB_ALIGNMENT_2K 0x04000000 +#define EFI_FVB_ALIGNMENT_4K 0x08000000 +#define EFI_FVB_ALIGNMENT_8K 0x10000000 +#define EFI_FVB_ALIGNMENT_16K 0x20000000 +#define EFI_FVB_ALIGNMENT_32K 0x40000000 +#define EFI_FVB_ALIGNMENT_64K 0x80000000 +///@} + +/// This is a simple macro defined as the set of all FV Block Attributes signifying capabilities. +#define EFI_FVB_CAPABILITIES ( EFI_FVB_READ_DISABLED_CAP | \ + EFI_FVB_READ_ENABLED_CAP | \ + EFI_FVB_WRITE_DISABLED_CAP | \ + EFI_FVB_WRITE_ENABLED_CAP | \ + EFI_FVB_LOCK_CAP \ + ) + +/** A parameterized macro defining a boolean expression that tests the state of a particular bit. + * + * @param FvbAttributes Indicates a test for CLEAR if EFI_FVB_ERASE_POLARITY is 1, else test for SET. + * + * @param TestAttributes The set of bits to test. + * + * @param Bit A value indicating the bit(s) to test. + * If multiple bits are set, the logical OR of their tests is the expression's value. +**/ +#define EFI_TEST_FFS_ATTRIBUTES_BIT( FvbAttributes, TestAttributes, Bit) \ + ((BOOLEAN) \ + ((FvbAttributes & EFI_FVB_ERASE_POLARITY) ? (((~TestAttributes) & Bit) == Bit) : ((TestAttributes & Bit) == Bit)) \ + ) + +/// A simple macro defined as the set of all FV Block Attribute bits that indicate status. +#define EFI_FVB_STATUS (EFI_FVB_READ_STATUS | EFI_FVB_WRITE_STATUS | EFI_FVB_LOCK_STATUS) + +#endif /* __EFI_FIRMWARE_VOLUME_HEADER_H__ */ diff --git a/OvmfPkg/Csm/Include/Framework/FirmwareVolumeImageFormat.h b/OvmfPkg/Csm/Include/Framework/FirmwareVolumeImageFormat.h new file mode 100644 index 0000000000..c77e39b4c0 --- /dev/null +++ b/OvmfPkg/Csm/Include/Framework/FirmwareVolumeImageFormat.h @@ -0,0 +1,32 @@ +/** @file + This file defines the data structures that are architecturally defined for file + images loaded via the FirmwareVolume protocol. The Firmware Volume specification + is the basis for these definitions. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Revision Reference: + These definitions are from the Firmware Volume Spec 0.9. + +**/ + +#ifndef __FIRMWARE_VOLUME_IMAGE_FORMAT_H__ +#define __FIRMWARE_VOLUME_IMAGE_FORMAT_H__ + +// +// Bit values for AuthenticationStatus +// +#define EFI_AGGREGATE_AUTH_STATUS_PLATFORM_OVERRIDE 0x000001 +#define EFI_AGGREGATE_AUTH_STATUS_IMAGE_SIGNED 0x000002 +#define EFI_AGGREGATE_AUTH_STATUS_NOT_TESTED 0x000004 +#define EFI_AGGREGATE_AUTH_STATUS_TEST_FAILED 0x000008 +#define EFI_AGGREGATE_AUTH_STATUS_ALL 0x00000f + +#define EFI_LOCAL_AUTH_STATUS_PLATFORM_OVERRIDE 0x010000 +#define EFI_LOCAL_AUTH_STATUS_IMAGE_SIGNED 0x020000 +#define EFI_LOCAL_AUTH_STATUS_NOT_TESTED 0x040000 +#define EFI_LOCAL_AUTH_STATUS_TEST_FAILED 0x080000 +#define EFI_LOCAL_AUTH_STATUS_ALL 0x0f0000 + +#endif diff --git a/OvmfPkg/Csm/Include/Framework/FrameworkInternalFormRepresentation.h b/OvmfPkg/Csm/Include/Framework/FrameworkInternalFormRepresentation.h new file mode 100644 index 0000000000..04cbae1ef5 --- /dev/null +++ b/OvmfPkg/Csm/Include/Framework/FrameworkInternalFormRepresentation.h @@ -0,0 +1,397 @@ +/** @file + This file defines the encoding for the VFR (Visual Form Representation) language. + Framework IFR is primarily consumed by the EFI presentation engine, and produced by EFI + internal application and drivers as well as all add-in card option-ROM drivers + +Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Revision Reference: + These definitions are from the Framework Specification HII 0.92. + +**/ + +#ifndef __FRAMEWORK_INTERNAL_FORMREPRESENTATION_H__ +#define __FRAMEWORK_INTERNAL_FORMREPRESENTATION_H__ + +typedef UINT16 STRING_REF; + +// +// IFR Op codes +// +#define FRAMEWORK_EFI_IFR_FORM_OP 0x01 +#define FRAMEWORK_EFI_IFR_SUBTITLE_OP 0x02 +#define FRAMEWORK_EFI_IFR_TEXT_OP 0x03 +#define EFI_IFR_GRAPHIC_OP 0x04 +#define FRAMEWORK_EFI_IFR_ONE_OF_OP 0x05 +#define FRAMEWORK_EFI_IFR_CHECKBOX_OP 0x06 +#define FRAMEWORK_EFI_IFR_NUMERIC_OP 0x07 +#define FRAMEWORK_EFI_IFR_PASSWORD_OP 0x08 +#define FRAMEWORK_EFI_IFR_ONE_OF_OPTION_OP 0x09 ///< ONEOF OPTION field. +#define FRAMEWORK_EFI_IFR_SUPPRESS_IF_OP 0x0A +#define EFI_IFR_END_FORM_OP 0x0B +#define EFI_IFR_HIDDEN_OP 0x0C +#define EFI_IFR_END_FORM_SET_OP 0x0D +#define FRAMEWORK_EFI_IFR_FORM_SET_OP 0x0E +#define FRAMEWORK_EFI_IFR_REF_OP 0x0F +#define EFI_IFR_END_ONE_OF_OP 0x10 +#define FRAMEWORK_EFI_IFR_END_OP EFI_IFR_END_ONE_OF_OP +#define FRAMEWORK_EFI_IFR_INCONSISTENT_IF_OP 0x11 +#define FRAMEWORK_EFI_IFR_EQ_ID_VAL_OP 0x12 +#define FRAMEWORK_EFI_IFR_EQ_ID_ID_OP 0x13 +#define FRAMEWORK_EFI_IFR_EQ_ID_LIST_OP 0x14 +#define FRAMEWORK_EFI_IFR_AND_OP 0x15 +#define FRAMEWORK_EFI_IFR_OR_OP 0x16 +#define FRAMEWORK_EFI_IFR_NOT_OP 0x17 +#define EFI_IFR_END_IF_OP 0x18 ///< For endif of inconsistentif, suppressif, grayoutif. +#define EFI_IFR_GRAYOUT_IF_OP 0x19 +#define FRAMEWORK_EFI_IFR_DATE_OP 0x1A +#define FRAMEWORK_EFI_IFR_TIME_OP 0x1B +#define FRAMEWORK_EFI_IFR_STRING_OP 0x1C +#define EFI_IFR_LABEL_OP 0x1D +#define EFI_IFR_SAVE_DEFAULTS_OP 0x1E +#define EFI_IFR_RESTORE_DEFAULTS_OP 0x1F +#define EFI_IFR_BANNER_OP 0x20 +#define EFI_IFR_INVENTORY_OP 0x21 +#define EFI_IFR_EQ_VAR_VAL_OP 0x22 +#define FRAMEWORK_EFI_IFR_ORDERED_LIST_OP 0x23 +#define FRAMEWORK_EFI_IFR_VARSTORE_OP 0x24 +#define EFI_IFR_VARSTORE_SELECT_OP 0x25 +#define EFI_IFR_VARSTORE_SELECT_PAIR_OP 0x26 +#define EFI_IFR_LAST_OPCODE EFI_IFR_VARSTORE_SELECT_PAIR_OP +#define EFI_IFR_OEM_OP 0xFE +#define EFI_IFR_NV_ACCESS_COMMAND 0xFF + +// +// Define values for the flags fields in some VFR opcodes. These are +// bitmasks. +// +#define EFI_IFR_FLAG_DEFAULT 0x01 +#define EFI_IFR_FLAG_MANUFACTURING 0x02 +#define EFI_IFR_FLAG_INTERACTIVE 0x04 +#define EFI_IFR_FLAG_NV_ACCESS 0x08 +#define EFI_IFR_FLAG_RESET_REQUIRED 0x10 +#define EFI_IFR_FLAG_LATE_CHECK 0x20 + +#define EFI_NON_DEVICE_CLASS 0x00 ///< Useful when you do not want something in the Device Manager. +#define EFI_DISK_DEVICE_CLASS 0x01 +#define EFI_VIDEO_DEVICE_CLASS 0x02 +#define EFI_NETWORK_DEVICE_CLASS 0x04 +#define EFI_INPUT_DEVICE_CLASS 0x08 +#define EFI_ON_BOARD_DEVICE_CLASS 0x10 +#define EFI_OTHER_DEVICE_CLASS 0x20 + +#define EFI_SETUP_APPLICATION_SUBCLASS 0x00 +#define EFI_GENERAL_APPLICATION_SUBCLASS 0x01 +#define EFI_FRONT_PAGE_SUBCLASS 0x02 +#define EFI_SINGLE_USE_SUBCLASS 0x03 ///< Used to display a single entity ,and then exit. + +/// +/// Used to flag dynamically created op-codes. This is meaningful to the IFR Library set +/// and the browser because we need to distinguish between compiled NV map data and created data. +/// We do not allow new entries to be created in the NV map dynamically, but we do need +/// to display this information correctly. To dynamically create op-codes and assume that their +/// data will be saved, ensure that the NV starting location they refer to is pre-defined in the +/// NV map. +/// +#define EFI_IFR_FLAG_CREATED 128 + + +#pragma pack(1) +// +// IFR Structure definitions +// +typedef struct { + UINT8 OpCode; + UINT8 Length; +} FRAMEWORK_EFI_IFR_OP_HEADER; + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; + EFI_GUID Guid; + STRING_REF FormSetTitle; + STRING_REF Help; + EFI_PHYSICAL_ADDRESS CallbackHandle; + UINT16 Class; + UINT16 SubClass; + UINT16 NvDataSize; ///< Set once; the size of the NV data as defined in the script. +} FRAMEWORK_EFI_IFR_FORM_SET; + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; + UINT16 FormId; + STRING_REF FormTitle; +} FRAMEWORK_EFI_IFR_FORM; + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; + UINT16 LabelId; +} EFI_IFR_LABEL; + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; + STRING_REF SubTitle; +} FRAMEWORK_EFI_IFR_SUBTITLE; + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; + STRING_REF Help; + STRING_REF Text; + STRING_REF TextTwo; + UINT8 Flags; ///< This is included solely for purposes of interactive/dynamic support. + UINT16 Key; ///< The value to be passed to the caller to identify this particular op-code. +} FRAMEWORK_EFI_IFR_TEXT; + +// +// goto +// +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; + UINT16 FormId; + STRING_REF Prompt; + STRING_REF Help; ///< The string Token for the context-help. + UINT8 Flags; ///< This is included solely for purposes of interactive/dynamic support. + UINT16 Key; ///< The value to be passed to the caller to identify this particular op-code. +} FRAMEWORK_EFI_IFR_REF; + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; +} EFI_IFR_END_FORM; + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; +} EFI_IFR_END_FORM_SET; + +// +// Also notice that the IFR_ONE_OF and IFR_CHECK_BOX are identical in structure...... +// code assumes this to be true, if this ever changes we need to revisit the InitializeTagStructures code +// +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; + UINT16 QuestionId; ///< The ID designating what the question is about... + UINT8 Width; ///< The Size of the Data being saved. + STRING_REF Prompt; ///< The String Token for the Prompt. + STRING_REF Help; ///< The string Token for the context-help. +} FRAMEWORK_EFI_IFR_ONE_OF; + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; + UINT16 QuestionId; ///< The offset in NV for storage of the data. + UINT8 MaxEntries; ///< The maximum number of options in the ordered list (=size of NVStore). + STRING_REF Prompt; ///< The string token for the prompt. + STRING_REF Help; ///< The string token for the context-help. +} FRAMEWORK_EFI_IFR_ORDERED_LIST; + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; + UINT16 QuestionId; ///< The ID designating what the question is about... + UINT8 Width; ///< The Size of the Data being saved. + STRING_REF Prompt; ///< The String Token for the Prompt. + STRING_REF Help; ///< The string Token for the context-help. + UINT8 Flags; ///< If non-zero, it means that it is the default option. + UINT16 Key; ///< Value to be passed to caller to identify this particular op-code. +} FRAMEWORK_EFI_IFR_CHECKBOX, EFI_IFR_CHECK_BOX; + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; + STRING_REF Option; ///< The string token describing the option. + UINT16 Value; ///< The value associated with this option that is stored in the NVRAM. + UINT8 Flags; ///< If non-zero, it means that it is the default option. + UINT16 Key; ///< Value to be passed to caller to identify this particular op-code. +} FRAMEWORK_EFI_IFR_ONE_OF_OPTION; + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; + UINT16 QuestionId; ///< The ID designating what the question is about... + UINT8 Width; ///< The Size of the Data being saved. + STRING_REF Prompt; ///< The String Token for the Prompt. + STRING_REF Help; ///< The string Token for the context-help. + UINT8 Flags; ///< This is included solely for purposes of interactive/dynamic support. + UINT16 Key; ///< The value to be passed to caller to identify this particular op-code. + UINT16 Minimum; + UINT16 Maximum; + UINT16 Step; ///< Zero means manual input. Otherwise, arrow selection is called for. + UINT16 Default; +} FRAMEWORK_EFI_IFR_NUMERIC; + +// +// There is an interesting twist with regards to Time and Date. This is one of the few items which can accept input +// from a user, and may or may not need to use storage in the NVRAM space. The decided method for determining +// if NVRAM space will be used (only for a TimeOp or DateOp) is: If .QuestionId == 0 && .Width == 0 (normally an +// impossibility) then use system resources to store the data away and not NV resources. In other words, the setup +// engine will call gRT->SetTime, and gRT->SetDate for the saving of data, and the values displayed will be from the +// gRT->GetXXXX series of calls. +// +typedef struct { + FRAMEWORK_EFI_IFR_NUMERIC Hour; + FRAMEWORK_EFI_IFR_NUMERIC Minute; + FRAMEWORK_EFI_IFR_NUMERIC Second; +} FRAMEWORK_EFI_IFR_TIME; + +typedef struct { + FRAMEWORK_EFI_IFR_NUMERIC Year; + FRAMEWORK_EFI_IFR_NUMERIC Month; + FRAMEWORK_EFI_IFR_NUMERIC Day; +} FRAMEWORK_EFI_IFR_DATE; + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; + UINT16 QuestionId;///< The ID designating what the question is about... + UINT8 Width; ///< The Size of the Data being saved. + STRING_REF Prompt; ///< The String Token for the Prompt. + STRING_REF Help; ///< The string Token for the context-help. + UINT8 Flags; ///< This is included solely for purposes of interactive/dynamic support. + UINT16 Key; ///< The value to be passed to caller to identify this particular op-code. + UINT8 MinSize; ///< Minimum allowable sized password. + UINT8 MaxSize; ///< Maximum allowable sized password. + UINT16 Encoding; +} FRAMEWORK_EFI_IFR_PASSWORD; + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; + UINT16 QuestionId; ///< The ID designating what the question is about... + UINT8 Width; ///< The Size of the Data being saved. + STRING_REF Prompt; ///< The String Token for the Prompt. + STRING_REF Help; ///< The string Token for the context-help. + UINT8 Flags; ///< This is included solely for purposes of interactive/dynamic support. + UINT16 Key; ///< The value to be passed to caller to identify this particular op-code. + UINT8 MinSize; ///< Minimum allowable sized password. + UINT8 MaxSize; ///< Maximum allowable sized password. +} FRAMEWORK_EFI_IFR_STRING; + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; +} EFI_IFR_END_ONE_OF; + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; + UINT16 Value; + UINT16 Key; +} EFI_IFR_HIDDEN; + +/// +/// Inconsistent with specification here: +/// The following defintion may not comply with Framework Specification HII 0.92. To +/// keep the inconsistant is for implementation needed. +///@{ +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; + UINT8 Flags; +} EFI_IFR_SUPPRESS; + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; + UINT8 Flags; +} EFI_IFR_GRAY_OUT; + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; + STRING_REF Popup; + UINT8 Flags; +} EFI_IFR_INCONSISTENT; + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; + UINT16 QuestionId; ///< The offset into variable storage. + UINT8 Width; ///< The size of variable storage. + UINT16 Value; ///< The value to compare against. +} FRAMEWORK_EFI_IFR_EQ_ID_VAL; + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; + UINT16 QuestionId; ///< The offset into variable storage. + UINT8 Width; ///< The size of variable storage. + UINT16 ListLength; + UINT16 ValueList[1]; +} FRAMEWORK_EFI_IFR_EQ_ID_LIST; + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; + UINT16 QuestionId1; ///< The offset into variable storage for first value to compare. + UINT8 Width; ///< The size of variable storage (must be same for both). + UINT16 QuestionId2; ///< The offset into variable storage for second value to compare. +} FRAMEWORK_EFI_IFR_EQ_ID_ID; + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; + UINT16 VariableId; ///< The offset into variable storage. + UINT16 Value; ///< The value to compare against. +} EFI_IFR_EQ_VAR_VAL; +///@} + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; +} FRAMEWORK_EFI_IFR_AND; + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; +} FRAMEWORK_EFI_IFR_OR; + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; +} FRAMEWORK_EFI_IFR_NOT; + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; +} EFI_IFR_END_EXPR, EFI_IFR_END_IF; + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; + UINT16 FormId; + STRING_REF Prompt; + STRING_REF Help; + UINT8 Flags; + UINT16 Key; +} EFI_IFR_SAVE_DEFAULTS; + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; + STRING_REF Help; + STRING_REF Text; + STRING_REF TextTwo; ///< Optional text. +} EFI_IFR_INVENTORY; + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; + EFI_GUID Guid; ///< GUID for the variable. + UINT16 VarId; ///< The variable store ID, as referenced elsewhere in the form. + UINT16 Size; ///< The size of the variable storage. +} FRAMEWORK_EFI_IFR_VARSTORE; + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; + UINT16 VarId; ///< The variable store ID, as referenced elsewhere in the form. +} EFI_IFR_VARSTORE_SELECT; + +/// +/// Used for the ideqid VFR statement where two variable stores may be referenced in the +/// same VFR statement. +/// A browser should treat this as an FRAMEWORK_EFI_IFR_VARSTORE_SELECT statement and assume that all following +/// IFR opcodes use the VarId as defined here. +/// +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; + UINT16 VarId; ///< The variable store ID, as referenced elsewhere in the form. + UINT16 SecondaryVarId; ///< The variable store ID, as referenced elsewhere in the form. +} EFI_IFR_VARSTORE_SELECT_PAIR; + +/// +/// Save defaults and restore defaults have same structure. +/// +#define EFI_IFR_RESTORE_DEFAULTS EFI_IFR_SAVE_DEFAULTS + +typedef struct { + FRAMEWORK_EFI_IFR_OP_HEADER Header; + STRING_REF Title; ///< The string token for the banner title. + UINT16 LineNumber; ///< 1-based line number. + UINT8 Alignment; ///< Left, center, or right-aligned. +} EFI_IFR_BANNER; + +#define EFI_IFR_BANNER_ALIGN_LEFT 0 +#define EFI_IFR_BANNER_ALIGN_CENTER 1 +#define EFI_IFR_BANNER_ALIGN_RIGHT 2 +#define EFI_IFR_BANNER_TIMEOUT 0xFF + +#pragma pack() + +#endif diff --git a/OvmfPkg/Csm/Include/Framework/Hob.h b/OvmfPkg/Csm/Include/Framework/Hob.h new file mode 100644 index 0000000000..f6a71fabe4 --- /dev/null +++ b/OvmfPkg/Csm/Include/Framework/Hob.h @@ -0,0 +1,28 @@ +/** @file + This file defines the data structures per HOB specification v0.9. + +Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Revision Reference: + These definitions are from the HOB Spec 0.9 that were not adopted by the PI specifications. + +**/ + +#ifndef _HOB_H_ +#define _HOB_H_ + +/// +/// Capsule volume HOB -- identical to a firmware volume. +/// This macro is defined to comply with the hob Framework Spec. And the marco was +/// retired in the PI1.0 specification. +/// +#define EFI_HOB_TYPE_CV 0x0008 + +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + EFI_PHYSICAL_ADDRESS BaseAddress; + UINT64 Length; +} EFI_HOB_CAPSULE_VOLUME; + +#endif diff --git a/OvmfPkg/Csm/Include/Framework/StatusCode.h b/OvmfPkg/Csm/Include/Framework/StatusCode.h new file mode 100644 index 0000000000..753029c13c --- /dev/null +++ b/OvmfPkg/Csm/Include/Framework/StatusCode.h @@ -0,0 +1,155 @@ +/** @file + Status Code Definitions, according to Intel Platform Innovation Framework + for EFI Status Codes Specification + +Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Revision Reference: + Intel Platform Innovation Framework for EFI Status Codes Specification + Version 0.92. + +**/ + +#ifndef _FRAMEWORK_STATUS_CODE_H_ +#define _FRAMEWORK_STATUS_CODE_H_ + +// +// Required for X64 defines for CPU exception types +// +#include + +/// +/// Software Class DXE BS Driver Subclass Progress Code definitions. +/// +/// Inconsistent with specification here: +/// The Framework Specification, StatusCodes 0.92, does not define the macros. +/// +///@{ +#define EFI_SW_DXE_BS_PC_BEGIN_CONNECTING_DRIVERS (EFI_SUBCLASS_SPECIFIC | 0x00000005) +#define EFI_SW_DXE_BS_PC_VERIFYING_PASSWORD (EFI_SUBCLASS_SPECIFIC | 0x00000006) +///@} + +/// +/// Software Class DXE RT Driver Subclass Progress Code definitions. +/// +/// Inconsistent with specification here: +/// The Framework Specification, StatusCodes 0.92, does not define the macros. +/// +///@{ +#define EFI_SW_DXE_RT_PC_S0 (EFI_SUBCLASS_SPECIFIC | 0x00000000) +#define EFI_SW_DXE_RT_PC_S1 (EFI_SUBCLASS_SPECIFIC | 0x00000001) +#define EFI_SW_DXE_RT_PC_S2 (EFI_SUBCLASS_SPECIFIC | 0x00000002) +#define EFI_SW_DXE_RT_PC_S3 (EFI_SUBCLASS_SPECIFIC | 0x00000003) +#define EFI_SW_DXE_RT_PC_S4 (EFI_SUBCLASS_SPECIFIC | 0x00000004) +#define EFI_SW_DXE_RT_PC_S5 (EFI_SUBCLASS_SPECIFIC | 0x00000005) +///@} + +/// +/// Software Subclass definitions. +/// +/// Inconsistent with specification here: +/// The Framework Specification, StatusCodes 0.92, does not define the macros. +/// +#define EFI_SOFTWARE_X64_EXCEPTION (EFI_SOFTWARE | 0x00130000) + +/// +/// Software Class X64 Exception Subclass Error Code definitions. +/// These exceptions are derived from the debug protocol definitions in the EFI +/// specification. +/// +/// Inconsistent with specification here: +/// The Framework Specification, StatusCodes 0.92, does not define the macros. +/// +///@{ +#define EFI_SW_EC_X64_DIVIDE_ERROR EXCEPT_X64_DIVIDE_ERROR +#define EFI_SW_EC_X64_DEBUG EXCEPT_X64_DEBUG +#define EFI_SW_EC_X64_NMI EXCEPT_X64_NMI +#define EFI_SW_EC_X64_BREAKPOINT EXCEPT_X64_BREAKPOINT +#define EFI_SW_EC_X64_OVERFLOW EXCEPT_X64_OVERFLOW +#define EFI_SW_EC_X64_BOUND EXCEPT_X64_BOUND +#define EFI_SW_EC_X64_INVALID_OPCODE EXCEPT_X64_INVALID_OPCODE +#define EFI_SW_EC_X64_DOUBLE_FAULT EXCEPT_X64_DOUBLE_FAULT +#define EFI_SW_EC_X64_INVALID_TSS EXCEPT_X64_INVALID_TSS +#define EFI_SW_EC_X64_SEG_NOT_PRESENT EXCEPT_X64_SEG_NOT_PRESENT +#define EFI_SW_EC_X64_STACK_FAULT EXCEPT_X64_STACK_FAULT +#define EFI_SW_EC_X64_GP_FAULT EXCEPT_X64_GP_FAULT +#define EFI_SW_EC_X64_PAGE_FAULT EXCEPT_X64_PAGE_FAULT +#define EFI_SW_EC_X64_FP_ERROR EXCEPT_X64_FP_ERROR +#define EFI_SW_EC_X64_ALIGNMENT_CHECK EXCEPT_X64_ALIGNMENT_CHECK +#define EFI_SW_EC_X64_MACHINE_CHECK EXCEPT_X64_MACHINE_CHECK +#define EFI_SW_EC_X64_SIMD EXCEPT_X64_SIMD +///@} + +/// +/// Software Class EFI After Life Subclass Progress Code definitions. +/// +///@{ +#define EFI_SW_AL_PC_ENTRY_POINT (EFI_SUBCLASS_SPECIFIC | 0x00000000) +#define EFI_SW_AL_PC_RETURN_TO_LAST (EFI_SUBCLASS_SPECIFIC | 0x00000001) +///@} + +/// +/// Software Class DXE Core Subclass Error Code definitions. +/// +/// Inconsistent with specification here: +/// The Framework Specification, StatusCodes 0.92, does not define the macros. +/// +#define EFI_SW_CSM_LEGACY_ROM_INIT (EFI_SUBCLASS_SPECIFIC | 0x00000000) + +/// +/// IO Bus Class ATA/ATAPI Subclass Progress Code definitions. +/// +/// +/// Inconsistent with specification here: +/// The Framework Specification, StatusCodes 0.92, does not define the macros. +/// +///@{ +#define EFI_IOB_ATA_BUS_SMART_ENABLE (EFI_SUBCLASS_SPECIFIC | 0x00000000) +#define EFI_IOB_ATA_BUS_SMART_DISABLE (EFI_SUBCLASS_SPECIFIC | 0x00000001) +#define EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD (EFI_SUBCLASS_SPECIFIC | 0x00000002) +#define EFI_IOB_ATA_BUS_SMART_UNDERTHRESHOLD (EFI_SUBCLASS_SPECIFIC | 0x00000003) +///@} + +/// +/// IO Bus Class ATA/ATAPI Subclass Error Code definitions. +/// +/// +/// Inconsistent with specification here: +/// The Framework Specification, StatusCodes 0.92, does not define the macros. +/// +///@{ +#define EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED (EFI_SUBCLASS_SPECIFIC | 0x00000000) +#define EFI_IOB_ATA_BUS_SMART_DISABLED (EFI_SUBCLASS_SPECIFIC | 0x00000001) +///@} + +/// +/// The reason that the processor was disabled. +/// +/// Inconsistent with specification here: +/// The Framework Specification, StatusCodes 0.92, does not define the macros. +/// +///@{ +#define EFI_CPU_CAUSE_NOT_DISABLED 0x0000 +///@} + +/// +/// Software Class PEI Module Subclass Progress Code definitions. +/// +///@{ +#define EFI_SW_PEIM_PC_RECOVERY_BEGIN EFI_SW_PEI_PC_RECOVERY_BEGIN +#define EFI_SW_PEIM_PC_CAPSULE_LOAD EFI_SW_PEI_PC_CAPSULE_LOAD +#define EFI_SW_PEIM_PC_CAPSULE_START EFI_SW_PEI_PC_CAPSULE_START +#define EFI_SW_PEIM_PC_RECOVERY_USER EFI_SW_PEI_PC_RECOVERY_USER +#define EFI_SW_PEIM_PC_RECOVERY_AUTO EFI_SW_PEI_PC_RECOVERY_AUTO +///@} + +/// +/// Software Class PEI Core Subclass Error Code definitions. +/// +///@{ +#define EFI_SW_PEIM_CORE_EC_DXE_CORRUPT EFI_SW_PEI_CORE_EC_DXE_CORRUPT +#define EFI_SW_PEIM_CORE_EC_DXEIPL_NOT_FOUND EFI_SW_PEI_CORE_EC_DXEIPL_NOT_FOUND +///@} + +#endif diff --git a/OvmfPkg/Csm/Include/FrameworkDxe.h b/OvmfPkg/Csm/Include/FrameworkDxe.h new file mode 100644 index 0000000000..1d801960fe --- /dev/null +++ b/OvmfPkg/Csm/Include/FrameworkDxe.h @@ -0,0 +1,26 @@ +/** @file + The root header file that provides Framework extension to UEFI/PI for modules. It can be included by + DXE, RUNTIME and SMM type modules that use Framework definitions. + + + This header file includes Framework extension definitions common to DXE + modules. + +Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _FRAMEWORK_DXE_H_ +#define _FRAMEWORK_DXE_H_ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#endif diff --git a/OvmfPkg/Csm/Include/Guid/LegacyBios.h b/OvmfPkg/Csm/Include/Guid/LegacyBios.h new file mode 100644 index 0000000000..e35fbff8d5 --- /dev/null +++ b/OvmfPkg/Csm/Include/Guid/LegacyBios.h @@ -0,0 +1,29 @@ +/** @file + Defines a Tag GUID used to mark a UEFI legacy BIOS thunk driver based + on legacy BIOS services and legacy option ROM. This Tag GUID must be installed on + the ImageHandle of any module that follows the EFI Driver Model and uses + the Int86() or FarCall() services of the Legacy Bios Protocol to produce + a standard UEFI I/O Protocol. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _LEGACY_BIOS_H_ +#define _LEGACY_BIOS_H_ + +/// +/// The Global ID for the Legacy BIOS GUID that must be installed onto the ImageHandle +/// of any module follows the EFI Driver Model and uses the Int86() or FarCall() +/// services of the Legacy BIOS Protocol to produce a standard UEFI I/O Protocol. +/// +#define EFI_LEGACY_BIOS_GUID \ + { \ + 0x2e3044ac, 0x879f, 0x490f, {0x97, 0x60, 0xbb, 0xdf, 0xaf, 0x69, 0x5f, 0x50 } \ + } + +extern EFI_GUID gEfiLegacyBiosGuid; + +#endif diff --git a/OvmfPkg/Csm/Include/Guid/LegacyDevOrder.h b/OvmfPkg/Csm/Include/Guid/LegacyDevOrder.h new file mode 100644 index 0000000000..8ec3de5e38 --- /dev/null +++ b/OvmfPkg/Csm/Include/Guid/LegacyDevOrder.h @@ -0,0 +1,39 @@ +/** @file + Guid of a NV Variable which store the information about the + FD/HD/CD/NET/BEV order. + +Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __LEGACY_DEV_ORDER_VARIABLE_GUID_H__ +#define __LEGACY_DEV_ORDER_VARIABLE_GUID_H__ + +/// +/// Name and Guid of a NV Variable which stores the information about the +/// FD/HD/CD/NET/BEV order +/// +#define EFI_LEGACY_DEV_ORDER_VARIABLE_GUID \ + { \ + 0xa56074db, 0x65fe, 0x45f7, {0xbd, 0x21, 0x2d, 0x2b, 0xdd, 0x8e, 0x96, 0x52} \ + } + +typedef UINT8 BBS_TYPE; + +#pragma pack(1) +typedef struct { + BBS_TYPE BbsType; + /// + /// Length = sizeof (UINT16) + sizeof (Data) + /// + UINT16 Length; + UINT16 Data[1]; +} LEGACY_DEV_ORDER_ENTRY; +#pragma pack() + +#define VAR_LEGACY_DEV_ORDER L"LegacyDevOrder" + +extern EFI_GUID gEfiLegacyDevOrderVariableGuid; + +#endif diff --git a/OvmfPkg/Csm/Include/Protocol/FirmwareVolume.h b/OvmfPkg/Csm/Include/Protocol/FirmwareVolume.h new file mode 100644 index 0000000000..5e0216c765 --- /dev/null +++ b/OvmfPkg/Csm/Include/Protocol/FirmwareVolume.h @@ -0,0 +1,340 @@ +/** @file + This file declares the Firmware Volume Protocol. + + The Firmware Volume Protocol provides file-level access to the firmware volume. + Each firmware volume driver must produce an instance of the Firmware Volume + Protocol if the firmware volume is to be visible to the system. The Firmware + Volume Protocol also provides mechanisms for determining and modifying some + attributes of the firmware volume. + +Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Revision Reference: + This protocol is defined in Firmware Volume specification. + Version 0.9. + +**/ + +#ifndef _FIRMWARE_VOLUME_H_ +#define _FIRMWARE_VOLUME_H_ + + +// +// Firmware Volume Protocol GUID definition +// +#define EFI_FIRMWARE_VOLUME_PROTOCOL_GUID \ + { \ + 0x389F751F, 0x1838, 0x4388, {0x83, 0x90, 0xCD, 0x81, 0x54, 0xBD, 0x27, 0xF8 } \ + } + +#define FV_DEVICE_SIGNATURE SIGNATURE_32 ('_', 'F', 'V', '_') + +typedef struct _EFI_FIRMWARE_VOLUME_PROTOCOL EFI_FIRMWARE_VOLUME_PROTOCOL; + +// +// FRAMEWORK_EFI_FV_ATTRIBUTES bit definitions +// +typedef UINT64 FRAMEWORK_EFI_FV_ATTRIBUTES; + +// +// ************************************************************ +// FRAMEWORK_EFI_FV_ATTRIBUTES bit definitions +// ************************************************************ +// +#define EFI_FV_READ_DISABLE_CAP 0x0000000000000001ULL +#define EFI_FV_READ_ENABLE_CAP 0x0000000000000002ULL +#define EFI_FV_READ_STATUS 0x0000000000000004ULL + +#define EFI_FV_WRITE_DISABLE_CAP 0x0000000000000008ULL +#define EFI_FV_WRITE_ENABLE_CAP 0x0000000000000010ULL +#define EFI_FV_WRITE_STATUS 0x0000000000000020ULL + +#define EFI_FV_LOCK_CAP 0x0000000000000040ULL +#define EFI_FV_LOCK_STATUS 0x0000000000000080ULL +#define EFI_FV_WRITE_POLICY_RELIABLE 0x0000000000000100ULL + +#define EFI_FV_ALIGNMENT_CAP 0x0000000000008000ULL +#define EFI_FV_ALIGNMENT_2 0x0000000000010000ULL +#define EFI_FV_ALIGNMENT_4 0x0000000000020000ULL +#define EFI_FV_ALIGNMENT_8 0x0000000000040000ULL +#define EFI_FV_ALIGNMENT_16 0x0000000000080000ULL +#define EFI_FV_ALIGNMENT_32 0x0000000000100000ULL +#define EFI_FV_ALIGNMENT_64 0x0000000000200000ULL +#define EFI_FV_ALIGNMENT_128 0x0000000000400000ULL +#define EFI_FV_ALIGNMENT_256 0x0000000000800000ULL +#define EFI_FV_ALIGNMENT_512 0x0000000001000000ULL +#define EFI_FV_ALIGNMENT_1K 0x0000000002000000ULL +#define EFI_FV_ALIGNMENT_2K 0x0000000004000000ULL +#define EFI_FV_ALIGNMENT_4K 0x0000000008000000ULL +#define EFI_FV_ALIGNMENT_8K 0x0000000010000000ULL +#define EFI_FV_ALIGNMENT_16K 0x0000000020000000ULL +#define EFI_FV_ALIGNMENT_32K 0x0000000040000000ULL +#define EFI_FV_ALIGNMENT_64K 0x0000000080000000ULL + +// +// Protocol API definitions +// + +/** + Retrieves attributes, insures positive polarity of attribute bits, and returns + resulting attributes in an output parameter. + + @param This Indicates the EFI_FIRMWARE_VOLUME_PROTOCOL instance. + @param Attributes Output buffer containing attributes. + + @retval EFI_SUCCESS The firmware volume attributes were returned. +**/ +typedef +EFI_STATUS +(EFIAPI *FRAMEWORK_EFI_FV_GET_ATTRIBUTES)( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, + OUT FRAMEWORK_EFI_FV_ATTRIBUTES *Attributes + ); + +/** + Sets volume attributes + + @param This Indicates the EFI_FIRMWARE_VOLUME_PROTOCOL instance. + @param Attributes On input, Attributes is a pointer to an + EFI_FV_ATTRIBUTES containing the desired firmware + volume settings. On successful return, it contains + the new settings of the firmware volume. On + unsuccessful return, Attributes is not modified + and the firmware volume settings are not changed. + + @retval EFI_INVALID_PARAMETER A bit in Attributes was invalid. + @retval EFI_SUCCESS The requested firmware volume attributes were set + and the resulting EFI_FV_ATTRIBUTES is returned in + Attributes. + @retval EFI_ACCESS_DENIED The Device is locked and does not permit modification. + +**/ +typedef +EFI_STATUS +(EFIAPI *FRAMEWORK_EFI_FV_SET_ATTRIBUTES)( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, + IN OUT FRAMEWORK_EFI_FV_ATTRIBUTES *Attributes + ); + +/** + Read the requested file (NameGuid) or file information from the firmware volume + and returns data in Buffer. + + @param This The EFI_FIRMWARE_VOLUME_PROTOCOL instance. + @param NameGuid The pointer to EFI_GUID, which is the filename of + the file to read. + @param Buffer The pointer to pointer to buffer in which contents of file are returned. +
+ If Buffer is NULL, only type, attributes, and size + are returned as there is no output buffer. +
+ If Buffer != NULL and *Buffer == NULL, the output + buffer is allocated from BS pool by ReadFile. +
+ If Buffer != NULL and *Buffer != NULL, the output + buffer has been allocated by the caller and is being + passed in. + @param BufferSize On input: The buffer size. On output: The size + required to complete the read. + @param FoundType The pointer to the type of the file whose data + is returned. + @param FileAttributes The pointer to attributes of the file whose data + is returned. + @param AuthenticationStatus The pointer to the authentication status of the data. + + @retval EFI_SUCCESS The call completed successfully. + @retval EFI_WARN_BUFFER_TOO_SMALL The buffer is too small to contain the requested output. + The buffer filled, and the output is truncated. + @retval EFI_NOT_FOUND NameGuid was not found in the firmware volume. + @retval EFI_DEVICE_ERROR A hardware error occurred when attempting to + access the firmware volume. + @retval EFI_ACCESS_DENIED The firmware volume is configured to disallow reads. + @retval EFI_OUT_OF_RESOURCES An allocation failure occurred. + +**/ +typedef +EFI_STATUS +(EFIAPI *FRAMEWORK_EFI_FV_READ_FILE)( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, + IN EFI_GUID *NameGuid, + IN OUT VOID **Buffer, + IN OUT UINTN *BufferSize, + OUT EFI_FV_FILETYPE *FoundType, + OUT EFI_FV_FILE_ATTRIBUTES *FileAttributes, + OUT UINT32 *AuthenticationStatus + ); + +/** + Read the requested section from the specified file and returns data in Buffer. + + @param This Indicates the EFI_FIRMWARE_VOLUME_PROTOCOL instance. + @param NameGuid Filename identifying the file from which to read. + @param SectionType The section type to retrieve. + @param SectionInstance The instance of SectionType to retrieve. + @param Buffer Pointer to pointer to buffer in which contents of + a file are returned. +
+ If Buffer is NULL, only type, attributes, and size + are returned as there is no output buffer. +
+ If Buffer != NULL and *Buffer == NULL, the output + buffer is allocated from BS pool by ReadFile. +
+ If Buffer != NULL and *Buffer != NULL, the output + buffer has been allocated by the caller and is being + passed in. + @param BufferSize The pointer to the buffer size passed in, and on + output the size required to complete the read. + @param AuthenticationStatus The pointer to the authentication status of the data. + + @retval EFI_SUCCESS The call completed successfully. + @retval EFI_WARN_BUFFER_TOO_SMALL The buffer is too small to contain the requested output. + The buffer is filled and the output is truncated. + @retval EFI_OUT_OF_RESOURCES An allocation failure occurred. + @retval EFI_NOT_FOUND The name was not found in the firmware volume. + @retval EFI_DEVICE_ERROR A hardware error occurred when attempting to + access the firmware volume. + @retval EFI_ACCESS_DENIED The firmware volume is configured to disallow reads. + +**/ +typedef +EFI_STATUS +(EFIAPI *FRAMEWORK_EFI_FV_READ_SECTION)( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, + IN EFI_GUID *NameGuid, + IN EFI_SECTION_TYPE SectionType, + IN UINTN SectionInstance, + IN OUT VOID **Buffer, + IN OUT UINTN *BufferSize, + OUT UINT32 *AuthenticationStatus + ); + +typedef UINT32 FRAMEWORK_EFI_FV_WRITE_POLICY; + +#define FRAMEWORK_EFI_FV_UNRELIABLE_WRITE 0x00000000 +#define FRAMEWORK_EFI_FV_RELIABLE_WRITE 0x00000001 + +typedef struct { + EFI_GUID *NameGuid; + EFI_FV_FILETYPE Type; + EFI_FV_FILE_ATTRIBUTES FileAttributes; + VOID *Buffer; + UINT32 BufferSize; +} FRAMEWORK_EFI_FV_WRITE_FILE_DATA; + +/** + Write the supplied file (NameGuid) to the FV. + + @param This Indicates the EFI_FIRMWARE_VOLUME_PROTOCOL instance. + @param NumberOfFiles Indicates the number of file records pointed to + by FileData. + @param WritePolicy Indicates the level of reliability of the write + with respect to things like power failure events. + @param FileData A pointer to an array of EFI_FV_WRITE_FILE_DATA + structures. Each element in the array indicates + a file to write, and there are NumberOfFiles + elements in the input array. + + @retval EFI_SUCCESS The write completed successfully. + @retval EFI_OUT_OF_RESOURCES The firmware volume does not have enough free + space to store file(s). + @retval EFI_DEVICE_ERROR A hardware error occurred when attempting to + access the firmware volume. + @retval EFI_WRITE_PROTECTED The firmware volume is configured to disallow writes. + @retval EFI_NOT_FOUND A delete was requested, but the requested file was + not found in the firmware volume. + @retval EFI_INVALID_PARAMETER A delete was requested with a multiple file write. + An unsupported WritePolicy was requested. + An unknown file type was specified. + A file system specific error has occurred. +**/ +typedef +EFI_STATUS +(EFIAPI *FRAMEWORK_EFI_FV_WRITE_FILE)( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, + IN UINT32 NumberOfFiles, + IN FRAMEWORK_EFI_FV_WRITE_POLICY WritePolicy, + IN FRAMEWORK_EFI_FV_WRITE_FILE_DATA *FileData + ); + +/** + Given the input key, search for the next matching file in the volume. + + @param This Indicates the EFI_FIRMWARE_VOLUME_PROTOCOL instance. + @param Key Pointer to a caller allocated buffer that contains + an implementation-specific key that is used to track + where to begin searching on successive calls. + @param FileType The pointer to the file type to filter for. + @param NameGuid The pointer to Guid filename of the file found. + @param Attributes The pointer to Attributes of the file found. + @param Size The pointer to Size in bytes of the file found. + + @retval EFI_SUCCESS The output parameters are filled with data obtained from + the first matching file that was found. + @retval EFI_NOT_FOUND No files of type FileType were found. + @retval EFI_DEVICE_ERROR A hardware error occurred when attempting to access + the firmware volume. + @retval EFI_ACCESS_DENIED The firmware volume is configured to disallow reads. + +**/ +typedef +EFI_STATUS +(EFIAPI *FRAMEWORK_EFI_FV_GET_NEXT_FILE)( + IN EFI_FIRMWARE_VOLUME_PROTOCOL *This, + IN OUT VOID *Key, + IN OUT EFI_FV_FILETYPE *FileType, + OUT EFI_GUID *NameGuid, + OUT EFI_FV_FILE_ATTRIBUTES *Attributes, + OUT UINTN *Size + ); + +// +// Protocol interface structure +// +struct _EFI_FIRMWARE_VOLUME_PROTOCOL { + /// + /// Retrieves volume capabilities and current settings. + /// + FRAMEWORK_EFI_FV_GET_ATTRIBUTES GetVolumeAttributes; + + /// + /// Modifies the current settings of the firmware volume. + /// + FRAMEWORK_EFI_FV_SET_ATTRIBUTES SetVolumeAttributes; + + /// + /// Reads an entire file from the firmware volume. + /// + FRAMEWORK_EFI_FV_READ_FILE ReadFile; + + /// + /// Reads a single section from a file into a buffer. + /// + FRAMEWORK_EFI_FV_READ_SECTION ReadSection; + + /// + /// Writes an entire file into the firmware volume. + /// + FRAMEWORK_EFI_FV_WRITE_FILE WriteFile; + + /// + /// Provides service to allow searching the firmware volume. + /// + FRAMEWORK_EFI_FV_GET_NEXT_FILE GetNextFile; + + /// + /// Data field that indicates the size in bytes of the Key input buffer for + /// the GetNextFile() API. + /// + UINT32 KeySize; + + /// + /// Handle of the parent firmware volume. + /// + EFI_HANDLE ParentHandle; +}; + +extern EFI_GUID gEfiFirmwareVolumeProtocolGuid; + +#endif diff --git a/OvmfPkg/Csm/Include/Protocol/IsaAcpi.h b/OvmfPkg/Csm/Include/Protocol/IsaAcpi.h new file mode 100644 index 0000000000..12aeb1227c --- /dev/null +++ b/OvmfPkg/Csm/Include/Protocol/IsaAcpi.h @@ -0,0 +1,298 @@ +/** @file + EFI ISA ACPI Protocol is used to enumerate and manage all the ISA controllers on + the platform's ISA Bus. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __ISA_ACPI_H_ +#define __ISA_ACPI_H_ + +/// +/// Global ID for the EFI ISA ACPI Protocol. +/// +#define EFI_ISA_ACPI_PROTOCOL_GUID \ + { \ + 0x64a892dc, 0x5561, 0x4536, { 0x92, 0xc7, 0x79, 0x9b, 0xfc, 0x18, 0x33, 0x55 } \ + } + +/// +/// Forward declaration fo the EFI ISA ACPI Protocol +/// +typedef struct _EFI_ISA_ACPI_PROTOCOL EFI_ISA_ACPI_PROTOCOL; + +/// +/// ISA ACPI Protocol interrupt resource attributes. +/// +#define EFI_ISA_ACPI_IRQ_TYPE_HIGH_TRUE_EDGE_SENSITIVE 0x01 ///< Edge triggered interrupt on a rising edge. +#define EFI_ISA_ACPI_IRQ_TYPE_LOW_TRUE_EDGE_SENSITIVE 0x02 ///< Edge triggered interrupt on a falling edge. +#define EFI_ISA_ACPI_IRQ_TYPE_HIGH_TRUE_LEVEL_SENSITIVE 0x04 ///< Level sensitive interrupt active high. +#define EFI_ISA_ACPI_IRQ_TYPE_LOW_TRUE_LEVEL_SENSITIVE 0x08 ///< Level sensitive interrupt active low. + +/// +/// ISA ACPI Protocol DMA resource attributes. +/// +#define EFI_ISA_ACPI_DMA_SPEED_TYPE_MASK 0x03 ///< Bit mask of supported DMA speed attributes. +#define EFI_ISA_ACPI_DMA_SPEED_TYPE_COMPATIBILITY 0x00 ///< ISA controller supports compatibility mode DMA transfers. +#define EFI_ISA_ACPI_DMA_SPEED_TYPE_A 0x01 ///< ISA controller supports type A DMA transfers. +#define EFI_ISA_ACPI_DMA_SPEED_TYPE_B 0x02 ///< ISA controller supports type B DMA transfers. +#define EFI_ISA_ACPI_DMA_SPEED_TYPE_F 0x03 ///< ISA controller supports type F DMA transfers. +#define EFI_ISA_ACPI_DMA_COUNT_BY_BYTE 0x04 ///< ISA controller increments DMA address by bytes (8-bit). +#define EFI_ISA_ACPI_DMA_COUNT_BY_WORD 0x08 ///< ISA controller increments DMA address by words (16-bit). +#define EFI_ISA_ACPI_DMA_BUS_MASTER 0x10 ///< ISA controller is a DMA bus master. +#define EFI_ISA_ACPI_DMA_TRANSFER_TYPE_8_BIT 0x20 ///< ISA controller only supports 8-bit DMA transfers. +#define EFI_ISA_ACPI_DMA_TRANSFER_TYPE_8_BIT_AND_16_BIT 0x40 ///< ISA controller both 8-bit and 16-bit DMA transfers. +#define EFI_ISA_ACPI_DMA_TRANSFER_TYPE_16_BIT 0x80 ///< ISA controller only supports 16-bit DMA transfers. + +/// +/// ISA ACPI Protocol MMIO resource attributes +/// +#define EFI_ISA_ACPI_MEMORY_WIDTH_MASK 0x03 ///< Bit mask of supported ISA memory width attributes. +#define EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT 0x00 ///< ISA MMIO region only supports 8-bit access. +#define EFI_ISA_ACPI_MEMORY_WIDTH_16_BIT 0x01 ///< ISA MMIO region only supports 16-bit access. +#define EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT_AND_16_BIT 0x02 ///< ISA MMIO region supports both 8-bit and 16-bit access. +#define EFI_ISA_ACPI_MEMORY_WRITEABLE 0x04 ///< ISA MMIO region supports write transactions. +#define EFI_ISA_ACPI_MEMORY_CACHEABLE 0x08 ///< ISA MMIO region supports being cached. +#define EFI_ISA_ACPI_MEMORY_SHADOWABLE 0x10 ///< ISA MMIO region may be shadowed. +#define EFI_ISA_ACPI_MEMORY_EXPANSION_ROM 0x20 ///< ISA MMIO region is an expansion ROM. + +/// +/// ISA ACPI Protocol I/O resource attributes +/// +#define EFI_ISA_ACPI_IO_DECODE_10_BITS 0x01 ///< ISA controllers uses a 10-bit address decoder for I/O cycles. +#define EFI_ISA_ACPI_IO_DECODE_16_BITS 0x02 ///< ISA controllers uses a 16-bit address decoder for I/O cycles. + +/// +/// EFI ISA ACPI resource type +/// +typedef enum { + EfiIsaAcpiResourceEndOfList, ///< Marks the end if a resource list. + EfiIsaAcpiResourceIo, ///< ISA I/O port resource range. + EfiIsaAcpiResourceMemory, ///< ISA MMIO resource range. + EfiIsaAcpiResourceDma, ///< ISA DMA resource. + EfiIsaAcpiResourceInterrupt ///< ISA interrupt resource. +} EFI_ISA_ACPI_RESOURCE_TYPE; + +/// +/// EFI ISA ACPI generic resource structure +/// +typedef struct { + EFI_ISA_ACPI_RESOURCE_TYPE Type; ///< The type of resource (I/O, MMIO, DMA, Interrupt). + UINT32 Attribute; ///< Bit mask of attributes associated with this resource. See EFI_ISA_ACPI_xxx macros for valid combinations. + UINT32 StartRange; ///< The start of the resource range. + UINT32 EndRange; ///< The end of the resource range. +} EFI_ISA_ACPI_RESOURCE; + +/// +/// EFI ISA ACPI resource device identifier +/// +typedef struct { + UINT32 HID; ///< The ACPI Hardware Identifier value associated with an ISA controller. Matchs ACPI DSDT contents. + UINT32 UID; ///< The ACPI Unique Identifier value associated with an ISA controller. Matches ACPI DSDT contents. +} EFI_ISA_ACPI_DEVICE_ID; + +/// +/// EFI ISA ACPI resource list +/// +typedef struct { + EFI_ISA_ACPI_DEVICE_ID Device; ///< The ACPI HID/UID associated with an ISA controller. + EFI_ISA_ACPI_RESOURCE *ResourceItem; ///< A pointer to the list of resources associated with an ISA controller. +} EFI_ISA_ACPI_RESOURCE_LIST; + +/** + Enumerates the ISA controllers on an ISA bus. + + This service allows all the ISA controllers on an ISA bus to be enumerated. If + Device is a pointer to a NULL value, then the first ISA controller on the ISA + bus is returned in Device and EFI_SUCCESS is returned. If Device is a pointer + to a value that was returned on a prior call to DeviceEnumerate(), then the next + ISA controller on the ISA bus is returned in Device and EFI_SUCCESS is returned. + If Device is a pointer to the last ISA controller on the ISA bus, then + EFI_NOT_FOUND is returned. + + @param[in] This The pointer to the EFI_ISA_ACPI_PROTOCOL instance. + @param[out] Device The pointer to an ISA controller named by ACPI HID/UID. + + @retval EFI_SUCCESS The next ISA controller on the ISA bus was returned. + @retval EFI_NOT_FOUND No device found. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_ACPI_DEVICE_ENUMERATE)( + IN EFI_ISA_ACPI_PROTOCOL *This, + OUT EFI_ISA_ACPI_DEVICE_ID **Device + ); + +/** + Sets the power state of an ISA controller. + + This services sets the power state of the ISA controller specified by Device to + the power state specified by OnOff. TRUE denotes on, FALSE denotes off. + If the power state is sucessfully set on the ISA Controller, then + EFI_SUCCESS is returned. + + @param[in] This The pointer to the EFI_ISA_ACPI_PROTOCOL instance. + @param[in] Device The pointer to an ISA controller named by ACPI HID/UID. + @param[in] OnOff TRUE denotes on, FALSE denotes off. + + @retval EFI_SUCCESS Successfully set the power state of the ISA controller. + @retval Other The ISA controller could not be placed in the requested power state. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_ACPI_SET_DEVICE_POWER)( + IN EFI_ISA_ACPI_PROTOCOL *This, + IN EFI_ISA_ACPI_DEVICE_ID *Device, + IN BOOLEAN OnOff + ); + +/** + Retrieves the current set of resources associated with an ISA controller. + + Retrieves the set of I/O, MMIO, DMA, and interrupt resources currently + assigned to the ISA controller specified by Device. These resources + are returned in ResourceList. + + @param[in] This The pointer to the EFI_ISA_ACPI_PROTOCOL instance. + @param[in] Device The pointer to an ISA controller named by ACPI HID/UID. + @param[out] ResourceList The pointer to the current resource list for Device. + + @retval EFI_SUCCESS Successfully retrieved the current resource list. + @retval EFI_NOT_FOUND The resource list could not be retrieved. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_ACPI_GET_CUR_RESOURCE)( + IN EFI_ISA_ACPI_PROTOCOL *This, + IN EFI_ISA_ACPI_DEVICE_ID *Device, + OUT EFI_ISA_ACPI_RESOURCE_LIST **ResourceList + ); + +/** + Retrieves the set of possible resources that may be assigned to an ISA controller + with SetResource(). + + Retrieves the possible sets of I/O, MMIO, DMA, and interrupt resources for the + ISA controller specified by Device. The sets are returned in ResourceList. + + @param[in] This The pointer to the EFI_ISA_ACPI_PROTOCOL instance. + @param[in] Device The pointer to an ISA controller named by ACPI HID/UID. + @param[out] ResourceList The pointer to the returned list of resource lists. + + @retval EFI_UNSUPPORTED This service is not supported. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_ACPI_GET_POS_RESOURCE)( + IN EFI_ISA_ACPI_PROTOCOL *This, + IN EFI_ISA_ACPI_DEVICE_ID *Device, + OUT EFI_ISA_ACPI_RESOURCE_LIST **ResourceList + ); + +/** + Assigns resources to an ISA controller. + + Assigns the I/O, MMIO, DMA, and interrupt resources specified by ResourceList + to the ISA controller specified by Device. ResourceList must match a resource list returned by GetPosResource() for the same ISA controller. + + @param[in] This The pointer to the EFI_ISA_ACPI_PROTOCOL instance. + @param[in] Device The pointer to an ISA controller named by ACPI HID/UID. + @param[in] ResourceList The pointer to a resources list that must be one of the + resource lists returned by GetPosResource() for the + ISA controller specified by Device. + + @retval EFI_SUCCESS Successfully set resources on the ISA controller. + @retval Other The resources could not be set for the ISA controller. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_ACPI_SET_RESOURCE)( + IN EFI_ISA_ACPI_PROTOCOL *This, + IN EFI_ISA_ACPI_DEVICE_ID *Device, + IN EFI_ISA_ACPI_RESOURCE_LIST *ResourceList + ); + +/** + Enables or disables an ISA controller. + + @param[in] This The pointer to the EFI_ISA_ACPI_PROTOCOL instance. + @param[in] Device The pointer to the ISA controller to enable/disable. + @param[in] Enable TRUE to enable the ISA controller. FALSE to disable the + ISA controller. + + @retval EFI_SUCCESS Successfully enabled/disabled the ISA controller. + @retval Other The ISA controller could not be placed in the requested state. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_ACPI_ENABLE_DEVICE)( + IN EFI_ISA_ACPI_PROTOCOL *This, + IN EFI_ISA_ACPI_DEVICE_ID *Device, + IN BOOLEAN Enable + ); + +/** + Initializes an ISA controller, so that it can be used. This service must be called + before SetResource(), EnableDevice(), or SetPower() will behave as expected. + + @param[in] This The pointer to the EFI_ISA_ACPI_PROTOCOL instance. + @param[in] Device The pointer to an ISA controller named by ACPI HID/UID. + + @retval EFI_SUCCESS Successfully initialized an ISA controller. + @retval Other The ISA controller could not be initialized. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_ACPI_INIT_DEVICE)( + IN EFI_ISA_ACPI_PROTOCOL *This, + IN EFI_ISA_ACPI_DEVICE_ID *Device + ); + +/** + Initializes all the HW states required for the ISA controllers on the ISA bus + to be enumerated and managed by the rest of the services in this prorotol. + This service must be called before any of the other services in this + protocol will function as expected. + + @param[in] This The pointer to the EFI_ISA_ACPI_PROTOCOL instance. + + @retval EFI_SUCCESS Successfully initialized all required hardware states. + @retval Other The ISA interface could not be initialized. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_ACPI_INTERFACE_INIT)( + IN EFI_ISA_ACPI_PROTOCOL *This + ); + +/// +/// The EFI_ISA_ACPI_PROTOCOL provides the services to enumerate and manage +/// ISA controllers on an ISA bus. These services include the ability to initialize, +/// enable, disable, and manage the power state of ISA controllers. It also +/// includes services to query current resources, query possible resources, +/// and assign resources to an ISA controller. +/// +struct _EFI_ISA_ACPI_PROTOCOL { + EFI_ISA_ACPI_DEVICE_ENUMERATE DeviceEnumerate; + EFI_ISA_ACPI_SET_DEVICE_POWER SetPower; + EFI_ISA_ACPI_GET_CUR_RESOURCE GetCurResource; + EFI_ISA_ACPI_GET_POS_RESOURCE GetPosResource; + EFI_ISA_ACPI_SET_RESOURCE SetResource; + EFI_ISA_ACPI_ENABLE_DEVICE EnableDevice; + EFI_ISA_ACPI_INIT_DEVICE InitDevice; + EFI_ISA_ACPI_INTERFACE_INIT InterfaceInit; +}; + +extern EFI_GUID gEfiIsaAcpiProtocolGuid; + +#endif diff --git a/OvmfPkg/Csm/Include/Protocol/IsaIo.h b/OvmfPkg/Csm/Include/Protocol/IsaIo.h new file mode 100644 index 0000000000..30000305fb --- /dev/null +++ b/OvmfPkg/Csm/Include/Protocol/IsaIo.h @@ -0,0 +1,356 @@ +/** @file + ISA I/O Protocol is used by ISA device drivers to perform I/O, MMIO and DMA + operations on the ISA controllers they manage. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EFI_ISA_IO_H_ +#define _EFI_ISA_IO_H_ + +#include + +/// +/// Global ID for the EFI_ISA_IO_PROTOCOL +/// +#define EFI_ISA_IO_PROTOCOL_GUID \ + { \ + 0x7ee2bd44, 0x3da0, 0x11d4, { 0x9a, 0x38, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } + +/// +/// Forward declaration for the EFI_ISA_IO_PROTOCOL. +/// +typedef struct _EFI_ISA_IO_PROTOCOL EFI_ISA_IO_PROTOCOL; + +/// +/// Width of EFI_ISA_IO_PROTOCOL I/O Port and MMIO operations. +/// +typedef enum { + EfiIsaIoWidthUint8 = 0, ///< 8-bit operation. + EfiIsaIoWidthUint16, ///< 16-bit operation. + EfiIsaIoWidthUint32, ///< 32-bit operation + EfiIsaIoWidthReserved, + EfiIsaIoWidthFifoUint8, ///< 8-bit FIFO operation. + EfiIsaIoWidthFifoUint16, ///< 16-bit FIFO operation. + EfiIsaIoWidthFifoUint32, ///< 32-bit FIFO operation. + EfiIsaIoWidthFifoReserved, + EfiIsaIoWidthFillUint8, ///< 8-bit Fill operation. + EfiIsaIoWidthFillUint16, ///< 16-bit Fill operation. + EfiIsaIoWidthFillUint32, ///< 32-bit Fill operation. + EfiIsaIoWidthFillReserved, + EfiIsaIoWidthMaximum +} EFI_ISA_IO_PROTOCOL_WIDTH; + +/// +/// Attributes for the EFI_ISA_IO_PROTOCOL common DMA buffer allocations. +/// +#define EFI_ISA_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE 0x080 ///< Map a memory range so write are combined. +#define EFI_ISA_IO_ATTRIBUTE_MEMORY_CACHED 0x800 ///< Map a memory range so all read and write accesses are cached. +#define EFI_ISA_IO_ATTRIBUTE_MEMORY_DISABLE 0x1000 ///< Disable a memory range. + +/// +/// Channel attribute for EFI_ISA_IO_PROTOCOL slave DMA requests +/// +#define EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_COMPATIBLE 0x001 ///< Set the speed of the DMA transfer in compatible mode. +#define EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_A 0x002 ///< Not supported. +#define EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_B 0x004 ///< Not supported. +#define EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_C 0x008 ///< Not supported. +#define EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8 0x010 ///< Request 8-bit DMA transfers. Only available on channels 0..3. +#define EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16 0x020 ///< Request 16-bit DMA transfers. Only available on channels 4..7. +#define EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE 0x040 ///< Request a single DMA transfer. +#define EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE 0x080 ///< Request multiple DMA transfers until TC (Terminal Count) or EOP (End of Process). +#define EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_AUTO_INITIALIZE 0x100 ///< Automatically reload base and count at the end of the DMA transfer. + +/// +/// The DMA opreration type for EFI_ISA_IO_PROTOCOL DMA requests. +/// +typedef enum { + /// + /// A read operation from system memory by a bus master. + /// + EfiIsaIoOperationBusMasterRead, + /// + /// A write operation to system memory by a bus master. + /// + EfiIsaIoOperationBusMasterWrite, + /// + /// Provides both read and write access to system memory by both the processor + /// and a bus master. The buffer is coherent from both the processor's and the + /// bus master's point of view. + /// + EfiIsaIoOperationBusMasterCommonBuffer, + /// + /// A read operation from system memory by a slave device. + /// + EfiIsaIoOperationSlaveRead, + /// + /// A write operation to system memory by a slave master. + /// + EfiIsaIoOperationSlaveWrite, + EfiIsaIoOperationMaximum +} EFI_ISA_IO_PROTOCOL_OPERATION; + +/** + Performs ISA I/O and MMIO Read/Write Cycles + + @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance. + @param[in] Width Specifies the width of the I/O or MMIO operation. + @param[in] Offset The offset into the ISA I/O or MMIO space to start the + operation. + @param[in] Count The number of I/O or MMIO operations to perform. + @param[in, out] Buffer For read operations, the destination buffer to store + the results. For write operations, the source buffer to + write data from. + + @retval EFI_SUCCESS The data was successfully read from or written to the device. + @retval EFI_UNSUPPORTED The Offset is not valid for this device. + @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_IO_PROTOCOL_IO_MEM)( + IN EFI_ISA_IO_PROTOCOL *This, + IN EFI_ISA_IO_PROTOCOL_WIDTH Width, + IN UINT32 Offset, + IN UINTN Count, + IN OUT VOID *Buffer + ); + +/// +/// Structure of functions for accessing ISA I/O and MMIO space. +/// +typedef struct { + /// + /// Read from ISA I/O or MMIO space. + /// + EFI_ISA_IO_PROTOCOL_IO_MEM Read; + /// + /// Write to ISA I/O or MMIO space. + /// + EFI_ISA_IO_PROTOCOL_IO_MEM Write; +} EFI_ISA_IO_PROTOCOL_ACCESS; + +/** + Copies data from one region of ISA MMIO space to another region of ISA + MMIO space. + + @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance. + @param[in] Width Specifies the width of the MMIO copy operation. + @param[in] DestOffset The offset of the destination in ISA MMIO space. + @param[in] SrcOffset The offset of the source in ISA MMIO space. + @param[in] Count The number tranfers to perform for this copy operation. + + @retval EFI_SUCCESS The data was copied sucessfully. + @retval EFI_UNSUPPORTED The DestOffset or SrcOffset is not valid for this device. + @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_IO_PROTOCOL_COPY_MEM)( + IN EFI_ISA_IO_PROTOCOL *This, + IN EFI_ISA_IO_PROTOCOL_WIDTH Width, + IN UINT32 DestOffset, + IN UINT32 SrcOffset, + IN UINTN Count + ); + +/** + Maps a memory region for DMA. + + This function returns the device-specific addresses required to access system memory. + This function is used to map system memory for ISA DMA operations. All ISA DMA + operations must be performed through their mapped addresses, and such mappings must + be freed with EFI_ISA_IO_PROTOCOL.Unmap() after the DMA operation is completed. + + If the DMA operation is a single read or write data transfer through an ISA bus + master, then EfiIsaIoOperationBusMasterRead or EfiIsaIoOperationBusMasterWrite + is used and the range is unmapped to complete the operation. If the DMA operation + is a single read or write data transfer through an ISA slave controller, then + EfiIsaIoOperationSlaveRead or EfiIsaIoOperationSlaveWrite is used and the range + is unmapped to complete the operation. + + If performing a DMA read operation, all the data must be present in system memory before the Map() is performed. Similarly, + if performing a DMA write operation, the data must not be accessed in system + memory until EFI_ISA_IO_PROTOCOL.Unmap() is performed. Bus master operations that + require both read and write access or require multiple host device interactions + within the same mapped region must use EfiIsaIoOperationBusMasterCommonBuffer. + However, only memory allocated via the EFI_ISA_IO_PROTOCOL.AllocateBuffer() interface + is guaranteed to be able to be mapped for this operation type. In all mapping + requests the NumberOfBytes returned may be less than originally requested. It is + the caller's responsibility to make additional requests to complete the entire + transfer. + + @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance. + @param[in] Operation Indicates the type of DMA (slave or bus master), + and if the DMA operation is going to read or + write to system memory. + @param[in] ChannelNumber The slave channel number to use for this DMA + operation. If Operation and ChannelAttributes + shows that this device performs bus mastering + DMA, then this field is ignored. The legal + range for this field is 0..7. + @param[in] ChannelAttributes A bitmask of the attributes used to configure + the slave DMA channel for this DMA operation. + See EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_* for the + legal bit combinations. + @param[in] HostAddress The system memory address to map to the device. + @param[in, out] NumberOfBytes On input the number of bytes to map. On + output the number of bytes that were mapped. + @param[out] DeviceAddress The resulting map address for the bus master + device to use to access the hosts HostAddress. + @param[out] Mapping A returned value that must be passed to into + EFI_ISA_IO_PROTOCOL.Unmap() to free all the the + resources associated with this map request. + + @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes. + @retval EFI_INVALID_PARAMETER The Operation is undefined. + @retval EFI_INVALID_PARAMETER The HostAddress is undefined. + @retval EFI_UNSUPPORTED The HostAddress can not be mapped as a common buffer. + @retval EFI_DEVICE_ERROR The system hardware could not map the requested address. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_IO_PROTOCOL_MAP)( + IN EFI_ISA_IO_PROTOCOL *This, + IN EFI_ISA_IO_PROTOCOL_OPERATION Operation, + IN UINT8 ChannelNumber OPTIONAL, + IN UINT32 ChannelAttributes, + IN VOID *HostAddress, + IN OUT UINTN *NumberOfBytes, + OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, + OUT VOID **Mapping + ); + +/** + Unmaps a memory region that was previously mapped with EFI_ISA_IO_PROTOCOL.Map(). + + The EFI_ISA_IO_PROTOCOL.Map() operation is completed and any corresponding + resources are released. If the operation was EfiIsaIoOperationSlaveWrite + or EfiIsaIoOperationBusMasterWrite, the data is committed to system memory. + Any resources used for the mapping are freed. + + @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance. + @param[in] Mapping The mapping value returned from EFI_ISA_IO_PROTOCOL.Map(). + + @retval EFI_SUCCESS The memory region was unmapped. + @retval EFI_DEVICE_ERROR The data was not committed to the target system memory. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_IO_PROTOCOL_UNMAP)( + IN EFI_ISA_IO_PROTOCOL *This, + IN VOID *Mapping + ); + +/** + Allocates pages that are suitable for an EfiIsaIoOperationBusMasterCommonBuffer + mapping. + + @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance. + @param[in] Type The type allocation to perform. + @param[in] MemoryType The type of memory to allocate. + @param[in] Pages The number of pages to allocate. + @param[out] HostAddress A pointer to store the base address of the allocated range. + @param[in] Attributes The requested bit mask of attributes for the allocated range. + + @retval EFI_SUCCESS The requested memory pages were allocated. + @retval EFI_INVALID_PARAMETER Type is invalid. + @retval EFI_INVALID_PARAMETER MemoryType is invalid. + @retval EFI_INVALID_PARAMETER HostAddress is NULL. + @retval EFI_UNSUPPORTED Attributes is unsupported. + @retval EFI_UNSUPPORTED The memory range specified by HostAddress, Pages, + and Type is not available for common buffer use. + @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_IO_PROTOCOL_ALLOCATE_BUFFER)( + IN EFI_ISA_IO_PROTOCOL *This, + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + OUT VOID **HostAddress, + IN UINT64 Attributes + ); + +/** + Frees a common buffer that was allocated with EFI_ISA_IO_PROTOCOL.AllocateBuffer(). + + @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance. + @param[in] Pages The number of pages to free from the previously allocated common buffer. + @param[in] HostAddress The base address of the previously allocated common buffer. + + + @retval EFI_SUCCESS The requested memory pages were freed. + @retval EFI_INVALID_PARAMETER The memory was not allocated with EFI_ISA_IO.AllocateBufer(). + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_IO_PROTOCOL_FREE_BUFFER)( + IN EFI_ISA_IO_PROTOCOL *This, + IN UINTN Pages, + IN VOID *HostAddress + ); + +/** + Flushes a DMA buffer, which forces all DMA posted write transactions to complete. + + @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance. + + @retval EFI_SUCCESS The DMA buffers were flushed. + @retval EFI_DEVICE_ERROR The buffers were not flushed due to a hardware error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_ISA_IO_PROTOCOL_FLUSH)( + IN EFI_ISA_IO_PROTOCOL *This + ); + +/// +/// The EFI_ISA_IO_PROTOCOL provides the basic Memory, I/O, and DMA interfaces +/// used to abstract accesses to ISA controllers. There is one EFI_ISA_IO_PROTOCOL +/// instance for each ISA controller on a ISA bus. A device driver that wishes +/// to manage an ISA controller in a system will have to retrieve the +/// ISA_PCI_IO_PROTOCOL instance associated with the ISA controller. +/// +struct _EFI_ISA_IO_PROTOCOL { + EFI_ISA_IO_PROTOCOL_ACCESS Mem; + EFI_ISA_IO_PROTOCOL_ACCESS Io; + EFI_ISA_IO_PROTOCOL_COPY_MEM CopyMem; + EFI_ISA_IO_PROTOCOL_MAP Map; + EFI_ISA_IO_PROTOCOL_UNMAP Unmap; + EFI_ISA_IO_PROTOCOL_ALLOCATE_BUFFER AllocateBuffer; + EFI_ISA_IO_PROTOCOL_FREE_BUFFER FreeBuffer; + EFI_ISA_IO_PROTOCOL_FLUSH Flush; + /// + /// The list of I/O , MMIO, DMA, and Interrupt resources associated with the + /// ISA controller abstracted by this instance of the EFI_ISA_IO_PROTOCOL. + /// + EFI_ISA_ACPI_RESOURCE_LIST *ResourceList; + /// + /// The size, in bytes, of the ROM image. + /// + UINT32 RomSize; + /// + /// A pointer to the in memory copy of the ROM image. The ISA Bus Driver is responsible + /// for allocating memory for the ROM image, and copying the contents of the ROM to memory + /// during ISA Bus initialization. + /// + VOID *RomImage; +}; + +extern EFI_GUID gEfiIsaIoProtocolGuid; + +#endif diff --git a/OvmfPkg/Csm/Include/Protocol/LegacyBios.h b/OvmfPkg/Csm/Include/Protocol/LegacyBios.h new file mode 100644 index 0000000000..36761da397 --- /dev/null +++ b/OvmfPkg/Csm/Include/Protocol/LegacyBios.h @@ -0,0 +1,1553 @@ +/** @file + The EFI Legacy BIOS Protocol is used to abstract legacy Option ROM usage + under EFI and Legacy OS boot. This file also includes all the related + COMPATIBILIY16 structures and defintions. + + Note: The names for EFI_IA32_REGISTER_SET elements were picked to follow + well known naming conventions. + + Thunk is the code that switches from 32-bit protected environment into the 16-bit real-mode + environment. Reverse thunk is the code that does the opposite. + +Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Revision Reference: + This protocol is defined in Framework for EFI Compatibility Support Module spec + Version 0.98. + +**/ + +#ifndef _EFI_LEGACY_BIOS_H_ +#define _EFI_LEGACY_BIOS_H_ + +/// +/// +/// +#pragma pack(1) + +typedef UINT8 SERIAL_MODE; +typedef UINT8 PARALLEL_MODE; + +#define EFI_COMPATIBILITY16_TABLE_SIGNATURE SIGNATURE_32 ('I', 'F', 'E', '$') + +/// +/// There is a table located within the traditional BIOS in either the 0xF000:xxxx or 0xE000:xxxx +/// physical address range. It is located on a 16-byte boundary and provides the physical address of the +/// entry point for the Compatibility16 functions. These functions provide the platform-specific +/// information that is required by the generic EfiCompatibility code. The functions are invoked via +/// thunking by using EFI_LEGACY_BIOS_PROTOCOL.FarCall86() with the 32-bit physical +/// entry point. +/// +typedef struct { + /// + /// The string "$EFI" denotes the start of the EfiCompatibility table. Byte 0 is "I," byte + /// 1 is "F," byte 2 is "E," and byte 3 is "$" and is normally accessed as a DWORD or UINT32. + /// + UINT32 Signature; + + /// + /// The value required such that byte checksum of TableLength equals zero. + /// + UINT8 TableChecksum; + + /// + /// The length of this table. + /// + UINT8 TableLength; + + /// + /// The major EFI revision for which this table was generated. + /// + UINT8 EfiMajorRevision; + + /// + /// The minor EFI revision for which this table was generated. + /// + UINT8 EfiMinorRevision; + + /// + /// The major revision of this table. + /// + UINT8 TableMajorRevision; + + /// + /// The minor revision of this table. + /// + UINT8 TableMinorRevision; + + /// + /// Reserved for future usage. + /// + UINT16 Reserved; + + /// + /// The segment of the entry point within the traditional BIOS for Compatibility16 functions. + /// + UINT16 Compatibility16CallSegment; + + /// + /// The offset of the entry point within the traditional BIOS for Compatibility16 functions. + /// + UINT16 Compatibility16CallOffset; + + /// + /// The segment of the entry point within the traditional BIOS for EfiCompatibility + /// to invoke the PnP installation check. + /// + UINT16 PnPInstallationCheckSegment; + + /// + /// The Offset of the entry point within the traditional BIOS for EfiCompatibility + /// to invoke the PnP installation check. + /// + UINT16 PnPInstallationCheckOffset; + + /// + /// EFI system resources table. Type EFI_SYSTEM_TABLE is defined in the IntelPlatform + ///Innovation Framework for EFI Driver Execution Environment Core Interface Specification (DXE CIS). + /// + UINT32 EfiSystemTable; + + /// + /// The address of an OEM-provided identifier string. The string is null terminated. + /// + UINT32 OemIdStringPointer; + + /// + /// The 32-bit physical address where ACPI RSD PTR is stored within the traditional + /// BIOS. The remained of the ACPI tables are located at their EFI addresses. The size + /// reserved is the maximum for ACPI 2.0. The EfiCompatibility will fill in the ACPI + /// RSD PTR with either the ACPI 1.0b or 2.0 values. + /// + UINT32 AcpiRsdPtrPointer; + + /// + /// The OEM revision number. Usage is undefined but provided for OEM module usage. + /// + UINT16 OemRevision; + + /// + /// The 32-bit physical address where INT15 E820 data is stored within the traditional + /// BIOS. The EfiCompatibility code will fill in the E820Pointer value and copy the + /// data to the indicated area. + /// + UINT32 E820Pointer; + + /// + /// The length of the E820 data and is filled in by the EfiCompatibility code. + /// + UINT32 E820Length; + + /// + /// The 32-bit physical address where the $PIR table is stored in the traditional BIOS. + /// The EfiCompatibility code will fill in the IrqRoutingTablePointer value and + /// copy the data to the indicated area. + /// + UINT32 IrqRoutingTablePointer; + + /// + /// The length of the $PIR table and is filled in by the EfiCompatibility code. + /// + UINT32 IrqRoutingTableLength; + + /// + /// The 32-bit physical address where the MP table is stored in the traditional BIOS. + /// The EfiCompatibility code will fill in the MpTablePtr value and copy the data + /// to the indicated area. + /// + UINT32 MpTablePtr; + + /// + /// The length of the MP table and is filled in by the EfiCompatibility code. + /// + UINT32 MpTableLength; + + /// + /// The segment of the OEM-specific INT table/code. + /// + UINT16 OemIntSegment; + + /// + /// The offset of the OEM-specific INT table/code. + /// + UINT16 OemIntOffset; + + /// + /// The segment of the OEM-specific 32-bit table/code. + /// + UINT16 Oem32Segment; + + /// + /// The offset of the OEM-specific 32-bit table/code. + /// + UINT16 Oem32Offset; + + /// + /// The segment of the OEM-specific 16-bit table/code. + /// + UINT16 Oem16Segment; + + /// + /// The offset of the OEM-specific 16-bit table/code. + /// + UINT16 Oem16Offset; + + /// + /// The segment of the TPM binary passed to 16-bit CSM. + /// + UINT16 TpmSegment; + + /// + /// The offset of the TPM binary passed to 16-bit CSM. + /// + UINT16 TpmOffset; + + /// + /// A pointer to a string identifying the independent BIOS vendor. + /// + UINT32 IbvPointer; + + /// + /// This field is NULL for all systems not supporting PCI Express. This field is the base + /// value of the start of the PCI Express memory-mapped configuration registers and + /// must be filled in prior to EfiCompatibility code issuing the Compatibility16 function + /// Compatibility16InitializeYourself(). + /// Compatibility16InitializeYourself() is defined in Compatability16 + /// Functions. + /// + UINT32 PciExpressBase; + + /// + /// Maximum PCI bus number assigned. + /// + UINT8 LastPciBus; + + /// + /// Start Address of Upper Memory Area (UMA) to be set as Read/Write. If + /// UmaAddress is a valid address in the shadow RAM, it also indicates that the region + /// from 0xC0000 to (UmaAddress - 1) can be used for Option ROM. + /// + UINT32 UmaAddress; + + /// + /// Upper Memory Area size in bytes to be set as Read/Write. If zero, no UMA region + /// will be set as Read/Write (i.e. all Shadow RAM is set as Read-Only). + /// + UINT32 UmaSize; + + /// + /// Start Address of high memory that can be used for permanent allocation. If zero, + /// high memory is not available for permanent allocation. + /// + UINT32 HiPermanentMemoryAddress; + + /// + /// Size of high memory that can be used for permanent allocation in bytes. If zero, + /// high memory is not available for permanent allocation. + /// + UINT32 HiPermanentMemorySize; +} EFI_COMPATIBILITY16_TABLE; + +/// +/// Functions provided by the CSM binary which communicate between the EfiCompatibility +/// and Compatability16 code. +/// +/// Inconsistent with the specification here: +/// The member's name started with "Compatibility16" [defined in Intel Framework +/// Compatibility Support Module Specification / 0.97 version] +/// has been changed to "Legacy16" since keeping backward compatible. +/// +typedef enum { + /// + /// Causes the Compatibility16 code to do any internal initialization required. + /// Input: + /// AX = Compatibility16InitializeYourself + /// ES:BX = Pointer to EFI_TO_COMPATIBILITY16_INIT_TABLE + /// Return: + /// AX = Return Status codes + /// + Legacy16InitializeYourself = 0x0000, + + /// + /// Causes the Compatibility16 BIOS to perform any drive number translations to match the boot sequence. + /// Input: + /// AX = Compatibility16UpdateBbs + /// ES:BX = Pointer to EFI_TO_COMPATIBILITY16_BOOT_TABLE + /// Return: + /// AX = Returned status codes + /// + Legacy16UpdateBbs = 0x0001, + + /// + /// Allows the Compatibility16 code to perform any final actions before booting. The Compatibility16 + /// code is read/write. + /// Input: + /// AX = Compatibility16PrepareToBoot + /// ES:BX = Pointer to EFI_TO_COMPATIBILITY16_BOOT_TABLE structure + /// Return: + /// AX = Returned status codes + /// + Legacy16PrepareToBoot = 0x0002, + + /// + /// Causes the Compatibility16 BIOS to boot. The Compatibility16 code is Read/Only. + /// Input: + /// AX = Compatibility16Boot + /// Output: + /// AX = Returned status codes + /// + Legacy16Boot = 0x0003, + + /// + /// Allows the Compatibility16 code to get the last device from which a boot was attempted. This is + /// stored in CMOS and is the priority number of the last attempted boot device. + /// Input: + /// AX = Compatibility16RetrieveLastBootDevice + /// Output: + /// AX = Returned status codes + /// BX = Priority number of the boot device. + /// + Legacy16RetrieveLastBootDevice = 0x0004, + + /// + /// Allows the Compatibility16 code rehook INT13, INT18, and/or INT19 after dispatching a legacy OpROM. + /// Input: + /// AX = Compatibility16DispatchOprom + /// ES:BX = Pointer to EFI_DISPATCH_OPROM_TABLE + /// Output: + /// AX = Returned status codes + /// BX = Number of non-BBS-compliant devices found. Equals 0 if BBS compliant. + /// + Legacy16DispatchOprom = 0x0005, + + /// + /// Finds a free area in the 0xFxxxx or 0xExxxx region of the specified length and returns the address + /// of that region. + /// Input: + /// AX = Compatibility16GetTableAddress + /// BX = Allocation region + /// 00 = Allocate from either 0xE0000 or 0xF0000 64 KB blocks. + /// Bit 0 = 1 Allocate from 0xF0000 64 KB block + /// Bit 1 = 1 Allocate from 0xE0000 64 KB block + /// CX = Requested length in bytes. + /// DX = Required address alignment. Bit mapped. First non-zero bit from the right is the alignment. + /// Output: + /// AX = Returned status codes + /// DS:BX = Address of the region + /// + Legacy16GetTableAddress = 0x0006, + + /// + /// Enables the EfiCompatibility module to do any nonstandard processing of keyboard LEDs or state. + /// Input: + /// AX = Compatibility16SetKeyboardLeds + /// CL = LED status. + /// Bit 0 Scroll Lock 0 = Off + /// Bit 1 NumLock + /// Bit 2 Caps Lock + /// Output: + /// AX = Returned status codes + /// + Legacy16SetKeyboardLeds = 0x0007, + + /// + /// Enables the EfiCompatibility module to install an interrupt handler for PCI mass media devices that + /// do not have an OpROM associated with them. An example is SATA. + /// Input: + /// AX = Compatibility16InstallPciHandler + /// ES:BX = Pointer to EFI_LEGACY_INSTALL_PCI_HANDLER structure + /// Output: + /// AX = Returned status codes + /// + Legacy16InstallPciHandler = 0x0008 +} EFI_COMPATIBILITY_FUNCTIONS; + + +/// +/// EFI_DISPATCH_OPROM_TABLE +/// +typedef struct { + UINT16 PnPInstallationCheckSegment; ///< A pointer to the PnpInstallationCheck data structure. + UINT16 PnPInstallationCheckOffset; ///< A pointer to the PnpInstallationCheck data structure. + UINT16 OpromSegment; ///< The segment where the OpROM was placed. Offset is assumed to be 3. + UINT8 PciBus; ///< The PCI bus. + UINT8 PciDeviceFunction; ///< The PCI device * 0x08 | PCI function. + UINT8 NumberBbsEntries; ///< The number of valid BBS table entries upon entry and exit. The IBV code may + ///< increase this number, if BBS-compliant devices also hook INTs in order to force the + ///< OpROM BIOS Setup to be executed. + UINT32 BbsTablePointer; ///< A pointer to the BBS table. + UINT16 RuntimeSegment; ///< The segment where the OpROM can be relocated to. If this value is 0x0000, this + ///< means that the relocation of this run time code is not supported. + ///< Inconsistent with specification here: + ///< The member's name "OpromDestinationSegment" [defined in Intel Framework Compatibility Support Module Specification / 0.97 version] + ///< has been changed to "RuntimeSegment" since keeping backward compatible. + +} EFI_DISPATCH_OPROM_TABLE; + +/// +/// EFI_TO_COMPATIBILITY16_INIT_TABLE +/// +typedef struct { + /// + /// Starting address of memory under 1 MB. The ending address is assumed to be 640 KB or 0x9FFFF. + /// + UINT32 BiosLessThan1MB; + + /// + /// The starting address of the high memory block. + /// + UINT32 HiPmmMemory; + + /// + /// The length of high memory block. + /// + UINT32 HiPmmMemorySizeInBytes; + + /// + /// The segment of the reverse thunk call code. + /// + UINT16 ReverseThunkCallSegment; + + /// + /// The offset of the reverse thunk call code. + /// + UINT16 ReverseThunkCallOffset; + + /// + /// The number of E820 entries copied to the Compatibility16 BIOS. + /// + UINT32 NumberE820Entries; + + /// + /// The amount of usable memory above 1 MB, e.g., E820 type 1 memory. + /// + UINT32 OsMemoryAbove1Mb; + + /// + /// The start of thunk code in main memory. Memory cannot be used by BIOS or PMM. + /// + UINT32 ThunkStart; + + /// + /// The size of the thunk code. + /// + UINT32 ThunkSizeInBytes; + + /// + /// Starting address of memory under 1 MB. + /// + UINT32 LowPmmMemory; + + /// + /// The length of low Memory block. + /// + UINT32 LowPmmMemorySizeInBytes; +} EFI_TO_COMPATIBILITY16_INIT_TABLE; + +/// +/// DEVICE_PRODUCER_SERIAL. +/// +typedef struct { + UINT16 Address; ///< I/O address assigned to the serial port. + UINT8 Irq; ///< IRQ assigned to the serial port. + SERIAL_MODE Mode; ///< Mode of serial port. Values are defined below. +} DEVICE_PRODUCER_SERIAL; + +/// +/// DEVICE_PRODUCER_SERIAL's modes. +///@{ +#define DEVICE_SERIAL_MODE_NORMAL 0x00 +#define DEVICE_SERIAL_MODE_IRDA 0x01 +#define DEVICE_SERIAL_MODE_ASK_IR 0x02 +#define DEVICE_SERIAL_MODE_DUPLEX_HALF 0x00 +#define DEVICE_SERIAL_MODE_DUPLEX_FULL 0x10 +///@) + +/// +/// DEVICE_PRODUCER_PARALLEL. +/// +typedef struct { + UINT16 Address; ///< I/O address assigned to the parallel port. + UINT8 Irq; ///< IRQ assigned to the parallel port. + UINT8 Dma; ///< DMA assigned to the parallel port. + PARALLEL_MODE Mode; ///< Mode of the parallel port. Values are defined below. +} DEVICE_PRODUCER_PARALLEL; + +/// +/// DEVICE_PRODUCER_PARALLEL's modes. +///@{ +#define DEVICE_PARALLEL_MODE_MODE_OUTPUT_ONLY 0x00 +#define DEVICE_PARALLEL_MODE_MODE_BIDIRECTIONAL 0x01 +#define DEVICE_PARALLEL_MODE_MODE_EPP 0x02 +#define DEVICE_PARALLEL_MODE_MODE_ECP 0x03 +///@} + +/// +/// DEVICE_PRODUCER_FLOPPY +/// +typedef struct { + UINT16 Address; ///< I/O address assigned to the floppy. + UINT8 Irq; ///< IRQ assigned to the floppy. + UINT8 Dma; ///< DMA assigned to the floppy. + UINT8 NumberOfFloppy; ///< Number of floppies in the system. +} DEVICE_PRODUCER_FLOPPY; + +/// +/// LEGACY_DEVICE_FLAGS +/// +typedef struct { + UINT32 A20Kybd : 1; ///< A20 controller by keyboard controller. + UINT32 A20Port90 : 1; ///< A20 controlled by port 0x92. + UINT32 Reserved : 30; ///< Reserved for future usage. +} LEGACY_DEVICE_FLAGS; + +/// +/// DEVICE_PRODUCER_DATA_HEADER +/// +typedef struct { + DEVICE_PRODUCER_SERIAL Serial[4]; ///< Data for serial port x. Type DEVICE_PRODUCER_SERIAL is defined below. + DEVICE_PRODUCER_PARALLEL Parallel[3]; ///< Data for parallel port x. Type DEVICE_PRODUCER_PARALLEL is defined below. + DEVICE_PRODUCER_FLOPPY Floppy; ///< Data for floppy. Type DEVICE_PRODUCER_FLOPPY is defined below. + UINT8 MousePresent; ///< Flag to indicate if mouse is present. + LEGACY_DEVICE_FLAGS Flags; ///< Miscellaneous Boolean state information passed to CSM. +} DEVICE_PRODUCER_DATA_HEADER; + +/// +/// ATAPI_IDENTIFY +/// +typedef struct { + UINT16 Raw[256]; ///< Raw data from the IDE IdentifyDrive command. +} ATAPI_IDENTIFY; + +/// +/// HDD_INFO +/// +typedef struct { + /// + /// Status of IDE device. Values are defined below. There is one HDD_INFO structure + /// per IDE controller. The IdentifyDrive is per drive. Index 0 is master and index + /// 1 is slave. + /// + UINT16 Status; + + /// + /// PCI bus of IDE controller. + /// + UINT32 Bus; + + /// + /// PCI device of IDE controller. + /// + UINT32 Device; + + /// + /// PCI function of IDE controller. + /// + UINT32 Function; + + /// + /// Command ports base address. + /// + UINT16 CommandBaseAddress; + + /// + /// Control ports base address. + /// + UINT16 ControlBaseAddress; + + /// + /// Bus master address. + /// + UINT16 BusMasterAddress; + + UINT8 HddIrq; + + /// + /// Data that identifies the drive data; one per possible attached drive. + /// + ATAPI_IDENTIFY IdentifyDrive[2]; +} HDD_INFO; + +/// +/// HDD_INFO status bits +/// +#define HDD_PRIMARY 0x01 +#define HDD_SECONDARY 0x02 +#define HDD_MASTER_ATAPI_CDROM 0x04 +#define HDD_SLAVE_ATAPI_CDROM 0x08 +#define HDD_MASTER_IDE 0x20 +#define HDD_SLAVE_IDE 0x40 +#define HDD_MASTER_ATAPI_ZIPDISK 0x10 +#define HDD_SLAVE_ATAPI_ZIPDISK 0x80 + +/// +/// BBS_STATUS_FLAGS;\. +/// +typedef struct { + UINT16 OldPosition : 4; ///< Prior priority. + UINT16 Reserved1 : 4; ///< Reserved for future use. + UINT16 Enabled : 1; ///< If 0, ignore this entry. + UINT16 Failed : 1; ///< 0 = Not known if boot failure occurred. + ///< 1 = Boot attempted failed. + + /// + /// State of media present. + /// 00 = No bootable media is present in the device. + /// 01 = Unknown if a bootable media present. + /// 10 = Media is present and appears bootable. + /// 11 = Reserved. + /// + UINT16 MediaPresent : 2; + UINT16 Reserved2 : 4; ///< Reserved for future use. +} BBS_STATUS_FLAGS; + +/// +/// BBS_TABLE, device type values & boot priority values. +/// +typedef struct { + /// + /// The boot priority for this boot device. Values are defined below. + /// + UINT16 BootPriority; + + /// + /// The PCI bus for this boot device. + /// + UINT32 Bus; + + /// + /// The PCI device for this boot device. + /// + UINT32 Device; + + /// + /// The PCI function for the boot device. + /// + UINT32 Function; + + /// + /// The PCI class for this boot device. + /// + UINT8 Class; + + /// + /// The PCI Subclass for this boot device. + /// + UINT8 SubClass; + + /// + /// Segment:offset address of an ASCIIZ description string describing the manufacturer. + /// + UINT16 MfgStringOffset; + + /// + /// Segment:offset address of an ASCIIZ description string describing the manufacturer. + /// + UINT16 MfgStringSegment; + + /// + /// BBS device type. BBS device types are defined below. + /// + UINT16 DeviceType; + + /// + /// Status of this boot device. Type BBS_STATUS_FLAGS is defined below. + /// + BBS_STATUS_FLAGS StatusFlags; + + /// + /// Segment:Offset address of boot loader for IPL devices or install INT13 handler for + /// BCV devices. + /// + UINT16 BootHandlerOffset; + + /// + /// Segment:Offset address of boot loader for IPL devices or install INT13 handler for + /// BCV devices. + /// + UINT16 BootHandlerSegment; + + /// + /// Segment:offset address of an ASCIIZ description string describing this device. + /// + UINT16 DescStringOffset; + + /// + /// Segment:offset address of an ASCIIZ description string describing this device. + /// + UINT16 DescStringSegment; + + /// + /// Reserved. + /// + UINT32 InitPerReserved; + + /// + /// The use of these fields is IBV dependent. They can be used to flag that an OpROM + /// has hooked the specified IRQ. The OpROM may be BBS compliant as some SCSI + /// BBS-compliant OpROMs also hook IRQ vectors in order to run their BIOS Setup + /// + UINT32 AdditionalIrq13Handler; + + /// + /// The use of these fields is IBV dependent. They can be used to flag that an OpROM + /// has hooked the specified IRQ. The OpROM may be BBS compliant as some SCSI + /// BBS-compliant OpROMs also hook IRQ vectors in order to run their BIOS Setup + /// + UINT32 AdditionalIrq18Handler; + + /// + /// The use of these fields is IBV dependent. They can be used to flag that an OpROM + /// has hooked the specified IRQ. The OpROM may be BBS compliant as some SCSI + /// BBS-compliant OpROMs also hook IRQ vectors in order to run their BIOS Setup + /// + UINT32 AdditionalIrq19Handler; + + /// + /// The use of these fields is IBV dependent. They can be used to flag that an OpROM + /// has hooked the specified IRQ. The OpROM may be BBS compliant as some SCSI + /// BBS-compliant OpROMs also hook IRQ vectors in order to run their BIOS Setup + /// + UINT32 AdditionalIrq40Handler; + UINT8 AssignedDriveNumber; + UINT32 AdditionalIrq41Handler; + UINT32 AdditionalIrq46Handler; + UINT32 IBV1; + UINT32 IBV2; +} BBS_TABLE; + +/// +/// BBS device type values +///@{ +#define BBS_FLOPPY 0x01 +#define BBS_HARDDISK 0x02 +#define BBS_CDROM 0x03 +#define BBS_PCMCIA 0x04 +#define BBS_USB 0x05 +#define BBS_EMBED_NETWORK 0x06 +#define BBS_BEV_DEVICE 0x80 +#define BBS_UNKNOWN 0xff +///@} + +/// +/// BBS boot priority values +///@{ +#define BBS_DO_NOT_BOOT_FROM 0xFFFC +#define BBS_LOWEST_PRIORITY 0xFFFD +#define BBS_UNPRIORITIZED_ENTRY 0xFFFE +#define BBS_IGNORE_ENTRY 0xFFFF +///@} + +/// +/// SMM_ATTRIBUTES +/// +typedef struct { + /// + /// Access mechanism used to generate the soft SMI. Defined types are below. The other + /// values are reserved for future usage. + /// + UINT16 Type : 3; + + /// + /// The size of "port" in bits. Defined values are below. + /// + UINT16 PortGranularity : 3; + + /// + /// The size of data in bits. Defined values are below. + /// + UINT16 DataGranularity : 3; + + /// + /// Reserved for future use. + /// + UINT16 Reserved : 7; +} SMM_ATTRIBUTES; + +/// +/// SMM_ATTRIBUTES type values. +///@{ +#define STANDARD_IO 0x00 +#define STANDARD_MEMORY 0x01 +///@} + +/// +/// SMM_ATTRIBUTES port size constants. +///@{ +#define PORT_SIZE_8 0x00 +#define PORT_SIZE_16 0x01 +#define PORT_SIZE_32 0x02 +#define PORT_SIZE_64 0x03 +///@} + +/// +/// SMM_ATTRIBUTES data size constants. +///@{ +#define DATA_SIZE_8 0x00 +#define DATA_SIZE_16 0x01 +#define DATA_SIZE_32 0x02 +#define DATA_SIZE_64 0x03 +///@} + +/// +/// SMM_FUNCTION & relating constants. +/// +typedef struct { + UINT16 Function : 15; + UINT16 Owner : 1; +} SMM_FUNCTION; + +/// +/// SMM_FUNCTION Function constants. +///@{ +#define INT15_D042 0x0000 +#define GET_USB_BOOT_INFO 0x0001 +#define DMI_PNP_50_57 0x0002 +///@} + +/// +/// SMM_FUNCTION Owner constants. +///@{ +#define STANDARD_OWNER 0x0 +#define OEM_OWNER 0x1 +///@} + +/// +/// This structure assumes both port and data sizes are 1. SmmAttribute must be +/// properly to reflect that assumption. +/// +typedef struct { + /// + /// Describes the access mechanism, SmmPort, and SmmData sizes. Type + /// SMM_ATTRIBUTES is defined below. + /// + SMM_ATTRIBUTES SmmAttributes; + + /// + /// Function Soft SMI is to perform. Type SMM_FUNCTION is defined below. + /// + SMM_FUNCTION SmmFunction; + + /// + /// SmmPort size depends upon SmmAttributes and ranges from2 bytes to 16 bytes. + /// + UINT8 SmmPort; + + /// + /// SmmData size depends upon SmmAttributes and ranges from2 bytes to 16 bytes. + /// + UINT8 SmmData; +} SMM_ENTRY; + +/// +/// SMM_TABLE +/// +typedef struct { + UINT16 NumSmmEntries; ///< Number of entries represented by SmmEntry. + SMM_ENTRY SmmEntry; ///< One entry per function. Type SMM_ENTRY is defined below. +} SMM_TABLE; + +/// +/// UDC_ATTRIBUTES +/// +typedef struct { + /// + /// This bit set indicates that the ServiceAreaData is valid. + /// + UINT8 DirectoryServiceValidity : 1; + + /// + /// This bit set indicates to use the Reserve Area Boot Code Address (RACBA) only if + /// DirectoryServiceValidity is 0. + /// + UINT8 RabcaUsedFlag : 1; + + /// + /// This bit set indicates to execute hard disk diagnostics. + /// + UINT8 ExecuteHddDiagnosticsFlag : 1; + + /// + /// Reserved for future use. Set to 0. + /// + UINT8 Reserved : 5; +} UDC_ATTRIBUTES; + +/// +/// UD_TABLE +/// +typedef struct { + /// + /// This field contains the bit-mapped attributes of the PARTIES information. Type + /// UDC_ATTRIBUTES is defined below. + /// + UDC_ATTRIBUTES Attributes; + + /// + /// This field contains the zero-based device on which the selected + /// ServiceDataArea is present. It is 0 for master and 1 for the slave device. + /// + UINT8 DeviceNumber; + + /// + /// This field contains the zero-based index into the BbsTable for the parent device. + /// This index allows the user to reference the parent device information such as PCI + /// bus, device function. + /// + UINT8 BbsTableEntryNumberForParentDevice; + + /// + /// This field contains the zero-based index into the BbsTable for the boot entry. + /// + UINT8 BbsTableEntryNumberForBoot; + + /// + /// This field contains the zero-based index into the BbsTable for the HDD diagnostics entry. + /// + UINT8 BbsTableEntryNumberForHddDiag; + + /// + /// The raw Beer data. + /// + UINT8 BeerData[128]; + + /// + /// The raw data of selected service area. + /// + UINT8 ServiceAreaData[64]; +} UD_TABLE; + +#define EFI_TO_LEGACY_MAJOR_VERSION 0x02 +#define EFI_TO_LEGACY_MINOR_VERSION 0x00 +#define MAX_IDE_CONTROLLER 8 + +/// +/// EFI_TO_COMPATIBILITY16_BOOT_TABLE +/// +typedef struct { + UINT16 MajorVersion; ///< The EfiCompatibility major version number. + UINT16 MinorVersion; ///< The EfiCompatibility minor version number. + UINT32 AcpiTable; ///< The location of the RSDT ACPI table. < 4G range. + UINT32 SmbiosTable; ///< The location of the SMBIOS table in EFI memory. < 4G range. + UINT32 SmbiosTableLength; + // + // Legacy SIO state + // + DEVICE_PRODUCER_DATA_HEADER SioData; ///< Standard traditional device information. + UINT16 DevicePathType; ///< The default boot type. + UINT16 PciIrqMask; ///< Mask of which IRQs have been assigned to PCI. + UINT32 NumberE820Entries; ///< Number of E820 entries. The number can change from the + ///< Compatibility16InitializeYourself() function. + // + // Controller & Drive Identify[2] per controller information + // + HDD_INFO HddInfo[MAX_IDE_CONTROLLER]; ///< Hard disk drive information, including raw Identify Drive data. + UINT32 NumberBbsEntries; ///< Number of entries in the BBS table + UINT32 BbsTable; ///< A pointer to the BBS table. Type BBS_TABLE is defined below. + UINT32 SmmTable; ///< A pointer to the SMM table. Type SMM_TABLE is defined below. + UINT32 OsMemoryAbove1Mb; ///< The amount of usable memory above 1 MB, i.e. E820 type 1 memory. This value can + ///< differ from the value in EFI_TO_COMPATIBILITY16_INIT_TABLE as more + ///< memory may have been discovered. + UINT32 UnconventionalDeviceTable; ///< Information to boot off an unconventional device like a PARTIES partition. Type + ///< UD_TABLE is defined below. +} EFI_TO_COMPATIBILITY16_BOOT_TABLE; + +/// +/// EFI_LEGACY_INSTALL_PCI_HANDLER +/// +typedef struct { + UINT8 PciBus; ///< The PCI bus of the device. + UINT8 PciDeviceFun; ///< The PCI device in bits 7:3 and function in bits 2:0. + UINT8 PciSegment; ///< The PCI segment of the device. + UINT8 PciClass; ///< The PCI class code of the device. + UINT8 PciSubclass; ///< The PCI subclass code of the device. + UINT8 PciInterface; ///< The PCI interface code of the device. + // + // Primary section + // + UINT8 PrimaryIrq; ///< The primary device IRQ. + UINT8 PrimaryReserved; ///< Reserved. + UINT16 PrimaryControl; ///< The primary device control I/O base. + UINT16 PrimaryBase; ///< The primary device I/O base. + UINT16 PrimaryBusMaster; ///< The primary device bus master I/O base. + // + // Secondary Section + // + UINT8 SecondaryIrq; ///< The secondary device IRQ. + UINT8 SecondaryReserved; ///< Reserved. + UINT16 SecondaryControl; ///< The secondary device control I/O base. + UINT16 SecondaryBase; ///< The secondary device I/O base. + UINT16 SecondaryBusMaster; ///< The secondary device bus master I/O base. +} EFI_LEGACY_INSTALL_PCI_HANDLER; + +// +// Restore default pack value +// +#pragma pack() + +#define EFI_LEGACY_BIOS_PROTOCOL_GUID \ + { \ + 0xdb9a1e3d, 0x45cb, 0x4abb, {0x85, 0x3b, 0xe5, 0x38, 0x7f, 0xdb, 0x2e, 0x2d } \ + } + +typedef struct _EFI_LEGACY_BIOS_PROTOCOL EFI_LEGACY_BIOS_PROTOCOL; + +/// +/// Flags returned by CheckPciRom(). +/// +#define NO_ROM 0x00 +#define ROM_FOUND 0x01 +#define VALID_LEGACY_ROM 0x02 +#define ROM_WITH_CONFIG 0x04 ///< Not defined in the Framework CSM Specification. + +/// +/// The following macros do not appear in the Framework CSM Specification and +/// are kept for backward compatibility only. They convert 32-bit address (_Adr) +/// to Segment:Offset 16-bit form. +/// +///@{ +#define EFI_SEGMENT(_Adr) (UINT16) ((UINT16) (((UINTN) (_Adr)) >> 4) & 0xf000) +#define EFI_OFFSET(_Adr) (UINT16) (((UINT16) ((UINTN) (_Adr))) & 0xffff) +///@} + +#define CARRY_FLAG 0x01 + +/// +/// EFI_EFLAGS_REG +/// +typedef struct { + UINT32 CF:1; + UINT32 Reserved1:1; + UINT32 PF:1; + UINT32 Reserved2:1; + UINT32 AF:1; + UINT32 Reserved3:1; + UINT32 ZF:1; + UINT32 SF:1; + UINT32 TF:1; + UINT32 IF:1; + UINT32 DF:1; + UINT32 OF:1; + UINT32 IOPL:2; + UINT32 NT:1; + UINT32 Reserved4:2; + UINT32 VM:1; + UINT32 Reserved5:14; +} EFI_EFLAGS_REG; + +/// +/// EFI_DWORD_REGS +/// +typedef struct { + UINT32 EAX; + UINT32 EBX; + UINT32 ECX; + UINT32 EDX; + UINT32 ESI; + UINT32 EDI; + EFI_EFLAGS_REG EFlags; + UINT16 ES; + UINT16 CS; + UINT16 SS; + UINT16 DS; + UINT16 FS; + UINT16 GS; + UINT32 EBP; + UINT32 ESP; +} EFI_DWORD_REGS; + +/// +/// EFI_FLAGS_REG +/// +typedef struct { + UINT16 CF:1; + UINT16 Reserved1:1; + UINT16 PF:1; + UINT16 Reserved2:1; + UINT16 AF:1; + UINT16 Reserved3:1; + UINT16 ZF:1; + UINT16 SF:1; + UINT16 TF:1; + UINT16 IF:1; + UINT16 DF:1; + UINT16 OF:1; + UINT16 IOPL:2; + UINT16 NT:1; + UINT16 Reserved4:1; +} EFI_FLAGS_REG; + +/// +/// EFI_WORD_REGS +/// +typedef struct { + UINT16 AX; + UINT16 ReservedAX; + UINT16 BX; + UINT16 ReservedBX; + UINT16 CX; + UINT16 ReservedCX; + UINT16 DX; + UINT16 ReservedDX; + UINT16 SI; + UINT16 ReservedSI; + UINT16 DI; + UINT16 ReservedDI; + EFI_FLAGS_REG Flags; + UINT16 ReservedFlags; + UINT16 ES; + UINT16 CS; + UINT16 SS; + UINT16 DS; + UINT16 FS; + UINT16 GS; + UINT16 BP; + UINT16 ReservedBP; + UINT16 SP; + UINT16 ReservedSP; +} EFI_WORD_REGS; + +/// +/// EFI_BYTE_REGS +/// +typedef struct { + UINT8 AL, AH; + UINT16 ReservedAX; + UINT8 BL, BH; + UINT16 ReservedBX; + UINT8 CL, CH; + UINT16 ReservedCX; + UINT8 DL, DH; + UINT16 ReservedDX; +} EFI_BYTE_REGS; + +/// +/// EFI_IA32_REGISTER_SET +/// +typedef union { + EFI_DWORD_REGS E; + EFI_WORD_REGS X; + EFI_BYTE_REGS H; +} EFI_IA32_REGISTER_SET; + +/** + Thunk to 16-bit real mode and execute a software interrupt with a vector + of BiosInt. Regs will contain the 16-bit register context on entry and + exit. + + @param[in] This The protocol instance pointer. + @param[in] BiosInt The processor interrupt vector to invoke. + @param[in,out] Reg Register contexted passed into (and returned) from thunk to + 16-bit mode. + + @retval TRUE Thunk completed with no BIOS errors in the target code. See Regs for status. + @retval FALSE There was a BIOS error in the target code. +**/ +typedef +BOOLEAN +(EFIAPI *EFI_LEGACY_BIOS_INT86)( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN UINT8 BiosInt, + IN OUT EFI_IA32_REGISTER_SET *Regs + ); + +/** + Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the + 16-bit register context on entry and exit. Arguments can be passed on + the Stack argument + + @param[in] This The protocol instance pointer. + @param[in] Segment The segemnt of 16-bit mode call. + @param[in] Offset The offset of 16-bit mdoe call. + @param[in] Reg Register contexted passed into (and returned) from thunk to + 16-bit mode. + @param[in] Stack The caller allocated stack used to pass arguments. + @param[in] StackSize The size of Stack in bytes. + + @retval FALSE Thunk completed with no BIOS errors in the target code. See Regs for status. @retval TRUE There was a BIOS error in the target code. +**/ +typedef +BOOLEAN +(EFIAPI *EFI_LEGACY_BIOS_FARCALL86)( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN UINT16 Segment, + IN UINT16 Offset, + IN EFI_IA32_REGISTER_SET *Regs, + IN VOID *Stack, + IN UINTN StackSize + ); + +/** + Test to see if a legacy PCI ROM exists for this device. Optionally return + the Legacy ROM instance for this PCI device. + + @param[in] This The protocol instance pointer. + @param[in] PciHandle The PCI PC-AT OPROM from this devices ROM BAR will be loaded + @param[out] RomImage Return the legacy PCI ROM for this device. + @param[out] RomSize The size of ROM Image. + @param[out] Flags Indicates if ROM found and if PC-AT. Multiple bits can be set as follows: + - 00 = No ROM. + - 01 = ROM Found. + - 02 = ROM is a valid legacy ROM. + + @retval EFI_SUCCESS The Legacy Option ROM available for this device + @retval EFI_UNSUPPORTED The Legacy Option ROM is not supported. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_BIOS_CHECK_ROM)( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN EFI_HANDLE PciHandle, + OUT VOID **RomImage, OPTIONAL + OUT UINTN *RomSize, OPTIONAL + OUT UINTN *Flags + ); + +/** + Load a legacy PC-AT OPROM on the PciHandle device. Return information + about how many disks were added by the OPROM and the shadow address and + size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C: + + @param[in] This The protocol instance pointer. + @param[in] PciHandle The PCI PC-AT OPROM from this devices ROM BAR will be loaded. + This value is NULL if RomImage is non-NULL. This is the normal + case. + @param[in] RomImage A PCI PC-AT ROM image. This argument is non-NULL if there is + no hardware associated with the ROM and thus no PciHandle, + otherwise is must be NULL. + Example is PXE base code. + @param[out] Flags The type of ROM discovered. Multiple bits can be set, as follows: + - 00 = No ROM. + - 01 = ROM found. + - 02 = ROM is a valid legacy ROM. + @param[out] DiskStart The disk number of first device hooked by the ROM. If DiskStart + is the same as DiskEnd no disked were hooked. + @param[out] DiskEnd disk number of the last device hooked by the ROM. + @param[out] RomShadowAddress Shadow address of PC-AT ROM. + @param[out] RomShadowSize Size of RomShadowAddress in bytes. + + @retval EFI_SUCCESS Thunk completed, see Regs for status. + @retval EFI_INVALID_PARAMETER PciHandle not found + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_BIOS_INSTALL_ROM)( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN EFI_HANDLE PciHandle, + IN VOID **RomImage, + OUT UINTN *Flags, + OUT UINT8 *DiskStart, OPTIONAL + OUT UINT8 *DiskEnd, OPTIONAL + OUT VOID **RomShadowAddress, OPTIONAL + OUT UINT32 *ShadowedRomSize OPTIONAL + ); + +/** + This function attempts to traditionally boot the specified BootOption. If the EFI context has + been compromised, this function will not return. This procedure is not used for loading an EFI-aware + OS off a traditional device. The following actions occur: + - Get EFI SMBIOS data structures, convert them to a traditional format, and copy to + Compatibility16. + - Get a pointer to ACPI data structures and copy the Compatibility16 RSD PTR to F0000 block. + - Find the traditional SMI handler from a firmware volume and register the traditional SMI + handler with the EFI SMI handler. + - Build onboard IDE information and pass this information to the Compatibility16 code. + - Make sure all PCI Interrupt Line registers are programmed to match 8259. + - Reconfigure SIO devices from EFI mode (polled) into traditional mode (interrupt driven). + - Shadow all PCI ROMs. + - Set up BDA and EBDA standard areas before the legacy boot. + - Construct the Compatibility16 boot memory map and pass it to the Compatibility16 code. + - Invoke the Compatibility16 table function Compatibility16PrepareToBoot(). This + invocation causes a thunk into the Compatibility16 code, which sets all appropriate internal + data structures. The boot device list is a parameter. + - Invoke the Compatibility16 Table function Compatibility16Boot(). This invocation + causes a thunk into the Compatibility16 code, which does an INT19. + - If the Compatibility16Boot() function returns, then the boot failed in a graceful + manner--meaning that the EFI code is still valid. An ungraceful boot failure causes a reset because the state + of EFI code is unknown. + + @param[in] This The protocol instance pointer. + @param[in] BootOption The EFI Device Path from BootXXXX variable. + @param[in] LoadOptionSize The size of LoadOption in size. + @param[in] LoadOption LThe oadOption from BootXXXX variable. + + @retval EFI_DEVICE_ERROR Failed to boot from any boot device and memory is uncorrupted. Note: This function normally does not returns. It will either boot the OS or reset the system if memory has been "corrupted" by loading a boot sector and passing control to it. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_BIOS_BOOT)( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN BBS_BBS_DEVICE_PATH *BootOption, + IN UINT32 LoadOptionsSize, + IN VOID *LoadOptions + ); + +/** + This function takes the Leds input parameter and sets/resets the BDA accordingly. + Leds is also passed to Compatibility16 code, in case any special processing is required. + This function is normally called from EFI Setup drivers that handle user-selectable + keyboard options such as boot with NUM LOCK on/off. This function does not + touch the keyboard or keyboard LEDs but only the BDA. + + @param[in] This The protocol instance pointer. + @param[in] Leds The status of current Scroll, Num & Cap lock LEDS: + - Bit 0 is Scroll Lock 0 = Not locked. + - Bit 1 is Num Lock. + - Bit 2 is Caps Lock. + + @retval EFI_SUCCESS The BDA was updated successfully. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_BIOS_UPDATE_KEYBOARD_LED_STATUS)( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN UINT8 Leds + ); + +/** + Retrieve legacy BBS info and assign boot priority. + + @param[in] This The protocol instance pointer. + @param[out] HddCount The number of HDD_INFO structures. + @param[out] HddInfo Onboard IDE controller information. + @param[out] BbsCount The number of BBS_TABLE structures. + @param[in,out] BbsTable Points to List of BBS_TABLE. + + @retval EFI_SUCCESS Tables were returned. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_BIOS_GET_BBS_INFO)( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + OUT UINT16 *HddCount, + OUT HDD_INFO **HddInfo, + OUT UINT16 *BbsCount, + IN OUT BBS_TABLE **BbsTable + ); + +/** + Assign drive number to legacy HDD drives prior to booting an EFI + aware OS so the OS can access drives without an EFI driver. + + @param[in] This The protocol instance pointer. + @param[out] BbsCount The number of BBS_TABLE structures + @param[out] BbsTable List of BBS entries + + @retval EFI_SUCCESS Drive numbers assigned. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_BIOS_PREPARE_TO_BOOT_EFI)( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + OUT UINT16 *BbsCount, + OUT BBS_TABLE **BbsTable + ); + +/** + To boot from an unconventional device like parties and/or execute + HDD diagnostics. + + @param[in] This The protocol instance pointer. + @param[in] Attributes How to interpret the other input parameters. + @param[in] BbsEntry The 0-based index into the BbsTable for the parent + device. + @param[in] BeerData A pointer to the 128 bytes of ram BEER data. + @param[in] ServiceAreaData A pointer to the 64 bytes of raw Service Area data. The + caller must provide a pointer to the specific Service + Area and not the start all Service Areas. + + @retval EFI_INVALID_PARAMETER If error. Does NOT return if no error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_BIOS_BOOT_UNCONVENTIONAL_DEVICE)( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN UDC_ATTRIBUTES Attributes, + IN UINTN BbsEntry, + IN VOID *BeerData, + IN VOID *ServiceAreaData + ); + +/** + Shadow all legacy16 OPROMs that haven't been shadowed. + Warning: Use this with caution. This routine disconnects all EFI + drivers. If used externally, then the caller must re-connect EFI + drivers. + + @param[in] This The protocol instance pointer. + + @retval EFI_SUCCESS OPROMs were shadowed. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_BIOS_SHADOW_ALL_LEGACY_OPROMS)( + IN EFI_LEGACY_BIOS_PROTOCOL *This + ); + +/** + Get a region from the LegacyBios for S3 usage. + + @param[in] This The protocol instance pointer. + @param[in] LegacyMemorySize The size of required region. + @param[in] Region The region to use. + 00 = Either 0xE0000 or 0xF0000 block. + - Bit0 = 1 0xF0000 block. + - Bit1 = 1 0xE0000 block. + @param[in] Alignment Address alignment. Bit mapped. The first non-zero + bit from right is alignment. + @param[out] LegacyMemoryAddress The Region Assigned + + @retval EFI_SUCCESS The Region was assigned. + @retval EFI_ACCESS_DENIED The function was previously invoked. + @retval Other The Region was not assigned. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_BIOS_GET_LEGACY_REGION)( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN UINTN LegacyMemorySize, + IN UINTN Region, + IN UINTN Alignment, + OUT VOID **LegacyMemoryAddress + ); + +/** + Get a region from the LegacyBios for Tiano usage. Can only be invoked once. + + @param[in] This The protocol instance pointer. + @param[in] LegacyMemorySize The size of data to copy. + @param[in] LegacyMemoryAddress The Legacy Region destination address. + Note: must be in region assigned by + LegacyBiosGetLegacyRegion. + @param[in] LegacyMemorySourceAddress The source of the data to copy. + + @retval EFI_SUCCESS The Region assigned. + @retval EFI_ACCESS_DENIED Destination was outside an assigned region. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_BIOS_COPY_LEGACY_REGION)( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN UINTN LegacyMemorySize, + IN VOID *LegacyMemoryAddress, + IN VOID *LegacyMemorySourceAddress + ); + +/// +/// Abstracts the traditional BIOS from the rest of EFI. The LegacyBoot() +/// member function allows the BDS to support booting a traditional OS. +/// EFI thunks drivers that make EFI bindings for BIOS INT services use +/// all the other member functions. +/// +struct _EFI_LEGACY_BIOS_PROTOCOL { + /// + /// Performs traditional software INT. See the Int86() function description. + /// + EFI_LEGACY_BIOS_INT86 Int86; + + /// + /// Performs a far call into Compatibility16 or traditional OpROM code. + /// + EFI_LEGACY_BIOS_FARCALL86 FarCall86; + + /// + /// Checks if a traditional OpROM exists for this device. + /// + EFI_LEGACY_BIOS_CHECK_ROM CheckPciRom; + + /// + /// Loads a traditional OpROM in traditional OpROM address space. + /// + EFI_LEGACY_BIOS_INSTALL_ROM InstallPciRom; + + /// + /// Boots a traditional OS. + /// + EFI_LEGACY_BIOS_BOOT LegacyBoot; + + /// + /// Updates BDA to reflect the current EFI keyboard LED status. + /// + EFI_LEGACY_BIOS_UPDATE_KEYBOARD_LED_STATUS UpdateKeyboardLedStatus; + + /// + /// Allows an external agent, such as BIOS Setup, to get the BBS data. + /// + EFI_LEGACY_BIOS_GET_BBS_INFO GetBbsInfo; + + /// + /// Causes all legacy OpROMs to be shadowed. + /// + EFI_LEGACY_BIOS_SHADOW_ALL_LEGACY_OPROMS ShadowAllLegacyOproms; + + /// + /// Performs all actions prior to boot. Used when booting an EFI-aware OS + /// rather than a legacy OS. + /// + EFI_LEGACY_BIOS_PREPARE_TO_BOOT_EFI PrepareToBootEfi; + + /// + /// Allows EFI to reserve an area in the 0xE0000 or 0xF0000 block. + /// + EFI_LEGACY_BIOS_GET_LEGACY_REGION GetLegacyRegion; + + /// + /// Allows EFI to copy data to the area specified by GetLegacyRegion. + /// + EFI_LEGACY_BIOS_COPY_LEGACY_REGION CopyLegacyRegion; + + /// + /// Allows the user to boot off an unconventional device such as a PARTIES partition. + /// + EFI_LEGACY_BIOS_BOOT_UNCONVENTIONAL_DEVICE BootUnconventionalDevice; +}; + +// +// Legacy BIOS needs to access memory in page 0 (0-4095), which is disabled if +// NULL pointer detection feature is enabled. Following macro can be used to +// enable/disable page 0 before/after accessing it. +// +#define ACCESS_PAGE0_CODE(statements) \ + do { \ + EFI_STATUS Status_; \ + EFI_GCD_MEMORY_SPACE_DESCRIPTOR Desc_; \ + \ + Desc_.Attributes = 0; \ + Status_ = gDS->GetMemorySpaceDescriptor (0, &Desc_); \ + ASSERT_EFI_ERROR (Status_); \ + if ((Desc_.Attributes & EFI_MEMORY_RP) != 0) { \ + Status_ = gDS->SetMemorySpaceAttributes ( \ + 0, \ + EFI_PAGES_TO_SIZE(1), \ + Desc_.Attributes & ~(UINT64)EFI_MEMORY_RP \ + ); \ + ASSERT_EFI_ERROR (Status_); \ + } \ + \ + { \ + statements; \ + } \ + \ + if ((Desc_.Attributes & EFI_MEMORY_RP) != 0) { \ + Status_ = gDS->SetMemorySpaceAttributes ( \ + 0, \ + EFI_PAGES_TO_SIZE(1), \ + Desc_.Attributes \ + ); \ + ASSERT_EFI_ERROR (Status_); \ + } \ + } while (FALSE) + +extern EFI_GUID gEfiLegacyBiosProtocolGuid; + +#endif diff --git a/OvmfPkg/Csm/Include/Protocol/LegacyBiosPlatform.h b/OvmfPkg/Csm/Include/Protocol/LegacyBiosPlatform.h new file mode 100644 index 0000000000..0a164dad3b --- /dev/null +++ b/OvmfPkg/Csm/Include/Protocol/LegacyBiosPlatform.h @@ -0,0 +1,755 @@ +/** @file + The EFI Legacy BIOS Patform Protocol is used to mate a Legacy16 + implementation with this EFI code. The EFI driver that produces + the Legacy BIOS protocol is generic and consumes this protocol. + A driver that matches the Legacy16 produces this protocol + +Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Revision Reference: + This protocol is defined in Framework for EFI Compatibility Support Module spec + Version 0.97. + +**/ + +#ifndef _EFI_LEGACY_BIOS_PLATFORM_H_ +#define _EFI_LEGACY_BIOS_PLATFORM_H_ + +/// +/// Legacy BIOS Platform depends on HDD_INFO and EFI_COMPATIBILITY16_TABLE that +/// are defined with the Legacy BIOS Protocol +/// +#include + +#define EFI_LEGACY_BIOS_PLATFORM_PROTOCOL_GUID \ + { \ + 0x783658a3, 0x4172, 0x4421, {0xa2, 0x99, 0xe0, 0x9, 0x7, 0x9c, 0xc, 0xb4 } \ + } + +typedef struct _EFI_LEGACY_BIOS_PLATFORM_PROTOCOL EFI_LEGACY_BIOS_PLATFORM_PROTOCOL; + +/** + This enum specifies the Mode param values for GetPlatformInfo() +**/ +typedef enum { + /// + /// This mode is invoked twice. The first invocation has LegacySegment and + /// LegacyOffset set to 0. The mode returns the MP table address in EFI memory, along with its size. + /// The second invocation has LegacySegment and LegacyOffset set to the location + /// in the 0xF0000 or 0xE0000 block to which the MP table is to be copied. The second + /// invocation allows any MP table address fixes to occur in the EFI memory copy of the + /// MP table. The caller, not EfiGetPlatformBinaryMpTable, copies the modified MP + /// table to the allocated region in 0xF0000 or 0xE0000 block after the second invocation. + /// + /// The function parameters associated with this mode are: + /// + /// Table Pointer to the MP table. + /// + /// TableSize Size in bytes of the MP table. + /// + /// Location Location to place table. 0x00. Either 0xE0000 or 0xF0000 64 KB blocks. + /// Bit 0 = 1 0xF0000 64 KB block. + /// Bit 1 = 1 0xE0000 64 KB block. + /// Multiple bits can be set. + /// + /// Alignment Bit-mapped address alignment granularity. + /// The first nonzero bit from the right is the address granularity. + /// + // LegacySegment Segment in which EfiCompatibility code will place the MP table. + /// + /// LegacyOffset Offset in which EfiCompatibility code will place the MP table. + /// + /// The return values associated with this mode are: + /// + /// EFI_SUCCESS The MP table was returned. + /// + /// EFI_UNSUPPORTED The MP table is not supported on this platform. + /// + EfiGetPlatformBinaryMpTable = 0, + /// + /// This mode returns a block of data. The content and usage is IBV or OEM defined. + /// OEMs or IBVs normally use this function for nonstandard Compatibility16 runtime soft + /// INTs. It is the responsibility of this routine to coalesce multiple OEM 16 bit functions, if + /// they exist, into one coherent package that is understandable by the Compatibility16 code. + /// This function is invoked twice. The first invocation has LegacySegment and + /// LegacyOffset set to 0. The function returns the table address in EFI memory, as well as its size. + /// The second invocation has LegacySegment and LegacyOffset set to the location + /// in the 0xF0000 or 0xE0000 block to which the data (table) is to be copied. The second + /// invocation allows any data (table) address fixes to occur in the EFI memory copy of + /// the table. The caller, not GetOemIntData(), copies the modified data (table) to the + /// allocated region in 0xF0000 or 0xE0000 block after the second invocation. + /// + /// The function parameters associated with this mode are: + /// + /// Table Pointer to OEM legacy 16 bit code or data. + /// + /// TableSize Size of data. + /// + /// Location Location to place table. 0x00. Either 0xE0000 or 0xF0000 64 KB blocks. + /// Bit 0 = 1 0xF0000 64 KB block. + /// Bit 1 = 1 0xE0000 64 KB block. + /// Multiple bits can be set. + /// + /// Alignment Bit mapped address alignment granularity. + /// The first nonzero bit from the right is the address granularity. + /// + /// LegacySegment Segment in which EfiCompatibility code will place the table or data. + /// + /// LegacyOffset Offset in which EfiCompatibility code will place the table or data. + /// + /// The return values associated with this mode are: + /// + /// EFI_SUCCESS The data was returned successfully. + /// + /// EFI_UNSUPPORTED Oem INT is not supported on this platform. + /// + EfiGetPlatformBinaryOemIntData = 1, + /// + /// This mode returns a block of data. The content and usage is IBV defined. OEMs or + /// IBVs normally use this mode for nonstandard Compatibility16 runtime 16 bit routines. It + /// is the responsibility of this routine to coalesce multiple OEM 16 bit functions, if they + /// exist, into one coherent package that is understandable by the Compatibility16 code. + /// + /// Example usage: A legacy mobile BIOS that has a pre-existing runtime + /// interface to return the battery status to calling applications. + /// + /// This mode is invoked twice. The first invocation has LegacySegment and + /// LegacyOffset set to 0. The mode returns the table address in EFI memory and its size. + /// The second invocation has LegacySegment and LegacyOffset set to the location + /// in the 0xF0000 or 0xE0000 block to which the table is to be copied. The second + /// invocation allows any table address fixes to occur in the EFI memory copy of the table. + /// The caller, not EfiGetPlatformBinaryOem16Data, copies the modified table to + /// the allocated region in 0xF0000 or 0xE0000 block after the second invocation. + /// + /// The function parameters associated with this mode are: + /// + /// Table Pointer to OEM legacy 16 bit code or data. + /// + /// TableSize Size of data. + /// + /// Location Location to place the table. 0x00. Either 0xE0000 or 0xF0000 64 KB blocks. + /// Bit 0 = 1 0xF0000 64 KB block. + /// Bit 1 = 1 0xE0000 64 KB block. + /// Multiple bits can be set. + /// + /// Alignment Bit mapped address alignment granularity. + /// The first nonzero bit from the right is the address granularity. + /// + /// LegacySegment Segment in which EfiCompatibility code will place the table or data. + /// + /// LegacyOffset Offset in which EfiCompatibility code will place the table or data. + /// + /// The return values associated with this mode are: + /// + /// EFI_SUCCESS The data was returned successfully. + /// + /// EFI_UNSUPPORTED Oem16 is not supported on this platform. + /// + EfiGetPlatformBinaryOem16Data = 2, +/// +/// This mode returns a block of data. The content and usage are IBV defined. OEMs or +/// IBVs normally use this mode for nonstandard Compatibility16 runtime 32 bit routines. It +/// is the responsibility of this routine to coalesce multiple OEM 32 bit functions, if they +/// exist, into one coherent package that is understandable by the Compatibility16 code. +/// +/// Example usage: A legacy mobile BIOS that has a pre existing runtime +/// interface to return the battery status to calling applications. +/// +/// This mode is invoked twice. The first invocation has LegacySegment and +/// LegacyOffset set to 0. The mode returns the table address in EFI memory and its size. +/// +/// The second invocation has LegacySegment and LegacyOffset set to the location +/// in the 0xF0000 or 0xE0000 block to which the table is to be copied. The second +/// invocation allows any table address fix ups to occur in the EFI memory copy of the table. +/// The caller, not EfiGetPlatformBinaryOem32Data, copies the modified table to +/// the allocated region in 0xF0000 or 0xE0000 block after the second invocation.. +/// +/// Note: There are two generic mechanisms by which this mode can be used. +/// Mechanism 1: This mode returns the data and the Legacy BIOS Protocol copies +/// the data into the F0000 or E0000 block in the Compatibility16 code. The +/// EFI_COMPATIBILITY16_TABLE entries Oem32Segment and Oem32Offset can +/// be viewed as two UINT16 entries. +/// Mechanism 2: This mode directly fills in the EFI_COMPATIBILITY16_TABLE with +/// a pointer to the INT15 E820 region containing the 32 bit code. It returns +/// EFI_UNSUPPORTED. The EFI_COMPATIBILITY16_TABLE entries, +/// Oem32Segment and Oem32Offset, can be viewed as two UINT16 entries or +/// as a single UINT32 entry as determined by the IBV. +/// +/// The function parameters associated with this mode are: +/// +/// TableSize Size of data. +/// +/// Location Location to place the table. 0x00 or 0xE0000 or 0xF0000 64 KB blocks. +/// Bit 0 = 1 0xF0000 64 KB block. +/// Bit 1 = 1 0xE0000 64 KB block. +/// Multiple bits can be set. +/// +/// Alignment Bit mapped address alignment granularity. +/// The first nonzero bit from the right is the address granularity. +/// +/// LegacySegment Segment in which EfiCompatibility code will place the table or data. +/// +/// LegacyOffset Offset in which EfiCompatibility code will place the table or data. +/// +/// The return values associated with this mode are: +/// EFI_SUCCESS The data was returned successfully. +/// EFI_UNSUPPORTED Oem32 is not supported on this platform. +/// +EfiGetPlatformBinaryOem32Data = 3, + /// + /// This mode returns a TPM binary image for the onboard TPM device. + /// + /// The function parameters associated with this mode are: + /// + /// Table TPM binary image for the onboard TPM device. + /// + /// TableSize Size of BinaryImage in bytes. + /// + /// Location Location to place the table. 0x00. Either 0xE0000 or 0xF0000 64 KB blocks. + /// Bit 0 = 1 0xF0000 64 KB block. + /// Bit 1 = 1 0xE0000 64 KB block. + /// Multiple bits can be set. + /// + /// Alignment Bit mapped address alignment granularity. + /// The first nonzero bit from the right is the address granularity. + /// + /// LegacySegment Segment in which EfiCompatibility code will place the table or data. + /// + /// LegacyOffset Offset in which EfiCompatibility code will place the table or data. + /// + /// The return values associated with this mode are: + /// + /// EFI_SUCCESS BinaryImage is valid. + /// + /// EFI_UNSUPPORTED Mode is not supported on this platform. + /// + /// EFI_NOT_FOUND No BinaryImage was found. + /// + EfiGetPlatformBinaryTpmBinary = 4, + /// + /// The mode finds the Compatibility16 Rom Image. + /// + /// The function parameters associated with this mode are: + /// + /// System ROM image for the platform. + /// + /// TableSize Size of Table in bytes. + /// + /// Location Ignored. + /// + /// Alignment Ignored. + /// + /// LegacySegment Ignored. + /// + /// LegacyOffset Ignored. + /// + /// The return values associated with this mode are: + /// + /// EFI_SUCCESS ROM image found. + /// + /// EFI_NOT_FOUND ROM not found. + /// + EfiGetPlatformBinarySystemRom = 5, + /// + /// This mode returns the Base address of PciExpress memory mapped configuration + /// address space. + /// + /// The function parameters associated with this mode are: + /// + /// Table System ROM image for the platform. + /// + /// TableSize Size of Table in bytes. + /// + /// Location Ignored. + /// + /// Alignment Ignored. + /// + /// LegacySegment Ignored. + /// + /// LegacyOffset Ignored. + /// + /// The return values associated with this mode are: + /// + /// EFI_SUCCESS Address is valid. + /// + /// EFI_UNSUPPORTED System does not PciExpress. + /// + EfiGetPlatformPciExpressBase = 6, + /// + EfiGetPlatformPmmSize = 7, + /// + EfiGetPlatformEndOpromShadowAddr = 8, + /// +} EFI_GET_PLATFORM_INFO_MODE; + +/** + This enum specifies the Mode param values for GetPlatformHandle(). +**/ +typedef enum { + /// + /// This mode returns the Compatibility16 policy for the device that should be the VGA + /// controller used during a Compatibility16 boot. + /// + /// The function parameters associated with this mode are: + /// + /// Type 0x00. + /// + /// HandleBuffer Buffer of all VGA handles found. + /// + /// HandleCount Number of VGA handles found. + /// + /// AdditionalData NULL. + /// + EfiGetPlatformVgaHandle = 0, + /// + /// This mode returns the Compatibility16 policy for the device that should be the IDE + /// controller used during a Compatibility16 boot. + /// + /// The function parameters associated with this mode are: + /// + /// Type 0x00. + /// + /// HandleBuffer Buffer of all IDE handles found. + /// + /// HandleCount Number of IDE handles found. + /// + /// AdditionalData Pointer to HddInfo. + /// Information about all onboard IDE controllers. + /// + EfiGetPlatformIdeHandle = 1, + /// + /// This mode returns the Compatibility16 policy for the device that should be the ISA bus + /// controller used during a Compatibility16 boot. + /// + /// The function parameters associated with this mode are: + /// + /// Type 0x00. + /// + /// HandleBuffer Buffer of all ISA bus handles found. + /// + /// HandleCount Number of ISA bus handles found. + /// + /// AdditionalData NULL. + /// + EfiGetPlatformIsaBusHandle = 2, + /// + /// This mode returns the Compatibility16 policy for the device that should be the USB + /// device used during a Compatibility16 boot. + /// + /// The function parameters associated with this mode are: + /// + /// Type 0x00. + /// + /// HandleBuffer Buffer of all USB handles found. + /// + /// HandleCount Number of USB bus handles found. + /// + /// AdditionalData NULL. + /// + EfiGetPlatformUsbHandle = 3 +} EFI_GET_PLATFORM_HANDLE_MODE; + +/** + This enum specifies the Mode param values for PlatformHooks(). + Note: Any OEM defined hooks start with 0x8000. +**/ +typedef enum { + /// + /// This mode allows any preprocessing before scanning OpROMs. + /// + /// The function parameters associated with this mode are: + /// + /// Type 0. + /// + /// DeviceHandle Handle of device OpROM is associated with. + /// + /// ShadowAddress Address where OpROM is shadowed. + /// + /// Compatibility16Table NULL. + /// + /// AdditionalData NULL. + /// + EfiPlatformHookPrepareToScanRom = 0, + /// + /// This mode shadows legacy OpROMS that may not have a physical device associated with + /// them. It returns EFI_SUCCESS if the ROM was shadowed. + /// + /// The function parameters associated with this mode are: + /// + /// Type 0. + /// + /// DeviceHandle 0. + /// + /// ShadowAddress First free OpROM area, after other OpROMs have been dispatched.. + /// + /// Compatibility16Table Pointer to the Compatability16 Table. + /// + /// AdditionalData NULL. + /// + EfiPlatformHookShadowServiceRoms= 1, + /// + /// This mode allows platform to perform any required operation after an OpROM has + /// completed its initialization. + /// + /// The function parameters associated with this mode are: + /// + /// Type 0. + /// + /// DeviceHandle Handle of device OpROM is associated with. + /// + /// ShadowAddress Address where OpROM is shadowed. + /// + /// Compatibility16Table NULL. + /// + /// AdditionalData NULL. + /// + EfiPlatformHookAfterRomInit = 2 +} EFI_GET_PLATFORM_HOOK_MODE; + +/// +/// This IRQ has not been assigned to PCI. +/// +#define PCI_UNUSED 0x00 +/// +/// This IRQ has been assigned to PCI. +/// +#define PCI_USED 0xFF +/// +/// This IRQ has been used by an SIO legacy device and cannot be used by PCI. +/// +#define LEGACY_USED 0xFE + +#pragma pack(1) + +typedef struct { + /// + /// IRQ for this entry. + /// + UINT8 Irq; + /// + /// Status of this IRQ. + /// + /// PCI_UNUSED 0x00. This IRQ has not been assigned to PCI. + /// + /// PCI_USED 0xFF. This IRQ has been assigned to PCI. + /// + /// LEGACY_USED 0xFE. This IRQ has been used by an SIO legacy + /// device and cannot be used by PCI. + /// + UINT8 Used; +} EFI_LEGACY_IRQ_PRIORITY_TABLE_ENTRY; + +// +// Define PIR table structures +// +#define EFI_LEGACY_PIRQ_TABLE_SIGNATURE SIGNATURE_32 ('$', 'P', 'I', 'R') + +typedef struct { + /// + /// $PIR. + /// + UINT32 Signature; + /// + /// 0x00. + /// + UINT8 MinorVersion; + /// + /// 0x01 for table version 1.0. + /// + UINT8 MajorVersion; + /// + /// 0x20 + RoutingTableEntries * 0x10. + /// + UINT16 TableSize; + /// + /// PCI interrupt router bus. + /// + UINT8 Bus; + /// + /// PCI interrupt router device/function. + /// + UINT8 DevFun; + /// + /// If nonzero, bit map of IRQs reserved for PCI. + /// + UINT16 PciOnlyIrq; + /// + /// Vendor ID of a compatible PCI interrupt router. + /// + UINT16 CompatibleVid; + /// + /// Device ID of a compatible PCI interrupt router. + /// + UINT16 CompatibleDid; + /// + /// If nonzero, a value passed directly to the IRQ miniport's Initialize function. + /// + UINT32 Miniport; + /// + /// Reserved for future usage. + /// + UINT8 Reserved[11]; + /// + /// This byte plus the sum of all other bytes in the LocalPirqTable equal 0x00. + /// + UINT8 Checksum; +} EFI_LEGACY_PIRQ_TABLE_HEADER; + + +typedef struct { + /// + /// If nonzero, a value assigned by the IBV. + /// + UINT8 Pirq; + /// + /// If nonzero, the IRQs that can be assigned to this device. + /// + UINT16 IrqMask; +} EFI_LEGACY_PIRQ_ENTRY; + +typedef struct { + /// + /// PCI bus of the entry. + /// + UINT8 Bus; + /// + /// PCI device of this entry. + /// + UINT8 Device; + /// + /// An IBV value and IRQ mask for PIRQ pins A through D. + /// + EFI_LEGACY_PIRQ_ENTRY PirqEntry[4]; + /// + /// If nonzero, the slot number assigned by the board manufacturer. + /// + UINT8 Slot; + /// + /// Reserved for future use. + /// + UINT8 Reserved; +} EFI_LEGACY_IRQ_ROUTING_ENTRY; + +#pragma pack() + + +/** + 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. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_BIOS_PLATFORM_GET_PLATFORM_INFO)( + 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 + ); + +/** + 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. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_BIOS_PLATFORM_GET_PLATFORM_HANDLE)( + IN EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *This, + IN EFI_GET_PLATFORM_HANDLE_MODE Mode, + IN UINT16 Type, + OUT EFI_HANDLE **HandleBuffer, + OUT UINTN *HandleCount, + IN VOID **AdditionalData OPTIONAL + ); + +/** + 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 + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_BIOS_PLATFORM_SMM_INIT)( + IN EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *This, + IN VOID *EfiToLegacy16BootTable + ); + +/** + 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. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_BIOS_PLATFORM_HOOKS)( + IN EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *This, + IN EFI_GET_PLATFORM_HOOK_MODE Mode, + IN UINT16 Type, + IN EFI_HANDLE DeviceHandle, OPTIONAL + IN OUT UINTN *ShadowAddress, OPTIONAL + IN EFI_COMPATIBILITY16_TABLE *Compatibility16Table, OPTIONAL + OUT VOID **AdditionalData OPTIONAL + ); + +/** + 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. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_BIOS_PLATFORM_GET_ROUTING_TABLE)( + 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 + ); + +/** + 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. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_BIOS_PLATFORM_TRANSLATE_PIRQ)( + IN EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *This, + IN UINTN PciBus, + IN UINTN PciDevice, + IN UINTN PciFunction, + IN OUT UINT8 *Pirq, + OUT UINT8 *PciIrq + ); + +/** + 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. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_BIOS_PLATFORM_PREPARE_TO_BOOT)( + 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 + ); + +/** + This protocol abstracts the platform portion of the traditional BIOS. +**/ +struct _EFI_LEGACY_BIOS_PLATFORM_PROTOCOL { + /// + /// Gets binary data or other platform information. + /// + EFI_LEGACY_BIOS_PLATFORM_GET_PLATFORM_INFO GetPlatformInfo; + /// + /// Returns a buffer of all handles matching the requested subfunction. + /// + EFI_LEGACY_BIOS_PLATFORM_GET_PLATFORM_HANDLE GetPlatformHandle; + /// + /// Loads and initializes the traditional BIOS SMM handler. + EFI_LEGACY_BIOS_PLATFORM_SMM_INIT SmmInit; + /// + /// Allows platform to perform any required actions after a LegacyBios operation. + /// + EFI_LEGACY_BIOS_PLATFORM_HOOKS PlatformHooks; + /// + /// Gets $PIR table. + EFI_LEGACY_BIOS_PLATFORM_GET_ROUTING_TABLE GetRoutingTable; + /// + /// Translates the given PIRQ to the final value after traversing any PCI bridges. + /// + EFI_LEGACY_BIOS_PLATFORM_TRANSLATE_PIRQ TranslatePirq; + /// + /// Final platform function before the system attempts to boot to a traditional OS. + /// + EFI_LEGACY_BIOS_PLATFORM_PREPARE_TO_BOOT PrepareToBoot; +}; + +extern EFI_GUID gEfiLegacyBiosPlatformProtocolGuid; + +#endif diff --git a/OvmfPkg/Csm/Include/Protocol/LegacyInterrupt.h b/OvmfPkg/Csm/Include/Protocol/LegacyInterrupt.h new file mode 100644 index 0000000000..b3ad2ffb3c --- /dev/null +++ b/OvmfPkg/Csm/Include/Protocol/LegacyInterrupt.h @@ -0,0 +1,122 @@ +/** @file + This protocol abstracts the PIRQ programming from the generic EFI Compatibility Support Modules (CSMs). + +Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Revision Reference: + This protocol is defined in Framework for the EFI Compatibility Support Module specification. + Version 0.97. + +**/ + +#ifndef _EFI_LEGACY_INTERRUPT_H_ +#define _EFI_LEGACY_INTERRUPT_H_ + + +#define EFI_LEGACY_INTERRUPT_PROTOCOL_GUID \ + { \ + 0x31ce593d, 0x108a, 0x485d, {0xad, 0xb2, 0x78, 0xf2, 0x1f, 0x29, 0x66, 0xbe } \ + } + +typedef struct _EFI_LEGACY_INTERRUPT_PROTOCOL EFI_LEGACY_INTERRUPT_PROTOCOL; + +/** + Get the number of PIRQs this hardware supports. + + @param This The protocol instance pointer. + @param NumberPirsq The number of PIRQs that are supported. + + @retval EFI_SUCCESS The number of PIRQs was returned successfully. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_INTERRUPT_GET_NUMBER_PIRQS)( + IN EFI_LEGACY_INTERRUPT_PROTOCOL *This, + OUT UINT8 *NumberPirqs + ); + +/** + Gets the PCI location associated with this protocol. + + @param This The Protocol instance pointer. + @param Bus The PCI Bus. + @param Device The PCI Device. + @param Function The PCI Function. + + @retval EFI_SUCCESS The Bus, Device, and Function were returned successfully. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_INTERRUPT_GET_LOCATION)( + IN EFI_LEGACY_INTERRUPT_PROTOCOL *This, + OUT UINT8 *Bus, + OUT UINT8 *Device, + OUT UINT8 *Function + ); + +/** + Read the PIRQ register and return the data + + @param This The protocol instance pointer. + @param PirqNumber The PIRQ register to read. + @param PirqData The data read. + + @retval EFI_SUCCESS The data was read. + @retval EFI_INVALID_PARAMETER Invalid PIRQ number. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_INTERRUPT_READ_PIRQ)( + IN EFI_LEGACY_INTERRUPT_PROTOCOL *This, + IN UINT8 PirqNumber, + OUT UINT8 *PirqData + ); + +/** + Write the specified PIRQ register with the given data. + + @param This The protocol instance pointer. + @param PirqNumber A PIRQ register to read. + @param PirqData The data to write. + + @retval EFI_SUCCESS The PIRQ was programmed. + @retval EFI_INVALID_PARAMETER Invalid PIRQ number. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_LEGACY_INTERRUPT_WRITE_PIRQ)( + IN EFI_LEGACY_INTERRUPT_PROTOCOL *This, + IN UINT8 PirqNumber, + IN UINT8 PirqData + ); + +struct _EFI_LEGACY_INTERRUPT_PROTOCOL { + /// + /// Gets the number of PIRQs supported. + /// + EFI_LEGACY_INTERRUPT_GET_NUMBER_PIRQS GetNumberPirqs; + + /// + /// Gets the PCI bus, device, and function that is associated with this protocol. + /// + EFI_LEGACY_INTERRUPT_GET_LOCATION GetLocation; + + /// + /// Reads the indicated PIRQ register. + /// + EFI_LEGACY_INTERRUPT_READ_PIRQ ReadPirq; + + /// + /// Writes to the indicated PIRQ register. + /// + EFI_LEGACY_INTERRUPT_WRITE_PIRQ WritePirq; +}; + +extern EFI_GUID gEfiLegacyInterruptProtocolGuid; + +#endif diff --git a/OvmfPkg/Csm/Include/Protocol/VgaMiniPort.h b/OvmfPkg/Csm/Include/Protocol/VgaMiniPort.h new file mode 100644 index 0000000000..41ff58e14c --- /dev/null +++ b/OvmfPkg/Csm/Include/Protocol/VgaMiniPort.h @@ -0,0 +1,88 @@ +/** @file + The VGA Mini Port Protocol used to set the text display mode of a VGA controller. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __VGA_MINI_PORT_H_ +#define __VGA_MINI_PORT_H_ + +/// +/// Global ID for the EFI_VGA_MINI_PORT_PROTOCOL. +/// +#define EFI_VGA_MINI_PORT_PROTOCOL_GUID \ + { \ + 0xc7735a2f, 0x88f5, 0x4882, {0xae, 0x63, 0xfa, 0xac, 0x8c, 0x8b, 0x86, 0xb3 } \ + } + +/// +/// Forward declaration for the EFI_VGA_MINI_PORT_PROTOCOL. +/// +typedef struct _EFI_VGA_MINI_PORT_PROTOCOL EFI_VGA_MINI_PORT_PROTOCOL; + +/** + Sets the text display mode of a VGA controller. + + Sets the text display mode of the VGA controller to the mode specified by + ModeNumber. A ModeNumber of 0 is a request for an 80x25 text mode. A + ModeNumber of 1 is a request for an 80x50 text mode. If ModeNumber is greater + than MaxModeNumber, then EFI_UNSUPPORTED is returned. If the VGA controller + is not functioning properly, then EFI_DEVICE_ERROR is returned. If the VGA + controller is sucessfully set to the mode number specified by ModeNumber, then + EFI_SUCCESS is returned. + + @param[in] This A pointer to the EFI_VGA_MINI_PORT_PROTOCOL instance. + @param[in] ModeNumber The requested mode number. 0 for 80x25. 1 for 80x5. + + @retval EFI_SUCCESS The mode number was set. + @retval EFI_UNSUPPORTED The mode number specified by ModeNumber is not supported. + @retval EFI_DEVICE_ERROR The device is not functioning properly. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_VGA_MINI_PORT_SET_MODE)( + IN EFI_VGA_MINI_PORT_PROTOCOL *This, + IN UINTN ModeNumber + ); + +struct _EFI_VGA_MINI_PORT_PROTOCOL { + EFI_VGA_MINI_PORT_SET_MODE SetMode; + /// + /// MMIO base address of the VGA text mode framebuffer. Typically set to 0xB8000. + /// + UINT64 VgaMemoryOffset; + /// + /// I/O Port address for the VGA CRTC address register. Typically set to 0x3D4. + /// + UINT64 CrtcAddressRegisterOffset; + /// + /// I/O Port address for the VGA CRTC data register. Typically set to 0x3D5. + /// + UINT64 CrtcDataRegisterOffset; + /// + /// PCI Controller MMIO BAR index of the VGA text mode frame buffer. Typically + /// set to EFI_PCI_IO_PASS_THROUGH_BAR + /// + UINT8 VgaMemoryBar; + /// + /// PCI Controller I/O BAR index of the VGA CRTC address register. Typically + /// set to EFI_PCI_IO_PASS_THROUGH_BAR + /// + UINT8 CrtcAddressRegisterBar; + /// + /// PCI Controller I/O BAR index of the VGA CRTC data register. Typically set + /// to EFI_PCI_IO_PASS_THROUGH_BAR + /// + UINT8 CrtcDataRegisterBar; + /// + /// The maximum number of text modes that this VGA controller supports. + /// + UINT8 MaxMode; +}; + +extern EFI_GUID gEfiVgaMiniPortProtocolGuid; + +#endif diff --git a/OvmfPkg/Csm/LegacyBiosDxe/IA32/InterruptTable.nasm b/OvmfPkg/Csm/LegacyBiosDxe/IA32/InterruptTable.nasm new file mode 100644 index 0000000000..90bfdffb0b --- /dev/null +++ b/OvmfPkg/Csm/LegacyBiosDxe/IA32/InterruptTable.nasm @@ -0,0 +1,63 @@ +;; @file +; Interrupt Redirection Template +; +; Copyright (c) 2016, Intel Corporation. All rights reserved.
+; +; SPDX-License-Identifier: BSD-2-Clause-Patent +; +;; + +SECTION .text + +;---------------------------------------------------------------------------- +; Procedure: InterruptRedirectionTemplate: Redirects interrupts 0x68-0x6F +; +; Input: None +; +; Output: None +; +; Prototype: VOID +; InterruptRedirectionTemplate ( +; VOID +; ); +; +; Saves: None +; +; Modified: None +; +; Description: Contains the code that is copied into low memory (below 640K). +; This code reflects interrupts 0x68-0x6f to interrupts 0x08-0x0f. +; This template must be copied into low memory, and the IDT entries +; 0x68-0x6F must be point to the low memory copy of this code. Each +; entry is 4 bytes long, so IDT entries 0x68-0x6F can be easily +; computed. +; +;---------------------------------------------------------------------------- + +global ASM_PFX(InterruptRedirectionTemplate) +ASM_PFX(InterruptRedirectionTemplate): + int 0x8 + DB 0xcf ; IRET + nop + int 0x9 + DB 0xcf ; IRET + nop + int 0xa + DB 0xcf ; IRET + nop + int 0xb + DB 0xcf ; IRET + nop + int 0xc + DB 0xcf ; IRET + nop + int 0xd + DB 0xcf ; IRET + nop + int 0xe + DB 0xcf ; IRET + nop + int 0xf + DB 0xcf ; IRET + nop + diff --git a/OvmfPkg/Csm/LegacyBiosDxe/LegacyBbs.c b/OvmfPkg/Csm/LegacyBiosDxe/LegacyBbs.c new file mode 100644 index 0000000000..6b1dd344f3 --- /dev/null +++ b/OvmfPkg/Csm/LegacyBiosDxe/LegacyBbs.c @@ -0,0 +1,377 @@ +/** @file + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "LegacyBiosInterface.h" +#include + +// Give floppy 3 states +// FLOPPY_PRESENT_WITH_MEDIA = Floppy controller present and media is inserted +// FLOPPY_NOT_PRESENT = No floppy controller present +// FLOPPY_PRESENT_NO_MEDIA = Floppy controller present but no media inserted +// +#define FLOPPY_NOT_PRESENT 0 +#define FLOPPY_PRESENT_WITH_MEDIA 1 +#define FLOPPY_PRESENT_NO_MEDIA 2 + +BBS_TABLE *mBbsTable; +BOOLEAN mBbsTableDoneFlag = FALSE; +BOOLEAN IsHaveMediaInFloppy = TRUE; + +/** + Checks the state of the floppy and if media is inserted. + + This routine checks the state of the floppy and if media is inserted. + There are 3 cases: + No floppy present - Set BBS entry to ignore + Floppy present & no media - Set BBS entry to lowest priority. We cannot + set it to ignore since 16-bit CSM will + indicate no floppy and thus drive A: is + unusable. CSM-16 will not try floppy since + lowest priority and thus not incur boot + time penality. + Floppy present & media - Set BBS entry to some priority. + + @return State of floppy media + +**/ +UINT8 +HasMediaInFloppy ( + VOID + ) +{ + EFI_STATUS Status; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN Index; + EFI_ISA_IO_PROTOCOL *IsaIo; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + + HandleBuffer = NULL; + HandleCount = 0; + + gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiIsaIoProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + + // + // If don't find any ISA/IO protocol assume no floppy. Need for floppy + // free system + // + if (HandleCount == 0) { + return FLOPPY_NOT_PRESENT; + } + + ASSERT (HandleBuffer != NULL); + + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiIsaIoProtocolGuid, + (VOID **) &IsaIo + ); + if (EFI_ERROR (Status)) { + continue; + } + + if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x604)) { + continue; + } + // + // Update blockio in case the floppy is inserted in during BdsTimeout + // + Status = gBS->DisconnectController (HandleBuffer[Index], NULL, NULL); + + if (EFI_ERROR (Status)) { + continue; + } + + Status = gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE); + + if (EFI_ERROR (Status)) { + continue; + } + + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiBlockIoProtocolGuid, + (VOID **) &BlkIo + ); + if (EFI_ERROR (Status)) { + continue; + } + + if (BlkIo->Media->MediaPresent) { + FreePool (HandleBuffer); + return FLOPPY_PRESENT_WITH_MEDIA; + } else { + FreePool (HandleBuffer); + return FLOPPY_PRESENT_NO_MEDIA; + } + } + + FreePool (HandleBuffer); + + return FLOPPY_NOT_PRESENT; + +} + + +/** + Complete build of BBS TABLE. + + @param Private Legacy BIOS Instance data + @param BbsTable BBS Table passed to 16-bit code + + @retval EFI_SUCCESS Removable media not present + +**/ +EFI_STATUS +LegacyBiosBuildBbs ( + IN LEGACY_BIOS_INSTANCE *Private, + IN BBS_TABLE *BbsTable + ) +{ + UINTN BbsIndex; + HDD_INFO *HddInfo; + UINTN HddIndex; + UINTN Index; + + // + // First entry is floppy. + // Next 2*MAX_IDE_CONTROLLER entries are for onboard IDE. + // Next n entries are filled in after each ROM is dispatched. + // Entry filled in if follow BBS spec. See LegacyPci.c + // Next entries are for non-BBS compliant ROMS. They are filled in by + // 16-bit code during Legacy16UpdateBbs invocation. Final BootPriority + // occurs after that invocation. + // + // Floppy + // Set default state. + // + IsHaveMediaInFloppy = HasMediaInFloppy (); + if (IsHaveMediaInFloppy == FLOPPY_PRESENT_WITH_MEDIA) { + BbsTable[0].BootPriority = BBS_UNPRIORITIZED_ENTRY; + } else { + if (IsHaveMediaInFloppy == FLOPPY_PRESENT_NO_MEDIA) { + BbsTable[0].BootPriority = BBS_LOWEST_PRIORITY; + } else { + BbsTable[0].BootPriority = BBS_IGNORE_ENTRY; + } + } + + BbsTable[0].Bus = 0xff; + BbsTable[0].Device = 0xff; + BbsTable[0].Function = 0xff; + BbsTable[0].DeviceType = BBS_FLOPPY; + BbsTable[0].Class = 01; + BbsTable[0].SubClass = 02; + BbsTable[0].StatusFlags.OldPosition = 0; + BbsTable[0].StatusFlags.Reserved1 = 0; + BbsTable[0].StatusFlags.Enabled = 0; + BbsTable[0].StatusFlags.Failed = 0; + BbsTable[0].StatusFlags.MediaPresent = 0; + BbsTable[0].StatusFlags.Reserved2 = 0; + + // + // Onboard HDD - Note Each HDD controller controls 2 drives + // Master & Slave + // + HddInfo = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo[0]; + // + // Get IDE Drive Info + // + LegacyBiosBuildIdeData (Private, &HddInfo, 0); + + for (HddIndex = 0; HddIndex < MAX_IDE_CONTROLLER; HddIndex++) { + + BbsIndex = HddIndex * 2 + 1; + for (Index = 0; Index < 2; ++Index) { + + BbsTable[BbsIndex + Index].Bus = HddInfo[HddIndex].Bus; + BbsTable[BbsIndex + Index].Device = HddInfo[HddIndex].Device; + BbsTable[BbsIndex + Index].Function = HddInfo[HddIndex].Function; + BbsTable[BbsIndex + Index].Class = 01; + BbsTable[BbsIndex + Index].SubClass = 01; + BbsTable[BbsIndex + Index].StatusFlags.OldPosition = 0; + BbsTable[BbsIndex + Index].StatusFlags.Reserved1 = 0; + BbsTable[BbsIndex + Index].StatusFlags.Enabled = 0; + BbsTable[BbsIndex + Index].StatusFlags.Failed = 0; + BbsTable[BbsIndex + Index].StatusFlags.MediaPresent = 0; + BbsTable[BbsIndex + Index].StatusFlags.Reserved2 = 0; + + // + // If no controller found or no device found set to ignore + // else set to unprioritized and set device type + // + if (HddInfo[HddIndex].CommandBaseAddress == 0) { + BbsTable[BbsIndex + Index].BootPriority = BBS_IGNORE_ENTRY; + } else { + if (Index == 0) { + if ((HddInfo[HddIndex].Status & (HDD_MASTER_IDE | HDD_MASTER_ATAPI_CDROM | HDD_MASTER_ATAPI_ZIPDISK)) != 0) { + BbsTable[BbsIndex + Index].BootPriority = BBS_UNPRIORITIZED_ENTRY; + if ((HddInfo[HddIndex].Status & HDD_MASTER_IDE) != 0) { + BbsTable[BbsIndex + Index].DeviceType = BBS_HARDDISK; + } else if ((HddInfo[HddIndex].Status & HDD_MASTER_ATAPI_CDROM) != 0) { + BbsTable[BbsIndex + Index].DeviceType = BBS_CDROM; + } else { + // + // for ZIPDISK + // + BbsTable[BbsIndex + Index].DeviceType = BBS_HARDDISK; + } + } else { + BbsTable[BbsIndex + Index].BootPriority = BBS_IGNORE_ENTRY; + } + } else { + if ((HddInfo[HddIndex].Status & (HDD_SLAVE_IDE | HDD_SLAVE_ATAPI_CDROM | HDD_SLAVE_ATAPI_ZIPDISK)) != 0) { + BbsTable[BbsIndex + Index].BootPriority = BBS_UNPRIORITIZED_ENTRY; + if ((HddInfo[HddIndex].Status & HDD_SLAVE_IDE) != 0) { + BbsTable[BbsIndex + Index].DeviceType = BBS_HARDDISK; + } else if ((HddInfo[HddIndex].Status & HDD_SLAVE_ATAPI_CDROM) != 0) { + BbsTable[BbsIndex + Index].DeviceType = BBS_CDROM; + } else { + // + // for ZIPDISK + // + BbsTable[BbsIndex + Index].DeviceType = BBS_HARDDISK; + } + } else { + BbsTable[BbsIndex + Index].BootPriority = BBS_IGNORE_ENTRY; + } + } + } + } + } + + return EFI_SUCCESS; + +} + + +/** + Get all BBS info + + @param This Protocol instance pointer. + @param HddCount Number of HDD_INFO structures + @param HddInfo Onboard IDE controller information + @param BbsCount Number of BBS_TABLE structures + @param BbsTable List BBS entries + + @retval EFI_SUCCESS Tables returned + @retval EFI_NOT_FOUND resource not found + @retval EFI_DEVICE_ERROR can not get BBS table + +**/ +EFI_STATUS +EFIAPI +LegacyBiosGetBbsInfo ( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + OUT UINT16 *HddCount, + OUT HDD_INFO **HddInfo, + OUT UINT16 *BbsCount, + OUT BBS_TABLE **BbsTable + ) +{ + LEGACY_BIOS_INSTANCE *Private; + EFI_IA32_REGISTER_SET Regs; + EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable; +// HDD_INFO *LocalHddInfo; +// IN BBS_TABLE *LocalBbsTable; + UINTN NumHandles; + EFI_HANDLE *HandleBuffer; + UINTN Index; + UINTN TempData; + UINT32 Granularity; + + HandleBuffer = NULL; + + Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); + EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable; +// LocalHddInfo = EfiToLegacy16BootTable->HddInfo; +// LocalBbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable; + + if (!mBbsTableDoneFlag) { + mBbsTable = Private->BbsTablePtr; + + // + // Always enable disk controllers so 16-bit CSM code has valid information for all + // drives. + // + // + // Get PciRootBridgeIO protocol + // + gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiPciRootBridgeIoProtocolGuid, + NULL, + &NumHandles, + &HandleBuffer + ); + + if (NumHandles == 0) { + return EFI_NOT_FOUND; + } + + mBbsTableDoneFlag = TRUE; + for (Index = 0; Index < NumHandles; Index++) { + // + // Connect PciRootBridgeIO protocol handle with FALSE parameter to let + // PCI bus driver enumerate all subsequent handles + // + gBS->ConnectController (HandleBuffer[Index], NULL, NULL, FALSE); + + } + + LegacyBiosBuildBbs (Private, mBbsTable); + + Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xe0000, 0x20000, &Granularity); + + // + // Call into Legacy16 code to add to BBS table for non BBS compliant OPROMs. + // + ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); + Regs.X.AX = Legacy16UpdateBbs; + + // + // Pass in handoff data + // + TempData = (UINTN) EfiToLegacy16BootTable; + Regs.X.ES = NORMALIZE_EFI_SEGMENT ((UINT32) TempData); + Regs.X.BX = NORMALIZE_EFI_OFFSET ((UINT32) TempData); + + Private->LegacyBios.FarCall86 ( + This, + Private->Legacy16CallSegment, + Private->Legacy16CallOffset, + &Regs, + NULL, + 0 + ); + + Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate); + Private->LegacyRegion->Lock (Private->LegacyRegion, 0xe0000, 0x20000, &Granularity); + + if (Regs.X.AX != 0) { + return EFI_DEVICE_ERROR; + } + } + + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + + *HddCount = MAX_IDE_CONTROLLER; + *HddInfo = EfiToLegacy16BootTable->HddInfo; + *BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable; + *BbsCount = (UINT16) (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE)); + return EFI_SUCCESS; +} diff --git a/OvmfPkg/Csm/LegacyBiosDxe/LegacyBda.c b/OvmfPkg/Csm/LegacyBiosDxe/LegacyBda.c new file mode 100644 index 0000000000..aa6e07ab91 --- /dev/null +++ b/OvmfPkg/Csm/LegacyBiosDxe/LegacyBda.c @@ -0,0 +1,62 @@ +/** @file + This code fills in BDA (0x400) and EBDA (pointed to by 0x4xx) + information. There is support for doing initializeation before + Legacy16 is loaded and before a legacy boot is attempted. + +Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "LegacyBiosInterface.h" + +/** + Fill in the standard BDA and EBDA stuff before Legacy16 load + + @param Private Legacy BIOS Instance data + + @retval EFI_SUCCESS It should always work. + +**/ +EFI_STATUS +LegacyBiosInitBda ( + IN LEGACY_BIOS_INSTANCE *Private + ) +{ + BDA_STRUC *Bda; + UINT8 *Ebda; + + Bda = (BDA_STRUC *) ((UINTN) 0x400); + Ebda = (UINT8 *) ((UINTN) 0x9fc00); + + ACCESS_PAGE0_CODE ( + ZeroMem (Bda, 0x100); + // + // 640k-1k for EBDA + // + Bda->MemSize = 0x27f; + Bda->KeyHead = 0x1e; + Bda->KeyTail = 0x1e; + Bda->FloppyData = 0x00; + Bda->FloppyTimeout = 0xff; + + Bda->KeyStart = 0x001E; + Bda->KeyEnd = 0x003E; + Bda->KeyboardStatus = 0x10; + Bda->Ebda = 0x9fc0; + + // + // Move LPT time out here and zero out LPT4 since some SCSI OPROMS + // use this as scratch pad (LPT4 is Reserved) + // + Bda->Lpt1_2Timeout = 0x1414; + Bda->Lpt3_4Timeout = 0x1400; + + ); + + ZeroMem (Ebda, 0x400); + *Ebda = 0x01; + + return EFI_SUCCESS; +} diff --git a/OvmfPkg/Csm/LegacyBiosDxe/LegacyBios.c b/OvmfPkg/Csm/LegacyBiosDxe/LegacyBios.c new file mode 100644 index 0000000000..05e3ffd2bb --- /dev/null +++ b/OvmfPkg/Csm/LegacyBiosDxe/LegacyBios.c @@ -0,0 +1,1214 @@ +/** @file + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "LegacyBiosInterface.h" + +#define PHYSICAL_ADDRESS_TO_POINTER(Address) ((VOID *) ((UINTN) Address)) + +// +// define maximum number of HDD system supports +// +#define MAX_HDD_ENTRIES 0x30 + +// +// Module Global: +// Since this driver will only ever produce one instance of the Private Data +// protocol you are not required to dynamically allocate the PrivateData. +// +LEGACY_BIOS_INSTANCE mPrivateData; + +// +// The SMBIOS table in EfiRuntimeServicesData memory +// +VOID *mRuntimeSmbiosEntryPoint = NULL; + +// +// The SMBIOS table in EfiReservedMemoryType memory +// +EFI_PHYSICAL_ADDRESS mReserveSmbiosEntryPoint = 0; +EFI_PHYSICAL_ADDRESS mStructureTableAddress = 0; +UINTN mStructureTablePages = 0; +BOOLEAN mEndOfDxe = FALSE; + +/** + Allocate memory for legacy usage. The memory is executable. + + @param AllocateType The type of allocation to perform. + @param MemoryType The type of memory to allocate. + @param StartPageAddress Start address of range + @param Pages Number of pages to allocate + @param Result Result of allocation + + @retval EFI_SUCCESS Legacy memory is allocated successfully. + @retval Other Legacy memory is not allocated. + +**/ +EFI_STATUS +AllocateLegacyMemory ( + IN EFI_ALLOCATE_TYPE AllocateType, + IN EFI_MEMORY_TYPE MemoryType, + IN EFI_PHYSICAL_ADDRESS StartPageAddress, + IN UINTN Pages, + OUT EFI_PHYSICAL_ADDRESS *Result + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS MemPage; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemDesc; + + // + // Allocate Pages of memory less <= StartPageAddress + // + MemPage = (EFI_PHYSICAL_ADDRESS) (UINTN) StartPageAddress; + Status = gBS->AllocatePages ( + AllocateType, + MemoryType, + Pages, + &MemPage + ); + // + // Do not ASSERT on Status error but let caller decide since some cases + // memory is already taken but that is ok. + // + if (!EFI_ERROR (Status)) { + if (MemoryType != EfiBootServicesCode) { + // + // Make sure that the buffer can be used to store code. + // + Status = gDS->GetMemorySpaceDescriptor (MemPage, &MemDesc); + if (!EFI_ERROR (Status) && (MemDesc.Attributes & EFI_MEMORY_XP) != 0) { + Status = gDS->SetMemorySpaceAttributes ( + MemPage, + EFI_PAGES_TO_SIZE (Pages), + MemDesc.Attributes & (~EFI_MEMORY_XP) + ); + } + if (EFI_ERROR (Status)) { + gBS->FreePages (MemPage, Pages); + } + } + } + + if (!EFI_ERROR (Status)) { + *Result = (EFI_PHYSICAL_ADDRESS) (UINTN) MemPage; + } + + return Status; +} + + +/** + This function is called when EFI needs to reserve an area in the 0xE0000 or 0xF0000 + 64 KB blocks. + + Note: inconsistency with the Framework CSM spec. Per the spec, this function may be + invoked only once. This limitation is relaxed to allow multiple calls in this implemenation. + + @param This Protocol instance pointer. + @param LegacyMemorySize Size of required region + @param Region Region to use. 00 = Either 0xE0000 or 0xF0000 + block Bit0 = 1 0xF0000 block Bit1 = 1 0xE0000 + block + @param Alignment Address alignment. Bit mapped. First non-zero + bit from right is alignment. + @param LegacyMemoryAddress Region Assigned + + @retval EFI_SUCCESS Region assigned + @retval EFI_ACCESS_DENIED Procedure previously invoked + @retval Other Region not assigned + +**/ +EFI_STATUS +EFIAPI +LegacyBiosGetLegacyRegion ( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN UINTN LegacyMemorySize, + IN UINTN Region, + IN UINTN Alignment, + OUT VOID **LegacyMemoryAddress + ) +{ + + LEGACY_BIOS_INSTANCE *Private; + EFI_IA32_REGISTER_SET Regs; + EFI_STATUS Status; + UINT32 Granularity; + + Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); + Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity); + + ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); + Regs.X.AX = Legacy16GetTableAddress; + Regs.X.BX = (UINT16) Region; + Regs.X.CX = (UINT16) LegacyMemorySize; + Regs.X.DX = (UINT16) Alignment; + Private->LegacyBios.FarCall86 ( + &Private->LegacyBios, + Private->Legacy16CallSegment, + Private->Legacy16CallOffset, + &Regs, + NULL, + 0 + ); + + if (Regs.X.AX == 0) { + *LegacyMemoryAddress = (VOID *) (((UINTN) Regs.X.DS << 4) + Regs.X.BX); + Status = EFI_SUCCESS; + } else { + Status = EFI_OUT_OF_RESOURCES; + } + + Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate); + Private->LegacyRegion->Lock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity); + + return Status; +} + + +/** + This function is called when copying data to the region assigned by + EFI_LEGACY_BIOS_PROTOCOL.GetLegacyRegion(). + + @param This Protocol instance pointer. + @param LegacyMemorySize Size of data to copy + @param LegacyMemoryAddress Legacy Region destination address Note: must + be in region assigned by + LegacyBiosGetLegacyRegion + @param LegacyMemorySourceAddress Source of data + + @retval EFI_SUCCESS The data was copied successfully. + @retval EFI_ACCESS_DENIED Either the starting or ending address is out of bounds. +**/ +EFI_STATUS +EFIAPI +LegacyBiosCopyLegacyRegion ( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN UINTN LegacyMemorySize, + IN VOID *LegacyMemoryAddress, + IN VOID *LegacyMemorySourceAddress + ) +{ + + LEGACY_BIOS_INSTANCE *Private; + UINT32 Granularity; + + if ((LegacyMemoryAddress < (VOID *)(UINTN)0xE0000 ) || + ((UINTN) LegacyMemoryAddress + LegacyMemorySize > (UINTN) 0x100000) + ) { + return EFI_ACCESS_DENIED; + } + // + // There is no protection from writes over lapping if this function is + // called multiple times. + // + Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); + Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity); + CopyMem (LegacyMemoryAddress, LegacyMemorySourceAddress, LegacyMemorySize); + + Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate); + Private->LegacyRegion->Lock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity); + + return EFI_SUCCESS; +} + + +/** + Find Legacy16 BIOS image in the FLASH device and shadow it into memory. Find + the $EFI table in the shadow area. Thunk into the Legacy16 code after it had + been shadowed. + + @param Private Legacy BIOS context data + + @retval EFI_SUCCESS Legacy16 code loaded + @retval Other No protocol installed, unload driver. + +**/ +EFI_STATUS +ShadowAndStartLegacy16 ( + IN LEGACY_BIOS_INSTANCE *Private + ) +{ + EFI_STATUS Status; + UINT8 *Ptr; + UINT8 *PtrEnd; + BOOLEAN Done; + EFI_COMPATIBILITY16_TABLE *Table; + UINT8 CheckSum; + EFI_IA32_REGISTER_SET Regs; + EFI_TO_COMPATIBILITY16_INIT_TABLE *EfiToLegacy16InitTable; + EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable; + VOID *LegacyBiosImage; + UINTN LegacyBiosImageSize; + UINTN E820Size; + UINT32 *ClearPtr; + BBS_TABLE *BbsTable; + LEGACY_EFI_HDD_TABLE *LegacyEfiHddTable; + UINTN Index; + UINT32 TpmPointer; + VOID *TpmBinaryImage; + UINTN TpmBinaryImageSize; + UINTN Location; + UINTN Alignment; + UINTN TempData; + EFI_PHYSICAL_ADDRESS Address; + UINT16 OldMask; + UINT16 NewMask; + UINT32 Granularity; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor; + + Location = 0; + Alignment = 0; + + // + // we allocate the C/D/E/F segment as RT code so no one will use it any more. + // + Address = 0xC0000; + gDS->GetMemorySpaceDescriptor (Address, &Descriptor); + if (Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) { + // + // If it is already reserved, we should be safe, or else we allocate it. + // + Status = gBS->AllocatePages ( + AllocateAddress, + EfiRuntimeServicesCode, + 0x40000/EFI_PAGE_SIZE, + &Address + ); + if (EFI_ERROR (Status)) { + // + // Bugbug: need to figure out whether C/D/E/F segment should be marked as reserved memory. + // + DEBUG ((DEBUG_ERROR, "Failed to allocate the C/D/E/F segment Status = %r", Status)); + } + } + + // + // start testtest + // GetTimerValue (&Ticker); + // + // gRT->SetVariable (L"StartLegacy", + // &gEfiGlobalVariableGuid, + // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + // sizeof (UINT64), + // (VOID *)&Ticker + // ); + // end testtest + // + EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable; + Status = Private->LegacyBiosPlatform->GetPlatformInfo ( + Private->LegacyBiosPlatform, + EfiGetPlatformBinarySystemRom, + &LegacyBiosImage, + &LegacyBiosImageSize, + &Location, + &Alignment, + 0, + 0 + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Private->BiosStart = (UINT32) (0x100000 - LegacyBiosImageSize); + Private->OptionRom = 0xc0000; + Private->LegacyBiosImageSize = (UINT32) LegacyBiosImageSize; + + // + // Can only shadow into memory allocated for legacy useage. + // + ASSERT (Private->BiosStart > Private->OptionRom); + + // + // Shadow Legacy BIOS. Turn on memory and copy image + // + Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xc0000, 0x40000, &Granularity); + + ClearPtr = (VOID *) ((UINTN) 0xc0000); + + // + // Initialize region from 0xc0000 to start of BIOS to all ffs. This allows unused + // regions to be used by EMM386 etc. + // + SetMem ((VOID *) ClearPtr, (UINTN) (0x40000 - LegacyBiosImageSize), 0xff); + + TempData = Private->BiosStart; + + CopyMem ( + (VOID *) TempData, + LegacyBiosImage, + (UINTN) LegacyBiosImageSize + ); + + Private->Cpu->FlushDataCache (Private->Cpu, 0xc0000, 0x40000, EfiCpuFlushTypeWriteBackInvalidate); + + // + // Search for Legacy16 table in Shadowed ROM + // + Done = FALSE; + Table = NULL; + for (Ptr = (UINT8 *) TempData; Ptr < (UINT8 *) ((UINTN) 0x100000) && !Done; Ptr += 0x10) { + if (*(UINT32 *) Ptr == SIGNATURE_32 ('I', 'F', 'E', '$')) { + Table = (EFI_COMPATIBILITY16_TABLE *) Ptr; + PtrEnd = Ptr + Table->TableLength; + for (CheckSum = 0; Ptr < PtrEnd; Ptr++) { + CheckSum = (UINT8) (CheckSum +*Ptr); + } + + Done = TRUE; + } + } + + if (Table == NULL) { + DEBUG ((EFI_D_ERROR, "No Legacy16 table found\n")); + return EFI_NOT_FOUND; + } + + if (!Done) { + // + // Legacy16 table header checksum error. + // + DEBUG ((EFI_D_ERROR, "Legacy16 table found with bad talbe header checksum\n")); + } + + // + // Remember location of the Legacy16 table + // + Private->Legacy16Table = Table; + Private->Legacy16CallSegment = Table->Compatibility16CallSegment; + Private->Legacy16CallOffset = Table->Compatibility16CallOffset; + EfiToLegacy16InitTable = &Private->IntThunk->EfiToLegacy16InitTable; + Private->Legacy16InitPtr = EfiToLegacy16InitTable; + Private->Legacy16BootPtr = &Private->IntThunk->EfiToLegacy16BootTable; + Private->InternalIrqRoutingTable = NULL; + Private->NumberIrqRoutingEntries = 0; + Private->BbsTablePtr = NULL; + Private->LegacyEfiHddTable = NULL; + Private->DiskEnd = 0; + Private->Disk4075 = 0; + Private->HddTablePtr = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo; + Private->NumberHddControllers = MAX_IDE_CONTROLLER; + Private->Dump[0] = 'D'; + Private->Dump[1] = 'U'; + Private->Dump[2] = 'M'; + Private->Dump[3] = 'P'; + + ZeroMem ( + Private->Legacy16BootPtr, + sizeof (EFI_TO_COMPATIBILITY16_BOOT_TABLE) + ); + + // + // Store away a copy of the EFI System Table + // + Table->EfiSystemTable = (UINT32) (UINTN) gST; + + // + // IPF CSM integration -Bug + // + // Construct the Legacy16 boot memory map. This sets up number of + // E820 entries. + // + LegacyBiosBuildE820 (Private, &E820Size); + // + // Initialize BDA and EBDA standard values needed to load Legacy16 code + // + LegacyBiosInitBda (Private); + LegacyBiosInitCmos (Private); + + // + // All legacy interrupt should be masked when do initialization work from legacy 16 code. + // + Private->Legacy8259->GetMask(Private->Legacy8259, &OldMask, NULL, NULL, NULL); + NewMask = 0xFFFF; + Private->Legacy8259->SetMask(Private->Legacy8259, &NewMask, NULL, NULL, NULL); + + // + // Call into Legacy16 code to do an INIT + // + ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); + Regs.X.AX = Legacy16InitializeYourself; + Regs.X.ES = EFI_SEGMENT (*((UINT32 *) &EfiToLegacy16InitTable)); + Regs.X.BX = EFI_OFFSET (*((UINT32 *) &EfiToLegacy16InitTable)); + + Private->LegacyBios.FarCall86 ( + &Private->LegacyBios, + Table->Compatibility16CallSegment, + Table->Compatibility16CallOffset, + &Regs, + NULL, + 0 + ); + + // + // Restore original legacy interrupt mask value + // + Private->Legacy8259->SetMask(Private->Legacy8259, &OldMask, NULL, NULL, NULL); + + if (Regs.X.AX != 0) { + return EFI_DEVICE_ERROR; + } + + // + // start testtest + // GetTimerValue (&Ticker); + // + // gRT->SetVariable (L"BackFromInitYourself", + // &gEfiGlobalVariableGuid, + // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + // sizeof (UINT64), + // (VOID *)&Ticker + // ); + // end testtest + // + // Copy E820 table after InitializeYourself is completed + // + ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); + Regs.X.AX = Legacy16GetTableAddress; + Regs.X.CX = (UINT16) E820Size; + Regs.X.DX = 1; + Private->LegacyBios.FarCall86 ( + &Private->LegacyBios, + Table->Compatibility16CallSegment, + Table->Compatibility16CallOffset, + &Regs, + NULL, + 0 + ); + + Table->E820Pointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX); + Table->E820Length = (UINT32) E820Size; + if (Regs.X.AX != 0) { + DEBUG ((EFI_D_ERROR, "Legacy16 E820 length insufficient\n")); + } else { + TempData = Table->E820Pointer; + CopyMem ((VOID *) TempData, Private->E820Table, E820Size); + } + // + // Get PnPInstallationCheck Info. + // + Private->PnPInstallationCheckSegment = Table->PnPInstallationCheckSegment; + Private->PnPInstallationCheckOffset = Table->PnPInstallationCheckOffset; + + // + // Check if PCI Express is supported. If yes, Save base address. + // + Status = Private->LegacyBiosPlatform->GetPlatformInfo ( + Private->LegacyBiosPlatform, + EfiGetPlatformPciExpressBase, + NULL, + NULL, + &Location, + &Alignment, + 0, + 0 + ); + if (!EFI_ERROR (Status)) { + Private->Legacy16Table->PciExpressBase = (UINT32)Location; + Location = 0; + } + // + // Check if TPM is supported. If yes get a region in E0000,F0000 to copy it + // into, copy it and update pointer to binary image. This needs to be + // done prior to any OPROM for security purposes. + // + Status = Private->LegacyBiosPlatform->GetPlatformInfo ( + Private->LegacyBiosPlatform, + EfiGetPlatformBinaryTpmBinary, + &TpmBinaryImage, + &TpmBinaryImageSize, + &Location, + &Alignment, + 0, + 0 + ); + if (!EFI_ERROR (Status)) { + + ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); + Regs.X.AX = Legacy16GetTableAddress; + Regs.X.CX = (UINT16) TpmBinaryImageSize; + Regs.X.DX = 1; + Private->LegacyBios.FarCall86 ( + &Private->LegacyBios, + Table->Compatibility16CallSegment, + Table->Compatibility16CallOffset, + &Regs, + NULL, + 0 + ); + + TpmPointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX); + if (Regs.X.AX != 0) { + DEBUG ((EFI_D_ERROR, "TPM cannot be loaded\n")); + } else { + CopyMem ((VOID *) (UINTN)TpmPointer, TpmBinaryImage, TpmBinaryImageSize); + Table->TpmSegment = Regs.X.DS; + Table->TpmOffset = Regs.X.BX; + + } + } + // + // Lock the Legacy BIOS region + // + Private->Cpu->FlushDataCache (Private->Cpu, Private->BiosStart, (UINT32) LegacyBiosImageSize, EfiCpuFlushTypeWriteBackInvalidate); + Private->LegacyRegion->Lock (Private->LegacyRegion, Private->BiosStart, (UINT32) LegacyBiosImageSize, &Granularity); + + // + // Get the BbsTable from LOW_MEMORY_THUNK + // + BbsTable = (BBS_TABLE *)(UINTN)Private->IntThunk->BbsTable; + ZeroMem ((VOID *)BbsTable, sizeof (Private->IntThunk->BbsTable)); + + EfiToLegacy16BootTable->BbsTable = (UINT32)(UINTN)BbsTable; + Private->BbsTablePtr = (VOID *) BbsTable; + // + // Skip Floppy and possible onboard IDE drives + // + EfiToLegacy16BootTable->NumberBbsEntries = 1 + 2 * MAX_IDE_CONTROLLER; + + for (Index = 0; Index < (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE)); Index++) { + BbsTable[Index].BootPriority = BBS_IGNORE_ENTRY; + } + // + // Allocate space for Legacy HDD table + // + LegacyEfiHddTable = (LEGACY_EFI_HDD_TABLE *) AllocateZeroPool ((UINTN) MAX_HDD_ENTRIES * sizeof (LEGACY_EFI_HDD_TABLE)); + ASSERT (LegacyEfiHddTable); + + Private->LegacyEfiHddTable = LegacyEfiHddTable; + Private->LegacyEfiHddTableIndex = 0x00; + + // + // start testtest + // GetTimerValue (&Ticker); + // + // gRT->SetVariable (L"EndOfLoadFv", + // &gEfiGlobalVariableGuid, + // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + // sizeof (UINT64), + // (VOID *)&Ticker + // ); + // end testtest + // + return EFI_SUCCESS; +} + +/** + Shadow all legacy16 OPROMs that haven't been shadowed. + Warning: Use this with caution. This routine disconnects all EFI + drivers. If used externally then caller must re-connect EFI + drivers. + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS OPROMs shadowed + +**/ +EFI_STATUS +EFIAPI +LegacyBiosShadowAllLegacyOproms ( + IN EFI_LEGACY_BIOS_PROTOCOL *This + ) +{ + LEGACY_BIOS_INSTANCE *Private; + + // + // EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform; + // EFI_LEGACY16_TABLE *Legacy16Table; + // + Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); + + // + // LegacyBiosPlatform = Private->LegacyBiosPlatform; + // Legacy16Table = Private->Legacy16Table; + // + // Shadow PCI ROMs. We must do this near the end since this will kick + // of Native EFI drivers that may be needed to collect info for Legacy16 + // + // WARNING: PciIo is gone after this call. + // + PciProgramAllInterruptLineRegisters (Private); + + PciShadowRoms (Private); + + // + // Shadow PXE base code, BIS etc. + // + // LegacyBiosPlatform->ShadowServiceRoms (LegacyBiosPlatform, + // &Private->OptionRom, + // Legacy16Table); + // + return EFI_SUCCESS; +} + +/** + Get the PCI BIOS interface version. + + @param Private Driver private data. + + @return The PCI interface version number in Binary Coded Decimal (BCD) format. + E.g.: 0x0210 indicates 2.10, 0x0300 indicates 3.00 + +**/ +UINT16 +GetPciInterfaceVersion ( + IN LEGACY_BIOS_INSTANCE *Private + ) +{ + EFI_IA32_REGISTER_SET Reg; + BOOLEAN ThunkFailed; + UINT16 PciInterfaceVersion; + + PciInterfaceVersion = 0; + + Reg.X.AX = 0xB101; + Reg.E.EDI = 0; + + ThunkFailed = Private->LegacyBios.Int86 (&Private->LegacyBios, 0x1A, &Reg); + if (!ThunkFailed) { + // + // From PCI Firmware 3.0 Specification: + // If the CARRY FLAG [CF] is cleared and AH is set to 00h, it is still necessary to examine the + // contents of [EDX] for the presence of the string "PCI" + (trailing space) to fully validate the + // presence of the PCI function set. [BX] will further indicate the version level, with enough + // granularity to allow for incremental changes in the code that don't affect the function interface. + // Version numbers are stored as Binary Coded Decimal (BCD) values. For example, Version 2.10 + // would be returned as a 02h in the [BH] registers and 10h in the [BL] registers. + // + if ((Reg.X.Flags.CF == 0) && (Reg.H.AH == 0) && (Reg.E.EDX == SIGNATURE_32 ('P', 'C', 'I', ' '))) { + PciInterfaceVersion = Reg.X.BX; + } + } + return PciInterfaceVersion; +} + +/** + Callback function to calculate SMBIOS table size, and allocate memory for SMBIOS table. + SMBIOS table will be copied into EfiReservedMemoryType memory in legacy boot path. + + @param Event Event whose notification function is being invoked. + @param Context The pointer to the notification function's context, + which is implementation-dependent. + +**/ +VOID +EFIAPI +InstallSmbiosEventCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + SMBIOS_TABLE_ENTRY_POINT *EntryPointStructure; + + // + // Get SMBIOS table from EFI configuration table + // + Status = EfiGetSystemConfigurationTable ( + &gEfiSmbiosTableGuid, + &mRuntimeSmbiosEntryPoint + ); + if ((EFI_ERROR (Status)) || (mRuntimeSmbiosEntryPoint == NULL)) { + return; + } + + EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *) mRuntimeSmbiosEntryPoint; + + // + // Allocate memory for SMBIOS Entry Point Structure. + // CSM framework spec requires SMBIOS table below 4GB in EFI_TO_COMPATIBILITY16_BOOT_TABLE. + // + if (mReserveSmbiosEntryPoint == 0) { + // + // Entrypoint structure with fixed size is allocated only once. + // + mReserveSmbiosEntryPoint = SIZE_4GB - 1; + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiReservedMemoryType, + EFI_SIZE_TO_PAGES ((UINTN) (EntryPointStructure->EntryPointLength)), + &mReserveSmbiosEntryPoint + ); + if (EFI_ERROR (Status)) { + mReserveSmbiosEntryPoint = 0; + return; + } + DEBUG ((EFI_D_INFO, "Allocate memory for Smbios Entry Point Structure\n")); + } + + if ((mStructureTableAddress != 0) && + (mStructureTablePages < EFI_SIZE_TO_PAGES ((UINT32)EntryPointStructure->TableLength))) { + // + // If original buffer is not enough for the new SMBIOS table, free original buffer and re-allocate + // + gBS->FreePages (mStructureTableAddress, mStructureTablePages); + mStructureTableAddress = 0; + mStructureTablePages = 0; + DEBUG ((EFI_D_INFO, "Original size is not enough. Re-allocate the memory.\n")); + } + + if (mStructureTableAddress == 0) { + // + // Allocate reserved memory below 4GB. + // Smbios spec requires the structure table is below 4GB. + // + mStructureTableAddress = SIZE_4GB - 1; + mStructureTablePages = EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength); + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiReservedMemoryType, + mStructureTablePages, + &mStructureTableAddress + ); + if (EFI_ERROR (Status)) { + gBS->FreePages ( + mReserveSmbiosEntryPoint, + EFI_SIZE_TO_PAGES ((UINTN) (EntryPointStructure->EntryPointLength)) + ); + mReserveSmbiosEntryPoint = 0; + mStructureTableAddress = 0; + mStructureTablePages = 0; + return; + } + DEBUG ((EFI_D_INFO, "Allocate memory for Smbios Structure Table\n")); + } +} + +/** + Callback function to toggle EndOfDxe status. NULL pointer detection needs + this status to decide if it's necessary to change attributes of page 0. + + @param Event Event whose notification function is being invoked. + @param Context The pointer to the notification function's context, + which is implementation-dependent. + +**/ +VOID +EFIAPI +ToggleEndOfDxeStatus ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + mEndOfDxe = TRUE; + return; +} + +/** + Install Driver to produce Legacy BIOS protocol. + + @param ImageHandle Handle of driver image. + @param SystemTable Pointer to system table. + + @retval EFI_SUCCESS Legacy BIOS protocol installed + @retval No protocol installed, unload driver. + +**/ +EFI_STATUS +EFIAPI +LegacyBiosInstall ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + LEGACY_BIOS_INSTANCE *Private; + EFI_TO_COMPATIBILITY16_INIT_TABLE *EfiToLegacy16InitTable; + EFI_PHYSICAL_ADDRESS MemoryAddress; + EFI_PHYSICAL_ADDRESS EbdaReservedBaseAddress; + VOID *MemoryPtr; + EFI_PHYSICAL_ADDRESS MemoryAddressUnder1MB; + UINTN Index; + UINT32 *BaseVectorMaster; + EFI_PHYSICAL_ADDRESS StartAddress; + UINT32 *ClearPtr; + EFI_PHYSICAL_ADDRESS MemStart; + UINT32 IntRedirCode; + UINT32 Granularity; + BOOLEAN DecodeOn; + UINT32 MemorySize; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor; + UINT64 Length; + UINT8 *SecureBoot; + EFI_EVENT InstallSmbiosEvent; + EFI_EVENT EndOfDxeEvent; + + // + // Load this driver's image to memory + // + Status = RelocateImageUnder4GIfNeeded (ImageHandle, SystemTable); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // When UEFI Secure Boot is enabled, CSM module will not start any more. + // + SecureBoot = NULL; + GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&SecureBoot, NULL); + if ((SecureBoot != NULL) && (*SecureBoot == SECURE_BOOT_MODE_ENABLE)) { + FreePool (SecureBoot); + return EFI_SECURITY_VIOLATION; + } + + if (SecureBoot != NULL) { + FreePool (SecureBoot); + } + + Private = &mPrivateData; + ZeroMem (Private, sizeof (LEGACY_BIOS_INSTANCE)); + + // + // Grab a copy of all the protocols we depend on. Any error would + // be a dispatcher bug!. + // + Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &Private->Cpu); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol (&gEfiTimerArchProtocolGuid, NULL, (VOID **) &Private->Timer); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol (&gEfiLegacyRegion2ProtocolGuid, NULL, (VOID **) &Private->LegacyRegion); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol (&gEfiLegacyBiosPlatformProtocolGuid, NULL, (VOID **) &Private->LegacyBiosPlatform); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **) &Private->Legacy8259); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol (&gEfiLegacyInterruptProtocolGuid, NULL, (VOID **) &Private->LegacyInterrupt); + ASSERT_EFI_ERROR (Status); + + // + // Locate Memory Test Protocol if exists + // + Status = gBS->LocateProtocol ( + &gEfiGenericMemTestProtocolGuid, + NULL, + (VOID **) &Private->GenericMemoryTest + ); + ASSERT_EFI_ERROR (Status); + + // + // Make sure all memory from 0-640K is tested + // + for (StartAddress = 0; StartAddress < 0xa0000; ) { + gDS->GetMemorySpaceDescriptor (StartAddress, &Descriptor); + if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) { + StartAddress = Descriptor.BaseAddress + Descriptor.Length; + continue; + } + Length = MIN (Descriptor.Length, 0xa0000 - StartAddress); + Private->GenericMemoryTest->CompatibleRangeTest ( + Private->GenericMemoryTest, + StartAddress, + Length + ); + StartAddress = StartAddress + Length; + } + // + // Make sure all memory from 1MB to 16MB is tested and added to memory map + // + for (StartAddress = BASE_1MB; StartAddress < BASE_16MB; ) { + gDS->GetMemorySpaceDescriptor (StartAddress, &Descriptor); + if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) { + StartAddress = Descriptor.BaseAddress + Descriptor.Length; + continue; + } + Length = MIN (Descriptor.Length, BASE_16MB - StartAddress); + Private->GenericMemoryTest->CompatibleRangeTest ( + Private->GenericMemoryTest, + StartAddress, + Length + ); + StartAddress = StartAddress + Length; + } + + Private->Signature = LEGACY_BIOS_INSTANCE_SIGNATURE; + + Private->LegacyBios.Int86 = LegacyBiosInt86; + Private->LegacyBios.FarCall86 = LegacyBiosFarCall86; + Private->LegacyBios.CheckPciRom = LegacyBiosCheckPciRom; + Private->LegacyBios.InstallPciRom = LegacyBiosInstallPciRom; + Private->LegacyBios.LegacyBoot = LegacyBiosLegacyBoot; + Private->LegacyBios.UpdateKeyboardLedStatus = LegacyBiosUpdateKeyboardLedStatus; + Private->LegacyBios.GetBbsInfo = LegacyBiosGetBbsInfo; + Private->LegacyBios.ShadowAllLegacyOproms = LegacyBiosShadowAllLegacyOproms; + Private->LegacyBios.PrepareToBootEfi = LegacyBiosPrepareToBootEfi; + Private->LegacyBios.GetLegacyRegion = LegacyBiosGetLegacyRegion; + Private->LegacyBios.CopyLegacyRegion = LegacyBiosCopyLegacyRegion; + Private->LegacyBios.BootUnconventionalDevice = LegacyBiosBootUnconventionalDevice; + + Private->ImageHandle = ImageHandle; + + // + // Enable read attribute of legacy region. + // + DecodeOn = TRUE; + Private->LegacyRegion->Decode ( + Private->LegacyRegion, + 0xc0000, + 0x40000, + &Granularity, + &DecodeOn + ); + // + // Set Cachebility for legacy region + // BUGBUG: Comments about this legacy region cacheability setting + // This setting will make D865GCHProduction CSM Unhappy + // + if (PcdGetBool (PcdLegacyBiosCacheLegacyRegion)) { + gDS->SetMemorySpaceAttributes ( + 0x0, + 0xA0000, + EFI_MEMORY_WB + ); + gDS->SetMemorySpaceAttributes ( + 0xc0000, + 0x40000, + EFI_MEMORY_WB + ); + } + + gDS->SetMemorySpaceAttributes ( + 0xA0000, + 0x20000, + EFI_MEMORY_UC + ); + + // + // Allocate 0 - 4K for real mode interupt vectors and BDA. + // + AllocateLegacyMemory ( + AllocateAddress, + EfiReservedMemoryType, + 0, + 1, + &MemoryAddress + ); + ASSERT (MemoryAddress == 0x000000000); + + ClearPtr = (VOID *) ((UINTN) 0x0000); + + // + // Initialize region from 0x0000 to 4k. This initializes interrupt vector + // range. + // + ACCESS_PAGE0_CODE ( + gBS->SetMem ((VOID *) ClearPtr, 0x400, INITIAL_VALUE_BELOW_1K); + ZeroMem ((VOID *) ((UINTN)ClearPtr + 0x400), 0xC00); + ); + + // + // Allocate pages for OPROM usage + // + MemorySize = PcdGet32 (PcdEbdaReservedMemorySize); + ASSERT ((MemorySize & 0xFFF) == 0); + + Status = AllocateLegacyMemory ( + AllocateAddress, + EfiReservedMemoryType, + CONVENTIONAL_MEMORY_TOP - MemorySize, + EFI_SIZE_TO_PAGES (MemorySize), + &MemoryAddress + ); + ASSERT_EFI_ERROR (Status); + + ZeroMem ((VOID *) ((UINTN) MemoryAddress), MemorySize); + + // + // Allocate all 32k chunks from 0x60000 ~ 0x88000 for Legacy OPROMs that + // don't use PMM but look for zeroed memory. Note that various non-BBS + // OpROMs expect different areas to be free + // + EbdaReservedBaseAddress = MemoryAddress; + MemoryAddress = PcdGet32 (PcdOpromReservedMemoryBase); + MemorySize = PcdGet32 (PcdOpromReservedMemorySize); + // + // Check if base address and size for reserved memory are 4KB aligned. + // + ASSERT ((MemoryAddress & 0xFFF) == 0); + ASSERT ((MemorySize & 0xFFF) == 0); + // + // Check if the reserved memory is below EBDA reserved range. + // + ASSERT ((MemoryAddress < EbdaReservedBaseAddress) && ((MemoryAddress + MemorySize - 1) < EbdaReservedBaseAddress)); + for (MemStart = MemoryAddress; MemStart < MemoryAddress + MemorySize; MemStart += 0x1000) { + Status = AllocateLegacyMemory ( + AllocateAddress, + EfiBootServicesCode, + MemStart, + 1, + &StartAddress + ); + if (!EFI_ERROR (Status)) { + MemoryPtr = (VOID *) ((UINTN) StartAddress); + ZeroMem (MemoryPtr, 0x1000); + } else { + DEBUG ((EFI_D_ERROR, "WARNING: Allocate legacy memory fail for SCSI card - %x\n", MemStart)); + } + } + + // + // Allocate low PMM memory and zero it out + // + MemorySize = PcdGet32 (PcdLowPmmMemorySize); + ASSERT ((MemorySize & 0xFFF) == 0); + Status = AllocateLegacyMemory ( + AllocateMaxAddress, + EfiBootServicesCode, + CONVENTIONAL_MEMORY_TOP, + EFI_SIZE_TO_PAGES (MemorySize), + &MemoryAddressUnder1MB + ); + ASSERT_EFI_ERROR (Status); + + ZeroMem ((VOID *) ((UINTN) MemoryAddressUnder1MB), MemorySize); + + // + // Allocate space for thunker and Init Thunker + // + Status = AllocateLegacyMemory ( + AllocateMaxAddress, + EfiReservedMemoryType, + CONVENTIONAL_MEMORY_TOP, + (sizeof (LOW_MEMORY_THUNK) / EFI_PAGE_SIZE) + 2, + &MemoryAddress + ); + ASSERT_EFI_ERROR (Status); + Private->IntThunk = (LOW_MEMORY_THUNK *) (UINTN) MemoryAddress; + EfiToLegacy16InitTable = &Private->IntThunk->EfiToLegacy16InitTable; + EfiToLegacy16InitTable->ThunkStart = (UINT32) (EFI_PHYSICAL_ADDRESS) (UINTN) MemoryAddress; + EfiToLegacy16InitTable->ThunkSizeInBytes = (UINT32) (sizeof (LOW_MEMORY_THUNK)); + + Status = LegacyBiosInitializeThunk (Private); + ASSERT_EFI_ERROR (Status); + + // + // Init the legacy memory map in memory < 1 MB. + // + EfiToLegacy16InitTable->BiosLessThan1MB = (UINT32) MemoryAddressUnder1MB; + EfiToLegacy16InitTable->LowPmmMemory = (UINT32) MemoryAddressUnder1MB; + EfiToLegacy16InitTable->LowPmmMemorySizeInBytes = MemorySize; + + MemorySize = PcdGet32 (PcdHighPmmMemorySize); + ASSERT ((MemorySize & 0xFFF) == 0); + // + // Allocate high PMM Memory under 16 MB + // + Status = AllocateLegacyMemory ( + AllocateMaxAddress, + EfiBootServicesCode, + 0x1000000, + EFI_SIZE_TO_PAGES (MemorySize), + &MemoryAddress + ); + if (EFI_ERROR (Status)) { + // + // If it fails, allocate high PMM Memory under 4GB + // + Status = AllocateLegacyMemory ( + AllocateMaxAddress, + EfiBootServicesCode, + 0xFFFFFFFF, + EFI_SIZE_TO_PAGES (MemorySize), + &MemoryAddress + ); + } + if (!EFI_ERROR (Status)) { + EfiToLegacy16InitTable->HiPmmMemory = (UINT32) (EFI_PHYSICAL_ADDRESS) (UINTN) MemoryAddress; + EfiToLegacy16InitTable->HiPmmMemorySizeInBytes = MemorySize; + } + + // + // ShutdownAPs(); + // + // Start the Legacy BIOS; + // + Status = ShadowAndStartLegacy16 (Private); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Initialize interrupt redirection code and entries; + // IDT Vectors 0x68-0x6f must be redirected to IDT Vectors 0x08-0x0f. + // + CopyMem ( + Private->IntThunk->InterruptRedirectionCode, + (VOID *) (UINTN) InterruptRedirectionTemplate, + sizeof (Private->IntThunk->InterruptRedirectionCode) + ); + + // + // Save Unexpected interrupt vector so can restore it just prior to boot + // + ACCESS_PAGE0_CODE ( + BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER); + Private->BiosUnexpectedInt = BaseVectorMaster[0]; + IntRedirCode = (UINT32) (UINTN) Private->IntThunk->InterruptRedirectionCode; + for (Index = 0; Index < 8; Index++) { + BaseVectorMaster[Index] = (EFI_SEGMENT (IntRedirCode + Index * 4) << 16) | EFI_OFFSET (IntRedirCode + Index * 4); + } + ); + + // + // Save EFI value + // + Private->ThunkSeg = (UINT16) (EFI_SEGMENT (IntRedirCode)); + + // + // Allocate reserved memory for SMBIOS table used in legacy boot if SMBIOS table exists + // + InstallSmbiosEventCallback (NULL, NULL); + + // + // Create callback function to update the size of reserved memory after LegacyBiosDxe starts + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + InstallSmbiosEventCallback, + NULL, + &gEfiSmbiosTableGuid, + &InstallSmbiosEvent + ); + ASSERT_EFI_ERROR (Status); + + // + // Create callback to update status of EndOfDxe, which is needed by NULL + // pointer detection + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + ToggleEndOfDxeStatus, + NULL, + &gEfiEndOfDxeEventGroupGuid, + &EndOfDxeEvent + ); + ASSERT_EFI_ERROR (Status); + + // + // Make a new handle and install the protocol + // + Private->Handle = NULL; + Status = gBS->InstallProtocolInterface ( + &Private->Handle, + &gEfiLegacyBiosProtocolGuid, + EFI_NATIVE_INTERFACE, + &Private->LegacyBios + ); + Private->Csm16PciInterfaceVersion = GetPciInterfaceVersion (Private); + + DEBUG ((EFI_D_INFO, "CSM16 PCI BIOS Interface Version: %02x.%02x\n", + (UINT8) (Private->Csm16PciInterfaceVersion >> 8), + (UINT8) Private->Csm16PciInterfaceVersion + )); + ASSERT (Private->Csm16PciInterfaceVersion != 0); + return Status; +} diff --git a/OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf b/OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf new file mode 100644 index 0000000000..471d37365c --- /dev/null +++ b/OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf @@ -0,0 +1,131 @@ +## @file +# Legacy Bios Module to support CSM. +# +# This driver installs Legacy Bios Protocol to support CSM module work in EFI system. +# +# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = LegacyBiosDxe + MODULE_UNI_FILE = LegacyBiosDxe.uni + FILE_GUID = F122A15C-C10B-4d54-8F48-60F4F06DD1AD + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = LegacyBiosInstall + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + LegacyCmos.c + LegacyIde.c + LegacyBios.c + LegacyBda.c + LegacyBiosInterface.h + LegacyPci.c + +[Sources.Ia32] + IA32/InterruptTable.nasm + Thunk.c + LegacyBootSupport.c + LegacyBbs.c + LegacySio.c + +[Sources.X64] + X64/InterruptTable.nasm + Thunk.c + LegacyBootSupport.c + LegacyBbs.c + LegacySio.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec + + +[LibraryClasses] + DevicePathLib + UefiBootServicesTableLib + MemoryAllocationLib + UefiDriverEntryPoint + BaseMemoryLib + UefiLib + DebugLib + DxeServicesTableLib + PcdLib + ReportStatusCodeLib + DebugAgentLib + +[LibraryClasses.IA32] + IoLib + HobLib + UefiRuntimeServicesTableLib + BaseLib + +[LibraryClasses.X64] + IoLib + HobLib + UefiRuntimeServicesTableLib + BaseLib + +[Guids] + gEfiDiskInfoIdeInterfaceGuid ## SOMETIMES_CONSUMES ##GUID #Used in LegacyBiosBuildIdeData() to assure device is a disk + gEfiSmbiosTableGuid ## SOMETIMES_CONSUMES ##SystemTable + gEfiLegacyBiosGuid ## SOMETIMES_CONSUMES ##GUID #Used in LegacyBiosInstallVgaRom() to locate handle buffer + gEfiEndOfDxeEventGroupGuid ## CONSUMES + +[Guids.IA32] + gEfiAcpi20TableGuid ## SOMETIMES_CONSUMES ##SystemTable + gEfiAcpi10TableGuid ## SOMETIMES_CONSUMES ##SystemTable + +[Guids.X64] + gEfiAcpi20TableGuid ## SOMETIMES_CONSUMES ##SystemTable + gEfiAcpi10TableGuid ## SOMETIMES_CONSUMES ##SystemTable + + +[Protocols] + gEfiLoadedImageProtocolGuid ## SOMETIMES_CONSUMES + gEfiDevicePathProtocolGuid ## SOMETIMES_CONSUMES + gEfiPciRootBridgeIoProtocolGuid ## SOMETIMES_CONSUMES + gEfiCpuArchProtocolGuid ## CONSUMES + gEfiTimerArchProtocolGuid ## CONSUMES + gEfiIsaIoProtocolGuid ## SOMETIMES_CONSUMES + gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES + gEfiPciIoProtocolGuid ## SOMETIMES_CONSUMES + gEfiGenericMemTestProtocolGuid ## CONSUMES + gEfiDiskInfoProtocolGuid ## SOMETIMES_CONSUMES + gEfiSimpleTextInProtocolGuid ## SOMETIMES_CONSUMES + gEfiLegacy8259ProtocolGuid ## CONSUMES + gEfiLegacyBiosPlatformProtocolGuid ## CONSUMES + gEfiLegacyInterruptProtocolGuid ## CONSUMES + gEfiLegacyRegion2ProtocolGuid ## CONSUMES + gEfiLegacyBiosProtocolGuid ## PRODUCES + gEfiSerialIoProtocolGuid ## CONSUMES + gEfiSioProtocolGuid ## CONSUMES + gEdkiiIoMmuProtocolGuid ## CONSUMES + +[Pcd] + gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdLegacyBiosCacheLegacyRegion ## CONSUMES + gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdEbdaReservedMemorySize ## CONSUMES + gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdEndOpromShadowAddress ## SOMETIMES_CONSUMES + gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdLowPmmMemorySize ## CONSUMES + gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdHighPmmMemorySize ## CONSUMES + gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdOpromReservedMemoryBase ## CONSUMES + gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdOpromReservedMemorySize ## CONSUMES + +[Depex] + gEfiLegacyRegion2ProtocolGuid AND gEfiLegacyInterruptProtocolGuid AND gEfiLegacyBiosPlatformProtocolGuid AND gEfiLegacy8259ProtocolGuid AND gEfiGenericMemTestProtocolGuid AND gEfiCpuArchProtocolGuid AND gEfiTimerArchProtocolGuid AND gEfiVariableWriteArchProtocolGuid + +[UserExtensions.TianoCore."ExtraFiles"] + LegacyBiosDxeExtra.uni diff --git a/OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxe.uni b/OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxe.uni new file mode 100644 index 0000000000..1a41d6d856 --- /dev/null +++ b/OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxe.uni @@ -0,0 +1,16 @@ +// /** @file +// Legacy Bios Module to support CSM. +// +// This driver installs Legacy Bios Protocol to support CSM module work in EFI system. +// +// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Legacy Bios Module to support CSM" + +#string STR_MODULE_DESCRIPTION #language en-US "This driver installs Legacy Bios Protocol to support CSM module work in a EFI system." + diff --git a/OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxeExtra.uni b/OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxeExtra.uni new file mode 100644 index 0000000000..a02e783d94 --- /dev/null +++ b/OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxeExtra.uni @@ -0,0 +1,14 @@ +// /** @file +// LegacyBiosDxe Localized Strings and Content +// +// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"Legacy BIOS Support DXE Driver" + + diff --git a/OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosInterface.h b/OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosInterface.h new file mode 100644 index 0000000000..a72c8470f6 --- /dev/null +++ b/OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosInterface.h @@ -0,0 +1,1460 @@ +/** @file + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _LEGACY_BIOS_INTERFACE_ +#define _LEGACY_BIOS_INTERFACE_ + + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// BUGBUG: This entry maybe changed to PCD in future and wait for +// redesign of BDS library +// +#define MAX_BBS_ENTRIES 0x100 + +// +// Thunk Status Codes +// (These apply only to errors with the thunk and not to the code that was +// thunked to.) +// +#define THUNK_OK 0x00 +#define THUNK_ERR_A20_UNSUP 0x01 +#define THUNK_ERR_A20_FAILED 0x02 + +// +// Vector base definitions +// +// +// 8259 Hardware definitions +// +#define LEGACY_MODE_BASE_VECTOR_MASTER 0x08 +#define LEGACY_MODE_BASE_VECTOR_SLAVE 0x70 + +// +// The original PC used INT8-F for master PIC. Since these mapped over +// processor exceptions TIANO moved the master PIC to INT68-6F. +// +// The vector base for slave PIC is set as 0x70 for PC-AT compatibility. +// +#define PROTECTED_MODE_BASE_VECTOR_MASTER 0x68 +#define PROTECTED_MODE_BASE_VECTOR_SLAVE 0x70 + +// +// When we call CSM16 functions, some CSM16 use es:[offset + 0xabcd] to get data passed from CSM32, +// offset + 0xabcd could overflow which exceeds 0xFFFF which is invalid in real mode. +// So this will keep offset as small as possible to avoid offset overflow in real mode. +// +#define NORMALIZE_EFI_SEGMENT(_Adr) (UINT16) (((UINTN) (_Adr)) >> 4) +#define NORMALIZE_EFI_OFFSET(_Adr) (UINT16) (((UINT16) ((UINTN) (_Adr))) & 0xf) + +// +// Trace defines +// +// +#define LEGACY_BDA_TRACE 0x000 +#define LEGACY_BIOS_TRACE 0x040 +#define LEGACY_BOOT_TRACE 0x080 +#define LEGACY_CMOS_TRACE 0x0C0 +#define LEGACY_IDE_TRACE 0x100 +#define LEGACY_MP_TRACE 0x140 +#define LEGACY_PCI_TRACE 0x180 +#define LEGACY_SIO_TRACE 0x1C0 + +#define LEGACY_PCI_TRACE_000 LEGACY_PCI_TRACE + 0x00 +#define LEGACY_PCI_TRACE_001 LEGACY_PCI_TRACE + 0x01 +#define LEGACY_PCI_TRACE_002 LEGACY_PCI_TRACE + 0x02 +#define LEGACY_PCI_TRACE_003 LEGACY_PCI_TRACE + 0x03 +#define LEGACY_PCI_TRACE_004 LEGACY_PCI_TRACE + 0x04 +#define LEGACY_PCI_TRACE_005 LEGACY_PCI_TRACE + 0x05 +#define LEGACY_PCI_TRACE_006 LEGACY_PCI_TRACE + 0x06 +#define LEGACY_PCI_TRACE_007 LEGACY_PCI_TRACE + 0x07 +#define LEGACY_PCI_TRACE_008 LEGACY_PCI_TRACE + 0x08 +#define LEGACY_PCI_TRACE_009 LEGACY_PCI_TRACE + 0x09 +#define LEGACY_PCI_TRACE_00A LEGACY_PCI_TRACE + 0x0A +#define LEGACY_PCI_TRACE_00B LEGACY_PCI_TRACE + 0x0B +#define LEGACY_PCI_TRACE_00C LEGACY_PCI_TRACE + 0x0C +#define LEGACY_PCI_TRACE_00D LEGACY_PCI_TRACE + 0x0D +#define LEGACY_PCI_TRACE_00E LEGACY_PCI_TRACE + 0x0E +#define LEGACY_PCI_TRACE_00F LEGACY_PCI_TRACE + 0x0F + +#define BDA_VIDEO_MODE 0x49 + +#define IDE_PI_REGISTER_PNE BIT0 +#define IDE_PI_REGISTER_SNE BIT2 + +typedef struct { + UINTN PciSegment; + UINTN PciBus; + UINTN PciDevice; + UINTN PciFunction; + UINT32 ShadowAddress; + UINT32 ShadowedSize; + UINT8 DiskStart; + UINT8 DiskEnd; +} ROM_INSTANCE_ENTRY; + +// +// Values for RealModeGdt +// +#if defined (MDE_CPU_IA32) + +#define NUM_REAL_GDT_ENTRIES 3 +#define CONVENTIONAL_MEMORY_TOP 0xA0000 // 640 KB +#define INITIAL_VALUE_BELOW_1K 0x0 + +#elif defined (MDE_CPU_X64) + +#define NUM_REAL_GDT_ENTRIES 8 +#define CONVENTIONAL_MEMORY_TOP 0xA0000 // 640 KB +#define INITIAL_VALUE_BELOW_1K 0x0 + +#endif + +#pragma pack(1) + +// +// Define what a processor GDT looks like +// +typedef struct { + UINT32 LimitLo : 16; + UINT32 BaseLo : 16; + UINT32 BaseMid : 8; + UINT32 Type : 4; + UINT32 System : 1; + UINT32 Dpl : 2; + UINT32 Present : 1; + UINT32 LimitHi : 4; + UINT32 Software : 1; + UINT32 Reserved : 1; + UINT32 DefaultSize : 1; + UINT32 Granularity : 1; + UINT32 BaseHi : 8; +} GDT32; + +typedef struct { + UINT16 LimitLow; + UINT16 BaseLow; + UINT8 BaseMid; + UINT8 Attribute; + UINT8 LimitHi; + UINT8 BaseHi; +} GDT64; + +// +// Define what a processor descriptor looks like +// This data structure must be kept in sync with ASM STRUCT in Thunk.inc +// +typedef struct { + UINT16 Limit; + UINT64 Base; +} DESCRIPTOR64; + +typedef struct { + UINT16 Limit; + UINT32 Base; +} DESCRIPTOR32; + +// +// Low stub lay out +// +#define LOW_STACK_SIZE (8 * 1024) // 8k? +#define EFI_MAX_E820_ENTRY 100 +#define FIRST_INSTANCE 1 +#define NOT_FIRST_INSTANCE 0 + +#if defined (MDE_CPU_IA32) +typedef struct { + // + // Space for the code + // The address of Code is also the beginning of the relocated Thunk code + // + CHAR8 Code[4096]; // ? + // + // The address of the Reverse Thunk code + // Note that this member CONTAINS the address of the relocated reverse thunk + // code unlike the member variable 'Code', which IS the address of the Thunk + // code. + // + UINT32 LowReverseThunkStart; + + // + // Data for the code (cs releative) + // + DESCRIPTOR32 GdtDesc; // Protected mode GDT + DESCRIPTOR32 IdtDesc; // Protected mode IDT + UINT32 FlatSs; + UINT32 FlatEsp; + + UINT32 LowCodeSelector; // Low code selector in GDT + UINT32 LowDataSelector; // Low data selector in GDT + UINT32 LowStack; + DESCRIPTOR32 RealModeIdtDesc; + + // + // real-mode GDT (temporary GDT with two real mode segment descriptors) + // + GDT32 RealModeGdt[NUM_REAL_GDT_ENTRIES]; + DESCRIPTOR32 RealModeGdtDesc; + + // + // Members specifically for the reverse thunk + // The RevReal* members are used to store the current state of real mode + // before performing the reverse thunk. The RevFlat* members must be set + // before calling the reverse thunk assembly code. + // + UINT16 RevRealDs; + UINT16 RevRealSs; + UINT32 RevRealEsp; + DESCRIPTOR32 RevRealIdtDesc; + UINT16 RevFlatDataSelector; // Flat data selector in GDT + UINT32 RevFlatStack; + + // + // A low memory stack + // + CHAR8 Stack[LOW_STACK_SIZE]; + + // + // Stack for flat mode after reverse thunk + // @bug - This may no longer be necessary if the reverse thunk interface + // is changed to have the flat stack in a different location. + // + CHAR8 RevThunkStack[LOW_STACK_SIZE]; + + // + // Legacy16 Init memory map info + // + EFI_TO_COMPATIBILITY16_INIT_TABLE EfiToLegacy16InitTable; + + EFI_TO_COMPATIBILITY16_BOOT_TABLE EfiToLegacy16BootTable; + + CHAR8 InterruptRedirectionCode[32]; + EFI_LEGACY_INSTALL_PCI_HANDLER PciHandler; + EFI_DISPATCH_OPROM_TABLE DispatchOpromTable; + BBS_TABLE BbsTable[MAX_BBS_ENTRIES]; +} LOW_MEMORY_THUNK; + +#elif defined (MDE_CPU_X64) + +typedef struct { + // + // Space for the code + // The address of Code is also the beginning of the relocated Thunk code + // + CHAR8 Code[4096]; // ? + + // + // Data for the code (cs releative) + // + DESCRIPTOR64 X64GdtDesc; // Protected mode GDT + DESCRIPTOR64 X64IdtDesc; // Protected mode IDT + UINTN X64Ss; + UINTN X64Esp; + + UINTN RealStack; + DESCRIPTOR32 RealModeIdtDesc; + DESCRIPTOR32 RealModeGdtDesc; + + // + // real-mode GDT (temporary GDT with two real mode segment descriptors) + // + GDT64 RealModeGdt[NUM_REAL_GDT_ENTRIES]; + UINT64 PageMapLevel4; + + // + // A low memory stack + // + CHAR8 Stack[LOW_STACK_SIZE]; + + // + // Legacy16 Init memory map info + // + EFI_TO_COMPATIBILITY16_INIT_TABLE EfiToLegacy16InitTable; + + EFI_TO_COMPATIBILITY16_BOOT_TABLE EfiToLegacy16BootTable; + + CHAR8 InterruptRedirectionCode[32]; + EFI_LEGACY_INSTALL_PCI_HANDLER PciHandler; + EFI_DISPATCH_OPROM_TABLE DispatchOpromTable; + BBS_TABLE BbsTable[MAX_BBS_ENTRIES]; +} LOW_MEMORY_THUNK; + +#endif + +// +// PnP Expansion Header +// +typedef struct { + UINT32 PnpSignature; + UINT8 Revision; + UINT8 Length; + UINT16 NextHeader; + UINT8 Reserved1; + UINT8 Checksum; + UINT32 DeviceId; + UINT16 MfgPointer; + UINT16 ProductNamePointer; + UINT8 Class; + UINT8 SubClass; + UINT8 Interface; + UINT8 DeviceIndicators; + UINT16 Bcv; + UINT16 DisconnectVector; + UINT16 Bev; + UINT16 Reserved2; + UINT16 StaticResourceVector; +} LEGACY_PNP_EXPANSION_HEADER; + +typedef struct { + UINT8 PciSegment; + UINT8 PciBus; + UINT8 PciDevice; + UINT8 PciFunction; + UINT16 Vid; + UINT16 Did; + UINT16 SysSid; + UINT16 SVid; + UINT8 Class; + UINT8 SubClass; + UINT8 Interface; + UINT8 Reserved; + UINTN RomStart; + UINTN ManufacturerString; + UINTN ProductNameString; +} LEGACY_ROM_AND_BBS_TABLE; + +// +// Structure how EFI has mapped a devices HDD drive numbers. +// Boot to EFI aware OS or shell requires this mapping when +// 16-bit CSM assigns drive numbers. +// This mapping is ignored booting to a legacy OS. +// +typedef struct { + UINT8 PciSegment; + UINT8 PciBus; + UINT8 PciDevice; + UINT8 PciFunction; + UINT8 StartDriveNumber; + UINT8 EndDriveNumber; +} LEGACY_EFI_HDD_TABLE; + +// +// This data is passed to Leacy16Boot +// +typedef enum { + EfiAcpiAddressRangeMemory = 1, + EfiAcpiAddressRangeReserved = 2, + EfiAcpiAddressRangeACPI = 3, + EfiAcpiAddressRangeNVS = 4, + EfiAddressRangePersistentMemory = 7 +} EFI_ACPI_MEMORY_TYPE; + +typedef struct { + UINT64 BaseAddr; + UINT64 Length; + EFI_ACPI_MEMORY_TYPE Type; +} EFI_E820_ENTRY64; + +typedef struct { + UINT32 BassAddrLow; + UINT32 BaseAddrHigh; + UINT32 LengthLow; + UINT32 LengthHigh; + EFI_ACPI_MEMORY_TYPE Type; +} EFI_E820_ENTRY; + +#pragma pack() + +extern BBS_TABLE *mBbsTable; + +extern EFI_GENERIC_MEMORY_TEST_PROTOCOL *gGenMemoryTest; + +extern BOOLEAN mEndOfDxe; + +#define PORT_70 0x70 +#define PORT_71 0x71 + +#define CMOS_0A 0x0a ///< Status register A +#define CMOS_0D 0x0d ///< Status register D +#define CMOS_0E 0x0e ///< Diagnostic Status +#define CMOS_0F 0x0f ///< Shutdown status +#define CMOS_10 0x10 ///< Floppy type +#define CMOS_12 0x12 ///< IDE type +#define CMOS_14 0x14 ///< Same as BDA 40:10 +#define CMOS_15 0x15 ///< Low byte of base memory in 1k increments +#define CMOS_16 0x16 ///< High byte of base memory in 1k increments +#define CMOS_17 0x17 ///< Low byte of 1MB+ memory in 1k increments - max 15 MB +#define CMOS_18 0x18 ///< High byte of 1MB+ memory in 1k increments - max 15 MB +#define CMOS_19 0x19 ///< C: extended drive type +#define CMOS_1A 0x1a ///< D: extended drive type +#define CMOS_2E 0x2e ///< Most significient byte of standard checksum +#define CMOS_2F 0x2f ///< Least significient byte of standard checksum +#define CMOS_30 0x30 ///< CMOS 0x17 +#define CMOS_31 0x31 ///< CMOS 0x18 +#define CMOS_32 0x32 ///< Century byte + +// +// 8254 Timer registers +// +#define TIMER0_COUNT_PORT 0x40 +#define TIMER1_COUNT_PORT 0x41 +#define TIMER2_COUNT_PORT 0x42 +#define TIMER_CONTROL_PORT 0x43 + +// +// Timer 0, Read/Write LSB then MSB, Square wave output, binary count use. +// +#define TIMER0_CONTROL_WORD 0x36 + +#define LEGACY_BIOS_INSTANCE_SIGNATURE SIGNATURE_32 ('L', 'B', 'I', 'T') +typedef struct { + UINTN Signature; + + EFI_HANDLE Handle; + EFI_LEGACY_BIOS_PROTOCOL LegacyBios; + + EFI_HANDLE ImageHandle; + + // + // CPU Architectural Protocol + // + EFI_CPU_ARCH_PROTOCOL *Cpu; + + // + // Timer Architectural Protocol + // + EFI_TIMER_ARCH_PROTOCOL *Timer; + BOOLEAN TimerUses8254; + + // + // Protocol to Lock and Unlock 0xc0000 - 0xfffff + // + EFI_LEGACY_REGION2_PROTOCOL *LegacyRegion; + + EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform; + + // + // Interrupt control for thunk and PCI IRQ + // + EFI_LEGACY_8259_PROTOCOL *Legacy8259; + + // + // PCI Interrupt PIRQ control + // + EFI_LEGACY_INTERRUPT_PROTOCOL *LegacyInterrupt; + + // + // Generic Memory Test + // + EFI_GENERIC_MEMORY_TEST_PROTOCOL *GenericMemoryTest; + + // + // TRUE if PCI Interupt Line registers have been programmed. + // + BOOLEAN PciInterruptLine; + + // + // Code space below 1MB needed by thunker to transition to real mode. + // Contains stack and real mode code fragments + // + LOW_MEMORY_THUNK *IntThunk; + + // + // Starting shadow address of the Legacy BIOS + // + UINT32 BiosStart; + UINT32 LegacyBiosImageSize; + + // + // Start of variables used by CsmItp.mac ITP macro file and/os LegacyBios + // + UINT8 Dump[4]; + + // + // $EFI Legacy16 code entry info in memory < 1 MB; + // + EFI_COMPATIBILITY16_TABLE *Legacy16Table; + VOID *Legacy16InitPtr; + VOID *Legacy16BootPtr; + VOID *InternalIrqRoutingTable; + UINT32 NumberIrqRoutingEntries; + VOID *BbsTablePtr; + VOID *HddTablePtr; + UINT32 NumberHddControllers; + + // + // Cached copy of Legacy16 entry point + // + UINT16 Legacy16CallSegment; + UINT16 Legacy16CallOffset; + + // + // Returned from $EFI and passed in to OPROMS + // + UINT16 PnPInstallationCheckSegment; + UINT16 PnPInstallationCheckOffset; + + // + // E820 table + // + EFI_E820_ENTRY E820Table[EFI_MAX_E820_ENTRY]; + UINT32 NumberE820Entries; + + // + // True if legacy VGA INT 10h handler installed + // + BOOLEAN VgaInstalled; + + // + // Number of IDE drives + // + UINT8 IdeDriveCount; + + // + // Current Free Option ROM space. An option ROM must NOT go past + // BiosStart. + // + UINT32 OptionRom; + + // + // Save Legacy16 unexpected interrupt vector. Reprogram INT 68-6F from + // EFI values to legacy value just before boot. + // + UINT32 BiosUnexpectedInt; + UINT32 ThunkSavedInt[8]; + UINT16 ThunkSeg; + LEGACY_EFI_HDD_TABLE *LegacyEfiHddTable; + UINT16 LegacyEfiHddTableIndex; + UINT8 DiskEnd; + UINT8 Disk4075; + UINT16 TraceIndex; + UINT16 Trace[0x200]; + + // + // Indicate that whether GenericLegacyBoot is entered or not + // + BOOLEAN LegacyBootEntered; + + // + // CSM16 PCI Interface Version + // + UINT16 Csm16PciInterfaceVersion; + +} LEGACY_BIOS_INSTANCE; + + +#pragma pack(1) + +/* + 40:00-01 Com1 + 40:02-03 Com2 + 40:04-05 Com3 + 40:06-07 Com4 + 40:08-09 Lpt1 + 40:0A-0B Lpt2 + 40:0C-0D Lpt3 + 40:0E-0E Ebda segment + 40:10-11 MachineConfig + 40:12 Bda12 - skip + 40:13-14 MemSize below 1MB + 40:15-16 Bda15_16 - skip + 40:17 Keyboard Shift status + 40:18-19 Bda18_19 - skip + 40:1A-1B Key buffer head + 40:1C-1D Key buffer tail + 40:1E-3D Bda1E_3D- key buffer -skip + 40:3E-3F FloppyData 3E = Calibration status 3F = Motor status + 40:40 FloppyTimeout + 40:41-74 Bda41_74 - skip + 40:75 Number of HDD drives + 40:76-77 Bda76_77 - skip + 40:78-79 78 = Lpt1 timeout, 79 = Lpt2 timeout + 40:7A-7B 7A = Lpt3 timeout, 7B = Lpt4 timeout + 40:7C-7D 7C = Com1 timeout, 7D = Com2 timeout + 40:7E-7F 7E = Com3 timeout, 7F = Com4 timeout + 40:80-81 Pointer to start of key buffer + 40:82-83 Pointer to end of key buffer + 40:84-87 Bda84_87 - skip + 40:88 HDD Data Xmit rate + 40:89-8f skip + 40:90 Floppy data rate + 40:91-95 skip + 40:96 Keyboard Status + 40:97 LED Status + 40:98-101 skip +*/ +typedef struct { + UINT16 Com1; + UINT16 Com2; + UINT16 Com3; + UINT16 Com4; + UINT16 Lpt1; + UINT16 Lpt2; + UINT16 Lpt3; + UINT16 Ebda; + UINT16 MachineConfig; + UINT8 Bda12; + UINT16 MemSize; + UINT8 Bda15_16[0x02]; + UINT8 ShiftStatus; + UINT8 Bda18_19[0x02]; + UINT16 KeyHead; + UINT16 KeyTail; + UINT16 Bda1E_3D[0x10]; + UINT16 FloppyData; + UINT8 FloppyTimeout; + UINT8 Bda41_74[0x34]; + UINT8 NumberOfDrives; + UINT8 Bda76_77[0x02]; + UINT16 Lpt1_2Timeout; + UINT16 Lpt3_4Timeout; + UINT16 Com1_2Timeout; + UINT16 Com3_4Timeout; + UINT16 KeyStart; + UINT16 KeyEnd; + UINT8 Bda84_87[0x4]; + UINT8 DataXmit; + UINT8 Bda89_8F[0x07]; + UINT8 FloppyXRate; + UINT8 Bda91_95[0x05]; + UINT8 KeyboardStatus; + UINT8 LedStatus; +} BDA_STRUC; +#pragma pack() + +#define LEGACY_BIOS_INSTANCE_FROM_THIS(this) CR (this, LEGACY_BIOS_INSTANCE, LegacyBios, LEGACY_BIOS_INSTANCE_SIGNATURE) + +/** + Thunk to 16-bit real mode and execute a software interrupt with a vector + of BiosInt. Regs will contain the 16-bit register context on entry and + exit. + + @param This Protocol instance pointer. + @param BiosInt Processor interrupt vector to invoke + @param Regs Register contexted passed into (and returned) from thunk to + 16-bit mode + + @retval FALSE Thunk completed, and there were no BIOS errors in the target code. + See Regs for status. + @retval TRUE There was a BIOS erro in the target code. + +**/ +BOOLEAN +EFIAPI +LegacyBiosInt86 ( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN UINT8 BiosInt, + IN EFI_IA32_REGISTER_SET *Regs + ); + + +/** + Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the + 16-bit register context on entry and exit. Arguments can be passed on + the Stack argument + + @param This Protocol instance pointer. + @param Segment Segemnt of 16-bit mode call + @param Offset Offset of 16-bit mdoe call + @param Regs Register contexted passed into (and returned) from + thunk to 16-bit mode + @param Stack Caller allocated stack used to pass arguments + @param StackSize Size of Stack in bytes + + @retval FALSE Thunk completed, and there were no BIOS errors in + the target code. See Regs for status. + @retval TRUE There was a BIOS erro in the target code. + +**/ +BOOLEAN +EFIAPI +LegacyBiosFarCall86 ( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN UINT16 Segment, + IN UINT16 Offset, + IN EFI_IA32_REGISTER_SET *Regs, + IN VOID *Stack, + IN UINTN StackSize + ); + + +/** + Test to see if a legacy PCI ROM exists for this device. Optionally return + the Legacy ROM instance for this PCI device. + + @param This Protocol instance pointer. + @param PciHandle The PCI PC-AT OPROM from this devices ROM BAR will + be loaded + @param RomImage Return the legacy PCI ROM for this device + @param RomSize Size of ROM Image + @param Flags Indicates if ROM found and if PC-AT. + + @retval EFI_SUCCESS Legacy Option ROM available for this device + @retval EFI_UNSUPPORTED Legacy Option ROM not supported. + +**/ +EFI_STATUS +EFIAPI +LegacyBiosCheckPciRom ( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN EFI_HANDLE PciHandle, + OUT VOID **RomImage, OPTIONAL + OUT UINTN *RomSize, OPTIONAL + OUT UINTN *Flags + ); + + +/** + Assign drive number to legacy HDD drives prior to booting an EFI + aware OS so the OS can access drives without an EFI driver. + Note: BBS compliant drives ARE NOT available until this call by + either shell or EFI. + + @param This Protocol instance pointer. + @param BbsCount Number of BBS_TABLE structures + @param BbsTable List BBS entries + + @retval EFI_SUCCESS Drive numbers assigned + +**/ +EFI_STATUS +EFIAPI +LegacyBiosPrepareToBootEfi ( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + OUT UINT16 *BbsCount, + OUT BBS_TABLE **BbsTable + ); + + +/** + To boot from an unconventional device like parties and/or execute + HDD diagnostics. + + @param This Protocol instance pointer. + @param Attributes How to interpret the other input parameters + @param BbsEntry The 0-based index into the BbsTable for the parent + device. + @param BeerData Pointer to the 128 bytes of ram BEER data. + @param ServiceAreaData Pointer to the 64 bytes of raw Service Area data. + The caller must provide a pointer to the specific + Service Area and not the start all Service Areas. + EFI_INVALID_PARAMETER if error. Does NOT return if no error. + +**/ +EFI_STATUS +EFIAPI +LegacyBiosBootUnconventionalDevice ( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN UDC_ATTRIBUTES Attributes, + IN UINTN BbsEntry, + IN VOID *BeerData, + IN VOID *ServiceAreaData + ); + + +/** + Load a legacy PC-AT OPROM on the PciHandle device. Return information + about how many disks were added by the OPROM and the shadow address and + size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C: + + @param This Protocol instance pointer. + @param PciHandle The PCI PC-AT OPROM from this devices ROM BAR will + be loaded. This value is NULL if RomImage is + non-NULL. This is the normal case. + @param RomImage A PCI PC-AT ROM image. This argument is non-NULL + if there is no hardware associated with the ROM + and thus no PciHandle, otherwise is must be NULL. + Example is PXE base code. + @param Flags Indicates if ROM found and if PC-AT. + @param DiskStart Disk number of first device hooked by the ROM. If + DiskStart is the same as DiskEnd no disked were + hooked. + @param DiskEnd Disk number of the last device hooked by the ROM. + @param RomShadowAddress Shadow address of PC-AT ROM + @param RomShadowedSize Size of RomShadowAddress in bytes + + @retval EFI_SUCCESS Legacy ROM loaded for this device + @retval EFI_INVALID_PARAMETER PciHandle not found + @retval EFI_UNSUPPORTED There is no PCI ROM in the ROM BAR or no onboard + ROM + +**/ +EFI_STATUS +EFIAPI +LegacyBiosInstallPciRom ( + IN EFI_LEGACY_BIOS_PROTOCOL * This, + IN EFI_HANDLE PciHandle, + IN VOID **RomImage, + OUT UINTN *Flags, + OUT UINT8 *DiskStart, OPTIONAL + OUT UINT8 *DiskEnd, OPTIONAL + OUT VOID **RomShadowAddress, OPTIONAL + OUT UINT32 *RomShadowedSize OPTIONAL + ); + + +/** + Fill in the standard BDA for Keyboard LEDs + + @param This Protocol instance pointer. + @param Leds Current LED status + + @retval EFI_SUCCESS It should always work. + +**/ +EFI_STATUS +EFIAPI +LegacyBiosUpdateKeyboardLedStatus ( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN UINT8 Leds + ); + + +/** + Get all BBS info + + @param This Protocol instance pointer. + @param HddCount Number of HDD_INFO structures + @param HddInfo Onboard IDE controller information + @param BbsCount Number of BBS_TABLE structures + @param BbsTable List BBS entries + + @retval EFI_SUCCESS Tables returned + @retval EFI_NOT_FOUND resource not found + @retval EFI_DEVICE_ERROR can not get BBS table + +**/ +EFI_STATUS +EFIAPI +LegacyBiosGetBbsInfo ( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + OUT UINT16 *HddCount, + OUT HDD_INFO **HddInfo, + OUT UINT16 *BbsCount, + OUT BBS_TABLE **BbsTable + ); + + +/** + Shadow all legacy16 OPROMs that haven't been shadowed. + Warning: Use this with caution. This routine disconnects all EFI + drivers. If used externally then caller must re-connect EFI + drivers. + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS OPROMs shadowed + +**/ +EFI_STATUS +EFIAPI +LegacyBiosShadowAllLegacyOproms ( + IN EFI_LEGACY_BIOS_PROTOCOL *This + ); + + +/** + Attempt to legacy boot the BootOption. If the EFI contexted has been + compromised this function will not return. + + @param This Protocol instance pointer. + @param BbsDevicePath EFI Device Path from BootXXXX variable. + @param LoadOptionsSize Size of LoadOption in size. + @param LoadOptions LoadOption from BootXXXX variable + + @retval EFI_SUCCESS Removable media not present + +**/ +EFI_STATUS +EFIAPI +LegacyBiosLegacyBoot ( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN BBS_BBS_DEVICE_PATH *BbsDevicePath, + IN UINT32 LoadOptionsSize, + IN VOID *LoadOptions + ); + + +/** + Allocate memory < 1 MB and copy the thunker code into low memory. Se up + all the descriptors. + + @param Private Private context for Legacy BIOS + + @retval EFI_SUCCESS Should only pass. + +**/ +EFI_STATUS +LegacyBiosInitializeThunk ( + IN LEGACY_BIOS_INSTANCE *Private + ); + + +/** + Fill in the standard BDA and EBDA stuff before Legacy16 load + + @param Private Legacy BIOS Instance data + + @retval EFI_SUCCESS It should always work. + +**/ +EFI_STATUS +LegacyBiosInitBda ( + IN LEGACY_BIOS_INSTANCE *Private + ); + + +/** + Collect IDE Inquiry data from the IDE disks + + @param Private Legacy BIOS Instance data + @param HddInfo Hdd Information + @param Flag Reconnect IdeController or not + + @retval EFI_SUCCESS It should always work. + +**/ +EFI_STATUS +LegacyBiosBuildIdeData ( + IN LEGACY_BIOS_INSTANCE *Private, + IN HDD_INFO **HddInfo, + IN UINT16 Flag + ); + + +/** + Enable ide controller. This gets disabled when LegacyBoot.c is about + to run the Option ROMs. + + @param Private Legacy BIOS Instance data + + +**/ +VOID +EnableIdeController ( + IN LEGACY_BIOS_INSTANCE *Private + ); + + +/** + If the IDE channel is in compatibility (legacy) mode, remove all + PCI I/O BAR addresses from the controller. + + @param IdeController The handle of target IDE controller + + +**/ +VOID +InitLegacyIdeController ( + IN EFI_HANDLE IdeController + ); + + +/** + Program the interrupt routing register in all the PCI devices. On a PC AT system + this register contains the 8259 IRQ vector that matches it's PCI interrupt. + + @param Private Legacy BIOS Instance data + + @retval EFI_SUCCESS Succeed. + @retval EFI_ALREADY_STARTED All PCI devices have been processed. + +**/ +EFI_STATUS +PciProgramAllInterruptLineRegisters ( + IN LEGACY_BIOS_INSTANCE *Private + ); + + +/** + Collect EFI Info about legacy devices. + + @param Private Legacy BIOS Instance data + + @retval EFI_SUCCESS It should always work. + +**/ +EFI_STATUS +LegacyBiosBuildSioData ( + IN LEGACY_BIOS_INSTANCE *Private + ); + + +/** + Shadow all the PCI legacy ROMs. Use data from the Legacy BIOS Protocol + to chose the order. Skip any devices that have already have legacy + BIOS run. + + @param Private Protocol instance pointer. + + @retval EFI_SUCCESS Succeed. + @retval EFI_UNSUPPORTED Cannot get VGA device handle. + +**/ +EFI_STATUS +PciShadowRoms ( + IN LEGACY_BIOS_INSTANCE *Private + ); + + +/** + Fill in the standard BDA and EBDA stuff prior to legacy Boot + + @param Private Legacy BIOS Instance data + + @retval EFI_SUCCESS It should always work. + +**/ +EFI_STATUS +LegacyBiosCompleteBdaBeforeBoot ( + IN LEGACY_BIOS_INSTANCE *Private + ); + + +/** + Fill in the standard CMOS stuff before Legacy16 load + + @param Private Legacy BIOS Instance data + + @retval EFI_SUCCESS It should always work. + +**/ +EFI_STATUS +LegacyBiosInitCmos ( + IN LEGACY_BIOS_INSTANCE *Private + ); + + +/** + Fill in the standard CMOS stuff prior to legacy Boot + + @param Private Legacy BIOS Instance data + + @retval EFI_SUCCESS It should always work. + +**/ +EFI_STATUS +LegacyBiosCompleteStandardCmosBeforeBoot ( + IN LEGACY_BIOS_INSTANCE *Private + ); + + +/** + Contains the code that is copied into low memory (below 640K). + This code reflects interrupts 0x68-0x6f to interrupts 0x08-0x0f. + This template must be copied into low memory, and the IDT entries + 0x68-0x6F must be point to the low memory copy of this code. Each + entry is 4 bytes long, so IDT entries 0x68-0x6F can be easily + computed. + +**/ +VOID +InterruptRedirectionTemplate ( + VOID + ); + + +/** + Build the E820 table. + + @param Private Legacy BIOS Instance data + @param Size Size of E820 Table + + @retval EFI_SUCCESS It should always work. + +**/ +EFI_STATUS +LegacyBiosBuildE820 ( + IN LEGACY_BIOS_INSTANCE *Private, + OUT UINTN *Size + ); + +/** + This function is to put all AP in halt state. + + @param Private Legacy BIOS Instance data + +**/ +VOID +ShutdownAPs ( + IN LEGACY_BIOS_INSTANCE *Private + ); + +/** + Worker function for LegacyBiosGetFlatDescs, retrieving content of + specific registers. + + @param IntThunk Pointer to IntThunk of Legacy BIOS context. + +**/ +VOID +GetRegisters ( + LOW_MEMORY_THUNK *IntThunk + ); + +/** + Routine for calling real thunk code. + + @param RealCode The address of thunk code. + @param BiosInt The Bios interrupt vector number. + @param CallAddress The address of 16-bit mode call. + + @return Status returned by real thunk code + +**/ +UINTN +CallRealThunkCode ( + UINT8 *RealCode, + UINT8 BiosInt, + UINT32 CallAddress + ); + +/** + Routine for generating soft interrupt. + + @param Vector The interrupt vector number. + +**/ +VOID +GenerateSoftInit ( + UINT8 Vector + ); + +/** + Allocate memory for legacy usage. + + @param AllocateType The type of allocation to perform. + @param MemoryType The type of memory to allocate. + @param StartPageAddress Start address of range + @param Pages Number of pages to allocate + @param Result Result of allocation + + @retval EFI_SUCCESS Legacy16 code loaded + @retval Other No protocol installed, unload driver. + +**/ +EFI_STATUS +AllocateLegacyMemory ( + IN EFI_ALLOCATE_TYPE AllocateType, + IN EFI_MEMORY_TYPE MemoryType, + IN EFI_PHYSICAL_ADDRESS StartPageAddress, + IN UINTN Pages, + OUT EFI_PHYSICAL_ADDRESS *Result + ); + +/** + Get a region from the LegacyBios for Tiano usage. Can only be invoked once. + + @param This Protocol instance pointer. + @param LegacyMemorySize Size of required region + @param Region Region to use. 00 = Either 0xE0000 or 0xF0000 + block Bit0 = 1 0xF0000 block Bit1 = 1 0xE0000 + block + @param Alignment Address alignment. Bit mapped. First non-zero + bit from right is alignment. + @param LegacyMemoryAddress Region Assigned + + @retval EFI_SUCCESS Region assigned + @retval EFI_ACCESS_DENIED Procedure previously invoked + @retval Other Region not assigned + +**/ +EFI_STATUS +EFIAPI +LegacyBiosGetLegacyRegion ( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN UINTN LegacyMemorySize, + IN UINTN Region, + IN UINTN Alignment, + OUT VOID **LegacyMemoryAddress + ); + +/** + Get a region from the LegacyBios for Tiano usage. Can only be invoked once. + + @param This Protocol instance pointer. + @param LegacyMemorySize Size of data to copy + @param LegacyMemoryAddress Legacy Region destination address Note: must + be in region assigned by + LegacyBiosGetLegacyRegion + @param LegacyMemorySourceAddress Source of data + + @retval EFI_SUCCESS Region assigned + @retval EFI_ACCESS_DENIED Destination outside assigned region + +**/ +EFI_STATUS +EFIAPI +LegacyBiosCopyLegacyRegion ( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN UINTN LegacyMemorySize, + IN VOID *LegacyMemoryAddress, + IN VOID *LegacyMemorySourceAddress + ); + +/** + Find Legacy16 BIOS image in the FLASH device and shadow it into memory. Find + the $EFI table in the shadow area. Thunk into the Legacy16 code after it had + been shadowed. + + @param Private Legacy BIOS context data + + @retval EFI_SUCCESS Legacy16 code loaded + @retval Other No protocol installed, unload driver. + +**/ +EFI_STATUS +ShadowAndStartLegacy16 ( + IN LEGACY_BIOS_INSTANCE *Private + ); + +/** + Checks the state of the floppy and if media is inserted. + + This routine checks the state of the floppy and if media is inserted. + There are 3 cases: + No floppy present - Set BBS entry to ignore + Floppy present & no media - Set BBS entry to lowest priority. We cannot + set it to ignore since 16-bit CSM will + indicate no floppy and thus drive A: is + unusable. CSM-16 will not try floppy since + lowest priority and thus not incur boot + time penality. + Floppy present & media - Set BBS entry to some priority. + + @return State of floppy media + +**/ +UINT8 +HasMediaInFloppy ( + VOID + ); + +/** + Identify drive data must be updated to actual parameters before boot. + This requires updating the checksum, if it exists. + + @param IdentifyDriveData ATA Identify Data + @param Checksum checksum of the ATA Identify Data + + @retval EFI_SUCCESS checksum calculated + @retval EFI_SECURITY_VIOLATION IdentifyData invalid + +**/ +EFI_STATUS +CalculateIdentifyDriveChecksum ( + IN UINT8 *IdentifyDriveData, + OUT UINT8 *Checksum + ); + +/** + Identify drive data must be updated to actual parameters before boot. + + @param IdentifyDriveData ATA Identify Data + +**/ +VOID +UpdateIdentifyDriveData ( + IN UINT8 *IdentifyDriveData + ); + +/** + Complete build of BBS TABLE. + + @param Private Legacy BIOS Instance data + @param BbsTable BBS Table passed to 16-bit code + + @retval EFI_SUCCESS Removable media not present + +**/ +EFI_STATUS +LegacyBiosBuildBbs ( + IN LEGACY_BIOS_INSTANCE *Private, + IN BBS_TABLE *BbsTable + ); + +/** + Read CMOS register through index/data port. + + @param[in] Index The index of the CMOS register to read. + + @return The data value from the CMOS register specified by Index. + +**/ +UINT8 +LegacyReadStandardCmos ( + IN UINT8 Index + ); + +/** + Write CMOS register through index/data port. + + @param[in] Index The index of the CMOS register to write. + @param[in] Value The value of CMOS register to write. + + @return The value written to the CMOS register specified by Index. + +**/ +UINT8 +LegacyWriteStandardCmos ( + IN UINT8 Index, + IN UINT8 Value + ); + +/** + Calculate the new standard CMOS checksum and write it. + + @param Private Legacy BIOS Instance data + + @retval EFI_SUCCESS Calculate 16-bit checksum successfully + +**/ +EFI_STATUS +LegacyCalculateWriteStandardCmosChecksum ( + VOID + ); + +/** + Test to see if a legacy PCI ROM exists for this device. Optionally return + the Legacy ROM instance for this PCI device. + + @param[in] This Protocol instance pointer. + @param[in] PciHandle The PCI PC-AT OPROM from this devices ROM BAR will be loaded + @param[out] RomImage Return the legacy PCI ROM for this device + @param[out] RomSize Size of ROM Image + @param[out] RuntimeImageLength Runtime size of ROM Image + @param[out] Flags Indicates if ROM found and if PC-AT. + @param[out] OpromRevision Revision of the PCI Rom + @param[out] ConfigUtilityCodeHeaderPointer of Configuration Utility Code Header + + @return EFI_SUCCESS Legacy Option ROM available for this device + @return EFI_ALREADY_STARTED This device is already managed by its Oprom + @return EFI_UNSUPPORTED Legacy Option ROM not supported. + +**/ +EFI_STATUS +LegacyBiosCheckPciRomEx ( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN EFI_HANDLE PciHandle, + OUT VOID **RomImage, OPTIONAL + OUT UINTN *RomSize, OPTIONAL + OUT UINTN *RuntimeImageLength, OPTIONAL + OUT UINTN *Flags, OPTIONAL + OUT UINT8 *OpromRevision, OPTIONAL + OUT VOID **ConfigUtilityCodeHeader OPTIONAL + ); + +/** + Relocate this image under 4G memory for IPF. + + @param ImageHandle Handle of driver image. + @param SystemTable Pointer to system table. + + @retval EFI_SUCCESS Image successfully relocated. + @retval EFI_ABORTED Failed to relocate image. + +**/ +EFI_STATUS +RelocateImageUnder4GIfNeeded ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the + 16-bit register context on entry and exit. Arguments can be passed on + the Stack argument + + @param This Protocol instance pointer. + @param Segment Segemnt of 16-bit mode call + @param Offset Offset of 16-bit mdoe call + @param Regs Register contexted passed into (and returned) from thunk to + 16-bit mode + @param Stack Caller allocated stack used to pass arguments + @param StackSize Size of Stack in bytes + + @retval FALSE Thunk completed, and there were no BIOS errors in the target code. + See Regs for status. + @retval TRUE There was a BIOS erro in the target code. + +**/ +BOOLEAN +EFIAPI +InternalLegacyBiosFarCall ( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN UINT16 Segment, + IN UINT16 Offset, + IN EFI_IA32_REGISTER_SET *Regs, + IN VOID *Stack, + IN UINTN StackSize + ); + +/** + Load a legacy PC-AT OpROM for VGA controller. + + @param Private Driver private data. + + @retval EFI_SUCCESS Legacy ROM successfully installed for this device. + @retval EFI_DEVICE_ERROR No VGA device handle found, or native EFI video + driver cannot be successfully disconnected, or VGA + thunk driver cannot be successfully connected. + +**/ +EFI_STATUS +LegacyBiosInstallVgaRom ( + IN LEGACY_BIOS_INSTANCE *Private + ); + +#endif diff --git a/OvmfPkg/Csm/LegacyBiosDxe/LegacyBootSupport.c b/OvmfPkg/Csm/LegacyBiosDxe/LegacyBootSupport.c new file mode 100644 index 0000000000..211750c012 --- /dev/null +++ b/OvmfPkg/Csm/LegacyBiosDxe/LegacyBootSupport.c @@ -0,0 +1,2173 @@ +/** @file + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "LegacyBiosInterface.h" +#include + +#define BOOT_LEGACY_OS 0 +#define BOOT_EFI_OS 1 +#define BOOT_UNCONVENTIONAL_DEVICE 2 + +UINT32 mLoadOptionsSize = 0; +UINTN mBootMode = BOOT_LEGACY_OS; +VOID *mLoadOptions = NULL; +BBS_BBS_DEVICE_PATH *mBbsDevicePathPtr = NULL; +BBS_BBS_DEVICE_PATH mBbsDevicePathNode; +UDC_ATTRIBUTES mAttributes = { 0, 0, 0, 0 }; +UINTN mBbsEntry = 0; +VOID *mBeerData = NULL; +VOID *mServiceAreaData = NULL; +UINT64 mLowWater = 0xffffffffffffffffULL; + +extern BBS_TABLE *mBbsTable; + +extern VOID *mRuntimeSmbiosEntryPoint; +extern EFI_PHYSICAL_ADDRESS mReserveSmbiosEntryPoint; +extern EFI_PHYSICAL_ADDRESS mStructureTableAddress; + +/** + Print the BBS Table. + + @param BbsTable The BBS table. + + +**/ +VOID +PrintBbsTable ( + IN BBS_TABLE *BbsTable + ) +{ + UINT16 Index; + UINT16 SubIndex; + CHAR8 *String; + + DEBUG ((EFI_D_INFO, "\n")); + DEBUG ((EFI_D_INFO, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs mfgs:mfgo dess:deso\n")); + DEBUG ((EFI_D_INFO, "=================================================================\n")); + for (Index = 0; Index < MAX_BBS_ENTRIES; Index++) { + // + // Filter + // + if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) { + continue; + } + + DEBUG (( + EFI_D_INFO, + " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x", + (UINTN) Index, + (UINTN) BbsTable[Index].BootPriority, + (UINTN) BbsTable[Index].Bus, + (UINTN) BbsTable[Index].Device, + (UINTN) BbsTable[Index].Function, + (UINTN) BbsTable[Index].Class, + (UINTN) BbsTable[Index].SubClass, + (UINTN) BbsTable[Index].DeviceType, + (UINTN) * (UINT16 *) &BbsTable[Index].StatusFlags + )); + DEBUG (( + EFI_D_INFO, + " %04x:%04x %04x:%04x %04x:%04x", + (UINTN) BbsTable[Index].BootHandlerSegment, + (UINTN) BbsTable[Index].BootHandlerOffset, + (UINTN) BbsTable[Index].MfgStringSegment, + (UINTN) BbsTable[Index].MfgStringOffset, + (UINTN) BbsTable[Index].DescStringSegment, + (UINTN) BbsTable[Index].DescStringOffset + )); + + // + // Print DescString + // + String = (CHAR8 *)(((UINTN)BbsTable[Index].DescStringSegment << 4) + BbsTable[Index].DescStringOffset); + if (String != NULL) { + DEBUG ((EFI_D_INFO," (")); + for (SubIndex = 0; String[SubIndex] != 0; SubIndex++) { + DEBUG ((EFI_D_INFO, "%c", String[SubIndex])); + } + DEBUG ((EFI_D_INFO,")")); + } + DEBUG ((EFI_D_INFO,"\n")); + } + + DEBUG ((EFI_D_INFO, "\n")); + + return ; +} + +/** + Print the BBS Table. + + @param HddInfo The HddInfo table. + + +**/ +VOID +PrintHddInfo ( + IN HDD_INFO *HddInfo + ) +{ + UINTN Index; + + DEBUG ((EFI_D_INFO, "\n")); + for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) { + DEBUG ((EFI_D_INFO, "Index - %04x\n", Index)); + DEBUG ((EFI_D_INFO, " Status - %04x\n", (UINTN)HddInfo[Index].Status)); + DEBUG ((EFI_D_INFO, " B/D/F - %02x/%02x/%02x\n", (UINTN)HddInfo[Index].Bus, (UINTN)HddInfo[Index].Device, (UINTN)HddInfo[Index].Function)); + DEBUG ((EFI_D_INFO, " Command - %04x\n", HddInfo[Index].CommandBaseAddress)); + DEBUG ((EFI_D_INFO, " Control - %04x\n", HddInfo[Index].ControlBaseAddress)); + DEBUG ((EFI_D_INFO, " BusMaster - %04x\n", HddInfo[Index].BusMasterAddress)); + DEBUG ((EFI_D_INFO, " HddIrq - %02x\n", HddInfo[Index].HddIrq)); + DEBUG ((EFI_D_INFO, " IdentifyDrive[0].Raw[0] - %x\n", HddInfo[Index].IdentifyDrive[0].Raw[0])); + DEBUG ((EFI_D_INFO, " IdentifyDrive[1].Raw[0] - %x\n", HddInfo[Index].IdentifyDrive[1].Raw[0])); + } + + DEBUG ((EFI_D_INFO, "\n")); + + return ; +} + +/** + Print the PCI Interrupt Line and Interrupt Pin registers. +**/ +VOID +PrintPciInterruptRegister ( + VOID + ) +{ + EFI_STATUS Status; + UINTN Index; + EFI_HANDLE *Handles; + UINTN HandleNum; + EFI_PCI_IO_PROTOCOL *PciIo; + UINT8 Interrupt[2]; + UINTN Segment; + UINTN Bus; + UINTN Device; + UINTN Function; + + gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiPciIoProtocolGuid, + NULL, + &HandleNum, + &Handles + ); + + Bus = 0; + Device = 0; + Function = 0; + + DEBUG ((EFI_D_INFO, "\n")); + DEBUG ((EFI_D_INFO, " bb/dd/ff interrupt line interrupt pin\n")); + DEBUG ((EFI_D_INFO, "======================================\n")); + for (Index = 0; Index < HandleNum; Index++) { + Status = gBS->HandleProtocol (Handles[Index], &gEfiPciIoProtocolGuid, (VOID **) &PciIo); + if (!EFI_ERROR (Status)) { + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint8, + PCI_INT_LINE_OFFSET, + 2, + Interrupt + ); + } + if (!EFI_ERROR (Status)) { + Status = PciIo->GetLocation ( + PciIo, + &Segment, + &Bus, + &Device, + &Function + ); + } + if (!EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, " %02x/%02x/%02x 0x%02x 0x%02x\n", + Bus, Device, Function, Interrupt[0], Interrupt[1])); + } + } + DEBUG ((EFI_D_INFO, "\n")); + + if (Handles != NULL) { + FreePool (Handles); + } +} + +/** + Identify drive data must be updated to actual parameters before boot. + + @param IdentifyDriveData ATA Identify Data + +**/ +VOID +UpdateIdentifyDriveData ( + IN UINT8 *IdentifyDriveData + ); + +/** + Update SIO data. + + @param Private Legacy BIOS Instance data + + @retval EFI_SUCCESS Removable media not present + +**/ +EFI_STATUS +UpdateSioData ( + IN LEGACY_BIOS_INSTANCE *Private + ) +{ + EFI_STATUS Status; + UINTN Index; + UINTN Index1; + UINT8 LegacyInterrupts[16]; + EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable; + UINTN RoutingTableEntries; + EFI_LEGACY_IRQ_PRIORITY_TABLE_ENTRY *IrqPriorityTable; + UINTN NumberPriorityEntries; + EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable; + UINT8 HddIrq; + UINT16 LegacyInt; + UINT16 LegMask; + UINT32 Register; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + EFI_ISA_IO_PROTOCOL *IsaIo; + + LegacyInt = 0; + HandleBuffer = NULL; + + EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable; + LegacyBiosBuildSioData (Private); + SetMem (LegacyInterrupts, sizeof (LegacyInterrupts), 0); + + // + // Create list of legacy interrupts. + // + for (Index = 0; Index < 4; Index++) { + LegacyInterrupts[Index] = EfiToLegacy16BootTable->SioData.Serial[Index].Irq; + } + + for (Index = 4; Index < 7; Index++) { + LegacyInterrupts[Index] = EfiToLegacy16BootTable->SioData.Parallel[Index - 4].Irq; + } + + LegacyInterrupts[7] = EfiToLegacy16BootTable->SioData.Floppy.Irq; + + // + // Get Legacy Hdd IRQs. If native mode treat as PCI + // + for (Index = 0; Index < 2; Index++) { + HddIrq = EfiToLegacy16BootTable->HddInfo[Index].HddIrq; + if ((HddIrq != 0) && ((HddIrq == 15) || (HddIrq == 14))) { + LegacyInterrupts[Index + 8] = HddIrq; + } + } + + Private->LegacyBiosPlatform->GetRoutingTable ( + Private->LegacyBiosPlatform, + (VOID *) &RoutingTable, + &RoutingTableEntries, + NULL, + NULL, + (VOID **) &IrqPriorityTable, + &NumberPriorityEntries + ); + // + // Remove legacy interrupts from the list of PCI interrupts available. + // + for (Index = 0; Index <= 0x0b; Index++) { + for (Index1 = 0; Index1 <= NumberPriorityEntries; Index1++) { + if (LegacyInterrupts[Index] != 0) { + LegacyInt = (UINT16) (LegacyInt | (1 << LegacyInterrupts[Index])); + if (LegacyInterrupts[Index] == IrqPriorityTable[Index1].Irq) { + IrqPriorityTable[Index1].Used = LEGACY_USED; + } + } + } + } + + Private->Legacy8259->GetMask ( + Private->Legacy8259, + &LegMask, + NULL, + NULL, + NULL + ); + + // + // Set SIO interrupts and disable mouse. Let mouse driver + // re-enable it. + // + LegMask = (UINT16) ((LegMask &~LegacyInt) | 0x1000); + Private->Legacy8259->SetMask ( + Private->Legacy8259, + &LegMask, + NULL, + NULL, + NULL + ); + + // + // Disable mouse in keyboard controller + // + Register = 0xA7; + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiIsaIoProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiIsaIoProtocolGuid, + (VOID **) &IsaIo + ); + ASSERT_EFI_ERROR (Status); + IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, 0x64, 1, &Register); + + } + + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + + return EFI_SUCCESS; + +} + +/** + Identify drive data must be updated to actual parameters before boot. + This requires updating the checksum, if it exists. + + @param IdentifyDriveData ATA Identify Data + @param Checksum checksum of the ATA Identify Data + + @retval EFI_SUCCESS checksum calculated + @retval EFI_SECURITY_VIOLATION IdentifyData invalid + +**/ +EFI_STATUS +CalculateIdentifyDriveChecksum ( + IN UINT8 *IdentifyDriveData, + OUT UINT8 *Checksum + ) +{ + UINTN Index; + UINT8 LocalChecksum; + LocalChecksum = 0; + *Checksum = 0; + if (IdentifyDriveData[510] != 0xA5) { + return EFI_SECURITY_VIOLATION; + } + + for (Index = 0; Index < 512; Index++) { + LocalChecksum = (UINT8) (LocalChecksum + IdentifyDriveData[Index]); + } + + *Checksum = LocalChecksum; + return EFI_SUCCESS; +} + + +/** + Identify drive data must be updated to actual parameters before boot. + + @param IdentifyDriveData ATA Identify Data + + +**/ +VOID +UpdateIdentifyDriveData ( + IN UINT8 *IdentifyDriveData + ) +{ + UINT16 NumberCylinders; + UINT16 NumberHeads; + UINT16 NumberSectorsTrack; + UINT32 CapacityInSectors; + UINT8 OriginalChecksum; + UINT8 FinalChecksum; + EFI_STATUS Status; + ATAPI_IDENTIFY *ReadInfo; + + // + // Status indicates if Integrity byte is correct. Checksum should be + // 0 if valid. + // + ReadInfo = (ATAPI_IDENTIFY *) IdentifyDriveData; + Status = CalculateIdentifyDriveChecksum (IdentifyDriveData, &OriginalChecksum); + if (OriginalChecksum != 0) { + Status = EFI_SECURITY_VIOLATION; + } + // + // If NumberCylinders = 0 then do data(Controller present but don drive attached). + // + NumberCylinders = ReadInfo->Raw[1]; + if (NumberCylinders != 0) { + ReadInfo->Raw[54] = NumberCylinders; + + NumberHeads = ReadInfo->Raw[3]; + ReadInfo->Raw[55] = NumberHeads; + + NumberSectorsTrack = ReadInfo->Raw[6]; + ReadInfo->Raw[56] = NumberSectorsTrack; + + // + // Copy Multisector info and set valid bit. + // + ReadInfo->Raw[59] = (UINT16) (ReadInfo->Raw[47] + 0x100); + CapacityInSectors = (UINT32) ((UINT32) (NumberCylinders) * (UINT32) (NumberHeads) * (UINT32) (NumberSectorsTrack)); + ReadInfo->Raw[57] = (UINT16) (CapacityInSectors >> 16); + ReadInfo->Raw[58] = (UINT16) (CapacityInSectors & 0xffff); + if (Status == EFI_SUCCESS) { + // + // Forece checksum byte to 0 and get new checksum. + // + ReadInfo->Raw[255] &= 0xff; + CalculateIdentifyDriveChecksum (IdentifyDriveData, &FinalChecksum); + + // + // Force new checksum such that sum is 0. + // + FinalChecksum = (UINT8) ((UINT8)0 - FinalChecksum); + ReadInfo->Raw[255] = (UINT16) (ReadInfo->Raw[255] | (FinalChecksum << 8)); + } + } +} + +/** + Identify drive data must be updated to actual parameters before boot. + Do for all drives. + + @param Private Legacy BIOS Instance data + + +**/ +VOID +UpdateAllIdentifyDriveData ( + IN LEGACY_BIOS_INSTANCE *Private + ) +{ + UINTN Index; + HDD_INFO *HddInfo; + + HddInfo = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo[0]; + + for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) { + // + // Each controller can have 2 devices. Update for each device + // + if ((HddInfo[Index].Status & HDD_MASTER_IDE) != 0) { + UpdateIdentifyDriveData ((UINT8 *) (&HddInfo[Index].IdentifyDrive[0].Raw[0])); + } + + if ((HddInfo[Index].Status & HDD_SLAVE_IDE) != 0) { + UpdateIdentifyDriveData ((UINT8 *) (&HddInfo[Index].IdentifyDrive[1].Raw[0])); + } + } +} + +/** + Enable ide controller. This gets disabled when LegacyBoot.c is about + to run the Option ROMs. + + @param Private Legacy BIOS Instance data + + +**/ +VOID +EnableIdeController ( + IN LEGACY_BIOS_INSTANCE *Private + ) +{ + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_STATUS Status; + EFI_HANDLE IdeController; + UINT8 ByteBuffer; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + + Status = Private->LegacyBiosPlatform->GetPlatformHandle ( + Private->LegacyBiosPlatform, + EfiGetPlatformIdeHandle, + 0, + &HandleBuffer, + &HandleCount, + NULL + ); + if (!EFI_ERROR (Status)) { + IdeController = HandleBuffer[0]; + Status = gBS->HandleProtocol ( + IdeController, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo + ); + ByteBuffer = 0x1f; + if (!EFI_ERROR (Status)) { + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x04, 1, &ByteBuffer); + } + } +} + + +/** + Enable ide controller. This gets disabled when LegacyBoot.c is about + to run the Option ROMs. + + @param Private Legacy BIOS Instance data + + +**/ +VOID +EnableAllControllers ( + IN LEGACY_BIOS_INSTANCE *Private + ) +{ + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN Index; + EFI_PCI_IO_PROTOCOL *PciIo; + PCI_TYPE01 PciConfigHeader; + EFI_STATUS Status; + + // + // + // + EnableIdeController (Private); + + // + // Assumption is table is built from low bus to high bus numbers. + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiPciIoProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + ASSERT_EFI_ERROR (Status); + + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo + ); + ASSERT_EFI_ERROR (Status); + + PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint32, + 0, + sizeof (PciConfigHeader) / sizeof (UINT32), + &PciConfigHeader + ); + + // + // We do not enable PPB here. This is for HotPlug Consideration. + // The Platform HotPlug Driver is responsible for Padding enough hot plug + // resources. It is also responsible for enable this bridge. If it + // does not pad it. It will cause some early Windows fail to installation. + // If the platform driver does not pad resource for PPB, PPB should be in + // un-enabled state to let Windows know that this PPB is not configured by + // BIOS. So Windows will allocate default resource for PPB. + // + // The reason for why we enable the command register is: + // The CSM will use the IO bar to detect some IRQ status, if the command + // is disabled, the IO resource will be out of scope. + // For example: + // We installed a legacy IRQ handle for a PCI IDE controller. When IRQ + // comes up, the handle will check the IO space to identify is the + // controller generated the IRQ source. + // If the IO command is not enabled, the IRQ handler will has wrong + // information. It will cause IRQ storm when the correctly IRQ handler fails + // to run. + // + if (!(IS_PCI_VGA (&PciConfigHeader) || + IS_PCI_OLD_VGA (&PciConfigHeader) || + IS_PCI_IDE (&PciConfigHeader) || + IS_PCI_P2P (&PciConfigHeader) || + IS_PCI_P2P_SUB (&PciConfigHeader) || + IS_PCI_LPC (&PciConfigHeader) )) { + + PciConfigHeader.Hdr.Command |= 0x1f; + + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 4, 1, &PciConfigHeader.Hdr.Command); + } + } +} + +/** + The following routines are identical in operation, so combine + for code compaction: + EfiGetPlatformBinaryGetMpTable + EfiGetPlatformBinaryGetOemIntData + EfiGetPlatformBinaryGetOem32Data + EfiGetPlatformBinaryGetOem16Data + + @param This Protocol instance pointer. + @param Id Table/Data identifier + + @retval EFI_SUCCESS Success + @retval EFI_INVALID_PARAMETER Invalid ID + @retval EFI_OUT_OF_RESOURCES no resource to get data or table + +**/ +EFI_STATUS +LegacyGetDataOrTable ( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN EFI_GET_PLATFORM_INFO_MODE Id + ) +{ + VOID *Table; + UINT32 TablePtr; + UINTN TableSize; + UINTN Alignment; + UINTN Location; + EFI_STATUS Status; + EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform; + EFI_COMPATIBILITY16_TABLE *Legacy16Table; + EFI_IA32_REGISTER_SET Regs; + LEGACY_BIOS_INSTANCE *Private; + + Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); + + LegacyBiosPlatform = Private->LegacyBiosPlatform; + Legacy16Table = Private->Legacy16Table; + + // + // Phase 1 - get an address allocated in 16-bit code + // + while (TRUE) { + switch (Id) { + case EfiGetPlatformBinaryMpTable: + case EfiGetPlatformBinaryOemIntData: + case EfiGetPlatformBinaryOem32Data: + case EfiGetPlatformBinaryOem16Data: + { + Status = LegacyBiosPlatform->GetPlatformInfo ( + LegacyBiosPlatform, + Id, + (VOID *) &Table, + &TableSize, + &Location, + &Alignment, + 0, + 0 + ); + DEBUG ((EFI_D_INFO, "LegacyGetDataOrTable - ID: %x, %r\n", (UINTN)Id, Status)); + DEBUG ((EFI_D_INFO, " Table - %x, Size - %x, Location - %x, Alignment - %x\n", (UINTN)Table, (UINTN)TableSize, (UINTN)Location, (UINTN)Alignment)); + break; + } + + default: + { + return EFI_INVALID_PARAMETER; + } + } + + if (EFI_ERROR (Status)) { + return Status; + } + + ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); + Regs.X.AX = Legacy16GetTableAddress; + Regs.X.CX = (UINT16) TableSize; + Regs.X.BX = (UINT16) Location; + Regs.X.DX = (UINT16) Alignment; + Private->LegacyBios.FarCall86 ( + This, + Private->Legacy16CallSegment, + Private->Legacy16CallOffset, + &Regs, + NULL, + 0 + ); + + if (Regs.X.AX != 0) { + DEBUG ((EFI_D_ERROR, "Table ID %x length insufficient\n", Id)); + return EFI_OUT_OF_RESOURCES; + } else { + break; + } + } + // + // Phase 2 Call routine second time with address to allow address adjustment + // + Status = LegacyBiosPlatform->GetPlatformInfo ( + LegacyBiosPlatform, + Id, + (VOID *) &Table, + &TableSize, + &Location, + &Alignment, + Regs.X.DS, + Regs.X.BX + ); + switch (Id) { + case EfiGetPlatformBinaryMpTable: + { + Legacy16Table->MpTablePtr = (UINT32) (Regs.X.DS * 16 + Regs.X.BX); + Legacy16Table->MpTableLength = (UINT32)TableSize; + DEBUG ((EFI_D_INFO, "MP table in legacy region - %x\n", (UINTN)Legacy16Table->MpTablePtr)); + break; + } + + case EfiGetPlatformBinaryOemIntData: + { + + Legacy16Table->OemIntSegment = Regs.X.DS; + Legacy16Table->OemIntOffset = Regs.X.BX; + DEBUG ((EFI_D_INFO, "OemInt table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->OemIntSegment, (UINTN)Legacy16Table->OemIntOffset)); + break; + } + + case EfiGetPlatformBinaryOem32Data: + { + Legacy16Table->Oem32Segment = Regs.X.DS; + Legacy16Table->Oem32Offset = Regs.X.BX; + DEBUG ((EFI_D_INFO, "Oem32 table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->Oem32Segment, (UINTN)Legacy16Table->Oem32Offset)); + break; + } + + case EfiGetPlatformBinaryOem16Data: + { + // + // Legacy16Table->Oem16Segment = Regs.X.DS; + // Legacy16Table->Oem16Offset = Regs.X.BX; + DEBUG ((EFI_D_INFO, "Oem16 table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->Oem16Segment, (UINTN)Legacy16Table->Oem16Offset)); + break; + } + + default: + { + return EFI_INVALID_PARAMETER; + } + } + + if (EFI_ERROR (Status)) { + return Status; + } + // + // Phase 3 Copy table to final location + // + TablePtr = (UINT32) (Regs.X.DS * 16 + Regs.X.BX); + + CopyMem ( + (VOID *) (UINTN)TablePtr, + Table, + TableSize + ); + + return EFI_SUCCESS; +} + +/** + Copy SMBIOS table to EfiReservedMemoryType of memory for legacy boot. + +**/ +VOID +CreateSmbiosTableInReservedMemory ( + VOID + ) +{ + SMBIOS_TABLE_ENTRY_POINT *EntryPointStructure; + + if ((mRuntimeSmbiosEntryPoint == NULL) || + (mReserveSmbiosEntryPoint == 0) || + (mStructureTableAddress == 0)) { + return; + } + + EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *) mRuntimeSmbiosEntryPoint; + + // + // Copy SMBIOS Entry Point Structure + // + CopyMem ( + (VOID *)(UINTN) mReserveSmbiosEntryPoint, + EntryPointStructure, + EntryPointStructure->EntryPointLength + ); + + // + // Copy SMBIOS Structure Table into EfiReservedMemoryType memory + // + CopyMem ( + (VOID *)(UINTN) mStructureTableAddress, + (VOID *)(UINTN) EntryPointStructure->TableAddress, + EntryPointStructure->TableLength + ); + + // + // Update TableAddress in Entry Point Structure + // + EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *)(UINTN) mReserveSmbiosEntryPoint; + EntryPointStructure->TableAddress = (UINT32)(UINTN) mStructureTableAddress; + + // + // Fixup checksums in the Entry Point Structure + // + EntryPointStructure->IntermediateChecksum = 0; + EntryPointStructure->EntryPointStructureChecksum = 0; + + EntryPointStructure->IntermediateChecksum = + CalculateCheckSum8 ( + (UINT8 *) EntryPointStructure + OFFSET_OF (SMBIOS_TABLE_ENTRY_POINT, IntermediateAnchorString), + EntryPointStructure->EntryPointLength - OFFSET_OF (SMBIOS_TABLE_ENTRY_POINT, IntermediateAnchorString) + ); + EntryPointStructure->EntryPointStructureChecksum = + CalculateCheckSum8 ((UINT8 *) EntryPointStructure, EntryPointStructure->EntryPointLength); +} + +/** + Assign drive number to legacy HDD drives prior to booting an EFI + aware OS so the OS can access drives without an EFI driver. + Note: BBS compliant drives ARE NOT available until this call by + either shell or EFI. + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS Drive numbers assigned + +**/ +EFI_STATUS +GenericLegacyBoot ( + IN EFI_LEGACY_BIOS_PROTOCOL *This + ) +{ + EFI_STATUS Status; + LEGACY_BIOS_INSTANCE *Private; + EFI_IA32_REGISTER_SET Regs; + EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable; + EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform; + UINTN CopySize; + VOID *AcpiPtr; + HDD_INFO *HddInfo; + HDD_INFO *LocalHddInfo; + UINTN Index; + EFI_COMPATIBILITY16_TABLE *Legacy16Table; + UINT32 *BdaPtr; + UINT16 HddCount; + UINT16 BbsCount; + BBS_TABLE *LocalBbsTable; + UINT32 *BaseVectorMaster; + EFI_TIME BootTime; + UINT32 LocalTime; + EFI_HANDLE IdeController; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + VOID *AcpiTable; + UINTN ShadowAddress; + UINT32 Granularity; + + LocalHddInfo = NULL; + HddCount = 0; + BbsCount = 0; + LocalBbsTable = NULL; + + Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); + DEBUG_CODE ( + DEBUG ((EFI_D_ERROR, "Start of legacy boot\n")); + ); + + Legacy16Table = Private->Legacy16Table; + EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable; + HddInfo = &EfiToLegacy16BootTable->HddInfo[0]; + + LegacyBiosPlatform = Private->LegacyBiosPlatform; + + EfiToLegacy16BootTable->MajorVersion = EFI_TO_LEGACY_MAJOR_VERSION; + EfiToLegacy16BootTable->MinorVersion = EFI_TO_LEGACY_MINOR_VERSION; + + // + // If booting to a legacy OS then force HDD drives to the appropriate + // boot mode by calling GetIdeHandle. + // A reconnect -r can force all HDDs back to native mode. + // + IdeController = NULL; + if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) { + Status = LegacyBiosPlatform->GetPlatformHandle ( + Private->LegacyBiosPlatform, + EfiGetPlatformIdeHandle, + 0, + &HandleBuffer, + &HandleCount, + NULL + ); + if (!EFI_ERROR (Status)) { + IdeController = HandleBuffer[0]; + } + } + // + // Unlock the Legacy BIOS region + // + Private->LegacyRegion->UnLock ( + Private->LegacyRegion, + 0xE0000, + 0x20000, + &Granularity + ); + + // + // Reconstruct the Legacy16 boot memory map + // + LegacyBiosBuildE820 (Private, &CopySize); + if (CopySize > Private->Legacy16Table->E820Length) { + ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); + Regs.X.AX = Legacy16GetTableAddress; + Regs.X.CX = (UINT16) CopySize; + Private->LegacyBios.FarCall86 ( + &Private->LegacyBios, + Private->Legacy16Table->Compatibility16CallSegment, + Private->Legacy16Table->Compatibility16CallOffset, + &Regs, + NULL, + 0 + ); + + Private->Legacy16Table->E820Pointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX); + Private->Legacy16Table->E820Length = (UINT32) CopySize; + if (Regs.X.AX != 0) { + DEBUG ((EFI_D_ERROR, "Legacy16 E820 length insufficient\n")); + } else { + CopyMem ( + (VOID *)(UINTN) Private->Legacy16Table->E820Pointer, + Private->E820Table, + CopySize + ); + } + } else { + CopyMem ( + (VOID *)(UINTN) Private->Legacy16Table->E820Pointer, + Private->E820Table, + CopySize + ); + Private->Legacy16Table->E820Length = (UINT32) CopySize; + } + + // + // We do not ASSERT if SmbiosTable not found. It is possbile that a platform does not produce SmbiosTable. + // + if (mReserveSmbiosEntryPoint == 0) { + DEBUG ((EFI_D_INFO, "Smbios table is not found!\n")); + } + CreateSmbiosTableInReservedMemory (); + EfiToLegacy16BootTable->SmbiosTable = (UINT32)(UINTN)mReserveSmbiosEntryPoint; + + AcpiTable = NULL; + Status = EfiGetSystemConfigurationTable ( + &gEfiAcpi20TableGuid, + &AcpiTable + ); + if (EFI_ERROR (Status)) { + Status = EfiGetSystemConfigurationTable ( + &gEfiAcpi10TableGuid, + &AcpiTable + ); + } + // + // We do not ASSERT if AcpiTable not found. It is possbile that a platform does not produce AcpiTable. + // + if (AcpiTable == NULL) { + DEBUG ((EFI_D_INFO, "ACPI table is not found!\n")); + } + EfiToLegacy16BootTable->AcpiTable = (UINT32)(UINTN)AcpiTable; + + // + // Get RSD Ptr table rev at offset 15 decimal + // Rev = 0 Length is 20 decimal + // Rev != 0 Length is UINT32 at offset 20 decimal + // + if (AcpiTable != NULL) { + + AcpiPtr = AcpiTable; + if (*((UINT8 *) AcpiPtr + 15) == 0) { + CopySize = 20; + } else { + AcpiPtr = ((UINT8 *) AcpiPtr + 20); + CopySize = (*(UINT32 *) AcpiPtr); + } + + CopyMem ( + (VOID *)(UINTN) Private->Legacy16Table->AcpiRsdPtrPointer, + AcpiTable, + CopySize + ); + } + // + // Make sure all PCI Interrupt Line register are programmed to match 8259 + // + PciProgramAllInterruptLineRegisters (Private); + + // + // Unlock the Legacy BIOS region as PciProgramAllInterruptLineRegisters + // can lock it. + // + Private->LegacyRegion->UnLock ( + Private->LegacyRegion, + Private->BiosStart, + Private->LegacyBiosImageSize, + &Granularity + ); + + // + // Configure Legacy Device Magic + // + // Only do this code if booting legacy OS + // + if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) { + UpdateSioData (Private); + } + // + // Setup BDA and EBDA standard areas before Legacy Boot + // + ACCESS_PAGE0_CODE ( + LegacyBiosCompleteBdaBeforeBoot (Private); + ); + LegacyBiosCompleteStandardCmosBeforeBoot (Private); + + // + // We must build IDE data, if it hasn't been done, before PciShadowRoms + // to insure EFI drivers are connected. + // + LegacyBiosBuildIdeData (Private, &HddInfo, 1); + UpdateAllIdentifyDriveData (Private); + + // + // Clear IO BAR, if IDE controller in legacy mode. + // + InitLegacyIdeController (IdeController); + + // + // Generate number of ticks since midnight for BDA. DOS requires this + // for its time. We have to make assumptions as to how long following + // code takes since after PciShadowRoms PciIo is gone. Place result in + // 40:6C-6F + // + // Adjust value by 1 second. + // + gRT->GetTime (&BootTime, NULL); + LocalTime = BootTime.Hour * 3600 + BootTime.Minute * 60 + BootTime.Second; + LocalTime += 1; + + // + // Multiply result by 18.2 for number of ticks since midnight. + // Use 182/10 to avoid floating point math. + // + LocalTime = (LocalTime * 182) / 10; + ACCESS_PAGE0_CODE ( + BdaPtr = (UINT32 *) (UINTN)0x46C; + *BdaPtr = LocalTime; + ); + + // + // Shadow PCI ROMs. We must do this near the end since this will kick + // of Native EFI drivers that may be needed to collect info for Legacy16 + // + // WARNING: PciIo is gone after this call. + // + PciShadowRoms (Private); + + // + // Shadow PXE base code, BIS etc. + // + Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xc0000, 0x40000, &Granularity); + ShadowAddress = Private->OptionRom; + Private->LegacyBiosPlatform->PlatformHooks ( + Private->LegacyBiosPlatform, + EfiPlatformHookShadowServiceRoms, + 0, + 0, + &ShadowAddress, + Legacy16Table, + NULL + ); + Private->OptionRom = (UINT32)ShadowAddress; + // + // Register Legacy SMI Handler + // + LegacyBiosPlatform->SmmInit ( + LegacyBiosPlatform, + EfiToLegacy16BootTable + ); + + // + // Let platform code know the boot options + // + LegacyBiosGetBbsInfo ( + This, + &HddCount, + &LocalHddInfo, + &BbsCount, + &LocalBbsTable + ); + + DEBUG_CODE ( + PrintPciInterruptRegister (); + PrintBbsTable (LocalBbsTable); + PrintHddInfo (LocalHddInfo); + ); + // + // If drive wasn't spun up then BuildIdeData may have found new drives. + // Need to update BBS boot priority. + // + for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) { + if ((LocalHddInfo[Index].IdentifyDrive[0].Raw[0] != 0) && + (LocalBbsTable[2 * Index + 1].BootPriority == BBS_IGNORE_ENTRY) + ) { + LocalBbsTable[2 * Index + 1].BootPriority = BBS_UNPRIORITIZED_ENTRY; + } + + if ((LocalHddInfo[Index].IdentifyDrive[1].Raw[0] != 0) && + (LocalBbsTable[2 * Index + 2].BootPriority == BBS_IGNORE_ENTRY) + ) { + LocalBbsTable[2 * Index + 2].BootPriority = BBS_UNPRIORITIZED_ENTRY; + } + } + + Private->LegacyRegion->UnLock ( + Private->LegacyRegion, + 0xc0000, + 0x40000, + &Granularity + ); + + LegacyBiosPlatform->PrepareToBoot ( + LegacyBiosPlatform, + mBbsDevicePathPtr, + mBbsTable, + mLoadOptionsSize, + mLoadOptions, + (VOID *) &Private->IntThunk->EfiToLegacy16BootTable + ); + + // + // If no boot device return to BDS + // + if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) { + for (Index = 0; Index < BbsCount; Index++){ + if ((LocalBbsTable[Index].BootPriority != BBS_DO_NOT_BOOT_FROM) && + (LocalBbsTable[Index].BootPriority != BBS_UNPRIORITIZED_ENTRY) && + (LocalBbsTable[Index].BootPriority != BBS_IGNORE_ENTRY)) { + break; + } + } + if (Index == BbsCount) { + return EFI_DEVICE_ERROR; + } + } + // + // Let the Legacy16 code know the device path type for legacy boot + // + EfiToLegacy16BootTable->DevicePathType = mBbsDevicePathPtr->DeviceType; + + // + // Copy MP table, if it exists. + // + LegacyGetDataOrTable (This, EfiGetPlatformBinaryMpTable); + + if (!Private->LegacyBootEntered) { + // + // Copy OEM INT Data, if it exists. Note: This code treats any data + // as a bag of bits and knows nothing of the contents nor cares. + // Contents are IBV specific. + // + LegacyGetDataOrTable (This, EfiGetPlatformBinaryOemIntData); + + // + // Copy OEM16 Data, if it exists.Note: This code treats any data + // as a bag of bits and knows nothing of the contents nor cares. + // Contents are IBV specific. + // + LegacyGetDataOrTable (This, EfiGetPlatformBinaryOem16Data); + + // + // Copy OEM32 Data, if it exists.Note: This code treats any data + // as a bag of bits and knows nothing of the contents nor cares. + // Contents are IBV specific. + // + LegacyGetDataOrTable (This, EfiGetPlatformBinaryOem32Data); + } + + // + // Call into Legacy16 code to prepare for INT 19h + // + ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); + Regs.X.AX = Legacy16PrepareToBoot; + + // + // Pass in handoff data + // + Regs.X.ES = NORMALIZE_EFI_SEGMENT ((UINTN)EfiToLegacy16BootTable); + Regs.X.BX = NORMALIZE_EFI_OFFSET ((UINTN)EfiToLegacy16BootTable); + + Private->LegacyBios.FarCall86 ( + This, + Private->Legacy16CallSegment, + Private->Legacy16CallOffset, + &Regs, + NULL, + 0 + ); + + if (Regs.X.AX != 0) { + return EFI_DEVICE_ERROR; + } + // + // Lock the Legacy BIOS region + // + Private->LegacyRegion->Lock ( + Private->LegacyRegion, + 0xc0000, + 0x40000, + &Granularity + ); + + if ((Private->Legacy16Table->TableLength >= OFFSET_OF (EFI_COMPATIBILITY16_TABLE, HiPermanentMemoryAddress)) && + ((Private->Legacy16Table->UmaAddress != 0) && (Private->Legacy16Table->UmaSize != 0))) { + // + // Here we could reduce UmaAddress down as far as Private->OptionRom, taking into + // account the granularity of the access control. + // + DEBUG((EFI_D_INFO, "Unlocking UMB RAM region 0x%x-0x%x\n", Private->Legacy16Table->UmaAddress, + Private->Legacy16Table->UmaAddress + Private->Legacy16Table->UmaSize)); + + Private->LegacyRegion->UnLock ( + Private->LegacyRegion, + Private->Legacy16Table->UmaAddress, + Private->Legacy16Table->UmaSize, + &Granularity + ); + } + + // + // Lock attributes of the Legacy Region if chipset supports + // + Private->LegacyRegion->BootLock ( + Private->LegacyRegion, + 0xc0000, + 0x40000, + &Granularity + ); + + // + // Call into Legacy16 code to do the INT 19h + // + EnableAllControllers (Private); + if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) { + + // + // Signal all the events that are waiting on EVT_SIGNAL_LEGACY_BOOT + // + EfiSignalEventLegacyBoot (); + + // + // Report Status Code to indicate legacy boot event was signalled + // + REPORT_STATUS_CODE ( + EFI_PROGRESS_CODE, + (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_LEGACY_BOOT_EVENT) + ); + + DEBUG ((EFI_D_INFO, "Legacy INT19 Boot...\n")); + + // + // Disable DXE Timer while executing in real mode + // + Private->Timer->SetTimerPeriod (Private->Timer, 0); + + // + // Save and disable interrupt of debug timer + // + SaveAndSetDebugTimerInterrupt (FALSE); + + + // + // Put the 8259 into its legacy mode by reprogramming the vector bases + // + Private->Legacy8259->SetVectorBase (Private->Legacy8259, LEGACY_MODE_BASE_VECTOR_MASTER, LEGACY_MODE_BASE_VECTOR_SLAVE); + // + // PC History + // The original PC used INT8-F for master PIC. Since these mapped over + // processor exceptions TIANO moved the master PIC to INT68-6F. + // We need to set these back to the Legacy16 unexpected interrupt(saved + // in LegacyBios.c) since some OS see that these have values different from + // what is expected and invoke them. Since the legacy OS corrupts EFI + // memory, there is no handler for these interrupts and OS blows up. + // + // We need to save the TIANO values for the rare case that the Legacy16 + // code cannot boot but knows memory hasn't been destroyed. + // + // To compound the problem, video takes over one of these INTS and must be + // be left. + // @bug - determine if video hooks INT(in which case we must find new + // set of TIANO vectors) or takes it over. + // + // + ACCESS_PAGE0_CODE ( + BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER); + for (Index = 0; Index < 8; Index++) { + Private->ThunkSavedInt[Index] = BaseVectorMaster[Index]; + if (Private->ThunkSeg == (UINT16) (BaseVectorMaster[Index] >> 16)) { + BaseVectorMaster[Index] = (UINT32) (Private->BiosUnexpectedInt); + } + } + ); + + ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); + Regs.X.AX = Legacy16Boot; + + Private->LegacyBios.FarCall86 ( + This, + Private->Legacy16CallSegment, + Private->Legacy16CallOffset, + &Regs, + NULL, + 0 + ); + + ACCESS_PAGE0_CODE ( + BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER); + for (Index = 0; Index < 8; Index++) { + BaseVectorMaster[Index] = Private->ThunkSavedInt[Index]; + } + ); + } + Private->LegacyBootEntered = TRUE; + if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) { + // + // Should never return unless never passed control to 0:7c00(first stage + // OS loader) and only then if no bootable device found. + // + return EFI_DEVICE_ERROR; + } else { + // + // If boot to EFI then expect to return to caller + // + return EFI_SUCCESS; + } +} + + +/** + Assign drive number to legacy HDD drives prior to booting an EFI + aware OS so the OS can access drives without an EFI driver. + Note: BBS compliant drives ARE NOT available until this call by + either shell or EFI. + + @param This Protocol instance pointer. + @param BbsCount Number of BBS_TABLE structures + @param BbsTable List BBS entries + + @retval EFI_SUCCESS Drive numbers assigned + +**/ +EFI_STATUS +EFIAPI +LegacyBiosPrepareToBootEfi ( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + OUT UINT16 *BbsCount, + OUT BBS_TABLE **BbsTable + ) +{ + EFI_STATUS Status; + EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable; + LEGACY_BIOS_INSTANCE *Private; + + Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); + EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable; + mBootMode = BOOT_EFI_OS; + mBbsDevicePathPtr = NULL; + Status = GenericLegacyBoot (This); + *BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable; + *BbsCount = (UINT16) (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE)); + return Status; +} + +/** + To boot from an unconventional device like parties and/or execute HDD diagnostics. + + @param This Protocol instance pointer. + @param Attributes How to interpret the other input parameters + @param BbsEntry The 0-based index into the BbsTable for the parent + device. + @param BeerData Pointer to the 128 bytes of ram BEER data. + @param ServiceAreaData Pointer to the 64 bytes of raw Service Area data. The + caller must provide a pointer to the specific Service + Area and not the start all Service Areas. + + @retval EFI_INVALID_PARAMETER if error. Does NOT return if no error. + +***/ +EFI_STATUS +EFIAPI +LegacyBiosBootUnconventionalDevice ( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN UDC_ATTRIBUTES Attributes, + IN UINTN BbsEntry, + IN VOID *BeerData, + IN VOID *ServiceAreaData + ) +{ + EFI_STATUS Status; + EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable; + LEGACY_BIOS_INSTANCE *Private; + UD_TABLE *UcdTable; + UINTN Index; + UINT16 BootPriority; + BBS_TABLE *BbsTable; + + BootPriority = 0; + Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); + mBootMode = BOOT_UNCONVENTIONAL_DEVICE; + mBbsDevicePathPtr = &mBbsDevicePathNode; + mAttributes = Attributes; + mBbsEntry = BbsEntry; + mBeerData = BeerData, mServiceAreaData = ServiceAreaData; + + EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable; + + // + // Do input parameter checking + // + if ((Attributes.DirectoryServiceValidity == 0) && + (Attributes.RabcaUsedFlag == 0) && + (Attributes.ExecuteHddDiagnosticsFlag == 0) + ) { + return EFI_INVALID_PARAMETER; + } + + if (((Attributes.DirectoryServiceValidity != 0) && (ServiceAreaData == NULL)) || + (((Attributes.DirectoryServiceValidity | Attributes.RabcaUsedFlag) != 0) && (BeerData == NULL)) + ) { + return EFI_INVALID_PARAMETER; + } + + UcdTable = (UD_TABLE *) AllocatePool ( + sizeof (UD_TABLE) + ); + if (NULL == UcdTable) { + return EFI_OUT_OF_RESOURCES; + } + + EfiToLegacy16BootTable->UnconventionalDeviceTable = (UINT32)(UINTN)UcdTable; + UcdTable->Attributes = Attributes; + UcdTable->BbsTableEntryNumberForParentDevice = (UINT8) BbsEntry; + // + // Force all existing BBS entries to DoNotBoot. This allows 16-bit CSM + // to assign drive numbers but bot boot from. Only newly created entries + // will be valid. + // + BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable; + for (Index = 0; Index < EfiToLegacy16BootTable->NumberBbsEntries; Index++) { + BbsTable[Index].BootPriority = BBS_DO_NOT_BOOT_FROM; + } + // + // If parent is onboard IDE then assign controller & device number + // else they are 0. + // + if (BbsEntry < MAX_IDE_CONTROLLER * 2) { + UcdTable->DeviceNumber = (UINT8) ((BbsEntry - 1) % 2); + } + + if (BeerData != NULL) { + CopyMem ( + (VOID *) UcdTable->BeerData, + BeerData, + (UINTN) 128 + ); + } + + if (ServiceAreaData != NULL) { + CopyMem ( + (VOID *) UcdTable->ServiceAreaData, + ServiceAreaData, + (UINTN) 64 + ); + } + // + // For each new entry do the following: + // 1. Increment current number of BBS entries + // 2. Copy parent entry to new entry. + // 3. Zero out BootHandler Offset & segment + // 4. Set appropriate device type. BEV(0x80) for HDD diagnostics + // and Floppy(0x01) for PARTIES boot. + // 5. Assign new priority. + // + if ((Attributes.ExecuteHddDiagnosticsFlag) != 0) { + EfiToLegacy16BootTable->NumberBbsEntries += 1; + + CopyMem ( + (VOID *) &BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority, + (VOID *) &BbsTable[BbsEntry].BootPriority, + sizeof (BBS_TABLE) + ); + + BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerOffset = 0; + BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerSegment = 0; + BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].DeviceType = 0x80; + + UcdTable->BbsTableEntryNumberForHddDiag = (UINT8) (EfiToLegacy16BootTable->NumberBbsEntries - 1); + + BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority = BootPriority; + BootPriority += 1; + + // + // Set device type as BBS_TYPE_DEV for PARTIES diagnostic + // + mBbsDevicePathNode.DeviceType = BBS_TYPE_BEV; + } + + if (((Attributes.DirectoryServiceValidity | Attributes.RabcaUsedFlag)) != 0) { + EfiToLegacy16BootTable->NumberBbsEntries += 1; + CopyMem ( + (VOID *) &BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority, + (VOID *) &BbsTable[BbsEntry].BootPriority, + sizeof (BBS_TABLE) + ); + + BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerOffset = 0; + BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerSegment = 0; + BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].DeviceType = 0x01; + UcdTable->BbsTableEntryNumberForBoot = (UINT8) (EfiToLegacy16BootTable->NumberBbsEntries - 1); + BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority = BootPriority; + + // + // Set device type as BBS_TYPE_FLOPPY for PARTIES boot as floppy + // + mBbsDevicePathNode.DeviceType = BBS_TYPE_FLOPPY; + } + // + // Build the BBS Device Path for this boot selection + // + mBbsDevicePathNode.Header.Type = BBS_DEVICE_PATH; + mBbsDevicePathNode.Header.SubType = BBS_BBS_DP; + SetDevicePathNodeLength (&mBbsDevicePathNode.Header, sizeof (BBS_BBS_DEVICE_PATH)); + mBbsDevicePathNode.StatusFlag = 0; + mBbsDevicePathNode.String[0] = 0; + + Status = GenericLegacyBoot (This); + return Status; +} + +/** + Attempt to legacy boot the BootOption. If the EFI contexted has been + compromised this function will not return. + + @param This Protocol instance pointer. + @param BbsDevicePath EFI Device Path from BootXXXX variable. + @param LoadOptionsSize Size of LoadOption in size. + @param LoadOptions LoadOption from BootXXXX variable + + @retval EFI_SUCCESS Removable media not present + +**/ +EFI_STATUS +EFIAPI +LegacyBiosLegacyBoot ( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN BBS_BBS_DEVICE_PATH *BbsDevicePath, + IN UINT32 LoadOptionsSize, + IN VOID *LoadOptions + ) +{ + EFI_STATUS Status; + + mBbsDevicePathPtr = BbsDevicePath; + mLoadOptionsSize = LoadOptionsSize; + mLoadOptions = LoadOptions; + mBootMode = BOOT_LEGACY_OS; + Status = GenericLegacyBoot (This); + + return Status; +} + +/** + Convert EFI Memory Type to E820 Memory Type. + + @param Type EFI Memory Type + + @return ACPI Memory Type for EFI Memory Type + +**/ +EFI_ACPI_MEMORY_TYPE +EfiMemoryTypeToE820Type ( + IN UINT32 Type + ) +{ + switch (Type) { + case EfiLoaderCode: + case EfiLoaderData: + case EfiBootServicesCode: + case EfiBootServicesData: + case EfiConventionalMemory: + // + // The memory of EfiRuntimeServicesCode and EfiRuntimeServicesData are + // usable memory for legacy OS, because legacy OS is not aware of EFI runtime concept. + // In ACPI specification, EfiRuntimeServiceCode and EfiRuntimeServiceData + // should be mapped to AddressRangeReserved. This statement is for UEFI OS, not for legacy OS. + // + case EfiRuntimeServicesCode: + case EfiRuntimeServicesData: + return EfiAcpiAddressRangeMemory; + + case EfiPersistentMemory: + return EfiAddressRangePersistentMemory; + + case EfiACPIReclaimMemory: + return EfiAcpiAddressRangeACPI; + + case EfiACPIMemoryNVS: + return EfiAcpiAddressRangeNVS; + + // + // All other types map to reserved. + // Adding the code just waists FLASH space. + // + // case EfiReservedMemoryType: + // case EfiUnusableMemory: + // case EfiMemoryMappedIO: + // case EfiMemoryMappedIOPortSpace: + // case EfiPalCode: + // + default: + return EfiAcpiAddressRangeReserved; + } +} + +/** + Build the E820 table. + + @param Private Legacy BIOS Instance data + @param Size Size of E820 Table + + @retval EFI_SUCCESS It should always work. + +**/ +EFI_STATUS +LegacyBiosBuildE820 ( + IN LEGACY_BIOS_INSTANCE *Private, + OUT UINTN *Size + ) +{ + EFI_STATUS Status; + EFI_E820_ENTRY64 *E820Table; + EFI_MEMORY_DESCRIPTOR *EfiMemoryMap; + EFI_MEMORY_DESCRIPTOR *EfiMemoryMapEnd; + EFI_MEMORY_DESCRIPTOR *EfiEntry; + EFI_MEMORY_DESCRIPTOR *NextEfiEntry; + EFI_MEMORY_DESCRIPTOR TempEfiEntry; + UINTN EfiMemoryMapSize; + UINTN EfiMapKey; + UINTN EfiDescriptorSize; + UINT32 EfiDescriptorVersion; + UINTN Index; + EFI_PEI_HOB_POINTERS Hob; + EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob; + UINTN TempIndex; + UINTN IndexSort; + UINTN TempNextIndex; + EFI_E820_ENTRY64 TempE820; + EFI_ACPI_MEMORY_TYPE TempType; + BOOLEAN ChangedFlag; + UINTN Above1MIndex; + UINT64 MemoryBlockLength; + + E820Table = (EFI_E820_ENTRY64 *) Private->E820Table; + + // + // Get the EFI memory map. + // + EfiMemoryMapSize = 0; + EfiMemoryMap = NULL; + Status = gBS->GetMemoryMap ( + &EfiMemoryMapSize, + EfiMemoryMap, + &EfiMapKey, + &EfiDescriptorSize, + &EfiDescriptorVersion + ); + ASSERT (Status == EFI_BUFFER_TOO_SMALL); + + do { + // + // Use size returned for the AllocatePool. + // We don't just multiply by 2 since the "for" loop below terminates on + // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwise + // we process bogus entries and create bogus E820 entries. + // + EfiMemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (EfiMemoryMapSize); + ASSERT (EfiMemoryMap != NULL); + Status = gBS->GetMemoryMap ( + &EfiMemoryMapSize, + EfiMemoryMap, + &EfiMapKey, + &EfiDescriptorSize, + &EfiDescriptorVersion + ); + if (EFI_ERROR (Status)) { + FreePool (EfiMemoryMap); + } + } while (Status == EFI_BUFFER_TOO_SMALL); + + ASSERT_EFI_ERROR (Status); + + // + // Punch in the E820 table for memory less than 1 MB. + // Assume ZeroMem () has been done on data structure. + // + // + // First entry is 0 to (640k - EBDA) + // + ACCESS_PAGE0_CODE ( + E820Table[0].BaseAddr = 0; + E820Table[0].Length = (UINT64) ((*(UINT16 *) (UINTN)0x40E) << 4); + E820Table[0].Type = EfiAcpiAddressRangeMemory; + ); + + // + // Second entry is (640k - EBDA) to 640k + // + E820Table[1].BaseAddr = E820Table[0].Length; + E820Table[1].Length = (UINT64) ((640 * 1024) - E820Table[0].Length); + E820Table[1].Type = EfiAcpiAddressRangeReserved; + + // + // Third Entry is legacy BIOS + // DO NOT CLAIM region from 0xA0000-0xDFFFF. OS can use free areas + // to page in memory under 1MB. + // Omit region from 0xE0000 to start of BIOS, if any. This can be + // used for a multiple reasons including OPROMS. + // + + // + // The CSM binary image size is not the actually size that CSM binary used, + // to avoid memory corrupt, we declare the 0E0000 - 0FFFFF is used by CSM binary. + // + E820Table[2].BaseAddr = 0xE0000; + E820Table[2].Length = 0x20000; + E820Table[2].Type = EfiAcpiAddressRangeReserved; + + Above1MIndex = 2; + + // + // Process the EFI map to produce E820 map; + // + + // + // Sort memory map from low to high + // + EfiEntry = EfiMemoryMap; + NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize); + EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize); + while (EfiEntry < EfiMemoryMapEnd) { + while (NextEfiEntry < EfiMemoryMapEnd) { + if (EfiEntry->PhysicalStart > NextEfiEntry->PhysicalStart) { + CopyMem (&TempEfiEntry, EfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR)); + CopyMem (EfiEntry, NextEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR)); + CopyMem (NextEfiEntry, &TempEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR)); + } + + NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (NextEfiEntry, EfiDescriptorSize); + } + + EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize); + NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize); + } + + EfiEntry = EfiMemoryMap; + EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize); + for (Index = Above1MIndex; (EfiEntry < EfiMemoryMapEnd) && (Index < EFI_MAX_E820_ENTRY - 1); ) { + MemoryBlockLength = (UINT64) (LShiftU64 (EfiEntry->NumberOfPages, 12)); + if ((EfiEntry->PhysicalStart + MemoryBlockLength) < 0x100000) { + // + // Skip the memory block if under 1MB + // + } else { + if (EfiEntry->PhysicalStart < 0x100000) { + // + // When the memory block spans below 1MB, ensure the memory block start address is at least 1MB + // + MemoryBlockLength -= 0x100000 - EfiEntry->PhysicalStart; + EfiEntry->PhysicalStart = 0x100000; + } + + // + // Convert memory type to E820 type + // + TempType = EfiMemoryTypeToE820Type (EfiEntry->Type); + + if ((E820Table[Index].Type == TempType) && (EfiEntry->PhysicalStart == (E820Table[Index].BaseAddr + E820Table[Index].Length))) { + // + // Grow an existing entry + // + E820Table[Index].Length += MemoryBlockLength; + } else { + // + // Make a new entry + // + ++Index; + E820Table[Index].BaseAddr = EfiEntry->PhysicalStart; + E820Table[Index].Length = MemoryBlockLength; + E820Table[Index].Type = TempType; + } + } + EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize); + } + + FreePool (EfiMemoryMap); + + // + // Process the reserved memory map to produce E820 map ; + // + for (Hob.Raw = GetHobList (); !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) { + if (Hob.Raw != NULL && GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { + ResourceHob = Hob.ResourceDescriptor; + if (((ResourceHob->ResourceType == EFI_RESOURCE_MEMORY_MAPPED_IO) || + (ResourceHob->ResourceType == EFI_RESOURCE_FIRMWARE_DEVICE) || + (ResourceHob->ResourceType == EFI_RESOURCE_MEMORY_RESERVED) ) && + (ResourceHob->PhysicalStart > 0x100000) && + (Index < EFI_MAX_E820_ENTRY - 1)) { + ++Index; + E820Table[Index].BaseAddr = ResourceHob->PhysicalStart; + E820Table[Index].Length = ResourceHob->ResourceLength; + E820Table[Index].Type = EfiAcpiAddressRangeReserved; + } + } + } + + Index ++; + Private->IntThunk->EfiToLegacy16InitTable.NumberE820Entries = (UINT32)Index; + Private->IntThunk->EfiToLegacy16BootTable.NumberE820Entries = (UINT32)Index; + Private->NumberE820Entries = (UINT32)Index; + *Size = (UINTN) (Index * sizeof (EFI_E820_ENTRY64)); + + // + // Sort E820Table from low to high + // + for (TempIndex = 0; TempIndex < Index; TempIndex++) { + ChangedFlag = FALSE; + for (TempNextIndex = 1; TempNextIndex < Index - TempIndex; TempNextIndex++) { + if (E820Table[TempNextIndex - 1].BaseAddr > E820Table[TempNextIndex].BaseAddr) { + ChangedFlag = TRUE; + TempE820.BaseAddr = E820Table[TempNextIndex - 1].BaseAddr; + TempE820.Length = E820Table[TempNextIndex - 1].Length; + TempE820.Type = E820Table[TempNextIndex - 1].Type; + + E820Table[TempNextIndex - 1].BaseAddr = E820Table[TempNextIndex].BaseAddr; + E820Table[TempNextIndex - 1].Length = E820Table[TempNextIndex].Length; + E820Table[TempNextIndex - 1].Type = E820Table[TempNextIndex].Type; + + E820Table[TempNextIndex].BaseAddr = TempE820.BaseAddr; + E820Table[TempNextIndex].Length = TempE820.Length; + E820Table[TempNextIndex].Type = TempE820.Type; + } + } + + if (!ChangedFlag) { + break; + } + } + + // + // Remove the overlap range + // + for (TempIndex = 1; TempIndex < Index; TempIndex++) { + if (E820Table[TempIndex - 1].BaseAddr <= E820Table[TempIndex].BaseAddr && + ((E820Table[TempIndex - 1].BaseAddr + E820Table[TempIndex - 1].Length) >= + (E820Table[TempIndex].BaseAddr +E820Table[TempIndex].Length))) { + // + //Overlap range is found + // + ASSERT (E820Table[TempIndex - 1].Type == E820Table[TempIndex].Type); + + if (TempIndex == Index - 1) { + E820Table[TempIndex].BaseAddr = 0; + E820Table[TempIndex].Length = 0; + E820Table[TempIndex].Type = (EFI_ACPI_MEMORY_TYPE) 0; + Index--; + break; + } else { + for (IndexSort = TempIndex; IndexSort < Index - 1; IndexSort ++) { + E820Table[IndexSort].BaseAddr = E820Table[IndexSort + 1].BaseAddr; + E820Table[IndexSort].Length = E820Table[IndexSort + 1].Length; + E820Table[IndexSort].Type = E820Table[IndexSort + 1].Type; + } + Index--; + } + } + } + + + + Private->IntThunk->EfiToLegacy16InitTable.NumberE820Entries = (UINT32)Index; + Private->IntThunk->EfiToLegacy16BootTable.NumberE820Entries = (UINT32)Index; + Private->NumberE820Entries = (UINT32)Index; + *Size = (UINTN) (Index * sizeof (EFI_E820_ENTRY64)); + + // + // Determine OS usable memory above 1MB + // + Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb = 0x0000; + for (TempIndex = Above1MIndex; TempIndex < Index; TempIndex++) { + if (E820Table[TempIndex].BaseAddr >= 0x100000 && E820Table[TempIndex].BaseAddr < 0x100000000ULL) { // not include above 4G memory + // + // ACPIReclaimMemory is also usable memory for ACPI OS, after OS dumps all ACPI tables. + // + if ((E820Table[TempIndex].Type == EfiAcpiAddressRangeMemory) || (E820Table[TempIndex].Type == EfiAcpiAddressRangeACPI)) { + Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb += (UINT32) (E820Table[TempIndex].Length); + } else { + break; // break at first not normal memory, because SMM may use reserved memory. + } + } + } + + Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb = Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb; + + // + // Print DEBUG information + // + for (TempIndex = 0; TempIndex < Index; TempIndex++) { + DEBUG((EFI_D_INFO, "E820[%2d]: 0x%016lx - 0x%016lx, Type = %d\n", + TempIndex, + E820Table[TempIndex].BaseAddr, + (E820Table[TempIndex].BaseAddr + E820Table[TempIndex].Length), + E820Table[TempIndex].Type + )); + } + + return EFI_SUCCESS; +} + + +/** + Fill in the standard BDA and EBDA stuff prior to legacy Boot + + @param Private Legacy BIOS Instance data + + @retval EFI_SUCCESS It should always work. + +**/ +EFI_STATUS +LegacyBiosCompleteBdaBeforeBoot ( + IN LEGACY_BIOS_INSTANCE *Private + ) +{ + BDA_STRUC *Bda; + UINT16 MachineConfig; + DEVICE_PRODUCER_DATA_HEADER *SioPtr; + + Bda = (BDA_STRUC *) ((UINTN) 0x400); + MachineConfig = 0; + + SioPtr = &(Private->IntThunk->EfiToLegacy16BootTable.SioData); + Bda->Com1 = SioPtr->Serial[0].Address; + Bda->Com2 = SioPtr->Serial[1].Address; + Bda->Com3 = SioPtr->Serial[2].Address; + Bda->Com4 = SioPtr->Serial[3].Address; + + if (SioPtr->Serial[0].Address != 0x00) { + MachineConfig += 0x200; + } + + if (SioPtr->Serial[1].Address != 0x00) { + MachineConfig += 0x200; + } + + if (SioPtr->Serial[2].Address != 0x00) { + MachineConfig += 0x200; + } + + if (SioPtr->Serial[3].Address != 0x00) { + MachineConfig += 0x200; + } + + Bda->Lpt1 = SioPtr->Parallel[0].Address; + Bda->Lpt2 = SioPtr->Parallel[1].Address; + Bda->Lpt3 = SioPtr->Parallel[2].Address; + + if (SioPtr->Parallel[0].Address != 0x00) { + MachineConfig += 0x4000; + } + + if (SioPtr->Parallel[1].Address != 0x00) { + MachineConfig += 0x4000; + } + + if (SioPtr->Parallel[2].Address != 0x00) { + MachineConfig += 0x4000; + } + + Bda->NumberOfDrives = (UINT8) (Bda->NumberOfDrives + Private->IdeDriveCount); + if (SioPtr->Floppy.NumberOfFloppy != 0x00) { + MachineConfig = (UINT16) (MachineConfig + 0x01 + (SioPtr->Floppy.NumberOfFloppy - 1) * 0x40); + Bda->FloppyXRate = 0x07; + } + + Bda->Lpt1_2Timeout = 0x1414; + Bda->Lpt3_4Timeout = 0x1414; + Bda->Com1_2Timeout = 0x0101; + Bda->Com3_4Timeout = 0x0101; + + // + // Force VGA and Coprocessor, indicate 101/102 keyboard + // + MachineConfig = (UINT16) (MachineConfig + 0x00 + 0x02 + (SioPtr->MousePresent * 0x04)); + Bda->MachineConfig = MachineConfig; + + return EFI_SUCCESS; +} + +/** + Fill in the standard BDA for Keyboard LEDs + + @param This Protocol instance pointer. + @param Leds Current LED status + + @retval EFI_SUCCESS It should always work. + +**/ +EFI_STATUS +EFIAPI +LegacyBiosUpdateKeyboardLedStatus ( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN UINT8 Leds + ) +{ + LEGACY_BIOS_INSTANCE *Private; + BDA_STRUC *Bda; + UINT8 LocalLeds; + EFI_IA32_REGISTER_SET Regs; + + Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); + + ACCESS_PAGE0_CODE ( + Bda = (BDA_STRUC *) ((UINTN) 0x400); + LocalLeds = Leds; + Bda->LedStatus = (UINT8) ((Bda->LedStatus &~0x07) | LocalLeds); + LocalLeds = (UINT8) (LocalLeds << 4); + Bda->ShiftStatus = (UINT8) ((Bda->ShiftStatus &~0x70) | LocalLeds); + LocalLeds = (UINT8) (Leds & 0x20); + Bda->KeyboardStatus = (UINT8) ((Bda->KeyboardStatus &~0x20) | LocalLeds); + ); + + // + // Call into Legacy16 code to allow it to do any processing + // + ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); + Regs.X.AX = Legacy16SetKeyboardLeds; + Regs.H.CL = Leds; + + Private->LegacyBios.FarCall86 ( + &Private->LegacyBios, + Private->Legacy16Table->Compatibility16CallSegment, + Private->Legacy16Table->Compatibility16CallOffset, + &Regs, + NULL, + 0 + ); + + return EFI_SUCCESS; +} + + +/** + Fill in the standard CMOS stuff prior to legacy Boot + + @param Private Legacy BIOS Instance data + + @retval EFI_SUCCESS It should always work. + +**/ +EFI_STATUS +LegacyBiosCompleteStandardCmosBeforeBoot ( + IN LEGACY_BIOS_INSTANCE *Private + ) +{ + UINT8 Bda; + UINT8 Floppy; + UINT32 Size; + + // + // Update CMOS locations + // 10 floppy + // 12,19,1A - ignore as OS don't use them and there is no standard due + // to large capacity drives + // CMOS 14 = BDA 40:10 plus bit 3(display enabled) + // + ACCESS_PAGE0_CODE ( + Bda = (UINT8)(*((UINT8 *)((UINTN)0x410)) | BIT3); + ); + + // + // Force display enabled + // + Floppy = 0x00; + if ((Bda & BIT0) != 0) { + Floppy = BIT6; + } + + // + // Check if 2.88MB floppy set + // + if ((Bda & (BIT7 | BIT6)) != 0) { + Floppy = (UINT8)(Floppy | BIT1); + } + + LegacyWriteStandardCmos (CMOS_10, Floppy); + LegacyWriteStandardCmos (CMOS_14, Bda); + + // + // Force Status Register A to set rate selection bits and divider + // + LegacyWriteStandardCmos (CMOS_0A, 0x26); + + // + // redo memory size since it can change + // + Size = (15 * SIZE_1MB) >> 10; + if (Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb < (15 * SIZE_1MB)) { + Size = Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb >> 10; + } + + LegacyWriteStandardCmos (CMOS_17, (UINT8)(Size & 0xFF)); + LegacyWriteStandardCmos (CMOS_30, (UINT8)(Size & 0xFF)); + LegacyWriteStandardCmos (CMOS_18, (UINT8)(Size >> 8)); + LegacyWriteStandardCmos (CMOS_31, (UINT8)(Size >> 8)); + + LegacyCalculateWriteStandardCmosChecksum (); + + return EFI_SUCCESS; +} + +/** + Relocate this image under 4G memory for IPF. + + @param ImageHandle Handle of driver image. + @param SystemTable Pointer to system table. + + @retval EFI_SUCCESS Image successfully relocated. + @retval EFI_ABORTED Failed to relocate image. + +**/ +EFI_STATUS +RelocateImageUnder4GIfNeeded ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return EFI_SUCCESS; +} diff --git a/OvmfPkg/Csm/LegacyBiosDxe/LegacyCmos.c b/OvmfPkg/Csm/LegacyBiosDxe/LegacyCmos.c new file mode 100644 index 0000000000..de25e06184 --- /dev/null +++ b/OvmfPkg/Csm/LegacyBiosDxe/LegacyCmos.c @@ -0,0 +1,117 @@ +/** @file + This code fills in standard CMOS values and updates the standard CMOS + checksum. The Legacy16 code or LegacyBiosPlatform.c is responsible for + non-standard CMOS locations and non-standard checksums. + +Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "LegacyBiosInterface.h" + +/** + Read CMOS register through index/data port. + + @param[in] Index The index of the CMOS register to read. + + @return The data value from the CMOS register specified by Index. + +**/ +UINT8 +LegacyReadStandardCmos ( + IN UINT8 Index + ) +{ + IoWrite8 (PORT_70, Index); + return IoRead8 (PORT_71); +} + +/** + Write CMOS register through index/data port. + + @param[in] Index The index of the CMOS register to write. + @param[in] Value The value of CMOS register to write. + + @return The value written to the CMOS register specified by Index. + +**/ +UINT8 +LegacyWriteStandardCmos ( + IN UINT8 Index, + IN UINT8 Value + ) +{ + IoWrite8 (PORT_70, Index); + return IoWrite8 (PORT_71, Value); +} + +/** + Calculate the new standard CMOS checksum and write it. + + @param Private Legacy BIOS Instance data + + @retval EFI_SUCCESS Calculate 16-bit checksum successfully + +**/ +EFI_STATUS +LegacyCalculateWriteStandardCmosChecksum ( + VOID + ) +{ + UINT8 Register; + UINT16 Checksum; + + for (Checksum = 0, Register = 0x10; Register < 0x2e; Register++) { + Checksum = (UINT16)(Checksum + LegacyReadStandardCmos (Register)); + } + LegacyWriteStandardCmos (CMOS_2E, (UINT8)(Checksum >> 8)); + LegacyWriteStandardCmos (CMOS_2F, (UINT8)(Checksum & 0xff)); + return EFI_SUCCESS; +} + + +/** + Fill in the standard CMOS stuff before Legacy16 load + + @param Private Legacy BIOS Instance data + + @retval EFI_SUCCESS It should always work. + +**/ +EFI_STATUS +LegacyBiosInitCmos ( + IN LEGACY_BIOS_INSTANCE *Private + ) +{ + UINT32 Size; + + // + // Clear all errors except RTC lost power + // + LegacyWriteStandardCmos (CMOS_0E, (UINT8)(LegacyReadStandardCmos (CMOS_0E) & BIT7)); + + // + // Update CMOS locations 15,16,17,18,30,31 and 32 + // CMOS 16,15 = 640Kb = 0x280 + // CMOS 18,17 = 31,30 = 15Mb max in 1Kb increments =0x3C00 max + // CMOS 32 = 0x20 + // + LegacyWriteStandardCmos (CMOS_15, 0x80); + LegacyWriteStandardCmos (CMOS_16, 0x02); + + Size = 15 * SIZE_1MB; + if (Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb < (15 * SIZE_1MB)) { + Size = Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb >> 10; + } + + LegacyWriteStandardCmos (CMOS_17, (UINT8)(Size & 0xFF)); + LegacyWriteStandardCmos (CMOS_30, (UINT8)(Size & 0xFF)); + LegacyWriteStandardCmos (CMOS_18, (UINT8)(Size >> 8)); + LegacyWriteStandardCmos (CMOS_31, (UINT8)(Size >> 8)); + + LegacyCalculateWriteStandardCmosChecksum (); + + return EFI_SUCCESS; +} diff --git a/OvmfPkg/Csm/LegacyBiosDxe/LegacyIde.c b/OvmfPkg/Csm/LegacyBiosDxe/LegacyIde.c new file mode 100644 index 0000000000..789f48370e --- /dev/null +++ b/OvmfPkg/Csm/LegacyBiosDxe/LegacyIde.c @@ -0,0 +1,310 @@ +/** @file + Collect IDE information from Native EFI Driver + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "LegacyBiosInterface.h" + +BOOLEAN mIdeDataBuiltFlag = FALSE; + +/** + Collect IDE Inquiry data from the IDE disks + + @param Private Legacy BIOS Instance data + @param HddInfo Hdd Information + @param Flag Reconnect IdeController or not + + @retval EFI_SUCCESS It should always work. + +**/ +EFI_STATUS +LegacyBiosBuildIdeData ( + IN LEGACY_BIOS_INSTANCE *Private, + IN HDD_INFO **HddInfo, + IN UINT16 Flag + ) +{ + EFI_STATUS Status; + EFI_HANDLE IdeController; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN Index; + EFI_DISK_INFO_PROTOCOL *DiskInfo; + UINT32 IdeChannel; + UINT32 IdeDevice; + UINT32 Size; + UINT8 *InquiryData; + UINT32 InquiryDataSize; + HDD_INFO *LocalHddInfo; + UINT32 PciIndex; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *DevicePathNode; + EFI_DEVICE_PATH_PROTOCOL *TempDevicePathNode; + PCI_DEVICE_PATH *PciDevicePath; + + // + // Only build data once + // We have a problem with GetBbsInfo in that it can be invoked two + // places. Once in BDS, when all EFI drivers are connected and once in + // LegacyBoot after all EFI drivers are disconnected causing this routine + // to hang. In LegacyBoot this function is also called before EFI drivers + // are disconnected. + // Cases covered + // GetBbsInfo invoked in BDS. Both invocations in LegacyBoot ignored. + // GetBbsInfo not invoked in BDS. First invocation of this function + // proceeds normally and second via GetBbsInfo ignored. + // + PciDevicePath = NULL; + LocalHddInfo = *HddInfo; + Status = Private->LegacyBiosPlatform->GetPlatformHandle ( + Private->LegacyBiosPlatform, + EfiGetPlatformIdeHandle, + 0, + &HandleBuffer, + &HandleCount, + (VOID *) &LocalHddInfo + ); + if (!EFI_ERROR (Status)) { + IdeController = HandleBuffer[0]; + // + // Force IDE drive spin up! + // + if (Flag != 0) { + gBS->DisconnectController ( + IdeController, + NULL, + NULL + ); + } + + gBS->ConnectController (IdeController, NULL, NULL, FALSE); + + // + // Do GetIdeHandle twice since disconnect/reconnect will switch to native mode + // And GetIdeHandle will switch to Legacy mode, if required. + // + Private->LegacyBiosPlatform->GetPlatformHandle ( + Private->LegacyBiosPlatform, + EfiGetPlatformIdeHandle, + 0, + &HandleBuffer, + &HandleCount, + (VOID *) &LocalHddInfo + ); + } + + mIdeDataBuiltFlag = TRUE; + + // + // Get Identity command from all drives + // + gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiDiskInfoProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + + Private->IdeDriveCount = (UINT8) HandleCount; + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiDiskInfoProtocolGuid, + (VOID **) &DiskInfo + ); + ASSERT_EFI_ERROR (Status); + + if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoIdeInterfaceGuid)) { + // + // Locate which PCI device + // + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiDevicePathProtocolGuid, + (VOID *) &DevicePath + ); + ASSERT_EFI_ERROR (Status); + + DevicePathNode = DevicePath; + while (!IsDevicePathEnd (DevicePathNode)) { + TempDevicePathNode = NextDevicePathNode (DevicePathNode); + if ((DevicePathType (DevicePathNode) == HARDWARE_DEVICE_PATH) && + ( DevicePathSubType (DevicePathNode) == HW_PCI_DP) && + ( DevicePathType(TempDevicePathNode) == MESSAGING_DEVICE_PATH) && + ( DevicePathSubType(TempDevicePathNode) == MSG_ATAPI_DP) ) { + PciDevicePath = (PCI_DEVICE_PATH *) DevicePathNode; + break; + } + DevicePathNode = NextDevicePathNode (DevicePathNode); + } + + if (PciDevicePath == NULL) { + continue; + } + + // + // Find start of PCI device in HddInfo. The assumption of the data + // structure is 2 controllers(channels) per PCI device and each + // controller can have 2 drives(devices). + // HddInfo[PciIndex+0].[0] = Channel[0].Device[0] Primary Master + // HddInfo[PciIndex+0].[1] = Channel[0].Device[1] Primary Slave + // HddInfo[PciIndex+1].[0] = Channel[1].Device[0] Secondary Master + // HddInfo[PciIndex+1].[1] = Channel[1].Device[1] Secondary Slave + // @bug eventually need to pass in max number of entries + // for end of for loop + // + for (PciIndex = 0; PciIndex < 8; PciIndex++) { + if ((PciDevicePath->Device == LocalHddInfo[PciIndex].Device) && + (PciDevicePath->Function == LocalHddInfo[PciIndex].Function) + ) { + break; + } + } + + if (PciIndex == 8) { + continue; + } + + Status = DiskInfo->WhichIde (DiskInfo, &IdeChannel, &IdeDevice); + if (!EFI_ERROR (Status)) { + Size = sizeof (ATAPI_IDENTIFY); + DiskInfo->Identify ( + DiskInfo, + &LocalHddInfo[PciIndex + IdeChannel].IdentifyDrive[IdeDevice], + &Size + ); + if (IdeChannel == 0) { + LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_PRIMARY; + } else if (IdeChannel == 1) { + LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SECONDARY; + } + + InquiryData = NULL; + InquiryDataSize = 0; + Status = DiskInfo->Inquiry ( + DiskInfo, + NULL, + &InquiryDataSize + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + InquiryData = (UINT8 *) AllocatePool ( + InquiryDataSize + ); + if (InquiryData != NULL) { + Status = DiskInfo->Inquiry ( + DiskInfo, + InquiryData, + &InquiryDataSize + ); + } + } else { + Status = EFI_DEVICE_ERROR; + } + + // + // If ATAPI device then Inquiry will pass and ATA fail. + // + if (!EFI_ERROR (Status)) { + ASSERT (InquiryData != NULL); + // + // If IdeDevice = 0 then set master bit, else slave bit + // + if (IdeDevice == 0) { + if ((InquiryData[0] & 0x1f) == 0x05) { + LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_ATAPI_CDROM; + } else if ((InquiryData[0] & 0x1f) == 0x00) { + LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_ATAPI_ZIPDISK; + } + } else { + if ((InquiryData[0] & 0x1f) == 0x05) { + LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_ATAPI_CDROM; + } else if ((InquiryData[0] & 0x1f) == 0x00) { + LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_ATAPI_ZIPDISK; + } + } + FreePool (InquiryData); + } else { + if (IdeDevice == 0) { + LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_IDE; + } else { + LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_IDE; + } + } + } + } + } + + if (HandleBuffer != NULL) { + FreePool (HandleBuffer); + } + + return EFI_SUCCESS; +} + + +/** + If the IDE channel is in compatibility (legacy) mode, remove all + PCI I/O BAR addresses from the controller. + + @param IdeController The handle of target IDE controller + + +**/ +VOID +InitLegacyIdeController ( + IN EFI_HANDLE IdeController + ) +{ + EFI_PCI_IO_PROTOCOL *PciIo; + UINT32 IOBarClear; + EFI_STATUS Status; + PCI_TYPE00 PciData; + + // + // If the IDE channel is in compatibility (legacy) mode, remove all + // PCI I/O BAR addresses from the controller. Some software gets + // confused if an IDE controller is in compatibility (legacy) mode + // and has PCI I/O resources allocated + // + Status = gBS->HandleProtocol ( + IdeController, + &gEfiPciIoProtocolGuid, + (VOID **)&PciIo + ); + if (EFI_ERROR (Status)) { + return ; + } + + Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0, sizeof (PciData), &PciData); + if (EFI_ERROR (Status)) { + return ; + } + + // + // Check whether this is IDE + // + if ((PciData.Hdr.ClassCode[2] != PCI_CLASS_MASS_STORAGE) || + (PciData.Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE)) { + return ; + } + + // + // Clear bar for legacy IDE + // + IOBarClear = 0x00; + if ((PciData.Hdr.ClassCode[0] & IDE_PI_REGISTER_PNE) == 0) { + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x10, 1, &IOBarClear); + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x14, 1, &IOBarClear); + } + if ((PciData.Hdr.ClassCode[0] & IDE_PI_REGISTER_SNE) == 0) { + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x18, 1, &IOBarClear); + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1C, 1, &IOBarClear); + } + + return ; +} diff --git a/OvmfPkg/Csm/LegacyBiosDxe/LegacyPci.c b/OvmfPkg/Csm/LegacyBiosDxe/LegacyPci.c new file mode 100644 index 0000000000..dc1f760876 --- /dev/null +++ b/OvmfPkg/Csm/LegacyBiosDxe/LegacyPci.c @@ -0,0 +1,3083 @@ +/** @file + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "LegacyBiosInterface.h" +#include + +#define PCI_START_ADDRESS(x) (((x) + 0x7ff) & ~0x7ff) + +#define MAX_BRIDGE_INDEX 0x20 +typedef struct { + UINTN PciSegment; + UINTN PciBus; + UINTN PciDevice; + UINTN PciFunction; + UINT8 PrimaryBus; + UINT8 SecondaryBus; + UINT8 SubordinateBus; +} BRIDGE_TABLE; + +#define ROM_MAX_ENTRIES 24 +BRIDGE_TABLE Bridges[MAX_BRIDGE_INDEX]; +UINTN SortedBridgeIndex[MAX_BRIDGE_INDEX]; +UINTN NumberOfBridges; +LEGACY_PNP_EXPANSION_HEADER *mBasePnpPtr; +UINT16 mBbsRomSegment; +UINTN mHandleCount; +EFI_HANDLE mVgaHandle; +BOOLEAN mIgnoreBbsUpdateFlag; +BOOLEAN mVgaInstallationInProgress = FALSE; +UINT32 mRomCount = 0x00; +ROM_INSTANCE_ENTRY mRomEntry[ROM_MAX_ENTRIES]; +EDKII_IOMMU_PROTOCOL *mIoMmu; + +/** + Query shadowed legacy ROM parameters registered by RomShadow() previously. + + @param PciHandle PCI device whos ROM has been shadowed + @param DiskStart DiskStart value from EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom + @param DiskEnd DiskEnd value from EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom + @param RomShadowAddress Address where ROM was shadowed + @param ShadowedSize Runtime size of ROM + + @retval EFI_SUCCESS Query Logging successful. + @retval EFI_NOT_FOUND No logged data found about PciHandle. + +**/ +EFI_STATUS +GetShadowedRomParameters ( + IN EFI_HANDLE PciHandle, + OUT UINT8 *DiskStart, OPTIONAL + OUT UINT8 *DiskEnd, OPTIONAL + OUT VOID **RomShadowAddress, OPTIONAL + OUT UINTN *ShadowedSize OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + UINTN Index; + UINTN PciSegment; + UINTN PciBus; + UINTN PciDevice; + UINTN PciFunction; + + // + // Get the PCI I/O Protocol on PciHandle + // + Status = gBS->HandleProtocol ( + PciHandle, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get the location of the PCI device + // + PciIo->GetLocation ( + PciIo, + &PciSegment, + &PciBus, + &PciDevice, + &PciFunction + ); + + for(Index = 0; Index < mRomCount; Index++) { + if ((mRomEntry[Index].PciSegment == PciSegment) && + (mRomEntry[Index].PciBus == PciBus) && + (mRomEntry[Index].PciDevice == PciDevice) && + (mRomEntry[Index].PciFunction == PciFunction)) { + break; + } + } + + if (Index == mRomCount) { + return EFI_NOT_FOUND; + } + + if (DiskStart != NULL) { + *DiskStart = mRomEntry[Index].DiskStart; + } + + if (DiskEnd != NULL) { + *DiskEnd = mRomEntry[Index].DiskEnd; + } + + if (RomShadowAddress != NULL) { + *RomShadowAddress = (VOID *)(UINTN)mRomEntry[Index].ShadowAddress; + } + + if (ShadowedSize != NULL) { + *ShadowedSize = mRomEntry[Index].ShadowedSize; + } + + return EFI_SUCCESS; +} + +/** + Every legacy ROM that is shadowed by the Legacy BIOS driver will be + registered into this API so that the policy code can know what has + happend + + @param PciHandle PCI device whos ROM is being shadowed + @param ShadowAddress Address that ROM was shadowed + @param ShadowedSize Runtime size of ROM + @param DiskStart DiskStart value from + EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom + @param DiskEnd DiskEnd value from + EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom + + @retval EFI_SUCCESS Logging successful. + @retval EFI_OUT_OF_RESOURCES No remaining room for registering another option + ROM. + +**/ +EFI_STATUS +RomShadow ( + IN EFI_HANDLE PciHandle, + IN UINT32 ShadowAddress, + IN UINT32 ShadowedSize, + IN UINT8 DiskStart, + IN UINT8 DiskEnd + ) +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + + // + // See if there is room to register another option ROM + // + if (mRomCount >= ROM_MAX_ENTRIES) { + return EFI_OUT_OF_RESOURCES; + } + // + // Get the PCI I/O Protocol on PciHandle + // + Status = gBS->HandleProtocol ( + PciHandle, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Get the location of the PCI device + // + PciIo->GetLocation ( + PciIo, + &mRomEntry[mRomCount].PciSegment, + &mRomEntry[mRomCount].PciBus, + &mRomEntry[mRomCount].PciDevice, + &mRomEntry[mRomCount].PciFunction + ); + mRomEntry[mRomCount].ShadowAddress = ShadowAddress; + mRomEntry[mRomCount].ShadowedSize = ShadowedSize; + mRomEntry[mRomCount].DiskStart = DiskStart; + mRomEntry[mRomCount].DiskEnd = DiskEnd; + + mRomCount++; + + return EFI_SUCCESS; +} + + +/** + Return EFI_SUCCESS if PciHandle has had a legacy BIOS ROM shadowed. This + information represents every call to RomShadow () + + @param PciHandle PCI device to get status for + + @retval EFI_SUCCESS Legacy ROM loaded for this device + @retval EFI_NOT_FOUND No Legacy ROM loaded for this device + +**/ +EFI_STATUS +IsLegacyRom ( + IN EFI_HANDLE PciHandle + ) +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + UINTN Index; + UINTN Segment; + UINTN Bus; + UINTN Device; + UINTN Function; + + // + // Get the PCI I/O Protocol on PciHandle + // + Status = gBS->HandleProtocol ( + PciHandle, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Get the location of the PCI device + // + PciIo->GetLocation ( + PciIo, + &Segment, + &Bus, + &Device, + &Function + ); + + // + // See if the option ROM from PciHandle has been previously posted + // + for (Index = 0; Index < mRomCount; Index++) { + if (mRomEntry[Index].PciSegment == Segment && + mRomEntry[Index].PciBus == Bus && + mRomEntry[Index].PciDevice == Device && + mRomEntry[Index].PciFunction == Function + ) { + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +/** + Find the PC-AT ROM Image in the raw PCI Option ROM. Also return the + related information from the header. + + @param Csm16Revision The PCI interface version of underlying CSM16 + @param VendorId Vendor ID of the PCI device + @param DeviceId Device ID of the PCI device + @param Rom On input pointing to beginning of the raw PCI OpROM + On output pointing to the first legacy PCI OpROM + @param ImageSize On input is the size of Raw PCI Rom + On output is the size of the first legacy PCI ROM + @param MaxRuntimeImageLength The max runtime image length only valid if OpRomRevision >= 3 + @param OpRomRevision Revision of the PCI Rom + @param ConfigUtilityCodeHeader Pointer to Configuration Utility Code Header + + @retval EFI_SUCCESS Successfully find the legacy PCI ROM + @retval EFI_NOT_FOUND Failed to find the legacy PCI ROM + +**/ +EFI_STATUS +GetPciLegacyRom ( + IN UINT16 Csm16Revision, + IN UINT16 VendorId, + IN UINT16 DeviceId, + IN OUT VOID **Rom, + IN OUT UINTN *ImageSize, + OUT UINTN *MaxRuntimeImageLength, OPTIONAL + OUT UINT8 *OpRomRevision, OPTIONAL + OUT VOID **ConfigUtilityCodeHeader OPTIONAL + ) +{ + BOOLEAN Match; + UINT16 *DeviceIdList; + EFI_PCI_ROM_HEADER RomHeader; + PCI_3_0_DATA_STRUCTURE *Pcir; + VOID *BackupImage; + VOID *BestImage; + + + if (*ImageSize < sizeof (EFI_PCI_ROM_HEADER)) { + return EFI_NOT_FOUND; + } + + BestImage = NULL; + BackupImage = NULL; + RomHeader.Raw = *Rom; + while (RomHeader.Generic->Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE) { + if (RomHeader.Generic->PcirOffset == 0 || + (RomHeader.Generic->PcirOffset & 3) !=0 || + *ImageSize < RomHeader.Raw - (UINT8 *) *Rom + RomHeader.Generic->PcirOffset + sizeof (PCI_DATA_STRUCTURE)) { + break; + } + + Pcir = (PCI_3_0_DATA_STRUCTURE *) (RomHeader.Raw + RomHeader.Generic->PcirOffset); + // + // Check signature in the PCI Data Structure. + // + if (Pcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) { + break; + } + + if (((UINTN)RomHeader.Raw - (UINTN)*Rom) + Pcir->ImageLength * 512 > *ImageSize) { + break; + } + + if (Pcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) { + Match = FALSE; + if (Pcir->VendorId == VendorId) { + if (Pcir->DeviceId == DeviceId) { + Match = TRUE; + } else if ((Pcir->Revision >= 3) && (Pcir->DeviceListOffset != 0)) { + DeviceIdList = (UINT16 *)(((UINT8 *) Pcir) + Pcir->DeviceListOffset); + // + // Checking the device list + // + while (*DeviceIdList != 0) { + if (*DeviceIdList == DeviceId) { + Match = TRUE; + break; + } + DeviceIdList ++; + } + } + } + + if (Match) { + if (Csm16Revision >= 0x0300) { + // + // Case 1: CSM16 3.0 + // + if (Pcir->Revision >= 3) { + // + // case 1.1: meets OpRom 3.0 + // Perfect!!! + // + BestImage = RomHeader.Raw; + break; + } else { + // + // case 1.2: meets OpRom 2.x + // Store it and try to find the OpRom 3.0 + // + BackupImage = RomHeader.Raw; + } + } else { + // + // Case 2: CSM16 2.x + // + if (Pcir->Revision >= 3) { + // + // case 2.1: meets OpRom 3.0 + // Store it and try to find the OpRom 2.x + // + BackupImage = RomHeader.Raw; + } else { + // + // case 2.2: meets OpRom 2.x + // Perfect!!! + // + BestImage = RomHeader.Raw; + break; + } + } + } else { + DEBUG ((EFI_D_ERROR, "GetPciLegacyRom - OpRom not match (%04x-%04x)\n", (UINTN)VendorId, (UINTN)DeviceId)); + } + } + + if ((Pcir->Indicator & 0x80) == 0x80) { + break; + } else { + RomHeader.Raw += 512 * Pcir->ImageLength; + } + } + + if (BestImage == NULL) { + if (BackupImage == NULL) { + return EFI_NOT_FOUND; + } + // + // The versions of CSM16 and OpRom don't match exactly + // + BestImage = BackupImage; + } + RomHeader.Raw = BestImage; + Pcir = (PCI_3_0_DATA_STRUCTURE *) (RomHeader.Raw + RomHeader.Generic->PcirOffset); + *Rom = BestImage; + *ImageSize = Pcir->ImageLength * 512; + + if (MaxRuntimeImageLength != NULL) { + if (Pcir->Revision < 3) { + *MaxRuntimeImageLength = 0; + } else { + *MaxRuntimeImageLength = Pcir->MaxRuntimeImageLength * 512; + } + } + + if (OpRomRevision != NULL) { + // + // Optional return PCI Data Structure revision + // + if (Pcir->Length >= 0x1C) { + *OpRomRevision = Pcir->Revision; + } else { + *OpRomRevision = 0; + } + } + + if (ConfigUtilityCodeHeader != NULL) { + // + // Optional return ConfigUtilityCodeHeaderOffset supported by the PC-AT ROM + // + if ((Pcir->Revision < 3) || (Pcir->ConfigUtilityCodeHeaderOffset == 0)) { + *ConfigUtilityCodeHeader = NULL; + } else { + *ConfigUtilityCodeHeader = RomHeader.Raw + Pcir->ConfigUtilityCodeHeaderOffset; + } + } + + return EFI_SUCCESS; +} + +/** + Build a table of bridge info for PIRQ translation. + + @param RoutingTable RoutingTable obtained from Platform. + @param RoutingTableEntries Number of RoutingTable entries. + + @retval EFI_SUCCESS New Subordinate bus. + @retval EFI_NOT_FOUND No more Subordinate busses. + +**/ +EFI_STATUS +CreateBridgeTable ( + IN EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable, + IN UINTN RoutingTableEntries + ) +{ + EFI_STATUS Status; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN BridgeIndex; + UINTN Index; + UINTN Index1; + EFI_PCI_IO_PROTOCOL *PciIo; + PCI_TYPE01 PciConfigHeader; + BRIDGE_TABLE SlotBridges[MAX_BRIDGE_INDEX]; + UINTN SlotBridgeIndex; + + BridgeIndex = 0x00; + SlotBridgeIndex = 0x00; + + // + // Assumption is table is built from low bus to high bus numbers. + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiPciIoProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo + ); + if (EFI_ERROR (Status)) { + continue; + } + + PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint32, + 0, + sizeof (PciConfigHeader) / sizeof (UINT32), + &PciConfigHeader + ); + + if (IS_PCI_P2P (&PciConfigHeader) && (BridgeIndex < MAX_BRIDGE_INDEX)) { + PciIo->GetLocation ( + PciIo, + &Bridges[BridgeIndex].PciSegment, + &Bridges[BridgeIndex].PciBus, + &Bridges[BridgeIndex].PciDevice, + &Bridges[BridgeIndex].PciFunction + ); + + Bridges[BridgeIndex].PrimaryBus = PciConfigHeader.Bridge.PrimaryBus; + + Bridges[BridgeIndex].SecondaryBus = PciConfigHeader.Bridge.SecondaryBus; + + Bridges[BridgeIndex].SubordinateBus = PciConfigHeader.Bridge.SubordinateBus; + + for (Index1 = 0; Index1 < RoutingTableEntries; Index1++){ + // + // Test whether we have found the Bridge in the slot, must be the one that directly interfaced to the board + // Once we find one, store it in the SlotBridges[] + // + if ((RoutingTable[Index1].Slot != 0) && (Bridges[BridgeIndex].PrimaryBus == RoutingTable[Index1].Bus) + && ((Bridges[BridgeIndex].PciDevice << 3) == RoutingTable[Index1].Device)) { + CopyMem (&SlotBridges[SlotBridgeIndex], &Bridges[BridgeIndex], sizeof (BRIDGE_TABLE)); + SlotBridgeIndex++; + + break; + } + } + + ++BridgeIndex; + } + } + + // + // Pack up Bridges by removing those useless ones + // + for (Index = 0; Index < BridgeIndex;){ + for (Index1 = 0; Index1 < SlotBridgeIndex; Index1++) { + if (((Bridges[Index].PciBus == SlotBridges[Index1].PrimaryBus) && (Bridges[Index].PciDevice == SlotBridges[Index1].PciDevice)) || + ((Bridges[Index].PciBus >= SlotBridges[Index1].SecondaryBus) && (Bridges[Index].PciBus <= SlotBridges[Index1].SubordinateBus))) { + // + // We have found one that meets our criteria + // + Index++; + break; + } + } + + // + // This one doesn't meet criteria, pack it + // + if (Index1 >= SlotBridgeIndex) { + for (Index1 = Index; BridgeIndex > 1 && Index1 < BridgeIndex - 1 ; Index1++) { + CopyMem (&Bridges[Index1], &Bridges[Index1 + 1], sizeof (BRIDGE_TABLE)); + } + + BridgeIndex--; + } + } + + NumberOfBridges = BridgeIndex; + + // + // Sort bridges low to high by Secondary bus followed by subordinate bus + // + if (NumberOfBridges > 1) { + Index = 0; + do { + SortedBridgeIndex[Index] = Index; + ++Index; + } while (Index < NumberOfBridges); + + for (Index = 0; Index < NumberOfBridges - 1; Index++) { + for (Index1 = Index + 1; Index1 < NumberOfBridges; Index1++) { + if (Bridges[Index].SecondaryBus > Bridges[Index1].SecondaryBus) { + SortedBridgeIndex[Index] = Index1; + SortedBridgeIndex[Index1] = Index; + } + + if ((Bridges[Index].SecondaryBus == Bridges[Index1].SecondaryBus) && + (Bridges[Index].SubordinateBus > Bridges[Index1].SubordinateBus) + ) { + SortedBridgeIndex[Index] = Index1; + SortedBridgeIndex[Index1] = Index; + } + } + } + } + FreePool (HandleBuffer); + return EFI_SUCCESS; +} + + +/** + Find base Bridge for device. + + @param Private Legacy BIOS Instance data + @param PciBus Input = Bus of device. + @param PciDevice Input = Device. + @param RoutingTable The platform specific routing table + @param RoutingTableEntries Number of entries in table + + @retval EFI_SUCCESS At base bus. + @retval EFI_NOT_FOUND Behind a bridge. + +**/ +EFI_STATUS +GetBaseBus ( + IN LEGACY_BIOS_INSTANCE *Private, + IN UINTN PciBus, + IN UINTN PciDevice, + IN EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable, + IN UINTN RoutingTableEntries + ) +{ + UINTN Index; + for (Index = 0; Index < RoutingTableEntries; Index++) { + if ((RoutingTable[Index].Bus == PciBus) && (RoutingTable[Index].Device == (PciDevice << 3))) { + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +/** + Translate PIRQ through busses + + @param Private Legacy BIOS Instance data + @param PciBus Input = Bus of device. Output = Translated Bus + @param PciDevice Input = Device. Output = Translated Device + @param PciFunction Input = Function. Output = Translated Function + @param PirqIndex Input = Original PIRQ index. If single function + device then 0, otherwise 0-3. + Output = Translated Index + + @retval EFI_SUCCESS Pirq successfully translated. + @retval EFI_NOT_FOUND The device is not behind any known bridge. + +**/ +EFI_STATUS +TranslateBusPirq ( + IN LEGACY_BIOS_INSTANCE *Private, + IN OUT UINTN *PciBus, + IN OUT UINTN *PciDevice, + IN OUT UINTN *PciFunction, + IN OUT UINT8 *PirqIndex + ) +{ + /* + This routine traverses the PCI busses from base slot + and translates the PIRQ register to the appropriate one. + + Example: + + Bus 0, Device 1 is PCI-PCI bridge that all PCI slots reside on. + Primary bus# = 0 + Secondary bus # = 1 + Subordinate bus # is highest bus # behind this bus + Bus 1, Device 0 is Slot 0 and is not a bridge. + Bus 1, Device 1 is Slot 1 and is a bridge. + Slot PIRQ routing is A,B,C,D. + Primary bus # = 1 + Secondary bus # = 2 + Subordinate bus # = 5 + Bus 2, Device 6 is a bridge. It has no bridges behind it. + Primary bus # = 2 + Secondary bus # = 3 + Subordinate bus # = 3 + Bridge PIRQ routing is C,D,A,B + Bus 2, Device 7 is a bridge. It has 1 bridge behind it. + Primary bus # = 2 + Secondary bus = 4 Device 6 takes bus 2. + Subordinate bus = 5. + Bridge PIRQ routing is D,A,B,C + Bus 4, Device 2 is a bridge. It has no bridges behind it. + Primary bus # = 4 + Secondary bus # = 5 + Subordinate bus = 5 + Bridge PIRQ routing is B,C,D,A + Bus 5, Device 1 is to be programmed. + Device PIRQ routing is C,D,A,B + + +Search busses starting from slot bus for final bus >= Secondary bus and +final bus <= Suborninate bus. Assumption is bus entries increase in bus +number. +Starting PIRQ is A,B,C,D. +Bus 2, Device 7 satisfies search criteria. Rotate (A,B,C,D) left by device + 7 modulo 4 giving (D,A,B,C). +Bus 4, Device 2 satisfies search criteria. Rotate (D,A,B,C) left by 2 giving + (B,C,D,A). +No other busses match criteria. Device to be programmed is Bus 5, Device 1. +Rotate (B,C,D,A) by 1 giving C,D,A,B. Translated PIRQ is C. + +*/ + UINTN LocalBus; + UINTN LocalDevice; + UINTN BaseBus; + UINTN BaseDevice; + UINTN BaseFunction; + UINT8 LocalPirqIndex; + BOOLEAN BaseIndexFlag; + UINTN BridgeIndex; + UINTN SBridgeIndex; + BaseIndexFlag = FALSE; + BridgeIndex = 0x00; + + LocalPirqIndex = *PirqIndex; + LocalBus = *PciBus; + LocalDevice = *PciDevice; + BaseBus = *PciBus; + BaseDevice = *PciDevice; + BaseFunction = *PciFunction; + + // + // LocalPirqIndex list PIRQs in rotated fashion + // = 0 A,B,C,D + // = 1 B,C,D,A + // = 2 C,D,A,B + // = 3 D,A,B,C + // + + for (BridgeIndex = 0; BridgeIndex < NumberOfBridges; BridgeIndex++) { + SBridgeIndex = SortedBridgeIndex[BridgeIndex]; + // + // Check if device behind this bridge + // + if ((LocalBus >= Bridges[SBridgeIndex].SecondaryBus) && (LocalBus <= Bridges[SBridgeIndex].SubordinateBus)) { + // + // If BaseIndexFlag = FALSE then have found base bridge, i.e + // bridge in slot. Save info for use by IRQ routing table. + // + if (!BaseIndexFlag) { + BaseBus = Bridges[SBridgeIndex].PciBus; + BaseDevice = Bridges[SBridgeIndex].PciDevice; + BaseFunction = Bridges[SBridgeIndex].PciFunction; + BaseIndexFlag = TRUE; + } else { + LocalPirqIndex = (UINT8) ((LocalPirqIndex + (UINT8)Bridges[SBridgeIndex].PciDevice)%4); + } + + // + // Check if at device. If not get new PCI location & PIRQ + // + if (Bridges[SBridgeIndex].SecondaryBus == (UINT8) LocalBus) { + // + // Translate PIRQ + // + LocalPirqIndex = (UINT8) ((LocalPirqIndex + (UINT8) (LocalDevice)) % 4); + break; + } + } + } + + // + // In case we fail to find the Bridge just above us, this is some potential error and we want to warn the user + // + if(BridgeIndex >= NumberOfBridges){ + DEBUG ((EFI_D_ERROR, "Cannot Find IRQ Routing for Bus %d, Device %d, Function %d\n", *PciBus, *PciDevice, *PciFunction)); + } + + *PirqIndex = LocalPirqIndex; + *PciBus = BaseBus; + *PciDevice = BaseDevice; + *PciFunction = BaseFunction; + + return EFI_SUCCESS; +} + + +/** + Copy the $PIR table as required. + + @param Private Legacy BIOS Instance data + @param RoutingTable Pointer to IRQ routing table + @param RoutingTableEntries IRQ routing table entries + @param PirqTable Pointer to $PIR table + @param PirqTableSize Length of table + +**/ +VOID +CopyPirqTable ( + IN LEGACY_BIOS_INSTANCE *Private, + IN EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable, + IN UINTN RoutingTableEntries, + IN EFI_LEGACY_PIRQ_TABLE_HEADER *PirqTable, + IN UINTN PirqTableSize + ) +{ + EFI_IA32_REGISTER_SET Regs; + UINT32 Granularity; + + // + // Copy $PIR table, if it exists. + // + if (PirqTable != NULL) { + Private->LegacyRegion->UnLock ( + Private->LegacyRegion, + 0xE0000, + 0x20000, + &Granularity + ); + + Private->InternalIrqRoutingTable = RoutingTable; + Private->NumberIrqRoutingEntries = (UINT16) (RoutingTableEntries); + ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET)); + + Regs.X.AX = Legacy16GetTableAddress; + Regs.X.CX = (UINT16) PirqTableSize; + // + // Allocate at F segment according to PCI IRQ Routing Table Specification + // + Regs.X.BX = (UINT16) 0x1; + // + // 16-byte boundary alignment requirement according to + // PCI IRQ Routing Table Specification + // + Regs.X.DX = 0x10; + Private->LegacyBios.FarCall86 ( + &Private->LegacyBios, + Private->Legacy16CallSegment, + Private->Legacy16CallOffset, + &Regs, + NULL, + 0 + ); + + Private->Legacy16Table->IrqRoutingTablePointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX); + if (Regs.X.AX != 0) { + DEBUG ((EFI_D_ERROR, "PIRQ table length insufficient - %x\n", PirqTableSize)); + } else { + DEBUG ((EFI_D_INFO, "PIRQ table in legacy region - %x\n", Private->Legacy16Table->IrqRoutingTablePointer)); + Private->Legacy16Table->IrqRoutingTableLength = (UINT32)PirqTableSize; + CopyMem ( + (VOID *) (UINTN)Private->Legacy16Table->IrqRoutingTablePointer, + PirqTable, + PirqTableSize + ); + } + + Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate); + Private->LegacyRegion->Lock ( + Private->LegacyRegion, + 0xE0000, + 0x20000, + &Granularity + ); + } + + Private->PciInterruptLine = TRUE; + mHandleCount = 0; +} + +/** + Dump EFI_LEGACY_INSTALL_PCI_HANDLER structure information. + + @param PciHandle The pointer to EFI_LEGACY_INSTALL_PCI_HANDLER structure + +**/ +VOID +DumpPciHandle ( + IN EFI_LEGACY_INSTALL_PCI_HANDLER *PciHandle + ) +{ + DEBUG ((EFI_D_INFO, "PciBus - %02x\n", (UINTN)PciHandle->PciBus)); + DEBUG ((EFI_D_INFO, "PciDeviceFun - %02x\n", (UINTN)PciHandle->PciDeviceFun)); + DEBUG ((EFI_D_INFO, "PciSegment - %02x\n", (UINTN)PciHandle->PciSegment)); + DEBUG ((EFI_D_INFO, "PciClass - %02x\n", (UINTN)PciHandle->PciClass)); + DEBUG ((EFI_D_INFO, "PciSubclass - %02x\n", (UINTN)PciHandle->PciSubclass)); + DEBUG ((EFI_D_INFO, "PciInterface - %02x\n", (UINTN)PciHandle->PciInterface)); + + DEBUG ((EFI_D_INFO, "PrimaryIrq - %02x\n", (UINTN)PciHandle->PrimaryIrq)); + DEBUG ((EFI_D_INFO, "PrimaryReserved - %02x\n", (UINTN)PciHandle->PrimaryReserved)); + DEBUG ((EFI_D_INFO, "PrimaryControl - %04x\n", (UINTN)PciHandle->PrimaryControl)); + DEBUG ((EFI_D_INFO, "PrimaryBase - %04x\n", (UINTN)PciHandle->PrimaryBase)); + DEBUG ((EFI_D_INFO, "PrimaryBusMaster - %04x\n", (UINTN)PciHandle->PrimaryBusMaster)); + + DEBUG ((EFI_D_INFO, "SecondaryIrq - %02x\n", (UINTN)PciHandle->SecondaryIrq)); + DEBUG ((EFI_D_INFO, "SecondaryReserved - %02x\n", (UINTN)PciHandle->SecondaryReserved)); + DEBUG ((EFI_D_INFO, "SecondaryControl - %04x\n", (UINTN)PciHandle->SecondaryControl)); + DEBUG ((EFI_D_INFO, "SecondaryBase - %04x\n", (UINTN)PciHandle->SecondaryBase)); + DEBUG ((EFI_D_INFO, "SecondaryBusMaster - %04x\n", (UINTN)PciHandle->SecondaryBusMaster)); + return; +} + +/** + Copy the $PIR table as required. + + @param Private Legacy BIOS Instance data + @param PciIo Pointer to PCI_IO protocol + @param PciIrq Pci IRQ number + @param PciConfigHeader Type00 Pci configuration header + +**/ +VOID +InstallLegacyIrqHandler ( + IN LEGACY_BIOS_INSTANCE *Private, + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN UINT8 PciIrq, + IN PCI_TYPE00 *PciConfigHeader + ) +{ + EFI_IA32_REGISTER_SET Regs; + UINT16 LegMask; + UINTN PciSegment; + UINTN PciBus; + UINTN PciDevice; + UINTN PciFunction; + EFI_LEGACY_8259_PROTOCOL *Legacy8259; + UINT16 PrimaryMaster; + UINT16 SecondaryMaster; + UINTN TempData; + UINTN RegisterAddress; + UINT32 Granularity; + + PrimaryMaster = 0; + SecondaryMaster = 0; + Legacy8259 = Private->Legacy8259; + // + // Disable interrupt in PIC, in case shared, to prevent an + // interrupt from occuring. + // + Legacy8259->GetMask ( + Legacy8259, + &LegMask, + NULL, + NULL, + NULL + ); + + LegMask = (UINT16) (LegMask | (UINT16) (1 << PciIrq)); + + Legacy8259->SetMask ( + Legacy8259, + &LegMask, + NULL, + NULL, + NULL + ); + + PciIo->GetLocation ( + PciIo, + &PciSegment, + &PciBus, + &PciDevice, + &PciFunction + ); + Private->IntThunk->PciHandler.PciBus = (UINT8) PciBus; + Private->IntThunk->PciHandler.PciDeviceFun = (UINT8) ((PciDevice << 3) + PciFunction); + Private->IntThunk->PciHandler.PciSegment = (UINT8) PciSegment; + Private->IntThunk->PciHandler.PciClass = PciConfigHeader->Hdr.ClassCode[2]; + Private->IntThunk->PciHandler.PciSubclass = PciConfigHeader->Hdr.ClassCode[1]; + Private->IntThunk->PciHandler.PciInterface = PciConfigHeader->Hdr.ClassCode[0]; + + // + // Use native mode base address registers in two cases: + // 1. Programming Interface (PI) register indicates Primary Controller is + // in native mode OR + // 2. PCI device Sub Class Code is not IDE + // + Private->IntThunk->PciHandler.PrimaryBusMaster = (UINT16)(PciConfigHeader->Device.Bar[4] & 0xfffc); + if (((PciConfigHeader->Hdr.ClassCode[0] & 0x01) != 0) || (PciConfigHeader->Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE)) { + Private->IntThunk->PciHandler.PrimaryIrq = PciIrq; + Private->IntThunk->PciHandler.PrimaryBase = (UINT16) (PciConfigHeader->Device.Bar[0] & 0xfffc); + Private->IntThunk->PciHandler.PrimaryControl = (UINT16) ((PciConfigHeader->Device.Bar[1] & 0xfffc) + 2); + } else { + Private->IntThunk->PciHandler.PrimaryIrq = 14; + Private->IntThunk->PciHandler.PrimaryBase = 0x1f0; + Private->IntThunk->PciHandler.PrimaryControl = 0x3f6; + } + // + // Secondary controller data + // + if (Private->IntThunk->PciHandler.PrimaryBusMaster != 0) { + Private->IntThunk->PciHandler.SecondaryBusMaster = (UINT16) ((PciConfigHeader->Device.Bar[4] & 0xfffc) + 8); + PrimaryMaster = (UINT16) (Private->IntThunk->PciHandler.PrimaryBusMaster + 2); + SecondaryMaster = (UINT16) (Private->IntThunk->PciHandler.SecondaryBusMaster + 2); + + // + // Clear pending interrupts in Bus Master registers + // + IoWrite16 (PrimaryMaster, 0x04); + IoWrite16 (SecondaryMaster, 0x04); + + } + + // + // Use native mode base address registers in two cases: + // 1. Programming Interface (PI) register indicates Secondary Controller is + // in native mode OR + // 2. PCI device Sub Class Code is not IDE + // + if (((PciConfigHeader->Hdr.ClassCode[0] & 0x04) != 0) || (PciConfigHeader->Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE)) { + Private->IntThunk->PciHandler.SecondaryIrq = PciIrq; + Private->IntThunk->PciHandler.SecondaryBase = (UINT16) (PciConfigHeader->Device.Bar[2] & 0xfffc); + Private->IntThunk->PciHandler.SecondaryControl = (UINT16) ((PciConfigHeader->Device.Bar[3] & 0xfffc) + 2); + } else { + + Private->IntThunk->PciHandler.SecondaryIrq = 15; + Private->IntThunk->PciHandler.SecondaryBase = 0x170; + Private->IntThunk->PciHandler.SecondaryControl = 0x376; + } + + // + // Clear pending interrupts in IDE Command Block Status reg before we + // Thunk to CSM16 below. Don't want a pending Interrupt before we + // install the handlers as wierd corruption would occur and hang system. + // + // + // Read IDE CMD blk status reg to clear out any pending interrupts. + // Do here for Primary and Secondary IDE channels + // + RegisterAddress = (UINT16)Private->IntThunk->PciHandler.PrimaryBase + 0x07; + IoRead8 (RegisterAddress); + RegisterAddress = (UINT16)Private->IntThunk->PciHandler.SecondaryBase + 0x07; + IoRead8 (RegisterAddress); + + Private->IntThunk->PciHandler.PrimaryReserved = 0; + Private->IntThunk->PciHandler.SecondaryReserved = 0; + Private->LegacyRegion->UnLock ( + Private->LegacyRegion, + 0xE0000, + 0x20000, + &Granularity + ); + + Regs.X.AX = Legacy16InstallPciHandler; + TempData = (UINTN) &Private->IntThunk->PciHandler; + Regs.X.ES = EFI_SEGMENT ((UINT32) TempData); + Regs.X.BX = EFI_OFFSET ((UINT32) TempData); + + DumpPciHandle (&Private->IntThunk->PciHandler); + + Private->LegacyBios.FarCall86 ( + &Private->LegacyBios, + Private->Legacy16CallSegment, + Private->Legacy16CallOffset, + &Regs, + NULL, + 0 + ); + + Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate); + Private->LegacyRegion->Lock ( + Private->LegacyRegion, + 0xE0000, + 0x20000, + &Granularity + ); + +} + + +/** + Program the interrupt routing register in all the PCI devices. On a PC AT system + this register contains the 8259 IRQ vector that matches it's PCI interrupt. + + @param Private Legacy BIOS Instance data + + @retval EFI_SUCCESS Succeed. + @retval EFI_ALREADY_STARTED All PCI devices have been processed. + +**/ +EFI_STATUS +PciProgramAllInterruptLineRegisters ( + IN LEGACY_BIOS_INSTANCE *Private + ) +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + EFI_LEGACY_8259_PROTOCOL *Legacy8259; + EFI_LEGACY_INTERRUPT_PROTOCOL *LegacyInterrupt; + EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform; + UINT8 InterruptPin; + UINTN Index; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN MassStorageHandleCount; + EFI_HANDLE *MassStorageHandleBuffer; + UINTN MassStorageHandleIndex; + UINT8 PciIrq; + UINT16 Command; + UINTN PciSegment; + UINTN PciBus; + UINTN PciDevice; + UINTN PciFunction; + EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable; + UINTN RoutingTableEntries; + UINT16 LegMask; + UINT16 LegEdgeLevel; + PCI_TYPE00 PciConfigHeader; + EFI_LEGACY_PIRQ_TABLE_HEADER *PirqTable; + UINTN PirqTableSize; + UINTN Flags; + HDD_INFO *HddInfo; + UINT64 Supports; + + // + // Note - This routine use to return immediately if Private->PciInterruptLine + // was true. Routine changed since resets etc can cause not all + // PciIo protocols to be registered the first time through. + // New algorithm is to do the copy $PIR table on first pass and save + // HandleCount on first pass. If subsequent passes LocateHandleBuffer gives + // a larger handle count then proceed with body of function else return + // EFI_ALREADY_STARTED. In addition check if PCI device InterruptLine != 0. + // If zero then function unprogrammed else skip function. + // + Legacy8259 = Private->Legacy8259; + LegacyInterrupt = Private->LegacyInterrupt; + LegacyBiosPlatform = Private->LegacyBiosPlatform; + + LegacyBiosPlatform->GetRoutingTable ( + Private->LegacyBiosPlatform, + (VOID *) &RoutingTable, + &RoutingTableEntries, + (VOID *) &PirqTable, + &PirqTableSize, + NULL, + NULL + ); + CreateBridgeTable (RoutingTable, RoutingTableEntries); + + if (!Private->PciInterruptLine) { + CopyPirqTable ( + Private, + RoutingTable, + RoutingTableEntries, + PirqTable, + PirqTableSize + ); + } + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiPciIoProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + if (HandleCount == mHandleCount) { + FreePool (HandleBuffer); + return EFI_ALREADY_STARTED; + } + + if (mHandleCount == 0x00) { + mHandleCount = HandleCount; + } + + for (Index = 0; Index < HandleCount; Index++) { + // + // If VGA then only do VGA to allow drives fore time to spin up + // otherwise assign PCI IRQs to all potential devices. + // + if ((mVgaInstallationInProgress) && (HandleBuffer[Index] != mVgaHandle)) { + continue; + } else { + // + // Force code to go through all handles next time called if video. + // This will catch case where HandleCount doesn't change but want + // to get drive info etc. + // + mHandleCount = 0x00; + } + + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo + ); + ASSERT_EFI_ERROR (Status); + + // + // Test whether the device can be enabled or not. + // If it can't be enabled, then just skip it to avoid further operation. + // + PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint32, + 0, + sizeof (PciConfigHeader) / sizeof (UINT32), + &PciConfigHeader + ); + Command = PciConfigHeader.Hdr.Command; + + // + // Note PciIo->Attributes does not program the PCI command register + // + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationSupported, + 0, + &Supports + ); + if (!EFI_ERROR (Status)) { + Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE; + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationEnable, + Supports, + NULL + ); + } + PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x04, 1, &Command); + + if (EFI_ERROR (Status)) { + continue; + } + + InterruptPin = PciConfigHeader.Device.InterruptPin; + + if ((InterruptPin != 0) && (PciConfigHeader.Device.InterruptLine == PCI_INT_LINE_UNKNOWN)) { + PciIo->GetLocation ( + PciIo, + &PciSegment, + &PciBus, + &PciDevice, + &PciFunction + ); + // + // Translate PIRQ index back thru busses to slot bus with InterruptPin + // zero based + // + InterruptPin -= 1; + + Status = GetBaseBus ( + Private, + PciBus, + PciDevice, + RoutingTable, + RoutingTableEntries + ); + + if (Status == EFI_NOT_FOUND) { + TranslateBusPirq ( + Private, + &PciBus, + &PciDevice, + &PciFunction, + &InterruptPin + ); + } + // + // Translate InterruptPin(0-3) into PIRQ + // + Status = LegacyBiosPlatform->TranslatePirq ( + LegacyBiosPlatform, + PciBus, + (PciDevice << 3), + PciFunction, + &InterruptPin, + &PciIrq + ); + // + // TranslatePirq() should never fail or we are in trouble + // If it does return failure status, check your PIRQ routing table to see if some item is missing or incorrect + // + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Translate Pirq Failed - Status = %r\n ", Status)); + continue; + } + + LegacyInterrupt->WritePirq ( + LegacyInterrupt, + InterruptPin, + PciIrq + ); + + // + // Check if device has an OPROM associated with it. + // If not invoke special 16-bit function, to allow 16-bit + // code to install an interrupt handler. + // + Status = LegacyBiosCheckPciRom ( + &Private->LegacyBios, + HandleBuffer[Index], + NULL, + NULL, + &Flags + ); + if ((EFI_ERROR (Status)) && (PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_MASS_STORAGE)) { + // + // Device has no OPROM associated with it and is a mass storage + // device. It needs to have an PCI IRQ handler installed. To + // correctly install the handler we need to insure device is + // connected. The device may just have register itself but not + // been connected. Re-read PCI config space after as it can + // change + // + // + // Get IDE Handle. If matches handle then skip ConnectController + // since ConnectController may force native mode and we don't + // want that for primary IDE controller + // + MassStorageHandleCount = 0; + MassStorageHandleBuffer = NULL; + LegacyBiosPlatform->GetPlatformHandle ( + Private->LegacyBiosPlatform, + EfiGetPlatformIdeHandle, + 0, + &MassStorageHandleBuffer, + &MassStorageHandleCount, + NULL + ); + + HddInfo = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo[0]; + + LegacyBiosBuildIdeData (Private, &HddInfo, 0); + PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint32, + 0, + sizeof (PciConfigHeader) / sizeof (UINT32), + &PciConfigHeader + ); + + for (MassStorageHandleIndex = 0; MassStorageHandleIndex < MassStorageHandleCount; MassStorageHandleIndex++) { + if (MassStorageHandleBuffer[MassStorageHandleIndex] == HandleBuffer[Index]) { + // + // InstallLegacyIrqHandler according to Platform requirement + // + InstallLegacyIrqHandler ( + Private, + PciIo, + PciIrq, + &PciConfigHeader + ); + break; + } + } + } + // + // Write InterruptPin and enable 8259. + // + PciIo->Pci.Write ( + PciIo, + EfiPciIoWidthUint8, + 0x3c, + 1, + &PciIrq + ); + Private->IntThunk->EfiToLegacy16BootTable.PciIrqMask = (UINT16) (Private->IntThunk->EfiToLegacy16BootTable.PciIrqMask | (UINT16) (1 << PciIrq)); + + Legacy8259->GetMask ( + Legacy8259, + &LegMask, + &LegEdgeLevel, + NULL, + NULL + ); + + LegMask = (UINT16) (LegMask & (UINT16)~(1 << PciIrq)); + LegEdgeLevel = (UINT16) (LegEdgeLevel | (UINT16) (1 << PciIrq)); + Legacy8259->SetMask ( + Legacy8259, + &LegMask, + &LegEdgeLevel, + NULL, + NULL + ); + } + } + FreePool (HandleBuffer); + return EFI_SUCCESS; +} + + +/** + Find & verify PnP Expansion header in ROM image + + @param Private Protocol instance pointer. + @param FirstHeader 1 = Find first header, 0 = Find successive headers + @param PnpPtr Input Rom start if FirstHeader =1, Current Header + otherwise Output Next header, if it exists + + @retval EFI_SUCCESS Next Header found at BasePnpPtr + @retval EFI_NOT_FOUND No more headers + +**/ +EFI_STATUS +FindNextPnpExpansionHeader ( + IN LEGACY_BIOS_INSTANCE *Private, + IN BOOLEAN FirstHeader, + IN OUT LEGACY_PNP_EXPANSION_HEADER **PnpPtr + + ) +{ + UINTN TempData; + LEGACY_PNP_EXPANSION_HEADER *LocalPnpPtr; + LocalPnpPtr = *PnpPtr; + if (FirstHeader == FIRST_INSTANCE) { + mBasePnpPtr = LocalPnpPtr; + mBbsRomSegment = (UINT16) ((UINTN) mBasePnpPtr >> 4); + // + // Offset 0x1a gives offset to PnP expansion header for the first + // instance, there after the structure gives the offset to the next + // structure + // + LocalPnpPtr = (LEGACY_PNP_EXPANSION_HEADER *) ((UINT8 *) LocalPnpPtr + 0x1a); + TempData = (*((UINT16 *) LocalPnpPtr)); + } else { + TempData = (UINT16) LocalPnpPtr->NextHeader; + } + + LocalPnpPtr = (LEGACY_PNP_EXPANSION_HEADER *) (((UINT8 *) mBasePnpPtr + TempData)); + + // + // Search for PnP table in Shadowed ROM + // + *PnpPtr = LocalPnpPtr; + if (*(UINT32 *) LocalPnpPtr == SIGNATURE_32 ('$', 'P', 'n', 'P')) { + return EFI_SUCCESS; + } else { + return EFI_NOT_FOUND; + } +} + + +/** + Update list of Bev or BCV table entries. + + @param Private Protocol instance pointer. + @param RomStart Table of ROM start address in RAM/ROM. PciIo _ + Handle to PCI IO for this device + @param PciIo Instance of PCI I/O Protocol + + @retval EFI_SUCCESS Always should succeed. + +**/ +EFI_STATUS +UpdateBevBcvTable ( + IN LEGACY_BIOS_INSTANCE *Private, + IN EFI_LEGACY_EXPANSION_ROM_HEADER *RomStart, + IN EFI_PCI_IO_PROTOCOL *PciIo + ) +{ + VOID *RomEnd; + BBS_TABLE *BbsTable; + UINTN BbsIndex; + EFI_LEGACY_EXPANSION_ROM_HEADER *PciPtr; + LEGACY_PNP_EXPANSION_HEADER *PnpPtr; + BOOLEAN Instance; + EFI_STATUS Status; + UINTN Segment; + UINTN Bus; + UINTN Device; + UINTN Function; + UINT8 Class; + UINT16 DeviceType; + Segment = 0; + Bus = 0; + Device = 0; + Function = 0; + Class = 0; + DeviceType = BBS_UNKNOWN; + + // + // Skip floppy and 2*onboard IDE controller entries(Master/Slave per + // controller). + // + BbsIndex = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries; + + BbsTable = (BBS_TABLE*)(UINTN) Private->IntThunk->EfiToLegacy16BootTable.BbsTable; + PnpPtr = (LEGACY_PNP_EXPANSION_HEADER *) RomStart; + PciPtr = (EFI_LEGACY_EXPANSION_ROM_HEADER *) RomStart; + + RomEnd = (VOID *) (PciPtr->Size512 * 512 + (UINTN) PciPtr); + Instance = FIRST_INSTANCE; + // + // OPROMs like PXE may not be tied to a piece of hardware and thus + // don't have a PciIo associated with them + // + if (PciIo != NULL) { + PciIo->GetLocation ( + PciIo, + &Segment, + &Bus, + &Device, + &Function + ); + PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint8, + 0x0b, + 1, + &Class + ); + + if (Class == PCI_CLASS_MASS_STORAGE) { + DeviceType = BBS_HARDDISK; + } else { + if (Class == PCI_CLASS_NETWORK) { + DeviceType = BBS_EMBED_NETWORK; + } + } + } + + while (TRUE) { + Status = FindNextPnpExpansionHeader (Private, Instance, &PnpPtr); + Instance = NOT_FIRST_INSTANCE; + if (EFI_ERROR (Status)) { + break; + } + // + // There can be additional $PnP headers within the OPROM. + // Example: SCSI can have one per drive. + // + BbsTable[BbsIndex].BootPriority = BBS_UNPRIORITIZED_ENTRY; + BbsTable[BbsIndex].DeviceType = DeviceType; + BbsTable[BbsIndex].Bus = (UINT32) Bus; + BbsTable[BbsIndex].Device = (UINT32) Device; + BbsTable[BbsIndex].Function = (UINT32) Function; + BbsTable[BbsIndex].StatusFlags.OldPosition = 0; + BbsTable[BbsIndex].StatusFlags.Reserved1 = 0; + BbsTable[BbsIndex].StatusFlags.Enabled = 0; + BbsTable[BbsIndex].StatusFlags.Failed = 0; + BbsTable[BbsIndex].StatusFlags.MediaPresent = 0; + BbsTable[BbsIndex].StatusFlags.Reserved2 = 0; + BbsTable[BbsIndex].Class = PnpPtr->Class; + BbsTable[BbsIndex].SubClass = PnpPtr->SubClass; + BbsTable[BbsIndex].DescStringOffset = PnpPtr->ProductNamePointer; + BbsTable[BbsIndex].DescStringSegment = mBbsRomSegment; + BbsTable[BbsIndex].MfgStringOffset = PnpPtr->MfgPointer; + BbsTable[BbsIndex].MfgStringSegment = mBbsRomSegment; + BbsTable[BbsIndex].BootHandlerSegment = mBbsRomSegment; + + // + // Have seen case where PXE base code have PnP expansion ROM + // header but no Bcv or Bev vectors. + // + if (PnpPtr->Bcv != 0) { + BbsTable[BbsIndex].BootHandlerOffset = PnpPtr->Bcv; + ++BbsIndex; + } + + if (PnpPtr->Bev != 0) { + BbsTable[BbsIndex].BootHandlerOffset = PnpPtr->Bev; + BbsTable[BbsIndex].DeviceType = BBS_BEV_DEVICE; + ++BbsIndex; + } + + if ((PnpPtr == (LEGACY_PNP_EXPANSION_HEADER *) PciPtr) || (PnpPtr > (LEGACY_PNP_EXPANSION_HEADER *) RomEnd)) { + break; + } + } + + BbsTable[BbsIndex].BootPriority = BBS_IGNORE_ENTRY; + Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries = (UINT32) BbsIndex; + return EFI_SUCCESS; +} + + +/** + Shadow all the PCI legacy ROMs. Use data from the Legacy BIOS Protocol + to chose the order. Skip any devices that have already have legacy + BIOS run. + + @param Private Protocol instance pointer. + + @retval EFI_SUCCESS Succeed. + @retval EFI_UNSUPPORTED Cannot get VGA device handle. + +**/ +EFI_STATUS +PciShadowRoms ( + IN LEGACY_BIOS_INSTANCE *Private + ) +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + PCI_TYPE00 Pci; + UINTN Index; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + EFI_HANDLE VgaHandle; + EFI_HANDLE FirstHandle; + VOID **RomStart; + UINTN Flags; + PCI_TYPE00 PciConfigHeader; + UINT16 *Command; + UINT64 Supports; + + // + // Make the VGA device first + // + Status = Private->LegacyBiosPlatform->GetPlatformHandle ( + Private->LegacyBiosPlatform, + EfiGetPlatformVgaHandle, + 0, + &HandleBuffer, + &HandleCount, + NULL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + VgaHandle = HandleBuffer[0]; + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiPciIoProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + + if (EFI_ERROR (Status)) { + return Status; + } + // + // Place the VGA handle as first. + // + for (Index = 0; Index < HandleCount; Index++) { + if (HandleBuffer[Index] == VgaHandle) { + FirstHandle = HandleBuffer[0]; + HandleBuffer[0] = HandleBuffer[Index]; + HandleBuffer[Index] = FirstHandle; + break; + } + } + // + // Allocate memory to save Command WORD from each device. We do this + // to restore devices to same state as EFI after switching to legacy. + // + Command = (UINT16 *) AllocatePool ( + sizeof (UINT16) * (HandleCount + 1) + ); + if (NULL == Command) { + FreePool (HandleBuffer); + return EFI_OUT_OF_RESOURCES; + } + // + // Disconnect all EFI devices first. This covers cases where alegacy BIOS + // may control multiple PCI devices. + // + for (Index = 0; Index < HandleCount; Index++) { + + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo + ); + ASSERT_EFI_ERROR (Status); + + // + // Save command register for "connect" loop + // + PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint32, + 0, + sizeof (PciConfigHeader) / sizeof (UINT32), + &PciConfigHeader + ); + Command[Index] = PciConfigHeader.Hdr.Command; + // + // Skip any device that already has a legacy ROM run + // + Status = IsLegacyRom (HandleBuffer[Index]); + if (!EFI_ERROR (Status)) { + continue; + } + // + // Stop EFI Drivers with oprom. + // + gBS->DisconnectController ( + HandleBuffer[Index], + NULL, + NULL + ); + } + // + // For every device that has not had a legacy ROM started. Start a legacy ROM. + // + for (Index = 0; Index < HandleCount; Index++) { + + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo + ); + + ASSERT_EFI_ERROR (Status); + + // + // Here make sure if one VGA have been shadowed, + // then wil not shadowed another one. + // + PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint32, + 0, + sizeof (Pci) / sizeof (UINT32), + &Pci + ); + + // + // Only one Video OPROM can be given control in BIOS phase. If there are multiple Video devices, + // one will work in legacy mode (OPROM will be given control) and + // other Video devices will work in native mode (OS driver will handle these devices). + // + if (IS_PCI_DISPLAY (&Pci) && Index != 0) { + continue; + } + // + // Skip any device that already has a legacy ROM run + // + Status = IsLegacyRom (HandleBuffer[Index]); + if (!EFI_ERROR (Status)) { + continue; + } + + // + // If legacy VBIOS Oprom has not been dispatched before, install legacy VBIOS here. + // + if (IS_PCI_DISPLAY (&Pci) && Index == 0) { + Status = LegacyBiosInstallVgaRom (Private); + // + // A return status of EFI_NOT_FOUND is considered valid (No EFI + // driver is controlling video). + // + ASSERT ((Status == EFI_SUCCESS) || (Status == EFI_NOT_FOUND)); + continue; + } + + // + // Install legacy ROM + // + Status = LegacyBiosInstallPciRom ( + &Private->LegacyBios, + HandleBuffer[Index], + NULL, + &Flags, + NULL, + NULL, + (VOID **) &RomStart, + NULL + ); + if (EFI_ERROR (Status)) { + if (!((Status == EFI_UNSUPPORTED) && (Flags == NO_ROM))) { + continue; + } + } + // + // Restore Command register so legacy has same devices enabled or disabled + // as EFI. + // If Flags = NO_ROM use command register as is. This covers the + // following cases: + // Device has no ROMs associated with it. + // Device has ROM associated with it but was already + // installed. + // = ROM_FOUND but not VALID_LEGACY_ROM, disable it. + // = ROM_FOUND and VALID_LEGACY_ROM, enable it. + // + if ((Flags & ROM_FOUND) == ROM_FOUND) { + if ((Flags & VALID_LEGACY_ROM) == 0) { + Command[Index] = 0; + } else { + // + // For several VGAs, only one of them can be enabled. + // + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationSupported, + 0, + &Supports + ); + if (!EFI_ERROR (Status)) { + Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE; + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationEnable, + Supports, + NULL + ); + } + if (!EFI_ERROR (Status)) { + Command[Index] = 0x1f; + } + } + } + + PciIo->Pci.Write ( + PciIo, + EfiPciIoWidthUint16, + 0x04, + 1, + &Command[Index] + ); + } + + FreePool (Command); + FreePool (HandleBuffer); + return EFI_SUCCESS; +} + + +/** + Test to see if a legacy PCI ROM exists for this device. Optionally return + the Legacy ROM instance for this PCI device. + + @param This Protocol instance pointer. + @param PciHandle The PCI PC-AT OPROM from this devices ROM BAR will + be loaded + @param RomImage Return the legacy PCI ROM for this device + @param RomSize Size of ROM Image + @param Flags Indicates if ROM found and if PC-AT. + + @retval EFI_SUCCESS Legacy Option ROM available for this device + @retval EFI_UNSUPPORTED Legacy Option ROM not supported. + +**/ +EFI_STATUS +EFIAPI +LegacyBiosCheckPciRom ( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN EFI_HANDLE PciHandle, + OUT VOID **RomImage, OPTIONAL + OUT UINTN *RomSize, OPTIONAL + OUT UINTN *Flags + ) +{ + return LegacyBiosCheckPciRomEx ( + This, + PciHandle, + RomImage, + RomSize, + NULL, + Flags, + NULL, + NULL + ); + +} + +/** + + Routine Description: + Test to see if a legacy PCI ROM exists for this device. Optionally return + the Legacy ROM instance for this PCI device. + + @param[in] This Protocol instance pointer. + @param[in] PciHandle The PCI PC-AT OPROM from this devices ROM BAR will be loaded + @param[out] RomImage Return the legacy PCI ROM for this device + @param[out] RomSize Size of ROM Image + @param[out] RuntimeImageLength Runtime size of ROM Image + @param[out] Flags Indicates if ROM found and if PC-AT. + @param[out] OpromRevision Revision of the PCI Rom + @param[out] ConfigUtilityCodeHeaderPointer of Configuration Utility Code Header + + @return EFI_SUCCESS Legacy Option ROM available for this device + @return EFI_ALREADY_STARTED This device is already managed by its Oprom + @return EFI_UNSUPPORTED Legacy Option ROM not supported. + +**/ +EFI_STATUS +LegacyBiosCheckPciRomEx ( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN EFI_HANDLE PciHandle, + OUT VOID **RomImage, OPTIONAL + OUT UINTN *RomSize, OPTIONAL + OUT UINTN *RuntimeImageLength, OPTIONAL + OUT UINTN *Flags, OPTIONAL + OUT UINT8 *OpromRevision, OPTIONAL + OUT VOID **ConfigUtilityCodeHeader OPTIONAL + ) +{ + EFI_STATUS Status; + LEGACY_BIOS_INSTANCE *Private; + EFI_PCI_IO_PROTOCOL *PciIo; + UINTN LocalRomSize; + VOID *LocalRomImage; + PCI_TYPE00 PciConfigHeader; + VOID *LocalConfigUtilityCodeHeader; + + LocalConfigUtilityCodeHeader = NULL; + *Flags = NO_ROM; + Status = gBS->HandleProtocol ( + PciHandle, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + // + // See if the option ROM for PciHandle has already been executed + // + Status = IsLegacyRom (PciHandle); + if (!EFI_ERROR (Status)) { + *Flags |= (UINTN)(ROM_FOUND | VALID_LEGACY_ROM); + return EFI_SUCCESS; + } + // + // Check for PCI ROM Bar + // + LocalRomSize = (UINTN) PciIo->RomSize; + LocalRomImage = PciIo->RomImage; + if (LocalRomSize != 0) { + *Flags |= ROM_FOUND; + } + + // + // PCI specification states you should check VendorId and Device Id. + // + PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint32, + 0, + sizeof (PciConfigHeader) / sizeof (UINT32), + &PciConfigHeader + ); + + Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); + Status = GetPciLegacyRom ( + Private->Csm16PciInterfaceVersion, + PciConfigHeader.Hdr.VendorId, + PciConfigHeader.Hdr.DeviceId, + &LocalRomImage, + &LocalRomSize, + RuntimeImageLength, + OpromRevision, + &LocalConfigUtilityCodeHeader + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + *Flags |= VALID_LEGACY_ROM; + + // + // See if Configuration Utility Code Header valid + // + if (LocalConfigUtilityCodeHeader != NULL) { + *Flags |= ROM_WITH_CONFIG; + } + + if (ConfigUtilityCodeHeader != NULL) { + *ConfigUtilityCodeHeader = LocalConfigUtilityCodeHeader; + } + + if (RomImage != NULL) { + *RomImage = LocalRomImage; + } + + if (RomSize != NULL) { + *RomSize = LocalRomSize; + } + + return EFI_SUCCESS; +} + +/** + Load a legacy PC-AT OPROM on the PciHandle device. Return information + about how many disks were added by the OPROM and the shadow address and + size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C: + + @retval EFI_SUCCESS Legacy ROM loaded for this device + @retval EFI_NOT_FOUND No PS2 Keyboard found + +**/ +EFI_STATUS +EnablePs2Keyboard ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN HandleCount; + EFI_ISA_IO_PROTOCOL *IsaIo; + UINTN Index; + + // + // Get SimpleTextIn and find PS2 controller + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSimpleTextInProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + for (Index = 0; Index < HandleCount; Index++) { + // + // Open the IO Abstraction(s) needed to perform the supported test + // + Status = gBS->OpenProtocol ( + HandleBuffer[Index], + &gEfiIsaIoProtocolGuid, + (VOID **) &IsaIo, + NULL, + HandleBuffer[Index], + EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL + ); + + if (!EFI_ERROR (Status)) { + // + // Use the ISA I/O Protocol to see if Controller is the Keyboard + // controller + // + if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x303) || IsaIo->ResourceList->Device.UID != 0) { + Status = EFI_UNSUPPORTED; + } + + gBS->CloseProtocol ( + HandleBuffer[Index], + &gEfiIsaIoProtocolGuid, + NULL, + HandleBuffer[Index] + ); + } + + if (!EFI_ERROR (Status)) { + gBS->ConnectController (HandleBuffer[Index], NULL, NULL, FALSE); + } + } + FreePool (HandleBuffer); + return EFI_SUCCESS; +} + + +/** + Load a legacy PC-AT OpROM for VGA controller. + + @param Private Driver private data. + + @retval EFI_SUCCESS Legacy ROM successfully installed for this device. + @retval EFI_DEVICE_ERROR No VGA device handle found, or native EFI video + driver cannot be successfully disconnected, or VGA + thunk driver cannot be successfully connected. + +**/ +EFI_STATUS +LegacyBiosInstallVgaRom ( + IN LEGACY_BIOS_INSTANCE *Private + ) +{ + EFI_STATUS Status; + EFI_HANDLE VgaHandle; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + EFI_HANDLE *ConnectHandleBuffer; + EFI_PCI_IO_PROTOCOL *PciIo; + PCI_TYPE00 PciConfigHeader; + UINT64 Supports; + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer; + UINTN EntryCount; + UINTN Index; + VOID *Interface; + + // + // EfiLegacyBiosGuild attached to a device implies that there is a legacy + // BIOS associated with that device. + // + // There are 3 cases to consider. + // Case 1: No EFI driver is controlling the video. + // Action: Return EFI_SUCCESS from DisconnectController, search + // video thunk driver, and connect it. + // Case 2: EFI driver is controlling the video and EfiLegacyBiosGuid is + // not on the image handle. + // Action: Disconnect EFI driver. + // ConnectController for video thunk + // Case 3: EFI driver is controlling the video and EfiLegacyBiosGuid is + // on the image handle. + // Action: Do nothing and set Private->VgaInstalled = TRUE. + // Then this routine is not called any more. + // + // + // Get the VGA device. + // + Status = Private->LegacyBiosPlatform->GetPlatformHandle ( + Private->LegacyBiosPlatform, + EfiGetPlatformVgaHandle, + 0, + &HandleBuffer, + &HandleCount, + NULL + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + VgaHandle = HandleBuffer[0]; + + // + // Check whether video thunk driver already starts. + // + Status = gBS->OpenProtocolInformation ( + VgaHandle, + &gEfiPciIoProtocolGuid, + &OpenInfoBuffer, + &EntryCount + ); + if (EFI_ERROR (Status)) { + return Status; + } + + for (Index = 0; Index < EntryCount; Index++) { + if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) { + Status = gBS->HandleProtocol ( + OpenInfoBuffer[Index].AgentHandle, + &gEfiLegacyBiosGuid, + (VOID **) &Interface + ); + if (!EFI_ERROR (Status)) { + // + // This should be video thunk driver which is managing video device + // So it need not start again + // + DEBUG ((EFI_D_INFO, "Video thunk driver already start! Return!\n")); + Private->VgaInstalled = TRUE; + return EFI_SUCCESS; + } + } + } + + // + // Kick off the native EFI driver + // + Status = gBS->DisconnectController ( + VgaHandle, + NULL, + NULL + ); + if (EFI_ERROR (Status)) { + if (Status != EFI_NOT_FOUND) { + return EFI_DEVICE_ERROR; + } else { + return Status; + } + } + // + // Find all the Thunk Driver + // + HandleBuffer = NULL; + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiLegacyBiosGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + ASSERT_EFI_ERROR (Status); + ConnectHandleBuffer = (EFI_HANDLE *) AllocatePool (sizeof (EFI_HANDLE) * (HandleCount + 1)); + ASSERT (ConnectHandleBuffer != NULL); + + CopyMem ( + ConnectHandleBuffer, + HandleBuffer, + sizeof (EFI_HANDLE) * HandleCount + ); + ConnectHandleBuffer[HandleCount] = NULL; + + FreePool (HandleBuffer); + + // + // Enable the device and make sure VGA cycles are being forwarded to this VGA device + // + Status = gBS->HandleProtocol ( + VgaHandle, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo + ); + ASSERT_EFI_ERROR (Status); + PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint32, + 0, + sizeof (PciConfigHeader) / sizeof (UINT32), + &PciConfigHeader + ); + + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationSupported, + 0, + &Supports + ); + if (!EFI_ERROR (Status)) { + Supports &= (UINT64)(EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | \ + EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16); + Status = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationEnable, + Supports, + NULL + ); + } + + if (Status == EFI_SUCCESS) { + Private->VgaInstalled = TRUE; + + // + // Attach the VGA thunk driver. + // Assume the video is installed. This prevents potential of infinite recursion. + // + Status = gBS->ConnectController ( + VgaHandle, + ConnectHandleBuffer, + NULL, + TRUE + ); + } + + FreePool (ConnectHandleBuffer); + + if (EFI_ERROR (Status)) { + + Private->VgaInstalled = FALSE; + + // + // Reconnect the EFI VGA driver. + // + gBS->ConnectController (VgaHandle, NULL, NULL, TRUE); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + + +/** + Load a legacy PC-AT OpROM. + + @param This Protocol instance pointer. + @param Private Driver's private data. + @param PciHandle The EFI handle for the PCI device. It could be + NULL if the OpROM image is not associated with + any device. + @param OpromRevision The revision of PCI PC-AT ROM image. + @param RomImage Pointer to PCI PC-AT ROM image header. It must not + be NULL. + @param ImageSize Size of the PCI PC-AT ROM image. + @param RuntimeImageLength On input is the max runtime image length indicated by the PCIR structure + On output is the actual runtime image length + @param DiskStart Disk number of first device hooked by the ROM. If + DiskStart is the same as DiskEnd no disked were + hooked. + @param DiskEnd Disk number of the last device hooked by the ROM. + @param RomShadowAddress Shadow address of PC-AT ROM + + @retval EFI_SUCCESS Legacy ROM loaded for this device + @retval EFI_OUT_OF_RESOURCES No more space for this ROM + +**/ +EFI_STATUS +EFIAPI +LegacyBiosInstallRom ( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN LEGACY_BIOS_INSTANCE *Private, + IN EFI_HANDLE PciHandle, + IN UINT8 OpromRevision, + IN VOID *RomImage, + IN UINTN ImageSize, + IN OUT UINTN *RuntimeImageLength, + OUT UINT8 *DiskStart, OPTIONAL + OUT UINT8 *DiskEnd, OPTIONAL + OUT VOID **RomShadowAddress OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_STATUS PciEnableStatus; + EFI_PCI_IO_PROTOCOL *PciIo; + UINT8 LocalDiskStart; + UINT8 LocalDiskEnd; + UINTN Segment; + UINTN Bus; + UINTN Device; + UINTN Function; + EFI_IA32_REGISTER_SET Regs; + UINT8 VideoMode; + UINT8 OldVideoMode; + EFI_TIME BootTime; + UINT32 *BdaPtr; + UINT32 LocalTime; + UINT32 StartBbsIndex; + UINT32 EndBbsIndex; + UINT32 MaxRomAddr; + UINTN TempData; + UINTN InitAddress; + UINTN RuntimeAddress; + EFI_PHYSICAL_ADDRESS PhysicalAddress; + UINT32 Granularity; + + PciIo = NULL; + LocalDiskStart = 0; + LocalDiskEnd = 0; + Segment = 0; + Bus = 0; + Device = 0; + Function = 0; + VideoMode = 0; + OldVideoMode = 0; + PhysicalAddress = 0; + MaxRomAddr = PcdGet32 (PcdEndOpromShadowAddress); + + if ((Private->Legacy16Table->TableLength >= OFFSET_OF(EFI_COMPATIBILITY16_TABLE, HiPermanentMemoryAddress)) && + (Private->Legacy16Table->UmaAddress != 0) && + (Private->Legacy16Table->UmaSize != 0) && + (MaxRomAddr > (Private->Legacy16Table->UmaAddress))) { + MaxRomAddr = Private->Legacy16Table->UmaAddress; + } + + + PciProgramAllInterruptLineRegisters (Private); + + if ((OpromRevision >= 3) && (Private->Csm16PciInterfaceVersion >= 0x0300)) { + // + // CSM16 3.0 meets PCI 3.0 OpROM + // first test if there is enough space for its INIT code + // + PhysicalAddress = CONVENTIONAL_MEMORY_TOP; + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiBootServicesCode, + EFI_SIZE_TO_PAGES (ImageSize), + &PhysicalAddress + ); + + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__)); + // + // Report Status Code to indicate that there is no enough space for OpROM + // + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_LEGACY_OPROM_NO_SPACE) + ); + return EFI_OUT_OF_RESOURCES; + } + InitAddress = (UINTN) PhysicalAddress; + // + // then test if there is enough space for its RT code + // + RuntimeAddress = Private->OptionRom; + if (RuntimeAddress + *RuntimeImageLength > MaxRomAddr) { + DEBUG ((EFI_D_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__)); + gBS->FreePages (PhysicalAddress, EFI_SIZE_TO_PAGES (ImageSize)); + // + // Report Status Code to indicate that there is no enough space for OpROM + // + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_LEGACY_OPROM_NO_SPACE) + ); + return EFI_OUT_OF_RESOURCES; + } + } else { + // CSM16 3.0 meets PCI 2.x OpROM + // CSM16 2.x meets PCI 2.x/3.0 OpROM + // test if there is enough space for its INIT code + // + InitAddress = PCI_START_ADDRESS (Private->OptionRom); + if (InitAddress + ImageSize > MaxRomAddr) { + DEBUG ((EFI_D_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__)); + // + // Report Status Code to indicate that there is no enough space for OpROM + // + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_LEGACY_OPROM_NO_SPACE) + ); + return EFI_OUT_OF_RESOURCES; + } + + RuntimeAddress = InitAddress; + } + + Private->LegacyRegion->UnLock ( + Private->LegacyRegion, + 0xE0000, + 0x20000, + &Granularity + ); + + Private->LegacyRegion->UnLock ( + Private->LegacyRegion, + (UINT32) RuntimeAddress, + (UINT32) ImageSize, + &Granularity + ); + + DEBUG ((EFI_D_INFO, " Shadowing OpROM init/runtime/isize = %x/%x/%x\n", InitAddress, RuntimeAddress, ImageSize)); + + CopyMem ((VOID *) InitAddress, RomImage, ImageSize); + + // + // Read the highest disk number "installed: and assume a new disk will + // show up on the first drive past the current value. + // There are several considerations here: + // 1. Non-BBS compliant drives will change 40:75 but 16-bit CSM will undo + // the change until boot selection time frame. + // 2. BBS compliants drives will not change 40:75 until boot time. + // 3. Onboard IDE controllers will change 40:75 + // + ACCESS_PAGE0_CODE ( + LocalDiskStart = (UINT8) ((*(UINT8 *) ((UINTN) 0x475)) + 0x80); + if ((Private->Disk4075 + 0x80) < LocalDiskStart) { + // + // Update table since onboard IDE drives found + // + Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment = 0xff; + Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus = 0xff; + Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice = 0xff; + Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction = 0xff; + Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber = (UINT8) (Private->Disk4075 + 0x80); + Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber = LocalDiskStart; + Private->LegacyEfiHddTableIndex ++; + Private->Disk4075 = (UINT8) (LocalDiskStart & 0x7f); + Private->DiskEnd = LocalDiskStart; + } + + if (PciHandle != mVgaHandle) { + + EnablePs2Keyboard (); + + // + // Store current mode settings since PrepareToScanRom may change mode. + // + VideoMode = *(UINT8 *) ((UINTN) (0x400 + BDA_VIDEO_MODE)); + } + ); + + // + // Notify the platform that we are about to scan the ROM + // + Status = Private->LegacyBiosPlatform->PlatformHooks ( + Private->LegacyBiosPlatform, + EfiPlatformHookPrepareToScanRom, + 0, + PciHandle, + &InitAddress, + NULL, + NULL + ); + + // + // If Status returned is EFI_UNSUPPORTED then abort due to platform + // policy. + // + if (Status == EFI_UNSUPPORTED) { + goto Done; + } + + // + // Report corresponding status code + // + REPORT_STATUS_CODE ( + EFI_PROGRESS_CODE, + (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_CSM_LEGACY_ROM_INIT) + ); + + // + // Generate number of ticks since midnight for BDA. Some OPROMs require + // this. Place result in 40:6C-6F + // + gRT->GetTime (&BootTime, NULL); + LocalTime = BootTime.Hour * 3600 + BootTime.Minute * 60 + BootTime.Second; + + // + // Multiply result by 18.2 for number of ticks since midnight. + // Use 182/10 to avoid floating point math. + // + ACCESS_PAGE0_CODE ( + LocalTime = (LocalTime * 182) / 10; + BdaPtr = (UINT32 *) ((UINTN) 0x46C); + *BdaPtr = LocalTime; + ); + + // + // Pass in handoff data + // + PciEnableStatus = EFI_UNSUPPORTED; + ZeroMem (&Regs, sizeof (Regs)); + if (PciHandle != NULL) { + + Status = gBS->HandleProtocol ( + PciHandle, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo + ); + ASSERT_EFI_ERROR (Status); + + // + // Enable command register. + // + PciEnableStatus = PciIo->Attributes ( + PciIo, + EfiPciIoAttributeOperationEnable, + EFI_PCI_DEVICE_ENABLE, + NULL + ); + + PciIo->GetLocation ( + PciIo, + &Segment, + &Bus, + &Device, + &Function + ); + DEBUG ((EFI_D_INFO, "Shadowing OpROM on the PCI device %x/%x/%x\n", Bus, Device, Function)); + } + + mIgnoreBbsUpdateFlag = FALSE; + Regs.X.AX = Legacy16DispatchOprom; + + // + // Generate DispatchOpRomTable data + // + Private->IntThunk->DispatchOpromTable.PnPInstallationCheckSegment = Private->Legacy16Table->PnPInstallationCheckSegment; + Private->IntThunk->DispatchOpromTable.PnPInstallationCheckOffset = Private->Legacy16Table->PnPInstallationCheckOffset; + Private->IntThunk->DispatchOpromTable.OpromSegment = (UINT16) (InitAddress >> 4); + Private->IntThunk->DispatchOpromTable.PciBus = (UINT8) Bus; + Private->IntThunk->DispatchOpromTable.PciDeviceFunction = (UINT8) ((Device << 3) | Function); + Private->IntThunk->DispatchOpromTable.NumberBbsEntries = (UINT8) Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries; + Private->IntThunk->DispatchOpromTable.BbsTablePointer = (UINT32) (UINTN) Private->BbsTablePtr; + Private->IntThunk->DispatchOpromTable.RuntimeSegment = (UINT16)((OpromRevision < 3) ? 0xffff : (RuntimeAddress >> 4)); + TempData = (UINTN) &Private->IntThunk->DispatchOpromTable; + Regs.X.ES = EFI_SEGMENT ((UINT32) TempData); + Regs.X.BX = EFI_OFFSET ((UINT32) TempData); + // + // Skip dispatching ROM for those PCI devices that can not be enabled by PciIo->Attributes + // Otherwise, it may cause the system to hang in some cases + // + if (!EFI_ERROR (PciEnableStatus)) { + DEBUG ((EFI_D_INFO, " Legacy16DispatchOprom - %02x/%02x/%02x\n", Bus, Device, Function)); + Private->LegacyBios.FarCall86 ( + &Private->LegacyBios, + Private->Legacy16CallSegment, + Private->Legacy16CallOffset, + &Regs, + NULL, + 0 + ); + } else { + Regs.X.BX = 0; + } + + if (Private->IntThunk->DispatchOpromTable.NumberBbsEntries != (UINT8) Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries) { + Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries = (UINT8) Private->IntThunk->DispatchOpromTable.NumberBbsEntries; + mIgnoreBbsUpdateFlag = TRUE; + } + // + // Check if non-BBS compliant drives found + // + if (Regs.X.BX != 0) { + LocalDiskEnd = (UINT8) (LocalDiskStart + Regs.H.BL); + Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment = (UINT8) Segment; + Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus = (UINT8) Bus; + Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice = (UINT8) Device; + Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction = (UINT8) Function; + Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber = Private->DiskEnd; + Private->DiskEnd = LocalDiskEnd; + Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber = Private->DiskEnd; + Private->LegacyEfiHddTableIndex += 1; + } + // + // Skip video mode set, if installing VGA + // + if (PciHandle != mVgaHandle) { + // + // Set mode settings since PrepareToScanRom may change mode + // + ACCESS_PAGE0_CODE ({ + OldVideoMode = *(UINT8 *) ((UINTN) (0x400 + BDA_VIDEO_MODE)); + }); + + if (VideoMode != OldVideoMode) { + // + // The active video mode is changed, restore it to original mode. + // + Regs.H.AH = 0x00; + Regs.H.AL = VideoMode; + Private->LegacyBios.Int86 (&Private->LegacyBios, 0x10, &Regs); + } + } + // + // Regs.X.AX from the adapter initializion is ignored since some adapters + // do not follow the standard of setting AX = 0 on success. + // + // + // The ROM could have updated it's size so we need to read again. + // + if (((EFI_LEGACY_EXPANSION_ROM_HEADER *) RuntimeAddress)->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) { + // + // Now we check the signature (0xaa55) to judge whether the run-time code is truly generated by INIT function. + // If signature is not valid, that means the INIT function didn't copy the run-time code to RuntimeAddress. + // + *RuntimeImageLength = 0; + } else { + *RuntimeImageLength = ((EFI_LEGACY_EXPANSION_ROM_HEADER *) RuntimeAddress)->Size512 * 512; + } + + DEBUG ((EFI_D_INFO, " fsize = %x\n", *RuntimeImageLength)); + + // + // If OpROM runs in 2.0 mode + // + if (PhysicalAddress == 0) { + if (*RuntimeImageLength < ImageSize) { + // + // Make area from end of shadowed rom to end of original rom all ffs + // + gBS->SetMem ((VOID *) (InitAddress + *RuntimeImageLength), ImageSize - *RuntimeImageLength, 0xff); + } + } + + ACCESS_PAGE0_CODE ( + LocalDiskEnd = (UINT8) ((*(UINT8 *) ((UINTN) 0x475)) + 0x80); + ); + + // + // Allow platform to perform any required actions after the + // OPROM has been initialized. + // + Status = Private->LegacyBiosPlatform->PlatformHooks ( + Private->LegacyBiosPlatform, + EfiPlatformHookAfterRomInit, + 0, + PciHandle, + &RuntimeAddress, + NULL, + NULL + ); + if (PciHandle != NULL) { + // + // If no PCI Handle then no header or Bevs. + // + if ((*RuntimeImageLength != 0) && (!mIgnoreBbsUpdateFlag)) { + StartBbsIndex = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries; + TempData = RuntimeAddress; + UpdateBevBcvTable ( + Private, + (EFI_LEGACY_EXPANSION_ROM_HEADER *) TempData, + PciIo + ); + EndBbsIndex = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries; + LocalDiskEnd = (UINT8) (LocalDiskStart + (UINT8) (EndBbsIndex - StartBbsIndex)); + if (LocalDiskEnd != LocalDiskStart) { + Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment = (UINT8) Segment; + Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus = (UINT8) Bus; + Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice = (UINT8) Device; + Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction = (UINT8) Function; + Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber = Private->DiskEnd; + Private->DiskEnd = LocalDiskEnd; + Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber = Private->DiskEnd; + Private->LegacyEfiHddTableIndex += 1; + } + } + // + // Mark PCI device as having a legacy BIOS ROM loaded. + // + RomShadow ( + PciHandle, + (UINT32) RuntimeAddress, + (UINT32) *RuntimeImageLength, + LocalDiskStart, + LocalDiskEnd + ); + } + + // + // Stuff caller's OPTIONAL return parameters. + // + if (RomShadowAddress != NULL) { + *RomShadowAddress = (VOID *) RuntimeAddress; + } + + if (DiskStart != NULL) { + *DiskStart = LocalDiskStart; + } + + if (DiskEnd != NULL) { + *DiskEnd = LocalDiskEnd; + } + + Private->OptionRom = (UINT32) (RuntimeAddress + *RuntimeImageLength); + + Status = EFI_SUCCESS; + +Done: + if (PhysicalAddress != 0) { + // + // Free pages when OpROM is 3.0 + // + gBS->FreePages (PhysicalAddress, EFI_SIZE_TO_PAGES (ImageSize)); + } + + // + // Insure all shadowed areas are locked + // + Private->LegacyRegion->Lock ( + Private->LegacyRegion, + 0xC0000, + 0x40000, + &Granularity + ); + + return Status; +} + +/** + Let IOMMU grant DMA access for the PCI device. + + @param PciHandle The EFI handle for the PCI device. + @param HostAddress The system memory address to map to the PCI controller. + @param NumberOfBytes The number of bytes to map. + + @retval EFI_SUCCESS The DMA access is granted. +**/ +EFI_STATUS +IoMmuGrantAccess ( + IN EFI_HANDLE PciHandle, + IN EFI_PHYSICAL_ADDRESS HostAddress, + IN UINTN NumberOfBytes + ) +{ + EFI_PHYSICAL_ADDRESS DeviceAddress; + VOID *Mapping; + EFI_STATUS Status; + + if (PciHandle == NULL) { + return EFI_UNSUPPORTED; + } + + Status = EFI_SUCCESS; + if (mIoMmu == NULL) { + gBS->LocateProtocol (&gEdkiiIoMmuProtocolGuid, NULL, (VOID **)&mIoMmu); + } + if (mIoMmu != NULL) { + Status = mIoMmu->Map ( + mIoMmu, + EdkiiIoMmuOperationBusMasterCommonBuffer, + (VOID *)(UINTN)HostAddress, + &NumberOfBytes, + &DeviceAddress, + &Mapping + ); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "LegacyPci - IoMmuMap - %r\n", Status)); + } else { + ASSERT (DeviceAddress == HostAddress); + Status = mIoMmu->SetAttribute ( + mIoMmu, + PciHandle, + Mapping, + EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE + ); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "LegacyPci - IoMmuSetAttribute - %r\n", Status)); + } + } + } + return Status; +} + +/** + Load a legacy PC-AT OPROM on the PciHandle device. Return information + about how many disks were added by the OPROM and the shadow address and + size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C: + + @param This Protocol instance pointer. + @param PciHandle The PCI PC-AT OPROM from this devices ROM BAR will + be loaded. This value is NULL if RomImage is + non-NULL. This is the normal case. + @param RomImage A PCI PC-AT ROM image. This argument is non-NULL + if there is no hardware associated with the ROM + and thus no PciHandle, otherwise is must be NULL. + Example is PXE base code. + @param Flags Indicates if ROM found and if PC-AT. + @param DiskStart Disk number of first device hooked by the ROM. If + DiskStart is the same as DiskEnd no disked were + hooked. + @param DiskEnd Disk number of the last device hooked by the ROM. + @param RomShadowAddress Shadow address of PC-AT ROM + @param RomShadowedSize Size of RomShadowAddress in bytes + + @retval EFI_SUCCESS Legacy ROM loaded for this device + @retval EFI_INVALID_PARAMETER PciHandle not found + @retval EFI_UNSUPPORTED There is no PCI ROM in the ROM BAR or no onboard + ROM + +**/ +EFI_STATUS +EFIAPI +LegacyBiosInstallPciRom ( + IN EFI_LEGACY_BIOS_PROTOCOL * This, + IN EFI_HANDLE PciHandle, + IN VOID **RomImage, + OUT UINTN *Flags, + OUT UINT8 *DiskStart, OPTIONAL + OUT UINT8 *DiskEnd, OPTIONAL + OUT VOID **RomShadowAddress, OPTIONAL + OUT UINT32 *RomShadowedSize OPTIONAL + ) +{ + EFI_STATUS Status; + LEGACY_BIOS_INSTANCE *Private; + VOID *LocalRomImage; + UINTN ImageSize; + UINTN RuntimeImageLength; + EFI_PCI_IO_PROTOCOL *PciIo; + PCI_TYPE01 PciConfigHeader; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN PciSegment; + UINTN PciBus; + UINTN PciDevice; + UINTN PciFunction; + UINTN LastBus; + UINTN Index; + UINT8 OpromRevision; + UINT32 Granularity; + PCI_3_0_DATA_STRUCTURE *Pcir; + + OpromRevision = 0; + + Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); + if (Private->Legacy16Table->LastPciBus == 0) { + // + // Get last bus number if not already found + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiPciIoProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + + LastBus = 0; + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo + ); + if (EFI_ERROR (Status)) { + continue; + } + + Status = PciIo->GetLocation ( + PciIo, + &PciSegment, + &PciBus, + &PciDevice, + &PciFunction + ); + if (PciBus > LastBus) { + LastBus = PciBus; + } + } + + Private->LegacyRegion->UnLock ( + Private->LegacyRegion, + 0xE0000, + 0x20000, + &Granularity + ); + Private->Legacy16Table->LastPciBus = (UINT8) LastBus; + Private->LegacyRegion->Lock ( + Private->LegacyRegion, + 0xE0000, + 0x20000, + &Granularity + ); + } + + *Flags = 0; + if ((PciHandle != NULL) && (RomImage == NULL)) { + // + // If PciHandle has OpRom to Execute + // and OpRom are all associated with Hardware + // + Status = gBS->HandleProtocol ( + PciHandle, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo + ); + + if (!EFI_ERROR (Status)) { + PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint32, + 0, + sizeof (PciConfigHeader) / sizeof (UINT32), + &PciConfigHeader + ); + + // + // if video installed & OPROM is video return + // + if ( + ( + ((PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_OLD) && + (PciConfigHeader.Hdr.ClassCode[1] == PCI_CLASS_OLD_VGA)) + || + ((PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_DISPLAY) && + (PciConfigHeader.Hdr.ClassCode[1] == PCI_CLASS_DISPLAY_VGA)) + ) + && + (!Private->VgaInstalled) + ) { + mVgaInstallationInProgress = TRUE; + + // + // return EFI_UNSUPPORTED; + // + } + } + // + // To run any legacy image, the VGA needs to be installed first. + // if installing the video, then don't need the thunk as already installed. + // + Status = Private->LegacyBiosPlatform->GetPlatformHandle ( + Private->LegacyBiosPlatform, + EfiGetPlatformVgaHandle, + 0, + &HandleBuffer, + &HandleCount, + NULL + ); + + if (!EFI_ERROR (Status)) { + mVgaHandle = HandleBuffer[0]; + if ((!Private->VgaInstalled) && (PciHandle != mVgaHandle)) { + // + // A return status of EFI_NOT_FOUND is considered valid (No EFI + // driver is controlling video. + // + mVgaInstallationInProgress = TRUE; + Status = LegacyBiosInstallVgaRom (Private); + if (EFI_ERROR (Status)) { + if (Status != EFI_NOT_FOUND) { + mVgaInstallationInProgress = FALSE; + return Status; + } + } else { + mVgaInstallationInProgress = FALSE; + } + } + } + // + // See if the option ROM for PciHandle has already been executed + // + Status = IsLegacyRom (PciHandle); + + if (!EFI_ERROR (Status)) { + mVgaInstallationInProgress = FALSE; + GetShadowedRomParameters ( + PciHandle, + DiskStart, + DiskEnd, + RomShadowAddress, + (UINTN *) RomShadowedSize + ); + return EFI_SUCCESS; + } + + Status = LegacyBiosCheckPciRomEx ( + &Private->LegacyBios, + PciHandle, + &LocalRomImage, + &ImageSize, + &RuntimeImageLength, + Flags, + &OpromRevision, + NULL + ); + if (EFI_ERROR (Status)) { + // + // There is no PCI ROM in the ROM BAR or no onboard ROM + // + mVgaInstallationInProgress = FALSE; + return EFI_UNSUPPORTED; + } + } else { + if ((RomImage == NULL) || (*RomImage == NULL)) { + // + // If PciHandle is NULL, and no OpRom is to be associated + // + mVgaInstallationInProgress = FALSE; + return EFI_UNSUPPORTED; + } + + Status = Private->LegacyBiosPlatform->GetPlatformHandle ( + Private->LegacyBiosPlatform, + EfiGetPlatformVgaHandle, + 0, + &HandleBuffer, + &HandleCount, + NULL + ); + if ((!EFI_ERROR (Status)) && (!Private->VgaInstalled)) { + // + // A return status of EFI_NOT_FOUND is considered valid (No EFI + // driver is controlling video. + // + mVgaInstallationInProgress = TRUE; + Status = LegacyBiosInstallVgaRom (Private); + if (EFI_ERROR (Status)) { + if (Status != EFI_NOT_FOUND) { + mVgaInstallationInProgress = FALSE; + return Status; + } + } else { + mVgaInstallationInProgress = FALSE; + } + } + + LocalRomImage = *RomImage; + if (((PCI_EXPANSION_ROM_HEADER *) LocalRomImage)->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE || + ((PCI_EXPANSION_ROM_HEADER *) LocalRomImage)->PcirOffset == 0 || + (((PCI_EXPANSION_ROM_HEADER *) LocalRomImage)->PcirOffset & 3 ) != 0) { + mVgaInstallationInProgress = FALSE; + return EFI_UNSUPPORTED; + } + + Pcir = (PCI_3_0_DATA_STRUCTURE *) + ((UINT8 *) LocalRomImage + ((PCI_EXPANSION_ROM_HEADER *) LocalRomImage)->PcirOffset); + + if ((Pcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) || (Pcir->CodeType != PCI_CODE_TYPE_PCAT_IMAGE)) { + mVgaInstallationInProgress = FALSE; + return EFI_UNSUPPORTED; + } + + ImageSize = Pcir->ImageLength * 512; + if (Pcir->Length >= 0x1C) { + OpromRevision = Pcir->Revision; + } else { + OpromRevision = 0; + } + if (Pcir->Revision < 3) { + RuntimeImageLength = 0; + } else { + RuntimeImageLength = Pcir->MaxRuntimeImageLength * 512; + } + } + + // + // Grant access for below 1M + // BDA/EBDA/LowPMM and scratch memory for OPROM. + // + IoMmuGrantAccess (PciHandle, 0, SIZE_1MB); + // + // Grant access for HiPmm + // + IoMmuGrantAccess ( + PciHandle, + Private->IntThunk->EfiToLegacy16InitTable.HiPmmMemory, + Private->IntThunk->EfiToLegacy16InitTable.HiPmmMemorySizeInBytes + ); + + // + // Shadow and initialize the OpROM. + // + ASSERT (Private->TraceIndex < 0x200); + Private->Trace[Private->TraceIndex] = LEGACY_PCI_TRACE_000; + Private->TraceIndex ++; + Private->TraceIndex = (UINT16) (Private->TraceIndex % 0x200); + Status = LegacyBiosInstallRom ( + This, + Private, + PciHandle, + OpromRevision, + LocalRomImage, + ImageSize, + &RuntimeImageLength, + DiskStart, + DiskEnd, + RomShadowAddress + ); + if (RomShadowedSize != NULL) { + *RomShadowedSize = (UINT32) RuntimeImageLength; + } + + mVgaInstallationInProgress = FALSE; + return Status; +} + diff --git a/OvmfPkg/Csm/LegacyBiosDxe/LegacySio.c b/OvmfPkg/Csm/LegacyBiosDxe/LegacySio.c new file mode 100644 index 0000000000..17720a74f7 --- /dev/null +++ b/OvmfPkg/Csm/LegacyBiosDxe/LegacySio.c @@ -0,0 +1,477 @@ +/** @file + Collect Sio information from Native EFI Drivers. + Sio is floppy, parallel, serial, ... hardware + +Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "LegacyBiosInterface.h" + +/** + Collect EFI Info about legacy devices through Super IO interface. + + @param SioPtr Pointer to SIO data. + + @retval EFI_SUCCESS When SIO data is got successfully. + @retval EFI_NOT_FOUND When ISA IO interface is absent. + +**/ +EFI_STATUS +LegacyBiosBuildSioDataFromSio ( + IN DEVICE_PRODUCER_DATA_HEADER *SioPtr + ) +{ + EFI_STATUS Status; + DEVICE_PRODUCER_SERIAL *SioSerial; + DEVICE_PRODUCER_PARALLEL *SioParallel; + DEVICE_PRODUCER_FLOPPY *SioFloppy; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN Index; + UINTN ChildIndex; + EFI_SIO_PROTOCOL *Sio; + ACPI_RESOURCE_HEADER_PTR Resources; + EFI_ACPI_IO_PORT_DESCRIPTOR *IoResource; + EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *FixedIoResource; + EFI_ACPI_DMA_DESCRIPTOR *DmaResource; + EFI_ACPI_IRQ_NOFLAG_DESCRIPTOR *IrqResource; + UINT16 Address; + UINT8 Dma; + UINT8 Irq; + UINTN EntryCount; + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + EFI_SERIAL_IO_PROTOCOL *SerialIo; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + ACPI_HID_DEVICE_PATH *Acpi; + + // + // Get the list of ISA controllers in the system + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSioProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + // + // Collect legacy information from each of the ISA controllers in the system + // + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiSioProtocolGuid, (VOID **) &Sio); + if (EFI_ERROR (Status)) { + continue; + } + + Address = MAX_UINT16; + Dma = MAX_UINT8; + Irq = MAX_UINT8; + Status = Sio->GetResources (Sio, &Resources); + if (!EFI_ERROR (Status)) { + // + // Get the base address information from ACPI resource descriptor. + // + while (Resources.SmallHeader->Byte != ACPI_END_TAG_DESCRIPTOR) { + switch (Resources.SmallHeader->Byte) { + case ACPI_IO_PORT_DESCRIPTOR: + IoResource = (EFI_ACPI_IO_PORT_DESCRIPTOR *) Resources.SmallHeader; + Address = IoResource->BaseAddressMin; + break; + + case ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR: + FixedIoResource = (EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *) Resources.SmallHeader; + Address = FixedIoResource->BaseAddress; + break; + + case ACPI_DMA_DESCRIPTOR: + DmaResource = (EFI_ACPI_DMA_DESCRIPTOR *) Resources.SmallHeader; + Dma = (UINT8) LowBitSet32 (DmaResource->ChannelMask); + break; + + case ACPI_IRQ_DESCRIPTOR: + case ACPI_IRQ_NOFLAG_DESCRIPTOR: + IrqResource = (EFI_ACPI_IRQ_NOFLAG_DESCRIPTOR *) Resources.SmallHeader; + Irq = (UINT8) LowBitSet32 (IrqResource->Mask); + break; + + default: + break; + } + + if (Resources.SmallHeader->Bits.Type == 0) { + Resources.SmallHeader = (ACPI_SMALL_RESOURCE_HEADER *) ((UINT8 *) Resources.SmallHeader + + Resources.SmallHeader->Bits.Length + + sizeof (*Resources.SmallHeader)); + } else { + Resources.LargeHeader = (ACPI_LARGE_RESOURCE_HEADER *) ((UINT8 *) Resources.LargeHeader + + Resources.LargeHeader->Length + + sizeof (*Resources.LargeHeader)); + } + } + } + + DEBUG ((EFI_D_INFO, "LegacySio: Address/Dma/Irq = %x/%d/%d\n", Address, Dma, Irq)); + + DevicePath = DevicePathFromHandle (HandleBuffer[Index]); + if (DevicePath == NULL) { + continue; + } + + Acpi = NULL; + while (!IsDevicePathEnd (DevicePath)) { + Acpi = (ACPI_HID_DEVICE_PATH *) DevicePath; + DevicePath = NextDevicePathNode (DevicePath); + } + + if ((Acpi == NULL) || (DevicePathType (Acpi) != ACPI_DEVICE_PATH) || + ((DevicePathSubType (Acpi) != ACPI_DP) && (DevicePathSubType (Acpi) != ACPI_EXTENDED_DP)) + ) { + continue; + } + + // + // See if this is an ISA serial port + // + // Ignore DMA resource since it is always returned NULL + // + if (Acpi->HID == EISA_PNP_ID (0x500) || Acpi->HID == EISA_PNP_ID (0x501)) { + + if (Acpi->UID < 4 && Address != MAX_UINT16 && Irq != MAX_UINT8) { + // + // Get the handle of the child device that has opened the Super I/O Protocol + // + Status = gBS->OpenProtocolInformation ( + HandleBuffer[Index], + &gEfiSioProtocolGuid, + &OpenInfoBuffer, + &EntryCount + ); + if (EFI_ERROR (Status)) { + continue; + } + for (ChildIndex = 0; ChildIndex < EntryCount; ChildIndex++) { + if ((OpenInfoBuffer[ChildIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) { + Status = gBS->HandleProtocol (OpenInfoBuffer[ChildIndex].ControllerHandle, &gEfiSerialIoProtocolGuid, (VOID **) &SerialIo); + if (!EFI_ERROR (Status)) { + SioSerial = &SioPtr->Serial[Acpi->UID]; + SioSerial->Address = Address; + SioSerial->Irq = Irq; + SioSerial->Mode = DEVICE_SERIAL_MODE_NORMAL | DEVICE_SERIAL_MODE_DUPLEX_HALF; + break; + } + } + } + + FreePool (OpenInfoBuffer); + } + } + // + // See if this is an ISA parallel port + // + // Ignore DMA resource since it is always returned NULL, port + // only used in output mode. + // + if (Acpi->HID == EISA_PNP_ID (0x400) || Acpi->HID == EISA_PNP_ID (0x401)) { + if (Acpi->UID < 3 && Address != MAX_UINT16 && Irq != MAX_UINT8 && Dma != MAX_UINT8) { + SioParallel = &SioPtr->Parallel[Acpi->UID]; + SioParallel->Address = Address; + SioParallel->Irq = Irq; + SioParallel->Dma = Dma; + SioParallel->Mode = DEVICE_PARALLEL_MODE_MODE_OUTPUT_ONLY; + } + } + // + // See if this is an ISA floppy controller + // + if (Acpi->HID == EISA_PNP_ID (0x604)) { + if (Address != MAX_UINT16 && Irq != MAX_UINT8 && Dma != MAX_UINT8) { + Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo); + if (!EFI_ERROR (Status)) { + SioFloppy = &SioPtr->Floppy; + SioFloppy->Address = Address; + SioFloppy->Irq = Irq; + SioFloppy->Dma = Dma; + SioFloppy->NumberOfFloppy++; + } + } + } + // + // See if this is a mouse + // Always set mouse found so USB hot plug will work + // + // Ignore lower byte of HID. Pnp0fxx is any type of mouse. + // + // Hid = ResourceList->Device.HID & 0xff00ffff; + // PnpId = EISA_PNP_ID(0x0f00); + // if (Hid == PnpId) { + // if (ResourceList->Device.UID == 1) { + // Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiSimplePointerProtocolGuid, &SimplePointer); + // if (!EFI_ERROR (Status)) { + // + SioPtr->MousePresent = 0x01; + // + // } + // } + // } + // + } + + FreePool (HandleBuffer); + return EFI_SUCCESS; + +} + +/** + Collect EFI Info about legacy devices through ISA IO interface. + + @param SioPtr Pointer to SIO data. + + @retval EFI_SUCCESS When SIO data is got successfully. + @retval EFI_NOT_FOUND When ISA IO interface is absent. + +**/ +EFI_STATUS +LegacyBiosBuildSioDataFromIsaIo ( + IN DEVICE_PRODUCER_DATA_HEADER *SioPtr + ) +{ + EFI_STATUS Status; + DEVICE_PRODUCER_SERIAL *SioSerial; + DEVICE_PRODUCER_PARALLEL *SioParallel; + DEVICE_PRODUCER_FLOPPY *SioFloppy; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN Index; + UINTN ResourceIndex; + UINTN ChildIndex; + EFI_ISA_IO_PROTOCOL *IsaIo; + EFI_ISA_ACPI_RESOURCE_LIST *ResourceList; + EFI_ISA_ACPI_RESOURCE *IoResource; + EFI_ISA_ACPI_RESOURCE *DmaResource; + EFI_ISA_ACPI_RESOURCE *InterruptResource; + UINTN EntryCount; + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + EFI_SERIAL_IO_PROTOCOL *SerialIo; + + // + // Get the list of ISA controllers in the system + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiIsaIoProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + // + // Collect legacy information from each of the ISA controllers in the system + // + for (Index = 0; Index < HandleCount; Index++) { + + Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiIsaIoProtocolGuid, (VOID **) &IsaIo); + if (EFI_ERROR (Status)) { + continue; + } + + ResourceList = IsaIo->ResourceList; + + if (ResourceList == NULL) { + continue; + } + // + // Collect the resource types neededto fill in the SIO data structure + // + IoResource = NULL; + DmaResource = NULL; + InterruptResource = NULL; + for (ResourceIndex = 0; + ResourceList->ResourceItem[ResourceIndex].Type != EfiIsaAcpiResourceEndOfList; + ResourceIndex++ + ) { + switch (ResourceList->ResourceItem[ResourceIndex].Type) { + case EfiIsaAcpiResourceIo: + IoResource = &ResourceList->ResourceItem[ResourceIndex]; + break; + + case EfiIsaAcpiResourceMemory: + break; + + case EfiIsaAcpiResourceDma: + DmaResource = &ResourceList->ResourceItem[ResourceIndex]; + break; + + case EfiIsaAcpiResourceInterrupt: + InterruptResource = &ResourceList->ResourceItem[ResourceIndex]; + break; + + default: + break; + } + } + // + // See if this is an ISA serial port + // + // Ignore DMA resource since it is always returned NULL + // + if (ResourceList->Device.HID == EISA_PNP_ID (0x500) || ResourceList->Device.HID == EISA_PNP_ID (0x501)) { + + if (ResourceList->Device.UID <= 3 && + IoResource != NULL && + InterruptResource != NULL + ) { + // + // Get the handle of the child device that has opened the ISA I/O Protocol + // + Status = gBS->OpenProtocolInformation ( + HandleBuffer[Index], + &gEfiIsaIoProtocolGuid, + &OpenInfoBuffer, + &EntryCount + ); + if (EFI_ERROR (Status)) { + continue; + } + // + // We want resource for legacy even if no 32-bit driver installed + // + for (ChildIndex = 0; ChildIndex < EntryCount; ChildIndex++) { + if ((OpenInfoBuffer[ChildIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) { + Status = gBS->HandleProtocol (OpenInfoBuffer[ChildIndex].ControllerHandle, &gEfiSerialIoProtocolGuid, (VOID **) &SerialIo); + if (!EFI_ERROR (Status)) { + SioSerial = &SioPtr->Serial[ResourceList->Device.UID]; + SioSerial->Address = (UINT16) IoResource->StartRange; + SioSerial->Irq = (UINT8) InterruptResource->StartRange; + SioSerial->Mode = DEVICE_SERIAL_MODE_NORMAL | DEVICE_SERIAL_MODE_DUPLEX_HALF; + break; + } + } + } + + FreePool (OpenInfoBuffer); + } + } + // + // See if this is an ISA parallel port + // + // Ignore DMA resource since it is always returned NULL, port + // only used in output mode. + // + if (ResourceList->Device.HID == EISA_PNP_ID (0x400) || ResourceList->Device.HID == EISA_PNP_ID (0x401)) { + if (ResourceList->Device.UID <= 2 && + IoResource != NULL && + InterruptResource != NULL && + DmaResource != NULL + ) { + SioParallel = &SioPtr->Parallel[ResourceList->Device.UID]; + SioParallel->Address = (UINT16) IoResource->StartRange; + SioParallel->Irq = (UINT8) InterruptResource->StartRange; + SioParallel->Dma = (UINT8) DmaResource->StartRange; + SioParallel->Mode = DEVICE_PARALLEL_MODE_MODE_OUTPUT_ONLY; + } + } + // + // See if this is an ISA floppy controller + // + if (ResourceList->Device.HID == EISA_PNP_ID (0x604)) { + if (IoResource != NULL && InterruptResource != NULL && DmaResource != NULL) { + Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo); + if (!EFI_ERROR (Status)) { + SioFloppy = &SioPtr->Floppy; + SioFloppy->Address = (UINT16) IoResource->StartRange; + SioFloppy->Irq = (UINT8) InterruptResource->StartRange; + SioFloppy->Dma = (UINT8) DmaResource->StartRange; + SioFloppy->NumberOfFloppy++; + } + } + } + // + // See if this is a mouse + // Always set mouse found so USB hot plug will work + // + // Ignore lower byte of HID. Pnp0fxx is any type of mouse. + // + // Hid = ResourceList->Device.HID & 0xff00ffff; + // PnpId = EISA_PNP_ID(0x0f00); + // if (Hid == PnpId) { + // if (ResourceList->Device.UID == 1) { + // Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiSimplePointerProtocolGuid, &SimplePointer); + // if (!EFI_ERROR (Status)) { + // + SioPtr->MousePresent = 0x01; + // + // } + // } + // } + // + } + + FreePool (HandleBuffer); + return EFI_SUCCESS; +} + +/** + Collect EFI Info about legacy devices. + + @param Private Legacy BIOS Instance data + + @retval EFI_SUCCESS It should always work. + +**/ +EFI_STATUS +LegacyBiosBuildSioData ( + IN LEGACY_BIOS_INSTANCE *Private + ) +{ + EFI_STATUS Status; + DEVICE_PRODUCER_DATA_HEADER *SioPtr; + EFI_HANDLE IsaBusController; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + + // + // Get the pointer to the SIO data structure + // + SioPtr = &Private->IntThunk->EfiToLegacy16BootTable.SioData; + + // + // Zero the data in the SIO data structure + // + gBS->SetMem (SioPtr, sizeof (DEVICE_PRODUCER_DATA_HEADER), 0); + + // + // Find the ISA Bus Controller used for legacy + // + Status = Private->LegacyBiosPlatform->GetPlatformHandle ( + Private->LegacyBiosPlatform, + EfiGetPlatformIsaBusHandle, + 0, + &HandleBuffer, + &HandleCount, + NULL + ); + IsaBusController = HandleBuffer[0]; + if (!EFI_ERROR (Status)) { + // + // Force ISA Bus Controller to produce all ISA devices + // + gBS->ConnectController (IsaBusController, NULL, NULL, TRUE); + } + + Status = LegacyBiosBuildSioDataFromIsaIo (SioPtr); + if (EFI_ERROR (Status)) { + LegacyBiosBuildSioDataFromSio (SioPtr); + } + + return EFI_SUCCESS; +} diff --git a/OvmfPkg/Csm/LegacyBiosDxe/Thunk.c b/OvmfPkg/Csm/LegacyBiosDxe/Thunk.c new file mode 100644 index 0000000000..a4985ede77 --- /dev/null +++ b/OvmfPkg/Csm/LegacyBiosDxe/Thunk.c @@ -0,0 +1,419 @@ +/** @file + Call into 16-bit BIOS code, Use AsmThunk16 function of BaseLib. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "LegacyBiosInterface.h" + +THUNK_CONTEXT mThunkContext; + +/** + Sets the counter value for Timer #0 in a legacy 8254 timer. + + @param Count - The 16-bit counter value to program into Timer #0 of the legacy 8254 timer. + +**/ +VOID +SetPitCount ( + IN UINT16 Count + ) +{ + IoWrite8 (TIMER_CONTROL_PORT, TIMER0_CONTROL_WORD); + IoWrite8 (TIMER0_COUNT_PORT, (UINT8) (Count & 0xFF)); + IoWrite8 (TIMER0_COUNT_PORT, (UINT8) ((Count>>8) & 0xFF)); +} + +/** + Thunk to 16-bit real mode and execute a software interrupt with a vector + of BiosInt. Regs will contain the 16-bit register context on entry and + exit. + + @param This Protocol instance pointer. + @param BiosInt Processor interrupt vector to invoke + @param Regs Register contexted passed into (and returned) from thunk to + 16-bit mode + + @retval FALSE Thunk completed, and there were no BIOS errors in the target code. + See Regs for status. + @retval TRUE There was a BIOS erro in the target code. + +**/ +BOOLEAN +EFIAPI +LegacyBiosInt86 ( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN UINT8 BiosInt, + IN EFI_IA32_REGISTER_SET *Regs + ) +{ + UINT16 Segment; + UINT16 Offset; + + Regs->X.Flags.Reserved1 = 1; + Regs->X.Flags.Reserved2 = 0; + Regs->X.Flags.Reserved3 = 0; + Regs->X.Flags.Reserved4 = 0; + Regs->X.Flags.IOPL = 3; + Regs->X.Flags.NT = 0; + Regs->X.Flags.IF = 0; + Regs->X.Flags.TF = 0; + Regs->X.Flags.CF = 0; + // + // The base address of legacy interrupt vector table is 0. + // We use this base address to get the legacy interrupt handler. + // + ACCESS_PAGE0_CODE ( + Segment = (UINT16)(((UINT32 *)0)[BiosInt] >> 16); + Offset = (UINT16)((UINT32 *)0)[BiosInt]; + ); + + return InternalLegacyBiosFarCall ( + This, + Segment, + Offset, + Regs, + &Regs->X.Flags, + sizeof (Regs->X.Flags) + ); +} + +/** + Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the + 16-bit register context on entry and exit. Arguments can be passed on + the Stack argument + + @param This Protocol instance pointer. + @param Segment Segemnt of 16-bit mode call + @param Offset Offset of 16-bit mdoe call + @param Regs Register contexted passed into (and returned) from + thunk to 16-bit mode + @param Stack Caller allocated stack used to pass arguments + @param StackSize Size of Stack in bytes + + @retval FALSE Thunk completed, and there were no BIOS errors in + the target code. See Regs for status. + @retval TRUE There was a BIOS erro in the target code. + +**/ +BOOLEAN +EFIAPI +LegacyBiosFarCall86 ( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN UINT16 Segment, + IN UINT16 Offset, + IN EFI_IA32_REGISTER_SET *Regs, + IN VOID *Stack, + IN UINTN StackSize + ) +{ + Regs->X.Flags.Reserved1 = 1; + Regs->X.Flags.Reserved2 = 0; + Regs->X.Flags.Reserved3 = 0; + Regs->X.Flags.Reserved4 = 0; + Regs->X.Flags.IOPL = 3; + Regs->X.Flags.NT = 0; + Regs->X.Flags.IF = 1; + Regs->X.Flags.TF = 0; + Regs->X.Flags.CF = 0; + + return InternalLegacyBiosFarCall (This, Segment, Offset, Regs, Stack, StackSize); +} + +/** + Provide NULL interrupt handler which is used to check + if there is more than one HW interrupt registers with the CPU AP. + + @param InterruptType - The type of interrupt that occured + @param SystemContext - A pointer to the system context when the interrupt occured + +**/ +VOID +EFIAPI +LegacyBiosNullInterruptHandler ( + IN EFI_EXCEPTION_TYPE InterruptType, + IN EFI_SYSTEM_CONTEXT SystemContext + ) +{ +} + +/** + Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the + 16-bit register context on entry and exit. Arguments can be passed on + the Stack argument + + @param This Protocol instance pointer. + @param Segment Segemnt of 16-bit mode call + @param Offset Offset of 16-bit mdoe call + @param Regs Register contexted passed into (and returned) from thunk to + 16-bit mode + @param Stack Caller allocated stack used to pass arguments + @param StackSize Size of Stack in bytes + + @retval FALSE Thunk completed, and there were no BIOS errors in the target code. + See Regs for status. + @retval TRUE There was a BIOS erro in the target code. + +**/ +BOOLEAN +EFIAPI +InternalLegacyBiosFarCall ( + IN EFI_LEGACY_BIOS_PROTOCOL *This, + IN UINT16 Segment, + IN UINT16 Offset, + IN EFI_IA32_REGISTER_SET *Regs, + IN VOID *Stack, + IN UINTN StackSize + ) +{ + UINTN Status; + LEGACY_BIOS_INSTANCE *Private; + UINT16 *Stack16; + EFI_TPL OriginalTpl; + IA32_REGISTER_SET ThunkRegSet; + BOOLEAN InterruptState; + UINT64 TimerPeriod; + + Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This); + + ZeroMem (&ThunkRegSet, sizeof (ThunkRegSet)); + ThunkRegSet.X.DI = Regs->X.DI; + ThunkRegSet.X.SI = Regs->X.SI; + ThunkRegSet.X.BP = Regs->X.BP; + ThunkRegSet.X.BX = Regs->X.BX; + ThunkRegSet.X.DX = Regs->X.DX; + // + // Sometimes, ECX is used to pass in 32 bit data. For example, INT 1Ah, AX = B10Dh is + // "PCI BIOS v2.0c + Write Configuration DWORD" and ECX has the dword to write. + // + ThunkRegSet.E.ECX = Regs->E.ECX; + ThunkRegSet.X.AX = Regs->X.AX; + ThunkRegSet.E.DS = Regs->X.DS; + ThunkRegSet.E.ES = Regs->X.ES; + + CopyMem (&(ThunkRegSet.E.EFLAGS.UintN), &(Regs->X.Flags), sizeof (Regs->X.Flags)); + + // + // Clear the error flag; thunk code may set it. Stack16 should be the high address + // Make Statk16 address the low 16 bit must be not zero. + // + Stack16 = (UINT16 *)((UINT8 *) mThunkContext.RealModeBuffer + mThunkContext.RealModeBufferSize - sizeof (UINT16)); + + // + // Save current rate of DXE Timer + // + Private->Timer->GetTimerPeriod (Private->Timer, &TimerPeriod); + + // + // Disable DXE Timer while executing in real mode + // + Private->Timer->SetTimerPeriod (Private->Timer, 0); + + // + // Save and disable interrupt of debug timer + // + InterruptState = SaveAndSetDebugTimerInterrupt (FALSE); + + // + // The call to Legacy16 is a critical section to EFI + // + OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); + + // + // Check to see if there is more than one HW interrupt registers with the CPU AP. + // If there is, then ASSERT() since that is not compatible with the CSM because + // interupts other than the Timer interrupt that was disabled above can not be + // handled properly from real mode. + // + DEBUG_CODE ( + UINTN Vector; + UINTN Count; + + for (Vector = 0x20, Count = 0; Vector < 0x100; Vector++) { + Status = Private->Cpu->RegisterInterruptHandler (Private->Cpu, Vector, LegacyBiosNullInterruptHandler); + if (Status == EFI_ALREADY_STARTED) { + Count++; + } + if (Status == EFI_SUCCESS) { + Private->Cpu->RegisterInterruptHandler (Private->Cpu, Vector, NULL); + } + } + if (Count >= 2) { + DEBUG ((EFI_D_ERROR, "ERROR: More than one HW interrupt active with CSM enabled\n")); + } + ASSERT (Count < 2); + ); + + // + // If the Timer AP has enabled the 8254 timer IRQ and the current 8254 timer + // period is less than the CSM required rate of 54.9254, then force the 8254 + // PIT counter to 0, which is the CSM required rate of 54.9254 ms + // + if (Private->TimerUses8254 && TimerPeriod < 549254) { + SetPitCount (0); + } + + if (Stack != NULL && StackSize != 0) { + // + // Copy Stack to low memory stack + // + Stack16 -= StackSize / sizeof (UINT16); + CopyMem (Stack16, Stack, StackSize); + } + + ThunkRegSet.E.SS = (UINT16) (((UINTN) Stack16 >> 16) << 12); + ThunkRegSet.E.ESP = (UINT16) (UINTN) Stack16; + ThunkRegSet.E.CS = Segment; + ThunkRegSet.E.Eip = Offset; + + mThunkContext.RealModeState = &ThunkRegSet; + + // + // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases. + // + Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259LegacyMode, NULL, NULL); + ASSERT_EFI_ERROR (Status); + + AsmThunk16 (&mThunkContext); + + if (Stack != NULL && StackSize != 0) { + // + // Copy low memory stack to Stack + // + CopyMem (Stack, Stack16, StackSize); + } + + // + // Restore protected mode interrupt state + // + Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259ProtectedMode, NULL, NULL); + ASSERT_EFI_ERROR (Status); + + mThunkContext.RealModeState = NULL; + + // + // Enable and restore rate of DXE Timer + // + Private->Timer->SetTimerPeriod (Private->Timer, TimerPeriod); + + // + // End critical section + // + gBS->RestoreTPL (OriginalTpl); + + // + // OPROM may allocate EBDA range by itself and change EBDA base and EBDA size. + // Get the current EBDA base address, and compared with pre-allocate minimum + // EBDA base address, if the current EBDA base address is smaller, it indicates + // PcdEbdaReservedMemorySize should be adjusted to larger for more OPROMs. + // + DEBUG_CODE ( + { + UINTN EbdaBaseAddress; + UINTN ReservedEbdaBaseAddress; + + ACCESS_PAGE0_CODE ( + EbdaBaseAddress = (*(UINT16 *) (UINTN) 0x40E) << 4; + ReservedEbdaBaseAddress = CONVENTIONAL_MEMORY_TOP + - PcdGet32 (PcdEbdaReservedMemorySize); + ASSERT (ReservedEbdaBaseAddress <= EbdaBaseAddress); + ); + } + ); + + // + // Restore interrupt of debug timer + // + SaveAndSetDebugTimerInterrupt (InterruptState); + + Regs->E.EDI = ThunkRegSet.E.EDI; + Regs->E.ESI = ThunkRegSet.E.ESI; + Regs->E.EBP = ThunkRegSet.E.EBP; + Regs->E.EBX = ThunkRegSet.E.EBX; + Regs->E.EDX = ThunkRegSet.E.EDX; + Regs->E.ECX = ThunkRegSet.E.ECX; + Regs->E.EAX = ThunkRegSet.E.EAX; + Regs->X.SS = ThunkRegSet.E.SS; + Regs->X.CS = ThunkRegSet.E.CS; + Regs->X.DS = ThunkRegSet.E.DS; + Regs->X.ES = ThunkRegSet.E.ES; + + CopyMem (&(Regs->X.Flags), &(ThunkRegSet.E.EFLAGS.UintN), sizeof (Regs->X.Flags)); + + return (BOOLEAN) (Regs->X.Flags.CF == 1); +} + +/** + Allocate memory < 1 MB and copy the thunker code into low memory. Se up + all the descriptors. + + @param Private Private context for Legacy BIOS + + @retval EFI_SUCCESS Should only pass. + +**/ +EFI_STATUS +LegacyBiosInitializeThunk ( + IN LEGACY_BIOS_INSTANCE *Private + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS MemoryAddress; + UINT8 TimerVector; + + MemoryAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) Private->IntThunk; + + mThunkContext.RealModeBuffer = (VOID *) (UINTN) (MemoryAddress + ((sizeof (LOW_MEMORY_THUNK) / EFI_PAGE_SIZE) + 1) * EFI_PAGE_SIZE); + mThunkContext.RealModeBufferSize = EFI_PAGE_SIZE; + mThunkContext.ThunkAttributes = THUNK_ATTRIBUTE_BIG_REAL_MODE | THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15; + + AsmPrepareThunk16 (&mThunkContext); + + // + // Get the interrupt vector number corresponding to IRQ0 from the 8259 driver + // + TimerVector = 0; + Status = Private->Legacy8259->GetVector (Private->Legacy8259, Efi8259Irq0, &TimerVector); + ASSERT_EFI_ERROR (Status); + + // + // Check to see if the Timer AP has hooked the IRQ0 from the 8254 PIT + // + Status = Private->Cpu->RegisterInterruptHandler ( + Private->Cpu, + TimerVector, + LegacyBiosNullInterruptHandler + ); + if (Status == EFI_SUCCESS) { + // + // If the Timer AP has not enabled the 8254 timer IRQ, then force the 8254 PIT + // counter to 0, which is the CSM required rate of 54.9254 ms + // + Private->Cpu->RegisterInterruptHandler ( + Private->Cpu, + TimerVector, + NULL + ); + SetPitCount (0); + + // + // Save status that the Timer AP is not using the 8254 PIT + // + Private->TimerUses8254 = FALSE; + } else if (Status == EFI_ALREADY_STARTED) { + // + // Save status that the Timer AP is using the 8254 PIT + // + Private->TimerUses8254 = TRUE; + } else { + // + // Unexpected status from CPU AP RegisterInterruptHandler() + // + ASSERT (FALSE); + } + + return EFI_SUCCESS; +} diff --git a/OvmfPkg/Csm/LegacyBiosDxe/X64/InterruptTable.nasm b/OvmfPkg/Csm/LegacyBiosDxe/X64/InterruptTable.nasm new file mode 100644 index 0000000000..afc2f0e639 --- /dev/null +++ b/OvmfPkg/Csm/LegacyBiosDxe/X64/InterruptTable.nasm @@ -0,0 +1,64 @@ +;; @file +; Interrupt Redirection Template +; +; Copyright (c) 2016, Intel Corporation. All rights reserved.
+; +; SPDX-License-Identifier: BSD-2-Clause-Patent +; +;; + + DEFAULT REL + SECTION .text + +;---------------------------------------------------------------------------- +; Procedure: InterruptRedirectionTemplate: Redirects interrupts 0x68-0x6F +; +; Input: None +; +; Output: None +; +; Prototype: VOID +; InterruptRedirectionTemplate ( +; VOID +; ); +; +; Saves: None +; +; Modified: None +; +; Description: Contains the code that is copied into low memory (below 640K). +; This code reflects interrupts 0x68-0x6f to interrupts 0x08-0x0f. +; This template must be copied into low memory, and the IDT entries +; 0x68-0x6F must be point to the low memory copy of this code. Each +; entry is 4 bytes long, so IDT entries 0x68-0x6F can be easily +; computed. +; +;---------------------------------------------------------------------------- + +global ASM_PFX(InterruptRedirectionTemplate) +ASM_PFX(InterruptRedirectionTemplate): + int 0x8 + DB 0xcf ; IRET + nop + int 0x9 + DB 0xcf ; IRET + nop + int 0xa + DB 0xcf ; IRET + nop + int 0xb + DB 0xcf ; IRET + nop + int 0xc + DB 0xcf ; IRET + nop + int 0xd + DB 0xcf ; IRET + nop + int 0xe + DB 0xcf ; IRET + nop + int 0xf + DB 0xcf ; IRET + nop + diff --git a/OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUi.c b/OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUi.c new file mode 100644 index 0000000000..af7d80eb5f --- /dev/null +++ b/OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUi.c @@ -0,0 +1,1505 @@ +/** @file + Legacy Boot Maintainence UI implementation. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
+(C) Copyright 2018 Hewlett Packard Enterprise Development LP
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include "LegacyBootMaintUi.h" + +LEGACY_BOOT_OPTION_CALLBACK_DATA *mLegacyBootOptionPrivate = NULL; +EFI_GUID mLegacyBootOptionGuid = LEGACY_BOOT_OPTION_FORMSET_GUID; +CHAR16 mLegacyBootStorageName[] = L"LegacyBootData"; +BBS_TYPE mBbsType[] = {BBS_FLOPPY, BBS_HARDDISK, BBS_CDROM, BBS_EMBED_NETWORK, BBS_BEV_DEVICE, BBS_UNKNOWN}; +BOOLEAN mFirstEnterLegacyForm = FALSE; + + +/// +/// Legacy FD Info from LegacyBios.GetBbsInfo() +/// +LEGACY_MENU_OPTION LegacyFDMenu = { + LEGACY_MENU_OPTION_SIGNATURE, + {NULL}, + 0 +}; + +/// +/// Legacy HD Info from LegacyBios.GetBbsInfo() +/// +LEGACY_MENU_OPTION LegacyHDMenu = { + LEGACY_MENU_OPTION_SIGNATURE, + {NULL}, + 0 +}; + +/// +/// Legacy CD Info from LegacyBios.GetBbsInfo() +/// +LEGACY_MENU_OPTION LegacyCDMenu = { + LEGACY_MENU_OPTION_SIGNATURE, + {NULL}, + 0 +}; + +/// +/// Legacy NET Info from LegacyBios.GetBbsInfo() +/// +LEGACY_MENU_OPTION LegacyNETMenu = { + LEGACY_MENU_OPTION_SIGNATURE, + {NULL}, + 0 +}; + +/// +/// Legacy NET Info from LegacyBios.GetBbsInfo() +/// +LEGACY_MENU_OPTION LegacyBEVMenu = { + LEGACY_MENU_OPTION_SIGNATURE, + {NULL}, + 0 +}; + + +VOID *mLegacyStartOpCodeHandle = NULL; +VOID *mLegacyEndOpCodeHandle = NULL; +EFI_IFR_GUID_LABEL *mLegacyStartLabel = NULL; +EFI_IFR_GUID_LABEL *mLegacyEndLabel = NULL; + + +HII_VENDOR_DEVICE_PATH mLegacyBootOptionHiiVendorDevicePath = { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8) (sizeof (VENDOR_DEVICE_PATH)), + (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) + } + }, + { 0x6bc75598, 0x89b4, 0x483d, { 0x91, 0x60, 0x7f, 0x46, 0x9a, 0x96, 0x35, 0x31 } } + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + (UINT8) (END_DEVICE_PATH_LENGTH), + (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8) + } + } +}; + +/** + + Build the LegacyFDMenu LegacyHDMenu LegacyCDMenu according to LegacyBios.GetBbsInfo(). + +**/ +VOID +GetLegacyOptions ( + VOID + ); + + +/** + + Base on the L"LegacyDevOrder" variable to build the current order data. + +**/ +VOID +GetLegacyOptionsOrder ( + VOID + ); + +/** + Re-order the Boot Option according to the DevOrder. + + The routine re-orders the Boot Option in BootOption array according to + the order specified by DevOrder. + + @param DevOrder Pointer to buffer containing the BBS Index, + high 8-bit value 0xFF indicating a disabled boot option + @param DevOrderCount Count of the BBS Index + @param EnBootOption Callee allocated buffer containing the enabled Boot Option Numbers + @param EnBootOptionCount Count of the enabled Boot Option Numbers + @param DisBootOption Callee allocated buffer containing the disabled Boot Option Numbers + @param DisBootOptionCount Count of the disabled Boot Option Numbers + + @return EFI_SUCCESS The function completed successfully. + @retval other Contain some error, details see the status return by gRT->SetVariable. +**/ +EFI_STATUS +OrderLegacyBootOption4SameType ( + UINT16 *DevOrder, + UINTN DevOrderCount, + UINT16 **EnBootOption, + UINTN *EnBootOptionCount, + UINT16 **DisBootOption, + UINTN *DisBootOptionCount + ) +{ + EFI_STATUS Status; + UINT16 *NewBootOption; + UINT16 *BootOrder; + UINTN BootOrderSize; + UINTN Index; + UINTN StartPosition; + + EFI_BOOT_MANAGER_LOAD_OPTION BootOption; + + CHAR16 OptionName[sizeof ("Boot####")]; + UINT16 *BbsIndexArray; + UINT16 *DeviceTypeArray; + + GetEfiGlobalVariable2 (L"BootOrder", (VOID **) &BootOrder, &BootOrderSize); + ASSERT (BootOrder != NULL); + + BbsIndexArray = AllocatePool (BootOrderSize); + DeviceTypeArray = AllocatePool (BootOrderSize); + *EnBootOption = AllocatePool (BootOrderSize); + *DisBootOption = AllocatePool (BootOrderSize); + *DisBootOptionCount = 0; + *EnBootOptionCount = 0; + Index = 0; + Status = EFI_SUCCESS; + + ASSERT (BbsIndexArray != NULL); + ASSERT (DeviceTypeArray != NULL); + ASSERT (*EnBootOption != NULL); + ASSERT (*DisBootOption != NULL); + + for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) { + + UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", BootOrder[Index]); + Status = EfiBootManagerVariableToLoadOption (OptionName, &BootOption); + ASSERT_EFI_ERROR (Status); + + if ((DevicePathType (BootOption.FilePath) == BBS_DEVICE_PATH) && + (DevicePathSubType (BootOption.FilePath) == BBS_BBS_DP)) { + // + // Legacy Boot Option + // + ASSERT (BootOption.OptionalDataSize == sizeof (LEGACY_BOOT_OPTION_BBS_DATA)); + + DeviceTypeArray[Index] = ((BBS_BBS_DEVICE_PATH *) BootOption.FilePath)->DeviceType; + BbsIndexArray [Index] = ((LEGACY_BOOT_OPTION_BBS_DATA *) BootOption.OptionalData)->BbsIndex; + } else { + DeviceTypeArray[Index] = BBS_TYPE_UNKNOWN; + BbsIndexArray [Index] = 0xFFFF; + } + EfiBootManagerFreeLoadOption (&BootOption); + } + + // + // Record the corresponding Boot Option Numbers according to the DevOrder + // Record the EnBootOption and DisBootOption according to the DevOrder + // + StartPosition = BootOrderSize / sizeof (UINT16); + NewBootOption = AllocatePool (DevOrderCount * sizeof (UINT16)); + ASSERT (NewBootOption != NULL); + while (DevOrderCount-- != 0) { + for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) { + if (BbsIndexArray[Index] == (DevOrder[DevOrderCount] & 0xFF)) { + StartPosition = MIN (StartPosition, Index); + NewBootOption[DevOrderCount] = BootOrder[Index]; + + if ((DevOrder[DevOrderCount] & 0xFF00) == 0xFF00) { + (*DisBootOption)[*DisBootOptionCount] = BootOrder[Index]; + (*DisBootOptionCount)++; + } else { + (*EnBootOption)[*EnBootOptionCount] = BootOrder[Index]; + (*EnBootOptionCount)++; + } + break; + } + } + } + + // + // Overwrite the old BootOption + // + CopyMem (&BootOrder[StartPosition], NewBootOption, (*DisBootOptionCount + *EnBootOptionCount) * sizeof (UINT16)); + Status = gRT->SetVariable ( + L"BootOrder", + &gEfiGlobalVariableGuid, + VAR_FLAG, + BootOrderSize, + BootOrder + ); + + FreePool (NewBootOption); + FreePool (DeviceTypeArray); + FreePool (BbsIndexArray); + + return Status; +} + +/** + Update the legacy BBS boot option. L"LegacyDevOrder" and gEfiLegacyDevOrderVariableGuid EFI Variable + is udpated with the new Legacy Boot order. The EFI Variable of "Boot####" and gEfiGlobalVariableGuid + is also updated. + + @param NVMapData The data for egacy BBS boot. + + @return EFI_SUCCESS The function completed successfully. + @retval EFI_NOT_FOUND If L"LegacyDevOrder" and gEfiLegacyDevOrderVariableGuid EFI Variable can not be found. + @retval EFI_OUT_OF_RESOURCES Fail to allocate memory resource + @retval other Contain some error, details see the status return by gRT->SetVariable. +**/ +EFI_STATUS +UpdateBBSOption ( + IN LEGACY_BOOT_NV_DATA *NVMapData + ) +{ + UINTN Index; + UINTN Index2; + UINTN CurrentType; + VOID *BootOptionVar; + CHAR16 VarName[100]; + UINTN OptionSize; + EFI_STATUS Status; + UINT32 *Attribute; + LEGACY_MENU_OPTION *OptionMenu; + UINT16 *LegacyDev; + UINT16 *InitialLegacyDev; + UINT8 *VarData; + UINTN VarSize; + LEGACY_DEV_ORDER_ENTRY *DevOrder; + UINT8 *OriginalPtr; + UINT8 *DisMap; + UINTN Pos; + UINTN Bit; + UINT16 *NewOrder; + UINT16 Tmp; + UINT16 *EnBootOption; + UINTN EnBootOptionCount; + UINT16 *DisBootOption; + UINTN DisBootOptionCount; + UINTN BufferSize; + + + DisMap = NULL; + NewOrder = NULL; + CurrentType = 0; + EnBootOption = NULL; + DisBootOption = NULL; + + + DisMap = mLegacyBootOptionPrivate->MaintainMapData->DisableMap; + Status = EFI_SUCCESS; + + // + // Update the Variable "LegacyDevOrder" + // + GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID **) &VarData, &VarSize); + if (VarData == NULL) { + return EFI_NOT_FOUND; + } + OriginalPtr = VarData; + + while (mBbsType[CurrentType] != BBS_UNKNOWN) { + switch (mBbsType[CurrentType]) { + case BBS_FLOPPY: + OptionMenu = (LEGACY_MENU_OPTION *) &LegacyFDMenu; + LegacyDev = NVMapData->LegacyFD; + InitialLegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyFD; + BufferSize = sizeof (NVMapData->LegacyFD); + break; + + case BBS_HARDDISK: + OptionMenu = (LEGACY_MENU_OPTION *) &LegacyHDMenu; + LegacyDev = NVMapData->LegacyHD; + InitialLegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyHD; + + BufferSize = sizeof (NVMapData->LegacyHD); + break; + + case BBS_CDROM: + OptionMenu = (LEGACY_MENU_OPTION *) &LegacyCDMenu; + LegacyDev = NVMapData->LegacyCD; + InitialLegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyCD; + BufferSize = sizeof (NVMapData->LegacyCD); + break; + + case BBS_EMBED_NETWORK: + OptionMenu = (LEGACY_MENU_OPTION *) &LegacyNETMenu; + LegacyDev = NVMapData->LegacyNET; + InitialLegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyNET; + BufferSize = sizeof (NVMapData->LegacyNET); + break; + + default: + ASSERT (mBbsType[CurrentType] == BBS_BEV_DEVICE); + OptionMenu = (LEGACY_MENU_OPTION *) &LegacyBEVMenu; + LegacyDev = NVMapData->LegacyBEV; + InitialLegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyBEV; + BufferSize = sizeof (NVMapData->LegacyBEV); + break; + } + + // + // Check whether has value changed. + // + if (CompareMem (LegacyDev, InitialLegacyDev, BufferSize) == 0) { + CurrentType++; + continue; + } + + DevOrder = (LEGACY_DEV_ORDER_ENTRY *) OriginalPtr; + while (VarData < OriginalPtr + VarSize) { + if (DevOrder->BbsType == mBbsType[CurrentType]) { + break; + } + + VarData += sizeof (BBS_TYPE) + DevOrder->Length; + DevOrder = (LEGACY_DEV_ORDER_ENTRY *) VarData; + } + + if (VarData >= OriginalPtr + VarSize) { + FreePool (OriginalPtr); + return EFI_NOT_FOUND; + } + + NewOrder = AllocateZeroPool (DevOrder->Length - sizeof (DevOrder->Length)); + if (NewOrder == NULL) { + FreePool (OriginalPtr); + return EFI_OUT_OF_RESOURCES; + } + + for (Index = 0; Index < OptionMenu->MenuNumber; Index++) { + if (0xFF == LegacyDev[Index]) { + break; + } + + NewOrder[Index] = LegacyDev[Index]; + } + + // + // Only the enable/disable state of each boot device with same device type can be changed, + // so we can count on the index information in DevOrder. + // DisMap bit array is the only reliable source to check a device's en/dis state, + // so we use DisMap to set en/dis state of each item in NewOrder array + // + for (Index2 = 0; Index2 < OptionMenu->MenuNumber; Index2++) { + Tmp = (UINT16) (DevOrder->Data[Index2] & 0xFF); + Pos = Tmp / 8; + Bit = 7 - (Tmp % 8); + if ((DisMap[Pos] & (1 << Bit)) != 0) { + NewOrder[Index] = (UINT16) (0xFF00 | Tmp); + Index++; + } + } + + CopyMem ( + DevOrder->Data, + NewOrder, + DevOrder->Length - sizeof (DevOrder->Length) + ); + FreePool (NewOrder); + + // + // Update BootOrder and Boot####.Attribute + // + // 1. Re-order the Option Number in BootOrder according to Legacy Dev Order + // + ASSERT (OptionMenu->MenuNumber == DevOrder->Length / sizeof (UINT16) - 1); + + Status = OrderLegacyBootOption4SameType ( + DevOrder->Data, + DevOrder->Length / sizeof (UINT16) - 1, + &EnBootOption, + &EnBootOptionCount, + &DisBootOption, + &DisBootOptionCount + ); + if (EFI_ERROR(Status)) { + goto Fail; + } + + // + // 2. Deactivate the DisBootOption and activate the EnBootOption + // + for (Index = 0; Index < DisBootOptionCount; Index++) { + UnicodeSPrint (VarName, sizeof (VarName), L"Boot%04x", DisBootOption[Index]); + GetEfiGlobalVariable2 (VarName, (VOID **) &BootOptionVar, &OptionSize); + if (BootOptionVar != NULL) { + Attribute = (UINT32 *) BootOptionVar; + *Attribute &= ~LOAD_OPTION_ACTIVE; + + Status = gRT->SetVariable ( + VarName, + &gEfiGlobalVariableGuid, + VAR_FLAG, + OptionSize, + BootOptionVar + ); + + FreePool (BootOptionVar); + } + } + + for (Index = 0; Index < EnBootOptionCount; Index++) { + UnicodeSPrint (VarName, sizeof (VarName), L"Boot%04x", EnBootOption[Index]); + GetEfiGlobalVariable2 (VarName, (VOID **) &BootOptionVar, &OptionSize); + if (BootOptionVar != NULL) { + Attribute = (UINT32 *) BootOptionVar; + *Attribute |= LOAD_OPTION_ACTIVE; + + Status = gRT->SetVariable ( + VarName, + &gEfiGlobalVariableGuid, + VAR_FLAG, + OptionSize, + BootOptionVar + ); + + FreePool (BootOptionVar); + } + } + + + FreePool (EnBootOption); + FreePool (DisBootOption); + + CurrentType++; + } + + Status = gRT->SetVariable ( + VAR_LEGACY_DEV_ORDER, + &gEfiLegacyDevOrderVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, + VarSize, + OriginalPtr + ); + +Fail: + if (EnBootOption != NULL) { + FreePool (EnBootOption); + } + + if (DisBootOption != NULL) { + FreePool (DisBootOption); + } + + FreePool (OriginalPtr); + return Status; +} + +/** + This function allows a caller to extract the current configuration for one + or more named elements from the target driver. + + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Request A null-terminated Unicode string in format. + @param Progress On return, points to a character in the Request string. + Points to the string's null terminator if request was successful. + Points to the most recent '&' before the first failing name/value + pair (or the beginning of the string if the failure is in the + first name/value pair) if the request was not successful. + @param Results A null-terminated Unicode string in format which + has all values filled in for the names in the Request string. + String to be allocated by the called function. + + @retval EFI_SUCCESS The Results is filled with the requested values. + @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results. + @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver. + +**/ +EFI_STATUS +EFIAPI +LegacyBootOptionExtractConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Request, + OUT EFI_STRING *Progress, + OUT EFI_STRING *Results + ) +{ + if (Progress == NULL || Results == NULL) { + return EFI_INVALID_PARAMETER; + } + *Progress = Request; + return EFI_NOT_FOUND; +} + +/** + This function processes the results of changes in configuration. + + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Configuration A null-terminated Unicode string in format. + @param Progress A pointer to a string filled in with the offset of the most + recent '&' before the first failing name/value pair (or the + beginning of the string if the failure is in the first + name/value pair) or the terminating NULL if all was successful. + + @retval EFI_SUCCESS The Results is processed successfully. + @retval EFI_INVALID_PARAMETER Configuration is NULL. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver. + +**/ +EFI_STATUS +EFIAPI +LegacyBootOptionRouteConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Configuration, + OUT EFI_STRING *Progress + ) +{ + EFI_STATUS Status; + EFI_HII_CONFIG_ROUTING_PROTOCOL *ConfigRouting; + LEGACY_BOOT_NV_DATA *CurrentNVMapData; + UINTN BufferSize; + + + if (Configuration == NULL || Progress == NULL) { + return EFI_INVALID_PARAMETER; + } + + *Progress = Configuration; + + // + // Check routing data in . + // Note: there is no name for Name/Value storage, only GUID will be checked + // + if (!HiiIsConfigHdrMatch (Configuration, &mLegacyBootOptionGuid, mLegacyBootStorageName)) { + return EFI_NOT_FOUND; + } + + Status = gBS->LocateProtocol ( + &gEfiHiiConfigRoutingProtocolGuid, + NULL, + (VOID **) &ConfigRouting + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Convert to buffer data by helper function ConfigToBlock() + // + CurrentNVMapData = &mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData; + Status = ConfigRouting->ConfigToBlock ( + ConfigRouting, + Configuration, + (UINT8 *) CurrentNVMapData, + &BufferSize, + Progress + ); + ASSERT_EFI_ERROR (Status); + + Status = UpdateBBSOption (CurrentNVMapData); + + return Status; +} + +/** + Refresh the global UpdateData structure. + +**/ +VOID +RefreshLegacyUpdateData ( + VOID + ) +{ + // + // Free current updated date + // + if (mLegacyStartOpCodeHandle != NULL) { + HiiFreeOpCodeHandle (mLegacyStartOpCodeHandle); + } + if (mLegacyEndOpCodeHandle != NULL) { + HiiFreeOpCodeHandle (mLegacyEndOpCodeHandle); + } + + // + // Create new OpCode Handle + // + mLegacyStartOpCodeHandle = HiiAllocateOpCodeHandle (); + mLegacyEndOpCodeHandle = HiiAllocateOpCodeHandle (); + + // + // Create Hii Extend Label OpCode as the start opcode + // + mLegacyStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + mLegacyStartOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + mLegacyStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + + mLegacyStartLabel->Number = FORM_BOOT_LEGACY_DEVICE_ID; + + // + // Create Hii Extend Label OpCode as the start opcode + // + mLegacyEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + mLegacyEndOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + mLegacyEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + + mLegacyEndLabel->Number = FORM_BOOT_LEGACY_LABEL_END; + +} + +/** + Get the Menu Entry from the list in Menu Entry List. + + If MenuNumber is great or equal to the number of Menu + Entry in the list, then ASSERT. + + @param MenuOption The Menu Entry List to read the menu entry. + @param MenuNumber The index of Menu Entry. + + @return The Menu Entry. + +**/ +LEGACY_MENU_ENTRY * +GetMenuEntry ( + LEGACY_MENU_OPTION *MenuOption, + UINTN MenuNumber + ) +{ + LEGACY_MENU_ENTRY *NewMenuEntry; + UINTN Index; + LIST_ENTRY *List; + + ASSERT (MenuNumber < MenuOption->MenuNumber); + + List = MenuOption->Head.ForwardLink; + for (Index = 0; Index < MenuNumber; Index++) { + List = List->ForwardLink; + } + + NewMenuEntry = CR (List, LEGACY_MENU_ENTRY, Link, LEGACY_MENU_ENTRY_SIGNATURE); + + return NewMenuEntry; +} + +/** + Create string tokens for a menu from its help strings and display strings + + @param HiiHandle Hii Handle of the package to be updated. + @param MenuOption The Menu whose string tokens need to be created + +**/ +VOID +CreateLegacyMenuStringToken ( + IN EFI_HII_HANDLE HiiHandle, + IN LEGACY_MENU_OPTION *MenuOption + ) +{ + LEGACY_MENU_ENTRY *NewMenuEntry; + UINTN Index; + + for (Index = 0; Index < MenuOption->MenuNumber; Index++) { + NewMenuEntry = GetMenuEntry (MenuOption, Index); + + NewMenuEntry->DisplayStringToken = HiiSetString ( + HiiHandle, + 0, + NewMenuEntry->DisplayString, + NULL + ); + + if (NULL == NewMenuEntry->HelpString) { + NewMenuEntry->HelpStringToken = NewMenuEntry->DisplayStringToken; + } else { + NewMenuEntry->HelpStringToken = HiiSetString ( + HiiHandle, + 0, + NewMenuEntry->HelpString, + NULL + ); + } + } +} + +/** + Create a dynamic page so that Legacy Device boot order + can be set for specified device type. + + @param UpdatePageId The form ID. It also spefies the legacy device type. + + +**/ +VOID +UpdateLegacyDeviceOrderPage ( + IN UINT16 UpdatePageId + ) +{ + LEGACY_MENU_OPTION *OptionMenu; + LEGACY_MENU_ENTRY *NewMenuEntry; + EFI_STRING_ID StrRef; + EFI_STRING_ID StrRefHelp; + UINT16 *Default; + UINT16 Index; + UINT16 Key; + CHAR16 String[100]; + CHAR16 *TypeStr; + CHAR16 *TypeStrHelp; + CHAR16 *FormTitle; + VOID *OptionsOpCodeHandle; + VOID *DefaultOpCodeHandle; + + Key = 0; + StrRef = 0; + StrRefHelp = 0; + OptionMenu = NULL; + TypeStr = NULL; + TypeStrHelp = NULL; + Default = NULL; + + RefreshLegacyUpdateData(); + + // + // Create oneof option list + // + switch (UpdatePageId) { + case FORM_FLOPPY_BOOT_ID: + OptionMenu = (LEGACY_MENU_OPTION *) &LegacyFDMenu; + Key = (UINT16) LEGACY_FD_QUESTION_ID; + TypeStr = STR_FLOPPY; + TypeStrHelp = STR_FLOPPY_HELP; + FormTitle = STR_FLOPPY_TITLE; + Default = mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData.LegacyFD; + break; + + case FORM_HARDDISK_BOOT_ID: + OptionMenu = (LEGACY_MENU_OPTION *) &LegacyHDMenu; + Key = (UINT16) LEGACY_HD_QUESTION_ID; + TypeStr = STR_HARDDISK; + TypeStrHelp = STR_HARDDISK_HELP; + FormTitle = STR_HARDDISK_TITLE; + Default = mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData.LegacyHD; + break; + + case FORM_CDROM_BOOT_ID: + OptionMenu = (LEGACY_MENU_OPTION *) &LegacyCDMenu; + Key = (UINT16) LEGACY_CD_QUESTION_ID; + TypeStr = STR_CDROM; + TypeStrHelp = STR_CDROM_HELP; + FormTitle = STR_CDROM_TITLE; + Default = mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData.LegacyCD; + break; + + case FORM_NET_BOOT_ID: + OptionMenu = (LEGACY_MENU_OPTION *) &LegacyNETMenu; + Key = (UINT16) LEGACY_NET_QUESTION_ID; + TypeStr = STR_NET; + TypeStrHelp = STR_NET_HELP; + FormTitle = STR_NET_TITLE; + Default = mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData.LegacyNET; + break; + + case FORM_BEV_BOOT_ID: + OptionMenu = (LEGACY_MENU_OPTION *) &LegacyBEVMenu; + Key = (UINT16) LEGACY_BEV_QUESTION_ID; + TypeStr = STR_BEV; + TypeStrHelp = STR_BEV_HELP; + FormTitle = STR_BEV_TITLE; + Default = mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData.LegacyBEV; + break; + + default: + DEBUG ((EFI_D_ERROR, "Invalid command ID for updating page!\n")); + return; + } + + HiiSetString (mLegacyBootOptionPrivate->HiiHandle, STRING_TOKEN(STR_ORDER_CHANGE_PROMPT), FormTitle, NULL); + + CreateLegacyMenuStringToken (mLegacyBootOptionPrivate->HiiHandle, OptionMenu); + + OptionsOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (OptionsOpCodeHandle != NULL); + + + for (Index = 0; Index < OptionMenu->MenuNumber; Index++) { + NewMenuEntry = GetMenuEntry (OptionMenu, Index); + // + // Create OneOf for each legacy device + // + HiiCreateOneOfOptionOpCode ( + OptionsOpCodeHandle, + NewMenuEntry->DisplayStringToken, + 0, + EFI_IFR_TYPE_NUM_SIZE_16, + ((LEGACY_DEVICE_CONTEXT *) NewMenuEntry->VariableContext)->BbsIndex + ); + } + + // + // Create OneOf for item "Disabled" + // + HiiCreateOneOfOptionOpCode ( + OptionsOpCodeHandle, + STRING_TOKEN (STR_DISABLE_LEGACY_DEVICE), + 0, + EFI_IFR_TYPE_NUM_SIZE_16, + 0xFF + ); + + // + // Create oneof tag here for FD/HD/CD #1 #2 + // + for (Index = 0; Index < OptionMenu->MenuNumber; Index++) { + DefaultOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (DefaultOpCodeHandle != NULL); + + HiiCreateDefaultOpCode ( + DefaultOpCodeHandle, + EFI_HII_DEFAULT_CLASS_STANDARD, + EFI_IFR_TYPE_NUM_SIZE_16, + *Default++ + ); + + // + // Create the string for oneof tag + // + UnicodeSPrint (String, sizeof (String), TypeStr, Index); + StrRef = HiiSetString (mLegacyBootOptionPrivate->HiiHandle, 0, String, NULL); + + UnicodeSPrint (String, sizeof (String), TypeStrHelp, Index); + StrRefHelp = HiiSetString (mLegacyBootOptionPrivate->HiiHandle, 0, String, NULL); + + HiiCreateOneOfOpCode ( + mLegacyStartOpCodeHandle, + (EFI_QUESTION_ID) (Key + Index), + VARSTORE_ID_LEGACY_BOOT, + (UINT16) (Key + Index * 2 - CONFIG_OPTION_OFFSET), + StrRef, + StrRefHelp, + EFI_IFR_FLAG_CALLBACK, + EFI_IFR_NUMERIC_SIZE_2, + OptionsOpCodeHandle, + DefaultOpCodeHandle //NULL // + ); + + HiiFreeOpCodeHandle (DefaultOpCodeHandle); + } + + HiiUpdateForm ( + mLegacyBootOptionPrivate->HiiHandle, + &mLegacyBootOptionGuid, + LEGACY_ORDER_CHANGE_FORM_ID, + mLegacyStartOpCodeHandle, + mLegacyEndOpCodeHandle + ); + + HiiFreeOpCodeHandle (OptionsOpCodeHandle); +} + + +/** + Adjust question value when one question value has been changed. + + @param QuestionId The question id for the value changed question. + @param Value The value for the changed question. + +**/ +VOID +AdjustOptionValue ( + IN UINT16 QuestionId, + IN EFI_IFR_TYPE_VALUE *Value + ) +{ + UINTN Number; + UINT16 *Default; + LEGACY_BOOT_NV_DATA *CurrentNVMap; + UINT16 *CurrentVal; + UINTN Index; + UINTN Index2; + UINTN Index3; + UINTN NewValuePos; + UINTN OldValue; + UINTN NewValue; + UINT8 *DisMap; + UINTN Pos; + UINTN Bit; + + Number = 0; + CurrentVal = 0; + Default = NULL; + NewValue = 0; + NewValuePos = 0; + OldValue = 0; + + // + // Update Select FD/HD/CD/NET/BEV Order Form + // + ASSERT ((QuestionId >= LEGACY_FD_QUESTION_ID) && (QuestionId < LEGACY_BEV_QUESTION_ID + MAX_MENU_NUMBER)); + + CurrentNVMap = &mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData; + HiiGetBrowserData (&mLegacyBootOptionGuid, mLegacyBootStorageName, sizeof (LEGACY_BOOT_NV_DATA), (UINT8 *) CurrentNVMap); + DisMap = mLegacyBootOptionPrivate->MaintainMapData->DisableMap; + + if (QuestionId >= LEGACY_FD_QUESTION_ID && QuestionId < LEGACY_FD_QUESTION_ID + MAX_MENU_NUMBER) { + Number = (UINT16) LegacyFDMenu.MenuNumber; + CurrentVal = CurrentNVMap->LegacyFD; + Default = mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData.LegacyFD; + } else if (QuestionId >= LEGACY_HD_QUESTION_ID && QuestionId < LEGACY_HD_QUESTION_ID + MAX_MENU_NUMBER) { + Number = (UINT16) LegacyHDMenu.MenuNumber; + CurrentVal = CurrentNVMap->LegacyHD; + Default = mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData.LegacyHD; + } else if (QuestionId >= LEGACY_CD_QUESTION_ID && QuestionId < LEGACY_CD_QUESTION_ID + MAX_MENU_NUMBER) { + Number = (UINT16) LegacyCDMenu.MenuNumber; + CurrentVal = CurrentNVMap->LegacyCD; + Default = mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData.LegacyCD; + } else if (QuestionId >= LEGACY_NET_QUESTION_ID && QuestionId < LEGACY_NET_QUESTION_ID + MAX_MENU_NUMBER) { + Number = (UINT16) LegacyNETMenu.MenuNumber; + CurrentVal = CurrentNVMap->LegacyNET; + Default = mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData.LegacyNET; + } else if (QuestionId >= LEGACY_BEV_QUESTION_ID && QuestionId < LEGACY_BEV_QUESTION_ID + MAX_MENU_NUMBER) { + Number = (UINT16) LegacyBEVMenu.MenuNumber; + CurrentVal = CurrentNVMap->LegacyBEV; + Default = mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData.LegacyBEV; + } + + // + // First, find the different position + // if there is change, it should be only one + // + for (Index = 0; Index < Number; Index++) { + if (CurrentVal[Index] != Default[Index]) { + OldValue = Default[Index]; + NewValue = CurrentVal[Index]; + break; + } + } + + if (Index != Number) { + // + // there is change, now process + // + if (0xFF == NewValue) { + // + // This item will be disable + // Just move the items behind this forward to overlap it + // + Pos = OldValue / 8; + Bit = 7 - (OldValue % 8); + DisMap[Pos] = (UINT8) (DisMap[Pos] | (UINT8) (1 << Bit)); + for (Index2 = Index; Index2 < Number - 1; Index2++) { + CurrentVal[Index2] = CurrentVal[Index2 + 1]; + } + + CurrentVal[Index2] = 0xFF; + } else { + for (Index2 = 0; Index2 < Number; Index2++) { + if (Index2 == Index) { + continue; + } + + if (Default[Index2] == NewValue) { + // + // If NewValue is in OldLegacyDev array + // remember its old position + // + NewValuePos = Index2; + break; + } + } + + if (Index2 != Number) { + // + // We will change current item to an existing item + // (It's hard to describe here, please read code, it's like a cycle-moving) + // + for (Index2 = NewValuePos; Index2 != Index;) { + if (NewValuePos < Index) { + CurrentVal[Index2] = Default[Index2 + 1]; + Index2++; + } else { + CurrentVal[Index2] = Default[Index2 - 1]; + Index2--; + } + } + } else { + // + // If NewValue is not in OldlegacyDev array, we are changing to a disabled item + // so we should modify DisMap to reflect the change + // + Pos = NewValue / 8; + Bit = 7 - (NewValue % 8); + DisMap[Pos] = (UINT8) (DisMap[Pos] & (~ (UINT8) (1 << Bit))); + if (0xFF != OldValue) { + // + // Because NewValue is a item that was disabled before + // so after changing the OldValue should be disabled + // actually we are doing a swap of enable-disable states of two items + // + Pos = OldValue / 8; + Bit = 7 - (OldValue % 8); + DisMap[Pos] = (UINT8) (DisMap[Pos] | (UINT8) (1 << Bit)); + } + } + } + // + // To prevent DISABLE appears in the middle of the list + // we should perform a re-ordering + // + Index3 = Index; + Index = 0; + while (Index < Number) { + if (0xFF != CurrentVal[Index]) { + Index++; + continue; + } + + Index2 = Index; + Index2++; + while (Index2 < Number) { + if (0xFF != CurrentVal[Index2]) { + break; + } + + Index2++; + } + + if (Index2 < Number) { + CurrentVal[Index] = CurrentVal[Index2]; + CurrentVal[Index2] = 0xFF; + } + + Index++; + } + + // + // Return correct question value. + // + Value->u16 = CurrentVal[Index3]; + CopyMem (Default, CurrentVal, sizeof (UINT16) * Number); + } + + // + // Pass changed uncommitted data back to Form Browser + // + HiiSetBrowserData (&mLegacyBootOptionGuid, mLegacyBootStorageName, sizeof (LEGACY_BOOT_NV_DATA), (UINT8 *) CurrentNVMap, NULL); +} + +/** + This call back function is registered with Boot Manager formset. + When user selects a boot option, this call back function will + be triggered. The boot option is saved for later processing. + + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Action Specifies the type of action taken by the browser. + @param QuestionId A unique value which is sent to the original exporting driver + so that it can identify the type of data to expect. + @param Type The type of value for the question. + @param Value A pointer to the data being sent to the original exporting driver. + @param ActionRequest On return, points to the action requested by the callback function. + + @retval EFI_SUCCESS The callback successfully handled the action. + @retval EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters. + +**/ +EFI_STATUS +EFIAPI +LegacyBootOptionCallback ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN EFI_BROWSER_ACTION Action, + IN EFI_QUESTION_ID QuestionId, + IN UINT8 Type, + IN EFI_IFR_TYPE_VALUE *Value, + OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest + ) +{ + if (Action != EFI_BROWSER_ACTION_CHANGED && Action != EFI_BROWSER_ACTION_CHANGING && Action != EFI_BROWSER_ACTION_FORM_OPEN) { + // + // Do nothing for other UEFI Action. Only do call back when data is changed or the form is open. + // + return EFI_UNSUPPORTED; + } + + if ((Value == NULL) || (ActionRequest == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (Action == EFI_BROWSER_ACTION_FORM_OPEN) { + if (QuestionId == FORM_FLOPPY_BOOT_ID) { + if (!mFirstEnterLegacyForm) { + // + // The leagcyBootMaintUiLib depends on the LegacyBootManagerLib to realize its functionality. + // We need to do the leagcy boot options related actions after the LegacyBootManagerLib has been initialized. + // Opening the legacy menus is the appropriate time that the LegacyBootManagerLib has already been initialized. + // + mFirstEnterLegacyForm = TRUE; + GetLegacyOptions (); + GetLegacyOptionsOrder (); + } + } + } + + if (Action == EFI_BROWSER_ACTION_CHANGING) { + switch (QuestionId) { + case FORM_FLOPPY_BOOT_ID: + case FORM_HARDDISK_BOOT_ID: + case FORM_CDROM_BOOT_ID: + case FORM_NET_BOOT_ID: + case FORM_BEV_BOOT_ID: + UpdateLegacyDeviceOrderPage (QuestionId); + break; + + default: + break; + } + } else if (Action == EFI_BROWSER_ACTION_CHANGED) { + if ((Value == NULL) || (ActionRequest == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((QuestionId >= LEGACY_FD_QUESTION_ID) && (QuestionId < LEGACY_BEV_QUESTION_ID + MAX_MENU_NUMBER)) { + AdjustOptionValue(QuestionId, Value); + } + } + return EFI_SUCCESS; +} + + +/** + Create a menu entry by given menu type. + + @param MenuType The Menu type to be created. + + @retval NULL If failed to create the menu. + @return the new menu entry. + +**/ +LEGACY_MENU_ENTRY * +CreateMenuEntry ( + VOID + ) +{ + LEGACY_MENU_ENTRY *MenuEntry; + + // + // Create new menu entry + // + MenuEntry = AllocateZeroPool (sizeof (LEGACY_MENU_ENTRY)); + if (MenuEntry == NULL) { + return NULL; + } + + MenuEntry->VariableContext = AllocateZeroPool (sizeof (LEGACY_DEVICE_CONTEXT)); + if (MenuEntry->VariableContext == NULL) { + FreePool (MenuEntry); + return NULL; + } + + MenuEntry->Signature = LEGACY_MENU_ENTRY_SIGNATURE; + return MenuEntry; +} + +/** + + Base on the L"LegacyDevOrder" variable to build the current order data. + +**/ +VOID +GetLegacyOptionsOrder ( + VOID + ) +{ + UINTN VarSize; + UINT8 *VarData; + UINT8 *VarTmp; + LEGACY_DEV_ORDER_ENTRY *DevOrder; + UINT16 *LegacyDev; + UINTN Index; + LEGACY_MENU_OPTION *OptionMenu; + UINT16 VarDevOrder; + UINTN Pos; + UINTN Bit; + UINT8 *DisMap; + UINTN TotalLength; + + LegacyDev = NULL; + OptionMenu = NULL; + + DisMap = ZeroMem (mLegacyBootOptionPrivate->MaintainMapData->DisableMap, sizeof (mLegacyBootOptionPrivate->MaintainMapData->DisableMap)); + + // + // Get Device Order from variable + // + GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID **) &VarData, &VarSize); + VarTmp = VarData; + if (NULL != VarData) { + DevOrder = (LEGACY_DEV_ORDER_ENTRY *) VarData; + while (VarData < VarTmp + VarSize) { + switch (DevOrder->BbsType) { + case BBS_FLOPPY: + LegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyFD; + OptionMenu = &LegacyFDMenu; + break; + + case BBS_HARDDISK: + LegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyHD; + OptionMenu = &LegacyHDMenu; + break; + + case BBS_CDROM: + LegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyCD; + OptionMenu = &LegacyCDMenu; + break; + + case BBS_EMBED_NETWORK: + LegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyNET; + OptionMenu = &LegacyNETMenu; + break; + + case BBS_BEV_DEVICE: + LegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyBEV; + OptionMenu = &LegacyBEVMenu; + break; + + case BBS_UNKNOWN: + default: + ASSERT (FALSE); + DEBUG ((DEBUG_ERROR, "Unsupported device type found!\n")); + break; + } + + // + // Create oneof tag here for FD/HD/CD #1 #2 + // + for (Index = 0; Index < OptionMenu->MenuNumber; Index++) { + TotalLength = sizeof (BBS_TYPE) + sizeof (UINT16) + Index * sizeof (UINT16); + VarDevOrder = *(UINT16 *) ((UINT8 *) DevOrder + TotalLength); + + if (0xFF00 == (VarDevOrder & 0xFF00)) { + LegacyDev[Index] = 0xFF; + Pos = (VarDevOrder & 0xFF) / 8; + Bit = 7 - ((VarDevOrder & 0xFF) % 8); + DisMap[Pos] = (UINT8) (DisMap[Pos] | (UINT8) (1 << Bit)); + } else { + LegacyDev[Index] = VarDevOrder & 0xFF; + } + } + + VarData ++; + VarData += *(UINT16 *) VarData; + DevOrder = (LEGACY_DEV_ORDER_ENTRY *) VarData; + } + } + + CopyMem (&mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData, &mLegacyBootOptionPrivate->MaintainMapData->InitialNvData, sizeof (LEGACY_BOOT_NV_DATA)); + CopyMem (&mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData, &mLegacyBootOptionPrivate->MaintainMapData->InitialNvData, sizeof (LEGACY_BOOT_NV_DATA)); +} + +/** + + Build the LegacyFDMenu LegacyHDMenu LegacyCDMenu according to LegacyBios.GetBbsInfo(). + +**/ +VOID +GetLegacyOptions ( + VOID + ) +{ + LEGACY_MENU_ENTRY *NewMenuEntry; + LEGACY_DEVICE_CONTEXT *NewLegacyDevContext; + EFI_BOOT_MANAGER_LOAD_OPTION *BootOption; + UINTN BootOptionCount; + UINT16 Index; + UINTN FDNum; + UINTN HDNum; + UINTN CDNum; + UINTN NETNum; + UINTN BEVNum; + + // + // Initialize Bbs Table Context from BBS info data + // + InitializeListHead (&LegacyFDMenu.Head); + InitializeListHead (&LegacyHDMenu.Head); + InitializeListHead (&LegacyCDMenu.Head); + InitializeListHead (&LegacyNETMenu.Head); + InitializeListHead (&LegacyBEVMenu.Head); + + FDNum = 0; + HDNum = 0; + CDNum = 0; + NETNum = 0; + BEVNum = 0; + + EfiBootManagerConnectAll (); + + // + // for better user experience + // 1. User changes HD configuration (e.g.: unplug HDD), here we have a chance to remove the HDD boot option + // 2. User enables/disables UEFI PXE, here we have a chance to add/remove EFI Network boot option + // + EfiBootManagerRefreshAllBootOption (); + + BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot); + for (Index = 0; Index < BootOptionCount; Index++) { + if ((DevicePathType (BootOption[Index].FilePath) != BBS_DEVICE_PATH) || + (DevicePathSubType (BootOption[Index].FilePath) != BBS_BBS_DP) + ) { + continue; + } + ASSERT (BootOption[Index].OptionalDataSize == sizeof (LEGACY_BOOT_OPTION_BBS_DATA)); + NewMenuEntry = CreateMenuEntry (); + ASSERT (NewMenuEntry != NULL); + + NewLegacyDevContext = (LEGACY_DEVICE_CONTEXT *) NewMenuEntry->VariableContext; + NewLegacyDevContext->BbsIndex = ((LEGACY_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex; + NewLegacyDevContext->Description = AllocateCopyPool (StrSize (BootOption[Index].Description), BootOption[Index].Description); + ASSERT (NewLegacyDevContext->Description != NULL); + + NewMenuEntry->DisplayString = NewLegacyDevContext->Description; + NewMenuEntry->HelpString = NULL; + + switch (((BBS_BBS_DEVICE_PATH *) BootOption[Index].FilePath)->DeviceType) { + case BBS_TYPE_FLOPPY: + InsertTailList (&LegacyFDMenu.Head, &NewMenuEntry->Link); + FDNum++; + break; + + case BBS_TYPE_HARDDRIVE: + InsertTailList (&LegacyHDMenu.Head, &NewMenuEntry->Link); + HDNum++; + break; + + case BBS_TYPE_CDROM: + InsertTailList (&LegacyCDMenu.Head, &NewMenuEntry->Link); + CDNum++; + break; + + case BBS_TYPE_EMBEDDED_NETWORK: + InsertTailList (&LegacyNETMenu.Head, &NewMenuEntry->Link); + NETNum++; + break; + + case BBS_TYPE_BEV: + InsertTailList (&LegacyBEVMenu.Head, &NewMenuEntry->Link); + BEVNum++; + break; + } + } + + EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount); + + LegacyFDMenu.MenuNumber = FDNum; + LegacyHDMenu.MenuNumber = HDNum; + LegacyCDMenu.MenuNumber = CDNum; + LegacyNETMenu.MenuNumber = NETNum; + LegacyBEVMenu.MenuNumber = BEVNum; +} + + +/** + + Install Boot Manager Menu driver. + + @param ImageHandle The image handle. + @param SystemTable The system table. + + @retval EFI_SUCEESS Install Boot manager menu success. + @retval Other Return error status. + +**/ +EFI_STATUS +EFIAPI +LegacyBootMaintUiLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + LEGACY_BOOT_OPTION_CALLBACK_DATA *LegacyBootOptionData; + + Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios); + if (!EFI_ERROR (Status)) { + // + // Create LegacyBootOptionData structures for Driver Callback + // + LegacyBootOptionData = AllocateZeroPool (sizeof (LEGACY_BOOT_OPTION_CALLBACK_DATA)); + ASSERT (LegacyBootOptionData != NULL); + + LegacyBootOptionData->MaintainMapData = AllocateZeroPool (sizeof (LEGACY_BOOT_MAINTAIN_DATA)); + ASSERT (LegacyBootOptionData->MaintainMapData != NULL); + + LegacyBootOptionData->ConfigAccess.ExtractConfig = LegacyBootOptionExtractConfig; + LegacyBootOptionData->ConfigAccess.RouteConfig = LegacyBootOptionRouteConfig; + LegacyBootOptionData->ConfigAccess.Callback = LegacyBootOptionCallback; + + // + // Install Device Path Protocol and Config Access protocol to driver handle + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &LegacyBootOptionData->DriverHandle, + &gEfiDevicePathProtocolGuid, + &mLegacyBootOptionHiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + &LegacyBootOptionData->ConfigAccess, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // + // Publish our HII data + // + LegacyBootOptionData->HiiHandle = HiiAddPackages ( + &mLegacyBootOptionGuid, + LegacyBootOptionData->DriverHandle, + LegacyBootMaintUiVfrBin, + LegacyBootMaintUiLibStrings, + NULL + ); + ASSERT (LegacyBootOptionData->HiiHandle != NULL); + + mLegacyBootOptionPrivate = LegacyBootOptionData; + } + + return EFI_SUCCESS; +} + +/** + Destructor of Customized Display Library Instance. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The destructor completed successfully. + @retval Other value The destructor did not complete successfully. + +**/ +EFI_STATUS +EFIAPI +LegacyBootMaintUiLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + if (mLegacyBootOptionPrivate != NULL && mLegacyBootOptionPrivate->DriverHandle != NULL) { + Status = gBS->UninstallMultipleProtocolInterfaces ( + mLegacyBootOptionPrivate->DriverHandle, + &gEfiDevicePathProtocolGuid, + &mLegacyBootOptionHiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + &mLegacyBootOptionPrivate->ConfigAccess, + NULL + ); + ASSERT_EFI_ERROR (Status); + + HiiRemovePackages (mLegacyBootOptionPrivate->HiiHandle); + + FreePool (mLegacyBootOptionPrivate->MaintainMapData); + FreePool (mLegacyBootOptionPrivate); + } + + return EFI_SUCCESS; +} + diff --git a/OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUi.h b/OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUi.h new file mode 100644 index 0000000000..0c491318c2 --- /dev/null +++ b/OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUi.h @@ -0,0 +1,249 @@ +/** @file + Legacy boot maintainence Ui definition. + +Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef _EFI_LEGACY_BOOT_OPTION_H_ +#define _EFI_LEGACY_BOOT_OPTION_H_ + +#include + + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "LegacyBootMaintUiVfr.h" + +#define CONFIG_OPTION_OFFSET 0x1200 + +// +// VarOffset that will be used to create question +// all these values are computed from the structure +// defined below +// +#define VAR_OFFSET(Field) ((UINT16) ((UINTN) &(((LEGACY_BOOT_NV_DATA *) 0)->Field))) + +// +// Question Id of Zero is invalid, so add an offset to it +// +#define QUESTION_ID(Field) (VAR_OFFSET (Field) + CONFIG_OPTION_OFFSET) + + +#define LEGACY_FD_QUESTION_ID QUESTION_ID (LegacyFD) +#define LEGACY_HD_QUESTION_ID QUESTION_ID (LegacyHD) +#define LEGACY_CD_QUESTION_ID QUESTION_ID (LegacyCD) +#define LEGACY_NET_QUESTION_ID QUESTION_ID (LegacyNET) +#define LEGACY_BEV_QUESTION_ID QUESTION_ID (LegacyBEV) + + +// +// String Contant +// +#define STR_FLOPPY L"Floppy Drive #%02x" +#define STR_HARDDISK L"HardDisk Drive #%02x" +#define STR_CDROM L"ATAPI CDROM Drive #%02x" +#define STR_NET L"NET Drive #%02x" +#define STR_BEV L"BEV Drive #%02x" + +#define STR_FLOPPY_HELP L"Select Floppy Drive #%02x" +#define STR_HARDDISK_HELP L"Select HardDisk Drive #%02x" +#define STR_CDROM_HELP L"Select ATAPI CDROM Drive #%02x" +#define STR_NET_HELP L"NET Drive #%02x" +#define STR_BEV_HELP L"BEV Drive #%02x" + +#define STR_FLOPPY_TITLE L"Set Legacy Floppy Drive Order" +#define STR_HARDDISK_TITLE L"Set Legacy HardDisk Drive Order" +#define STR_CDROM_TITLE L"Set Legacy CDROM Drive Order" +#define STR_NET_TITLE L"Set Legacy NET Drive Order" +#define STR_BEV_TITLE L"Set Legacy BEV Drive Order" + +// +// These are the VFR compiler generated data representing our VFR data. +// +extern UINT8 LegacyBootMaintUiVfrBin[]; + +#pragma pack(1) + +/// +/// HII specific Vendor Device Path definition. +/// +typedef struct { + VENDOR_DEVICE_PATH VendorDevicePath; + EFI_DEVICE_PATH_PROTOCOL End; +} HII_VENDOR_DEVICE_PATH; + + + +// +// Variable created with this flag will be "Efi:...." +// +#define VAR_FLAG EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE + + +#define LEGACY_BOOT_OPTION_CALLBACK_DATA_SIGNATURE SIGNATURE_32 ('L', 'G', 'C', 'B') + +typedef struct { + UINTN Signature; + + // + // HII relative handles + // + EFI_HII_HANDLE HiiHandle; + EFI_HANDLE DriverHandle; + + // + // Produced protocols + // + EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess; + + // + // Maintain the data. + // + LEGACY_BOOT_MAINTAIN_DATA *MaintainMapData; +} LEGACY_BOOT_OPTION_CALLBACK_DATA; + +// +// All of the signatures that will be used in list structure +// +#define LEGACY_MENU_OPTION_SIGNATURE SIGNATURE_32 ('m', 'e', 'n', 'u') +#define LEGACY_MENU_ENTRY_SIGNATURE SIGNATURE_32 ('e', 'n', 't', 'r') + +#define LEGACY_LEGACY_DEV_CONTEXT_SELECT 0x9 + +typedef struct { + UINTN Signature; + LIST_ENTRY Head; + UINTN MenuNumber; +} LEGACY_MENU_OPTION; + +typedef struct { + UINT16 BbsIndex; + CHAR16 *Description; +} LEGACY_DEVICE_CONTEXT; + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; + UINTN OptionNumber; + UINT16 *DisplayString; + UINT16 *HelpString; + EFI_STRING_ID DisplayStringToken; + EFI_STRING_ID HelpStringToken; + VOID *VariableContext; +} LEGACY_MENU_ENTRY; + +typedef struct { + UINT16 BbsIndex; +} LEGACY_BOOT_OPTION_BBS_DATA; + +#pragma pack() + +/** + This call back function is registered with Boot Manager formset. + When user selects a boot option, this call back function will + be triggered. The boot option is saved for later processing. + + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Action Specifies the type of action taken by the browser. + @param QuestionId A unique value which is sent to the original exporting driver + so that it can identify the type of data to expect. + @param Type The type of value for the question. + @param Value A pointer to the data being sent to the original exporting driver. + @param ActionRequest On return, points to the action requested by the callback function. + + @retval EFI_SUCCESS The callback successfully handled the action. + @retval EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters. + +**/ +EFI_STATUS +EFIAPI +LegacyBootOptionCallback ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN EFI_BROWSER_ACTION Action, + IN EFI_QUESTION_ID QuestionId, + IN UINT8 Type, + IN EFI_IFR_TYPE_VALUE *Value, + OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest + ); + +/** + This function allows a caller to extract the current configuration for one + or more named elements from the target driver. + + + @param This - Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Request - A null-terminated Unicode string in format. + @param Progress - On return, points to a character in the Request string. + Points to the string's null terminator if request was successful. + Points to the most recent '&' before the first failing name/value + pair (or the beginning of the string if the failure is in the + first name/value pair) if the request was not successful. + @param Results - A null-terminated Unicode string in format which + has all values filled in for the names in the Request string. + String to be allocated by the called function. + + @retval EFI_SUCCESS The Results is filled with the requested values. + @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results. + @retval EFI_INVALID_PARAMETER Request is NULL, illegal syntax, or unknown name. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver. + +**/ +EFI_STATUS +EFIAPI +LegacyBootOptionExtractConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Request, + OUT EFI_STRING *Progress, + OUT EFI_STRING *Results + ); + +/** + This function processes the results of changes in configuration. + + + @param This - Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Configuration - A null-terminated Unicode string in format. + @param Progress - A pointer to a string filled in with the offset of the most + recent '&' before the first failing name/value pair (or the + beginning of the string if the failure is in the first + name/value pair) or the terminating NULL if all was successful. + + @retval EFI_SUCCESS The Results is processed successfully. + @retval EFI_INVALID_PARAMETER Configuration is NULL. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver. + +**/ +EFI_STATUS +EFIAPI +LegacyBootOptionRouteConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Configuration, + OUT EFI_STRING *Progress + ); + +#endif diff --git a/OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUiLib.inf b/OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUiLib.inf new file mode 100644 index 0000000000..557b8d8169 --- /dev/null +++ b/OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUiLib.inf @@ -0,0 +1,63 @@ +## @file +# Legacy Boot Maintainence UI module is library for BDS phase. +# +# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = LegacyBootMaintUiLib + MODULE_UNI_FILE = LegacyBootMaintUiLib.uni + FILE_GUID = e6f7f038-3ed9-401a-af1f-5ea7bf644d34 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL|DXE_DRIVER UEFI_APPLICATION + CONSTRUCTOR = LegacyBootMaintUiLibConstructor + DESTRUCTOR = LegacyBootMaintUiLibDestructor +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + LegacyBootMaintUiVfr.h + LegacyBootMaintUi.h + LegacyBootMaintUiVfr.Vfr + LegacyBootMaintUiStrings.uni + LegacyBootMaintUi.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + +[LibraryClasses] + DevicePathLib + BaseLib + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + DebugLib + HiiLib + MemoryAllocationLib + UefiBootManagerLib + UefiLib + PrintLib + BaseMemoryLib + +[Guids] + gEfiIfrTianoGuid ## SOMETIMES_PRODUCES ## UNDEFINED # Extended IFR Guid Opcode + gEfiIfrBootMaintenanceGuid ## CONSUMES ## HII # BootMaint HII Package + gEfiLegacyDevOrderVariableGuid ## PRODUCES ## Variable:L"LegacyDevOrder" + +[Protocols] + gEfiHiiConfigAccessProtocolGuid ## PRODUCES + gEfiLegacyBiosProtocolGuid ## CONSUMES + gEfiHiiConfigRoutingProtocolGuid ## CONSUMES + +[Depex] + gEfiHiiDatabaseProtocolGuid + diff --git a/OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUiLib.uni b/OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUiLib.uni new file mode 100644 index 0000000000..c2c100d378 --- /dev/null +++ b/OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUiLib.uni @@ -0,0 +1,20 @@ +// /** @file +// Legacy Boot Maintainence UI module is library for BDS phase. +// +// Legacy Boot Maintainence UI module is library for BDS phase. +// +// Copyright (c) 2015, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT +#language en-US +"Legacy Boot Maintainence UI module is library for BDS phase." + +#string STR_MODULE_DESCRIPTION +#language en-US +"Legacy Boot Maintainence UI module is library for BDS phase." + + diff --git a/OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUiStrings.uni b/OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUiStrings.uni new file mode 100644 index 0000000000..8d40ca1af1 --- /dev/null +++ b/OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUiStrings.uni @@ -0,0 +1,43 @@ +///** @file +// +// String definitions for Legacy Boot Maintainece Ui. +// +// Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +//**/ + +/=# + +#langdef en-US "English" +#langdef fr-FR "Français" + +#string STR_LEGACY_BOOT_PROMPT #language en-US "Legacy Boot Options Menu" + #language fr-FR "Legacy Boot Options Menu" +#string STR_LEGACY_BOOT_HELP #language en-US "Manager legacy boot options in this driver." + #language fr-FR "Manager legacy boot options in this driver." +#string STR_FORM_FLOPPY_BOOT_TITLE #language en-US "Set Legacy Floppy Driver Order" + #language fr-FR "Set Legacy Floppy Driver Order" +#string STR_FORM_FLOPPY_BOOT_HELP #language en-US "Set Legacy Floppy Driver Order." + #language fr-FR "Set Legacy Floppy Driver Order." +#string STR_FORM_HARDDISK_BOOT_TITLE #language en-US "Set Legacy HARDDISK Driver Order" + #language fr-FR "Set Legacy HARDDISK Driver Order" +#string STR_FORM_HARDDISK_BOOT_HELP #language en-US "Set Legacy HARDDISK Driver Order." + #language fr-FR "Set Legacy HARDDISK Driver Order." +#string STR_FORM_CDROM_BOOT_TITLE #language en-US "Set Legacy CDROM Driver Order" + #language fr-FR "Set Legacy CDROM Driver Order" +#string STR_FORM_CDROM_BOOT_HELP #language en-US "Set Legacy CDROM Driver Order." + #language fr-FR "Set Legacy CDROM Driver Order." +#string STR_FORM_NET_BOOT_TITLE #language en-US "Set Legacy NET Driver Order" + #language fr-FR "Set Legacy NET Driver Order" +#string STR_FORM_NET_BOOT_HELP #language en-US "Set Legacy NET Driver Order." + #language fr-FR "Set Legacy NET Driver Order." +#string STR_FORM_BEV_BOOT_TITLE #language en-US "Set Legacy BEV Driver Order" + #language fr-FR "Set Legacy BEV Driver Order" +#string STR_FORM_BEV_BOOT_HELP #language en-US "Set Legacy BEV Driver Order." + #language fr-FR "Set Legacy BEV Driver Order." +#string STR_ORDER_CHANGE_PROMPT #language en-US "Change Driver Boot Order." + #language fr-FR "Change Driver Boot Order." +#string STR_DISABLE_LEGACY_DEVICE #language en-US "Disabled" + #language fr-FR "Disabled" + diff --git a/OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUiVfr.Vfr b/OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUiVfr.Vfr new file mode 100644 index 0000000000..c879ca551f --- /dev/null +++ b/OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUiVfr.Vfr @@ -0,0 +1,67 @@ +///** @file +// +// Browser formset. +// +// Copyright (c) 2015, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +//**/ + +#include "LegacyBootMaintUiVfr.h" + + +formset + guid = LEGACY_BOOT_OPTION_FORMSET_GUID, + title = STRING_TOKEN(STR_LEGACY_BOOT_PROMPT), + help = STRING_TOKEN(STR_LEGACY_BOOT_HELP), + classguid = EFI_IFR_BOOT_MAINTENANCE_GUID, + + varstore LEGACY_BOOT_NV_DATA, + varid = VARSTORE_ID_LEGACY_BOOT, + name = LegacyBootData, + guid = LEGACY_BOOT_OPTION_FORMSET_GUID; + + form formid = LEGACY_BOOT_FORM_ID, + title = STRING_TOKEN(STR_LEGACY_BOOT_PROMPT); + + goto LEGACY_ORDER_CHANGE_FORM_ID, + prompt = STRING_TOKEN(STR_FORM_FLOPPY_BOOT_TITLE), + help = STRING_TOKEN(STR_FORM_FLOPPY_BOOT_HELP), + flags = INTERACTIVE, + key = FORM_FLOPPY_BOOT_ID; + + goto LEGACY_ORDER_CHANGE_FORM_ID, + prompt = STRING_TOKEN(STR_FORM_HARDDISK_BOOT_TITLE), + help = STRING_TOKEN(STR_FORM_HARDDISK_BOOT_HELP), + flags = INTERACTIVE, + key = FORM_HARDDISK_BOOT_ID; + + goto LEGACY_ORDER_CHANGE_FORM_ID, + prompt = STRING_TOKEN(STR_FORM_CDROM_BOOT_TITLE), + help = STRING_TOKEN(STR_FORM_CDROM_BOOT_HELP), + flags = INTERACTIVE, + key = FORM_CDROM_BOOT_ID; + + goto LEGACY_ORDER_CHANGE_FORM_ID, + prompt = STRING_TOKEN(STR_FORM_NET_BOOT_TITLE), + help = STRING_TOKEN(STR_FORM_NET_BOOT_HELP), + flags = INTERACTIVE, + key = FORM_NET_BOOT_ID; + + goto LEGACY_ORDER_CHANGE_FORM_ID, + prompt = STRING_TOKEN(STR_FORM_BEV_BOOT_TITLE), + help = STRING_TOKEN(STR_FORM_BEV_BOOT_HELP), + flags = INTERACTIVE, + key = FORM_BEV_BOOT_ID; + + endform; + + form formid = LEGACY_ORDER_CHANGE_FORM_ID, + title = STRING_TOKEN(STR_ORDER_CHANGE_PROMPT); + + label FORM_BOOT_LEGACY_DEVICE_ID; + label FORM_BOOT_LEGACY_LABEL_END; + + endform; + +endformset; diff --git a/OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUiVfr.h b/OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUiVfr.h new file mode 100644 index 0000000000..e16fc39415 --- /dev/null +++ b/OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUiVfr.h @@ -0,0 +1,79 @@ +/** @file + Legacy Boot Maintainence UI definition. + +Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef _EFI_LEGACY_BOOT_OPTION_VFR_H_ +#define _EFI_LEGACY_BOOT_OPTION_VFR_H_ + +#include + +#define MAX_MENU_NUMBER 100 + +#define LEGACY_BOOT_OPTION_FORMSET_GUID { 0x6bc75598, 0x89b4, 0x483d, { 0x91, 0x60, 0x7f, 0x46, 0x9a, 0x96, 0x35, 0x31 } } + +#define VARSTORE_ID_LEGACY_BOOT 0x0001 + + +#define LEGACY_BOOT_FORM_ID 0x1000 +#define LEGACY_ORDER_CHANGE_FORM_ID 0x1001 + + +#define FORM_FLOPPY_BOOT_ID 0x2000 +#define FORM_HARDDISK_BOOT_ID 0x2001 +#define FORM_CDROM_BOOT_ID 0x2002 +#define FORM_NET_BOOT_ID 0x2003 +#define FORM_BEV_BOOT_ID 0x2004 + + + +#define FORM_BOOT_LEGACY_DEVICE_ID 0x9000 +#define FORM_BOOT_LEGACY_LABEL_END 0x9001 + + +#pragma pack(1) + +/// +/// This is the structure that will be used to store the +/// question's current value. Use it at initialize time to +/// set default value for each question. When using at run +/// time, this map is returned by the callback function, +/// so dynamically changing the question's value will be +/// possible through this mechanism +/// +typedef struct { + // + // Legacy Device Order Selection Storage + // + UINT16 LegacyFD[MAX_MENU_NUMBER]; + UINT16 LegacyHD[MAX_MENU_NUMBER]; + UINT16 LegacyCD[MAX_MENU_NUMBER]; + UINT16 LegacyNET[MAX_MENU_NUMBER]; + UINT16 LegacyBEV[MAX_MENU_NUMBER]; +} LEGACY_BOOT_NV_DATA; + +/// +/// This is the structure that will be used to store the +/// question's current value. Use it at initialize time to +/// set default value for each question. When using at run +/// time, this map is returned by the callback function, +/// so dynamically changing the question's value will be +/// possible through this mechanism +/// +typedef struct { + // + // Legacy Device Order Selection Storage + // + LEGACY_BOOT_NV_DATA InitialNvData; + LEGACY_BOOT_NV_DATA CurrentNvData; + LEGACY_BOOT_NV_DATA LastTimeNvData; + UINT8 DisableMap[32]; +} LEGACY_BOOT_MAINTAIN_DATA; + +#pragma pack() + +#endif diff --git a/OvmfPkg/Csm/LegacyBootManagerLib/InternalLegacyBm.h b/OvmfPkg/Csm/LegacyBootManagerLib/InternalLegacyBm.h new file mode 100644 index 0000000000..292e2c1e7a --- /dev/null +++ b/OvmfPkg/Csm/LegacyBootManagerLib/InternalLegacyBm.h @@ -0,0 +1,60 @@ +/** @file + +Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _INTERNAL_LEGACY_BM_H_ +#define _INTERNAL_LEGACY_BM_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma pack(1) +typedef struct { + UINT16 BbsIndex; +} LEGACY_BM_BOOT_OPTION_BBS_DATA; +#pragma pack() + +/** + Boot the legacy system with the boot option. + + @param BootOption The legacy boot option which have BBS device path + On return, BootOption->Status contains the boot status. + EFI_UNSUPPORTED There is no legacybios protocol, do not support + legacy boot. + EFI_STATUS The status of LegacyBios->LegacyBoot (). +**/ +VOID +EFIAPI +LegacyBmBoot ( + IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption + ); + +/** + Refresh all legacy boot options. + +**/ +VOID +EFIAPI +LegacyBmRefreshAllBootOption ( + VOID + ); + +#endif // _INTERNAL_LEGACY_BM_H_ diff --git a/OvmfPkg/Csm/LegacyBootManagerLib/LegacyBm.c b/OvmfPkg/Csm/LegacyBootManagerLib/LegacyBm.c new file mode 100644 index 0000000000..6138a32ad7 --- /dev/null +++ b/OvmfPkg/Csm/LegacyBootManagerLib/LegacyBm.c @@ -0,0 +1,1530 @@ +/** @file + This function deal with the legacy boot option, it create, delete + and manage the legacy boot option, all legacy boot option is getting from + the legacy BBS table. + +Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalLegacyBm.h" + +#define LEGACY_BM_BOOT_DESCRIPTION_LENGTH 32 + +/** + Initialize legacy boot manager library by call EfiBootManagerRegisterLegacyBootSupport + function to export two function pointer. + + @param ImageHandle The image handle. + @param SystemTable The system table. + + @retval EFI_SUCCESS The legacy boot manager library is initialized correctly. + @return Other value if failed to initialize the legacy boot manager library. +**/ +EFI_STATUS +EFIAPI +LegacyBootManagerLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable +) +{ + EfiBootManagerRegisterLegacyBootSupport ( + LegacyBmRefreshAllBootOption, + LegacyBmBoot + ); + return EFI_SUCCESS; +} + +/** + Get the device type from the input legacy device path. + + @param DevicePath The legacy device path. + + @retval The legacy device type. +**/ +UINT16 +LegacyBmDeviceType ( + EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + ASSERT ((DevicePathType (DevicePath) == BBS_DEVICE_PATH) && + (DevicePathSubType (DevicePath) == BBS_BBS_DP)); + return ((BBS_BBS_DEVICE_PATH *) DevicePath)->DeviceType; +} + +/** + Validate the BbsEntry base on the Boot Priority info in the BbsEntry. + + @param BbsEntry The input bbs entry info. + + @retval TRUE The BbsEntry is valid. + @retval FALSE The BbsEntry is invalid. +**/ +BOOLEAN +LegacyBmValidBbsEntry ( + IN BBS_TABLE *BbsEntry + ) +{ + switch (BbsEntry->BootPriority) { + case BBS_IGNORE_ENTRY: + case BBS_DO_NOT_BOOT_FROM: + case BBS_LOWEST_PRIORITY: + return FALSE; + default: + return TRUE; + } +} + +/** + Build Legacy Device Name String according. + + @param CurBBSEntry BBS Table. + @param Index Index. + @param BufSize The buffer size. + @param BootString The output string. + +**/ +VOID +LegacyBmBuildLegacyDevNameString ( + IN BBS_TABLE *CurBBSEntry, + IN UINTN Index, + IN UINTN BufSize, + OUT CHAR16 *BootString + ) +{ + CHAR16 *Fmt; + CHAR16 *Type; + CHAR8 *StringDesc; + CHAR8 StringBufferA[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1]; + CHAR16 StringBufferU[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1]; + + switch (Index) { + // + // Primary Master + // + case 1: + Fmt = L"Primary Master %s"; + break; + + // + // Primary Slave + // + case 2: + Fmt = L"Primary Slave %s"; + break; + + // + // Secondary Master + // + case 3: + Fmt = L"Secondary Master %s"; + break; + + // + // Secondary Slave + // + case 4: + Fmt = L"Secondary Slave %s"; + break; + + default: + Fmt = L"%s"; + break; + } + + switch (CurBBSEntry->DeviceType) { + case BBS_FLOPPY: + Type = L"Floppy"; + break; + + case BBS_HARDDISK: + Type = L"Harddisk"; + break; + + case BBS_CDROM: + Type = L"CDROM"; + break; + + case BBS_PCMCIA: + Type = L"PCMCIAe"; + break; + + case BBS_USB: + Type = L"USB"; + break; + + case BBS_EMBED_NETWORK: + Type = L"Network"; + break; + + case BBS_BEV_DEVICE: + Type = L"BEVe"; + break; + + case BBS_UNKNOWN: + default: + Type = L"Unknown"; + break; + } + // + // If current BBS entry has its description then use it. + // + StringDesc = (CHAR8 *) (((UINTN) CurBBSEntry->DescStringSegment << 4) + CurBBSEntry->DescStringOffset); + if (NULL != StringDesc) { + // + // Only get fisrt 32 characters, this is suggested by BBS spec + // + CopyMem (StringBufferA, StringDesc, LEGACY_BM_BOOT_DESCRIPTION_LENGTH); + StringBufferA[LEGACY_BM_BOOT_DESCRIPTION_LENGTH] = 0; + AsciiStrToUnicodeStrS (StringBufferA, StringBufferU, ARRAY_SIZE (StringBufferU)); + Fmt = L"%s"; + Type = StringBufferU; + } + + // + // BbsTable 16 entries are for onboard IDE. + // Set description string for SATA harddisks, Harddisk 0 ~ Harddisk 11 + // + if (Index >= 5 && Index <= 16 && (CurBBSEntry->DeviceType == BBS_HARDDISK || CurBBSEntry->DeviceType == BBS_CDROM)) { + Fmt = L"%s %d"; + UnicodeSPrint (BootString, BufSize, Fmt, Type, Index - 5); + } else { + UnicodeSPrint (BootString, BufSize, Fmt, Type); + } +} + +/** + Get the Bbs index for the input boot option. + + @param BootOption The input boot option info. + @param BbsTable The input Bbs table. + @param BbsCount The input total bbs entry number. + @param BbsIndexUsed The array shows how many BBS table indexs have been used. + + @retval The index for the input boot option. +**/ +UINT16 +LegacyBmFuzzyMatch ( + EFI_BOOT_MANAGER_LOAD_OPTION *BootOption, + BBS_TABLE *BbsTable, + UINT16 BbsCount, + BOOLEAN *BbsIndexUsed + ) +{ + UINT16 Index; + LEGACY_BM_BOOT_OPTION_BBS_DATA *BbsData; + CHAR16 Description[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1]; + + BbsData = (LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption->OptionalData; + + // + // Directly check the BBS index stored in BootOption + // + if ((BbsData->BbsIndex < BbsCount) && + (LegacyBmDeviceType (BootOption->FilePath) == BbsTable[BbsData->BbsIndex].DeviceType)) { + LegacyBmBuildLegacyDevNameString ( + &BbsTable[BbsData->BbsIndex], + BbsData->BbsIndex, + sizeof (Description), + Description + ); + if ((StrCmp (Description, BootOption->Description) == 0) && !BbsIndexUsed[BbsData->BbsIndex]) { + // + // If devices with the same description string are connected, + // the BbsIndex of the first device is returned for the other device also. + // So, check if the BbsIndex is already being used, before assigning the BbsIndex. + // + BbsIndexUsed[BbsData->BbsIndex] = TRUE; + return BbsData->BbsIndex; + } + } + + // + // BBS table could be changed (entry removed/moved) + // find the correct BBS index + // + for (Index = 0; Index < BbsCount; Index++) { + if (!LegacyBmValidBbsEntry (&BbsTable[Index]) || + (BbsTable[Index].DeviceType != LegacyBmDeviceType (BootOption->FilePath))) { + continue; + } + + LegacyBmBuildLegacyDevNameString ( + &BbsTable[Index], + Index, + sizeof (Description), + Description + ); + if ((StrCmp (Description, BootOption->Description) == 0) && !BbsIndexUsed[Index]) { + // + // If devices with the same description string are connected, + // the BbsIndex of the first device is assigned for the other device also. + // So, check if the BbsIndex is already being used, before assigning the corrected BbsIndex. + // + break; + } + } + + // + // Add the corrected BbsIndex in the UsedBbsIndex Buffer + // + if (Index != BbsCount) { + BbsIndexUsed[Index] = TRUE; + } + + return Index; +} + +/** + + Update legacy device order base on the input info. + + @param LegacyDevOrder Legacy device order data buffer. + @param LegacyDevOrderSize Legacy device order data buffer size. + @param DeviceType Device type which need to check. + @param OldBbsIndex Old Bds Index. + @param NewBbsIndex New Bds Index, if it is -1,means remove this option. + +**/ +VOID +LegacyBmUpdateBbsIndex ( + LEGACY_DEV_ORDER_ENTRY *LegacyDevOrder, + UINTN *LegacyDevOrderSize, + UINT16 DeviceType, + UINT16 OldBbsIndex, + UINT16 NewBbsIndex // Delete entry if -1 + ) +{ + LEGACY_DEV_ORDER_ENTRY *Entry; + UINTN Index; + + ASSERT (((LegacyDevOrder == NULL) && (*LegacyDevOrderSize == 0)) || + ((LegacyDevOrder != NULL) && (*LegacyDevOrderSize != 0)) + ); + + for (Entry = LegacyDevOrder; + Entry < (LEGACY_DEV_ORDER_ENTRY *) ((UINT8 *) LegacyDevOrder + *LegacyDevOrderSize); + Entry = (LEGACY_DEV_ORDER_ENTRY *) ((UINTN) Entry + sizeof (BBS_TYPE) + Entry->Length) + ) { + if (Entry->BbsType == DeviceType) { + for (Index = 0; Index < Entry->Length / sizeof (UINT16) - 1; Index++) { + if (Entry->Data[Index] == OldBbsIndex) { + if (NewBbsIndex == (UINT16) -1) { + // + // Delete the old entry + // + CopyMem ( + &Entry->Data[Index], + &Entry->Data[Index + 1], + (UINT8 *) LegacyDevOrder + *LegacyDevOrderSize - (UINT8 *) &Entry->Data[Index + 1] + ); + Entry->Length -= sizeof (UINT16); + *LegacyDevOrderSize -= sizeof(UINT16); + } else { + Entry->Data[Index] = NewBbsIndex; + } + break; + } + } + break; + } + } +} + +/** + Delete all the legacy boot options. + + @retval EFI_SUCCESS All legacy boot options are deleted. +**/ +EFI_STATUS +LegacyBmDeleteAllBootOptions ( + VOID + ) +{ + EFI_STATUS Status; + UINTN Index; + EFI_BOOT_MANAGER_LOAD_OPTION *BootOption; + UINTN BootOptionCount; + + BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot); + for (Index = 0; Index < BootOptionCount; Index++) { + if ((DevicePathType (BootOption[Index].FilePath) == BBS_DEVICE_PATH) && + (DevicePathSubType (BootOption[Index].FilePath) == BBS_BBS_DP)) { + Status = EfiBootManagerDeleteLoadOptionVariable (BootOption[Index].OptionNumber, BootOption[Index].OptionType); + // + // Deleting variable with current variable implementation shouldn't fail. + // + ASSERT_EFI_ERROR (Status); + } + } + + Status = gRT->SetVariable ( + VAR_LEGACY_DEV_ORDER, + &gEfiLegacyDevOrderVariableGuid, + 0, + 0, + NULL + ); + // + // Deleting variable with current variable implementation shouldn't fail. + // + ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND); + + return EFI_SUCCESS; +} + + +/** + Delete all the invalid legacy boot options. + + @retval EFI_SUCCESS All invalide legacy boot options are deleted. + @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory. + @retval EFI_NOT_FOUND Fail to retrive variable of boot order. +**/ +EFI_STATUS +LegacyBmDeleteAllInvalidBootOptions ( + VOID + ) +{ + EFI_STATUS Status; + UINT16 HddCount; + UINT16 BbsCount; + HDD_INFO *HddInfo; + BBS_TABLE *BbsTable; + UINT16 BbsIndex; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + UINTN Index; + EFI_BOOT_MANAGER_LOAD_OPTION *BootOption; + UINTN BootOptionCount; + LEGACY_DEV_ORDER_ENTRY *LegacyDevOrder; + UINTN LegacyDevOrderSize; + BOOLEAN *BbsIndexUsed; + + HddCount = 0; + BbsCount = 0; + HddInfo = NULL; + BbsTable = NULL; + + Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = LegacyBios->GetBbsInfo ( + LegacyBios, + &HddCount, + &HddInfo, + &BbsCount, + &BbsTable + ); + if (EFI_ERROR (Status)) { + return Status; + } + + GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID **) &LegacyDevOrder, &LegacyDevOrderSize); + + BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot); + + BbsIndexUsed = AllocateZeroPool (BbsCount * sizeof (BOOLEAN)); + ASSERT (BbsIndexUsed != NULL); + + for (Index = 0; Index < BootOptionCount; Index++) { + // + // Skip non legacy boot option + // + if ((DevicePathType (BootOption[Index].FilePath) != BBS_DEVICE_PATH) || + (DevicePathSubType (BootOption[Index].FilePath) != BBS_BBS_DP)) { + continue; + } + + BbsIndex = LegacyBmFuzzyMatch (&BootOption[Index], BbsTable, BbsCount, BbsIndexUsed); + if (BbsIndex == BbsCount) { + DEBUG ((EFI_D_INFO, "[LegacyBds] Delete Boot Option Boot%04x: %s\n", (UINTN) BootOption[Index].OptionNumber, BootOption[Index].Description)); + // + // Delete entry from LegacyDevOrder + // + LegacyBmUpdateBbsIndex ( + LegacyDevOrder, + &LegacyDevOrderSize, + LegacyBmDeviceType (BootOption[Index].FilePath), + ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex, + (UINT16) -1 + ); + EfiBootManagerDeleteLoadOptionVariable (BootOption[Index].OptionNumber, BootOption[Index].OptionType); + } else { + if (((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex != BbsIndex) { + DEBUG ((EFI_D_INFO, "[LegacyBds] Update Boot Option Boot%04x: %s Bbs0x%04x->Bbs0x%04x\n", (UINTN) BootOption[Index].OptionNumber, BootOption[Index].Description, + (UINTN) ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex, (UINTN) BbsIndex)); + // + // Update the BBS index in LegacyDevOrder + // + LegacyBmUpdateBbsIndex ( + LegacyDevOrder, + &LegacyDevOrderSize, + LegacyBmDeviceType (BootOption[Index].FilePath), + ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex, + BbsIndex + ); + + // + // Update the OptionalData in the Boot#### variable + // + ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex = BbsIndex; + EfiBootManagerLoadOptionToVariable (&BootOption[Index]); + } + } + } + EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount); + + if (LegacyDevOrder != NULL) { + Status = gRT->SetVariable ( + VAR_LEGACY_DEV_ORDER, + &gEfiLegacyDevOrderVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, + LegacyDevOrderSize, + LegacyDevOrder + ); + // + // Shrink variable with current variable implementation shouldn't fail. + // + ASSERT_EFI_ERROR (Status); + + FreePool (LegacyDevOrder); + } + FreePool(BbsIndexUsed); + return Status; +} + +/** + Create legacy boot option. + + @param BootOption Ponter to the boot option which will be crated. + @param BbsEntry The input bbs entry info. + @param BbsIndex The BBS index. + + @retval EFI_SUCCESS Create legacy boot option successfully. + @retval EFI_INVALID_PARAMETER Invalid input parameter. + +**/ +EFI_STATUS +LegacyBmCreateLegacyBootOption ( + IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *BootOption, + IN BBS_TABLE *BbsEntry, + IN UINT16 BbsIndex + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + CHAR16 Description[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1]; + CHAR8 HelpString[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1]; + UINTN StringLen; + LEGACY_BM_BOOT_OPTION_BBS_DATA *OptionalData; + BBS_BBS_DEVICE_PATH *BbsNode; + + if ((BootOption == NULL) || (BbsEntry == NULL)) { + return EFI_INVALID_PARAMETER; + } + + LegacyBmBuildLegacyDevNameString (BbsEntry, BbsIndex, sizeof (Description), Description); + + // + // Create the BBS device path with description string + // + UnicodeStrToAsciiStrS (Description, HelpString, sizeof (HelpString)); + StringLen = AsciiStrLen (HelpString); + DevicePath = AllocatePool (sizeof (BBS_BBS_DEVICE_PATH) + StringLen + END_DEVICE_PATH_LENGTH); + ASSERT (DevicePath != NULL); + + BbsNode = (BBS_BBS_DEVICE_PATH *) DevicePath; + SetDevicePathNodeLength (BbsNode, sizeof (BBS_BBS_DEVICE_PATH) + StringLen); + BbsNode->Header.Type = BBS_DEVICE_PATH; + BbsNode->Header.SubType = BBS_BBS_DP; + BbsNode->DeviceType = BbsEntry->DeviceType; + CopyMem (&BbsNode->StatusFlag, &BbsEntry->StatusFlags, sizeof (BBS_STATUS_FLAGS)); + CopyMem (BbsNode->String, HelpString, StringLen + 1); + + SetDevicePathEndNode (NextDevicePathNode (BbsNode)); + + // + // Create the OptionalData + // + OptionalData = AllocatePool (sizeof (LEGACY_BM_BOOT_OPTION_BBS_DATA)); + ASSERT (OptionalData != NULL); + OptionalData->BbsIndex = BbsIndex; + + // + // Create the BootOption + // + Status = EfiBootManagerInitializeLoadOption ( + BootOption, + LoadOptionNumberUnassigned, + LoadOptionTypeBoot, + LOAD_OPTION_ACTIVE, + Description, + DevicePath, + (UINT8 *) OptionalData, + sizeof (LEGACY_BM_BOOT_OPTION_BBS_DATA) + ); + FreePool (DevicePath); + FreePool (OptionalData); + + return Status; +} + +/** + Fill the device order buffer. + + @param BbsTable The BBS table. + @param BbsType The BBS Type. + @param BbsCount The BBS Count. + @param Buf device order buffer. + + @return The device order buffer. + +**/ +UINT16 * +LegacyBmFillDevOrderBuf ( + IN BBS_TABLE *BbsTable, + IN BBS_TYPE BbsType, + IN UINTN BbsCount, + OUT UINT16 *Buf + ) +{ + UINTN Index; + + for (Index = 0; Index < BbsCount; Index++) { + if (!LegacyBmValidBbsEntry (&BbsTable[Index])) { + continue; + } + + if (BbsTable[Index].DeviceType != BbsType) { + continue; + } + + *Buf = (UINT16) (Index & 0xFF); + Buf++; + } + + return Buf; +} + +/** + Create the device order buffer. + + @param BbsTable The BBS table. + @param BbsCount The BBS Count. + + @retval EFI_SUCCES The buffer is created and the EFI variable named + VAR_LEGACY_DEV_ORDER and EfiLegacyDevOrderGuid is + set correctly. + @retval EFI_OUT_OF_RESOURCES Memmory or storage is not enough. + @retval EFI_DEVICE_ERROR Fail to add the device order into EFI variable fail + because of hardware error. +**/ +EFI_STATUS +LegacyBmCreateDevOrder ( + IN BBS_TABLE *BbsTable, + IN UINT16 BbsCount + ) +{ + UINTN Index; + UINTN FDCount; + UINTN HDCount; + UINTN CDCount; + UINTN NETCount; + UINTN BEVCount; + UINTN TotalSize; + UINTN HeaderSize; + LEGACY_DEV_ORDER_ENTRY *DevOrder; + LEGACY_DEV_ORDER_ENTRY *DevOrderPtr; + EFI_STATUS Status; + + FDCount = 0; + HDCount = 0; + CDCount = 0; + NETCount = 0; + BEVCount = 0; + TotalSize = 0; + HeaderSize = sizeof (BBS_TYPE) + sizeof (UINT16); + DevOrder = NULL; + Status = EFI_SUCCESS; + + // + // Count all boot devices + // + for (Index = 0; Index < BbsCount; Index++) { + if (!LegacyBmValidBbsEntry (&BbsTable[Index])) { + continue; + } + + switch (BbsTable[Index].DeviceType) { + case BBS_FLOPPY: + FDCount++; + break; + + case BBS_HARDDISK: + HDCount++; + break; + + case BBS_CDROM: + CDCount++; + break; + + case BBS_EMBED_NETWORK: + NETCount++; + break; + + case BBS_BEV_DEVICE: + BEVCount++; + break; + + default: + break; + } + } + + TotalSize += (HeaderSize + sizeof (UINT16) * FDCount); + TotalSize += (HeaderSize + sizeof (UINT16) * HDCount); + TotalSize += (HeaderSize + sizeof (UINT16) * CDCount); + TotalSize += (HeaderSize + sizeof (UINT16) * NETCount); + TotalSize += (HeaderSize + sizeof (UINT16) * BEVCount); + + // + // Create buffer to hold all boot device order + // + DevOrder = AllocateZeroPool (TotalSize); + if (NULL == DevOrder) { + return EFI_OUT_OF_RESOURCES; + } + DevOrderPtr = DevOrder; + + DevOrderPtr->BbsType = BBS_FLOPPY; + DevOrderPtr->Length = (UINT16) (sizeof (DevOrderPtr->Length) + FDCount * sizeof (UINT16)); + DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_FLOPPY, BbsCount, DevOrderPtr->Data); + + DevOrderPtr->BbsType = BBS_HARDDISK; + DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16)); + DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_HARDDISK, BbsCount, DevOrderPtr->Data); + + DevOrderPtr->BbsType = BBS_CDROM; + DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16)); + DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_CDROM, BbsCount, DevOrderPtr->Data); + + DevOrderPtr->BbsType = BBS_EMBED_NETWORK; + DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16)); + DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_EMBED_NETWORK, BbsCount, DevOrderPtr->Data); + + DevOrderPtr->BbsType = BBS_BEV_DEVICE; + DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16)); + DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_BEV_DEVICE, BbsCount, DevOrderPtr->Data); + + ASSERT (TotalSize == ((UINTN) DevOrderPtr - (UINTN) DevOrder)); + + // + // Save device order for legacy boot device to variable. + // + Status = gRT->SetVariable ( + VAR_LEGACY_DEV_ORDER, + &gEfiLegacyDevOrderVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, + TotalSize, + DevOrder + ); + FreePool (DevOrder); + + return Status; +} + +/** + Add the legacy boot devices from BBS table into + the legacy device boot order. + + @retval EFI_SUCCESS The boot devices are added successfully. + @retval EFI_NOT_FOUND The legacy boot devices are not found. + @retval EFI_OUT_OF_RESOURCES Memmory or storage is not enough. + @retval EFI_DEVICE_ERROR Fail to add the legacy device boot order into EFI variable + because of hardware error. +**/ +EFI_STATUS +LegacyBmUpdateDevOrder ( + VOID + ) +{ + LEGACY_DEV_ORDER_ENTRY *DevOrder; + LEGACY_DEV_ORDER_ENTRY *NewDevOrder; + LEGACY_DEV_ORDER_ENTRY *Ptr; + LEGACY_DEV_ORDER_ENTRY *NewPtr; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + EFI_STATUS Status; + UINT16 HddCount; + UINT16 BbsCount; + HDD_INFO *LocalHddInfo; + BBS_TABLE *LocalBbsTable; + UINTN Index; + UINTN Index2; + UINTN *Idx; + UINTN FDCount; + UINTN HDCount; + UINTN CDCount; + UINTN NETCount; + UINTN BEVCount; + UINTN TotalSize; + UINTN HeaderSize; + UINT16 *NewFDPtr; + UINT16 *NewHDPtr; + UINT16 *NewCDPtr; + UINT16 *NewNETPtr; + UINT16 *NewBEVPtr; + UINT16 *NewDevPtr; + UINTN FDIndex; + UINTN HDIndex; + UINTN CDIndex; + UINTN NETIndex; + UINTN BEVIndex; + + Idx = NULL; + FDCount = 0; + HDCount = 0; + CDCount = 0; + NETCount = 0; + BEVCount = 0; + TotalSize = 0; + HeaderSize = sizeof (BBS_TYPE) + sizeof (UINT16); + FDIndex = 0; + HDIndex = 0; + CDIndex = 0; + NETIndex = 0; + BEVIndex = 0; + NewDevPtr = NULL; + + Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = LegacyBios->GetBbsInfo ( + LegacyBios, + &HddCount, + &LocalHddInfo, + &BbsCount, + &LocalBbsTable + ); + if (EFI_ERROR (Status)) { + return Status; + } + + GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID **) &DevOrder, NULL); + if (NULL == DevOrder) { + return LegacyBmCreateDevOrder (LocalBbsTable, BbsCount); + } + // + // First we figure out how many boot devices with same device type respectively + // + for (Index = 0; Index < BbsCount; Index++) { + if (!LegacyBmValidBbsEntry (&LocalBbsTable[Index])) { + continue; + } + + switch (LocalBbsTable[Index].DeviceType) { + case BBS_FLOPPY: + FDCount++; + break; + + case BBS_HARDDISK: + HDCount++; + break; + + case BBS_CDROM: + CDCount++; + break; + + case BBS_EMBED_NETWORK: + NETCount++; + break; + + case BBS_BEV_DEVICE: + BEVCount++; + break; + + default: + break; + } + } + + TotalSize += (HeaderSize + FDCount * sizeof (UINT16)); + TotalSize += (HeaderSize + HDCount * sizeof (UINT16)); + TotalSize += (HeaderSize + CDCount * sizeof (UINT16)); + TotalSize += (HeaderSize + NETCount * sizeof (UINT16)); + TotalSize += (HeaderSize + BEVCount * sizeof (UINT16)); + + NewDevOrder = AllocateZeroPool (TotalSize); + if (NULL == NewDevOrder) { + return EFI_OUT_OF_RESOURCES; + } + + // + // copy FD + // + Ptr = DevOrder; + NewPtr = NewDevOrder; + NewPtr->BbsType = Ptr->BbsType; + NewPtr->Length = (UINT16) (sizeof (UINT16) + FDCount * sizeof (UINT16)); + for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) { + if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) || + LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_FLOPPY + ) { + continue; + } + + NewPtr->Data[FDIndex] = Ptr->Data[Index]; + FDIndex++; + } + NewFDPtr = NewPtr->Data; + + // + // copy HD + // + Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]); + NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]); + NewPtr->BbsType = Ptr->BbsType; + NewPtr->Length = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16)); + for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) { + if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) || + LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_HARDDISK + ) { + continue; + } + + NewPtr->Data[HDIndex] = Ptr->Data[Index]; + HDIndex++; + } + NewHDPtr = NewPtr->Data; + + // + // copy CD + // + Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]); + NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]); + NewPtr->BbsType = Ptr->BbsType; + NewPtr->Length = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16)); + for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) { + if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) || + LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_CDROM + ) { + continue; + } + + NewPtr->Data[CDIndex] = Ptr->Data[Index]; + CDIndex++; + } + NewCDPtr = NewPtr->Data; + + // + // copy NET + // + Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]); + NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]); + NewPtr->BbsType = Ptr->BbsType; + NewPtr->Length = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16)); + for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) { + if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) || + LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_EMBED_NETWORK + ) { + continue; + } + + NewPtr->Data[NETIndex] = Ptr->Data[Index]; + NETIndex++; + } + NewNETPtr = NewPtr->Data; + + // + // copy BEV + // + Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]); + NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]); + NewPtr->BbsType = Ptr->BbsType; + NewPtr->Length = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16)); + for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) { + if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) || + LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_BEV_DEVICE + ) { + continue; + } + + NewPtr->Data[BEVIndex] = Ptr->Data[Index]; + BEVIndex++; + } + NewBEVPtr = NewPtr->Data; + + for (Index = 0; Index < BbsCount; Index++) { + if (!LegacyBmValidBbsEntry (&LocalBbsTable[Index])) { + continue; + } + + switch (LocalBbsTable[Index].DeviceType) { + case BBS_FLOPPY: + Idx = &FDIndex; + NewDevPtr = NewFDPtr; + break; + + case BBS_HARDDISK: + Idx = &HDIndex; + NewDevPtr = NewHDPtr; + break; + + case BBS_CDROM: + Idx = &CDIndex; + NewDevPtr = NewCDPtr; + break; + + case BBS_EMBED_NETWORK: + Idx = &NETIndex; + NewDevPtr = NewNETPtr; + break; + + case BBS_BEV_DEVICE: + Idx = &BEVIndex; + NewDevPtr = NewBEVPtr; + break; + + default: + Idx = NULL; + break; + } + // + // at this point we have copied those valid indexes to new buffer + // and we should check if there is any new appeared boot device + // + if (Idx != NULL) { + for (Index2 = 0; Index2 < *Idx; Index2++) { + if ((NewDevPtr[Index2] & 0xFF) == (UINT16) Index) { + break; + } + } + + if (Index2 == *Idx) { + // + // Index2 == *Idx means we didn't find Index + // so Index is a new appeared device's index in BBS table + // insert it before disabled indexes. + // + for (Index2 = 0; Index2 < *Idx; Index2++) { + if ((NewDevPtr[Index2] & 0xFF00) == 0xFF00) { + break; + } + } + CopyMem (&NewDevPtr[Index2 + 1], &NewDevPtr[Index2], (*Idx - Index2) * sizeof (UINT16)); + NewDevPtr[Index2] = (UINT16) (Index & 0xFF); + (*Idx)++; + } + } + } + + FreePool (DevOrder); + + Status = gRT->SetVariable ( + VAR_LEGACY_DEV_ORDER, + &gEfiLegacyDevOrderVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, + TotalSize, + NewDevOrder + ); + FreePool (NewDevOrder); + + return Status; +} + +/** + Set Boot Priority for specified device type. + + @param DeviceType The device type. + @param BbsIndex The BBS index to set the highest priority. Ignore when -1. + @param LocalBbsTable The BBS table. + @param Priority The prority table. + + @retval EFI_SUCCESS The function completes successfully. + @retval EFI_NOT_FOUND Failed to find device. + @retval EFI_OUT_OF_RESOURCES Failed to get the efi variable of device order. + +**/ +EFI_STATUS +LegacyBmSetPriorityForSameTypeDev ( + IN UINT16 DeviceType, + IN UINTN BbsIndex, + IN OUT BBS_TABLE *LocalBbsTable, + IN OUT UINT16 *Priority + ) +{ + LEGACY_DEV_ORDER_ENTRY *DevOrder; + LEGACY_DEV_ORDER_ENTRY *DevOrderPtr; + UINTN DevOrderSize; + UINTN Index; + + GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID **) &DevOrder, &DevOrderSize); + if (NULL == DevOrder) { + return EFI_OUT_OF_RESOURCES; + } + + DevOrderPtr = DevOrder; + while ((UINT8 *) DevOrderPtr < (UINT8 *) DevOrder + DevOrderSize) { + if (DevOrderPtr->BbsType == DeviceType) { + break; + } + + DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) ((UINTN) DevOrderPtr + sizeof (BBS_TYPE) + DevOrderPtr->Length); + } + + if ((UINT8 *) DevOrderPtr >= (UINT8 *) DevOrder + DevOrderSize) { + FreePool (DevOrder); + return EFI_NOT_FOUND; + } + + if (BbsIndex != (UINTN) -1) { + // + // In case the BBS entry isn't valid because devices were plugged or removed. + // + if (!LegacyBmValidBbsEntry (&LocalBbsTable[BbsIndex]) || (LocalBbsTable[BbsIndex].DeviceType != DeviceType)) { + FreePool (DevOrder); + return EFI_NOT_FOUND; + } + LocalBbsTable[BbsIndex].BootPriority = *Priority; + (*Priority)++; + } + // + // If the high byte of the DevIndex is 0xFF, it indicates that this device has been disabled. + // + for (Index = 0; Index < DevOrderPtr->Length / sizeof (UINT16) - 1; Index++) { + if ((DevOrderPtr->Data[Index] & 0xFF00) == 0xFF00) { + // + // LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = BBS_DISABLED_ENTRY; + // + } else if (DevOrderPtr->Data[Index] != BbsIndex) { + LocalBbsTable[DevOrderPtr->Data[Index]].BootPriority = *Priority; + (*Priority)++; + } + } + + FreePool (DevOrder); + return EFI_SUCCESS; +} + +/** + Print the BBS Table. + + @param LocalBbsTable The BBS table. + @param BbsCount The count of entry in BBS table. +**/ +VOID +LegacyBmPrintBbsTable ( + IN BBS_TABLE *LocalBbsTable, + IN UINT16 BbsCount + ) +{ + UINT16 Index; + + DEBUG ((DEBUG_INFO, "\n")); + DEBUG ((DEBUG_INFO, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs\n")); + DEBUG ((DEBUG_INFO, "=============================================\n")); + for (Index = 0; Index < BbsCount; Index++) { + if (!LegacyBmValidBbsEntry (&LocalBbsTable[Index])) { + continue; + } + + DEBUG ( + (DEBUG_INFO, + " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x %04x:%04x\n", + (UINTN) Index, + (UINTN) LocalBbsTable[Index].BootPriority, + (UINTN) LocalBbsTable[Index].Bus, + (UINTN) LocalBbsTable[Index].Device, + (UINTN) LocalBbsTable[Index].Function, + (UINTN) LocalBbsTable[Index].Class, + (UINTN) LocalBbsTable[Index].SubClass, + (UINTN) LocalBbsTable[Index].DeviceType, + (UINTN) * (UINT16 *) &LocalBbsTable[Index].StatusFlags, + (UINTN) LocalBbsTable[Index].BootHandlerSegment, + (UINTN) LocalBbsTable[Index].BootHandlerOffset, + (UINTN) ((LocalBbsTable[Index].MfgStringSegment << 4) + LocalBbsTable[Index].MfgStringOffset), + (UINTN) ((LocalBbsTable[Index].DescStringSegment << 4) + LocalBbsTable[Index].DescStringOffset)) + ); + } + + DEBUG ((DEBUG_INFO, "\n")); +} + +/** + Set the boot priority for BBS entries based on boot option entry and boot order. + + @param BootOption The boot option is to be checked for refresh BBS table. + + @retval EFI_SUCCESS The boot priority for BBS entries is refreshed successfully. + @retval EFI_NOT_FOUND BBS entries can't be found. + @retval EFI_OUT_OF_RESOURCES Failed to get the legacy device boot order. +**/ +EFI_STATUS +LegacyBmRefreshBbsTableForBoot ( + IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption + ) +{ + EFI_STATUS Status; + UINT16 BbsIndex; + UINT16 HddCount; + UINT16 BbsCount; + HDD_INFO *LocalHddInfo; + BBS_TABLE *LocalBbsTable; + UINT16 DevType; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + UINTN Index; + UINT16 Priority; + UINT16 *DeviceType; + UINTN DeviceTypeCount; + UINTN DeviceTypeIndex; + EFI_BOOT_MANAGER_LOAD_OPTION *Option; + UINTN OptionCount; + + HddCount = 0; + BbsCount = 0; + LocalHddInfo = NULL; + LocalBbsTable = NULL; + DevType = BBS_UNKNOWN; + + Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = LegacyBios->GetBbsInfo ( + LegacyBios, + &HddCount, + &LocalHddInfo, + &BbsCount, + &LocalBbsTable + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // First, set all the present devices' boot priority to BBS_UNPRIORITIZED_ENTRY + // We will set them according to the settings setup by user + // + for (Index = 0; Index < BbsCount; Index++) { + if (LegacyBmValidBbsEntry (&LocalBbsTable[Index])) { + LocalBbsTable[Index].BootPriority = BBS_UNPRIORITIZED_ENTRY; + } + } + // + // boot priority always starts at 0 + // + Priority = 0; + if ((DevicePathType (BootOption->FilePath) == BBS_DEVICE_PATH) && + (DevicePathSubType (BootOption->FilePath) == BBS_BBS_DP)) { + // + // If BootOption stands for a legacy boot option, we prioritize the devices with the same type first. + // + DevType = LegacyBmDeviceType (BootOption->FilePath); + BbsIndex = ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption->OptionalData)->BbsIndex; + Status = LegacyBmSetPriorityForSameTypeDev ( + DevType, + BbsIndex, + LocalBbsTable, + &Priority + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + // + // we have to set the boot priority for other BBS entries with different device types + // + Option = EfiBootManagerGetLoadOptions (&OptionCount, LoadOptionTypeBoot); + DeviceType = AllocatePool (sizeof (UINT16) * OptionCount); + ASSERT (DeviceType != NULL); + DeviceType[0] = DevType; + DeviceTypeCount = 1; + for (Index = 0; Index < OptionCount; Index++) { + if ((DevicePathType (Option[Index].FilePath) != BBS_DEVICE_PATH) || + (DevicePathSubType (Option[Index].FilePath) != BBS_BBS_DP)) { + continue; + } + + DevType = LegacyBmDeviceType (Option[Index].FilePath); + for (DeviceTypeIndex = 0; DeviceTypeIndex < DeviceTypeCount; DeviceTypeIndex++) { + if (DeviceType[DeviceTypeIndex] == DevType) { + break; + } + } + if (DeviceTypeIndex < DeviceTypeCount) { + // + // We don't want to process twice for a device type + // + continue; + } + + DeviceType[DeviceTypeCount] = DevType; + DeviceTypeCount++; + + Status = LegacyBmSetPriorityForSameTypeDev ( + DevType, + (UINTN) -1, + LocalBbsTable, + &Priority + ); + } + EfiBootManagerFreeLoadOptions (Option, OptionCount); + + DEBUG_CODE_BEGIN(); + LegacyBmPrintBbsTable (LocalBbsTable, BbsCount); + DEBUG_CODE_END(); + + return Status; +} + + +/** + Boot the legacy system with the boot option. + + @param BootOption The legacy boot option which have BBS device path + On return, BootOption->Status contains the boot status. + EFI_UNSUPPORTED There is no legacybios protocol, do not support + legacy boot. + EFI_STATUS The status of LegacyBios->LegacyBoot (). +**/ +VOID +EFIAPI +LegacyBmBoot ( + IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption + ) +{ + EFI_STATUS Status; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + + Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios); + if (EFI_ERROR (Status)) { + // + // If no LegacyBios protocol we do not support legacy boot + // + BootOption->Status = EFI_UNSUPPORTED; + return; + } + // + // Notes: if we separate the int 19, then we don't need to refresh BBS + // + Status = LegacyBmRefreshBbsTableForBoot (BootOption); + if (EFI_ERROR (Status)) { + BootOption->Status = Status; + return; + } + + BootOption->Status = LegacyBios->LegacyBoot ( + LegacyBios, + (BBS_BBS_DEVICE_PATH *) BootOption->FilePath, + BootOption->OptionalDataSize, + BootOption->OptionalData + ); +} + +/** + This function enumerates all the legacy boot options. + + @param BootOptionCount Return the legacy boot option count. + + @retval Pointer to the legacy boot option buffer. +**/ +EFI_BOOT_MANAGER_LOAD_OPTION * +LegacyBmEnumerateAllBootOptions ( + UINTN *BootOptionCount + ) +{ + EFI_STATUS Status; + UINT16 HddCount; + UINT16 BbsCount; + HDD_INFO *HddInfo; + BBS_TABLE *BbsTable; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + UINT16 Index; + EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions; + + ASSERT (BootOptionCount != NULL); + + BootOptions = NULL; + *BootOptionCount = 0; + BbsCount = 0; + + Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios); + if (EFI_ERROR (Status)) { + return NULL; + } + + Status = LegacyBios->GetBbsInfo ( + LegacyBios, + &HddCount, + &HddInfo, + &BbsCount, + &BbsTable + ); + if (EFI_ERROR (Status)) { + return NULL; + } + + for (Index = 0; Index < BbsCount; Index++) { + if (!LegacyBmValidBbsEntry (&BbsTable[Index])) { + continue; + } + + BootOptions = ReallocatePool ( + sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount), + sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1), + BootOptions + ); + ASSERT (BootOptions != NULL); + + Status = LegacyBmCreateLegacyBootOption (&BootOptions[(*BootOptionCount)++], &BbsTable[Index], Index); + ASSERT_EFI_ERROR (Status); + } + + return BootOptions; +} + +/** + Return the index of the boot option in the boot option array. + + The function compares the Description, FilePath, OptionalData. + + @param Key The input boot option which is compared with. + @param Array The input boot option array. + @param Count The count of the input boot options. + + @retval The index of the input boot option in the array. + +**/ +INTN +LegacyBmFindBootOption ( + IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key, + IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array, + IN UINTN Count + ) +{ + UINTN Index; + + for (Index = 0; Index < Count; Index++) { + if ((StrCmp (Key->Description, Array[Index].Description) == 0) && + (CompareMem (Key->FilePath, Array[Index].FilePath, GetDevicePathSize (Key->FilePath)) == 0) && + (Key->OptionalDataSize == Array[Index].OptionalDataSize) && + (CompareMem (Key->OptionalData, Array[Index].OptionalData, Key->OptionalDataSize) == 0)) { + return (INTN) Index; + } + } + + return -1; +} + +/** + Refresh all legacy boot options. + +**/ +VOID +EFIAPI +LegacyBmRefreshAllBootOption ( + VOID + ) +{ + EFI_STATUS Status; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + UINTN RootBridgeHandleCount; + EFI_HANDLE *RootBridgeHandleBuffer; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN RootBridgeIndex; + UINTN Index; + UINTN Flags; + EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions; + UINTN BootOptionCount; + EFI_BOOT_MANAGER_LOAD_OPTION *ExistingBootOptions; + UINTN ExistingBootOptionCount; + + Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios); + if (EFI_ERROR (Status)) { + LegacyBmDeleteAllBootOptions (); + return; + } + PERF_START (NULL, "LegacyBootOptionEnum", "BDS", 0); + + // + // Before enumerating the legacy boot option, we need to dispatch all the legacy option roms + // to ensure the GetBbsInfo() counts all the legacy devices. + // + gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiPciRootBridgeIoProtocolGuid, + NULL, + &RootBridgeHandleCount, + &RootBridgeHandleBuffer + ); + for (RootBridgeIndex = 0; RootBridgeIndex < RootBridgeHandleCount; RootBridgeIndex++) { + gBS->ConnectController (RootBridgeHandleBuffer[RootBridgeIndex], NULL, NULL, FALSE); + gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiPciIoProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + for (Index = 0; Index < HandleCount; Index++) { + // + // Start the thunk driver so that the legacy option rom gets dispatched. + // Note: We don't directly call InstallPciRom because some thunk drivers + // (e.g. BlockIo thunk driver) depend on the immediate result after dispatching + // + Status = LegacyBios->CheckPciRom ( + LegacyBios, + HandleBuffer[Index], + NULL, + NULL, + &Flags + ); + if (!EFI_ERROR (Status)) { + gBS->ConnectController (HandleBuffer[Index], NULL, NULL, FALSE); + } + } + } + + // + // Same algorithm pattern as the EfiBootManagerRefreshAllBootOption + // Firstly delete the invalid legacy boot options, + // then enumreate and save the newly appeared legacy boot options + // the last step is legacy boot option special action to refresh the LegacyDevOrder variable + // + LegacyBmDeleteAllInvalidBootOptions (); + + ExistingBootOptions = EfiBootManagerGetLoadOptions (&ExistingBootOptionCount, LoadOptionTypeBoot); + BootOptions = LegacyBmEnumerateAllBootOptions (&BootOptionCount); + + for (Index = 0; Index < BootOptionCount; Index++) { + if (LegacyBmFindBootOption (&BootOptions[Index], ExistingBootOptions, ExistingBootOptionCount) == -1) { + Status = EfiBootManagerAddLoadOptionVariable (&BootOptions[Index], (UINTN) -1); + DEBUG (( + EFI_D_INFO, "[LegacyBds] New Boot Option: Boot%04x Bbs0x%04x %s %r\n", + (UINTN) BootOptions[Index].OptionNumber, + (UINTN) ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOptions[Index].OptionalData)->BbsIndex, + BootOptions[Index].Description, + Status + )); + // + // Continue upon failure to add boot option. + // + } + } + + EfiBootManagerFreeLoadOptions (ExistingBootOptions, ExistingBootOptionCount); + EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount); + + // + // Failure to create LegacyDevOrder variable only impacts the boot order. + // + LegacyBmUpdateDevOrder (); + + PERF_END (NULL, "LegacyBootOptionEnum", "BDS", 0); +} diff --git a/OvmfPkg/Csm/LegacyBootManagerLib/LegacyBootManagerLib.inf b/OvmfPkg/Csm/LegacyBootManagerLib/LegacyBootManagerLib.inf new file mode 100644 index 0000000000..eaf7b7235d --- /dev/null +++ b/OvmfPkg/Csm/LegacyBootManagerLib/LegacyBootManagerLib.inf @@ -0,0 +1,58 @@ +## @file +# Legacy Boot Manager module is library for BDS phase. +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = LegacyBootManagerLib + MODULE_UNI_FILE = LegacyBootManagerLib.uni + FILE_GUID = F1B87BE4-0ACC-409A-A52B-7BFFABCC96A0 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL|DXE_DRIVER UEFI_APPLICATION + CONSTRUCTOR = LegacyBootManagerLibConstructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + LegacyBm.c + InternalLegacyBm.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + DevicePathLib + MemoryAllocationLib + UefiLib + DebugLib + PrintLib + PerformanceLib + UefiBootManagerLib + +[Guids] + gEfiGlobalVariableGuid ## SOMETIMES_PRODUCES ## Variable:L"Boot####" (Boot option variable) + ## SOMETIMES_CONSUMES ## Variable:L"BootOrder" (The boot option array) + gEfiLegacyDevOrderVariableGuid + +[Protocols] + gEfiLegacyBiosProtocolGuid ## SOMETIMES_CONSUMES + +[FeaturePcd] + +[Pcd] diff --git a/OvmfPkg/Csm/LegacyBootManagerLib/LegacyBootManagerLib.uni b/OvmfPkg/Csm/LegacyBootManagerLib/LegacyBootManagerLib.uni new file mode 100644 index 0000000000..da2915a9a3 --- /dev/null +++ b/OvmfPkg/Csm/LegacyBootManagerLib/LegacyBootManagerLib.uni @@ -0,0 +1,20 @@ +// /** @file +// Legacy Boot Manager module is library for BDS phase. +// +// Legacy Boot Manager module is library for BDS phase. +// +// Copyright (c) 2015, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT +#language en-US +"Legacy Boot Manager module is library for BDS phase." + +#string STR_MODULE_DESCRIPTION +#language en-US +"Legacy Boot Manager module is library for BDS phase." + + -- 2.39.2