summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:49:04 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:49:04 +0000
commit16f504a9dca3fe3b70568f67b7d41241ae485288 (patch)
treec60f36ada0496ba928b7161059ba5ab1ab224f9d /src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe
parentInitial commit. (diff)
downloadvirtualbox-upstream.tar.xz
virtualbox-upstream.zip
Adding upstream version 7.0.6-dfsg.upstream/7.0.6-dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe')
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/ComponentName.c247
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/DriverSupportedEfiVersion.c58
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/Edid.c676
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVga.c1171
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVga.h473
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaDxe.inf133
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaGraphicsOutput.c544
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaI2c.c469
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaI2c.h106
-rw-r--r--src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaUgaDraw.c417
10 files changed, 4294 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/ComponentName.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/ComponentName.c
new file mode 100644
index 00000000..a3a64c94
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/ComponentName.c
@@ -0,0 +1,247 @@
+/* $Id: ComponentName.c $ */
+/** @file
+ * ComponentName.c
+ */
+
+/*
+ * Copyright (C) 2009-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/*
+ This code is based on:
+
+ Copyright (c) 2006, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+*/
+
+#include "VBoxVga.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gVBoxVgaComponentName = {
+ VBoxVgaComponentNameGetDriverName,
+ VBoxVgaComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gVBoxVgaComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) VBoxVgaComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) VBoxVgaComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mVBoxVgaDriverNameTable[] = {
+ { "eng;en", L"VirtualBox SVGA Driver" },
+ { NULL , NULL }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mVBoxVgaControllerNameTable[] = {
+ { "eng;en", L"VirtualBox SVGA 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
+VBoxVgaComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mVBoxVgaDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gVBoxVgaComponentName)
+ );
+}
+
+/**
+ 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
+VBoxVgaComponentNameGetControllerName (
+ 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,
+ gVBoxVgaDriverBinding.DriverBindingHandle,
+ &gEfiPciIoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the Cirrus Logic 5430's Device structure
+ //
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mVBoxVgaControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gVBoxVgaComponentName)
+ );
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/DriverSupportedEfiVersion.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/DriverSupportedEfiVersion.c
new file mode 100644
index 00000000..737e68ff
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/DriverSupportedEfiVersion.c
@@ -0,0 +1,58 @@
+/* $Id: DriverSupportedEfiVersion.c $ */
+/** @file
+ * DriverSupportedEfiVersion.c
+ */
+
+/*
+ * Copyright (C) 2009-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/*
+ This code is based on:
+
+ Copyright (c) 2007, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ Module Name: DriverSupportEfiVersion.c
+
+*/
+#include "VBoxVga.h"
+
+EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL gVBoxVgaDriverSupportedEfiVersion = {
+ sizeof (EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL), // Size of Protocol structure.
+ 0 // Version number to be filled at start up.
+};
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/Edid.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/Edid.c
new file mode 100644
index 00000000..4c3c73c1
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/Edid.c
@@ -0,0 +1,676 @@
+/* $Id: Edid.c $ */
+/** @file
+ * Edid.c
+ */
+
+/*
+ * Copyright (C) 2009-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/*
+ This code is based on:
+
+ Read EDID information and parse EDID information.
+
+ Copyright (c) 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+*/
+
+#include "VBoxVga.h"
+#include "VBoxVgaI2c.h"
+
+//
+// EDID block
+//
+typedef struct {
+ UINT8 Header[8]; //EDID header "00 FF FF FF FF FF FF 00"
+ UINT16 ManufactureName; //EISA 3-character ID
+ UINT16 ProductCode; //Vendor assigned code
+ UINT32 SerialNumber; //32-bit serial number
+ UINT8 WeekOfManufacture; //Week number
+ UINT8 YearOfManufacture; //Year
+ UINT8 EdidVersion; //EDID Structure Version
+ UINT8 EdidRevision; //EDID Structure Revision
+ UINT8 VideoInputDefinition;
+ UINT8 MaxHorizontalImageSize; //cm
+ UINT8 MaxVerticalImageSize; //cm
+ UINT8 DisplayTransferCharacteristic;
+ UINT8 FeatureSupport;
+ UINT8 RedGreenLowBits; //Rx1 Rx0 Ry1 Ry0 Gx1 Gx0 Gy1Gy0
+ UINT8 BlueWhiteLowBits; //Bx1 Bx0 By1 By0 Wx1 Wx0 Wy1 Wy0
+ UINT8 RedX; //Red-x Bits 9 - 2
+ UINT8 RedY; //Red-y Bits 9 - 2
+ UINT8 GreenX; //Green-x Bits 9 - 2
+ UINT8 GreenY; //Green-y Bits 9 - 2
+ UINT8 BlueX; //Blue-x Bits 9 - 2
+ UINT8 BlueY; //Blue-y Bits 9 - 2
+ UINT8 WhiteX; //White-x Bits 9 - 2
+ UINT8 WhiteY; //White-x Bits 9 - 2
+ UINT8 EstablishedTimings[3];
+ UINT8 StandardTimingIdentification[16];
+ UINT8 DetailedTimingDescriptions[72];
+ UINT8 ExtensionFlag; //Number of (optional) 128-byte EDID extension blocks to follow
+ UINT8 Checksum;
+} EDID_BLOCK;
+
+#define EDID_BLOCK_SIZE 128
+#define VBE_EDID_ESTABLISHED_TIMING_MAX_NUMBER 17
+
+typedef struct {
+ UINT16 HorizontalResolution;
+ UINT16 VerticalResolution;
+ UINT16 RefreshRate;
+} EDID_TIMING;
+
+typedef struct {
+ UINT32 ValidNumber;
+ UINT32 Key[VBE_EDID_ESTABLISHED_TIMING_MAX_NUMBER];
+} VALID_EDID_TIMING;
+
+//
+// Standard timing defined by VESA EDID
+//
+EDID_TIMING mVbeEstablishedEdidTiming[] = {
+ //
+ // Established Timing I
+ //
+ {800, 600, 60},
+ {800, 600, 56},
+ {640, 480, 75},
+ {640, 480, 72},
+ {640, 480, 67},
+ {640, 480, 60},
+ {720, 400, 88},
+ {720, 400, 70},
+ //
+ // Established Timing II
+ //
+ {1280, 1024, 75},
+ {1024, 768, 75},
+ {1024, 768, 70},
+ {1024, 768, 60},
+ {1024, 768, 87},
+ {832, 624, 75},
+ {800, 600, 75},
+ {800, 600, 72},
+ //
+ // Established Timing III
+ //
+ {1152, 870, 75}
+};
+
+/**
+ Read EDID information from I2C Bus on CirrusLogic.
+
+ @param Private Pointer to VBOX_VGA_PRIVATE_DATA.
+ @param EdidDataBlock Pointer to EDID data block.
+ @param EdidSize Returned EDID block size.
+
+ @retval EFI_UNSUPPORTED
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+ReadEdidData (
+ VBOX_VGA_PRIVATE_DATA *Private,
+ UINT8 **EdidDataBlock,
+ UINTN *EdidSize
+ )
+{
+ UINTN Index;
+ UINT8 EdidData[EDID_BLOCK_SIZE * 2];
+ UINT8 *ValidEdid;
+ UINT64 Signature;
+
+ for (Index = 0; Index < EDID_BLOCK_SIZE * 2; Index ++) {
+ I2cReadByte (Private->PciIo, 0xa0, (UINT8)Index, &EdidData[Index]);
+ }
+
+ //
+ // Search for the EDID signature
+ //
+ ValidEdid = &EdidData[0];
+ Signature = 0x00ffffffffffff00ull;
+ for (Index = 0; Index < EDID_BLOCK_SIZE * 2; Index ++, ValidEdid ++) {
+ if (CompareMem (ValidEdid, &Signature, 8) == 0) {
+ break;
+ }
+ }
+
+ if (Index == 256) {
+ //
+ // No EDID signature found
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ *EdidDataBlock = AllocateCopyPool (
+ sizeof (EDID_BLOCK_SIZE),
+ ValidEdid
+ );
+ if (*EdidDataBlock == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Currently only support EDID 1.x
+ //
+ *EdidSize = EDID_BLOCK_SIZE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Generate a search key for a specified timing data.
+
+ @param EdidTiming Pointer to EDID timing
+
+ @return The 32 bit unique key for search.
+
+**/
+UINT32
+CalculateEdidKey (
+ EDID_TIMING *EdidTiming
+ )
+{
+ UINT32 Key;
+
+ //
+ // Be sure no conflicts for all standard timing defined by VESA.
+ //
+ Key = (EdidTiming->HorizontalResolution * 2) + EdidTiming->VerticalResolution;
+ return Key;
+}
+
+/**
+ Search a specified Timing in all the valid EDID timings.
+
+ @param ValidEdidTiming All valid EDID timing information.
+ @param EdidTiming The Timing to search for.
+
+ @retval TRUE Found.
+ @retval FALSE Not found.
+
+**/
+BOOLEAN
+SearchEdidTiming (
+ VALID_EDID_TIMING *ValidEdidTiming,
+ EDID_TIMING *EdidTiming
+ )
+{
+ UINT32 Index;
+ UINT32 Key;
+
+ Key = CalculateEdidKey (EdidTiming);
+
+ for (Index = 0; Index < ValidEdidTiming->ValidNumber; Index ++) {
+ if (Key == ValidEdidTiming->Key[Index]) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Parse the Established Timing and Standard Timing in EDID data block.
+
+ @param EdidBuffer Pointer to EDID data block
+ @param ValidEdidTiming Valid EDID timing information
+
+ @retval TRUE The EDID data is valid.
+ @retval FALSE The EDID data is invalid.
+
+**/
+BOOLEAN
+ParseEdidData (
+ UINT8 *EdidBuffer,
+ VALID_EDID_TIMING *ValidEdidTiming
+ )
+{
+ UINT8 CheckSum;
+ UINT32 Index;
+ UINT32 ValidNumber;
+ UINT32 TimingBits;
+ UINT8 *BufferIndex;
+ UINT16 HorizontalResolution;
+ UINT16 VerticalResolution;
+ UINT8 AspectRatio;
+ UINT8 RefreshRate;
+ EDID_TIMING TempTiming;
+ EDID_BLOCK *EdidDataBlock;
+
+ EdidDataBlock = (EDID_BLOCK *) EdidBuffer;
+
+ //
+ // Check the checksum of EDID data
+ //
+ CheckSum = 0;
+ for (Index = 0; Index < EDID_BLOCK_SIZE; Index ++) {
+ CheckSum = (UINT8) (CheckSum + EdidBuffer[Index]);
+ }
+ if (CheckSum != 0) {
+ return FALSE;
+ }
+
+ ValidNumber = 0;
+ SetMem (ValidEdidTiming, sizeof (VALID_EDID_TIMING), 0);
+
+ if ((EdidDataBlock->EstablishedTimings[0] != 0) ||
+ (EdidDataBlock->EstablishedTimings[1] != 0) ||
+ (EdidDataBlock->EstablishedTimings[2] != 0)
+ ) {
+ //
+ // Established timing data
+ //
+ TimingBits = EdidDataBlock->EstablishedTimings[0] |
+ (EdidDataBlock->EstablishedTimings[1] << 8) |
+ ((EdidDataBlock->EstablishedTimings[2] & 0x80) << 9) ;
+ for (Index = 0; Index < VBE_EDID_ESTABLISHED_TIMING_MAX_NUMBER; Index ++) {
+ if (TimingBits & 0x1) {
+ ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&mVbeEstablishedEdidTiming[Index]);
+ ValidNumber ++;
+ }
+ TimingBits = TimingBits >> 1;
+ }
+ } else {
+ //
+ // If no Established timing data, read the standard timing data
+ //
+ BufferIndex = &EdidDataBlock->StandardTimingIdentification[0];
+ for (Index = 0; Index < 8; Index ++) {
+ if ((BufferIndex[0] != 0x1) && (BufferIndex[1] != 0x1)){
+ //
+ // A valid Standard Timing
+ //
+ HorizontalResolution = (UINT16) (BufferIndex[0] * 8 + 248);
+ AspectRatio = (UINT8) (BufferIndex[1] >> 6);
+ switch (AspectRatio) {
+ case 0:
+ VerticalResolution = (UINT16) (HorizontalResolution / 16 * 10);
+ break;
+ case 1:
+ VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);
+ break;
+ case 2:
+ VerticalResolution = (UINT16) (HorizontalResolution / 5 * 4);
+ break;
+ case 3:
+ VerticalResolution = (UINT16) (HorizontalResolution / 16 * 9);
+ break;
+ default:
+ VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);
+ break;
+ }
+ RefreshRate = (UINT8) ((BufferIndex[1] & 0x1f) + 60);
+ TempTiming.HorizontalResolution = HorizontalResolution;
+ TempTiming.VerticalResolution = VerticalResolution;
+ TempTiming.RefreshRate = RefreshRate;
+ ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&TempTiming);
+ ValidNumber ++;
+ }
+ BufferIndex += 2;
+ }
+ }
+
+ ValidEdidTiming->ValidNumber = ValidNumber;
+ return TRUE;
+}
+
+static uint16_t in_word(uint16_t port, uint16_t addr)
+{
+ ASMOutU16(port, addr);
+ return ASMInU16(port);
+}
+
+static EFI_STATUS VBoxVgaVideoModeInitExtra(void)
+{
+ UINT16 w, cur_info_ofs, vmode, xres, yres;
+ UINTN Index;
+ VBOX_VGA_VIDEO_MODES *VideoMode;
+
+ // Read and check the VBE Extra Data magic
+ w = in_word(VBE_EXTRA_PORT, 0);
+ if (w != VBEHEADER_MAGIC) {
+ DEBUG((DEBUG_INFO, "%a:%d could not find VBE magic, got %x\n", __FILE__, __LINE__, w));
+ return EFI_NOT_FOUND;
+ }
+
+ cur_info_ofs = sizeof(VBEHeader);
+
+ Index = VBoxVgaVideoModeCount - 16;
+ VideoMode = &VBoxVgaVideoModes[Index];
+ vmode = in_word(VBE_EXTRA_PORT, cur_info_ofs + OFFSET_OF(ModeInfoListItem, mode));
+ while (vmode != VBE_VESA_MODE_END_OF_LIST)
+ {
+ xres = in_word(VBE_EXTRA_PORT, cur_info_ofs + OFFSET_OF(ModeInfoListItem, info.XResolution));
+ yres = in_word(VBE_EXTRA_PORT, cur_info_ofs + OFFSET_OF(ModeInfoListItem, info.YResolution));
+
+ if (vmode >= VBE_VBOX_MODE_CUSTOM1 && vmode <= VBE_VBOX_MODE_CUSTOM16 && xres && yres && Index < VBoxVgaVideoModeCount) {
+ VideoMode->Width = xres;
+ VideoMode->Height = yres;
+ VideoMode->ColorDepth = 32;
+ VideoMode->RefreshRate = 60;
+ VideoMode->MiscSetting = 0x01;
+ VideoMode++;
+ Index++;
+ }
+
+ cur_info_ofs += sizeof(ModeInfoListItem);
+ vmode = in_word(VBE_EXTRA_PORT, cur_info_ofs + OFFSET_OF(ModeInfoListItem, mode));
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Construct the valid video modes for VBoxVga.
+
+**/
+EFI_STATUS
+VBoxVgaVideoModeSetup (
+ VBOX_VGA_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ BOOLEAN EdidFound;
+ EFI_EDID_OVERRIDE_PROTOCOL *EdidOverride;
+ UINT32 EdidAttributes;
+ BOOLEAN EdidOverrideFound;
+ UINTN EdidOverrideDataSize;
+ UINT8 *EdidOverrideDataBlock;
+ UINTN EdidDiscoveredDataSize;
+ UINT8 *EdidDiscoveredDataBlock;
+ UINTN EdidActiveDataSize;
+ UINT8 *EdidActiveDataBlock;
+ VALID_EDID_TIMING ValidEdidTiming;
+ UINT32 ValidModeCount;
+ VBOX_VGA_MODE_DATA *ModeData;
+ BOOLEAN TimingMatch;
+ const VBOX_VGA_VIDEO_MODES *VideoMode;
+ EDID_TIMING TempTiming;
+
+ //
+ // setup EDID information
+ //
+ Private->EdidDiscovered.Edid = NULL;
+ Private->EdidDiscovered.SizeOfEdid = 0;
+ Private->EdidActive.Edid = NULL;
+ Private->EdidActive.SizeOfEdid = 0;
+
+ EdidFound = FALSE;
+ EdidOverrideFound = FALSE;
+ EdidAttributes = 0xff;
+ EdidOverrideDataSize = 0;
+ EdidOverrideDataBlock = NULL;
+ EdidActiveDataSize = 0;
+ EdidActiveDataBlock = NULL;
+ EdidDiscoveredDataBlock = NULL;
+
+ //
+ // Find EDID Override protocol firstly, this protocol is installed by platform if needed.
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiEdidOverrideProtocolGuid,
+ NULL,
+ (VOID **) &EdidOverride
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow
+ //
+ EdidOverrideDataBlock = AllocatePool (sizeof (EDID_BLOCK_SIZE * 2));
+ if (NULL == EdidOverrideDataBlock) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ Status = EdidOverride->GetEdid (
+ EdidOverride,
+ Private->Handle,
+ &EdidAttributes,
+ &EdidOverrideDataSize,
+ (UINT8 **) &EdidOverrideDataBlock
+ );
+ if (!EFI_ERROR (Status) &&
+ EdidAttributes == 0 &&
+ EdidOverrideDataSize != 0) {
+ //
+ // Succeeded to get EDID Override Data
+ //
+ EdidOverrideFound = TRUE;
+ }
+ }
+
+ if (EdidOverrideFound != TRUE || EdidAttributes == EFI_EDID_OVERRIDE_DONT_OVERRIDE) {
+ //
+ // If EDID Override data doesn't exist or EFI_EDID_OVERRIDE_DONT_OVERRIDE returned,
+ // read EDID information through I2C Bus
+ //
+ if (ReadEdidData (Private, &EdidDiscoveredDataBlock, &EdidDiscoveredDataSize) == EFI_SUCCESS) {
+ Private->EdidDiscovered.SizeOfEdid = (UINT32) EdidDiscoveredDataSize;
+ Private->EdidDiscovered.Edid = (UINT8 *) AllocateCopyPool (
+ EdidDiscoveredDataSize,
+ EdidDiscoveredDataBlock
+ );
+
+ if (NULL == Private->EdidDiscovered.Edid) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ EdidActiveDataSize = Private->EdidDiscovered.SizeOfEdid;
+ EdidActiveDataBlock = Private->EdidDiscovered.Edid;
+
+ EdidFound = TRUE;
+ }
+ }
+
+ if (EdidFound != TRUE && EdidOverrideFound == TRUE) {
+ EdidActiveDataSize = EdidOverrideDataSize;
+ EdidActiveDataBlock = EdidOverrideDataBlock;
+ EdidFound = TRUE;
+ }
+
+ if (EdidFound == TRUE) {
+ //
+ // Parse EDID data structure to retrieve modes supported by monitor
+ //
+ if (ParseEdidData ((UINT8 *) EdidActiveDataBlock, &ValidEdidTiming) == TRUE) {
+ //
+ // Copy EDID Override Data to EDID Active Data
+ //
+ Private->EdidActive.SizeOfEdid = (UINT32) EdidActiveDataSize;
+ Private->EdidActive.Edid = (UINT8 *) AllocateCopyPool (
+ EdidActiveDataSize,
+ EdidActiveDataBlock
+ );
+ if (NULL == Private->EdidActive.Edid) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ }
+ } else {
+ Private->EdidActive.SizeOfEdid = 0;
+ Private->EdidActive.Edid = NULL;
+ EdidFound = FALSE;
+ }
+
+ if (EdidFound && 0) {
+ //
+ // Initialize the private mode data with the supported modes.
+ //
+ ValidModeCount = 0;
+ Private->ModeData = AllocatePool(sizeof(VBOX_VGA_MODE_DATA) * VBoxVgaVideoModeCount);
+ ModeData = &Private->ModeData[0];
+ VideoMode = &VBoxVgaVideoModes[0];
+ for (Index = 0; Index < VBoxVgaVideoModeCount; Index++) {
+
+ TimingMatch = TRUE;
+
+ //
+ // Check whether match with VBoxVga video mode
+ //
+ TempTiming.HorizontalResolution = (UINT16) VideoMode->Width;
+ TempTiming.VerticalResolution = (UINT16) VideoMode->Height;
+ TempTiming.RefreshRate = (UINT16) VideoMode->RefreshRate;
+ if (SearchEdidTiming (&ValidEdidTiming, &TempTiming) != TRUE) {
+ TimingMatch = FALSE;
+ }
+
+ //
+ // Not export Mode 0x0 as GOP mode, this is not defined in spec.
+ //
+ if ((VideoMode->Width == 0) || (VideoMode->Height == 0)) {
+ TimingMatch = FALSE;
+ }
+
+ //
+ // Check whether the mode would be exceeding the VRAM size.
+ //
+ if (VideoMode->Width * VideoMode->Height * (VideoMode->ColorDepth / 8) > Private->VRAMSize) {
+ TimingMatch = FALSE;
+ }
+
+ if (TimingMatch) {
+ ModeData->ModeNumber = Index;
+ ModeData->HorizontalResolution = VideoMode->Width;
+ ModeData->VerticalResolution = VideoMode->Height;
+ ModeData->ColorDepth = VideoMode->ColorDepth;
+ ModeData->RefreshRate = VideoMode->RefreshRate;
+
+ ModeData ++;
+ ValidModeCount ++;
+ }
+
+ VideoMode ++;
+ }
+ } else {
+ //
+ // If EDID information wasn't found
+ //
+ VBoxVgaVideoModeInitExtra();
+ ValidModeCount = 0;
+ Private->ModeData = AllocatePool(sizeof(VBOX_VGA_MODE_DATA) * VBoxVgaVideoModeCount);
+ ModeData = &Private->ModeData[0];
+ VideoMode = &VBoxVgaVideoModes[0];
+ for (Index = 0; Index < VBoxVgaVideoModeCount; Index ++) {
+
+ TimingMatch = TRUE;
+
+ //
+ // Not export Mode 0x0 as GOP mode, this is not defined in spec.
+ //
+ if ((VideoMode->Width == 0) || (VideoMode->Height == 0)) {
+ TimingMatch = FALSE;
+ }
+
+ //
+ // Check whether the mode would be exceeding the VRAM size.
+ //
+ if (VideoMode->Width * VideoMode->Height * (VideoMode->ColorDepth / 8) > Private->VRAMSize) {
+ TimingMatch = FALSE;
+ }
+
+ if (TimingMatch) {
+ ModeData->ModeNumber = Index;
+ ModeData->HorizontalResolution = VideoMode->Width;
+ ModeData->VerticalResolution = VideoMode->Height;
+ ModeData->ColorDepth = VideoMode->ColorDepth;
+ ModeData->RefreshRate = VideoMode->RefreshRate;
+
+ ModeData ++;
+ ValidModeCount ++;
+ }
+
+ VideoMode ++;
+ }
+ }
+
+ // Sort list of video modes (keeping duplicates) by increasing X, then Y,
+ // then the mode number. This way the custom modes are not overriding the
+ // default modes if they are for the same resolution.
+ ModeData = &Private->ModeData[0];
+ for (Index = 0; Index < ValidModeCount - 1; Index ++) {
+ UINT32 Index2;
+ VBOX_VGA_MODE_DATA *ModeData2 = ModeData + 1;
+ for (Index2 = Index + 1; Index2 < ValidModeCount; Index2 ++) {
+ if ( ModeData->HorizontalResolution > ModeData2->HorizontalResolution
+ || ( ModeData->HorizontalResolution == ModeData2->HorizontalResolution
+ && ModeData->VerticalResolution > ModeData2->VerticalResolution)
+ || ( ModeData->HorizontalResolution == ModeData2->HorizontalResolution
+ && ModeData->VerticalResolution == ModeData2->VerticalResolution
+ && ModeData->ModeNumber > ModeData2->ModeNumber)) {
+ VBOX_VGA_MODE_DATA Tmp;
+ CopyMem(&Tmp, ModeData, sizeof(Tmp));
+ CopyMem(ModeData, ModeData2, sizeof(Tmp));
+ CopyMem(ModeData2, &Tmp, sizeof(Tmp));
+ DEBUG((DEBUG_INFO, "%a:%d swapped mode entries %d and %d\n", __FILE__, __LINE__, Index, Index2));
+ }
+ ModeData2++;
+ }
+ ModeData++;
+ }
+
+ // dump mode list for debugging purposes
+ ModeData = &Private->ModeData[0];
+ for (Index = 0; Index < ValidModeCount; Index ++) {
+ DEBUG((DEBUG_INFO, "%a:%d mode %d: %dx%d mode number %d\n", __FILE__, __LINE__, Index, ModeData->HorizontalResolution, ModeData->VerticalResolution, ModeData->ModeNumber));
+ ModeData++;
+ }
+
+ Private->MaxMode = ValidModeCount;
+
+ if (EdidOverrideDataBlock != NULL) {
+ FreePool (EdidOverrideDataBlock);
+ }
+
+ return EFI_SUCCESS;
+
+Done:
+ if (EdidOverrideDataBlock != NULL) {
+ FreePool (EdidOverrideDataBlock);
+ }
+ if (Private->EdidDiscovered.Edid != NULL) {
+ FreePool (Private->EdidDiscovered.Edid);
+ }
+ if (Private->EdidDiscovered.Edid != NULL) {
+ FreePool (Private->EdidActive.Edid);
+ }
+
+ return EFI_DEVICE_ERROR;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVga.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVga.c
new file mode 100644
index 00000000..3d97fa94
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVga.c
@@ -0,0 +1,1171 @@
+/* $Id: VBoxVga.c $ */
+/** @file
+ * VBoxVga.c
+ */
+
+/*
+ * Copyright (C) 2009-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/*
+ This code is based on:
+
+ Cirrus Logic 5430 Controller Driver.
+ This driver is a sample implementation of the UGA Draw and Graphics Output
+ Protocols for the Cirrus Logic 5430 family of PCI video controllers.
+ This driver is only usable in the EFI pre-boot environment.
+ This sample is intended to show how the UGA Draw and Graphics output Protocol
+ is able to function.
+ The UGA I/O Protocol is not implemented in this sample.
+ A fully compliant EFI UGA driver requires both
+ the UGA Draw and the UGA I/O Protocol. Please refer to Microsoft's
+ documentation on UGA for details on how to write a UGA driver that is able
+ to function both in the EFI pre-boot environment and from the OS runtime.
+
+ Copyright (c) 2006 - 2009, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+*/
+
+//
+// VirtualBox VGA Controller Driver
+//
+#include "VBoxVga.h"
+#include <IndustryStandard/Acpi.h>
+#include "iprt/asm.h"
+
+
+#define BOUTB(storage, count, aport, dport) \
+ do { \
+ for (i = 0 ; i < (count); ++i) \
+ if ((dport) == (aport) + 1) \
+ ASMOutU16((aport), ((UINT16)storage[i] << 8) | (UINT8)i); \
+ else { \
+ ASMOutU8((aport), (UINT8)i); \
+ ASMOutU8((dport), storage[i]); \
+ } \
+ } while (0)
+
+
+
+EFI_DRIVER_BINDING_PROTOCOL gVBoxVgaDriverBinding = {
+ VBoxVgaControllerDriverSupported,
+ VBoxVgaControllerDriverStart,
+ VBoxVgaControllerDriverStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+///
+/// 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
+};
+
+///
+/// Generic Graphics Controller Sequencer Register Settings
+///
+UINT8 Seq_Default[5] = {
+ 0x01, 0x01, 0x0f, 0x00, 0x0a
+};
+
+#if 0 // CRTC tables not used (and not checked for correctness), as VBE is much simpler
+//
+// 640 x 480 x 256 color @ 60 Hertz
+//
+UINT8 Crtc_640_480_256_60[25] = {
+ /* r0 = */0x5f, /* r1 = */0x4f, /* r2 = */0x50, /* r3 = */0x82,
+ /* r4 = */0x54, /* r5 = */0x80, /* r6 = */0x0b, /* r7 = */0x3e,
+ /* r8 = */0x00, /* r9 = */0x40, /* r10 = */0x00, /* r11 = */0x00,
+ /* r12 = */0x00, /* r13 = */0x00, /* r14 = */0x00, /* r15 = */0x00,
+ /* r16 = */0xea, /* r17 = */0x0c, /* r18 = */0xdf, /* r19 = */0x28,
+ /* r20 = */0x4f, /* r21 = */0xe7, /* r22 = */0x04, /* r23 = */0xe3,
+ /* r24 = */0xff
+};
+
+//
+// 800 x 600 x 256 color @ 60 Hertz
+//
+UINT8 Crtc_800_600_256_60[25] = {
+ /* r0 = */0x7f, /* r1 = */0x63, /* r2 = */0x64, /* r3 = */0x82,
+ /* r4 = */0x6b, /* r5 = */0x80, /* r6 = */0x0b, /* r7 = */0x3e,
+ /* r8 = */0x00, /* r9 = */0x60, /* r10 = */0x00, /* r11 = */0x00,
+ /* r12 = */0x00, /* r13 = */0x00, /* r14 = */0x00, /* r15 = */0x00,
+ /* r16 = */0xea, /* r17 = */0x0c, /* r18 = */0xdf, /* r19 = */0x28,
+ /* r20 = */0x4f, /* r21 = */0xe7, /* r22 = */0x04, /* r23 = */0xe3,
+ /* r24 = */0xff
+
+};
+
+//
+// 1024 x 768 x 256 color @ 60 Hertz
+//
+UINT8 Crtc_1024_768_256_60[25] = {
+ /* r0 = */0xa3, /* r1 = */0x7f, /* r2 = */0x81, /* r3 = */0x90,
+ /* r4 = */0x88, /* r5 = */0x05, /* r6 = */0x28, /* r7 = */0xfd,
+ /* r8 = */0x00, /* r9 = */0x60, /* r10 = */0x00, /* r11 = */0x00,
+ /* r12 = */0x00, /* r13 = */0x00, /* r14 = */0x00, /* r15 = */0x00,
+ /* r16 = */0x06, /* r17 = */0x0f, /* r18 = */0xff, /* r19 = */0x40,
+ /* r20 = */0x4f, /* r21 = */0x05, /* r22 = */0x1a, /* r23 = */0xe3,
+ /* r24 = */0xff
+};
+#endif
+
+///
+/// Table of supported video modes (sorted by increasing horizontal, then by
+/// increasing vertical resolution)
+///
+VBOX_VGA_VIDEO_MODES VBoxVgaVideoModes[] =
+{
+ { 640, 480, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // VGA 4:3
+ { 800, 600, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // SVGA 4:3
+ { 1024, 768, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // XGA 4:3
+ { 1152, 864, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // XGA+ 4:3
+ { 1280, 720, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // HD 16:9
+ { 1280, 800, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // WXGA 16:10
+ { 1280, 1024, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // SXGA 5:4
+ { 1400, 1050, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // SXGA+ 4:3
+ { 1440, 900, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // WXGA+ 16:10
+ { 1600, 900, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // HD+ 16:9
+ { 1600, 1200, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // UXGA 4:3
+ { 1680, 1050, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // WSXGA+ 16:10
+ { 1920, 1080, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // FHD 16:9
+ { 1920, 1200, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // WUXGA 16:10
+ { 2048, 1080, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // DCI_2K 19:10
+ { 2160, 1440, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // FHD+ 3:2
+ { 2304, 1440, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // unnamed 16:10
+ { 2560, 1440, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // QHD 16:9
+ { 2560, 1600, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // WQXGA 16:10
+ { 2880, 1800, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // QWXGA+ 16:10
+ { 3200, 1800, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // QHD+ 16:9
+ { 3200, 2048, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // WQSXGA 16:10
+ { 3840, 2160, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // 4K_UHD 16:9
+ { 3840, 2400, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // WQUXGA 16:10
+ { 4096, 2160, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // DCI_4K 19:10
+ { 4096, 3072, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // HXGA 4:3
+ { 5120, 2880, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // UHD+ 16:9
+ { 5120, 3200, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // WHXGA 16:10
+ { 6400, 4096, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // WHSXGA 16:10
+ { 6400, 4800, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // HUXGA 4:3
+ { 7680, 4320, 32, 60, NULL /* crtc */, NULL /* sequencer */, 0x01 }, // 8K_UHD2 16:9
+ { 0, }, // Custom video mode 0, do not delete, must be at the end!
+ { 0, }, // Custom video mode 1, do not delete, must be at the end!
+ { 0, }, // Custom video mode 2, do not delete, must be at the end!
+ { 0, }, // Custom video mode 3, do not delete, must be at the end!
+ { 0, }, // Custom video mode 4, do not delete, must be at the end!
+ { 0, }, // Custom video mode 5, do not delete, must be at the end!
+ { 0, }, // Custom video mode 6, do not delete, must be at the end!
+ { 0, }, // Custom video mode 7, do not delete, must be at the end!
+ { 0, }, // Custom video mode 8, do not delete, must be at the end!
+ { 0, }, // Custom video mode 9, do not delete, must be at the end!
+ { 0, }, // Custom video mode 10, do not delete, must be at the end!
+ { 0, }, // Custom video mode 11, do not delete, must be at the end!
+ { 0, }, // Custom video mode 12, do not delete, must be at the end!
+ { 0, }, // Custom video mode 13, do not delete, must be at the end!
+ { 0, }, // Custom video mode 14, do not delete, must be at the end!
+ { 0, } // Custom video mode 15, do not delete, must be at the end!
+};
+
+const UINT32 VBoxVgaVideoModeCount = sizeof(VBoxVgaVideoModes) / sizeof(VBoxVgaVideoModes[0]);
+
+typedef struct _APPLE_FRAMEBUFFERINFO_PROTOCOL APPLE_FRAMEBUFFERINFO_PROTOCOL;
+
+typedef
+EFI_STATUS
+(EFIAPI *APPLE_FRAMEBUFFERINFO_PROTOCOL_GET_INFO) (
+ IN APPLE_FRAMEBUFFERINFO_PROTOCOL *This,
+ OUT UINT32 *BaseAddr,
+ OUT UINT32 *Something,
+ OUT UINT32 *RowBytes,
+ OUT UINT32 *Width,
+ OUT UINT32 *Height,
+ OUT UINT32 *Depth);
+
+struct _APPLE_FRAMEBUFFERINFO_PROTOCOL {
+ APPLE_FRAMEBUFFERINFO_PROTOCOL_GET_INFO GetInfo;
+ VBOX_VGA_PRIVATE_DATA *Private;
+};
+
+EFI_STATUS EFIAPI
+GetFrameBufferInfo(IN APPLE_FRAMEBUFFERINFO_PROTOCOL *This,
+ OUT UINT32 *BaseAddr,
+ OUT UINT32 *Something,
+ OUT UINT32 *RowBytes,
+ OUT UINT32 *Width,
+ OUT UINT32 *Height,
+ OUT UINT32 *Depth);
+
+static APPLE_FRAMEBUFFERINFO_PROTOCOL gAppleFrameBufferInfo =
+{
+ GetFrameBufferInfo,
+ NULL
+};
+
+
+/*
+ * @todo move this function to the library.
+ */
+UINT32 VBoxVgaGetVmVariable(UINT32 Variable, CHAR8* Buffer, UINT32 Size)
+{
+ UINT32 VarLen, i;
+
+ ASMOutU32(EFI_INFO_PORT, Variable);
+ VarLen = ASMInU32(EFI_INFO_PORT);
+
+ for (i = 0; i < VarLen && i < Size; i++)
+ Buffer[i] = ASMInU8(EFI_INFO_PORT);
+
+ return VarLen;
+}
+
+
+/**
+ VBoxVgaControllerDriverSupported
+
+ TODO: This - add argument and description to function comment
+ TODO: Controller - add argument and description to function comment
+ TODO: RemainingDevicePath - add argument and description to function comment
+**/
+EFI_STATUS
+EFIAPI
+VBoxVgaControllerDriverSupported (
+ 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;
+ EFI_DEV_PATH *Node;
+
+ //
+ // 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)) {
+ DEBUG((DEBUG_INFO, "%a:%d status:%r\n", __FILE__, __LINE__, 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)) {
+ DEBUG((DEBUG_INFO, "%a:%d status:%r\n", __FILE__, __LINE__, Status));
+ goto Done;
+ }
+
+ Status = EFI_UNSUPPORTED;
+ //
+ // See if the I/O enable is on. Most systems only allow one VGA device to be turned on
+ // at a time, so see if this is one that is turned on.
+ //
+ // if (((Pci.Hdr.Command & 0x01) == 0x01)) {
+ //
+ // See if this is a VirtualBox VGA or VMSVGA II PCI controller
+ //
+ if ( ((Pci.Hdr.VendorId == VBOX_VENDOR_ID) && (Pci.Hdr.DeviceId == VBOX_VGA_DEVICE_ID))
+ || ((Pci.Hdr.VendorId == VMSVGA_VENDOR_ID) && (Pci.Hdr.DeviceId == VMSVGA_II_DEVICE_ID))) {
+
+ Status = EFI_SUCCESS;
+ if (RemainingDevicePath != NULL) {
+ Node = (EFI_DEV_PATH *) RemainingDevicePath;
+ //
+ // Check if RemainingDevicePath is the End of Device Path Node,
+ // if yes, return EFI_SUCCESS
+ //
+ if (!IsDevicePathEnd (Node)) {
+ //
+ // If RemainingDevicePath isn't the End of Device Path Node,
+ // check its validation
+ //
+ if (Node->DevPath.Type != ACPI_DEVICE_PATH ||
+ Node->DevPath.SubType != ACPI_ADR_DP ||
+ DevicePathNodeLength(&Node->DevPath) != sizeof(ACPI_ADR_DEVICE_PATH)) {
+ DEBUG((DEBUG_INFO, "%a:%d status:%r\n", __FILE__, __LINE__, Status));
+ Status = EFI_UNSUPPORTED;
+ }
+ }
+ }
+ }
+
+Done:
+ //
+ // Close the PCI I/O Protocol
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ DEBUG((DEBUG_INFO, "%a:%d status:%r\n", __FILE__, __LINE__, Status));
+ return Status;
+}
+
+/**
+ VBoxVgaControllerDriverStart
+
+ TODO: This - add argument and description to function comment
+ TODO: Controller - add argument and description to function comment
+ TODO: RemainingDevicePath - add argument and description to function comment
+**/
+EFI_STATUS
+EFIAPI
+VBoxVgaControllerDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ VBOX_VGA_PRIVATE_DATA *Private;
+ BOOLEAN PciAttributesSaved;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ ACPI_ADR_DEVICE_PATH AcpiDeviceNode;
+ PCI_TYPE00 Pci;
+
+ PciAttributesSaved = FALSE;
+ //
+ // Allocate Private context data for UGA Draw interface.
+ //
+ Private = AllocateZeroPool (sizeof (VBOX_VGA_PRIVATE_DATA));
+ if (Private == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+ gAppleFrameBufferInfo.Private = Private;
+ //
+ // Set up context record
+ //
+ Private->Signature = VBOX_VGA_PRIVATE_DATA_SIGNATURE;
+ Private->Handle = NULL;
+
+ //
+ // 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 Error;
+ }
+
+ //
+ // Read the PCI Configuration Header from the PCI Device again to figure out the model.
+ //
+ Status = Private->PciIo->Pci.Read (
+ Private->PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (Pci) / sizeof (UINT32),
+ &Pci
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_INFO, "%a:%d status:%r\n", __FILE__, __LINE__, Status));
+ goto Error;
+ }
+
+ Private->DeviceType = Pci.Hdr.DeviceId;
+
+ //
+ // Save original PCI attributes
+ //
+ Status = Private->PciIo->Attributes (
+ Private->PciIo,
+ EfiPciIoAttributeOperationGet,
+ 0,
+ &Private->OriginalPciAttributes
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ PciAttributesSaved = TRUE;
+
+ Status = Private->PciIo->Attributes (
+ Private->PciIo,
+ EfiPciIoAttributeOperationEnable,
+ EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ //
+ // Get ParentDevicePath
+ //
+ Status = gBS->HandleProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ if (FeaturePcdGet (PcdSupportGop)) {
+ //
+ // Set Gop Device Path
+ //
+ if (RemainingDevicePath == NULL) {
+ ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH));
+ AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;
+ AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;
+ AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA, 0, 0);
+ SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH));
+
+ Private->GopDevicePath = AppendDevicePathNode (
+ ParentDevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode
+ );
+ } else if (!IsDevicePathEnd (RemainingDevicePath)) {
+ //
+ // If RemainingDevicePath isn't the End of Device Path Node,
+ // only scan the specified device by RemainingDevicePath
+ //
+ Private->GopDevicePath = AppendDevicePathNode (ParentDevicePath, RemainingDevicePath);
+ } else {
+ //
+ // If RemainingDevicePath is the End of Device Path Node,
+ // don't create child device and return EFI_SUCCESS
+ //
+ Private->GopDevicePath = NULL;
+ }
+
+ if (Private->GopDevicePath != NULL) {
+ //
+ // Create child handle and device path protocol first
+ //
+ Private->Handle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Private->Handle,
+ &gEfiDevicePathProtocolGuid,
+ Private->GopDevicePath,
+ NULL
+ );
+ }
+ }
+
+ //
+ // Now do some model-specific setup.
+ //
+ if (Private->DeviceType == VMSVGA_II_DEVICE_ID) {
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *IOPortDesc;
+
+ // VMSVGA
+ Private->BarIndexFB = 1;
+
+ Private->PciIo->GetBarAttributes (
+ Private->PciIo,
+ 0, // BAR 0 is the I/O port space
+ NULL,
+ (VOID**) &IOPortDesc
+ );
+ Private->IOBase = (UINT16)IOPortDesc->AddrRangeMin;
+
+ //
+ // Query the VRAM size (for proper mode filtering)
+ //
+ ASMOutU32(Private->IOBase + SVGA_INDEX_PORT, SVGA_REG_VRAM_SIZE);
+ Private->VRAMSize = ASMInU32(Private->IOBase + SVGA_VALUE_PORT);
+
+#if 0
+ // Not used because of buggy emulation(?) which is not fully compatible
+ // with the simple "legacy" VMSVGA II register interface.
+
+ // Enable the device, set initial mode
+ ASMOutU32(Private->IOBase + SVGA_INDEX_PORT, SVGA_REG_WIDTH);
+ ASMOutU32(Private->IOBase + SVGA_VALUE_PORT, 1024);
+ ASMOutU32(Private->IOBase + SVGA_INDEX_PORT, SVGA_REG_HEIGHT);
+ ASMOutU32(Private->IOBase + SVGA_VALUE_PORT, 768);
+ ASMOutU32(Private->IOBase + SVGA_INDEX_PORT, SVGA_REG_BYTES_PER_LINE);
+ ASMOutU32(Private->IOBase + SVGA_VALUE_PORT, 768 * 4);
+ ASMOutU32(Private->IOBase + SVGA_INDEX_PORT, SVGA_REG_BITS_PER_PIXEL);
+ ASMOutU32(Private->IOBase + SVGA_VALUE_PORT, 32);
+ ASMOutU32(Private->IOBase + SVGA_INDEX_PORT, SVGA_REG_CONFIG_DONE);
+ ASMOutU32(Private->IOBase + SVGA_VALUE_PORT, 1);
+
+ ASMOutU32(Private->IOBase + SVGA_INDEX_PORT, SVGA_REG_ENABLE);
+ ASMOutU32(Private->IOBase + SVGA_VALUE_PORT, SVGA_REG_ENABLE_ENABLE);
+#endif
+ } else {
+ // VBoxVGA / VBoxSVGA
+ Private->BarIndexFB = 0;
+ //
+ // Get VRAM size, needed for constructing a correct video mode list
+ //
+ Private->VRAMSize = ASMInU32(VBE_DISPI_IOPORT_DATA);
+ }
+
+
+ //
+ // Construct video mode list
+ //
+ Status = VBoxVgaVideoModeSetup (Private);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ if (FeaturePcdGet (PcdSupportUga)) {
+ //
+ // Start the UGA Draw software stack.
+ //
+ Status = VBoxVgaUgaDrawConstructor (Private);
+ ASSERT_EFI_ERROR (Status);
+
+ Private->UgaDevicePath = ParentDevicePath;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ //&gEfiUgaDrawProtocolGuid,
+ //&Private->UgaDraw,
+ &gEfiDevicePathProtocolGuid,
+ Private->UgaDevicePath,
+ NULL
+ );
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiUgaDrawProtocolGuid,
+ &Private->UgaDraw,
+ NULL
+ );
+
+ } else if (FeaturePcdGet (PcdSupportGop)) {
+ if (Private->GopDevicePath == NULL) {
+ //
+ // If RemainingDevicePath is the End of Device Path Node,
+ // don't create child device and return EFI_SUCCESS
+ //
+ Status = EFI_SUCCESS;
+ } else {
+
+ //
+ // Start the GOP software stack.
+ //
+ Status = VBoxVgaGraphicsOutputConstructor (Private);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Private->Handle,
+ &gEfiGraphicsOutputProtocolGuid,
+ &Private->GraphicsOutput,
+ &gEfiEdidDiscoveredProtocolGuid,
+ &Private->EdidDiscovered,
+ &gEfiEdidActiveProtocolGuid,
+ &Private->EdidActive,
+ NULL
+ );
+ }
+ } else {
+ //
+ // This driver must support eithor GOP or UGA or both.
+ //
+ ASSERT (FALSE);
+ Status = EFI_UNSUPPORTED;
+ }
+
+Error:
+ if (EFI_ERROR (Status)) {
+ if (Private) {
+ if (Private->PciIo) {
+ if (PciAttributesSaved == TRUE) {
+ //
+ // Restore original PCI attributes
+ //
+ Private->PciIo->Attributes (
+ Private->PciIo,
+ EfiPciIoAttributeOperationSet,
+ Private->OriginalPciAttributes,
+ NULL
+ );
+ }
+ //
+ // Close the PCI I/O Protocol
+ //
+ gBS->CloseProtocol (
+ Private->Handle,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Private->Handle
+ );
+ }
+
+ gBS->FreePool (Private);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ VBoxVgaControllerDriverStop
+
+ TODO: This - add argument and description to function comment
+ TODO: Controller - add argument and description to function comment
+ TODO: NumberOfChildren - add argument and description to function comment
+ TODO: ChildHandleBuffer - add argument and description to function comment
+ TODO: EFI_SUCCESS - add return value to function comment
+**/
+EFI_STATUS
+EFIAPI
+VBoxVgaControllerDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_UGA_DRAW_PROTOCOL *UgaDraw;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+
+ EFI_STATUS Status;
+ VBOX_VGA_PRIVATE_DATA *Private;
+
+ if (FeaturePcdGet (PcdSupportUga)) {
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiUgaDrawProtocolGuid,
+ (VOID **) &UgaDraw,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get our private context information
+ //
+ Private = VBOX_VGA_PRIVATE_DATA_FROM_UGA_DRAW_THIS (UgaDraw);
+ VBoxVgaUgaDrawDestructor (Private);
+
+ if (FeaturePcdGet (PcdSupportGop)) {
+ VBoxVgaGraphicsOutputDestructor (Private);
+ //
+ // Remove the UGA and GOP protocol interface from the system
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Private->Handle,
+ &gEfiUgaDrawProtocolGuid,
+ &Private->UgaDraw,
+ &gEfiGraphicsOutputProtocolGuid,
+ &Private->GraphicsOutput,
+ NULL
+ );
+ } else {
+ //
+ // Remove the UGA Draw interface from the system
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Private->Handle,
+ &gEfiUgaDrawProtocolGuid,
+ &Private->UgaDraw,
+ NULL
+ );
+ }
+ } else {
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiGraphicsOutputProtocolGuid,
+ (VOID **) &GraphicsOutput,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get our private context information
+ //
+ Private = VBOX_VGA_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput);
+
+ VBoxVgaGraphicsOutputDestructor (Private);
+ //
+ // Remove the GOP protocol interface from the system
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Private->Handle,
+ &gEfiGraphicsOutputProtocolGuid,
+ &Private->GraphicsOutput,
+ NULL
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Private->ModeData) {
+ FreePool(Private->ModeData);
+ Private->ModeData = NULL;
+ }
+
+ //
+ // Restore original PCI attributes
+ //
+ Private->PciIo->Attributes (
+ Private->PciIo,
+ EfiPciIoAttributeOperationSet,
+ Private->OriginalPciAttributes,
+ NULL
+ );
+
+ //
+ // Close the PCI I/O Protocol
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Free our instance data
+ //
+ gBS->FreePool (Private);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ VBoxVgaUgaDrawDestructor
+
+ TODO: Private - add argument and description to function comment
+ TODO: EFI_SUCCESS - add return value to function comment
+**/
+EFI_STATUS
+VBoxVgaUgaDrawDestructor (
+ VBOX_VGA_PRIVATE_DATA *Private
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ 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 (
+ VBOX_VGA_PRIVATE_DATA *Private,
+ UINTN Index,
+ UINT8 Red,
+ UINT8 Green,
+ UINT8 Blue
+ )
+{
+ ASMOutU8(PALETTE_INDEX_REGISTER, (UINT8) Index);
+ ASMOutU8(PALETTE_DATA_REGISTER, (UINT8) (Red >> 2));
+ ASMOutU8(PALETTE_DATA_REGISTER, (UINT8) (Green >> 2));
+ ASMOutU8(PALETTE_DATA_REGISTER, (UINT8) (Blue >> 2));
+}
+
+/**
+ TODO: Add function description
+
+ @param Private TODO: add argument description
+
+ TODO: add return values
+
+**/
+VOID
+SetDefaultPalette (
+ VBOX_VGA_PRIVATE_DATA *Private
+ )
+{
+#if 1
+ 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++;
+ }
+ }
+ }
+#else
+ {
+ int i;
+ static const UINT8 s_a3bVgaDac[64*3] =
+ {
+ 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x2A,
+ 0x00, 0x2A, 0x00,
+ 0x00, 0x2A, 0x2A,
+ 0x2A, 0x00, 0x00,
+ 0x2A, 0x00, 0x2A,
+ 0x2A, 0x2A, 0x00,
+ 0x2A, 0x2A, 0x2A,
+ 0x00, 0x00, 0x15,
+ 0x00, 0x00, 0x3F,
+ 0x00, 0x2A, 0x15,
+ 0x00, 0x2A, 0x3F,
+ 0x2A, 0x00, 0x15,
+ 0x2A, 0x00, 0x3F,
+ 0x2A, 0x2A, 0x15,
+ 0x2A, 0x2A, 0x3F,
+ 0x00, 0x15, 0x00,
+ 0x00, 0x15, 0x2A,
+ 0x00, 0x3F, 0x00,
+ 0x00, 0x3F, 0x2A,
+ 0x2A, 0x15, 0x00,
+ 0x2A, 0x15, 0x2A,
+ 0x2A, 0x3F, 0x00,
+ 0x2A, 0x3F, 0x2A,
+ 0x00, 0x15, 0x15,
+ 0x00, 0x15, 0x3F,
+ 0x00, 0x3F, 0x15,
+ 0x00, 0x3F, 0x3F,
+ 0x2A, 0x15, 0x15,
+ 0x2A, 0x15, 0x3F,
+ 0x2A, 0x3F, 0x15,
+ 0x2A, 0x3F, 0x3F,
+ 0x15, 0x00, 0x00,
+ 0x15, 0x00, 0x2A,
+ 0x15, 0x2A, 0x00,
+ 0x15, 0x2A, 0x2A,
+ 0x3F, 0x00, 0x00,
+ 0x3F, 0x00, 0x2A,
+ 0x3F, 0x2A, 0x00,
+ 0x3F, 0x2A, 0x2A,
+ 0x15, 0x00, 0x15,
+ 0x15, 0x00, 0x3F,
+ 0x15, 0x2A, 0x15,
+ 0x15, 0x2A, 0x3F,
+ 0x3F, 0x00, 0x15,
+ 0x3F, 0x00, 0x3F,
+ 0x3F, 0x2A, 0x15,
+ 0x3F, 0x2A, 0x3F,
+ 0x15, 0x15, 0x00,
+ 0x15, 0x15, 0x2A,
+ 0x15, 0x3F, 0x00,
+ 0x15, 0x3F, 0x2A,
+ 0x3F, 0x15, 0x00,
+ 0x3F, 0x15, 0x2A,
+ 0x3F, 0x3F, 0x00,
+ 0x3F, 0x3F, 0x2A,
+ 0x15, 0x15, 0x15,
+ 0x15, 0x15, 0x3F,
+ 0x15, 0x3F, 0x15,
+ 0x15, 0x3F, 0x3F,
+ 0x3F, 0x15, 0x15,
+ 0x3F, 0x15, 0x3F,
+ 0x3F, 0x3F, 0x15,
+ 0x3F, 0x3F, 0x3F
+ };
+
+ for (i = 0; i < 64; ++i)
+ {
+ ASMOutU8(PALETTE_INDEX_REGISTER, (UINT8)i);
+ ASMOutU8(PALETTE_DATA_REGISTER, s_a3bVgaDac[i*3 + 0]);
+ ASMOutU8(PALETTE_DATA_REGISTER, s_a3bVgaDac[i*3 + 1]);
+ ASMOutU8(PALETTE_DATA_REGISTER, s_a3bVgaDac[i*3 + 2]);
+ }
+ }
+
+#endif
+}
+
+/**
+ TODO: Add function description
+
+ @param Private TODO: add argument description
+
+ TODO: add return values
+
+**/
+VOID
+ClearScreen (
+ VBOX_VGA_PRIVATE_DATA *Private
+ )
+{
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL blt;
+ blt.Blue = 0;
+ blt.Green = 0;
+ blt.Red = 0;
+ blt.Reserved = 0;
+ Private->PciIo->Mem.Write (
+ Private->PciIo,
+ EfiPciIoWidthFillUint32,
+ Private->BarIndexFB,
+ 0,
+ Private->ModeData[Private->CurrentMode].HorizontalResolution
+ * Private->ModeData[Private->CurrentMode].VerticalResolution,
+ &blt
+ );
+}
+
+/**
+ TODO: Add function description
+
+ @param Private TODO: add argument description
+
+ TODO: add return values
+
+**/
+VOID
+DrawLogo (
+ VBOX_VGA_PRIVATE_DATA *Private,
+ UINTN ScreenWidth,
+ UINTN ScreenHeight
+ )
+{
+ DEBUG((DEBUG_INFO, "UGA is %a GOP is %a\n",
+ FeaturePcdGet(PcdSupportUga) ? "on" : "off",
+ FeaturePcdGet(PcdSupportGop) ? "on" : "off"
+ ));
+}
+
+/**
+ TODO: Add function description
+
+ @param Private TODO: add argument description
+ @param ModeData TODO: add argument description
+
+ TODO: add return values
+
+**/
+VOID
+InitializeGraphicsMode (
+ VBOX_VGA_PRIVATE_DATA *Private,
+ VBOX_VGA_VIDEO_MODES *ModeData
+ )
+{
+ UINT16 DeviceId;
+ EFI_STATUS Status;
+ int i;
+
+ DEBUG((DEBUG_INFO, "%a:%d InitializeGraphicsMode: %dx%d bpp:%d\n", __FILE__, __LINE__, ModeData->Width, ModeData->Height, ModeData->ColorDepth));
+
+ //
+ // Read the PCI ID from the PCI Device (dummy)
+ //
+ Status = Private->PciIo->Pci.Read (
+ Private->PciIo,
+ EfiPciIoWidthUint16,
+ PCI_DEVICE_ID_OFFSET,
+ 1,
+ &DeviceId
+ );
+ ASSERT_EFI_ERROR(Status);
+
+ ASMOutU8(MISC_OUTPUT_REGISTER, 0xc3);
+ ASMOutU16(SEQ_ADDRESS_REGISTER, 0x0204);
+
+ ASMInU8(INPUT_STATUS_1_REGISTER); // reset attribute address/data flip-flop
+ ASMOutU8(ATT_ADDRESS_REGISTER, 0); // blank screen using the attribute address register
+
+ ASMOutU16(CRTC_ADDRESS_REGISTER, 0x0011);
+
+ ASMOutU16(SEQ_ADDRESS_REGISTER, 0x0100);
+ if (ModeData->SeqSettings)
+ BOUTB(ModeData->SeqSettings, 5, SEQ_ADDRESS_REGISTER, SEQ_DATA_REGISTER);
+ else
+ BOUTB(Seq_Default, 5, SEQ_ADDRESS_REGISTER, SEQ_DATA_REGISTER);
+ ASMOutU16(SEQ_ADDRESS_REGISTER, 0x0300);
+
+ BOUTB(GraphicsController, 9, GRAPH_ADDRESS_REGISTER, GRAPH_DATA_REGISTER);
+
+ ASMInU8(INPUT_STATUS_1_REGISTER); // reset attribute address/data flip-flop
+ BOUTB(AttributeController, 21, ATT_ADDRESS_REGISTER, ATT_DATA_REGISTER);
+
+ ASMOutU8(MISC_OUTPUT_REGISTER, ModeData->MiscSetting);
+
+ if (ModeData->ColorDepth <= 8)
+ {
+ ASMOutU8(DAC_PIXEL_MASK_REGISTER, 0xff);
+ SetDefaultPalette(Private);
+ }
+
+ if (!ModeData->CrtcSettings)
+ {
+ // No CRTC settings, use VBE
+ ASMOutU16(VBE_DISPI_IOPORT_INDEX, 0x00); ASMOutU16(VBE_DISPI_IOPORT_DATA, 0xb0c0); // ID
+ ASMOutU16(VBE_DISPI_IOPORT_INDEX, 0x04); ASMOutU16(VBE_DISPI_IOPORT_DATA, 0); // ENABLE
+ ASMOutU16(VBE_DISPI_IOPORT_INDEX, 0x01); ASMOutU16(VBE_DISPI_IOPORT_DATA, (UINT16)ModeData->Width); // XRES
+ ASMOutU16(VBE_DISPI_IOPORT_INDEX, 0x02); ASMOutU16(VBE_DISPI_IOPORT_DATA, (UINT16)ModeData->Height); // YRES
+ ASMOutU16(VBE_DISPI_IOPORT_INDEX, 0x03); ASMOutU16(VBE_DISPI_IOPORT_DATA, (UINT16)ModeData->ColorDepth); // BPP
+ ASMOutU16(VBE_DISPI_IOPORT_INDEX, 0x05); ASMOutU16(VBE_DISPI_IOPORT_DATA, 0); // BANK
+ ASMOutU16(VBE_DISPI_IOPORT_INDEX, 0x06); ASMOutU16(VBE_DISPI_IOPORT_DATA, (UINT16)ModeData->Width); // VIRT_WIDTH
+ ASMOutU16(VBE_DISPI_IOPORT_INDEX, 0x07); ASMOutU16(VBE_DISPI_IOPORT_DATA, (UINT16)ModeData->Height); // VIRT_HEIGHT
+ ASMOutU16(VBE_DISPI_IOPORT_INDEX, 0x08); ASMOutU16(VBE_DISPI_IOPORT_DATA, 0); // X_OFFSET
+ ASMOutU16(VBE_DISPI_IOPORT_INDEX, 0x09); ASMOutU16(VBE_DISPI_IOPORT_DATA, 0); // Y_OFFSET
+ ASMOutU16(VBE_DISPI_IOPORT_INDEX, 0x04); ASMOutU16(VBE_DISPI_IOPORT_DATA, 1); // ENABLE
+ /// @todo enabling VBE is automatically tweaking the CRTC, GC, SC, clears the
+ // screen and at the end unblanks graphics. So make sure that nothing is done
+ // after this which needs blanking. Way too much magic, but that's how it is...
+ }
+ else
+ {
+ BOUTB(ModeData->CrtcSettings, 25, CRTC_ADDRESS_REGISTER, CRTC_DATA_REGISTER);
+ }
+
+ ASMInU8(INPUT_STATUS_1_REGISTER); // reset attribute address/data flip-flop
+ ASMOutU8(ATT_ADDRESS_REGISTER, 0x20); // unblank screen
+
+ ClearScreen(Private);
+}
+
+/** Aka know as AppleGraphInfoProtocolGuid in other sources. */
+#define EFI_UNKNOWN_2_PROTOCOL_GUID \
+ { 0xE316E100, 0x0751, 0x4C49, {0x90, 0x56, 0x48, 0x6C, 0x7E, 0x47, 0x29, 0x03} }
+
+EFI_GUID gEfiAppleFrameBufferInfoGuid = EFI_UNKNOWN_2_PROTOCOL_GUID;
+
+EFI_STATUS EFIAPI
+GetFrameBufferInfo(IN APPLE_FRAMEBUFFERINFO_PROTOCOL *This,
+ OUT UINT32 *BaseAddr,
+ OUT UINT32 *Something,
+ OUT UINT32 *RowBytes,
+ OUT UINT32 *Width,
+ OUT UINT32 *Height,
+ OUT UINT32 *Depth)
+{
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *FrameBufDesc;
+ UINT32 W, H, BPP;
+ VBOX_VGA_PRIVATE_DATA *Private = This->Private;
+ UINTN CurrentModeNumber = Private->CurrentMode;
+ VBOX_VGA_MODE_DATA const *pCurrentMode = &Private->ModeData[CurrentModeNumber];
+
+ W = pCurrentMode->HorizontalResolution;
+ H = pCurrentMode->VerticalResolution;
+ BPP = pCurrentMode->ColorDepth;
+ DEBUG((DEBUG_INFO, "%a:%d GetFrameBufferInfo: %dx%d bpp:%d\n", __FILE__, __LINE__, W, H, BPP));
+
+ Private->PciIo->GetBarAttributes (
+ Private->PciIo,
+ Private->BarIndexFB,
+ NULL,
+ (VOID**) &FrameBufDesc
+ );
+
+
+ /* EFI firmware remaps it here */
+ *BaseAddr = (UINT32)FrameBufDesc->AddrRangeMin;
+ *RowBytes = W * BPP / 8;
+ *Width = W;
+ *Height = H;
+ *Depth = BPP;
+ // what *Something shall be?
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+InitializeVBoxVga (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gVBoxVgaDriverBinding,
+ ImageHandle,
+ &gVBoxVgaComponentName,
+ &gVBoxVgaComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install EFI Driver Supported EFI Version Protocol required for
+ // EFI drivers that are on PCI and other plug in cards.
+ //
+ gVBoxVgaDriverSupportedEfiVersion.FirmwareVersion = PcdGet32 (PcdDriverSupportedEfiVersion);
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiDriverSupportedEfiVersionProtocolGuid,
+ &gVBoxVgaDriverSupportedEfiVersion,
+ &gEfiAppleFrameBufferInfoGuid,
+ &gAppleFrameBufferInfo,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVga.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVga.h
new file mode 100644
index 00000000..25ff1a4e
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVga.h
@@ -0,0 +1,473 @@
+/* $Id: VBoxVga.h $ */
+/** @file
+ * VBoxVga.h
+ */
+
+/*
+ * Copyright (C) 2009-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/*
+ This code is based on:
+
+ Cirrus Logic 5430 Controller Driver
+
+ Copyright (c) 2006 - 2007, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+*/
+
+//
+// VirtualBox VGA Controller Driver
+//
+
+#ifndef _VBOX_VGA_H_
+#define _VBOX_VGA_H_
+
+
+#include <Uefi.h>
+#include <Protocol/UgaDraw.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/DriverSupportedEfiVersion.h>
+#include <Protocol/EdidOverride.h>
+#include <Protocol/EdidDiscovered.h>
+#include <Protocol/EdidActive.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 <IndustryStandard/Pci.h>
+
+#include "VBoxPkg.h"
+#include "DevEFI.h"
+#include "VBox/Graphics/VBoxVideoVBE.h"
+#include "VBox/Graphics/VBoxVideoVBEPrivate.h"
+
+//
+// VirtualBox VGA PCI Configuration Header values
+//
+#define VBOX_VENDOR_ID 0x80ee
+#define VBOX_VGA_DEVICE_ID 0xbeef
+
+
+//
+// VMSVGA II PCI Configuration Header values
+//
+#define VMSVGA_VENDOR_ID 0x15ad
+#define VMSVGA_II_DEVICE_ID 0x0405
+
+// Port offsets relative to BAR 0
+#define SVGA_INDEX_PORT 0
+#define SVGA_VALUE_PORT 1
+
+// SVGA_REG_ENABLE bits
+#define SVGA_REG_ENABLE_DISABLE 0
+#define SVGA_REG_ENABLE_ENABLE 1
+
+// Registers
+#define SVGA_REG_ENABLE 1
+#define SVGA_REG_WIDTH 2
+#define SVGA_REG_HEIGHT 3
+#define SVGA_REG_MAX_WIDTH 4
+#define SVGA_REG_MAX_HEIGHT 5
+#define SVGA_REG_DEPTH 6
+#define SVGA_REG_BITS_PER_PIXEL 7
+#define SVGA_REG_BYTES_PER_LINE 12
+#define SVGA_REG_FB_START 13
+#define SVGA_REG_FB_OFFSET 14
+#define SVGA_REG_VRAM_SIZE 15
+#define SVGA_REG_CONFIG_DONE 20 ///@todo: Why do we need this?
+
+//
+// VirtualBox VGA Graphical Mode Data
+//
+typedef struct {
+ UINT32 ModeNumber;
+ UINT32 HorizontalResolution;
+ UINT32 VerticalResolution;
+ UINT32 ColorDepth;
+ UINT32 RefreshRate;
+} VBOX_VGA_MODE_DATA;
+
+#define GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER 0xffff
+
+//
+// VirtualBox VGA Private Data Structure
+//
+#define VBOX_VGA_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('V', 'B', 'V', 'D')
+
+typedef struct {
+ UINT64 Signature;
+ EFI_HANDLE Handle;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT64 OriginalPciAttributes;
+ EFI_UGA_DRAW_PROTOCOL UgaDraw;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL GraphicsOutput;
+ EFI_EDID_DISCOVERED_PROTOCOL EdidDiscovered;
+ EFI_EDID_ACTIVE_PROTOCOL EdidActive;
+ EFI_DEVICE_PATH_PROTOCOL *GopDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *UgaDevicePath;
+ UINTN CurrentMode;
+ UINTN MaxMode;
+ VBOX_VGA_MODE_DATA *ModeData;
+ BOOLEAN HardwareNeedsStarting;
+ UINT8 BarIndexFB;
+ UINT16 DeviceType;
+ UINT16 IOBase;
+ UINT32 VRAMSize;
+} VBOX_VGA_PRIVATE_DATA;
+
+///
+/// Video Mode structure
+///
+typedef struct {
+ UINT32 Width;
+ UINT32 Height;
+ UINT32 ColorDepth;
+ UINT32 RefreshRate;
+ /// CRTC settings are optional. If NULL then VBE is used
+ UINT8 *CrtcSettings;
+ /// Sequencer settings are optional. If NULL then defaults are used
+ UINT8 *SeqSettings;
+ UINT8 MiscSetting;
+} VBOX_VGA_VIDEO_MODES;
+
+#define VBOX_VGA_PRIVATE_DATA_FROM_UGA_DRAW_THIS(a) \
+ CR(a, VBOX_VGA_PRIVATE_DATA, UgaDraw, VBOX_VGA_PRIVATE_DATA_SIGNATURE)
+
+#define VBOX_VGA_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS(a) \
+ CR(a, VBOX_VGA_PRIVATE_DATA, GraphicsOutput, VBOX_VGA_PRIVATE_DATA_SIGNATURE)
+
+
+//
+// Global Variables
+//
+extern UINT8 AttributeController[];
+extern UINT8 GraphicsController[];
+extern UINT8 Crtc_640_480_256_60[];
+extern UINT8 Seq_640_480_256_60[];
+extern UINT8 Crtc_800_600_256_60[];
+extern UINT8 Seq_800_600_256_60[];
+extern UINT8 Crtc_1024_768_256_60[];
+extern UINT8 Seq_1024_768_256_60[];
+extern VBOX_VGA_VIDEO_MODES VBoxVgaVideoModes[];
+extern const UINT32 VBoxVgaVideoModeCount;
+extern EFI_DRIVER_BINDING_PROTOCOL gVBoxVgaDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gVBoxVgaComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gVBoxVgaComponentName2;
+extern EFI_DRIVER_SUPPORTED_EFI_VERSION_PROTOCOL gVBoxVgaDriverSupportedEfiVersion;
+
+//
+// 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 ATT_DATA_REGISTER 0x3c1
+#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
+
+
+//
+// UGA Draw Hardware abstraction internal worker functions
+//
+EFI_STATUS
+VBoxVgaUgaDrawConstructor (
+ VBOX_VGA_PRIVATE_DATA *Private
+ );
+
+EFI_STATUS
+VBoxVgaUgaDrawDestructor (
+ VBOX_VGA_PRIVATE_DATA *Private
+ );
+
+//
+// Graphics Output Hardware abstraction internal worker functions
+//
+EFI_STATUS
+VBoxVgaGraphicsOutputConstructor (
+ VBOX_VGA_PRIVATE_DATA *Private
+ );
+
+EFI_STATUS
+VBoxVgaGraphicsOutputDestructor (
+ VBOX_VGA_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
+VBoxVgaControllerDriverSupported (
+ 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
+VBoxVgaControllerDriverStart (
+ 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
+VBoxVgaControllerDriverStop (
+ 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
+VBoxVgaComponentNameGetDriverName (
+ 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
+VBoxVgaComponentNameGetControllerName (
+ 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
+InitializeGraphicsMode (
+ VBOX_VGA_PRIVATE_DATA *Private,
+ VBOX_VGA_VIDEO_MODES *ModeData
+ );
+
+VOID
+SetPaletteColor (
+ VBOX_VGA_PRIVATE_DATA *Private,
+ UINTN Index,
+ UINT8 Red,
+ UINT8 Green,
+ UINT8 Blue
+ );
+
+VOID
+SetDefaultPalette (
+ VBOX_VGA_PRIVATE_DATA *Private
+ );
+
+VOID
+DrawLogo (
+ VBOX_VGA_PRIVATE_DATA *Private,
+ UINTN ScreenWidth,
+ UINTN ScreenHeight
+ );
+
+EFI_STATUS
+VBoxVgaVideoModeSetup (
+ VBOX_VGA_PRIVATE_DATA *Private
+ );
+
+UINT32 VBoxVgaGetVmVariable(UINT32 Variable, CHAR8* Buffer, UINT32 Size);
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaDxe.inf b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaDxe.inf
new file mode 100644
index 00000000..79f6dc38
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaDxe.inf
@@ -0,0 +1,133 @@
+# $Id: VBoxVgaDxe.inf $
+## @file
+# VBoxVgaDxe.inf
+#
+
+#
+# Copyright (C) 2010-2022 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+#
+# This code is based on:
+#
+#/** @file
+# Component description file for CirrusLogic5430 module
+#
+# Cirrus Logic 5430 Controller Driver.This driver is a sample implementation
+# of the UGA Draw Protocol for the Cirrus Logic 5430 family of PCI video controllers.
+# This driver is only usable in the EFI pre-boot environment. This sample is
+# intended to show how the UGA Draw Protocol is able to function. The UGA I/O
+# Protocol is not implemented in this sample. A fully compliant EFI UGA driver
+# requires both the UGA Draw and the UGA I/O Protocol. Please refer to Microsoft's
+# documentation on UGA for details on how to write a UGA driver that is able
+# to function both in the EFI pre-boot environment and from the OS runtime.
+# Copyright (c) 2006 - 2009, Intel Corporation
+#
+# All rights reserved. This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VBoxVgaDxe
+ FILE_GUID = b8a784bc-af4d-4d95-bdb1-ba28236a54f4
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ EDK_RELEASE_VERSION = 0x00020000
+ EFI_SPECIFICATION_VERSION = 0x00020000
+
+ ENTRY_POINT = InitializeVBoxVga
+
+ PCI_VENDOR_ID = 0x80EE
+ PCI_DEVICE_ID = 0xBEEF
+ PCI_CLASS_CODE = 0x030000
+ PCI_REVISION = 0x00
+ COMPRESS = TRUE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+# DRIVER_BINDING = VBoxVgaDriverBinding
+# COMPONENT_NAME = VBoxVgaComponentName
+#
+
+[Sources.common]
+ ComponentName.c
+ DriverSupportedEfiVersion.c
+ VBoxVgaUgaDraw.c
+ VBoxVgaGraphicsOutput.c
+ VBoxVga.c
+ VBoxVga.h
+ Edid.c
+ VBoxVgaI2c.h
+ VBoxVgaI2c.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ VBoxPkg/VBoxPkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+ BaseMemoryLib
+ DevicePathLib
+ TimerLib
+
+[Protocols]
+ gEfiDriverSupportedEfiVersionProtocolGuid # PROTOCOL ALWAYS_PRODUCED
+ gEfiUgaDrawProtocolGuid # PROTOCOL BY_START
+ gEfiGraphicsOutputProtocolGuid # PROTOCOL BY_START
+ gEfiEdidDiscoveredProtocolGuid # PROTOCOL BY_START
+ gEfiEdidActiveProtocolGuid # PROTOCOL BY_START
+ gEfiDevicePathProtocolGuid # PROTOCOL BY_START
+ gEfiPciIoProtocolGuid # PROTOCOL TO_START
+ gEfiEdidOverrideProtocolGuid # PROTOCOL TO_START
+
+
+[FeaturePcd.common]
+ gVBoxVgaPkgTokenSpaceGuid.PcdSupportGop
+ gVBoxVgaPkgTokenSpaceGuid.PcdSupportUga
+
+[Pcd]
+ gVBoxVgaPkgTokenSpaceGuid.PcdDriverSupportedEfiVersion
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution ## PRODUCES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution ## PRODUCES
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaGraphicsOutput.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaGraphicsOutput.c
new file mode 100644
index 00000000..f5706441
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaGraphicsOutput.c
@@ -0,0 +1,544 @@
+/* $Id: VBoxVgaGraphicsOutput.c $ */
+/** @file
+ * VBoxVgaGraphicsOutput.c
+ */
+
+/*
+ * Copyright (C) 2009-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/*
+ This code is based on:
+
+Copyright (c) 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ UefiVBoxVgaGraphicsOutput.c
+
+Abstract:
+
+ This file produces the graphics abstraction of Graphics Output Protocol. It is called by
+ VBoxVga.c file which deals with the EFI 1.1 driver model.
+ This file just does graphics.
+
+*/
+#include "VBoxVga.h"
+#include <IndustryStandard/Acpi.h>
+
+
+STATIC
+VOID
+VBoxVgaCompleteModeInfo (
+ OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info
+ )
+{
+ Info->Version = 0;
+ Info->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
+ Info->PixelsPerScanLine = Info->HorizontalResolution;
+}
+
+
+STATIC
+EFI_STATUS
+VBoxVgaCompleteModeData (
+ IN VBOX_VGA_PRIVATE_DATA *Private,
+ OUT EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *Mode
+ )
+{
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *FrameBufDesc;
+
+ Info = Mode->Info;
+ VBoxVgaCompleteModeInfo (Info);
+
+ Private->PciIo->GetBarAttributes (
+ Private->PciIo,
+ Private->BarIndexFB,
+ NULL,
+ (VOID**) &FrameBufDesc
+ );
+
+ DEBUG((DEBUG_INFO, "%a:%d FrameBufferBase:%x\n", __FILE__, __LINE__, FrameBufDesc->AddrRangeMin));
+ Mode->FrameBufferBase = FrameBufDesc->AddrRangeMin;
+ Mode->FrameBufferSize = Info->PixelsPerScanLine * Info->VerticalResolution
+ * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL); /* 32bpp only! */
+
+ return EFI_SUCCESS;
+}
+
+
+//
+// Graphics Output Protocol Member Functions
+//
+EFI_STATUS
+EFIAPI
+VBoxVgaGraphicsOutputQueryMode (
+ 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.
+
+--*/
+{
+ VBOX_VGA_PRIVATE_DATA *Private;
+
+ Private = VBOX_VGA_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This);
+
+ if (Private->HardwareNeedsStarting) {
+ return EFI_NOT_STARTED;
+ }
+
+ 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);
+
+ (*Info)->HorizontalResolution = Private->ModeData[ModeNumber].HorizontalResolution;
+ (*Info)->VerticalResolution = Private->ModeData[ModeNumber].VerticalResolution;
+ VBoxVgaCompleteModeInfo (*Info);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+VBoxVgaGraphicsOutputSetMode (
+ 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.
+
+--*/
+{
+ VBOX_VGA_PRIVATE_DATA *Private;
+ VBOX_VGA_MODE_DATA *ModeData;
+
+ Private = VBOX_VGA_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This);
+
+ DEBUG((DEBUG_INFO, "%a:%d mode:%d\n", __FILE__, __LINE__, ModeNumber));
+ if (ModeNumber >= This->Mode->MaxMode) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ModeData = &Private->ModeData[ModeNumber];
+
+ InitializeGraphicsMode (Private, &VBoxVgaVideoModes[ModeData->ModeNumber]);
+
+ 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);
+
+ VBoxVgaCompleteModeData (Private, This->Mode);
+
+ Private->HardwareNeedsStarting = FALSE;
+ /* update current mode */
+ Private->CurrentMode = ModeNumber;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+VBoxVgaGraphicsOutputBlt (
+ 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
+
+--*/
+{
+ VBOX_VGA_PRIVATE_DATA *Private;
+ EFI_TPL OriginalTPL;
+ UINTN DstY;
+ UINTN SrcY;
+ UINT32 CurrentMode;
+ UINTN ScreenWidth;
+ UINTN ScreenHeight;
+ EFI_STATUS Status;
+
+ Private = VBOX_VGA_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (This);
+ CurrentMode = This->Mode->Mode;
+ ScreenWidth = Private->ModeData[CurrentMode].HorizontalResolution;
+ ScreenHeight = Private->ModeData[CurrentMode].VerticalResolution;
+
+ if ((BltOperation < 0) || (BltOperation >= EfiGraphicsOutputBltOperationMax)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Width == 0 || Height == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If Delta is zero, then the entire BltBuffer is being used, so Delta
+ // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
+ // the number of bytes in each row can be computed.
+ //
+ if (Delta == 0) {
+ Delta = Width * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
+ }
+ // code below assumes a Delta value in pixels, not bytes
+ Delta /= sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
+
+ //
+ // Make sure the SourceX, SourceY, DestinationX, DestinationY, Width, and Height parameters
+ // are valid for the operation and the current screen geometry.
+ //
+ if (BltOperation == EfiBltVideoToBltBuffer || BltOperation == EfiBltVideoToVideo) {
+ if (SourceY + Height > ScreenHeight) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (SourceX + Width > ScreenWidth) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ if (BltOperation == EfiBltBufferToVideo || BltOperation == EfiBltVideoToVideo || BltOperation == EfiBltVideoFill) {
+ if (DestinationY + Height > ScreenHeight) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DestinationX + Width > ScreenWidth) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // 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:
+ //
+ // Video to BltBuffer: Source is Video, destination is BltBuffer
+ //
+ for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY) && BltBuffer; SrcY++, DstY++) {
+ /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthUint32) and format matches EFI_GRAPHICS_OUTPUT_BLT_PIXEL
+ Status = Private->PciIo->Mem.Read (
+ Private->PciIo,
+ EfiPciIoWidthUint32,
+ Private->BarIndexFB,
+ ((SrcY * ScreenWidth) + SourceX) * 4,
+ Width,
+ BltBuffer + (DstY * Delta) + DestinationX
+ );
+ ASSERT_EFI_ERROR((Status));
+ }
+ break;
+
+ case EfiBltBufferToVideo:
+ //
+ // BltBuffer to Video: Source is BltBuffer, destination is Video
+ //
+ for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
+ /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthUint32) and format matches EFI_GRAPHICS_OUTPUT_BLT_PIXEL
+ Status = Private->PciIo->Mem.Write (
+ Private->PciIo,
+ EfiPciIoWidthUint32,
+ Private->BarIndexFB,
+ ((DstY * ScreenWidth) + DestinationX) * 4,
+ Width,
+ BltBuffer + (SrcY * Delta) + SourceX
+ );
+ ASSERT_EFI_ERROR((Status));
+ }
+ break;
+
+ case EfiBltVideoToVideo:
+ //
+ // Video to Video: Source is Video, destination is Video
+ //
+ if (DestinationY <= SourceY) {
+ // forward copy
+ for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
+ /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthUint32) and format matches EFI_GRAPHICS_OUTPUT_BLT_PIXEL
+ Status = Private->PciIo->CopyMem (
+ Private->PciIo,
+ EfiPciIoWidthUint32,
+ Private->BarIndexFB,
+ ((DstY * ScreenWidth) + DestinationX) * 4,
+ Private->BarIndexFB,
+ ((SrcY * ScreenWidth) + SourceX) * 4,
+ Width
+ );
+ ASSERT_EFI_ERROR((Status));
+ }
+ } else {
+ // reverse copy
+ for (SrcY = SourceY + Height - 1, DstY = DestinationY + Height - 1; SrcY >= SourceY && SrcY <= SourceY + Height - 1; SrcY--, DstY--) {
+ /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthUint32) and format matches EFI_GRAPHICS_OUTPUT_BLT_PIXEL
+ Status = Private->PciIo->CopyMem (
+ Private->PciIo,
+ EfiPciIoWidthUint32,
+ Private->BarIndexFB,
+ ((DstY * ScreenWidth) + DestinationX) * 4,
+ Private->BarIndexFB,
+ ((SrcY * ScreenWidth) + SourceX) * 4,
+ Width
+ );
+ ASSERT_EFI_ERROR((Status));
+ }
+ }
+ break;
+
+ case EfiBltVideoFill:
+ //
+ // Video Fill: Source is BltBuffer, destination is Video
+ //
+ if (DestinationX == 0 && Width == ScreenWidth) {
+ /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthFillUint32) and format matches EFI_GRAPHICS_OUTPUT_BLT_PIXEL
+ Status = Private->PciIo->Mem.Write (
+ Private->PciIo,
+ EfiPciIoWidthFillUint32,
+ Private->BarIndexFB,
+ DestinationY * ScreenWidth * 4,
+ (Width * Height),
+ BltBuffer
+ );
+ ASSERT_EFI_ERROR((Status));
+ } else {
+ for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
+ /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthFillUint32) and format matches EFI_GRAPHICS_OUTPUT_BLT_PIXEL
+ Status = Private->PciIo->Mem.Write (
+ Private->PciIo,
+ EfiPciIoWidthFillUint32,
+ Private->BarIndexFB,
+ ((DstY * ScreenWidth) + DestinationX) * 4,
+ Width,
+ BltBuffer
+ );
+ ASSERT_EFI_ERROR((Status));
+ }
+ }
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+
+ gBS->RestoreTPL (OriginalTPL);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+VBoxVgaGraphicsOutputConstructor (
+ VBOX_VGA_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ UINT32 Index;
+ UINT32 HorizontalResolution = 1024;
+ UINT32 VerticalResolution = 768;
+ UINT32 ColorDepth = 32;
+
+ DEBUG((DEBUG_INFO, "%a:%d construct\n", __FILE__, __LINE__));
+
+ GraphicsOutput = &Private->GraphicsOutput;
+ GraphicsOutput->QueryMode = VBoxVgaGraphicsOutputQueryMode;
+ GraphicsOutput->SetMode = VBoxVgaGraphicsOutputSetMode;
+ GraphicsOutput->Blt = VBoxVgaGraphicsOutputBlt;
+
+ //
+ // 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)) {
+ return Status;
+ }
+ Private->GraphicsOutput.Mode->MaxMode = (UINT32) Private->MaxMode;
+ Private->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;
+ Private->HardwareNeedsStarting = TRUE;
+
+ //
+ // Initialize the hardware
+ //
+ VBoxVgaGetVmVariable(EFI_INFO_INDEX_HORIZONTAL_RESOLUTION, (CHAR8 *)&HorizontalResolution,
+ sizeof(HorizontalResolution));
+ VBoxVgaGetVmVariable(EFI_INFO_INDEX_VERTICAL_RESOLUTION, (CHAR8 *)&VerticalResolution,
+ sizeof(VerticalResolution));
+ for (Index = 0; Index < Private->MaxMode; Index++)
+ {
+ if ( HorizontalResolution == Private->ModeData[Index].HorizontalResolution
+ && VerticalResolution == Private->ModeData[Index].VerticalResolution
+ && ColorDepth == Private->ModeData[Index].ColorDepth)
+ break;
+ }
+ // not found? try mode number
+ if (Index >= Private->MaxMode)
+ {
+ VBoxVgaGetVmVariable(EFI_INFO_INDEX_GRAPHICS_MODE, (CHAR8 *)&Index, sizeof(Index));
+ // try with mode 2 (usually 1024x768) as a fallback
+ if (Index >= Private->MaxMode)
+ Index = 2;
+ // try with mode 0 (usually 640x480) as a fallback
+ if (Index >= Private->MaxMode)
+ Index = 0;
+ }
+
+ // skip mode setting completely if there is no valid mode
+ if (Index >= Private->MaxMode)
+ return EFI_UNSUPPORTED;
+
+ GraphicsOutput->SetMode (GraphicsOutput, Index);
+
+ DrawLogo (
+ Private,
+ Private->ModeData[Private->GraphicsOutput.Mode->Mode].HorizontalResolution,
+ Private->ModeData[Private->GraphicsOutput.Mode->Mode].VerticalResolution
+ );
+
+ PcdSet32S(PcdVideoHorizontalResolution, Private->ModeData[Private->GraphicsOutput.Mode->Mode].HorizontalResolution);
+ PcdSet32S(PcdVideoVerticalResolution, Private->ModeData[Private->GraphicsOutput.Mode->Mode].VerticalResolution);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+VBoxVgaGraphicsOutputDestructor (
+ VBOX_VGA_PRIVATE_DATA *Private
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Returns:
+
+ None
+
+--*/
+{
+ 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/VBoxPkg/VBoxVgaDxe/VBoxVgaI2c.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaI2c.c
new file mode 100644
index 00000000..ba1fceb9
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaI2c.c
@@ -0,0 +1,469 @@
+/* $Id: VBoxVgaI2c.c $ */
+/** @file
+ * VBoxVgaI2c.c
+ */
+
+/*
+ * Copyright (C) 2009-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/*
+ This code is based on:
+
+ I2C Bus implementation upon CirrusLogic.
+
+ Copyright (c) 2008 - 2009, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+*/
+
+#include "VBoxVga.h"
+#include "VBoxVgaI2c.h"
+
+#define SEQ_ADDRESS_REGISTER 0x3c4
+#define SEQ_DATA_REGISTER 0x3c5
+
+#define I2C_CONTROL 0x08
+#define I2CDAT_IN 7
+#define I2CCLK_IN 2
+#define I2CDAT_OUT 1
+#define I2CCLK_OUT 0
+
+#define I2C_BUS_SPEED 100 //100kbps
+
+/**
+ PCI I/O byte write function.
+
+ @param PciIo The pointer to PCI_IO_PROTOCOL.
+ @param Address The bit map of I2C Data or I2C Clock pins.
+ @param Data The date to write.
+
+**/
+VOID
+I2cOutb (
+ EFI_PCI_IO_PROTOCOL *PciIo,
+ UINTN Address,
+ UINT8 Data
+ )
+{
+ PciIo->Io.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ Address,
+ 1,
+ &Data
+ );
+}
+/**
+ PCI I/O byte read function.
+
+ @param PciIo The pointer to PCI_IO_PROTOCOL.
+ @param Address The bit map of I2C Data or I2C Clock pins.
+
+ return byte value read from PCI I/O space.
+
+**/
+UINT8
+I2cInb (
+ EFI_PCI_IO_PROTOCOL *PciIo,
+ UINTN Address
+ )
+{
+ UINT8 Data;
+
+ PciIo->Io.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ Address,
+ 1,
+ &Data
+ );
+ return Data;
+}
+
+/**
+ Read status of I2C Data and I2C Clock Pins.
+
+ @param PciIo The pointer to PCI_IO_PROTOCOL.
+ @param Blt The bit map of I2C Data or I2C Clock pins.
+
+ @retval 0 Low on I2C Data or I2C Clock Pin.
+ @retval 1 High on I2C Data or I2C Clock Pin.
+
+**/
+UINT8
+I2cPinRead (
+ EFI_PCI_IO_PROTOCOL *PciIo,
+ UINT8 Bit
+ )
+{
+ I2cOutb (PciIo, SEQ_ADDRESS_REGISTER, I2C_CONTROL);
+ return (UINT8) ((I2cInb (PciIo, SEQ_DATA_REGISTER) >> Bit ) & 0xfe);
+}
+
+
+/**
+ Set/Clear I2C Data and I2C Clock Pins.
+
+ @param PciIo The pointer to PCI_IO_PROTOCOL.
+ @param Blt The bit map to controller I2C Data or I2C Clock pins.
+ @param Value 1 or 0 stands for Set or Clear I2C Data and I2C Clock Pins.
+
+**/
+VOID
+I2cPinWrite (
+ EFI_PCI_IO_PROTOCOL *PciIo,
+ UINT8 Bit,
+ UINT8 Value
+ )
+{
+ UINT8 Byte;
+ I2cOutb (PciIo, SEQ_ADDRESS_REGISTER, I2C_CONTROL);
+ Byte = (UINT8) (I2cInb (PciIo, SEQ_DATA_REGISTER) & (UINT8) ~(1 << Bit)) ;
+ Byte = (UINT8) (Byte | ((Value & 0x01) << Bit));
+ I2cOutb (PciIo, SEQ_DATA_REGISTER, (UINT8) (Byte | 0x40));
+ return;
+}
+
+/**
+ Read/write delay according to I2C Bus Speed.
+
+**/
+VOID
+I2cDelay (
+ VOID
+ )
+{
+ MicroSecondDelay (1000 / I2C_BUS_SPEED);
+}
+
+/**
+ Write a 8-bit data onto I2C Data Pin.
+
+ @param PciIo The pointer to PCI_IO_PROTOCOL.
+ @param Data The byte data to write.
+
+**/
+VOID
+I2cSendByte (
+ EFI_PCI_IO_PROTOCOL *PciIo,
+ UINT8 Data
+ )
+{
+ UINTN Index;
+ //
+ // Send byte data onto I2C Bus
+ //
+ for (Index = 0; Index < 8; Index --) {
+ I2cPinWrite (PciIo, I2CDAT_OUT, (UINT8) (Data >> (7 - Index)));
+ I2cPinWrite (PciIo, I2CCLK_OUT, 1);
+ I2cDelay ();
+ I2cPinWrite (PciIo, I2CCLK_OUT, 0);
+ }
+}
+
+/**
+ Read a 8-bit data from I2C Data Pin.
+
+ @param PciIo The pointer to PCI_IO_PROTOCOL.
+
+ Return the byte data read from I2C Data Pin.
+**/
+UINT8
+I2cReceiveByte (
+ EFI_PCI_IO_PROTOCOL *PciIo
+ )
+{
+ UINT8 Data;
+ UINTN Index;
+
+ Data = 0;
+ //
+ // Read byte data from I2C Bus
+ //
+ for (Index = 0; Index < 8; Index --) {
+ I2cPinWrite (PciIo, I2CCLK_OUT, 1);
+ I2cDelay ();
+ Data = (UINT8) (Data << 1);
+ Data = (UINT8) (Data | I2cPinRead (PciIo, I2CDAT_IN));
+ I2cPinWrite (PciIo, I2CCLK_OUT, 0);
+ }
+
+ return Data;
+}
+
+/**
+ Receive an ACK signal from I2C Bus.
+
+ @param PciIo The pointer to PCI_IO_PROTOCOL.
+
+**/
+BOOLEAN
+I2cWaitAck (
+ EFI_PCI_IO_PROTOCOL *PciIo
+ )
+{
+ //
+ // Wait for ACK signal
+ //
+ I2cPinWrite (PciIo, I2CDAT_OUT, 1);
+ I2cPinWrite (PciIo, I2CCLK_OUT, 1);
+ I2cDelay ();
+ if (I2cPinRead (PciIo, I2CDAT_IN) == 0) {
+ I2cPinWrite (PciIo, I2CDAT_OUT, 1);
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Send an ACK signal onto I2C Bus.
+
+ @param PciIo The pointer to PCI_IO_PROTOCOL.
+
+**/
+VOID
+I2cSendAck (
+ EFI_PCI_IO_PROTOCOL *PciIo
+ )
+{
+ I2cPinWrite (PciIo, I2CCLK_OUT, 1);
+ I2cPinWrite (PciIo, I2CDAT_OUT, 1);
+ I2cPinWrite (PciIo, I2CDAT_OUT, 0);
+ I2cPinWrite (PciIo, I2CCLK_OUT, 0);
+}
+
+/**
+ Start a I2C transfer on I2C Bus.
+
+ @param PciIo The pointer to PCI_IO_PROTOCOL.
+
+**/
+VOID
+I2cStart (
+ EFI_PCI_IO_PROTOCOL *PciIo
+ )
+{
+ //
+ // Init CLK and DAT pins
+ //
+ I2cPinWrite (PciIo, I2CCLK_OUT, 1);
+ I2cPinWrite (PciIo, I2CDAT_OUT, 1);
+ //
+ // Start a I2C transfer, set SDA low from high, when SCL is high
+ //
+ I2cPinWrite (PciIo, I2CDAT_OUT, 0);
+ I2cPinWrite (PciIo, I2CCLK_OUT, 0);
+}
+
+/**
+ Stop a I2C transfer on I2C Bus.
+
+ @param PciIo The pointer to PCI_IO_PROTOCOL.
+
+**/
+VOID
+I2cStop (
+ EFI_PCI_IO_PROTOCOL *PciIo
+ )
+{
+ //
+ // Stop a I2C transfer, set SDA high from low, when SCL is high
+ //
+ I2cPinWrite (PciIo, I2CDAT_OUT, 0);
+ I2cPinWrite (PciIo, I2CCLK_OUT, 1);
+ I2cPinWrite (PciIo, I2CDAT_OUT, 1);
+}
+
+/**
+ Read one byte data on I2C Bus.
+
+ Read one byte data from the slave device connected to I2C Bus.
+ If Data is NULL, then ASSERT().
+
+ @param PciIo The pointer to PCI_IO_PROTOCOL.
+ @param DeviceAddress Slave device's address.
+ @param RegisterAddress The register address on slave device.
+ @param Data The pointer to returned data if EFI_SUCCESS returned.
+
+ @retval EFI_DEVICE_ERROR
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+I2cReadByte (
+ EFI_PCI_IO_PROTOCOL *PciIo,
+ UINT8 DeviceAddress,
+ UINT8 RegisterAddress,
+ UINT8 *Data
+ )
+{
+ ASSERT (Data != NULL);
+
+ //
+ // Start I2C transfer
+ //
+ I2cStart (PciIo);
+
+ //
+ // Send slave address with enabling write flag
+ //
+ I2cSendByte (PciIo, (UINT8) (DeviceAddress & 0xfe));
+
+ //
+ // Wait for ACK signal
+ //
+ if (I2cWaitAck (PciIo) == FALSE) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Send register address
+ //
+ I2cSendByte (PciIo, RegisterAddress);
+
+ //
+ // Wait for ACK signal
+ //
+ if (I2cWaitAck (PciIo) == FALSE) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Send slave address with enabling read flag
+ //
+ I2cSendByte (PciIo, (UINT8) (DeviceAddress | 0x01));
+
+ //
+ // Wait for ACK signal
+ //
+ if (I2cWaitAck (PciIo) == FALSE) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Read byte data from I2C Bus
+ //
+ *Data = I2cReceiveByte (PciIo);
+
+ //
+ // Send ACK signal onto I2C Bus
+ //
+ I2cSendAck (PciIo);
+
+ //
+ // Stop a I2C transfer
+ //
+ I2cStop (PciIo);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Write one byte data onto I2C Bus.
+
+ Write one byte data to the slave device connected to I2C Bus.
+ If Data is NULL, then ASSERT().
+
+ @param PciIo The pointer to PCI_IO_PROTOCOL.
+ @param DeviceAddress Slave device's address.
+ @param RegisterAddress The register address on slave device.
+ @param Data The pointer to write data.
+
+ @retval EFI_DEVICE_ERROR
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+I2cWriteByte (
+ EFI_PCI_IO_PROTOCOL *PciIo,
+ UINT8 DeviceAddress,
+ UINT8 RegisterAddress,
+ UINT8 *Data
+ )
+{
+ ASSERT (Data != NULL);
+
+ I2cStart (PciIo);
+ //
+ // Send slave address with enabling write flag
+ //
+ I2cSendByte (PciIo, (UINT8) (DeviceAddress & 0xfe));
+
+ //
+ // Wait for ACK signal
+ //
+ if (I2cWaitAck (PciIo) == FALSE) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Send register address
+ //
+ I2cSendByte (PciIo, RegisterAddress);
+
+ //
+ // Wait for ACK signal
+ //
+ if (I2cWaitAck (PciIo) == FALSE) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Send byte data onto I2C Bus
+ //
+ I2cSendByte (PciIo, *Data);
+
+ //
+ // Wait for ACK signal
+ //
+ if (I2cWaitAck (PciIo) == FALSE) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Stop a I2C transfer
+ //
+ I2cStop (PciIo);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaI2c.h b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaI2c.h
new file mode 100644
index 00000000..c88c0587
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaI2c.h
@@ -0,0 +1,106 @@
+/* $Id: VBoxVgaI2c.h $ */
+/** @file
+ * VBoxVgaI2c.h
+ */
+
+/*
+ * Copyright (C) 2009-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/*
+ This code is based on:
+
+ I2c Bus byte read/write functions.
+
+ Copyright (c) 2008 - 2009, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+*/
+
+#ifndef _CIRRUS_LOGIC_I2C_H_
+#define _CIRRUS_LOGIC_I2C_H_
+
+#include <Protocol/PciIo.h>
+
+/**
+ Read one byte data on I2C Bus.
+
+ Read one byte data from the slave device connected to I2C Bus.
+ If Data is NULL, then ASSERT().
+
+ @param PciIo The pointer to PCI_IO_PROTOCOL.
+ @param DeviceAddress Slave device's address.
+ @param RegisterAddress The register address on slave device.
+ @param Data The pointer to returned data if EFI_SUCCESS returned.
+
+ @retval EFI_DEVICE_ERROR
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+I2cReadByte (
+ EFI_PCI_IO_PROTOCOL *PciIo,
+ UINT8 DeviceAddress,
+ UINT8 RegisterAddress,
+ UINT8 *Data
+ );
+
+/**
+ Write one byte data onto I2C Bus.
+
+ Write one byte data to the slave device connected to I2C Bus.
+ If Data is NULL, then ASSERT().
+
+ @param PciIo The pointer to PCI_IO_PROTOCOL.
+ @param DeviceAddress Slave device's address.
+ @param RegisterAddress The register address on slave device.
+ @param Data The pointer to write data.
+
+ @retval EFI_DEVICE_ERROR
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+I2cWriteByte (
+ EFI_PCI_IO_PROTOCOL *PciIo,
+ UINT8 DeviceAddress,
+ UINT8 RegisterAddress,
+ UINT8 *Data
+ );
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaUgaDraw.c b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaUgaDraw.c
new file mode 100644
index 00000000..79b38073
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVgaDxe/VBoxVgaUgaDraw.c
@@ -0,0 +1,417 @@
+/* $Id: VBoxVgaUgaDraw.c $ */
+/** @file
+ * VBoxVgaUgaDraw.c
+ */
+
+/*
+ * Copyright (C) 2009-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/*
+ This code is based on:
+
+ This file produces the graphics abstraction of UGA Draw. It is called by
+ VBoxVga.c file which deals with the EFI 1.1 driver model.
+ This file just does graphics.
+
+ Copyright (c) 2006, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+*/
+
+#include "VBoxVga.h"
+
+//
+// UGA Draw Protocol Member Functions
+//
+EFI_STATUS
+EFIAPI
+VBoxVgaUgaDrawGetMode (
+ IN EFI_UGA_DRAW_PROTOCOL *This,
+ OUT UINT32 *HorizontalResolution,
+ OUT UINT32 *VerticalResolution,
+ OUT UINT32 *ColorDepth,
+ OUT UINT32 *RefreshRate
+ )
+{
+ VBOX_VGA_PRIVATE_DATA *Private;
+
+ Private = VBOX_VGA_PRIVATE_DATA_FROM_UGA_DRAW_THIS (This);
+
+ if (Private->HardwareNeedsStarting) {
+ return EFI_NOT_STARTED;
+ }
+
+ if ((HorizontalResolution == NULL) ||
+ (VerticalResolution == NULL) ||
+ (ColorDepth == NULL) ||
+ (RefreshRate == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *HorizontalResolution = Private->ModeData[Private->CurrentMode].HorizontalResolution;
+ *VerticalResolution = Private->ModeData[Private->CurrentMode].VerticalResolution;
+ *ColorDepth = Private->ModeData[Private->CurrentMode].ColorDepth;
+ *RefreshRate = Private->ModeData[Private->CurrentMode].RefreshRate;
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+VBoxVgaUgaDrawSetMode (
+ IN EFI_UGA_DRAW_PROTOCOL *This,
+ IN UINT32 HorizontalResolution,
+ IN UINT32 VerticalResolution,
+ IN UINT32 ColorDepth,
+ IN UINT32 RefreshRate
+ )
+{
+ VBOX_VGA_PRIVATE_DATA *Private;
+ UINTN Index;
+
+ DEBUG((DEBUG_INFO, "%a:%d VIDEO: %dx%d %d bpp\n", __FILE__, __LINE__, HorizontalResolution, VerticalResolution, ColorDepth));
+ Private = VBOX_VGA_PRIVATE_DATA_FROM_UGA_DRAW_THIS (This);
+
+ for (Index = 0; Index < Private->MaxMode; Index++) {
+
+ if (HorizontalResolution != Private->ModeData[Index].HorizontalResolution) {
+ continue;
+ }
+
+ if (VerticalResolution != Private->ModeData[Index].VerticalResolution) {
+ continue;
+ }
+
+ if (ColorDepth != Private->ModeData[Index].ColorDepth) {
+ continue;
+ }
+
+#if 0
+ if (RefreshRate != Private->ModeData[Index].RefreshRate) {
+ continue;
+ }
+#endif
+
+ InitializeGraphicsMode (Private, &VBoxVgaVideoModes[Private->ModeData[Index].ModeNumber]);
+
+ Private->CurrentMode = Index;
+
+ Private->HardwareNeedsStarting = FALSE;
+
+ /* update current mode */
+ Private->CurrentMode = Index;
+ return EFI_SUCCESS;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+EFI_STATUS
+EFIAPI
+VBoxVgaUgaDrawBlt (
+ IN EFI_UGA_DRAW_PROTOCOL *This,
+ IN EFI_UGA_PIXEL *BltBuffer, OPTIONAL
+ IN EFI_UGA_BLT_OPERATION BltOperation,
+ IN UINTN SourceX,
+ IN UINTN SourceY,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height,
+ IN UINTN Delta
+ )
+{
+ VBOX_VGA_PRIVATE_DATA *Private;
+ EFI_TPL OriginalTPL;
+ UINTN DstY;
+ UINTN SrcY;
+ UINTN ScreenWidth;
+ UINTN ScreenHeight;
+ EFI_STATUS Status;
+
+ Private = VBOX_VGA_PRIVATE_DATA_FROM_UGA_DRAW_THIS (This);
+ ScreenWidth = Private->ModeData[Private->CurrentMode].HorizontalResolution;
+ ScreenHeight = Private->ModeData[Private->CurrentMode].VerticalResolution;
+
+ if ((BltOperation < 0) || (BltOperation >= EfiUgaBltMax)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Width == 0 || Height == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If Delta is zero, then the entire BltBuffer is being used, so Delta
+ // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
+ // the number of bytes in each row can be computed.
+ //
+ if (Delta == 0) {
+ Delta = Width * sizeof (EFI_UGA_PIXEL);
+ }
+ // code below assumes a Delta value in pixels, not bytes
+ Delta /= sizeof (EFI_UGA_PIXEL);
+
+ //
+ // Make sure the SourceX, SourceY, DestinationX, DestinationY, Width, and Height parameters
+ // are valid for the operation and the current screen geometry.
+ //
+ if (BltOperation == EfiUgaVideoToBltBuffer || BltOperation == EfiUgaVideoToVideo) {
+ if (SourceY + Height > ScreenHeight) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (SourceX + Width > ScreenWidth) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ if (BltOperation == EfiUgaBltBufferToVideo || BltOperation == EfiUgaVideoToVideo || BltOperation == EfiUgaVideoFill) {
+ if (DestinationY + Height > ScreenHeight) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DestinationX + Width > ScreenWidth) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // 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 EfiUgaVideoToBltBuffer:
+ //
+ // Video to BltBuffer: Source is Video, destination is BltBuffer
+ //
+ for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) {
+ /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthUint32) and format matches EFI_UGA_PIXEL
+ Status = Private->PciIo->Mem.Read (
+ Private->PciIo,
+ EfiPciIoWidthUint32,
+ Private->BarIndexFB,
+ ((SrcY * ScreenWidth) + SourceX) * 4,
+ Width,
+ BltBuffer + (DstY * Delta) + DestinationX
+ );
+ ASSERT_EFI_ERROR((Status));
+ }
+ break;
+
+ case EfiUgaBltBufferToVideo:
+ //
+ // BltBuffer to Video: Source is BltBuffer, destination is Video
+ //
+ for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
+ /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthUint32) and format matches EFI_UGA_PIXEL
+ Status = Private->PciIo->Mem.Write (
+ Private->PciIo,
+ EfiPciIoWidthUint32,
+ Private->BarIndexFB,
+ ((DstY * ScreenWidth) + DestinationX) * 4,
+ Width,
+ BltBuffer + (SrcY * Delta) + SourceX
+ );
+ ASSERT_EFI_ERROR((Status));
+ }
+ break;
+
+ case EfiUgaVideoToVideo:
+ //
+ // Video to Video: Source is Video, destination is Video
+ //
+ if (DestinationY <= SourceY) {
+ // forward copy
+ for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
+ /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthUint32) and format matches EFI_UGA_PIXEL
+ Status = Private->PciIo->CopyMem (
+ Private->PciIo,
+ EfiPciIoWidthUint32,
+ Private->BarIndexFB,
+ ((DstY * ScreenWidth) + DestinationX) * 4,
+ Private->BarIndexFB,
+ ((SrcY * ScreenWidth) + SourceX) * 4,
+ Width
+ );
+ ASSERT_EFI_ERROR((Status));
+ }
+ } else {
+ // reverse copy
+ for (SrcY = SourceY + Height - 1, DstY = DestinationY + Height - 1; SrcY >= SourceY && SrcY <= SourceY + Height - 1; SrcY--, DstY--) {
+ /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthUint32) and format matches EFI_UGA_PIXEL
+ Status = Private->PciIo->CopyMem (
+ Private->PciIo,
+ EfiPciIoWidthUint32,
+ Private->BarIndexFB,
+ ((DstY * ScreenWidth) + DestinationX) * 4,
+ Private->BarIndexFB,
+ ((SrcY * ScreenWidth) + SourceX) * 4,
+ Width
+ );
+ ASSERT_EFI_ERROR((Status));
+ }
+ }
+ break;
+
+ case EfiUgaVideoFill:
+ //
+ // Video Fill: Source is BltBuffer, destination is Video
+ //
+ if (DestinationX == 0 && Width == ScreenWidth) {
+ /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthFillUint32) and format matches EFI_UGA_PIXEL
+ Status = Private->PciIo->Mem.Write (
+ Private->PciIo,
+ EfiPciIoWidthFillUint32,
+ Private->BarIndexFB,
+ DestinationY * ScreenWidth * 4,
+ (Width * Height),
+ BltBuffer
+ );
+ ASSERT_EFI_ERROR((Status));
+ } else {
+ for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
+ /// @todo assumes that color depth is 32 (*4, EfiPciIoWidthFillUint32) and format matches EFI_UGA_PIXEL
+ Private->PciIo->Mem.Write (
+ Private->PciIo,
+ EfiPciIoWidthFillUint32,
+ Private->BarIndexFB,
+ ((DstY * ScreenWidth) + DestinationX) * 4,
+ Width,
+ BltBuffer
+ );
+ }
+ }
+ break;
+
+ default:
+ ASSERT (FALSE);
+ }
+
+ gBS->RestoreTPL (OriginalTPL);
+
+ return EFI_SUCCESS;
+}
+
+//
+// Construction and Destruction functions
+//
+EFI_STATUS
+VBoxVgaUgaDrawConstructor (
+ VBOX_VGA_PRIVATE_DATA *Private
+ )
+{
+ EFI_UGA_DRAW_PROTOCOL *UgaDraw;
+ UINT32 Index;
+ UINT32 HorizontalResolution = 1024;
+ UINT32 VerticalResolution = 768;
+ UINT32 ColorDepth = 32;
+
+ //
+ // Fill in Private->UgaDraw protocol
+ //
+ UgaDraw = &Private->UgaDraw;
+
+ UgaDraw->GetMode = VBoxVgaUgaDrawGetMode;
+ UgaDraw->SetMode = VBoxVgaUgaDrawSetMode;
+ UgaDraw->Blt = VBoxVgaUgaDrawBlt;
+
+ //
+ // Initialize the private data
+ //
+ Private->CurrentMode = 0;
+ Private->HardwareNeedsStarting = TRUE;
+
+ //
+ // Initialize the hardware
+ //
+ VBoxVgaGetVmVariable(EFI_INFO_INDEX_HORIZONTAL_RESOLUTION, (CHAR8 *)&HorizontalResolution,
+ sizeof(HorizontalResolution));
+ VBoxVgaGetVmVariable(EFI_INFO_INDEX_VERTICAL_RESOLUTION, (CHAR8 *)&VerticalResolution,
+ sizeof(VerticalResolution));
+ for (Index = 0; Index < Private->MaxMode; Index++)
+ {
+ if ( HorizontalResolution == Private->ModeData[Index].HorizontalResolution
+ && VerticalResolution == Private->ModeData[Index].VerticalResolution
+ && ColorDepth == Private->ModeData[Index].ColorDepth)
+ break;
+ }
+ // not found? try mode number
+ if (Index >= Private->MaxMode)
+ {
+ VBoxVgaGetVmVariable(EFI_INFO_INDEX_GRAPHICS_MODE, (CHAR8 *)&Index, sizeof(Index));
+ // try with mode 2 (usually 1024x768) as a fallback
+ if (Index >= Private->MaxMode)
+ Index = 2;
+ // try with mode 0 (usually 640x480) as a fallback
+ if (Index >= Private->MaxMode)
+ Index = 0;
+
+ // get the resolution from the mode if valid
+ if (Index < Private->MaxMode)
+ {
+ HorizontalResolution = Private->ModeData[Index].HorizontalResolution;
+ VerticalResolution = Private->ModeData[Index].VerticalResolution;
+ ColorDepth = Private->ModeData[Index].ColorDepth;
+ }
+ }
+
+ // skip mode setting completely if there is no valid mode
+ if (Index >= Private->MaxMode)
+ return EFI_UNSUPPORTED;
+
+ UgaDraw->SetMode (
+ UgaDraw,
+ HorizontalResolution,
+ VerticalResolution,
+ ColorDepth,
+ 60
+ );
+
+ DrawLogo (
+ Private,
+ Private->ModeData[Private->CurrentMode].HorizontalResolution,
+ Private->ModeData[Private->CurrentMode].VerticalResolution
+ );
+
+ PcdSet32S(PcdVideoHorizontalResolution, HorizontalResolution);
+ PcdSet32S(PcdVideoVerticalResolution, VerticalResolution);
+
+ return EFI_SUCCESS;
+}
+