diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
commit | f215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch) | |
tree | 6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe | |
parent | Initial commit. (diff) | |
download | virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip |
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe')
10 files changed, 3920 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/ComponentName.c b/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/ComponentName.c new file mode 100644 index 00000000..a0f20671 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/ComponentName.c @@ -0,0 +1,206 @@ +/** @file + Component name for the QEMU video controller. + + Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Qemu.h" + +// +// EFI Component Name Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gQemuVideoComponentName = { + QemuVideoComponentNameGetDriverName, + QemuVideoComponentNameGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gQemuVideoComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) QemuVideoComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) QemuVideoComponentNameGetControllerName, + "en" +}; + + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mQemuVideoDriverNameTable[] = { + { "eng;en", L"QEMU Video Driver" }, + { NULL , NULL } +}; + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mQemuVideoControllerNameTable[] = { + { "eng;en", L"QEMU Video PCI Adapter" }, + { 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 +QemuVideoComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mQemuVideoDriverNameTable, + DriverName, + (BOOLEAN)(This == &gQemuVideoComponentName) + ); +} + +/** + 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 not a valid EFI_HANDLE. + + @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 +QemuVideoComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + EFI_STATUS Status; + + // + // This is a device driver, so ChildHandle must be NULL. + // + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + // + // Make sure this driver is currently managing ControllHandle + // + Status = EfiTestManagedDevice ( + ControllerHandle, + gQemuVideoDriverBinding.DriverBindingHandle, + &gEfiPciIoProtocolGuid + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get the QEMU Video's Device structure + // + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mQemuVideoControllerNameTable, + ControllerName, + (BOOLEAN)(This == &gQemuVideoComponentName) + ); +} diff --git a/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/Driver.c b/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/Driver.c new file mode 100644 index 00000000..ffae1361 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/Driver.c @@ -0,0 +1,1006 @@ +/** @file + This driver is a sample implementation of the Graphics Output Protocol for + the QEMU (Cirrus Logic 5446) video controller. + + Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Qemu.h" +#include <IndustryStandard/Acpi.h> + +EFI_DRIVER_BINDING_PROTOCOL gQemuVideoDriverBinding = { + QemuVideoControllerDriverSupported, + QemuVideoControllerDriverStart, + QemuVideoControllerDriverStop, + 0x10, + NULL, + NULL +}; + +QEMU_VIDEO_CARD gQemuVideoCardList[] = { + { + PCI_CLASS_DISPLAY_VGA, + CIRRUS_LOGIC_VENDOR_ID, + CIRRUS_LOGIC_5430_DEVICE_ID, + QEMU_VIDEO_CIRRUS_5430, + L"Cirrus 5430" + },{ + PCI_CLASS_DISPLAY_VGA, + CIRRUS_LOGIC_VENDOR_ID, + CIRRUS_LOGIC_5430_ALTERNATE_DEVICE_ID, + QEMU_VIDEO_CIRRUS_5430, + L"Cirrus 5430" + },{ + PCI_CLASS_DISPLAY_VGA, + CIRRUS_LOGIC_VENDOR_ID, + CIRRUS_LOGIC_5446_DEVICE_ID, + QEMU_VIDEO_CIRRUS_5446, + L"Cirrus 5446" + },{ + PCI_CLASS_DISPLAY_VGA, + 0x1234, + 0x1111, + QEMU_VIDEO_BOCHS_MMIO, + L"QEMU Standard VGA" + },{ + PCI_CLASS_DISPLAY_OTHER, + 0x1234, + 0x1111, + QEMU_VIDEO_BOCHS_MMIO, + L"QEMU Standard VGA (secondary)" + },{ + PCI_CLASS_DISPLAY_VGA, + 0x1b36, + 0x0100, + QEMU_VIDEO_BOCHS, + L"QEMU QXL VGA" + },{ + PCI_CLASS_DISPLAY_VGA, + 0x1af4, + 0x1050, + QEMU_VIDEO_BOCHS_MMIO, + L"QEMU VirtIO VGA" + },{ + PCI_CLASS_DISPLAY_VGA, + 0x15ad, + 0x0405, + QEMU_VIDEO_VMWARE_SVGA, + L"QEMU VMWare SVGA" + },{ + 0 /* end of list */ + } +}; + +static QEMU_VIDEO_CARD* +QemuVideoDetect( + IN UINT8 SubClass, + IN UINT16 VendorId, + IN UINT16 DeviceId + ) +{ + UINTN Index = 0; + + while (gQemuVideoCardList[Index].VendorId != 0) { + if (gQemuVideoCardList[Index].SubClass == SubClass && + gQemuVideoCardList[Index].VendorId == VendorId && + gQemuVideoCardList[Index].DeviceId == DeviceId) { + return gQemuVideoCardList + Index; + } + Index++; + } + return NULL; +} + +/** + Check if this device is supported. + + @param This The driver binding protocol. + @param Controller The controller handle to check. + @param RemainingDevicePath The remaining device path. + + @retval EFI_SUCCESS The bus supports this controller. + @retval EFI_UNSUPPORTED This device isn't supported. + +**/ +EFI_STATUS +EFIAPI +QemuVideoControllerDriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_PCI_IO_PROTOCOL *PciIo; + PCI_TYPE00 Pci; + QEMU_VIDEO_CARD *Card; + + // + // Open the PCI I/O Protocol + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Read the PCI Configuration Header from the PCI Device + // + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint32, + 0, + sizeof (Pci) / sizeof (UINT32), + &Pci + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = EFI_UNSUPPORTED; + if (!IS_PCI_DISPLAY (&Pci)) { + goto Done; + } + Card = QemuVideoDetect(Pci.Hdr.ClassCode[1], Pci.Hdr.VendorId, Pci.Hdr.DeviceId); + if (Card != NULL) { + DEBUG ((DEBUG_INFO, "QemuVideo: %s detected\n", Card->Name)); + Status = EFI_SUCCESS; + } + +Done: + // + // Close the PCI I/O Protocol + // + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; +} + +/** + Start to process the controller. + + @param This The USB bus driver binding instance. + @param Controller The controller to check. + @param RemainingDevicePath The remaining device patch. + + @retval EFI_SUCCESS The controller is controlled by the usb bus. + @retval EFI_ALREADY_STARTED The controller is already controlled by the usb + bus. + @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. + +**/ +EFI_STATUS +EFIAPI +QemuVideoControllerDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_TPL OldTpl; + EFI_STATUS Status; + QEMU_VIDEO_PRIVATE_DATA *Private; + BOOLEAN IsQxl; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + ACPI_ADR_DEVICE_PATH AcpiDeviceNode; + PCI_TYPE00 Pci; + QEMU_VIDEO_CARD *Card; + EFI_PCI_IO_PROTOCOL *ChildPciIo; + UINT64 SupportedVgaIo; + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + // + // Allocate Private context data for GOP interface. + // + Private = AllocateZeroPool (sizeof (QEMU_VIDEO_PRIVATE_DATA)); + if (Private == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto RestoreTpl; + } + + // + // Set up context record + // + Private->Signature = QEMU_VIDEO_PRIVATE_DATA_SIGNATURE; + + // + // Open PCI I/O Protocol + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &Private->PciIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto FreePrivate; + } + + // + // Read the PCI Configuration Header from the PCI Device + // + Status = Private->PciIo->Pci.Read ( + Private->PciIo, + EfiPciIoWidthUint32, + 0, + sizeof (Pci) / sizeof (UINT32), + &Pci + ); + if (EFI_ERROR (Status)) { + goto ClosePciIo; + } + + // + // Determine card variant. + // + Card = QemuVideoDetect(Pci.Hdr.ClassCode[1], Pci.Hdr.VendorId, Pci.Hdr.DeviceId); + if (Card == NULL) { + Status = EFI_DEVICE_ERROR; + goto ClosePciIo; + } + Private->Variant = Card->Variant; + + // + // IsQxl is based on the detected Card->Variant, which at a later point might + // not match Private->Variant. + // + IsQxl = (BOOLEAN)(Card->Variant == QEMU_VIDEO_BOCHS); + + // + // Save original PCI attributes + // + Status = Private->PciIo->Attributes ( + Private->PciIo, + EfiPciIoAttributeOperationGet, + 0, + &Private->OriginalPciAttributes + ); + + if (EFI_ERROR (Status)) { + goto ClosePciIo; + } + + // + // Get supported PCI attributes + // + Status = Private->PciIo->Attributes ( + Private->PciIo, + EfiPciIoAttributeOperationSupported, + 0, + &SupportedVgaIo + ); + if (EFI_ERROR (Status)) { + goto ClosePciIo; + } + + SupportedVgaIo &= (UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16); + if (SupportedVgaIo == 0 && IS_PCI_VGA (&Pci)) { + Status = EFI_UNSUPPORTED; + goto ClosePciIo; + } + + // + // Set new PCI attributes + // + Status = Private->PciIo->Attributes ( + Private->PciIo, + EfiPciIoAttributeOperationEnable, + EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | SupportedVgaIo, + NULL + ); + if (EFI_ERROR (Status)) { + goto ClosePciIo; + } + + // + // Check whenever the qemu stdvga mmio bar is present (qemu 1.3+). + // + if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) { + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *MmioDesc; + + Status = Private->PciIo->GetBarAttributes ( + Private->PciIo, + PCI_BAR_IDX2, + NULL, + (VOID**) &MmioDesc + ); + if (EFI_ERROR (Status) || + MmioDesc->ResType != ACPI_ADDRESS_SPACE_TYPE_MEM) { + DEBUG ((DEBUG_INFO, "QemuVideo: No mmio bar, fallback to port io\n")); + Private->Variant = QEMU_VIDEO_BOCHS; + } else { + DEBUG ((DEBUG_INFO, "QemuVideo: Using mmio bar @ 0x%lx\n", + MmioDesc->AddrRangeMin)); + } + + if (!EFI_ERROR (Status)) { + FreePool (MmioDesc); + } + } + + // + // VMWare SVGA is handled like Bochs (with port IO only). + // + if (Private->Variant == QEMU_VIDEO_VMWARE_SVGA) { + Private->Variant = QEMU_VIDEO_BOCHS; + Private->FrameBufferVramBarIndex = PCI_BAR_IDX1; + } + + // + // Check if accessing the bochs interface works. + // + if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO || + Private->Variant == QEMU_VIDEO_BOCHS) { + UINT16 BochsId; + BochsId = BochsRead(Private, VBE_DISPI_INDEX_ID); + if ((BochsId & 0xFFF0) != VBE_DISPI_ID0) { + DEBUG ((DEBUG_INFO, "QemuVideo: BochsID mismatch (got 0x%x)\n", BochsId)); + Status = EFI_DEVICE_ERROR; + goto RestoreAttributes; + } + } + + // + // Get ParentDevicePath + // + Status = gBS->HandleProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &ParentDevicePath + ); + if (EFI_ERROR (Status)) { + goto RestoreAttributes; + } + + // + // Set Gop Device Path + // + 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)); + + Private->GopDevicePath = AppendDevicePathNode ( + ParentDevicePath, + (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode + ); + if (Private->GopDevicePath == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto RestoreAttributes; + } + + // + // Create new child handle and install the device path protocol on it. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &Private->Handle, + &gEfiDevicePathProtocolGuid, + Private->GopDevicePath, + NULL + ); + if (EFI_ERROR (Status)) { + goto FreeGopDevicePath; + } + + // + // Construct video mode buffer + // + switch (Private->Variant) { + case QEMU_VIDEO_CIRRUS_5430: + case QEMU_VIDEO_CIRRUS_5446: + Status = QemuVideoCirrusModeSetup (Private); + break; + case QEMU_VIDEO_BOCHS_MMIO: + case QEMU_VIDEO_BOCHS: + Status = QemuVideoBochsModeSetup (Private, IsQxl); + break; + default: + ASSERT (FALSE); + Status = EFI_DEVICE_ERROR; + break; + } + if (EFI_ERROR (Status)) { + goto UninstallGopDevicePath; + } + + // + // Start the GOP software stack. + // + Status = QemuVideoGraphicsOutputConstructor (Private); + if (EFI_ERROR (Status)) { + goto FreeModeData; + } + + Status = gBS->InstallMultipleProtocolInterfaces ( + &Private->Handle, + &gEfiGraphicsOutputProtocolGuid, + &Private->GraphicsOutput, + NULL + ); + if (EFI_ERROR (Status)) { + goto DestructQemuVideoGraphics; + } + + // + // Reference parent handle from child handle. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + (VOID **) &ChildPciIo, + This->DriverBindingHandle, + Private->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + if (EFI_ERROR (Status)) { + goto UninstallGop; + } + +#if defined MDE_CPU_IA32 || defined MDE_CPU_X64 + if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO || + Private->Variant == QEMU_VIDEO_BOCHS) { + InstallVbeShim (Card->Name, Private->GraphicsOutput.Mode->FrameBufferBase); + } +#endif + + gBS->RestoreTPL (OldTpl); + return EFI_SUCCESS; + +UninstallGop: + gBS->UninstallProtocolInterface (Private->Handle, + &gEfiGraphicsOutputProtocolGuid, &Private->GraphicsOutput); + +DestructQemuVideoGraphics: + QemuVideoGraphicsOutputDestructor (Private); + +FreeModeData: + FreePool (Private->ModeData); + +UninstallGopDevicePath: + gBS->UninstallProtocolInterface (Private->Handle, + &gEfiDevicePathProtocolGuid, Private->GopDevicePath); + +FreeGopDevicePath: + FreePool (Private->GopDevicePath); + +RestoreAttributes: + Private->PciIo->Attributes (Private->PciIo, EfiPciIoAttributeOperationSet, + Private->OriginalPciAttributes, NULL); + +ClosePciIo: + gBS->CloseProtocol (Controller, &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, Controller); + +FreePrivate: + FreePool (Private); + +RestoreTpl: + gBS->RestoreTPL (OldTpl); + + return Status; +} + +/** + Stop this device + + @param This The USB bus driver binding protocol. + @param Controller The controller to release. + @param NumberOfChildren The number of children of this device that + opened the controller BY_CHILD. + @param ChildHandleBuffer The array of child handle. + + @retval EFI_SUCCESS The controller or children are stopped. + @retval EFI_DEVICE_ERROR Failed to stop the driver. + +**/ +EFI_STATUS +EFIAPI +QemuVideoControllerDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; + + EFI_STATUS Status; + QEMU_VIDEO_PRIVATE_DATA *Private; + + if (NumberOfChildren == 0) { + // + // Close the PCI I/O Protocol + // + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return EFI_SUCCESS; + } + + // + // free all resources for whose access we need the child handle, because the + // child handle is going away + // + ASSERT (NumberOfChildren == 1); + Status = gBS->OpenProtocol ( + ChildHandleBuffer[0], + &gEfiGraphicsOutputProtocolGuid, + (VOID **) &GraphicsOutput, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get our private context information + // + Private = QEMU_VIDEO_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput); + ASSERT (Private->Handle == ChildHandleBuffer[0]); + + QemuVideoGraphicsOutputDestructor (Private); + // + // Remove the GOP protocol interface from the system + // + Status = gBS->UninstallMultipleProtocolInterfaces ( + Private->Handle, + &gEfiGraphicsOutputProtocolGuid, + &Private->GraphicsOutput, + NULL + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Restore original PCI attributes + // + Private->PciIo->Attributes ( + Private->PciIo, + EfiPciIoAttributeOperationSet, + Private->OriginalPciAttributes, + NULL + ); + + gBS->CloseProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, + Private->Handle + ); + + FreePool (Private->ModeData); + gBS->UninstallProtocolInterface (Private->Handle, + &gEfiDevicePathProtocolGuid, Private->GopDevicePath); + FreePool (Private->GopDevicePath); + + // + // Free our instance data + // + gBS->FreePool (Private); + + return EFI_SUCCESS; +} + +/** + TODO: Add function description + + @param Private TODO: add argument description + @param Address TODO: add argument description + @param Data TODO: add argument description + + TODO: add return values + +**/ +VOID +outb ( + QEMU_VIDEO_PRIVATE_DATA *Private, + UINTN Address, + UINT8 Data + ) +{ + Private->PciIo->Io.Write ( + Private->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + Address, + 1, + &Data + ); +} + +/** + TODO: Add function description + + @param Private TODO: add argument description + @param Address TODO: add argument description + @param Data TODO: add argument description + + TODO: add return values + +**/ +VOID +outw ( + QEMU_VIDEO_PRIVATE_DATA *Private, + UINTN Address, + UINT16 Data + ) +{ + Private->PciIo->Io.Write ( + Private->PciIo, + EfiPciIoWidthUint16, + EFI_PCI_IO_PASS_THROUGH_BAR, + Address, + 1, + &Data + ); +} + +/** + TODO: Add function description + + @param Private TODO: add argument description + @param Address TODO: add argument description + + TODO: add return values + +**/ +UINT8 +inb ( + QEMU_VIDEO_PRIVATE_DATA *Private, + UINTN Address + ) +{ + UINT8 Data; + + Private->PciIo->Io.Read ( + Private->PciIo, + EfiPciIoWidthUint8, + EFI_PCI_IO_PASS_THROUGH_BAR, + Address, + 1, + &Data + ); + return Data; +} + +/** + TODO: Add function description + + @param Private TODO: add argument description + @param Address TODO: add argument description + + TODO: add return values + +**/ +UINT16 +inw ( + QEMU_VIDEO_PRIVATE_DATA *Private, + UINTN Address + ) +{ + UINT16 Data; + + Private->PciIo->Io.Read ( + Private->PciIo, + EfiPciIoWidthUint16, + EFI_PCI_IO_PASS_THROUGH_BAR, + Address, + 1, + &Data + ); + return Data; +} + +/** + TODO: Add function description + + @param Private TODO: add argument description + @param Index TODO: add argument description + @param Red TODO: add argument description + @param Green TODO: add argument description + @param Blue TODO: add argument description + + TODO: add return values + +**/ +VOID +SetPaletteColor ( + QEMU_VIDEO_PRIVATE_DATA *Private, + UINTN Index, + UINT8 Red, + UINT8 Green, + UINT8 Blue + ) +{ + VgaOutb (Private, PALETTE_INDEX_REGISTER, (UINT8) Index); + VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8) (Red >> 2)); + VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8) (Green >> 2)); + VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8) (Blue >> 2)); +} + +/** + TODO: Add function description + + @param Private TODO: add argument description + + TODO: add return values + +**/ +VOID +SetDefaultPalette ( + QEMU_VIDEO_PRIVATE_DATA *Private + ) +{ + UINTN Index; + UINTN RedIndex; + UINTN GreenIndex; + UINTN BlueIndex; + + Index = 0; + for (RedIndex = 0; RedIndex < 8; RedIndex++) { + for (GreenIndex = 0; GreenIndex < 8; GreenIndex++) { + for (BlueIndex = 0; BlueIndex < 4; BlueIndex++) { + SetPaletteColor (Private, Index, (UINT8) (RedIndex << 5), (UINT8) (GreenIndex << 5), (UINT8) (BlueIndex << 6)); + Index++; + } + } + } +} + +/** + TODO: Add function description + + @param Private TODO: add argument description + + TODO: add return values + +**/ +VOID +ClearScreen ( + QEMU_VIDEO_PRIVATE_DATA *Private + ) +{ + UINT32 Color; + + Color = 0; + Private->PciIo->Mem.Write ( + Private->PciIo, + EfiPciIoWidthFillUint32, + Private->FrameBufferVramBarIndex, + 0, + 0x400000 >> 2, + &Color + ); +} + +/** + TODO: Add function description + + @param Private TODO: add argument description + + TODO: add return values + +**/ +VOID +DrawLogo ( + QEMU_VIDEO_PRIVATE_DATA *Private, + UINTN ScreenWidth, + UINTN ScreenHeight + ) +{ +} + +/** + TODO: Add function description + + @param Private TODO: add argument description + @param ModeData TODO: add argument description + + TODO: add return values + +**/ +VOID +InitializeCirrusGraphicsMode ( + QEMU_VIDEO_PRIVATE_DATA *Private, + QEMU_VIDEO_CIRRUS_MODES *ModeData + ) +{ + UINT8 Byte; + UINTN Index; + + outw (Private, SEQ_ADDRESS_REGISTER, 0x1206); + outw (Private, SEQ_ADDRESS_REGISTER, 0x0012); + + for (Index = 0; Index < 15; Index++) { + outw (Private, SEQ_ADDRESS_REGISTER, ModeData->SeqSettings[Index]); + } + + if (Private->Variant == QEMU_VIDEO_CIRRUS_5430) { + outb (Private, SEQ_ADDRESS_REGISTER, 0x0f); + Byte = (UINT8) ((inb (Private, SEQ_DATA_REGISTER) & 0xc7) ^ 0x30); + outb (Private, SEQ_DATA_REGISTER, Byte); + } + + outb (Private, MISC_OUTPUT_REGISTER, ModeData->MiscSetting); + outw (Private, GRAPH_ADDRESS_REGISTER, 0x0506); + outw (Private, SEQ_ADDRESS_REGISTER, 0x0300); + outw (Private, CRTC_ADDRESS_REGISTER, 0x2011); + + for (Index = 0; Index < 28; Index++) { + outw (Private, CRTC_ADDRESS_REGISTER, (UINT16) ((ModeData->CrtcSettings[Index] << 8) | Index)); + } + + for (Index = 0; Index < 9; Index++) { + outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((GraphicsController[Index] << 8) | Index)); + } + + inb (Private, INPUT_STATUS_1_REGISTER); + + for (Index = 0; Index < 21; Index++) { + outb (Private, ATT_ADDRESS_REGISTER, (UINT8) Index); + outb (Private, ATT_ADDRESS_REGISTER, AttributeController[Index]); + } + + outb (Private, ATT_ADDRESS_REGISTER, 0x20); + + outw (Private, GRAPH_ADDRESS_REGISTER, 0x0009); + outw (Private, GRAPH_ADDRESS_REGISTER, 0x000a); + outw (Private, GRAPH_ADDRESS_REGISTER, 0x000b); + outb (Private, DAC_PIXEL_MASK_REGISTER, 0xff); + + SetDefaultPalette (Private); + ClearScreen (Private); +} + +VOID +BochsWrite ( + QEMU_VIDEO_PRIVATE_DATA *Private, + UINT16 Reg, + UINT16 Data + ) +{ + EFI_STATUS Status; + + if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) { + Status = Private->PciIo->Mem.Write ( + Private->PciIo, + EfiPciIoWidthUint16, + PCI_BAR_IDX2, + 0x500 + (Reg << 1), + 1, + &Data + ); + ASSERT_EFI_ERROR (Status); + } else { + outw (Private, VBE_DISPI_IOPORT_INDEX, Reg); + outw (Private, VBE_DISPI_IOPORT_DATA, Data); + } +} + +UINT16 +BochsRead ( + QEMU_VIDEO_PRIVATE_DATA *Private, + UINT16 Reg + ) +{ + EFI_STATUS Status; + UINT16 Data; + + if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) { + Status = Private->PciIo->Mem.Read ( + Private->PciIo, + EfiPciIoWidthUint16, + PCI_BAR_IDX2, + 0x500 + (Reg << 1), + 1, + &Data + ); + ASSERT_EFI_ERROR (Status); + } else { + outw (Private, VBE_DISPI_IOPORT_INDEX, Reg); + Data = inw (Private, VBE_DISPI_IOPORT_DATA); + } + return Data; +} + +VOID +VgaOutb ( + QEMU_VIDEO_PRIVATE_DATA *Private, + UINTN Reg, + UINT8 Data + ) +{ + EFI_STATUS Status; + + if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) { + Status = Private->PciIo->Mem.Write ( + Private->PciIo, + EfiPciIoWidthUint8, + PCI_BAR_IDX2, + 0x400 - 0x3c0 + Reg, + 1, + &Data + ); + ASSERT_EFI_ERROR (Status); + } else { + outb (Private, Reg, Data); + } +} + +VOID +InitializeBochsGraphicsMode ( + QEMU_VIDEO_PRIVATE_DATA *Private, + QEMU_VIDEO_BOCHS_MODES *ModeData + ) +{ + DEBUG ((DEBUG_INFO, "InitializeBochsGraphicsMode: %dx%d @ %d\n", + ModeData->Width, ModeData->Height, ModeData->ColorDepth)); + + /* unblank */ + VgaOutb (Private, ATT_ADDRESS_REGISTER, 0x20); + + BochsWrite (Private, VBE_DISPI_INDEX_ENABLE, 0); + BochsWrite (Private, VBE_DISPI_INDEX_BANK, 0); + BochsWrite (Private, VBE_DISPI_INDEX_X_OFFSET, 0); + BochsWrite (Private, VBE_DISPI_INDEX_Y_OFFSET, 0); + + BochsWrite (Private, VBE_DISPI_INDEX_BPP, (UINT16) ModeData->ColorDepth); + BochsWrite (Private, VBE_DISPI_INDEX_XRES, (UINT16) ModeData->Width); + BochsWrite (Private, VBE_DISPI_INDEX_VIRT_WIDTH, (UINT16) ModeData->Width); + BochsWrite (Private, VBE_DISPI_INDEX_YRES, (UINT16) ModeData->Height); + BochsWrite (Private, VBE_DISPI_INDEX_VIRT_HEIGHT, (UINT16) ModeData->Height); + + BochsWrite (Private, VBE_DISPI_INDEX_ENABLE, + VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED); + + SetDefaultPalette (Private); + ClearScreen (Private); +} + +EFI_STATUS +EFIAPI +InitializeQemuVideo ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gQemuVideoDriverBinding, + ImageHandle, + &gQemuVideoComponentName, + &gQemuVideoComponentName2 + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/Gop.c b/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/Gop.c new file mode 100644 index 00000000..e1cf1651 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/Gop.c @@ -0,0 +1,417 @@ +/** @file + Graphics Output Protocol functions for the QEMU video controller. + + Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Qemu.h" + +STATIC +VOID +QemuVideoCompleteModeInfo ( + IN QEMU_VIDEO_MODE_DATA *ModeData, + OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info + ) +{ + Info->Version = 0; + if (ModeData->ColorDepth == 8) { + Info->PixelFormat = PixelBitMask; + Info->PixelInformation.RedMask = PIXEL_RED_MASK; + Info->PixelInformation.GreenMask = PIXEL_GREEN_MASK; + Info->PixelInformation.BlueMask = PIXEL_BLUE_MASK; + Info->PixelInformation.ReservedMask = 0; + } else if (ModeData->ColorDepth == 24) { + Info->PixelFormat = PixelBitMask; + Info->PixelInformation.RedMask = PIXEL24_RED_MASK; + Info->PixelInformation.GreenMask = PIXEL24_GREEN_MASK; + Info->PixelInformation.BlueMask = PIXEL24_BLUE_MASK; + Info->PixelInformation.ReservedMask = 0; + } else if (ModeData->ColorDepth == 32) { + DEBUG ((DEBUG_INFO, "PixelBlueGreenRedReserved8BitPerColor\n")); + Info->PixelFormat = PixelBlueGreenRedReserved8BitPerColor; + } + Info->PixelsPerScanLine = Info->HorizontalResolution; +} + + +STATIC +EFI_STATUS +QemuVideoCompleteModeData ( + IN QEMU_VIDEO_PRIVATE_DATA *Private, + OUT EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode + ) +{ + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *FrameBufDesc; + QEMU_VIDEO_MODE_DATA *ModeData; + + ModeData = &Private->ModeData[Mode->Mode]; + Info = Mode->Info; + QemuVideoCompleteModeInfo (ModeData, Info); + + Private->PciIo->GetBarAttributes ( + Private->PciIo, + Private->FrameBufferVramBarIndex, + NULL, + (VOID**) &FrameBufDesc + ); + + Mode->FrameBufferBase = FrameBufDesc->AddrRangeMin; + Mode->FrameBufferSize = Info->HorizontalResolution * Info->VerticalResolution; + Mode->FrameBufferSize = Mode->FrameBufferSize * ((ModeData->ColorDepth + 7) / 8); + Mode->FrameBufferSize = EFI_PAGES_TO_SIZE ( + EFI_SIZE_TO_PAGES (Mode->FrameBufferSize) + ); + DEBUG ((DEBUG_INFO, "FrameBufferBase: 0x%Lx, FrameBufferSize: 0x%Lx\n", + Mode->FrameBufferBase, (UINT64)Mode->FrameBufferSize)); + + FreePool (FrameBufDesc); + return EFI_SUCCESS; +} + +// +// Graphics Output Protocol Member Functions +// +EFI_STATUS +EFIAPI +QemuVideoGraphicsOutputQueryMode ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN UINT32 ModeNumber, + OUT UINTN *SizeOfInfo, + OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info + ) +/*++ + +Routine Description: + + Graphics Output protocol interface to query video mode + + Arguments: + This - Protocol instance pointer. + ModeNumber - The mode number to return information on. + Info - Caller allocated buffer that returns information about ModeNumber. + SizeOfInfo - A pointer to the size, in bytes, of the Info buffer. + + Returns: + EFI_SUCCESS - Mode information returned. + EFI_BUFFER_TOO_SMALL - The Info buffer was too small. + EFI_DEVICE_ERROR - A hardware error occurred trying to retrieve the video mode. + EFI_NOT_STARTED - Video display is not initialized. Call SetMode () + EFI_INVALID_PARAMETER - One of the input args was NULL. + +--*/ +{ + QEMU_VIDEO_PRIVATE_DATA *Private; + QEMU_VIDEO_MODE_DATA *ModeData; + + Private = QEMU_VIDEO_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This); + + if (Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) { + return EFI_INVALID_PARAMETER; + } + + *Info = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)); + if (*Info == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); + + ModeData = &Private->ModeData[ModeNumber]; + (*Info)->HorizontalResolution = ModeData->HorizontalResolution; + (*Info)->VerticalResolution = ModeData->VerticalResolution; + QemuVideoCompleteModeInfo (ModeData, *Info); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +QemuVideoGraphicsOutputSetMode ( + IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This, + IN UINT32 ModeNumber + ) +/*++ + +Routine Description: + + Graphics Output protocol interface to set video mode + + Arguments: + This - Protocol instance pointer. + ModeNumber - The mode number to be set. + + Returns: + EFI_SUCCESS - Graphics mode was changed. + EFI_DEVICE_ERROR - The device had an error and could not complete the request. + EFI_UNSUPPORTED - ModeNumber is not supported by this device. + +--*/ +{ + QEMU_VIDEO_PRIVATE_DATA *Private; + QEMU_VIDEO_MODE_DATA *ModeData; + RETURN_STATUS Status; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL Black; + + Private = QEMU_VIDEO_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This); + + if (ModeNumber >= This->Mode->MaxMode) { + return EFI_UNSUPPORTED; + } + + ModeData = &Private->ModeData[ModeNumber]; + + switch (Private->Variant) { + case QEMU_VIDEO_CIRRUS_5430: + case QEMU_VIDEO_CIRRUS_5446: + InitializeCirrusGraphicsMode (Private, &QemuVideoCirrusModes[ModeData->InternalModeIndex]); + break; + case QEMU_VIDEO_BOCHS_MMIO: + case QEMU_VIDEO_BOCHS: + InitializeBochsGraphicsMode (Private, &QemuVideoBochsModes[ModeData->InternalModeIndex]); + break; + default: + ASSERT (FALSE); + return EFI_DEVICE_ERROR; + } + + This->Mode->Mode = ModeNumber; + This->Mode->Info->HorizontalResolution = ModeData->HorizontalResolution; + This->Mode->Info->VerticalResolution = ModeData->VerticalResolution; + This->Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION); + + QemuVideoCompleteModeData (Private, This->Mode); + + // + // Re-initialize the frame buffer configure when mode changes. + // + Status = FrameBufferBltConfigure ( + (VOID*) (UINTN) This->Mode->FrameBufferBase, + This->Mode->Info, + Private->FrameBufferBltConfigure, + &Private->FrameBufferBltConfigureSize + ); + if (Status == RETURN_BUFFER_TOO_SMALL) { + // + // Frame buffer configure may be larger in new mode. + // + if (Private->FrameBufferBltConfigure != NULL) { + FreePool (Private->FrameBufferBltConfigure); + } + Private->FrameBufferBltConfigure = + AllocatePool (Private->FrameBufferBltConfigureSize); + ASSERT (Private->FrameBufferBltConfigure != NULL); + + // + // Create the configuration for FrameBufferBltLib + // + Status = FrameBufferBltConfigure ( + (VOID*) (UINTN) This->Mode->FrameBufferBase, + This->Mode->Info, + Private->FrameBufferBltConfigure, + &Private->FrameBufferBltConfigureSize + ); + } + ASSERT (Status == RETURN_SUCCESS); + + // + // Per UEFI Spec, need to clear the visible portions of the output display to black. + // + ZeroMem (&Black, sizeof (Black)); + Status = FrameBufferBlt ( + Private->FrameBufferBltConfigure, + &Black, + EfiBltVideoFill, + 0, 0, + 0, 0, + This->Mode->Info->HorizontalResolution, This->Mode->Info->VerticalResolution, + 0 + ); + ASSERT_RETURN_ERROR (Status); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +QemuVideoGraphicsOutputBlt ( + 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 + ) +/*++ + +Routine Description: + + Graphics Output protocol instance to block transfer for CirrusLogic device + +Arguments: + + This - Pointer to Graphics Output protocol instance + BltBuffer - The data to transfer to screen + BltOperation - The operation to perform + SourceX - The X coordinate of the source for BltOperation + SourceY - The Y coordinate of the source for BltOperation + DestinationX - The X coordinate of the destination for BltOperation + DestinationY - The Y coordinate of the destination for BltOperation + Width - The width of a rectangle in the blt rectangle in pixels + Height - The height of a rectangle in the blt rectangle in pixels + 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. + +Returns: + + EFI_INVALID_PARAMETER - Invalid parameter passed in + EFI_SUCCESS - Blt operation success + +--*/ +{ + EFI_STATUS Status; + EFI_TPL OriginalTPL; + QEMU_VIDEO_PRIVATE_DATA *Private; + + Private = QEMU_VIDEO_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This); + // + // 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: + case EfiBltBufferToVideo: + case EfiBltVideoFill: + case EfiBltVideoToVideo: + Status = FrameBufferBlt ( + Private->FrameBufferBltConfigure, + BltBuffer, + BltOperation, + SourceX, + SourceY, + DestinationX, + DestinationY, + Width, + Height, + Delta + ); + break; + + default: + Status = EFI_INVALID_PARAMETER; + break; + } + + gBS->RestoreTPL (OriginalTPL); + + return Status; +} + +EFI_STATUS +QemuVideoGraphicsOutputConstructor ( + QEMU_VIDEO_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput; + + + GraphicsOutput = &Private->GraphicsOutput; + GraphicsOutput->QueryMode = QemuVideoGraphicsOutputQueryMode; + GraphicsOutput->SetMode = QemuVideoGraphicsOutputSetMode; + GraphicsOutput->Blt = QemuVideoGraphicsOutputBlt; + + // + // Initialize the private data + // + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE), + (VOID **) &Private->GraphicsOutput.Mode + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION), + (VOID **) &Private->GraphicsOutput.Mode->Info + ); + if (EFI_ERROR (Status)) { + goto FreeMode; + } + Private->GraphicsOutput.Mode->MaxMode = (UINT32) Private->MaxMode; + Private->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER; + Private->FrameBufferBltConfigure = NULL; + Private->FrameBufferBltConfigureSize = 0; + + // + // Initialize the hardware + // + Status = GraphicsOutput->SetMode (GraphicsOutput, 0); + if (EFI_ERROR (Status)) { + goto FreeInfo; + } + + DrawLogo ( + Private, + Private->ModeData[Private->GraphicsOutput.Mode->Mode].HorizontalResolution, + Private->ModeData[Private->GraphicsOutput.Mode->Mode].VerticalResolution + ); + + return EFI_SUCCESS; + +FreeInfo: + FreePool (Private->GraphicsOutput.Mode->Info); + +FreeMode: + FreePool (Private->GraphicsOutput.Mode); + Private->GraphicsOutput.Mode = NULL; + + return Status; +} + +EFI_STATUS +QemuVideoGraphicsOutputDestructor ( + QEMU_VIDEO_PRIVATE_DATA *Private + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +{ + if (Private->FrameBufferBltConfigure != NULL) { + FreePool (Private->FrameBufferBltConfigure); + } + + if (Private->GraphicsOutput.Mode != NULL) { + if (Private->GraphicsOutput.Mode->Info != NULL) { + gBS->FreePool (Private->GraphicsOutput.Mode->Info); + } + gBS->FreePool (Private->GraphicsOutput.Mode); + } + + return EFI_SUCCESS; +} + + diff --git a/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/Initialize.c b/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/Initialize.c new file mode 100644 index 00000000..b35a0fee --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/Initialize.c @@ -0,0 +1,342 @@ +/** @file + Graphics Output Protocol functions for the QEMU video controller. + + Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Qemu.h" + + +/// +/// Generic Attribute Controller Register Settings +/// +UINT8 AttributeController[21] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00 +}; + +/// +/// Generic Graphics Controller Register Settings +/// +UINT8 GraphicsController[9] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 0xFF +}; + +// +// 640 x 480 x 256 color @ 60 Hertz +// +UINT8 Crtc_640_480_256_60[28] = { + 0x5d, 0x4f, 0x50, 0x82, 0x53, 0x9f, 0x00, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe1, 0x83, 0xdf, 0x50, 0x00, 0xe7, 0x04, 0xe3, + 0xff, 0x00, 0x00, 0x22 +}; + +UINT8 Crtc_640_480_32bpp_60[28] = { + 0x5d, 0x4f, 0x50, 0x82, 0x53, 0x9f, 0x00, 0x3e, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe1, 0x83, 0xdf, 0x40, 0x00, 0xe7, 0x04, 0xe3, + 0xff, 0x00, 0x00, 0x32 +}; + +UINT16 Seq_640_480_256_60[15] = { + 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1107, 0x0008, 0x4a0b, + 0x5b0c, 0x450d, 0x7e0e, 0x2b1b, 0x2f1c, 0x301d, 0x331e +}; + +UINT16 Seq_640_480_32bpp_60[15] = { + 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1907, 0x0008, 0x4a0b, + 0x5b0c, 0x450d, 0x7e0e, 0x2b1b, 0x2f1c, 0x301d, 0x331e +}; + +// +// 800 x 600 x 256 color @ 60 Hertz +// +UINT8 Crtc_800_600_256_60[28] = { + 0x7F, 0x63, 0x64, 0x80, 0x6B, 0x1B, 0x72, 0xF0, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x58, 0x8C, 0x57, 0x64, 0x00, 0x5F, 0x91, 0xE3, + 0xFF, 0x00, 0x00, 0x22 +}; + +UINT8 Crtc_800_600_32bpp_60[28] = { + 0x7F, 0x63, 0x64, 0x80, 0x6B, 0x1B, 0x72, 0xF0, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x58, 0x8C, 0x57, 0x90, 0x00, 0x5F, 0x91, 0xE3, + 0xFF, 0x00, 0x00, 0x32 +}; + +UINT16 Seq_800_600_256_60[15] = { + 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1107, 0x0008, 0x4a0b, + 0x5b0c, 0x450d, 0x510e, 0x2b1b, 0x2f1c, 0x301d, 0x3a1e +}; + +UINT16 Seq_800_600_32bpp_60[15] = { + 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1907, 0x0008, 0x4a0b, + 0x5b0c, 0x450d, 0x510e, 0x2b1b, 0x2f1c, 0x301d, 0x3a1e +}; + +UINT8 Crtc_960_720_32bpp_60[28] = { + 0xA3, 0x77, 0x80, 0x86, 0x85, 0x96, 0x24, 0xFD, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x88, 0xCF, 0xe0, 0x00, 0x00, 0x64, 0xE3, + 0xFF, 0x4A, 0x00, 0x32 +}; + +UINT16 Seq_960_720_32bpp_60[15] = { + 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1907, 0x0008, 0x4a0b, + 0x5b0c, 0x450d, 0x760e, 0x2b1b, 0x2f1c, 0x301d, 0x341e +}; + +// +// 1024 x 768 x 256 color @ 60 Hertz +// +UINT8 Crtc_1024_768_256_60[28] = { + 0xA3, 0x7F, 0x80, 0x86, 0x85, 0x96, 0x24, 0xFD, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x88, 0xFF, 0x80, 0x00, 0x00, 0x24, 0xE3, + 0xFF, 0x4A, 0x00, 0x22 +}; + +UINT16 Seq_1024_768_256_60[15] = { + 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1107, 0x0008, 0x4a0b, + 0x5b0c, 0x450d, 0x760e, 0x2b1b, 0x2f1c, 0x301d, 0x341e +}; + +// +// 1024 x 768 x 24-bit color @ 60 Hertz +// +UINT8 Crtc_1024_768_24bpp_60[28] = { + 0xA3, 0x7F, 0x80, 0x86, 0x85, 0x96, 0x24, 0xFD, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x88, 0xFF, 0x80, 0x00, 0x00, 0x24, 0xE3, + 0xFF, 0x4A, 0x00, 0x32 +}; + +UINT16 Seq_1024_768_24bpp_60[15] = { + 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1507, 0x0008, 0x4a0b, + 0x5b0c, 0x450d, 0x760e, 0x2b1b, 0x2f1c, 0x301d, 0x341e +}; + +UINT8 Crtc_1024_768_32bpp_60[28] = { + 0xA3, 0x7F, 0x80, 0x86, 0x85, 0x96, 0x24, 0xFD, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x88, 0xFF, 0xe0, 0x00, 0x00, 0x64, 0xE3, + 0xFF, 0x4A, 0x00, 0x32 +}; + +UINT16 Seq_1024_768_32bpp_60[15] = { + 0x0100, 0x0101, 0x0f02, 0x0003, 0x0e04, 0x1907, 0x0008, 0x4a0b, + 0x5b0c, 0x450d, 0x760e, 0x2b1b, 0x2f1c, 0x301d, 0x341e +}; + +/// +/// Table of supported video modes +/// +QEMU_VIDEO_CIRRUS_MODES QemuVideoCirrusModes[] = { +// { 640, 480, 8, Crtc_640_480_256_60, Seq_640_480_256_60, 0xe3 }, +// { 800, 600, 8, Crtc_800_600_256_60, Seq_800_600_256_60, 0xef }, + { 640, 480, 32, Crtc_640_480_32bpp_60, Seq_640_480_32bpp_60, 0xef }, + { 800, 600, 32, Crtc_800_600_32bpp_60, Seq_800_600_32bpp_60, 0xef }, +// { 1024, 768, 8, Crtc_1024_768_256_60, Seq_1024_768_256_60, 0xef } + { 1024, 768, 24, Crtc_1024_768_24bpp_60, Seq_1024_768_24bpp_60, 0xef } +// { 1024, 768, 32, Crtc_1024_768_32bpp_60, Seq_1024_768_32bpp_60, 0xef } +// { 960, 720, 32, Crtc_960_720_32bpp_60, Seq_1024_768_32bpp_60, 0xef } +}; + +#define QEMU_VIDEO_CIRRUS_MODE_COUNT \ + (ARRAY_SIZE (QemuVideoCirrusModes)) + +/** + Construct the valid video modes for QemuVideo. + +**/ +EFI_STATUS +QemuVideoCirrusModeSetup ( + QEMU_VIDEO_PRIVATE_DATA *Private + ) +{ + UINT32 Index; + QEMU_VIDEO_MODE_DATA *ModeData; + QEMU_VIDEO_CIRRUS_MODES *VideoMode; + + // + // Setup Video Modes + // + Private->ModeData = AllocatePool ( + sizeof (Private->ModeData[0]) * QEMU_VIDEO_CIRRUS_MODE_COUNT + ); + if (Private->ModeData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + ModeData = Private->ModeData; + VideoMode = &QemuVideoCirrusModes[0]; + for (Index = 0; Index < QEMU_VIDEO_CIRRUS_MODE_COUNT; Index ++) { + ModeData->InternalModeIndex = Index; + ModeData->HorizontalResolution = VideoMode->Width; + ModeData->VerticalResolution = VideoMode->Height; + ModeData->ColorDepth = VideoMode->ColorDepth; + DEBUG ((DEBUG_INFO, + "Adding Mode %d as Cirrus Internal Mode %d: %dx%d, %d-bit\n", + (INT32) (ModeData - Private->ModeData), + ModeData->InternalModeIndex, + ModeData->HorizontalResolution, + ModeData->VerticalResolution, + ModeData->ColorDepth + )); + + ModeData ++ ; + VideoMode ++; + } + Private->MaxMode = ModeData - Private->ModeData; + + return EFI_SUCCESS; +} + +/// +/// Table of supported video modes +/// +QEMU_VIDEO_BOCHS_MODES QemuVideoBochsModes[] = { + { 640, 480, 32 }, + { 800, 480, 32 }, + { 800, 600, 32 }, + { 832, 624, 32 }, + { 960, 640, 32 }, + { 1024, 600, 32 }, + { 1024, 768, 32 }, + { 1152, 864, 32 }, + { 1152, 870, 32 }, + { 1280, 720, 32 }, + { 1280, 760, 32 }, + { 1280, 768, 32 }, + { 1280, 800, 32 }, + { 1280, 960, 32 }, + { 1280, 1024, 32 }, + { 1360, 768, 32 }, + { 1366, 768, 32 }, + { 1400, 1050, 32 }, + { 1440, 900, 32 }, + { 1600, 900, 32 }, + { 1600, 1200, 32 }, + { 1680, 1050, 32 }, + { 1920, 1080, 32 }, + { 1920, 1200, 32 }, + { 1920, 1440, 32 }, + { 2000, 2000, 32 }, + { 2048, 1536, 32 }, + { 2048, 2048, 32 }, + { 2560, 1440, 32 }, + { 2560, 1600, 32 }, + { 2560, 2048, 32 }, + { 2800, 2100, 32 }, + { 3200, 2400, 32 }, + { 3840, 2160, 32 }, + { 4096, 2160, 32 }, + { 7680, 4320, 32 }, + { 8192, 4320, 32 } +}; + +#define QEMU_VIDEO_BOCHS_MODE_COUNT \ + (ARRAY_SIZE (QemuVideoBochsModes)) + +EFI_STATUS +QemuVideoBochsModeSetup ( + QEMU_VIDEO_PRIVATE_DATA *Private, + BOOLEAN IsQxl + ) +{ + UINT32 AvailableFbSize; + UINT32 Index; + QEMU_VIDEO_MODE_DATA *ModeData; + QEMU_VIDEO_BOCHS_MODES *VideoMode; + + // + // Fetch the available framebuffer size. + // + // VBE_DISPI_INDEX_VIDEO_MEMORY_64K is expected to return the size of the + // drawable framebuffer. Up to and including qemu-2.1 however it used to + // return the size of PCI BAR 0 (ie. the full video RAM size). + // + // On stdvga the two concepts coincide with each other; the full memory size + // is usable for drawing. + // + // On QXL however, only a leading segment, "surface 0", can be used for + // drawing; the rest of the video memory is used for the QXL guest-host + // protocol. VBE_DISPI_INDEX_VIDEO_MEMORY_64K should report the size of + // "surface 0", but since it doesn't (up to and including qemu-2.1), we + // retrieve the size of the drawable portion from a field in the QXL ROM BAR, + // where it is also available. + // + if (IsQxl) { + UINT32 Signature; + UINT32 DrawStart; + + Signature = 0; + DrawStart = 0xFFFFFFFF; + AvailableFbSize = 0; + if (EFI_ERROR ( + Private->PciIo->Mem.Read (Private->PciIo, EfiPciIoWidthUint32, + PCI_BAR_IDX2, 0, 1, &Signature)) || + Signature != SIGNATURE_32 ('Q', 'X', 'R', 'O') || + EFI_ERROR ( + Private->PciIo->Mem.Read (Private->PciIo, EfiPciIoWidthUint32, + PCI_BAR_IDX2, 36, 1, &DrawStart)) || + DrawStart != 0 || + EFI_ERROR ( + Private->PciIo->Mem.Read (Private->PciIo, EfiPciIoWidthUint32, + PCI_BAR_IDX2, 40, 1, &AvailableFbSize))) { + DEBUG ((DEBUG_ERROR, "%a: can't read size of drawable buffer from QXL " + "ROM\n", __FUNCTION__)); + return EFI_NOT_FOUND; + } + } else { + AvailableFbSize = BochsRead (Private, VBE_DISPI_INDEX_VIDEO_MEMORY_64K); + AvailableFbSize *= SIZE_64KB; + } + DEBUG ((DEBUG_INFO, "%a: AvailableFbSize=0x%x\n", __FUNCTION__, + AvailableFbSize)); + + // + // Setup Video Modes + // + Private->ModeData = AllocatePool ( + sizeof (Private->ModeData[0]) * QEMU_VIDEO_BOCHS_MODE_COUNT + ); + if (Private->ModeData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + ModeData = Private->ModeData; + VideoMode = &QemuVideoBochsModes[0]; + for (Index = 0; Index < QEMU_VIDEO_BOCHS_MODE_COUNT; Index ++) { + UINTN RequiredFbSize; + + ASSERT (VideoMode->ColorDepth % 8 == 0); + RequiredFbSize = (UINTN) VideoMode->Width * VideoMode->Height * + (VideoMode->ColorDepth / 8); + if (RequiredFbSize <= AvailableFbSize) { + ModeData->InternalModeIndex = Index; + ModeData->HorizontalResolution = VideoMode->Width; + ModeData->VerticalResolution = VideoMode->Height; + ModeData->ColorDepth = VideoMode->ColorDepth; + DEBUG ((DEBUG_INFO, + "Adding Mode %d as Bochs Internal Mode %d: %dx%d, %d-bit\n", + (INT32) (ModeData - Private->ModeData), + ModeData->InternalModeIndex, + ModeData->HorizontalResolution, + ModeData->VerticalResolution, + ModeData->ColorDepth + )); + + ModeData ++ ; + } + VideoMode ++; + } + Private->MaxMode = ModeData - Private->ModeData; + + return EFI_SUCCESS; +} + diff --git a/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/Qemu.h b/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/Qemu.h new file mode 100644 index 00000000..6a029dc8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/Qemu.h @@ -0,0 +1,506 @@ +/** @file + QEMU Video Controller Driver + + Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +// +// QEMU Video Controller Driver +// + +#ifndef _QEMU_H_ +#define _QEMU_H_ + + +#include <Uefi.h> +#include <Protocol/GraphicsOutput.h> +#include <Protocol/PciIo.h> +#include <Protocol/DriverSupportedEfiVersion.h> +#include <Protocol/DevicePath.h> + +#include <Library/DebugLib.h> +#include <Library/UefiDriverEntryPoint.h> +#include <Library/UefiLib.h> +#include <Library/PcdLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DevicePathLib.h> +#include <Library/TimerLib.h> +#include <Library/FrameBufferBltLib.h> + +#include <IndustryStandard/Pci.h> +#include <IndustryStandard/Acpi.h> + +// +// QEMU Video PCI Configuration Header values +// +#define CIRRUS_LOGIC_VENDOR_ID 0x1013 +#define CIRRUS_LOGIC_5430_DEVICE_ID 0x00a8 +#define CIRRUS_LOGIC_5430_ALTERNATE_DEVICE_ID 0x00a0 +#define CIRRUS_LOGIC_5446_DEVICE_ID 0x00b8 + +// +// QEMU Vide Graphical Mode Data +// +typedef struct { + UINT32 InternalModeIndex; // points into card-specific mode table + UINT32 HorizontalResolution; + UINT32 VerticalResolution; + UINT32 ColorDepth; +} QEMU_VIDEO_MODE_DATA; + +#define PIXEL_RED_SHIFT 0 +#define PIXEL_GREEN_SHIFT 3 +#define PIXEL_BLUE_SHIFT 6 + +#define PIXEL_RED_MASK (BIT7 | BIT6 | BIT5) +#define PIXEL_GREEN_MASK (BIT4 | BIT3 | BIT2) +#define PIXEL_BLUE_MASK (BIT1 | BIT0) + +#define PIXEL_TO_COLOR_BYTE(pixel, mask, shift) ((UINT8) ((pixel & mask) << shift)) +#define PIXEL_TO_RED_BYTE(pixel) PIXEL_TO_COLOR_BYTE(pixel, PIXEL_RED_MASK, PIXEL_RED_SHIFT) +#define PIXEL_TO_GREEN_BYTE(pixel) PIXEL_TO_COLOR_BYTE(pixel, PIXEL_GREEN_MASK, PIXEL_GREEN_SHIFT) +#define PIXEL_TO_BLUE_BYTE(pixel) PIXEL_TO_COLOR_BYTE(pixel, PIXEL_BLUE_MASK, PIXEL_BLUE_SHIFT) + +#define RGB_BYTES_TO_PIXEL(Red, Green, Blue) \ + (UINT8) ( (((Red) >> PIXEL_RED_SHIFT) & PIXEL_RED_MASK) | \ + (((Green) >> PIXEL_GREEN_SHIFT) & PIXEL_GREEN_MASK) | \ + (((Blue) >> PIXEL_BLUE_SHIFT) & PIXEL_BLUE_MASK) ) + +#define PIXEL24_RED_MASK 0x00ff0000 +#define PIXEL24_GREEN_MASK 0x0000ff00 +#define PIXEL24_BLUE_MASK 0x000000ff + +#define GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER 0xffff + +// +// QEMU Video Private Data Structure +// +#define QEMU_VIDEO_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('Q', 'V', 'I', 'D') + +typedef enum { + QEMU_VIDEO_CIRRUS_5430 = 1, + QEMU_VIDEO_CIRRUS_5446, + QEMU_VIDEO_BOCHS, + QEMU_VIDEO_BOCHS_MMIO, + QEMU_VIDEO_VMWARE_SVGA, +} QEMU_VIDEO_VARIANT; + +typedef struct { + UINT8 SubClass; + UINT16 VendorId; + UINT16 DeviceId; + QEMU_VIDEO_VARIANT Variant; + CHAR16 *Name; +} QEMU_VIDEO_CARD; + +typedef struct { + UINT64 Signature; + EFI_HANDLE Handle; + EFI_PCI_IO_PROTOCOL *PciIo; + UINT64 OriginalPciAttributes; + EFI_GRAPHICS_OUTPUT_PROTOCOL GraphicsOutput; + EFI_DEVICE_PATH_PROTOCOL *GopDevicePath; + + // + // The next two fields match the client-visible + // EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE.MaxMode field. + // + UINTN MaxMode; + QEMU_VIDEO_MODE_DATA *ModeData; + + QEMU_VIDEO_VARIANT Variant; + FRAME_BUFFER_CONFIGURE *FrameBufferBltConfigure; + UINTN FrameBufferBltConfigureSize; + UINT8 FrameBufferVramBarIndex; +} QEMU_VIDEO_PRIVATE_DATA; + +/// +/// Card-specific Video Mode structures +/// +typedef struct { + UINT32 Width; + UINT32 Height; + UINT32 ColorDepth; + UINT8 *CrtcSettings; + UINT16 *SeqSettings; + UINT8 MiscSetting; +} QEMU_VIDEO_CIRRUS_MODES; + +typedef struct { + UINT32 Width; + UINT32 Height; + UINT32 ColorDepth; +} QEMU_VIDEO_BOCHS_MODES; + +#define QEMU_VIDEO_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS(a) \ + CR(a, QEMU_VIDEO_PRIVATE_DATA, GraphicsOutput, QEMU_VIDEO_PRIVATE_DATA_SIGNATURE) + + +// +// Global Variables +// +extern UINT8 AttributeController[]; +extern UINT8 GraphicsController[]; +extern UINT8 Crtc_640_480_256_60[]; +extern UINT16 Seq_640_480_256_60[]; +extern UINT8 Crtc_800_600_256_60[]; +extern UINT16 Seq_800_600_256_60[]; +extern UINT8 Crtc_1024_768_256_60[]; +extern UINT16 Seq_1024_768_256_60[]; +extern QEMU_VIDEO_CIRRUS_MODES QemuVideoCirrusModes[]; +extern QEMU_VIDEO_BOCHS_MODES QemuVideoBochsModes[]; +extern EFI_DRIVER_BINDING_PROTOCOL gQemuVideoDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gQemuVideoComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gQemuVideoComponentName2; + +// +// Io Registers defined by VGA +// +#define CRTC_ADDRESS_REGISTER 0x3d4 +#define CRTC_DATA_REGISTER 0x3d5 +#define SEQ_ADDRESS_REGISTER 0x3c4 +#define SEQ_DATA_REGISTER 0x3c5 +#define GRAPH_ADDRESS_REGISTER 0x3ce +#define GRAPH_DATA_REGISTER 0x3cf +#define ATT_ADDRESS_REGISTER 0x3c0 +#define MISC_OUTPUT_REGISTER 0x3c2 +#define INPUT_STATUS_1_REGISTER 0x3da +#define DAC_PIXEL_MASK_REGISTER 0x3c6 +#define PALETTE_INDEX_REGISTER 0x3c8 +#define PALETTE_DATA_REGISTER 0x3c9 + +#define VBE_DISPI_IOPORT_INDEX 0x01CE +#define VBE_DISPI_IOPORT_DATA 0x01D0 + +#define VBE_DISPI_INDEX_ID 0x0 +#define VBE_DISPI_INDEX_XRES 0x1 +#define VBE_DISPI_INDEX_YRES 0x2 +#define VBE_DISPI_INDEX_BPP 0x3 +#define VBE_DISPI_INDEX_ENABLE 0x4 +#define VBE_DISPI_INDEX_BANK 0x5 +#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6 +#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7 +#define VBE_DISPI_INDEX_X_OFFSET 0x8 +#define VBE_DISPI_INDEX_Y_OFFSET 0x9 +#define VBE_DISPI_INDEX_VIDEO_MEMORY_64K 0xa + +#define VBE_DISPI_ID0 0xB0C0 +#define VBE_DISPI_ID1 0xB0C1 +#define VBE_DISPI_ID2 0xB0C2 +#define VBE_DISPI_ID3 0xB0C3 +#define VBE_DISPI_ID4 0xB0C4 +#define VBE_DISPI_ID5 0xB0C5 + +#define VBE_DISPI_DISABLED 0x00 +#define VBE_DISPI_ENABLED 0x01 +#define VBE_DISPI_GETCAPS 0x02 +#define VBE_DISPI_8BIT_DAC 0x20 +#define VBE_DISPI_LFB_ENABLED 0x40 +#define VBE_DISPI_NOCLEARMEM 0x80 + +// +// Graphics Output Hardware abstraction internal worker functions +// +EFI_STATUS +QemuVideoGraphicsOutputConstructor ( + QEMU_VIDEO_PRIVATE_DATA *Private + ); + +EFI_STATUS +QemuVideoGraphicsOutputDestructor ( + QEMU_VIDEO_PRIVATE_DATA *Private + ); + + +// +// EFI_DRIVER_BINDING_PROTOCOL Protocol Interface +// +/** + TODO: Add function description + + @param This TODO: add argument description + @param Controller TODO: add argument description + @param RemainingDevicePath TODO: add argument description + + TODO: add return values + +**/ +EFI_STATUS +EFIAPI +QemuVideoControllerDriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +/** + TODO: Add function description + + @param This TODO: add argument description + @param Controller TODO: add argument description + @param RemainingDevicePath TODO: add argument description + + TODO: add return values + +**/ +EFI_STATUS +EFIAPI +QemuVideoControllerDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +/** + TODO: Add function description + + @param This TODO: add argument description + @param Controller TODO: add argument description + @param NumberOfChildren TODO: add argument description + @param ChildHandleBuffer TODO: add argument description + + TODO: add return values + +**/ +EFI_STATUS +EFIAPI +QemuVideoControllerDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +// +// 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 +QemuVideoComponentNameGetDriverName ( + 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 not a valid EFI_HANDLE. + + @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 +QemuVideoComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + + +// +// Local Function Prototypes +// +VOID +InitializeCirrusGraphicsMode ( + QEMU_VIDEO_PRIVATE_DATA *Private, + QEMU_VIDEO_CIRRUS_MODES *ModeData + ); + +VOID +InitializeBochsGraphicsMode ( + QEMU_VIDEO_PRIVATE_DATA *Private, + QEMU_VIDEO_BOCHS_MODES *ModeData + ); + +VOID +SetPaletteColor ( + QEMU_VIDEO_PRIVATE_DATA *Private, + UINTN Index, + UINT8 Red, + UINT8 Green, + UINT8 Blue + ); + +VOID +SetDefaultPalette ( + QEMU_VIDEO_PRIVATE_DATA *Private + ); + +VOID +DrawLogo ( + QEMU_VIDEO_PRIVATE_DATA *Private, + UINTN ScreenWidth, + UINTN ScreenHeight + ); + +VOID +outb ( + QEMU_VIDEO_PRIVATE_DATA *Private, + UINTN Address, + UINT8 Data + ); + +VOID +outw ( + QEMU_VIDEO_PRIVATE_DATA *Private, + UINTN Address, + UINT16 Data + ); + +UINT8 +inb ( + QEMU_VIDEO_PRIVATE_DATA *Private, + UINTN Address + ); + +UINT16 +inw ( + QEMU_VIDEO_PRIVATE_DATA *Private, + UINTN Address + ); + +VOID +BochsWrite ( + QEMU_VIDEO_PRIVATE_DATA *Private, + UINT16 Reg, + UINT16 Data + ); + +UINT16 +BochsRead ( + QEMU_VIDEO_PRIVATE_DATA *Private, + UINT16 Reg + ); + +VOID +VgaOutb ( + QEMU_VIDEO_PRIVATE_DATA *Private, + UINTN Reg, + UINT8 Data + ); + +EFI_STATUS +QemuVideoCirrusModeSetup ( + QEMU_VIDEO_PRIVATE_DATA *Private + ); + +EFI_STATUS +QemuVideoBochsModeSetup ( + QEMU_VIDEO_PRIVATE_DATA *Private, + BOOLEAN IsQxl + ); + +VOID +InstallVbeShim ( + IN CONST CHAR16 *CardName, + IN EFI_PHYSICAL_ADDRESS FrameBufferBase + ); +#endif diff --git a/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf b/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf new file mode 100644 index 00000000..c642e3b7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf @@ -0,0 +1,66 @@ +## @file +# This driver is a sample implementation of the Graphics Output Protocol for +# the QEMU (Cirrus Logic 5446) video controller. +# +# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = QemuVideoDxe + FILE_GUID = e3752948-b9a1-4770-90c4-df41c38986be + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = InitializeQemuVideo + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# +# DRIVER_BINDING = gQemuVideoDriverBinding +# COMPONENT_NAME = gQemuVideoComponentName +# + +[Sources.common] + ComponentName.c + Driver.c + Gop.c + Initialize.c + Qemu.h + +[Sources.Ia32, Sources.X64] + VbeShim.c + VbeShim.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + OvmfPkg/OvmfPkg.dec + +[LibraryClasses] + BaseMemoryLib + FrameBufferBltLib + DebugLib + DevicePathLib + MemoryAllocationLib + PcdLib + PciLib + PrintLib + TimerLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiLib + +[Protocols] + gEfiGraphicsOutputProtocolGuid # PROTOCOL BY_START + gEfiDevicePathProtocolGuid # PROTOCOL BY_START + gEfiPciIoProtocolGuid # PROTOCOL TO_START + +[Pcd] + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfHostBridgePciDevId + gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask diff --git a/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/VbeShim.asm b/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/VbeShim.asm new file mode 100644 index 00000000..097ef306 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/VbeShim.asm @@ -0,0 +1,281 @@ +;------------------------------------------------------------------------------ +; @file +; A minimal Int10h stub that allows the Windows 2008 R2 SP1 UEFI guest's buggy, +; default VGA driver to switch to 1024x768x32, on the stdvga and QXL video +; cards of QEMU. +; +; Copyright (C) 2014, Red Hat, Inc. +; Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR> +; +; SPDX-License-Identifier: BSD-2-Clause-Patent +; +;------------------------------------------------------------------------------ + +; enable this macro for debug messages +;%define DEBUG + +%macro DebugLog 1 +%ifdef DEBUG + push si + mov si, %1 + call PrintStringSi + pop si +%endif +%endmacro + + +BITS 16 +ORG 0 + +VbeInfo: +TIMES 256 nop + +VbeModeInfo: +TIMES 256 nop + + +Handler: + cmp ax, 0x4f00 + je GetInfo + cmp ax, 0x4f01 + je GetModeInfo + cmp ax, 0x4f02 + je SetMode + cmp ax, 0x4f03 + je GetMode + cmp ax, 0x4f10 + je GetPmCapabilities + cmp ax, 0x4f15 + je ReadEdid + cmp ah, 0x00 + je SetModeLegacy + DebugLog StrUnknownFunction +Hang: + jmp Hang + + +GetInfo: + push es + push di + push ds + push si + push cx + + DebugLog StrEnterGetInfo + + ; target (es:di) set on input + push cs + pop ds + mov si, VbeInfo + ; source (ds:si) set now + + mov cx, 256 + cld + rep movsb + + pop cx + pop si + pop ds + pop di + pop es + jmp Success + + +GetModeInfo: + push es + push di + push ds + push si + push cx + + DebugLog StrEnterGetModeInfo + + and cx, ~0x4000 ; clear potentially set LFB bit in mode number + cmp cx, 0x00f1 + je KnownMode1 + DebugLog StrUnknownMode + jmp Hang +KnownMode1: + ; target (es:di) set on input + push cs + pop ds + mov si, VbeModeInfo + ; source (ds:si) set now + + mov cx, 256 + cld + rep movsb + + pop cx + pop si + pop ds + pop di + pop es + jmp Success + + +%define ATT_ADDRESS_REGISTER 0x03c0 +%define VBE_DISPI_IOPORT_INDEX 0x01ce +%define VBE_DISPI_IOPORT_DATA 0x01d0 + +%define VBE_DISPI_INDEX_XRES 0x1 +%define VBE_DISPI_INDEX_YRES 0x2 +%define VBE_DISPI_INDEX_BPP 0x3 +%define VBE_DISPI_INDEX_ENABLE 0x4 +%define VBE_DISPI_INDEX_BANK 0x5 +%define VBE_DISPI_INDEX_VIRT_WIDTH 0x6 +%define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7 +%define VBE_DISPI_INDEX_X_OFFSET 0x8 +%define VBE_DISPI_INDEX_Y_OFFSET 0x9 + +%define VBE_DISPI_ENABLED 0x01 +%define VBE_DISPI_LFB_ENABLED 0x40 + +%macro BochsWrite 2 + push dx + push ax + + mov dx, VBE_DISPI_IOPORT_INDEX + mov ax, %1 + out dx, ax + + mov dx, VBE_DISPI_IOPORT_DATA + mov ax, %2 + out dx, ax + + pop ax + pop dx +%endmacro + +SetMode: + push dx + push ax + + DebugLog StrEnterSetMode + + cmp bx, 0x40f1 + je KnownMode2 + DebugLog StrUnknownMode + jmp Hang +KnownMode2: + + ; unblank + mov dx, ATT_ADDRESS_REGISTER + mov al, 0x20 + out dx, al + + BochsWrite VBE_DISPI_INDEX_ENABLE, 0 + BochsWrite VBE_DISPI_INDEX_BANK, 0 + BochsWrite VBE_DISPI_INDEX_X_OFFSET, 0 + BochsWrite VBE_DISPI_INDEX_Y_OFFSET, 0 + BochsWrite VBE_DISPI_INDEX_BPP, 32 + BochsWrite VBE_DISPI_INDEX_XRES, 1024 + BochsWrite VBE_DISPI_INDEX_VIRT_WIDTH, 1024 + BochsWrite VBE_DISPI_INDEX_YRES, 768 + BochsWrite VBE_DISPI_INDEX_VIRT_HEIGHT, 768 + BochsWrite VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED + + pop ax + pop dx + jmp Success + + +GetMode: + DebugLog StrEnterGetMode + mov bx, 0x40f1 + jmp Success + + +GetPmCapabilities: + DebugLog StrGetPmCapabilities + jmp Unsupported + + +ReadEdid: + DebugLog StrReadEdid + jmp Unsupported + + +SetModeLegacy: + DebugLog StrEnterSetModeLegacy + + cmp al, 0x03 + je KnownMode3 + cmp al, 0x12 + je KnownMode4 + DebugLog StrUnknownMode + jmp Hang +KnownMode3: + mov al, 0x30 + jmp SetModeLegacyDone +KnownMode4: + mov al, 0x20 +SetModeLegacyDone: + DebugLog StrExitSuccess + iret + + +Success: + DebugLog StrExitSuccess + mov ax, 0x004f + iret + + +Unsupported: + DebugLog StrExitUnsupported + mov ax, 0x014f + iret + + +%ifdef DEBUG +PrintStringSi: + pusha + push ds ; save original + push cs + pop ds + mov dx, 0x0402 +PrintStringSiLoop: + lodsb + cmp al, 0 + je PrintStringSiDone + out dx, al + jmp PrintStringSiLoop +PrintStringSiDone: + pop ds ; restore original + popa + ret + + +StrExitSuccess: + db 'Exit', 0x0a, 0 + +StrExitUnsupported: + db 'Unsupported', 0x0a, 0 + +StrUnknownFunction: + db 'Unknown Function', 0x0a, 0 + +StrEnterGetInfo: + db 'GetInfo', 0x0a, 0 + +StrEnterGetModeInfo: + db 'GetModeInfo', 0x0a, 0 + +StrEnterGetMode: + db 'GetMode', 0x0a, 0 + +StrEnterSetMode: + db 'SetMode', 0x0a, 0 + +StrEnterSetModeLegacy: + db 'SetModeLegacy', 0x0a, 0 + +StrUnknownMode: + db 'Unknown Mode', 0x0a, 0 + +StrGetPmCapabilities: + db 'GetPmCapabilities', 0x0a, 0 + +StrReadEdid: + db 'ReadEdid', 0x0a, 0 +%endif diff --git a/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/VbeShim.c b/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/VbeShim.c new file mode 100644 index 00000000..63be9eca --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/VbeShim.c @@ -0,0 +1,316 @@ +/** @file + Install a fake VGABIOS service handler (real mode Int10h) for the buggy + Windows 2008 R2 SP1 UEFI guest. + + The handler is never meant to be directly executed by a VCPU; it's there for + the internal real mode emulator of Windows 2008 R2 SP1. + + The code is based on Ralf Brown's Interrupt List: + <http://www.cs.cmu.edu/~ralf/files.html> + <http://www.ctyme.com/rbrown.htm> + + Copyright (C) 2014, Red Hat, Inc. + Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include <IndustryStandard/LegacyVgaBios.h> +#include <Library/DebugLib.h> +#include <Library/PciLib.h> +#include <Library/PrintLib.h> +#include <OvmfPlatforms.h> + +#include "Qemu.h" +#include "VbeShim.h" + +#pragma pack (1) +typedef struct { + UINT16 Offset; + UINT16 Segment; +} IVT_ENTRY; +#pragma pack () + +// +// This string is displayed by Windows 2008 R2 SP1 in the Screen Resolution, +// Advanced Settings dialog. It should be short. +// +STATIC CONST CHAR8 mProductRevision[] = "OVMF Int10h (fake)"; + +/** + Install the VBE Info and VBE Mode Info structures, and the VBE service + handler routine in the C segment. Point the real-mode Int10h interrupt vector + to the handler. The only advertised mode is 1024x768x32. + + @param[in] CardName Name of the video card to be exposed in the + Product Name field of the VBE Info structure. The + parameter must originate from a + QEMU_VIDEO_CARD.Name field. + @param[in] FrameBufferBase Guest-physical base address of the video card's + frame buffer. +**/ +VOID +InstallVbeShim ( + IN CONST CHAR16 *CardName, + IN EFI_PHYSICAL_ADDRESS FrameBufferBase + ) +{ + EFI_PHYSICAL_ADDRESS Segment0, SegmentC, SegmentF; + UINTN Segment0Pages; + IVT_ENTRY *Int0x10; + EFI_STATUS Segment0AllocationStatus; + UINT16 HostBridgeDevId; + UINTN Pam1Address; + UINT8 Pam1; + UINTN SegmentCPages; + VBE_INFO *VbeInfoFull; + VBE_INFO_BASE *VbeInfo; + UINT8 *Ptr; + UINTN Printed; + VBE_MODE_INFO *VbeModeInfo; + + if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & (BIT0|BIT7)) == BIT0) { + DEBUG (( + DEBUG_WARN, + "%a: page 0 protected, not installing VBE shim\n", + __FUNCTION__ + )); + DEBUG (( + DEBUG_WARN, + "%a: page 0 protection prevents Windows 7 from booting anyway\n", + __FUNCTION__ + )); + return; + } + + Segment0 = 0x00000; + SegmentC = 0xC0000; + SegmentF = 0xF0000; + + // + // Attempt to cover the real mode IVT with an allocation. This is a UEFI + // driver, hence the arch protocols have been installed previously. Among + // those, the CPU arch protocol has configured the IDT, so we can overwrite + // the IVT used in real mode. + // + // The allocation request may fail, eg. if LegacyBiosDxe has already run. + // + Segment0Pages = 1; + Int0x10 = (IVT_ENTRY *)(UINTN)(Segment0 + 0x10 * sizeof (IVT_ENTRY)); + Segment0AllocationStatus = gBS->AllocatePages ( + AllocateAddress, + EfiBootServicesCode, + Segment0Pages, + &Segment0 + ); + + if (EFI_ERROR (Segment0AllocationStatus)) { + EFI_PHYSICAL_ADDRESS Handler; + + // + // Check if a video BIOS handler has been installed previously -- we + // shouldn't override a real video BIOS with our shim, nor our own shim if + // it's already present. + // + Handler = (Int0x10->Segment << 4) + Int0x10->Offset; + if (Handler >= SegmentC && Handler < SegmentF) { + DEBUG ((DEBUG_INFO, "%a: Video BIOS handler found at %04x:%04x\n", + __FUNCTION__, Int0x10->Segment, Int0x10->Offset)); + return; + } + + // + // Otherwise we'll overwrite the Int10h vector, even though we may not own + // the page at zero. + // + DEBUG (( + DEBUG_INFO, + "%a: failed to allocate page at zero: %r\n", + __FUNCTION__, + Segment0AllocationStatus + )); + } else { + // + // We managed to allocate the page at zero. SVN r14218 guarantees that it + // is NUL-filled. + // + ASSERT (Int0x10->Segment == 0x0000); + ASSERT (Int0x10->Offset == 0x0000); + } + + // + // Put the shim in place first. + // + // Start by determining the address of the PAM1 register. + // + HostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId); + switch (HostBridgeDevId) { + case INTEL_82441_DEVICE_ID: + Pam1Address = PMC_REGISTER_PIIX4 (PIIX4_PAM1); + break; + case INTEL_Q35_MCH_DEVICE_ID: + Pam1Address = DRAMC_REGISTER_Q35 (MCH_PAM1); + break; + default: + DEBUG (( + DEBUG_ERROR, + "%a: unknown host bridge device ID: 0x%04x\n", + __FUNCTION__, + HostBridgeDevId + )); + ASSERT (FALSE); + + if (!EFI_ERROR (Segment0AllocationStatus)) { + gBS->FreePages (Segment0, Segment0Pages); + } + return; + } + // + // low nibble covers 0xC0000 to 0xC3FFF + // high nibble covers 0xC4000 to 0xC7FFF + // bit1 in each nibble is Write Enable + // bit0 in each nibble is Read Enable + // + Pam1 = PciRead8 (Pam1Address); + PciWrite8 (Pam1Address, Pam1 | (BIT1 | BIT0)); + + // + // We never added memory space during PEI or DXE for the C segment, so we + // don't need to (and can't) allocate from there. Also, guest operating + // systems will see a hole in the UEFI memory map there. + // + SegmentCPages = 4; + + ASSERT (sizeof mVbeShim <= EFI_PAGES_TO_SIZE (SegmentCPages)); + CopyMem ((VOID *)(UINTN)SegmentC, mVbeShim, sizeof mVbeShim); + + // + // Fill in the VBE INFO structure. + // + VbeInfoFull = (VBE_INFO *)(UINTN)SegmentC; + VbeInfo = &VbeInfoFull->Base; + Ptr = VbeInfoFull->Buffer; + + CopyMem (VbeInfo->Signature, "VESA", 4); + VbeInfo->VesaVersion = 0x0300; + + VbeInfo->OemNameAddress = (UINT32)SegmentC << 12 | (UINT16)(UINTN)Ptr; + CopyMem (Ptr, "QEMU", 5); + Ptr += 5; + + VbeInfo->Capabilities = BIT0; // DAC can be switched into 8-bit mode + + VbeInfo->ModeListAddress = (UINT32)SegmentC << 12 | (UINT16)(UINTN)Ptr; + *(UINT16*)Ptr = 0x00f1; // mode number + Ptr += 2; + *(UINT16*)Ptr = 0xFFFF; // mode list terminator + Ptr += 2; + + VbeInfo->VideoMem64K = (UINT16)((1024 * 768 * 4 + 65535) / 65536); + VbeInfo->OemSoftwareVersion = 0x0000; + + VbeInfo->VendorNameAddress = (UINT32)SegmentC << 12 | (UINT16)(UINTN)Ptr; + CopyMem (Ptr, "OVMF", 5); + Ptr += 5; + + VbeInfo->ProductNameAddress = (UINT32)SegmentC << 12 | (UINT16)(UINTN)Ptr; + Printed = AsciiSPrint ((CHAR8 *)Ptr, + sizeof VbeInfoFull->Buffer - (Ptr - VbeInfoFull->Buffer), "%s", + CardName); + Ptr += Printed + 1; + + VbeInfo->ProductRevAddress = (UINT32)SegmentC << 12 | (UINT16)(UINTN)Ptr; + CopyMem (Ptr, mProductRevision, sizeof mProductRevision); + Ptr += sizeof mProductRevision; + + ASSERT (sizeof VbeInfoFull->Buffer >= Ptr - VbeInfoFull->Buffer); + ZeroMem (Ptr, sizeof VbeInfoFull->Buffer - (Ptr - VbeInfoFull->Buffer)); + + // + // Fil in the VBE MODE INFO structure. + // + VbeModeInfo = (VBE_MODE_INFO *)(VbeInfoFull + 1); + + // + // bit0: mode supported by present hardware configuration + // bit1: optional information available (must be =1 for VBE v1.2+) + // bit3: set if color, clear if monochrome + // bit4: set if graphics mode, clear if text mode + // bit5: mode is not VGA-compatible + // bit7: linear framebuffer mode supported + // + VbeModeInfo->ModeAttr = BIT7 | BIT5 | BIT4 | BIT3 | BIT1 | BIT0; + + // + // bit0: exists + // bit1: bit1: readable + // bit2: writeable + // + VbeModeInfo->WindowAAttr = BIT2 | BIT1 | BIT0; + + VbeModeInfo->WindowBAttr = 0x00; + VbeModeInfo->WindowGranularityKB = 0x0040; + VbeModeInfo->WindowSizeKB = 0x0040; + VbeModeInfo->WindowAStartSegment = 0xA000; + VbeModeInfo->WindowBStartSegment = 0x0000; + VbeModeInfo->WindowPositioningAddress = 0x0000; + VbeModeInfo->BytesPerScanLine = 1024 * 4; + + VbeModeInfo->Width = 1024; + VbeModeInfo->Height = 768; + VbeModeInfo->CharCellWidth = 8; + VbeModeInfo->CharCellHeight = 16; + VbeModeInfo->NumPlanes = 1; + VbeModeInfo->BitsPerPixel = 32; + VbeModeInfo->NumBanks = 1; + VbeModeInfo->MemoryModel = 6; // direct color + VbeModeInfo->BankSizeKB = 0; + VbeModeInfo->NumImagePagesLessOne = 0; + VbeModeInfo->Vbe3 = 0x01; + + VbeModeInfo->RedMaskSize = 8; + VbeModeInfo->RedMaskPos = 16; + VbeModeInfo->GreenMaskSize = 8; + VbeModeInfo->GreenMaskPos = 8; + VbeModeInfo->BlueMaskSize = 8; + VbeModeInfo->BlueMaskPos = 0; + VbeModeInfo->ReservedMaskSize = 8; + VbeModeInfo->ReservedMaskPos = 24; + + // + // bit1: Bytes in reserved field may be used by application + // + VbeModeInfo->DirectColorModeInfo = BIT1; + + VbeModeInfo->LfbAddress = (UINT32)FrameBufferBase; + VbeModeInfo->OffScreenAddress = 0; + VbeModeInfo->OffScreenSizeKB = 0; + + VbeModeInfo->BytesPerScanLineLinear = 1024 * 4; + VbeModeInfo->NumImagesLessOneBanked = 0; + VbeModeInfo->NumImagesLessOneLinear = 0; + VbeModeInfo->RedMaskSizeLinear = 8; + VbeModeInfo->RedMaskPosLinear = 16; + VbeModeInfo->GreenMaskSizeLinear = 8; + VbeModeInfo->GreenMaskPosLinear = 8; + VbeModeInfo->BlueMaskSizeLinear = 8; + VbeModeInfo->BlueMaskPosLinear = 0; + VbeModeInfo->ReservedMaskSizeLinear = 8; + VbeModeInfo->ReservedMaskPosLinear = 24; + VbeModeInfo->MaxPixelClockHz = 0; + + ZeroMem (VbeModeInfo->Reserved, sizeof VbeModeInfo->Reserved); + + // + // Clear Write Enable (bit1), keep Read Enable (bit0) set + // + PciWrite8 (Pam1Address, (Pam1 & ~BIT1) | BIT0); + + // + // Second, point the Int10h vector at the shim. + // + Int0x10->Segment = (UINT16) ((UINT32)SegmentC >> 4); + Int0x10->Offset = (UINT16) ((UINTN) (VbeModeInfo + 1) - SegmentC); + + DEBUG ((DEBUG_INFO, "%a: VBE shim installed\n", __FUNCTION__)); +} diff --git a/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/VbeShim.h b/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/VbeShim.h new file mode 100644 index 00000000..8d8d5f30 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/VbeShim.h @@ -0,0 +1,701 @@ +// +// THIS FILE WAS GENERATED BY "VbeShim.sh". DO NOT EDIT. +// +#ifndef _VBE_SHIM_H_ +#define _VBE_SHIM_H_ +STATIC CONST UINT8 mVbeShim[] = { + /* 00000000 nop */ 0x90, + /* 00000001 nop */ 0x90, + /* 00000002 nop */ 0x90, + /* 00000003 nop */ 0x90, + /* 00000004 nop */ 0x90, + /* 00000005 nop */ 0x90, + /* 00000006 nop */ 0x90, + /* 00000007 nop */ 0x90, + /* 00000008 nop */ 0x90, + /* 00000009 nop */ 0x90, + /* 0000000A nop */ 0x90, + /* 0000000B nop */ 0x90, + /* 0000000C nop */ 0x90, + /* 0000000D nop */ 0x90, + /* 0000000E nop */ 0x90, + /* 0000000F nop */ 0x90, + /* 00000010 nop */ 0x90, + /* 00000011 nop */ 0x90, + /* 00000012 nop */ 0x90, + /* 00000013 nop */ 0x90, + /* 00000014 nop */ 0x90, + /* 00000015 nop */ 0x90, + /* 00000016 nop */ 0x90, + /* 00000017 nop */ 0x90, + /* 00000018 nop */ 0x90, + /* 00000019 nop */ 0x90, + /* 0000001A nop */ 0x90, + /* 0000001B nop */ 0x90, + /* 0000001C nop */ 0x90, + /* 0000001D nop */ 0x90, + /* 0000001E nop */ 0x90, + /* 0000001F nop */ 0x90, + /* 00000020 nop */ 0x90, + /* 00000021 nop */ 0x90, + /* 00000022 nop */ 0x90, + /* 00000023 nop */ 0x90, + /* 00000024 nop */ 0x90, + /* 00000025 nop */ 0x90, + /* 00000026 nop */ 0x90, + /* 00000027 nop */ 0x90, + /* 00000028 nop */ 0x90, + /* 00000029 nop */ 0x90, + /* 0000002A nop */ 0x90, + /* 0000002B nop */ 0x90, + /* 0000002C nop */ 0x90, + /* 0000002D nop */ 0x90, + /* 0000002E nop */ 0x90, + /* 0000002F nop */ 0x90, + /* 00000030 nop */ 0x90, + /* 00000031 nop */ 0x90, + /* 00000032 nop */ 0x90, + /* 00000033 nop */ 0x90, + /* 00000034 nop */ 0x90, + /* 00000035 nop */ 0x90, + /* 00000036 nop */ 0x90, + /* 00000037 nop */ 0x90, + /* 00000038 nop */ 0x90, + /* 00000039 nop */ 0x90, + /* 0000003A nop */ 0x90, + /* 0000003B nop */ 0x90, + /* 0000003C nop */ 0x90, + /* 0000003D nop */ 0x90, + /* 0000003E nop */ 0x90, + /* 0000003F nop */ 0x90, + /* 00000040 nop */ 0x90, + /* 00000041 nop */ 0x90, + /* 00000042 nop */ 0x90, + /* 00000043 nop */ 0x90, + /* 00000044 nop */ 0x90, + /* 00000045 nop */ 0x90, + /* 00000046 nop */ 0x90, + /* 00000047 nop */ 0x90, + /* 00000048 nop */ 0x90, + /* 00000049 nop */ 0x90, + /* 0000004A nop */ 0x90, + /* 0000004B nop */ 0x90, + /* 0000004C nop */ 0x90, + /* 0000004D nop */ 0x90, + /* 0000004E nop */ 0x90, + /* 0000004F nop */ 0x90, + /* 00000050 nop */ 0x90, + /* 00000051 nop */ 0x90, + /* 00000052 nop */ 0x90, + /* 00000053 nop */ 0x90, + /* 00000054 nop */ 0x90, + /* 00000055 nop */ 0x90, + /* 00000056 nop */ 0x90, + /* 00000057 nop */ 0x90, + /* 00000058 nop */ 0x90, + /* 00000059 nop */ 0x90, + /* 0000005A nop */ 0x90, + /* 0000005B nop */ 0x90, + /* 0000005C nop */ 0x90, + /* 0000005D nop */ 0x90, + /* 0000005E nop */ 0x90, + /* 0000005F nop */ 0x90, + /* 00000060 nop */ 0x90, + /* 00000061 nop */ 0x90, + /* 00000062 nop */ 0x90, + /* 00000063 nop */ 0x90, + /* 00000064 nop */ 0x90, + /* 00000065 nop */ 0x90, + /* 00000066 nop */ 0x90, + /* 00000067 nop */ 0x90, + /* 00000068 nop */ 0x90, + /* 00000069 nop */ 0x90, + /* 0000006A nop */ 0x90, + /* 0000006B nop */ 0x90, + /* 0000006C nop */ 0x90, + /* 0000006D nop */ 0x90, + /* 0000006E nop */ 0x90, + /* 0000006F nop */ 0x90, + /* 00000070 nop */ 0x90, + /* 00000071 nop */ 0x90, + /* 00000072 nop */ 0x90, + /* 00000073 nop */ 0x90, + /* 00000074 nop */ 0x90, + /* 00000075 nop */ 0x90, + /* 00000076 nop */ 0x90, + /* 00000077 nop */ 0x90, + /* 00000078 nop */ 0x90, + /* 00000079 nop */ 0x90, + /* 0000007A nop */ 0x90, + /* 0000007B nop */ 0x90, + /* 0000007C nop */ 0x90, + /* 0000007D nop */ 0x90, + /* 0000007E nop */ 0x90, + /* 0000007F nop */ 0x90, + /* 00000080 nop */ 0x90, + /* 00000081 nop */ 0x90, + /* 00000082 nop */ 0x90, + /* 00000083 nop */ 0x90, + /* 00000084 nop */ 0x90, + /* 00000085 nop */ 0x90, + /* 00000086 nop */ 0x90, + /* 00000087 nop */ 0x90, + /* 00000088 nop */ 0x90, + /* 00000089 nop */ 0x90, + /* 0000008A nop */ 0x90, + /* 0000008B nop */ 0x90, + /* 0000008C nop */ 0x90, + /* 0000008D nop */ 0x90, + /* 0000008E nop */ 0x90, + /* 0000008F nop */ 0x90, + /* 00000090 nop */ 0x90, + /* 00000091 nop */ 0x90, + /* 00000092 nop */ 0x90, + /* 00000093 nop */ 0x90, + /* 00000094 nop */ 0x90, + /* 00000095 nop */ 0x90, + /* 00000096 nop */ 0x90, + /* 00000097 nop */ 0x90, + /* 00000098 nop */ 0x90, + /* 00000099 nop */ 0x90, + /* 0000009A nop */ 0x90, + /* 0000009B nop */ 0x90, + /* 0000009C nop */ 0x90, + /* 0000009D nop */ 0x90, + /* 0000009E nop */ 0x90, + /* 0000009F nop */ 0x90, + /* 000000A0 nop */ 0x90, + /* 000000A1 nop */ 0x90, + /* 000000A2 nop */ 0x90, + /* 000000A3 nop */ 0x90, + /* 000000A4 nop */ 0x90, + /* 000000A5 nop */ 0x90, + /* 000000A6 nop */ 0x90, + /* 000000A7 nop */ 0x90, + /* 000000A8 nop */ 0x90, + /* 000000A9 nop */ 0x90, + /* 000000AA nop */ 0x90, + /* 000000AB nop */ 0x90, + /* 000000AC nop */ 0x90, + /* 000000AD nop */ 0x90, + /* 000000AE nop */ 0x90, + /* 000000AF nop */ 0x90, + /* 000000B0 nop */ 0x90, + /* 000000B1 nop */ 0x90, + /* 000000B2 nop */ 0x90, + /* 000000B3 nop */ 0x90, + /* 000000B4 nop */ 0x90, + /* 000000B5 nop */ 0x90, + /* 000000B6 nop */ 0x90, + /* 000000B7 nop */ 0x90, + /* 000000B8 nop */ 0x90, + /* 000000B9 nop */ 0x90, + /* 000000BA nop */ 0x90, + /* 000000BB nop */ 0x90, + /* 000000BC nop */ 0x90, + /* 000000BD nop */ 0x90, + /* 000000BE nop */ 0x90, + /* 000000BF nop */ 0x90, + /* 000000C0 nop */ 0x90, + /* 000000C1 nop */ 0x90, + /* 000000C2 nop */ 0x90, + /* 000000C3 nop */ 0x90, + /* 000000C4 nop */ 0x90, + /* 000000C5 nop */ 0x90, + /* 000000C6 nop */ 0x90, + /* 000000C7 nop */ 0x90, + /* 000000C8 nop */ 0x90, + /* 000000C9 nop */ 0x90, + /* 000000CA nop */ 0x90, + /* 000000CB nop */ 0x90, + /* 000000CC nop */ 0x90, + /* 000000CD nop */ 0x90, + /* 000000CE nop */ 0x90, + /* 000000CF nop */ 0x90, + /* 000000D0 nop */ 0x90, + /* 000000D1 nop */ 0x90, + /* 000000D2 nop */ 0x90, + /* 000000D3 nop */ 0x90, + /* 000000D4 nop */ 0x90, + /* 000000D5 nop */ 0x90, + /* 000000D6 nop */ 0x90, + /* 000000D7 nop */ 0x90, + /* 000000D8 nop */ 0x90, + /* 000000D9 nop */ 0x90, + /* 000000DA nop */ 0x90, + /* 000000DB nop */ 0x90, + /* 000000DC nop */ 0x90, + /* 000000DD nop */ 0x90, + /* 000000DE nop */ 0x90, + /* 000000DF nop */ 0x90, + /* 000000E0 nop */ 0x90, + /* 000000E1 nop */ 0x90, + /* 000000E2 nop */ 0x90, + /* 000000E3 nop */ 0x90, + /* 000000E4 nop */ 0x90, + /* 000000E5 nop */ 0x90, + /* 000000E6 nop */ 0x90, + /* 000000E7 nop */ 0x90, + /* 000000E8 nop */ 0x90, + /* 000000E9 nop */ 0x90, + /* 000000EA nop */ 0x90, + /* 000000EB nop */ 0x90, + /* 000000EC nop */ 0x90, + /* 000000ED nop */ 0x90, + /* 000000EE nop */ 0x90, + /* 000000EF nop */ 0x90, + /* 000000F0 nop */ 0x90, + /* 000000F1 nop */ 0x90, + /* 000000F2 nop */ 0x90, + /* 000000F3 nop */ 0x90, + /* 000000F4 nop */ 0x90, + /* 000000F5 nop */ 0x90, + /* 000000F6 nop */ 0x90, + /* 000000F7 nop */ 0x90, + /* 000000F8 nop */ 0x90, + /* 000000F9 nop */ 0x90, + /* 000000FA nop */ 0x90, + /* 000000FB nop */ 0x90, + /* 000000FC nop */ 0x90, + /* 000000FD nop */ 0x90, + /* 000000FE nop */ 0x90, + /* 000000FF nop */ 0x90, + /* 00000100 nop */ 0x90, + /* 00000101 nop */ 0x90, + /* 00000102 nop */ 0x90, + /* 00000103 nop */ 0x90, + /* 00000104 nop */ 0x90, + /* 00000105 nop */ 0x90, + /* 00000106 nop */ 0x90, + /* 00000107 nop */ 0x90, + /* 00000108 nop */ 0x90, + /* 00000109 nop */ 0x90, + /* 0000010A nop */ 0x90, + /* 0000010B nop */ 0x90, + /* 0000010C nop */ 0x90, + /* 0000010D nop */ 0x90, + /* 0000010E nop */ 0x90, + /* 0000010F nop */ 0x90, + /* 00000110 nop */ 0x90, + /* 00000111 nop */ 0x90, + /* 00000112 nop */ 0x90, + /* 00000113 nop */ 0x90, + /* 00000114 nop */ 0x90, + /* 00000115 nop */ 0x90, + /* 00000116 nop */ 0x90, + /* 00000117 nop */ 0x90, + /* 00000118 nop */ 0x90, + /* 00000119 nop */ 0x90, + /* 0000011A nop */ 0x90, + /* 0000011B nop */ 0x90, + /* 0000011C nop */ 0x90, + /* 0000011D nop */ 0x90, + /* 0000011E nop */ 0x90, + /* 0000011F nop */ 0x90, + /* 00000120 nop */ 0x90, + /* 00000121 nop */ 0x90, + /* 00000122 nop */ 0x90, + /* 00000123 nop */ 0x90, + /* 00000124 nop */ 0x90, + /* 00000125 nop */ 0x90, + /* 00000126 nop */ 0x90, + /* 00000127 nop */ 0x90, + /* 00000128 nop */ 0x90, + /* 00000129 nop */ 0x90, + /* 0000012A nop */ 0x90, + /* 0000012B nop */ 0x90, + /* 0000012C nop */ 0x90, + /* 0000012D nop */ 0x90, + /* 0000012E nop */ 0x90, + /* 0000012F nop */ 0x90, + /* 00000130 nop */ 0x90, + /* 00000131 nop */ 0x90, + /* 00000132 nop */ 0x90, + /* 00000133 nop */ 0x90, + /* 00000134 nop */ 0x90, + /* 00000135 nop */ 0x90, + /* 00000136 nop */ 0x90, + /* 00000137 nop */ 0x90, + /* 00000138 nop */ 0x90, + /* 00000139 nop */ 0x90, + /* 0000013A nop */ 0x90, + /* 0000013B nop */ 0x90, + /* 0000013C nop */ 0x90, + /* 0000013D nop */ 0x90, + /* 0000013E nop */ 0x90, + /* 0000013F nop */ 0x90, + /* 00000140 nop */ 0x90, + /* 00000141 nop */ 0x90, + /* 00000142 nop */ 0x90, + /* 00000143 nop */ 0x90, + /* 00000144 nop */ 0x90, + /* 00000145 nop */ 0x90, + /* 00000146 nop */ 0x90, + /* 00000147 nop */ 0x90, + /* 00000148 nop */ 0x90, + /* 00000149 nop */ 0x90, + /* 0000014A nop */ 0x90, + /* 0000014B nop */ 0x90, + /* 0000014C nop */ 0x90, + /* 0000014D nop */ 0x90, + /* 0000014E nop */ 0x90, + /* 0000014F nop */ 0x90, + /* 00000150 nop */ 0x90, + /* 00000151 nop */ 0x90, + /* 00000152 nop */ 0x90, + /* 00000153 nop */ 0x90, + /* 00000154 nop */ 0x90, + /* 00000155 nop */ 0x90, + /* 00000156 nop */ 0x90, + /* 00000157 nop */ 0x90, + /* 00000158 nop */ 0x90, + /* 00000159 nop */ 0x90, + /* 0000015A nop */ 0x90, + /* 0000015B nop */ 0x90, + /* 0000015C nop */ 0x90, + /* 0000015D nop */ 0x90, + /* 0000015E nop */ 0x90, + /* 0000015F nop */ 0x90, + /* 00000160 nop */ 0x90, + /* 00000161 nop */ 0x90, + /* 00000162 nop */ 0x90, + /* 00000163 nop */ 0x90, + /* 00000164 nop */ 0x90, + /* 00000165 nop */ 0x90, + /* 00000166 nop */ 0x90, + /* 00000167 nop */ 0x90, + /* 00000168 nop */ 0x90, + /* 00000169 nop */ 0x90, + /* 0000016A nop */ 0x90, + /* 0000016B nop */ 0x90, + /* 0000016C nop */ 0x90, + /* 0000016D nop */ 0x90, + /* 0000016E nop */ 0x90, + /* 0000016F nop */ 0x90, + /* 00000170 nop */ 0x90, + /* 00000171 nop */ 0x90, + /* 00000172 nop */ 0x90, + /* 00000173 nop */ 0x90, + /* 00000174 nop */ 0x90, + /* 00000175 nop */ 0x90, + /* 00000176 nop */ 0x90, + /* 00000177 nop */ 0x90, + /* 00000178 nop */ 0x90, + /* 00000179 nop */ 0x90, + /* 0000017A nop */ 0x90, + /* 0000017B nop */ 0x90, + /* 0000017C nop */ 0x90, + /* 0000017D nop */ 0x90, + /* 0000017E nop */ 0x90, + /* 0000017F nop */ 0x90, + /* 00000180 nop */ 0x90, + /* 00000181 nop */ 0x90, + /* 00000182 nop */ 0x90, + /* 00000183 nop */ 0x90, + /* 00000184 nop */ 0x90, + /* 00000185 nop */ 0x90, + /* 00000186 nop */ 0x90, + /* 00000187 nop */ 0x90, + /* 00000188 nop */ 0x90, + /* 00000189 nop */ 0x90, + /* 0000018A nop */ 0x90, + /* 0000018B nop */ 0x90, + /* 0000018C nop */ 0x90, + /* 0000018D nop */ 0x90, + /* 0000018E nop */ 0x90, + /* 0000018F nop */ 0x90, + /* 00000190 nop */ 0x90, + /* 00000191 nop */ 0x90, + /* 00000192 nop */ 0x90, + /* 00000193 nop */ 0x90, + /* 00000194 nop */ 0x90, + /* 00000195 nop */ 0x90, + /* 00000196 nop */ 0x90, + /* 00000197 nop */ 0x90, + /* 00000198 nop */ 0x90, + /* 00000199 nop */ 0x90, + /* 0000019A nop */ 0x90, + /* 0000019B nop */ 0x90, + /* 0000019C nop */ 0x90, + /* 0000019D nop */ 0x90, + /* 0000019E nop */ 0x90, + /* 0000019F nop */ 0x90, + /* 000001A0 nop */ 0x90, + /* 000001A1 nop */ 0x90, + /* 000001A2 nop */ 0x90, + /* 000001A3 nop */ 0x90, + /* 000001A4 nop */ 0x90, + /* 000001A5 nop */ 0x90, + /* 000001A6 nop */ 0x90, + /* 000001A7 nop */ 0x90, + /* 000001A8 nop */ 0x90, + /* 000001A9 nop */ 0x90, + /* 000001AA nop */ 0x90, + /* 000001AB nop */ 0x90, + /* 000001AC nop */ 0x90, + /* 000001AD nop */ 0x90, + /* 000001AE nop */ 0x90, + /* 000001AF nop */ 0x90, + /* 000001B0 nop */ 0x90, + /* 000001B1 nop */ 0x90, + /* 000001B2 nop */ 0x90, + /* 000001B3 nop */ 0x90, + /* 000001B4 nop */ 0x90, + /* 000001B5 nop */ 0x90, + /* 000001B6 nop */ 0x90, + /* 000001B7 nop */ 0x90, + /* 000001B8 nop */ 0x90, + /* 000001B9 nop */ 0x90, + /* 000001BA nop */ 0x90, + /* 000001BB nop */ 0x90, + /* 000001BC nop */ 0x90, + /* 000001BD nop */ 0x90, + /* 000001BE nop */ 0x90, + /* 000001BF nop */ 0x90, + /* 000001C0 nop */ 0x90, + /* 000001C1 nop */ 0x90, + /* 000001C2 nop */ 0x90, + /* 000001C3 nop */ 0x90, + /* 000001C4 nop */ 0x90, + /* 000001C5 nop */ 0x90, + /* 000001C6 nop */ 0x90, + /* 000001C7 nop */ 0x90, + /* 000001C8 nop */ 0x90, + /* 000001C9 nop */ 0x90, + /* 000001CA nop */ 0x90, + /* 000001CB nop */ 0x90, + /* 000001CC nop */ 0x90, + /* 000001CD nop */ 0x90, + /* 000001CE nop */ 0x90, + /* 000001CF nop */ 0x90, + /* 000001D0 nop */ 0x90, + /* 000001D1 nop */ 0x90, + /* 000001D2 nop */ 0x90, + /* 000001D3 nop */ 0x90, + /* 000001D4 nop */ 0x90, + /* 000001D5 nop */ 0x90, + /* 000001D6 nop */ 0x90, + /* 000001D7 nop */ 0x90, + /* 000001D8 nop */ 0x90, + /* 000001D9 nop */ 0x90, + /* 000001DA nop */ 0x90, + /* 000001DB nop */ 0x90, + /* 000001DC nop */ 0x90, + /* 000001DD nop */ 0x90, + /* 000001DE nop */ 0x90, + /* 000001DF nop */ 0x90, + /* 000001E0 nop */ 0x90, + /* 000001E1 nop */ 0x90, + /* 000001E2 nop */ 0x90, + /* 000001E3 nop */ 0x90, + /* 000001E4 nop */ 0x90, + /* 000001E5 nop */ 0x90, + /* 000001E6 nop */ 0x90, + /* 000001E7 nop */ 0x90, + /* 000001E8 nop */ 0x90, + /* 000001E9 nop */ 0x90, + /* 000001EA nop */ 0x90, + /* 000001EB nop */ 0x90, + /* 000001EC nop */ 0x90, + /* 000001ED nop */ 0x90, + /* 000001EE nop */ 0x90, + /* 000001EF nop */ 0x90, + /* 000001F0 nop */ 0x90, + /* 000001F1 nop */ 0x90, + /* 000001F2 nop */ 0x90, + /* 000001F3 nop */ 0x90, + /* 000001F4 nop */ 0x90, + /* 000001F5 nop */ 0x90, + /* 000001F6 nop */ 0x90, + /* 000001F7 nop */ 0x90, + /* 000001F8 nop */ 0x90, + /* 000001F9 nop */ 0x90, + /* 000001FA nop */ 0x90, + /* 000001FB nop */ 0x90, + /* 000001FC nop */ 0x90, + /* 000001FD nop */ 0x90, + /* 000001FE nop */ 0x90, + /* 000001FF nop */ 0x90, + /* 00000200 cmp ax,0x4f00 */ 0x3D, 0x00, 0x4F, + /* 00000203 jz 0x22d */ 0x74, 0x28, + /* 00000205 cmp ax,0x4f01 */ 0x3D, 0x01, 0x4F, + /* 00000208 jz 0x245 */ 0x74, 0x3B, + /* 0000020A cmp ax,0x4f02 */ 0x3D, 0x02, 0x4F, + /* 0000020D jz 0x269 */ 0x74, 0x5A, + /* 0000020F cmp ax,0x4f03 */ 0x3D, 0x03, 0x4F, + /* 00000212 jz word 0x331 */ 0x0F, 0x84, 0x1B, 0x01, + /* 00000216 cmp ax,0x4f10 */ 0x3D, 0x10, 0x4F, + /* 00000219 jz word 0x336 */ 0x0F, 0x84, 0x19, 0x01, + /* 0000021D cmp ax,0x4f15 */ 0x3D, 0x15, 0x4F, + /* 00000220 jz word 0x338 */ 0x0F, 0x84, 0x14, 0x01, + /* 00000224 cmp ah,0x0 */ 0x80, 0xFC, 0x00, + /* 00000227 jz word 0x33a */ 0x0F, 0x84, 0x0F, 0x01, + /* 0000022B jmp short 0x22b */ 0xEB, 0xFE, + /* 0000022D push es */ 0x06, + /* 0000022E push di */ 0x57, + /* 0000022F push ds */ 0x1E, + /* 00000230 push si */ 0x56, + /* 00000231 push cx */ 0x51, + /* 00000232 push cs */ 0x0E, + /* 00000233 pop ds */ 0x1F, + /* 00000234 mov si,0x0 */ 0xBE, 0x00, 0x00, + /* 00000237 mov cx,0x100 */ 0xB9, 0x00, 0x01, + /* 0000023A cld */ 0xFC, + /* 0000023B rep movsb */ 0xF3, 0xA4, + /* 0000023D pop cx */ 0x59, + /* 0000023E pop si */ 0x5E, + /* 0000023F pop ds */ 0x1F, + /* 00000240 pop di */ 0x5F, + /* 00000241 pop es */ 0x07, + /* 00000242 jmp word 0x34c */ 0xE9, 0x07, 0x01, + /* 00000245 push es */ 0x06, + /* 00000246 push di */ 0x57, + /* 00000247 push ds */ 0x1E, + /* 00000248 push si */ 0x56, + /* 00000249 push cx */ 0x51, + /* 0000024A and cx,0xbfff */ 0x81, 0xE1, 0xFF, 0xBF, + /* 0000024E cmp cx,0xf1 */ 0x81, 0xF9, 0xF1, 0x00, + /* 00000252 jz 0x256 */ 0x74, 0x02, + /* 00000254 jmp short 0x22b */ 0xEB, 0xD5, + /* 00000256 push cs */ 0x0E, + /* 00000257 pop ds */ 0x1F, + /* 00000258 mov si,0x100 */ 0xBE, 0x00, 0x01, + /* 0000025B mov cx,0x100 */ 0xB9, 0x00, 0x01, + /* 0000025E cld */ 0xFC, + /* 0000025F rep movsb */ 0xF3, 0xA4, + /* 00000261 pop cx */ 0x59, + /* 00000262 pop si */ 0x5E, + /* 00000263 pop ds */ 0x1F, + /* 00000264 pop di */ 0x5F, + /* 00000265 pop es */ 0x07, + /* 00000266 jmp word 0x34c */ 0xE9, 0xE3, 0x00, + /* 00000269 push dx */ 0x52, + /* 0000026A push ax */ 0x50, + /* 0000026B cmp bx,0x40f1 */ 0x81, 0xFB, 0xF1, 0x40, + /* 0000026F jz 0x273 */ 0x74, 0x02, + /* 00000271 jmp short 0x22b */ 0xEB, 0xB8, + /* 00000273 mov dx,0x3c0 */ 0xBA, 0xC0, 0x03, + /* 00000276 mov al,0x20 */ 0xB0, 0x20, + /* 00000278 out dx,al */ 0xEE, + /* 00000279 push dx */ 0x52, + /* 0000027A push ax */ 0x50, + /* 0000027B mov dx,0x1ce */ 0xBA, 0xCE, 0x01, + /* 0000027E mov ax,0x4 */ 0xB8, 0x04, 0x00, + /* 00000281 out dx,ax */ 0xEF, + /* 00000282 mov dx,0x1d0 */ 0xBA, 0xD0, 0x01, + /* 00000285 mov ax,0x0 */ 0xB8, 0x00, 0x00, + /* 00000288 out dx,ax */ 0xEF, + /* 00000289 pop ax */ 0x58, + /* 0000028A pop dx */ 0x5A, + /* 0000028B push dx */ 0x52, + /* 0000028C push ax */ 0x50, + /* 0000028D mov dx,0x1ce */ 0xBA, 0xCE, 0x01, + /* 00000290 mov ax,0x5 */ 0xB8, 0x05, 0x00, + /* 00000293 out dx,ax */ 0xEF, + /* 00000294 mov dx,0x1d0 */ 0xBA, 0xD0, 0x01, + /* 00000297 mov ax,0x0 */ 0xB8, 0x00, 0x00, + /* 0000029A out dx,ax */ 0xEF, + /* 0000029B pop ax */ 0x58, + /* 0000029C pop dx */ 0x5A, + /* 0000029D push dx */ 0x52, + /* 0000029E push ax */ 0x50, + /* 0000029F mov dx,0x1ce */ 0xBA, 0xCE, 0x01, + /* 000002A2 mov ax,0x8 */ 0xB8, 0x08, 0x00, + /* 000002A5 out dx,ax */ 0xEF, + /* 000002A6 mov dx,0x1d0 */ 0xBA, 0xD0, 0x01, + /* 000002A9 mov ax,0x0 */ 0xB8, 0x00, 0x00, + /* 000002AC out dx,ax */ 0xEF, + /* 000002AD pop ax */ 0x58, + /* 000002AE pop dx */ 0x5A, + /* 000002AF push dx */ 0x52, + /* 000002B0 push ax */ 0x50, + /* 000002B1 mov dx,0x1ce */ 0xBA, 0xCE, 0x01, + /* 000002B4 mov ax,0x9 */ 0xB8, 0x09, 0x00, + /* 000002B7 out dx,ax */ 0xEF, + /* 000002B8 mov dx,0x1d0 */ 0xBA, 0xD0, 0x01, + /* 000002BB mov ax,0x0 */ 0xB8, 0x00, 0x00, + /* 000002BE out dx,ax */ 0xEF, + /* 000002BF pop ax */ 0x58, + /* 000002C0 pop dx */ 0x5A, + /* 000002C1 push dx */ 0x52, + /* 000002C2 push ax */ 0x50, + /* 000002C3 mov dx,0x1ce */ 0xBA, 0xCE, 0x01, + /* 000002C6 mov ax,0x3 */ 0xB8, 0x03, 0x00, + /* 000002C9 out dx,ax */ 0xEF, + /* 000002CA mov dx,0x1d0 */ 0xBA, 0xD0, 0x01, + /* 000002CD mov ax,0x20 */ 0xB8, 0x20, 0x00, + /* 000002D0 out dx,ax */ 0xEF, + /* 000002D1 pop ax */ 0x58, + /* 000002D2 pop dx */ 0x5A, + /* 000002D3 push dx */ 0x52, + /* 000002D4 push ax */ 0x50, + /* 000002D5 mov dx,0x1ce */ 0xBA, 0xCE, 0x01, + /* 000002D8 mov ax,0x1 */ 0xB8, 0x01, 0x00, + /* 000002DB out dx,ax */ 0xEF, + /* 000002DC mov dx,0x1d0 */ 0xBA, 0xD0, 0x01, + /* 000002DF mov ax,0x400 */ 0xB8, 0x00, 0x04, + /* 000002E2 out dx,ax */ 0xEF, + /* 000002E3 pop ax */ 0x58, + /* 000002E4 pop dx */ 0x5A, + /* 000002E5 push dx */ 0x52, + /* 000002E6 push ax */ 0x50, + /* 000002E7 mov dx,0x1ce */ 0xBA, 0xCE, 0x01, + /* 000002EA mov ax,0x6 */ 0xB8, 0x06, 0x00, + /* 000002ED out dx,ax */ 0xEF, + /* 000002EE mov dx,0x1d0 */ 0xBA, 0xD0, 0x01, + /* 000002F1 mov ax,0x400 */ 0xB8, 0x00, 0x04, + /* 000002F4 out dx,ax */ 0xEF, + /* 000002F5 pop ax */ 0x58, + /* 000002F6 pop dx */ 0x5A, + /* 000002F7 push dx */ 0x52, + /* 000002F8 push ax */ 0x50, + /* 000002F9 mov dx,0x1ce */ 0xBA, 0xCE, 0x01, + /* 000002FC mov ax,0x2 */ 0xB8, 0x02, 0x00, + /* 000002FF out dx,ax */ 0xEF, + /* 00000300 mov dx,0x1d0 */ 0xBA, 0xD0, 0x01, + /* 00000303 mov ax,0x300 */ 0xB8, 0x00, 0x03, + /* 00000306 out dx,ax */ 0xEF, + /* 00000307 pop ax */ 0x58, + /* 00000308 pop dx */ 0x5A, + /* 00000309 push dx */ 0x52, + /* 0000030A push ax */ 0x50, + /* 0000030B mov dx,0x1ce */ 0xBA, 0xCE, 0x01, + /* 0000030E mov ax,0x7 */ 0xB8, 0x07, 0x00, + /* 00000311 out dx,ax */ 0xEF, + /* 00000312 mov dx,0x1d0 */ 0xBA, 0xD0, 0x01, + /* 00000315 mov ax,0x300 */ 0xB8, 0x00, 0x03, + /* 00000318 out dx,ax */ 0xEF, + /* 00000319 pop ax */ 0x58, + /* 0000031A pop dx */ 0x5A, + /* 0000031B push dx */ 0x52, + /* 0000031C push ax */ 0x50, + /* 0000031D mov dx,0x1ce */ 0xBA, 0xCE, 0x01, + /* 00000320 mov ax,0x4 */ 0xB8, 0x04, 0x00, + /* 00000323 out dx,ax */ 0xEF, + /* 00000324 mov dx,0x1d0 */ 0xBA, 0xD0, 0x01, + /* 00000327 mov ax,0x41 */ 0xB8, 0x41, 0x00, + /* 0000032A out dx,ax */ 0xEF, + /* 0000032B pop ax */ 0x58, + /* 0000032C pop dx */ 0x5A, + /* 0000032D pop ax */ 0x58, + /* 0000032E pop dx */ 0x5A, + /* 0000032F jmp short 0x34c */ 0xEB, 0x1B, + /* 00000331 mov bx,0x40f1 */ 0xBB, 0xF1, 0x40, + /* 00000334 jmp short 0x34c */ 0xEB, 0x16, + /* 00000336 jmp short 0x350 */ 0xEB, 0x18, + /* 00000338 jmp short 0x350 */ 0xEB, 0x16, + /* 0000033A cmp al,0x3 */ 0x3C, 0x03, + /* 0000033C jz 0x345 */ 0x74, 0x07, + /* 0000033E cmp al,0x12 */ 0x3C, 0x12, + /* 00000340 jz 0x349 */ 0x74, 0x07, + /* 00000342 jmp word 0x22b */ 0xE9, 0xE6, 0xFE, + /* 00000345 mov al,0x30 */ 0xB0, 0x30, + /* 00000347 jmp short 0x34b */ 0xEB, 0x02, + /* 00000349 mov al,0x20 */ 0xB0, 0x20, + /* 0000034B iretw */ 0xCF, + /* 0000034C mov ax,0x4f */ 0xB8, 0x4F, 0x00, + /* 0000034F iretw */ 0xCF, + /* 00000350 mov ax,0x14f */ 0xB8, 0x4F, 0x01, + /* 00000353 iretw */ 0xCF, +}; +#endif diff --git a/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/VbeShim.sh b/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/VbeShim.sh new file mode 100755 index 00000000..aea28be3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/OvmfPkg/QemuVideoDxe/VbeShim.sh @@ -0,0 +1,79 @@ +#!/bin/sh +### +# @file +# Shell script to assemble and dump the fake Int10h handler from NASM source to +# a C array. +# +# Copyright (C) 2014, Red Hat, Inc. +# Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +### + +set -e -u + +STEM=$(dirname -- "$0")/$(basename -- "$0" .sh) + +# +# Install exit handler -- remove temporary files. +# +exit_handler() +{ + rm -f -- "$STEM".bin "$STEM".disasm "$STEM".offsets "$STEM".insns \ + "$STEM".bytes +} +trap exit_handler EXIT + +# +# Assemble the source file. +# +nasm -o "$STEM".bin -- "$STEM".asm + +# +# Disassemble it, in order to get a binary dump associated with the source. +# (ndisasm doesn't recognize the "--" end-of-options delimiter.) +# +ndisasm "$STEM".bin >"$STEM".disasm + +# +# Create three files, each with one column of the disassembly. +# +# The first column contains the offsets, and it starts the comment. +# +cut -c 1-8 -- "$STEM".disasm \ +| sed -e 's,^, /* ,' >"$STEM".offsets + +# +# The second column contains the assembly-language instructions, and it closes +# the comment. We first pad it to 30 characters. +# +cut -c 29- -- "$STEM".disasm \ +| sed -e 's,$, ,' \ + -e 's,^\(.\{30\}\).*$,\1 */,' >"$STEM".insns + +# +# The third column contains the bytes corresponding to the instruction, +# represented as C integer constants. First strip trailing whitespace from the +# middle column of the input disassembly, then process pairs of nibbles. +# +cut -c 11-28 -- "$STEM".disasm \ +| sed -e 's, \+$,,' -e 's/\(..\)/ 0x\1,/g' >"$STEM".bytes + +# +# Write the output file, recombining the columns. The output should have CRLF +# line endings. +# +{ + printf '//\n' + printf '// THIS FILE WAS GENERATED BY "%s". DO NOT EDIT.\n' \ + "$(basename -- "$0")" + printf '//\n' + printf '#ifndef _VBE_SHIM_H_\n' + printf '#define _VBE_SHIM_H_\n' + printf 'STATIC CONST UINT8 mVbeShim[] = {\n' + paste -d ' ' -- "$STEM".offsets "$STEM".insns "$STEM".bytes + printf '};\n' + printf '#endif\n' +} \ +| unix2dos >"$STEM".h |