summaryrefslogtreecommitdiffstats
path: root/OvmfPkg/Csm
diff options
context:
space:
mode:
authorHao A Wu <hao.a.wu@intel.com>2019-05-15 11:22:29 +0800
committerHao A Wu <hao.a.wu@intel.com>2019-06-14 13:05:33 +0800
commitb522c77bdb4538710715dd13502840a2ca8072f6 (patch)
treebddb2f23f144c6d444340916f3e934cd35ab1c6b /OvmfPkg/Csm
parentbb4485d388392c9b99aac2435ab08e3d54836f26 (diff)
downloadedk2-b522c77bdb4538710715dd13502840a2ca8072f6.tar.gz
edk2-b522c77bdb4538710715dd13502840a2ca8072f6.tar.bz2
edk2-b522c77bdb4538710715dd13502840a2ca8072f6.zip
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 <ray.ni@intel.com> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org> Signed-off-by: Hao A Wu <hao.a.wu@intel.com> Reviewed-by: David Woodhouse <dwmw2@infradead.org> Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Diffstat (limited to 'OvmfPkg/Csm')
-rw-r--r--OvmfPkg/Csm/BiosThunk/VideoDxe/BiosVideo.c3289
-rw-r--r--OvmfPkg/Csm/BiosThunk/VideoDxe/BiosVideo.h532
-rw-r--r--OvmfPkg/Csm/BiosThunk/VideoDxe/BiosVideoDxe.uni17
-rw-r--r--OvmfPkg/Csm/BiosThunk/VideoDxe/BiosVideoDxeExtra.uni14
-rw-r--r--OvmfPkg/Csm/BiosThunk/VideoDxe/ComponentName.c306
-rw-r--r--OvmfPkg/Csm/BiosThunk/VideoDxe/VesaBiosExtensions.h459
-rw-r--r--OvmfPkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf80
-rw-r--r--OvmfPkg/Csm/Include/Framework/BootScript.h41
-rw-r--r--OvmfPkg/Csm/Include/Framework/DxeCis.h170
-rw-r--r--OvmfPkg/Csm/Include/Framework/FirmwareVolumeHeader.h79
-rw-r--r--OvmfPkg/Csm/Include/Framework/FirmwareVolumeImageFormat.h32
-rw-r--r--OvmfPkg/Csm/Include/Framework/FrameworkInternalFormRepresentation.h397
-rw-r--r--OvmfPkg/Csm/Include/Framework/Hob.h28
-rw-r--r--OvmfPkg/Csm/Include/Framework/StatusCode.h155
-rw-r--r--OvmfPkg/Csm/Include/FrameworkDxe.h26
-rw-r--r--OvmfPkg/Csm/Include/Guid/LegacyBios.h29
-rw-r--r--OvmfPkg/Csm/Include/Guid/LegacyDevOrder.h39
-rw-r--r--OvmfPkg/Csm/Include/Protocol/FirmwareVolume.h340
-rw-r--r--OvmfPkg/Csm/Include/Protocol/IsaAcpi.h298
-rw-r--r--OvmfPkg/Csm/Include/Protocol/IsaIo.h356
-rw-r--r--OvmfPkg/Csm/Include/Protocol/LegacyBios.h1553
-rw-r--r--OvmfPkg/Csm/Include/Protocol/LegacyBiosPlatform.h755
-rw-r--r--OvmfPkg/Csm/Include/Protocol/LegacyInterrupt.h122
-rw-r--r--OvmfPkg/Csm/Include/Protocol/VgaMiniPort.h88
-rw-r--r--OvmfPkg/Csm/LegacyBiosDxe/IA32/InterruptTable.nasm63
-rw-r--r--OvmfPkg/Csm/LegacyBiosDxe/LegacyBbs.c377
-rw-r--r--OvmfPkg/Csm/LegacyBiosDxe/LegacyBda.c62
-rw-r--r--OvmfPkg/Csm/LegacyBiosDxe/LegacyBios.c1214
-rw-r--r--OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf131
-rw-r--r--OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxe.uni16
-rw-r--r--OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosDxeExtra.uni14
-rw-r--r--OvmfPkg/Csm/LegacyBiosDxe/LegacyBiosInterface.h1460
-rw-r--r--OvmfPkg/Csm/LegacyBiosDxe/LegacyBootSupport.c2173
-rw-r--r--OvmfPkg/Csm/LegacyBiosDxe/LegacyCmos.c117
-rw-r--r--OvmfPkg/Csm/LegacyBiosDxe/LegacyIde.c310
-rw-r--r--OvmfPkg/Csm/LegacyBiosDxe/LegacyPci.c3083
-rw-r--r--OvmfPkg/Csm/LegacyBiosDxe/LegacySio.c477
-rw-r--r--OvmfPkg/Csm/LegacyBiosDxe/Thunk.c419
-rw-r--r--OvmfPkg/Csm/LegacyBiosDxe/X64/InterruptTable.nasm64
-rw-r--r--OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUi.c1505
-rw-r--r--OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUi.h249
-rw-r--r--OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUiLib.inf63
-rw-r--r--OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUiLib.uni20
-rw-r--r--OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUiStrings.uni43
-rw-r--r--OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUiVfr.Vfr67
-rw-r--r--OvmfPkg/Csm/LegacyBootMaintUiLib/LegacyBootMaintUiVfr.h79
-rw-r--r--OvmfPkg/Csm/LegacyBootManagerLib/InternalLegacyBm.h60
-rw-r--r--OvmfPkg/Csm/LegacyBootManagerLib/LegacyBm.c1530
-rw-r--r--OvmfPkg/Csm/LegacyBootManagerLib/LegacyBootManagerLib.inf58
-rw-r--r--OvmfPkg/Csm/LegacyBootManagerLib/LegacyBootManagerLib.uni20
50 files changed, 22879 insertions, 0 deletions
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.<BR>
+
+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.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _BIOS_GRAPHICS_OUTPUT_H_
+#define _BIOS_GRAPHICS_OUTPUT_H_
+
+#include <FrameworkDxe.h>
+
+#include <Protocol/PciIo.h>
+#include <Protocol/EdidActive.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/EdidDiscovered.h>
+#include <Protocol/LegacyBios.h>
+#include <Protocol/VgaMiniPort.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/EdidOverride.h>
+
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Guid/LegacyBios.h>
+#include <Guid/EventGroup.h>
+
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <IndustryStandard/Pci.h>
+#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.<BR>
+//
+// 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.<BR>
+//
+// 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.<BR>
+
+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.<BR>
+
+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.<BR>
+#
+# 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.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _BOOT_SCRIPT_H_
+#define _BOOT_SCRIPT_H_
+
+#include <PiDxe.h>
+///
+/// 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.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _DXECIS_H_
+#define _DXECIS_H_
+
+#include <Protocol/StatusCode.h>
+
+/**
+ 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.<BR>
+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.<BR>
+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.<BR>
+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.<BR>
+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.<BR>
+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 <Protocol/DebugSupport.h>
+
+///
+/// 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.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _FRAMEWORK_DXE_H_
+#define _FRAMEWORK_DXE_H_
+
+#include <PiDxe.h>
+
+#include <Framework/FrameworkInternalFormRepresentation.h>
+#include <Framework/FirmwareVolumeImageFormat.h>
+#include <Framework/FirmwareVolumeHeader.h>
+#include <Framework/Hob.h>
+#include <Framework/BootScript.h>
+#include <Framework/StatusCode.h>
+#include <Framework/DxeCis.h>
+
+#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.<BR>
+
+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.<BR>
+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.<BR>
+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.
+ <br>
+ If Buffer is NULL, only type, attributes, and size
+ are returned as there is no output buffer.
+ <br>
+ If Buffer != NULL and *Buffer == NULL, the output
+ buffer is allocated from BS pool by ReadFile.
+ <br>
+ 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.
+ <br>
+ If Buffer is NULL, only type, attributes, and size
+ are returned as there is no output buffer.
+ <br>
+ If Buffer != NULL and *Buffer == NULL, the output
+ buffer is allocated from BS pool by ReadFile.
+ <br>
+ 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.<BR>
+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.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_ISA_IO_H_
+#define _EFI_ISA_IO_H_
+
+#include <Protocol/IsaAcpi.h>
+
+///
+/// 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.<BR>
+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.<BR>
+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 <Protocol/LegacyBios.h>
+
+#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.<BR>
+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.<BR>
+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.<BR>
+;
+; 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.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "LegacyBiosInterface.h"
+#include <IndustryStandard/Pci.h>
+
+// 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.<BR>
+
+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.<BR>
+
+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.<BR>
+#
+# 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.<BR>
+//
+// 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.<BR>
+//
+// 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.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _LEGACY_BIOS_INTERFACE_
+#define _LEGACY_BIOS_INTERFACE_
+
+
+#include <FrameworkDxe.h>
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/SmBios.h>
+#include <IndustryStandard/Acpi10.h>
+
+#include <Guid/SmBios.h>
+#include <Guid/Acpi.h>
+#include <Guid/DxeServices.h>
+#include <Guid/LegacyBios.h>
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Guid/ImageAuthentication.h>
+
+#include <Protocol/BlockIo.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/Cpu.h>
+#include <Protocol/Timer.h>
+#include <Protocol/IsaIo.h>
+#include <Protocol/LegacyRegion2.h>
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/LegacyInterrupt.h>
+#include <Protocol/LegacyBios.h>
+#include <Protocol/DiskInfo.h>
+#include <Protocol/GenericMemoryTest.h>
+#include <Protocol/LegacyBiosPlatform.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/Legacy8259.h>
+#include <Protocol/PciRootBridgeIo.h>
+#include <Protocol/SerialIo.h>
+#include <Protocol/SuperIo.h>
+#include <Protocol/IoMmu.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/HobLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/DebugAgentLib.h>
+
+//
+// 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.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "LegacyBiosInterface.h"
+#include <IndustryStandard/Pci.h>
+
+#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.<BR>
+
+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.<BR>
+
+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.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "LegacyBiosInterface.h"
+#include <IndustryStandard/Pci30.h>
+
+#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.<BR>
+
+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.<BR>
+
+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.<BR>
+;
+; 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.<BR>
+(C) Copyright 2018 Hewlett Packard Enterprise Development LP<BR>
+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 <ConfigRequest> 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 <ConfigAltResp> 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 <ConfigResp> 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 <ConfigHdr>.
+ // 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 <ConfigResp> 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.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef _EFI_LEGACY_BOOT_OPTION_H_
+#define _EFI_LEGACY_BOOT_OPTION_H_
+
+#include <PiDxe.h>
+
+
+#include <Guid/GlobalVariable.h>
+#include <Guid/LegacyDevOrder.h>
+#include <Guid/MdeModuleHii.h>
+
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/HiiConfigRouting.h>
+
+#include <Protocol/HiiDatabase.h>
+#include <Protocol/LegacyBios.h>
+
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HiiLib.h>
+#include <Library/UefiBootManagerLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PrintLib.h>
+#include <Library/BaseMemoryLib.h>
+
+#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 <ConfigRequest> 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 <ConfigAltResp> 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 <ConfigResp> 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.<BR>
+# 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.<BR>
+//
+// 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.<BR>
+// 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.<BR>
+// 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.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef _EFI_LEGACY_BOOT_OPTION_VFR_H_
+#define _EFI_LEGACY_BOOT_OPTION_VFR_H_
+
+#include <Guid/HiiBootMaintenanceFormset.h>
+
+#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.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _INTERNAL_LEGACY_BM_H_
+#define _INTERNAL_LEGACY_BM_H_
+
+#include <PiDxe.h>
+#include <Guid/LegacyDevOrder.h>
+#include <Guid/GlobalVariable.h>
+#include <Protocol/LegacyBios.h>
+#include <Protocol/PciRootBridgeIo.h>
+#include <Protocol/PciIo.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiBootManagerLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PrintLib.h>
+#include <Library/PerformanceLib.h>
+
+#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.<BR>
+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.<BR>
+# 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.<BR>
+//
+// 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."
+
+