summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers')
-rw-r--r--src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportTcpDxe/FastbootTransportTcp.c660
-rw-r--r--src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportTcpDxe/FastbootTransportTcpDxe.inf46
-rw-r--r--src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsb.c272
-rw-r--r--src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsbDxe.inf41
-rw-r--r--src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.c288
-rw-r--r--src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.h25
-rw-r--r--src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.inf55
-rw-r--r--src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.uni21
-rw-r--r--src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.vfr38
-rw-r--r--src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.c208
-rw-r--r--src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.h25
-rw-r--r--src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.inf54
-rw-r--r--src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformHii.uni21
-rw-r--r--src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformHii.vfr38
-rw-r--r--src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.c250
-rw-r--r--src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.inf35
-rw-r--r--src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/ComponentName.c181
-rw-r--r--src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/ComponentName.h147
-rw-r--r--src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/VirtualKeyboard.c1143
-rw-r--r--src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/VirtualKeyboard.h537
-rw-r--r--src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/VirtualKeyboardDxe.inf54
21 files changed, 4139 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportTcpDxe/FastbootTransportTcp.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportTcpDxe/FastbootTransportTcp.c
new file mode 100644
index 00000000..c4e20ea5
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportTcpDxe/FastbootTransportTcp.c
@@ -0,0 +1,660 @@
+/** @file
+#
+# Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+#**/
+
+#include <Protocol/AndroidFastbootTransport.h>
+#include <Protocol/Dhcp4.h>
+#include <Protocol/Tcp4.h>
+#include <Protocol/ServiceBinding.h>
+#include <Protocol/SimpleTextOut.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#define IP4_ADDR_TO_STRING(IpAddr, IpAddrString) UnicodeSPrint ( \
+ IpAddrString, \
+ 16 * 2, \
+ L"%d.%d.%d.%d", \
+ IpAddr.Addr[0], \
+ IpAddr.Addr[1], \
+ IpAddr.Addr[2], \
+ IpAddr.Addr[3] \
+ );
+
+// Fastboot says max packet size is 512, but FASTBOOT_TRANSPORT_PROTOCOL
+// doesn't place a limit on the size of buffers returned by Receive.
+// (This isn't actually a packet size - it's just the size of the buffers we
+// pass to the TCP driver to fill with received data.)
+// We can achieve much better performance by doing this in larger chunks.
+#define RX_FRAGMENT_SIZE 2048
+
+STATIC EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *mTextOut;
+
+STATIC EFI_TCP4_PROTOCOL *mTcpConnection;
+STATIC EFI_TCP4_PROTOCOL *mTcpListener;
+
+STATIC EFI_EVENT mReceiveEvent;
+
+STATIC EFI_SERVICE_BINDING_PROTOCOL *mTcpServiceBinding;
+STATIC EFI_HANDLE mTcpHandle = NULL;
+
+// We only ever use one IO token for receive and one for transmit. To save
+// repeatedly allocating and freeing, just allocate statically and re-use.
+#define NUM_RX_TOKENS 16
+#define TOKEN_NEXT(Index) (((Index) + 1) % NUM_RX_TOKENS)
+
+STATIC UINTN mNextSubmitIndex;
+STATIC UINTN mNextReceiveIndex;
+STATIC EFI_TCP4_IO_TOKEN mReceiveToken[NUM_RX_TOKENS];
+STATIC EFI_TCP4_RECEIVE_DATA mRxData[NUM_RX_TOKENS];
+STATIC EFI_TCP4_IO_TOKEN mTransmitToken;
+STATIC EFI_TCP4_TRANSMIT_DATA mTxData;
+// We also reuse the accept token
+STATIC EFI_TCP4_LISTEN_TOKEN mAcceptToken;
+// .. and the close token
+STATIC EFI_TCP4_CLOSE_TOKEN mCloseToken;
+
+// List type for queued received packets
+typedef struct _FASTBOOT_TCP_PACKET_LIST {
+ LIST_ENTRY Link;
+ VOID *Buffer;
+ UINTN BufferSize;
+} FASTBOOT_TCP_PACKET_LIST;
+
+STATIC LIST_ENTRY mPacketListHead;
+
+STATIC
+VOID
+EFIAPI
+DataReceived (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/*
+ Helper function to set up a receive IO token and call Tcp->Receive
+*/
+STATIC
+EFI_STATUS
+SubmitRecieveToken (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VOID *FragmentBuffer;
+
+ Status = EFI_SUCCESS;
+
+ FragmentBuffer = AllocatePool (RX_FRAGMENT_SIZE);
+ ASSERT (FragmentBuffer != NULL);
+ if (FragmentBuffer == NULL) {
+ DEBUG ((EFI_D_ERROR, "TCP Fastboot out of resources"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mRxData[mNextSubmitIndex].DataLength = RX_FRAGMENT_SIZE;
+ mRxData[mNextSubmitIndex].FragmentTable[0].FragmentLength = RX_FRAGMENT_SIZE;
+ mRxData[mNextSubmitIndex].FragmentTable[0].FragmentBuffer = FragmentBuffer;
+
+ Status = mTcpConnection->Receive (mTcpConnection, &mReceiveToken[mNextSubmitIndex]);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "TCP Receive: %r\n", Status));
+ FreePool (FragmentBuffer);
+ }
+
+ mNextSubmitIndex = TOKEN_NEXT (mNextSubmitIndex);
+ return Status;
+}
+
+/*
+ Event notify function for when we have closed our TCP connection.
+ We can now start listening for another connection.
+*/
+STATIC
+VOID
+ConnectionClosed (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+
+ // Possible bug in EDK2 TCP4 driver: closing a connection doesn't remove its
+ // PCB from the list of live connections. Subsequent attempts to Configure()
+ // a TCP instance with the same local port will fail with INVALID_PARAMETER.
+ // Calling Configure with NULL is a workaround for this issue.
+ Status = mTcpConnection->Configure (mTcpConnection, NULL);
+
+ mTcpConnection = NULL;
+
+ Status = mTcpListener->Accept (mTcpListener, &mAcceptToken);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "TCP Accept: %r\n", Status));
+ }
+}
+
+STATIC
+VOID
+CloseReceiveEvents (
+ VOID
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < NUM_RX_TOKENS; Index++) {
+ gBS->CloseEvent (mReceiveToken[Index].CompletionToken.Event);
+ }
+}
+
+/*
+ Event notify function to be called when we receive TCP data.
+*/
+STATIC
+VOID
+EFIAPI
+DataReceived (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ FASTBOOT_TCP_PACKET_LIST *NewEntry;
+ EFI_TCP4_IO_TOKEN *ReceiveToken;
+
+ ReceiveToken = &mReceiveToken[mNextReceiveIndex];
+
+ Status = ReceiveToken->CompletionToken.Status;
+
+ if (Status == EFI_CONNECTION_FIN) {
+ //
+ // Remote host closed connection. Close our end.
+ //
+
+ CloseReceiveEvents ();
+
+ Status = mTcpConnection->Close (mTcpConnection, &mCloseToken);
+ ASSERT_EFI_ERROR (Status);
+
+ return;
+ }
+
+ //
+ // Add an element to the receive queue
+ //
+
+ NewEntry = AllocatePool (sizeof (FASTBOOT_TCP_PACKET_LIST));
+ if (NewEntry == NULL) {
+ DEBUG ((EFI_D_ERROR, "TCP Fastboot: Out of resources\n"));
+ return;
+ }
+
+ mNextReceiveIndex = TOKEN_NEXT (mNextReceiveIndex);
+
+ if (!EFI_ERROR (Status)) {
+ NewEntry->Buffer
+ = ReceiveToken->Packet.RxData->FragmentTable[0].FragmentBuffer;
+ NewEntry->BufferSize
+ = ReceiveToken->Packet.RxData->FragmentTable[0].FragmentLength;
+
+ // Prepare to receive more data
+ SubmitRecieveToken();
+ } else {
+ // Fatal receive error. Put an entry with NULL in the queue, signifying
+ // to return EFI_DEVICE_ERROR from TcpFastbootTransportReceive.
+ NewEntry->Buffer = NULL;
+ NewEntry->BufferSize = 0;
+
+ DEBUG ((EFI_D_ERROR, "\nTCP Fastboot Receive error: %r\n", Status));
+ }
+
+ InsertTailList (&mPacketListHead, &NewEntry->Link);
+
+ Status = gBS->SignalEvent (mReceiveEvent);
+ ASSERT_EFI_ERROR (Status);
+}
+
+
+/*
+ Event notify function to be called when we accept an incoming TCP connection.
+*/
+STATIC
+VOID
+EFIAPI
+ConnectionAccepted (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_TCP4_LISTEN_TOKEN *AcceptToken;
+ EFI_STATUS Status;
+ UINTN Index;
+
+ AcceptToken = (EFI_TCP4_LISTEN_TOKEN *) Context;
+ Status = AcceptToken->CompletionToken.Status;
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "TCP Fastboot: Connection Error: %r\n", Status));
+ return;
+ }
+ DEBUG ((EFI_D_ERROR, "TCP Fastboot: Connection Received.\n"));
+
+ //
+ // Accepting a new TCP connection creates a new instance of the TCP protocol.
+ // Open it and prepare to receive on it.
+ //
+
+ Status = gBS->OpenProtocol (
+ AcceptToken->NewChildHandle,
+ &gEfiTcp4ProtocolGuid,
+ (VOID **) &mTcpConnection,
+ gImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Open TCP Connection: %r\n", Status));
+ return;
+ }
+
+ mNextSubmitIndex = 0;
+ mNextReceiveIndex = 0;
+
+ for (Index = 0; Index < NUM_RX_TOKENS; Index++) {
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ DataReceived,
+ NULL,
+ &(mReceiveToken[Index].CompletionToken.Event)
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ for (Index = 0; Index < NUM_RX_TOKENS; Index++) {
+ SubmitRecieveToken();
+ }
+}
+
+/*
+ Set up TCP Fastboot transport: Configure the network device via DHCP then
+ start waiting for a TCP connection on the Fastboot port.
+*/
+EFI_STATUS
+TcpFastbootTransportStart (
+ EFI_EVENT ReceiveEvent
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE NetDeviceHandle;
+ EFI_HANDLE *HandleBuffer;
+ EFI_IP4_MODE_DATA Ip4ModeData;
+ UINTN NumHandles;
+ CHAR16 IpAddrString[16];
+ UINTN Index;
+
+ EFI_TCP4_CONFIG_DATA TcpConfigData = {
+ 0x00, // IPv4 Type of Service
+ 255, // IPv4 Time to Live
+ { // AccessPoint:
+ TRUE, // Use default address
+ { {0, 0, 0, 0} }, // IP Address (ignored - use default)
+ { {0, 0, 0, 0} }, // Subnet mask (ignored - use default)
+ FixedPcdGet32 (PcdAndroidFastbootTcpPort), // Station port
+ { {0, 0, 0, 0} }, // Remote address: accept any
+ 0, // Remote Port: accept any
+ FALSE // ActiveFlag: be a "server"
+ },
+ NULL // Default advanced TCP options
+ };
+
+ mReceiveEvent = ReceiveEvent;
+ InitializeListHead (&mPacketListHead);
+
+ mTextOut->OutputString (mTextOut, L"Initialising TCP Fastboot transport...\r\n");
+
+ //
+ // Open a passive TCP instance
+ //
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiTcp4ServiceBindingProtocolGuid,
+ NULL,
+ &NumHandles,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Find TCP Service Binding: %r\n", Status));
+ return Status;
+ }
+
+ // We just use the first network device
+ NetDeviceHandle = HandleBuffer[0];
+
+ Status = gBS->OpenProtocol (
+ NetDeviceHandle,
+ &gEfiTcp4ServiceBindingProtocolGuid,
+ (VOID **) &mTcpServiceBinding,
+ gImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Open TCP Service Binding: %r\n", Status));
+ return Status;
+ }
+
+ Status = mTcpServiceBinding->CreateChild (mTcpServiceBinding, &mTcpHandle);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "TCP ServiceBinding Create: %r\n", Status));
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ mTcpHandle,
+ &gEfiTcp4ProtocolGuid,
+ (VOID **) &mTcpListener,
+ gImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Open TCP Protocol: %r\n", Status));
+ }
+
+ //
+ // Set up re-usable tokens
+ //
+
+ for (Index = 0; Index < NUM_RX_TOKENS; Index++) {
+ mRxData[Index].UrgentFlag = FALSE;
+ mRxData[Index].FragmentCount = 1;
+ mReceiveToken[Index].Packet.RxData = &mRxData[Index];
+ }
+
+ mTxData.Push = TRUE;
+ mTxData.Urgent = FALSE;
+ mTxData.FragmentCount = 1;
+ mTransmitToken.Packet.TxData = &mTxData;
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ ConnectionAccepted,
+ &mAcceptToken,
+ &mAcceptToken.CompletionToken.Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ ConnectionClosed,
+ &mCloseToken,
+ &mCloseToken.CompletionToken.Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Configure the TCP instance
+ //
+
+ Status = mTcpListener->Configure (mTcpListener, &TcpConfigData);
+ if (Status == EFI_NO_MAPPING) {
+ // Wait until the IP configuration process (probably DHCP) has finished
+ do {
+ Status = mTcpListener->GetModeData (mTcpListener,
+ NULL, NULL,
+ &Ip4ModeData,
+ NULL, NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ } while (!Ip4ModeData.IsConfigured);
+ Status = mTcpListener->Configure (mTcpListener, &TcpConfigData);
+ } else if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "TCP Configure: %r\n", Status));
+ return Status;
+ }
+
+ //
+ // Tell the user our address and hostname
+ //
+ IP4_ADDR_TO_STRING (Ip4ModeData.ConfigData.StationAddress, IpAddrString);
+
+ mTextOut->OutputString (mTextOut, L"TCP Fastboot transport configured.");
+ mTextOut->OutputString (mTextOut, L"\r\nIP address: ");
+ mTextOut->OutputString (mTextOut ,IpAddrString);
+ mTextOut->OutputString (mTextOut, L"\r\n");
+
+ //
+ // Start listening for a connection
+ //
+
+ Status = mTcpListener->Accept (mTcpListener, &mAcceptToken);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "TCP Accept: %r\n", Status));
+ return Status;
+ }
+
+ mTextOut->OutputString (mTextOut, L"TCP Fastboot transport initialised.\r\n");
+
+ FreePool (HandleBuffer);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+TcpFastbootTransportStop (
+ VOID
+ )
+{
+ EFI_TCP4_CLOSE_TOKEN CloseToken;
+ EFI_STATUS Status;
+ UINTN EventIndex;
+ FASTBOOT_TCP_PACKET_LIST *Entry;
+ FASTBOOT_TCP_PACKET_LIST *NextEntry;
+
+ // Close any existing TCP connection, blocking until it's done.
+ if (mTcpConnection != NULL) {
+ CloseReceiveEvents ();
+
+ CloseToken.AbortOnClose = FALSE;
+
+ Status = gBS->CreateEvent (0, 0, NULL, NULL, &CloseToken.CompletionToken.Event);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = mTcpConnection->Close (mTcpConnection, &CloseToken);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->WaitForEvent (
+ 1,
+ &CloseToken.CompletionToken.Event,
+ &EventIndex
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ASSERT_EFI_ERROR (CloseToken.CompletionToken.Status);
+
+ // Possible bug in EDK2 TCP4 driver: closing a connection doesn't remove its
+ // PCB from the list of live connections. Subsequent attempts to Configure()
+ // a TCP instance with the same local port will fail with INVALID_PARAMETER.
+ // Calling Configure with NULL is a workaround for this issue.
+ Status = mTcpConnection->Configure (mTcpConnection, NULL);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+
+ gBS->CloseEvent (mAcceptToken.CompletionToken.Event);
+
+ // Stop listening for connections.
+ // Ideally we would do this with Cancel, but it isn't implemented by EDK2.
+ // So we just "reset this TCPv4 instance brutally".
+ Status = mTcpListener->Configure (mTcpListener, NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = mTcpServiceBinding->DestroyChild (mTcpServiceBinding, mTcpHandle);
+
+ // Free any data the user didn't pick up
+ Entry = (FASTBOOT_TCP_PACKET_LIST *) GetFirstNode (&mPacketListHead);
+ while (!IsNull (&mPacketListHead, &Entry->Link)) {
+ NextEntry = (FASTBOOT_TCP_PACKET_LIST *) GetNextNode (&mPacketListHead, &Entry->Link);
+
+ RemoveEntryList (&Entry->Link);
+ if (Entry->Buffer) {
+ FreePool (Entry->Buffer);
+ }
+ FreePool (Entry);
+
+ Entry = NextEntry;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/*
+ Event notify function for when data has been sent. Free resources and report
+ errors.
+ Context should point to the transmit IO token passed to
+ TcpConnection->Transmit.
+*/
+STATIC
+VOID
+DataSent (
+ EFI_EVENT Event,
+ VOID *Context
+ )
+{
+ EFI_STATUS Status;
+
+ Status = mTransmitToken.CompletionToken.Status;
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "TCP Fastboot transmit result: %r\n", Status));
+ gBS->SignalEvent (*(EFI_EVENT *) Context);
+ }
+
+ FreePool (mTransmitToken.Packet.TxData->FragmentTable[0].FragmentBuffer);
+}
+
+EFI_STATUS
+TcpFastbootTransportSend (
+ IN UINTN BufferSize,
+ IN CONST VOID *Buffer,
+ IN EFI_EVENT *FatalErrorEvent
+ )
+{
+ EFI_STATUS Status;
+
+ if (BufferSize > 512) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Build transmit IO token
+ //
+
+ // Create an event so we are notified when a transmission is complete.
+ // We use this to free resources and report errors.
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ DataSent,
+ FatalErrorEvent,
+ &mTransmitToken.CompletionToken.Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mTxData.DataLength = BufferSize;
+
+ mTxData.FragmentTable[0].FragmentLength = BufferSize;
+ mTxData.FragmentTable[0].FragmentBuffer = AllocateCopyPool (
+ BufferSize,
+ Buffer
+ );
+
+ Status = mTcpConnection->Transmit (mTcpConnection, &mTransmitToken);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "TCP Transmit: %r\n", Status));
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+EFI_STATUS
+TcpFastbootTransportReceive (
+ OUT UINTN *BufferSize,
+ OUT VOID **Buffer
+ )
+{
+ FASTBOOT_TCP_PACKET_LIST *Entry;
+
+ if (IsListEmpty (&mPacketListHead)) {
+ return EFI_NOT_READY;
+ }
+
+ Entry = (FASTBOOT_TCP_PACKET_LIST *) GetFirstNode (&mPacketListHead);
+
+ if (Entry->Buffer == NULL) {
+ // There was an error receiving this packet.
+ return EFI_DEVICE_ERROR;
+ }
+
+ *Buffer = Entry->Buffer;
+ *BufferSize = Entry->BufferSize;
+
+ RemoveEntryList (&Entry->Link);
+ FreePool (Entry);
+
+ return EFI_SUCCESS;
+}
+
+FASTBOOT_TRANSPORT_PROTOCOL mTransportProtocol = {
+ TcpFastbootTransportStart,
+ TcpFastbootTransportStop,
+ TcpFastbootTransportSend,
+ TcpFastbootTransportReceive
+};
+
+EFI_STATUS
+TcpFastbootTransportEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+
+ Status = gBS->LocateProtocol(
+ &gEfiSimpleTextOutProtocolGuid,
+ NULL,
+ (VOID **) &mTextOut
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Fastboot: Open Text Output Protocol: %r\n", Status));
+ return Status;
+ }
+
+ Status = gBS->InstallProtocolInterface (
+ &ImageHandle,
+ &gAndroidFastbootTransportProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mTransportProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Fastboot: Install transport Protocol: %r\n", Status));
+ }
+
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportTcpDxe/FastbootTransportTcpDxe.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportTcpDxe/FastbootTransportTcpDxe.inf
new file mode 100644
index 00000000..7f1693a9
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportTcpDxe/FastbootTransportTcpDxe.inf
@@ -0,0 +1,46 @@
+#/** @file
+#
+# Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TcpFastbootTransportDxe
+ FILE_GUID = 86787704-8fed-11e3-b3ff-f33b73acfec2
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = TcpFastbootTransportEntryPoint
+
+[Sources.common]
+ FastbootTransportTcp.c
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ PrintLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiRuntimeServicesTableLib
+
+[Protocols]
+ gAndroidFastbootTransportProtocolGuid
+ gEfiDhcp4ProtocolGuid
+ gEfiDhcp4ServiceBindingProtocolGuid
+ gEfiTcp4ServiceBindingProtocolGuid
+ gEfiSimpleTextOutProtocolGuid
+ gEfiTcp4ProtocolGuid
+ gEfiSimpleTextOutProtocolGuid
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+
+[FixedPcd]
+ gEmbeddedTokenSpaceGuid.PcdAndroidFastbootTcpPort
diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsb.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsb.c
new file mode 100644
index 00000000..130b00ad
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsb.c
@@ -0,0 +1,272 @@
+/** @file
+
+ Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+/*
+ * Implementation of the FASTBOOT_TRANSPORT_PROTOCOL using the USB_DEVICE_PROTOCOL
+ */
+
+#include <Protocol/UsbDevice.h>
+#include <Protocol/AndroidFastbootTransport.h>
+#include <Protocol/SimpleTextOut.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+
+STATIC USB_DEVICE_PROTOCOL *mUsbDevice;
+
+// Configuration attributes:
+// bit 7 reserved and must be 1, bit 6 means self-powered.
+#define CONFIG_DESC_ATTRIBUTES (BIT7 | BIT6)
+
+#define MAX_PACKET_SIZE_BULK 512
+
+STATIC USB_DEVICE_PROTOCOL *mUsbDevice;
+STATIC EFI_EVENT mReceiveEvent = NULL;
+STATIC LIST_ENTRY mPacketList;
+
+// List type for queued received packets
+typedef struct _FASTBOOT_USB_PACKET_LIST {
+ LIST_ENTRY Link;
+ VOID *Buffer;
+ UINTN BufferSize;
+} FASTBOOT_USB_PACKET_LIST;
+
+
+/*
+ No string descriptors - all string descriptor members are set to 0
+*/
+
+STATIC USB_DEVICE_DESCRIPTOR mDeviceDescriptor = {
+ sizeof (USB_DEVICE_DESCRIPTOR), //Length
+ USB_DESC_TYPE_DEVICE, //DescriptorType
+ 0x0200, //BcdUSB
+ 0xFF, //DeviceClass
+ 0, //DeviceSubClass
+ 0, //DeviceProtocol
+ 64, //MaxPacketSize0
+ FixedPcdGet32 (PcdAndroidFastbootUsbVendorId), //IdVendor
+ FixedPcdGet32 (PcdAndroidFastbootUsbProductId), //IdProduct
+ 0, //BcdDevice
+ 0, //StrManufacturer
+ 0, //StrProduct
+ 0, //StrSerialNumber
+ 1 //NumConfigurations
+};
+
+/*
+ We have one configuration, one interface, and two endpoints (one IN, one OUT)
+*/
+
+// Lazy (compile-time) way to concatenate descriptors to pass to the USB device
+// protocol
+
+#pragma pack(1)
+typedef struct {
+ USB_CONFIG_DESCRIPTOR ConfigDescriptor;
+ USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+ USB_ENDPOINT_DESCRIPTOR EndpointDescriptor1;
+ USB_ENDPOINT_DESCRIPTOR EndpointDescriptor2;
+} GET_CONFIG_DESCRIPTOR_RESPONSE;
+#pragma pack()
+
+STATIC GET_CONFIG_DESCRIPTOR_RESPONSE mGetConfigDescriptorResponse = {
+ { // USB_CONFIG_DESCRIPTOR
+ sizeof (USB_CONFIG_DESCRIPTOR), //Length;
+ USB_DESC_TYPE_CONFIG, //DescriptorType;
+ sizeof (GET_CONFIG_DESCRIPTOR_RESPONSE), //TotalLength;
+ 1, //NumInterfaces;
+ 1, //ConfigurationValue;
+ 0, //Configuration;
+ CONFIG_DESC_ATTRIBUTES, //Attributes;
+ 0 //MaxPower;
+ },
+ { // USB_INTERFACE_DESCRIPTOR
+ sizeof (USB_INTERFACE_DESCRIPTOR), //Length;
+ USB_DESC_TYPE_INTERFACE, //DescriptorType;
+ 0, //InterfaceNumber;
+ 0, //AlternateSetting;
+ 2, //NumEndpoints;
+ 0xFF, //InterfaceClass;
+ // Vendor specific interface subclass and protocol codes.
+ // I found these values in the Fastboot code
+ // (in match_fastboot_with_serial in fastboot.c).
+ 0x42, //InterfaceSubClass;
+ 0x03, //InterfaceProtocol;
+ 0 //Interface;
+ },
+ { // USB_ENDPOINT_DESCRIPTOR (In Endpoint)
+ sizeof (USB_ENDPOINT_DESCRIPTOR), //Length;
+ USB_DESC_TYPE_ENDPOINT, //DescriptorType;
+ 1 | BIT7, //EndpointAddress;
+ 0x2, //Attributes;
+ MAX_PACKET_SIZE_BULK, //MaxPacketSize;
+ 16 //Interval;
+ },
+ { // STATIC USB_ENDPOINT_DESCRIPTOR (Out Endpoint)
+ sizeof (USB_ENDPOINT_DESCRIPTOR), //Length;
+ USB_DESC_TYPE_ENDPOINT, //DescriptorType;
+ 1, //EndpointAddress;
+ 0x2, //Attributes;
+ MAX_PACKET_SIZE_BULK, //MaxPacketSize;
+ 16 //Interval;
+ }
+};
+
+STATIC
+VOID
+DataReceived (
+ IN UINTN Size,
+ IN VOID *Buffer
+ )
+{
+ FASTBOOT_USB_PACKET_LIST *NewEntry;
+
+ NewEntry = AllocatePool (sizeof (*NewEntry));
+ ASSERT (NewEntry != NULL);
+
+ NewEntry->Buffer = Buffer;
+ NewEntry->BufferSize = Size;
+
+ InsertTailList (&mPacketList, &NewEntry->Link);
+
+ if (mReceiveEvent) {
+ gBS->SignalEvent (mReceiveEvent);
+ }
+}
+
+STATIC
+VOID
+DataSent (
+ IN UINT8 EndpointIndex
+ )
+{
+ // Don't care.
+}
+
+/*
+ Set up the transport system for use by Fastboot.
+ e.g. For USB this probably means making the device enumerable.
+*/
+EFI_STATUS
+FastbootTransportUsbStart (
+ EFI_EVENT ReceiveEvent
+ )
+{
+ GET_CONFIG_DESCRIPTOR_RESPONSE *Responses;
+
+ mReceiveEvent = ReceiveEvent;
+
+ mGetConfigDescriptorResponse.ConfigDescriptor.TotalLength = sizeof (GET_CONFIG_DESCRIPTOR_RESPONSE);
+ Responses = &mGetConfigDescriptorResponse;
+
+ InitializeListHead (&mPacketList);
+
+ return mUsbDevice->Start (&mDeviceDescriptor, (VOID **) &Responses, DataReceived, DataSent);
+}
+
+/*
+ Function to be called when all Fastboot transactions are finished, to
+ de-initialise the transport system.
+ e.g. A USB OTG system might want to get out of peripheral mode so it can be
+ a USB host.
+*/
+EFI_STATUS
+FastbootTransportUsbStop (
+ VOID
+ )
+{
+ // not yet implemented in USB
+ return EFI_SUCCESS;
+}
+
+/*
+ Send data. This function can be used both for command responses like "OKAY"
+ and for the data phase (the protocol doesn't describe any situation when the
+ latter might be necessary, but does allow it)
+ */
+EFI_STATUS
+FastbootTransportUsbSend (
+ IN UINTN BufferSize,
+ IN CONST VOID *Buffer,
+ IN EFI_EVENT *FatalErrorEvent
+ )
+{
+ // Current USB protocol is blocking, so ignore FatalErrorEvent
+ return mUsbDevice->Send(1, BufferSize, Buffer);
+}
+
+/*
+ When the event has been Signalled to say data is available from the host,
+ this function is used to get data. In order to handle the case where several
+ packets are received before ReceiveEvent's notify function is called, packets
+ received are queued, and each call to this function returns the next packet in
+ the queue. It should therefore be called in a loop, the exit condition being a
+ return of EFI_NOT_READY.
+
+ Parameters:
+ Buffer - The buffer in which to place data
+ BufferSize - The size of Buffer in bytes
+
+ Return EFI_NOT_READY if there is no data available
+*/
+EFI_STATUS
+FastbootTransportUsbReceive (
+ OUT UINTN *BufferSize,
+ OUT VOID **Buffer
+ )
+{
+ FASTBOOT_USB_PACKET_LIST *Entry;
+
+ if (IsListEmpty (&mPacketList)) {
+ return EFI_NOT_READY;
+ }
+
+ Entry = (FASTBOOT_USB_PACKET_LIST *) GetFirstNode (&mPacketList);
+
+ *BufferSize = Entry->BufferSize;
+ *Buffer = Entry->Buffer;
+
+ RemoveEntryList (&Entry->Link);
+ FreePool (Entry);
+
+ return EFI_SUCCESS;
+}
+
+STATIC FASTBOOT_TRANSPORT_PROTOCOL mTransportProtocol = {
+ FastbootTransportUsbStart,
+ FastbootTransportUsbStop,
+ FastbootTransportUsbSend,
+ FastbootTransportUsbReceive
+};
+
+EFI_STATUS
+FastbootTransportUsbEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ // Assume there's only one USB peripheral controller.
+ Status = gBS->LocateProtocol (&gUsbDeviceProtocolGuid, NULL, (VOID **) &mUsbDevice);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->InstallProtocolInterface (
+ &ImageHandle,
+ &gAndroidFastbootTransportProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mTransportProtocol
+ );
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsbDxe.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsbDxe.inf
new file mode 100644
index 00000000..94c804ff
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsbDxe.inf
@@ -0,0 +1,41 @@
+#/** @file
+#
+# Copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = FastbootTransportUsbDxe
+ FILE_GUID = f6bec3fe-88fb-11e3-ae84-e73b77561c35
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = FastbootTransportUsbEntryPoint
+
+[Sources.common]
+ FastbootTransportUsb.c
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+
+[Protocols]
+ gEfiDriverBindingProtocolGuid
+ gUsbDeviceProtocolGuid
+ gAndroidFastbootTransportProtocolGuid
+ gEfiSimpleTextOutProtocolGuid
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+
+[FixedPcd]
+ gEmbeddedTokenSpaceGuid.PcdAndroidFastbootUsbVendorId
+ gEmbeddedTokenSpaceGuid.PcdAndroidFastbootUsbProductId
diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.c
new file mode 100644
index 00000000..e92d0fd7
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.c
@@ -0,0 +1,288 @@
+/** @file
+*
+* Copyright (c) 2017, Linaro, Ltd. All rights reserved.
+*
+* SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+
+#include <Uefi.h>
+#include <IndustryStandard/Acpi.h>
+#include <libfdt.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/HiiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#include <Protocol/AcpiTable.h>
+#include <Protocol/AcpiSystemDescriptionTable.h>
+
+#include "ConsolePrefDxe.h"
+
+#define SPCR_SIG EFI_ACPI_2_0_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE
+
+extern UINT8 ConsolePrefHiiBin[];
+extern UINT8 ConsolePrefDxeStrings[];
+
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} HII_VENDOR_DEVICE_PATH;
+
+STATIC HII_VENDOR_DEVICE_PATH mConsolePrefDxeVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ CONSOLE_PREF_FORMSET_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+STATIC EFI_EVENT mReadyToBootEvent;
+
+STATIC
+EFI_STATUS
+InstallHiiPages (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HANDLE DriverHandle;
+
+ DriverHandle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (&DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mConsolePrefDxeVendorDevicePath,
+ NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ HiiHandle = HiiAddPackages (&gConsolePrefFormSetGuid,
+ DriverHandle,
+ ConsolePrefDxeStrings,
+ ConsolePrefHiiBin,
+ NULL);
+
+ if (HiiHandle == NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mConsolePrefDxeVendorDevicePath,
+ NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ return EFI_SUCCESS;
+}
+
+STATIC
+VOID
+RemoveDtStdoutPath (
+ VOID
+)
+{
+ VOID *Dtb;
+ INT32 Node;
+ INT32 Error;
+ EFI_STATUS Status;
+
+ Status = EfiGetSystemConfigurationTable (&gFdtTableGuid, &Dtb);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "%a: could not retrieve DT blob - %r\n", __FUNCTION__,
+ Status));
+ return;
+ }
+
+ Node = fdt_path_offset (Dtb, "/chosen");
+ if (Node < 0) {
+ return;
+ }
+
+ Error = fdt_delprop (Dtb, Node, "stdout-path");
+ if (Error) {
+ DEBUG ((DEBUG_INFO, "%a: Failed to delete 'stdout-path' property: %a\n",
+ __FUNCTION__, fdt_strerror (Error)));
+ }
+}
+
+STATIC
+VOID
+RemoveSpcrTable (
+ VOID
+ )
+{
+ EFI_ACPI_SDT_PROTOCOL *Sdt;
+ EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
+ EFI_STATUS Status;
+ UINTN TableIndex;
+ EFI_ACPI_SDT_HEADER *TableHeader;
+ EFI_ACPI_TABLE_VERSION TableVersion;
+ UINTN TableKey;
+
+ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL,
+ (VOID **)&AcpiTable);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ Status = gBS->LocateProtocol (&gEfiAcpiSdtProtocolGuid, NULL, (VOID **)&Sdt);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ TableIndex = 0;
+ TableKey = 0;
+ TableHeader = NULL;
+
+ do {
+ Status = Sdt->GetAcpiTable (TableIndex++, &TableHeader, &TableVersion,
+ &TableKey);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (TableHeader->Signature != SPCR_SIG) {
+ continue;
+ }
+
+ Status = AcpiTable->UninstallAcpiTable (AcpiTable, TableKey);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "%a: failed to uninstall SPCR table - %r\n",
+ __FUNCTION__, Status));
+ }
+ break;
+ } while (TRUE);
+}
+
+STATIC
+VOID
+EFIAPI
+OnReadyToBoot (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ CONSOLE_PREF_VARSTORE_DATA ConsolePref;
+ UINTN BufferSize;
+ EFI_STATUS Status;
+ VOID *Gop;
+
+ BufferSize = sizeof (ConsolePref);
+ Status = gRT->GetVariable (CONSOLE_PREF_VARIABLE_NAME,
+ &gConsolePrefFormSetGuid, NULL, &BufferSize, &ConsolePref);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: variable '%s' could not be read - bailing!\n", __FUNCTION__,
+ CONSOLE_PREF_VARIABLE_NAME));
+ return;
+ }
+
+ if (ConsolePref.Console == CONSOLE_PREF_SERIAL) {
+ DEBUG ((DEBUG_INFO,
+ "%a: serial console preferred - doing nothing\n", __FUNCTION__));
+ return;
+ }
+
+ //
+ // Check if any GOP instances exist: if so, disable stdout-path and SPCR
+ //
+ Status = gBS->LocateProtocol (&gEfiGraphicsOutputProtocolGuid, NULL, &Gop);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO,
+ "%a: no GOP instances found - doing nothing (%r)\n", __FUNCTION__,
+ Status));
+ return;
+ }
+
+ RemoveDtStdoutPath ();
+ RemoveSpcrTable ();
+}
+
+/**
+ The entry point for ConsolePrefDxe driver.
+
+ @param[in] ImageHandle The image handle of the driver.
+ @param[in] SystemTable The system table.
+
+ @retval EFI_ALREADY_STARTED The driver already exists in system.
+ @retval EFI_OUT_OF_RESOURCES Fail to execute entry point due to lack of
+ resources.
+ @retval EFI_SUCCESS All the related protocols are installed on
+ the driver.
+
+**/
+EFI_STATUS
+EFIAPI
+ConsolePrefDxeEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ CONSOLE_PREF_VARSTORE_DATA ConsolePref;
+ UINTN BufferSize;
+
+ //
+ // Get the current console preference from the ConsolePref variable.
+ //
+ BufferSize = sizeof (ConsolePref);
+ Status = gRT->GetVariable (CONSOLE_PREF_VARIABLE_NAME,
+ &gConsolePrefFormSetGuid, NULL, &BufferSize, &ConsolePref);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO,
+ "%a: no console preference found, defaulting to graphical\n",
+ __FUNCTION__));
+ ConsolePref.Console = CONSOLE_PREF_GRAPHICAL;
+ }
+
+ if (!EFI_ERROR (Status) &&
+ ConsolePref.Console != CONSOLE_PREF_GRAPHICAL &&
+ ConsolePref.Console != CONSOLE_PREF_SERIAL) {
+ DEBUG ((DEBUG_WARN, "%a: invalid value for %s, defaulting to graphical\n",
+ __FUNCTION__, CONSOLE_PREF_VARIABLE_NAME));
+ ConsolePref.Console = CONSOLE_PREF_GRAPHICAL;
+ Status = EFI_INVALID_PARAMETER; // trigger setvar below
+ }
+
+ //
+ // Write the newly selected value back to the variable store.
+ //
+ if (EFI_ERROR (Status)) {
+ ZeroMem (&ConsolePref.Reserved, sizeof (ConsolePref.Reserved));
+ Status = gRT->SetVariable (CONSOLE_PREF_VARIABLE_NAME,
+ &gConsolePrefFormSetGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (ConsolePref), &ConsolePref);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: gRT->SetVariable () failed - %r\n",
+ __FUNCTION__, Status));
+ return Status;
+ }
+ }
+
+ Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
+ OnReadyToBoot, NULL, &gEfiEventReadyToBootGuid,
+ &mReadyToBootEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ return InstallHiiPages ();
+}
diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.h
new file mode 100644
index 00000000..8d87ca90
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.h
@@ -0,0 +1,25 @@
+/** @file
+*
+* Copyright (c) 2017, Linaro Limited. All rights reserved.
+*
+* SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+
+#ifndef __CONSOLE_PREF_DXE_H__
+#define __CONSOLE_PREF_DXE_H__
+
+#include <Guid/HiiPlatformSetupFormset.h>
+#include <Guid/ConsolePrefFormSet.h>
+
+#define CONSOLE_PREF_GRAPHICAL 0x0
+#define CONSOLE_PREF_SERIAL 0x1
+
+#define CONSOLE_PREF_VARIABLE_NAME L"ConsolePref"
+
+typedef struct {
+ UINT8 Console;
+ UINT8 Reserved[3];
+} CONSOLE_PREF_VARSTORE_DATA;
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.inf
new file mode 100644
index 00000000..aa58142a
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefDxe.inf
@@ -0,0 +1,55 @@
+## @file
+#
+# Copyright (c) 2017, Linaro, Ltd. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010019
+ BASE_NAME = ConsolePrefDxe
+ FILE_GUID = bbe2668c-0efc-46fb-9137-4f2da8f419f3
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = ConsolePrefDxeEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64
+#
+
+[Sources]
+ ConsolePrefDxe.c
+ ConsolePrefHii.vfr
+ ConsolePrefHii.uni
+
+[Packages]
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ FdtLib
+ HiiLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+ UefiRuntimeServicesTableLib
+
+[Guids]
+ gConsolePrefFormSetGuid
+ gFdtTableGuid
+ gEfiEventReadyToBootGuid
+
+[Protocols]
+ gEfiAcpiTableProtocolGuid
+ gEfiAcpiSdtProtocolGuid
+ gEfiGraphicsOutputProtocolGuid
+
+[Depex]
+ gEfiVariableArchProtocolGuid AND
+ gEfiVariableWriteArchProtocolGuid
diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.uni b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.uni
new file mode 100644
index 00000000..d1c532b1
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.uni
@@ -0,0 +1,21 @@
+/** @file
+*
+* Copyright (c) 2017, Linaro, Ltd. All rights reserved.
+*
+* SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+
+#langdef en-US "English"
+
+#string STR_FORM_SET_TITLE #language en-US "Console Preference Selection"
+#string STR_FORM_SET_TITLE_HELP #language en-US "Press <Enter> to choose between graphical and serial console."
+
+#string STR_MAIN_FORM_TITLE #language en-US "Console Preference Selection"
+#string STR_NULL_STRING #language en-US ""
+
+#string STR_CONSOLE_PREF_SELECT_PROMPT #language en-US "Preferred console"
+#string STR_CONSOLE_PREF_SELECT_HELP #language en-US "Select the preferred console if both graphical and serial are available."
+
+#string STR_CONSOLE_PREF_GRAPHICAL #language en-US "Graphical"
+#string STR_CONSOLE_PREF_SERIAL #language en-US "Serial"
diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.vfr b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.vfr
new file mode 100644
index 00000000..719f99e3
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/ConsolePrefDxe/ConsolePrefHii.vfr
@@ -0,0 +1,38 @@
+/** @file
+*
+* Copyright (c) 2017, Linaro, Ltd. All rights reserved.
+*
+* SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+
+#include <Uefi/UefiMultiPhase.h>
+#include "ConsolePrefDxe.h"
+
+formset
+ guid = CONSOLE_PREF_FORMSET_GUID,
+ title = STRING_TOKEN(STR_FORM_SET_TITLE),
+ help = STRING_TOKEN(STR_FORM_SET_TITLE_HELP),
+ classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID,
+
+ efivarstore CONSOLE_PREF_VARSTORE_DATA,
+ attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, // EFI variable attributes
+ name = ConsolePref,
+ guid = CONSOLE_PREF_FORMSET_GUID;
+
+ form formid = 0x1000,
+ title = STRING_TOKEN(STR_MAIN_FORM_TITLE);
+
+ oneof varid = ConsolePref.Console,
+ prompt = STRING_TOKEN(STR_CONSOLE_PREF_SELECT_PROMPT),
+ help = STRING_TOKEN(STR_CONSOLE_PREF_SELECT_HELP),
+ flags = NUMERIC_SIZE_1 | INTERACTIVE,
+ option text = STRING_TOKEN(STR_CONSOLE_PREF_GRAPHICAL), value = CONSOLE_PREF_GRAPHICAL, flags = DEFAULT;
+ option text = STRING_TOKEN(STR_CONSOLE_PREF_SERIAL), value = CONSOLE_PREF_SERIAL, flags = 0;
+ endoneof;
+
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+ endform;
+
+endformset;
diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.c
new file mode 100644
index 00000000..ef092a60
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.c
@@ -0,0 +1,208 @@
+/** @file
+*
+* Copyright (c) 2017, Linaro, Ltd. All rights reserved.
+*
+* SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/DtPlatformDtbLoaderLib.h>
+#include <Library/HiiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#include "DtPlatformDxe.h"
+
+extern UINT8 DtPlatformHiiBin[];
+extern UINT8 DtPlatformDxeStrings[];
+
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} HII_VENDOR_DEVICE_PATH;
+
+STATIC HII_VENDOR_DEVICE_PATH mDtPlatformDxeVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ DT_PLATFORM_FORMSET_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+STATIC
+EFI_STATUS
+InstallHiiPages (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HANDLE DriverHandle;
+
+ DriverHandle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (&DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mDtPlatformDxeVendorDevicePath,
+ NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ HiiHandle = HiiAddPackages (&gDtPlatformFormSetGuid,
+ DriverHandle,
+ DtPlatformDxeStrings,
+ DtPlatformHiiBin,
+ NULL);
+
+ if (HiiHandle == NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mDtPlatformDxeVendorDevicePath,
+ NULL);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ The entry point for DtPlatformDxe driver.
+
+ @param[in] ImageHandle The image handle of the driver.
+ @param[in] SystemTable The system table.
+
+ @retval EFI_ALREADY_STARTED The driver already exists in system.
+ @retval EFI_OUT_OF_RESOURCES Fail to execute entry point due to lack of
+ resources.
+ @retval EFI_SUCCESS All the related protocols are installed on
+ the driver.
+
+**/
+EFI_STATUS
+EFIAPI
+DtPlatformDxeEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ DT_ACPI_VARSTORE_DATA DtAcpiPref;
+ UINTN BufferSize;
+ VOID *Dtb;
+ UINTN DtbSize;
+
+ Dtb = NULL;
+ Status = DtPlatformLoadDtb (&Dtb, &DtbSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN,
+ "%a: no DTB blob could be loaded, defaulting to ACPI (Status == %r)\n",
+ __FUNCTION__, Status));
+ DtAcpiPref.Pref = DT_ACPI_SELECT_ACPI;
+ } else {
+ //
+ // Get the current DT/ACPI preference from the DtAcpiPref variable.
+ //
+ BufferSize = sizeof (DtAcpiPref);
+ Status = gRT->GetVariable(DT_ACPI_VARIABLE_NAME, &gDtPlatformFormSetGuid,
+ NULL, &BufferSize, &DtAcpiPref);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "%a: no DT/ACPI preference found, defaulting to %a\n",
+ __FUNCTION__, PcdGetBool (PcdDefaultDtPref) ? "DT" : "ACPI"));
+ DtAcpiPref.Pref = PcdGetBool (PcdDefaultDtPref) ? DT_ACPI_SELECT_DT
+ : DT_ACPI_SELECT_ACPI;
+ }
+ }
+
+ if (!EFI_ERROR (Status) &&
+ DtAcpiPref.Pref != DT_ACPI_SELECT_ACPI &&
+ DtAcpiPref.Pref != DT_ACPI_SELECT_DT) {
+ DEBUG ((DEBUG_WARN, "%a: invalid value for %s, defaulting to %a\n",
+ __FUNCTION__, DT_ACPI_VARIABLE_NAME,
+ PcdGetBool (PcdDefaultDtPref) ? "DT" : "ACPI"));
+ DtAcpiPref.Pref = PcdGetBool (PcdDefaultDtPref) ? DT_ACPI_SELECT_DT
+ : DT_ACPI_SELECT_ACPI;
+ Status = EFI_INVALID_PARAMETER; // trigger setvar below
+ }
+
+ //
+ // Write the newly selected default value back to the variable store.
+ //
+ if (EFI_ERROR (Status)) {
+ Status = gRT->SetVariable(DT_ACPI_VARIABLE_NAME, &gDtPlatformFormSetGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (DtAcpiPref), &DtAcpiPref);
+ if (EFI_ERROR (Status)) {
+ goto FreeDtb;
+ }
+ }
+
+ if (DtAcpiPref.Pref == DT_ACPI_SELECT_ACPI) {
+ //
+ // ACPI was selected: install the gEdkiiPlatformHasAcpiGuid GUID as a
+ // NULL protocol to unlock dispatch of ACPI related drivers.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (&ImageHandle,
+ &gEdkiiPlatformHasAcpiGuid, NULL, NULL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: failed to install gEdkiiPlatformHasAcpiGuid as a protocol\n",
+ __FUNCTION__));
+ goto FreeDtb;
+ }
+ } else if (DtAcpiPref.Pref == DT_ACPI_SELECT_DT) {
+ //
+ // DT was selected: copy the blob into newly allocated memory and install
+ // a reference to it as the FDT configuration table.
+ //
+ Status = gBS->InstallConfigurationTable (&gFdtTableGuid, Dtb);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: failed to install FDT configuration table\n",
+ __FUNCTION__));
+ goto FreeDtb;
+ }
+ } else {
+ ASSERT (FALSE);
+ }
+
+ //
+ // No point in installing the HII pages if ACPI is the only description
+ // we have
+ //
+ if (Dtb == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Note that we don't uninstall the gEdkiiPlatformHasAcpiGuid protocol nor
+ // the FDT configuration table if the following call fails. While that will
+ // cause loading of this driver to fail, proceeding with ACPI and DT both
+ // disabled will guarantee a failed boot, and so it is better to leave them
+ // installed in that case.
+ //
+ return InstallHiiPages ();
+
+FreeDtb:
+ if (Dtb != NULL) {
+ FreePool (Dtb);
+ }
+
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.h
new file mode 100644
index 00000000..6a9d3962
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.h
@@ -0,0 +1,25 @@
+/** @file
+*
+* Copyright (c) 2017, Linaro Limited. All rights reserved.
+*
+* SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+
+#ifndef __DT_PLATFORM_DXE_H__
+#define __DT_PLATFORM_DXE_H__
+
+#include <Guid/HiiPlatformSetupFormset.h>
+#include <Guid/DtPlatformFormSet.h>
+
+#define DT_ACPI_SELECT_DT 0x0
+#define DT_ACPI_SELECT_ACPI 0x1
+
+#define DT_ACPI_VARIABLE_NAME L"DtAcpiPref"
+
+typedef struct {
+ UINT8 Pref;
+ UINT8 Reserved[3];
+} DT_ACPI_VARSTORE_DATA;
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.inf
new file mode 100644
index 00000000..7beccd34
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformDxe.inf
@@ -0,0 +1,54 @@
+## @file
+#
+# Copyright (c) 2017, Linaro, Ltd. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010019
+ BASE_NAME = DtPlatformDxe
+ FILE_GUID = FC097B3C-2EBD-4A75-A3DA-121DCAB365CC
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = DtPlatformDxeEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64
+#
+
+[Sources]
+ DtPlatformDxe.c
+ DtPlatformHii.vfr
+ DtPlatformHii.uni
+
+[Packages]
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ DtPlatformDtbLoaderLib
+ HiiLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiRuntimeServicesTableLib
+
+[Guids]
+ gDtPlatformFormSetGuid
+ gDtPlatformDefaultDtbFileGuid
+ gEdkiiPlatformHasAcpiGuid
+ gFdtTableGuid
+
+[Pcd]
+ gEmbeddedTokenSpaceGuid.PcdDefaultDtPref
+
+[Depex]
+ gEfiVariableArchProtocolGuid AND
+ gEfiVariableWriteArchProtocolGuid
diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformHii.uni b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformHii.uni
new file mode 100644
index 00000000..5f24061a
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformHii.uni
@@ -0,0 +1,21 @@
+/** @file
+*
+* Copyright (c) 2017, Linaro, Ltd. All rights reserved.
+*
+* SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+
+#langdef en-US "English"
+
+#string STR_FORM_SET_TITLE #language en-US "O/S Hardware Description Selection"
+#string STR_FORM_SET_TITLE_HELP #language en-US "Press <Enter> to choose between ACPI and DT hardware descriptions."
+
+#string STR_MAIN_FORM_TITLE #language en-US "O/S Hardware Description Selection"
+#string STR_NULL_STRING #language en-US ""
+
+#string STR_DT_ACPI_SELECT_PROMPT #language en-US "O/S Hardware Description"
+#string STR_DT_ACPI_SELECT_HELP #language en-US "Select the hardware description that will be exposed to the O/S."
+
+#string STR_DT_ACPI_SELECT_DT #language en-US "Device Tree"
+#string STR_DT_ACPI_SELECT_ACPI #language en-US "ACPI"
diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformHii.vfr b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformHii.vfr
new file mode 100644
index 00000000..99d03bad
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/DtPlatformDxe/DtPlatformHii.vfr
@@ -0,0 +1,38 @@
+/** @file
+*
+* Copyright (c) 2017, Linaro, Ltd. All rights reserved.
+*
+* SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+
+#include <Uefi/UefiMultiPhase.h>
+#include "DtPlatformDxe.h"
+
+formset
+ guid = DT_PLATFORM_FORMSET_GUID,
+ title = STRING_TOKEN(STR_FORM_SET_TITLE),
+ help = STRING_TOKEN(STR_FORM_SET_TITLE_HELP),
+ classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID,
+
+ efivarstore DT_ACPI_VARSTORE_DATA,
+ attribute = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, // EFI variable attributes
+ name = DtAcpiPref,
+ guid = DT_PLATFORM_FORMSET_GUID;
+
+ form formid = 0x1000,
+ title = STRING_TOKEN(STR_MAIN_FORM_TITLE);
+
+ oneof varid = DtAcpiPref.Pref,
+ prompt = STRING_TOKEN(STR_DT_ACPI_SELECT_PROMPT),
+ help = STRING_TOKEN(STR_DT_ACPI_SELECT_HELP),
+ flags = NUMERIC_SIZE_1 | INTERACTIVE | RESET_REQUIRED,
+ option text = STRING_TOKEN(STR_DT_ACPI_SELECT_DT), value = DT_ACPI_SELECT_DT, flags = DEFAULT;
+ option text = STRING_TOKEN(STR_DT_ACPI_SELECT_ACPI), value = DT_ACPI_SELECT_ACPI, flags = 0;
+ endoneof;
+
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+ endform;
+
+endformset;
diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.c
new file mode 100644
index 00000000..48605463
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.c
@@ -0,0 +1,250 @@
+/** @file
+
+ Copyright (c) 2019, Linaro, Ltd. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DmaLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/IoMmu.h>
+
+/**
+ Set IOMMU attribute for a system memory.
+
+ If the IOMMU protocol exists, the system memory cannot be used
+ for DMA by default.
+
+ When a device requests a DMA access for a system memory,
+ the device driver need use SetAttribute() to update the IOMMU
+ attribute to request DMA access (read and/or write).
+
+ The DeviceHandle is used to identify which device submits the request.
+ The IOMMU implementation need translate the device path to an IOMMU device
+ ID, and set IOMMU hardware register accordingly.
+ 1) DeviceHandle can be a standard PCI device.
+ The memory for BusMasterRead need set EDKII_IOMMU_ACCESS_READ.
+ The memory for BusMasterWrite need set EDKII_IOMMU_ACCESS_WRITE.
+ The memory for BusMasterCommonBuffer need set
+ EDKII_IOMMU_ACCESS_READ|EDKII_IOMMU_ACCESS_WRITE.
+ After the memory is used, the memory need set 0 to keep it being
+ protected.
+ 2) DeviceHandle can be an ACPI device (ISA, I2C, SPI, etc).
+ The memory for DMA access need set EDKII_IOMMU_ACCESS_READ and/or
+ EDKII_IOMMU_ACCESS_WRITE.
+
+ @param[in] This The protocol instance pointer.
+ @param[in] DeviceHandle The device who initiates the DMA access
+ request.
+ @param[in] Mapping The mapping value returned from Map().
+ @param[in] IoMmuAccess The IOMMU access.
+
+ @retval EFI_SUCCESS The IoMmuAccess is set for the memory range
+ specified by DeviceAddress and Length.
+ @retval EFI_INVALID_PARAMETER DeviceHandle is an invalid handle.
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by
+ Map().
+ @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination
+ of access.
+ @retval EFI_UNSUPPORTED DeviceHandle is unknown by the IOMMU.
+ @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported
+ by the IOMMU.
+ @retval EFI_UNSUPPORTED The IOMMU does not support the memory range
+ specified by Mapping.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
+ modify the IOMMU access.
+ @retval EFI_DEVICE_ERROR The IOMMU device reported an error while
+ attempting the operation.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+NonCoherentIoMmuSetAttribute (
+ IN EDKII_IOMMU_PROTOCOL *This,
+ IN EFI_HANDLE DeviceHandle,
+ IN VOID *Mapping,
+ IN UINT64 IoMmuAccess
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Provides the controller-specific addresses required to access system memory
+ from a DMA bus master. On SEV guest, the DMA operations must be performed on
+ shared buffer hence we allocate a bounce buffer to map the HostAddress to a
+ DeviceAddress. The Encryption attribute is removed from the DeviceAddress
+ buffer.
+
+ @param This The protocol instance pointer.
+ @param Operation Indicates if the bus master is going to read or
+ write to system memory.
+ @param HostAddress The system memory address to map to the PCI
+ controller.
+ @param NumberOfBytes On input the number of bytes to map. On output
+ the number of bytes that were mapped.
+ @param DeviceAddress The resulting map address for the bus master
+ PCI controller to use to access the hosts
+ HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned
+ NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common
+ buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested
+ address.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+NonCoherentIoMmuMap (
+ IN EDKII_IOMMU_PROTOCOL *This,
+ IN EDKII_IOMMU_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ DMA_MAP_OPERATION DmaOperation;
+
+ switch (Operation) {
+ case EdkiiIoMmuOperationBusMasterRead:
+ case EdkiiIoMmuOperationBusMasterRead64:
+ DmaOperation = MapOperationBusMasterRead;
+ break;
+
+ case EdkiiIoMmuOperationBusMasterWrite:
+ case EdkiiIoMmuOperationBusMasterWrite64:
+ DmaOperation = MapOperationBusMasterWrite;
+ break;
+
+ case EdkiiIoMmuOperationBusMasterCommonBuffer:
+ case EdkiiIoMmuOperationBusMasterCommonBuffer64:
+ DmaOperation = MapOperationBusMasterCommonBuffer;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return DmaMap (DmaOperation, HostAddress, NumberOfBytes,
+ DeviceAddress, Mapping);
+}
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param This The protocol instance pointer.
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by
+ Map().
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system
+ memory.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+NonCoherentIoMmuUnmap (
+ IN EDKII_IOMMU_PROTOCOL *This,
+ IN VOID *Mapping
+ )
+{
+ return DmaUnmap (Mapping);
+}
+
+/**
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param This The protocol instance pointer.
+ @param Type This parameter is not used and must be ignored.
+ @param MemoryType The type of memory to allocate,
+ EfiBootServicesData or EfiRuntimeServicesData.
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory
+ address of the allocated range.
+ @param Attributes The requested bit mask of attributes for the
+ allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal
+ attribute bits are MEMORY_WRITE_COMBINE and
+ MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+NonCoherentIoMmuAllocateBuffer (
+ IN EDKII_IOMMU_PROTOCOL *This,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ IN OUT VOID **HostAddress,
+ IN UINT64 Attributes
+ )
+{
+ return DmaAllocateBuffer (MemoryType, Pages, HostAddress);
+}
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ @param This The protocol instance pointer.
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated
+ range.
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and
+ Pages was not allocated with AllocateBuffer().
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+NonCoherentIoMmuFreeBuffer (
+ IN EDKII_IOMMU_PROTOCOL *This,
+ IN UINTN Pages,
+ IN VOID *HostAddress
+ )
+{
+ return DmaFreeBuffer (Pages, HostAddress);
+}
+
+STATIC EDKII_IOMMU_PROTOCOL mNonCoherentIoMmuOps = {
+ EDKII_IOMMU_PROTOCOL_REVISION,
+ NonCoherentIoMmuSetAttribute,
+ NonCoherentIoMmuMap,
+ NonCoherentIoMmuUnmap,
+ NonCoherentIoMmuAllocateBuffer,
+ NonCoherentIoMmuFreeBuffer,
+};
+
+
+EFI_STATUS
+EFIAPI
+NonCoherentIoMmuDxeEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return gBS->InstallMultipleProtocolInterfaces (&ImageHandle,
+ &gEdkiiIoMmuProtocolGuid, &mNonCoherentIoMmuOps,
+ NULL);
+}
diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.inf
new file mode 100644
index 00000000..12ab8a80
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/NonCoherentIoMmuDxe/NonCoherentIoMmuDxe.inf
@@ -0,0 +1,35 @@
+#/** @file
+#
+# Copyright (c) 2019, Linaro, Ltd. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#**/
+
+[Defines]
+ INF_VERSION = 1.27
+ BASE_NAME = NonCoherentIoMmuDxe
+ FILE_GUID = 7ed510aa-9cdc-49d2-a306-6e11e359f9b3
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = NonCoherentIoMmuDxeEntryPoint
+
+[Sources]
+ NonCoherentIoMmuDxe.c
+
+[Packages]
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ DmaLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+
+[Protocols]
+ gEdkiiIoMmuProtocolGuid ## PRODUCES
+
+[Depex]
+ TRUE
diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/ComponentName.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/ComponentName.c
new file mode 100644
index 00000000..d12f1c63
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/ComponentName.c
@@ -0,0 +1,181 @@
+/** @file
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2018, Linaro Ltd. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "VirtualKeyboard.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gVirtualKeyboardComponentName = {
+ VirtualKeyboardComponentNameGetDriverName,
+ VirtualKeyboardComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gVirtualKeyboardComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) VirtualKeyboardComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) VirtualKeyboardComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mVirtualKeyboardDriverNameTable[] = {
+ {
+ "eng;en",
+ L"Virtual Keyboard Driver"
+ },
+ {
+ "zh-CHS",
+ L"虚拟键盘驱动程序"
+ },
+ {
+ 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
+VirtualKeyboardComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mVirtualKeyboardDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gVirtualKeyboardComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/ComponentName.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/ComponentName.h
new file mode 100644
index 00000000..45c20332
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/ComponentName.h
@@ -0,0 +1,147 @@
+/** @file
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2018, Linaro Ltd. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _VIRTUAL_KEYBOARD_COMPONENT_NAME_H_
+#define _VIRTUAL_KEYBOARD_COMPONENT_NAME_H_
+
+
+extern EFI_COMPONENT_NAME_PROTOCOL gVirtualKeyboardComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gVirtualKeyboardComponentName2;
+
+//
+// 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
+VirtualKeyboardComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/VirtualKeyboard.c b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/VirtualKeyboard.c
new file mode 100644
index 00000000..c0193aed
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/VirtualKeyboard.c
@@ -0,0 +1,1143 @@
+/** @file
+ VirtualKeyboard driver
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2018, Linaro Ltd. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "VirtualKeyboard.h"
+
+//
+// RAM Keyboard Driver Binding Protocol Instance
+//
+EFI_DRIVER_BINDING_PROTOCOL gVirtualKeyboardDriverBinding = {
+ VirtualKeyboardDriverBindingSupported,
+ VirtualKeyboardDriverBindingStart,
+ VirtualKeyboardDriverBindingStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+//
+// EFI Driver Binding Protocol Functions
+//
+
+/**
+ Check whether the driver supports this device.
+
+ @param This The Udriver binding protocol.
+ @param Controller The controller handle to check.
+ @param RemainingDevicePath The remaining device path.
+
+ @retval EFI_SUCCESS The driver supports this controller.
+ @retval other This device isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ PLATFORM_VIRTUAL_KBD_PROTOCOL *PlatformVirtual;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gPlatformVirtualKeyboardProtocolGuid,
+ (VOID **) &PlatformVirtual,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ gBS->CloseProtocol (
+ Controller,
+ &gPlatformVirtualKeyboardProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return Status;
+}
+
+/**
+ Starts the device with this driver.
+
+ @param This The driver binding instance.
+ @param Controller Handle of device to bind driver to.
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS The controller is controlled by the driver.
+ @retval Other This controller cannot be started.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
+ PLATFORM_VIRTUAL_KBD_PROTOCOL *PlatformVirtual;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gPlatformVirtualKeyboardProtocolGuid,
+ (VOID **) &PlatformVirtual,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Allocate the private device structure
+ //
+ VirtualKeyboardPrivate = (VIRTUAL_KEYBOARD_DEV *) AllocateZeroPool (sizeof (VIRTUAL_KEYBOARD_DEV));
+ if (VirtualKeyboardPrivate == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Initialize the private device structure
+ //
+ VirtualKeyboardPrivate->Signature = VIRTUAL_KEYBOARD_DEV_SIGNATURE;
+ VirtualKeyboardPrivate->Handle = Controller;
+ VirtualKeyboardPrivate->PlatformVirtual = PlatformVirtual;
+ VirtualKeyboardPrivate->Queue.Front = 0;
+ VirtualKeyboardPrivate->Queue.Rear = 0;
+ VirtualKeyboardPrivate->QueueForNotify.Front = 0;
+ VirtualKeyboardPrivate->QueueForNotify.Rear = 0;
+
+ VirtualKeyboardPrivate->SimpleTextIn.Reset = VirtualKeyboardReset;
+ VirtualKeyboardPrivate->SimpleTextIn.ReadKeyStroke = VirtualKeyboardReadKeyStroke;
+
+ VirtualKeyboardPrivate->SimpleTextInputEx.Reset = VirtualKeyboardResetEx;
+ VirtualKeyboardPrivate->SimpleTextInputEx.ReadKeyStrokeEx = VirtualKeyboardReadKeyStrokeEx;
+ VirtualKeyboardPrivate->SimpleTextInputEx.SetState = VirtualKeyboardSetState;
+
+ VirtualKeyboardPrivate->SimpleTextInputEx.RegisterKeyNotify = VirtualKeyboardRegisterKeyNotify;
+ VirtualKeyboardPrivate->SimpleTextInputEx.UnregisterKeyNotify = VirtualKeyboardUnregisterKeyNotify;
+ InitializeListHead (&VirtualKeyboardPrivate->NotifyList);
+
+ Status = PlatformVirtual->Register ();
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Report that the keyboard is being enabled
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE
+ );
+
+ //
+ // Setup the WaitForKey event
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ VirtualKeyboardWaitForKey,
+ &(VirtualKeyboardPrivate->SimpleTextIn),
+ &((VirtualKeyboardPrivate->SimpleTextIn).WaitForKey)
+ );
+ if (EFI_ERROR (Status)) {
+ (VirtualKeyboardPrivate->SimpleTextIn).WaitForKey = NULL;
+ goto Done;
+ }
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ VirtualKeyboardWaitForKeyEx,
+ &(VirtualKeyboardPrivate->SimpleTextInputEx),
+ &(VirtualKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx)
+ );
+ if (EFI_ERROR (Status)) {
+ VirtualKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx = NULL;
+ goto Done;
+ }
+
+ //
+ // Setup a periodic timer, used for reading keystrokes at a fixed interval
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ VirtualKeyboardTimerHandler,
+ VirtualKeyboardPrivate,
+ &VirtualKeyboardPrivate->TimerEvent
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ Status = gBS->SetTimer (
+ VirtualKeyboardPrivate->TimerEvent,
+ TimerPeriodic,
+ KEYBOARD_TIMER_INTERVAL
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ KeyNotifyProcessHandler,
+ VirtualKeyboardPrivate,
+ &VirtualKeyboardPrivate->KeyNotifyProcessEvent
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Reset the keyboard device
+ //
+ Status = VirtualKeyboardPrivate->SimpleTextInputEx.Reset (
+ &VirtualKeyboardPrivate->SimpleTextInputEx,
+ FALSE
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "[KBD]Reset Failed. Status - %r\n", Status));
+ goto Done;
+ }
+ //
+ // Install protocol interfaces for the keyboard device.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiSimpleTextInProtocolGuid,
+ &VirtualKeyboardPrivate->SimpleTextIn,
+ &gEfiSimpleTextInputExProtocolGuid,
+ &VirtualKeyboardPrivate->SimpleTextInputEx,
+ NULL
+ );
+
+Done:
+ if (EFI_ERROR (Status)) {
+ if (VirtualKeyboardPrivate != NULL) {
+ if ((VirtualKeyboardPrivate->SimpleTextIn).WaitForKey != NULL) {
+ gBS->CloseEvent ((VirtualKeyboardPrivate->SimpleTextIn).WaitForKey);
+ }
+
+ if ((VirtualKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx != NULL) {
+ gBS->CloseEvent (
+ (VirtualKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx
+ );
+ }
+
+ if (VirtualKeyboardPrivate->KeyNotifyProcessEvent != NULL) {
+ gBS->CloseEvent (VirtualKeyboardPrivate->KeyNotifyProcessEvent);
+ }
+
+ VirtualKeyboardFreeNotifyList (&VirtualKeyboardPrivate->NotifyList);
+
+ if (VirtualKeyboardPrivate->TimerEvent != NULL) {
+ gBS->CloseEvent (VirtualKeyboardPrivate->TimerEvent);
+ }
+ FreePool (VirtualKeyboardPrivate);
+ }
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gPlatformVirtualKeyboardProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+/**
+ Stop the device handled by this driver.
+
+ @param This The driver binding protocol.
+ @param Controller The controller to release.
+ @param NumberOfChildren The number of handles in ChildHandleBuffer.
+ @param ChildHandleBuffer The array of child handle.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a
+ device error.
+ @retval Others Fail to uninstall protocols attached on the
+ device.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Enqueue the key.
+
+ @param Queue The queue to be enqueued.
+ @param KeyData The key data to be enqueued.
+
+ @retval EFI_NOT_READY The queue is full.
+ @retval EFI_SUCCESS Successfully enqueued the key data.
+
+**/
+EFI_STATUS
+Enqueue (
+ IN SIMPLE_QUEUE *Queue,
+ IN EFI_KEY_DATA *KeyData
+ )
+{
+ if ((Queue->Rear + 1) % QUEUE_MAX_COUNT == Queue->Front) {
+ return EFI_NOT_READY;
+ }
+
+ CopyMem (&Queue->Buffer[Queue->Rear], KeyData, sizeof (EFI_KEY_DATA));
+ Queue->Rear = (Queue->Rear + 1) % QUEUE_MAX_COUNT;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Dequeue the key.
+
+ @param Queue The queue to be dequeued.
+ @param KeyData The key data to be dequeued.
+
+ @retval EFI_NOT_READY The queue is empty.
+ @retval EFI_SUCCESS Successfully dequeued the key data.
+
+**/
+EFI_STATUS
+Dequeue (
+ IN SIMPLE_QUEUE *Queue,
+ IN EFI_KEY_DATA *KeyData
+ )
+{
+ if (Queue->Front == Queue->Rear) {
+ return EFI_NOT_READY;
+ }
+
+ CopyMem (KeyData, &Queue->Buffer[Queue->Front], sizeof (EFI_KEY_DATA));
+ Queue->Front = (Queue->Front + 1) % QUEUE_MAX_COUNT;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check whether the queue is empty.
+
+ @param Queue The queue to be checked.
+
+ @retval EFI_NOT_READY The queue is empty.
+ @retval EFI_SUCCESS The queue is not empty.
+
+**/
+EFI_STATUS
+CheckQueue (
+ IN SIMPLE_QUEUE *Queue
+ )
+{
+ if (Queue->Front == Queue->Rear) {
+ return EFI_NOT_READY;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check key buffer to get the key stroke status.
+
+ @param This Pointer of the protocol EFI_SIMPLE_TEXT_IN_PROTOCOL.
+
+ @retval EFI_SUCCESS A key is being pressed now.
+ @retval Other No key is now pressed.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardCheckForKey (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This
+ )
+{
+ VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
+
+ VirtualKeyboardPrivate = VIRTUAL_KEYBOARD_DEV_FROM_THIS (This);
+
+ return CheckQueue (&VirtualKeyboardPrivate->Queue);
+}
+
+/**
+ Free keyboard notify list.
+
+ @param ListHead The list head
+
+ @retval EFI_SUCCESS Free the notify list successfully
+ @retval EFI_INVALID_PARAMETER ListHead is invalid.
+
+**/
+EFI_STATUS
+VirtualKeyboardFreeNotifyList (
+ IN OUT LIST_ENTRY *ListHead
+ )
+{
+ VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode;
+
+ if (ListHead == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ while (!IsListEmpty (ListHead)) {
+ NotifyNode = CR (
+ ListHead->ForwardLink,
+ VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
+ NotifyEntry,
+ VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+ );
+ RemoveEntryList (ListHead->ForwardLink);
+ gBS->FreePool (NotifyNode);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Judge whether is a registed key
+
+ @param RegsiteredData A pointer to a buffer that is filled in with
+ the keystroke state data for the key that was
+ registered.
+ @param InputData A pointer to a buffer that is filled in with
+ the keystroke state data for the key that was
+ pressed.
+
+ @retval TRUE Key be pressed matches a registered key.
+ @retval FALSE Match failed.
+
+**/
+BOOLEAN
+IsKeyRegistered (
+ IN EFI_KEY_DATA *RegsiteredData,
+ IN EFI_KEY_DATA *InputData
+ )
+
+{
+ ASSERT (RegsiteredData != NULL && InputData != NULL);
+
+ if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) ||
+ (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
+ return FALSE;
+ }
+
+ //
+ // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means
+ // these state could be ignored.
+ //
+ if ((RegsiteredData->KeyState.KeyShiftState != 0) &&
+ (RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState)) {
+ return FALSE;
+ }
+ if ((RegsiteredData->KeyState.KeyToggleState != 0) &&
+ (RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState)) {
+ return FALSE;
+ }
+
+ return TRUE;
+
+}
+
+/**
+ Event notification function for SIMPLE_TEXT_IN.WaitForKey event
+ Signal the event if there is key available
+
+ @param Event the event object
+ @param Context waiting context
+
+**/
+VOID
+EFIAPI
+VirtualKeyboardWaitForKey (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // Stall 1ms to give a chance to let other driver interrupt this routine
+ // for their timer event.
+ // e.g. UI setup or Shell, other drivers which are driven by timer event
+ // will have a bad performance during this period,
+ // e.g. usb keyboard driver.
+ // Add a stall period can greatly increate other driver performance during
+ // the WaitForKey is recursivly invoked. 1ms delay will make little impact
+ // to the thunk keyboard driver, and user can not feel the delay at all when
+ // input.
+ //
+ gBS->Stall (1000);
+ //
+ // Use TimerEvent callback function to check whether there's any key pressed
+ //
+ VirtualKeyboardTimerHandler (NULL, VIRTUAL_KEYBOARD_DEV_FROM_THIS (Context));
+
+ if (!EFI_ERROR (VirtualKeyboardCheckForKey (Context))) {
+ gBS->SignalEvent (Event);
+ }
+}
+
+/**
+ Event notification function for SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx
+ event. Signal the event if there is key available
+
+ @param Event event object
+ @param Context waiting context
+
+**/
+VOID
+EFIAPI
+VirtualKeyboardWaitForKeyEx (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+
+{
+ VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
+
+ VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (Context);
+ VirtualKeyboardWaitForKey (Event, &VirtualKeyboardPrivate->SimpleTextIn);
+
+}
+
+//
+// EFI Simple Text In Protocol Functions
+//
+/**
+ Reset the Keyboard and do BAT test for it, if (ExtendedVerification == TRUE)
+ then do some extra keyboard validations.
+
+ @param This Pointer of simple text Protocol.
+ @param ExtendedVerification Whether perform the extra validation of
+ keyboard. True: perform; FALSE: skip.
+
+ @retval EFI_SUCCESS The command byte is written successfully.
+ @retval EFI_DEVICE_ERROR Errors occurred during resetting keyboard.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardReset (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ VirtualKeyboardPrivate = VIRTUAL_KEYBOARD_DEV_FROM_THIS (This);
+
+ //
+ // Raise TPL to avoid mouse operation impact
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ if (VirtualKeyboardPrivate->PlatformVirtual &&
+ VirtualKeyboardPrivate->PlatformVirtual->Reset) {
+ Status = VirtualKeyboardPrivate->PlatformVirtual->Reset ();
+ } else {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // resume priority of task level
+ //
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+/**
+ Reset the input device and optionally run diagnostics
+
+ @param This Protocol instance pointer.
+ @param ExtendedVerification Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and
+ could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardResetEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (This);
+
+ Status = VirtualKeyboardPrivate->SimpleTextIn.Reset (
+ &VirtualKeyboardPrivate->SimpleTextIn,
+ ExtendedVerification
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Reads the next keystroke from the input device. The WaitForKey Event can
+ be used to test for existence of a keystroke via WaitForEvent () call.
+
+ @param VirtualKeyboardPrivate Virtualkeyboard driver private structure.
+ @param KeyData A pointer to a buffer that is filled in
+ with the keystroke state data for the key
+ that was pressed.
+
+ @retval EFI_SUCCESS The keystroke information was returned.
+ @retval EFI_NOT_READY There was no keystroke data available.
+ @retval EFI_DEVICE_ERROR The keystroke information was not returned
+ due to hardware errors.
+ @retval EFI_INVALID_PARAMETER KeyData is NULL.
+
+**/
+EFI_STATUS
+KeyboardReadKeyStrokeWorker (
+ IN VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate,
+ OUT EFI_KEY_DATA *KeyData
+ )
+{
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+ if (KeyData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Use TimerEvent callback function to check whether there's any key pressed
+ //
+
+ //
+ // Stall 1ms to give a chance to let other driver interrupt this routine for
+ // their timer event.
+ // e.g. OS loader, other drivers which are driven by timer event will have a
+ // bad performance during this period,
+ // e.g. usb keyboard driver.
+ // Add a stall period can greatly increate other driver performance during
+ // the WaitForKey is recursivly invoked. 1ms delay will make little impact
+ // to the thunk keyboard driver, and user can not feel the delay at all when
+ // input.
+ //
+ gBS->Stall (1000);
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ VirtualKeyboardTimerHandler (NULL, VirtualKeyboardPrivate);
+ //
+ // If there's no key, just return
+ //
+ Status = CheckQueue (&VirtualKeyboardPrivate->Queue);
+ if (EFI_ERROR (Status)) {
+ gBS->RestoreTPL (OldTpl);
+ return EFI_NOT_READY;
+ }
+
+ Status = Dequeue (&VirtualKeyboardPrivate->Queue, KeyData);
+
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read out the scan code of the key that has just been stroked.
+
+ @param This Pointer of simple text Protocol.
+ @param Key Pointer for store the key that read out.
+
+ @retval EFI_SUCCESS The key is read out successfully.
+ @retval other The key reading failed.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardReadKeyStroke (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ OUT EFI_INPUT_KEY *Key
+ )
+{
+ VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
+ EFI_STATUS Status;
+ EFI_KEY_DATA KeyData;
+
+ VirtualKeyboardPrivate = VIRTUAL_KEYBOARD_DEV_FROM_THIS (This);
+
+ Status = KeyboardReadKeyStrokeWorker (VirtualKeyboardPrivate, &KeyData);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Convert the Ctrl+[a-z] to Ctrl+[1-26]
+ //
+ if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {
+ if (KeyData.Key.UnicodeChar >= L'a' &&
+ KeyData.Key.UnicodeChar <= L'z') {
+ KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1);
+ } else if (KeyData.Key.UnicodeChar >= L'A' &&
+ KeyData.Key.UnicodeChar <= L'Z') {
+ KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1);
+ }
+ }
+
+ CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Reads the next keystroke from the input device. The WaitForKey Event can
+ be used to test for existence of a keystroke via WaitForEvent () call.
+
+ @param This Protocol instance pointer.
+ @param KeyData A pointer to a buffer that is filled in with the
+ keystroke state data for the key that was pressed.
+
+ @retval EFI_SUCCESS The keystroke information was returned.
+ @retval EFI_NOT_READY There was no keystroke data available.
+ @retval EFI_DEVICE_ERROR The keystroke information was not returned
+ due to hardware errors.
+ @retval EFI_INVALID_PARAMETER KeyData is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardReadKeyStrokeEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ OUT EFI_KEY_DATA *KeyData
+ )
+{
+ VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
+
+ if (KeyData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (This);
+
+ return KeyboardReadKeyStrokeWorker (VirtualKeyboardPrivate, KeyData);
+
+}
+
+/**
+ Set certain state for the input device.
+
+ @param This Protocol instance pointer.
+ @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the
+ state for the input device.
+
+ @retval EFI_SUCCESS The device state was set successfully.
+ @retval EFI_DEVICE_ERROR The device is not functioning correctly and
+ could not have the setting adjusted.
+ @retval EFI_UNSUPPORTED The device does not have the ability to set
+ its state.
+ @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardSetState (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_TOGGLE_STATE *KeyToggleState
+ )
+{
+ if (KeyToggleState == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Register a notification function for a particular keystroke for the
+ input device.
+
+ @param This Protocol instance pointer.
+ @param KeyData A pointer to a buffer that is filled in with
+ the keystroke information data for the key
+ that was pressed.
+ @param KeyNotificationFunction Points to the function to be called when the
+ key sequence is typed specified by KeyData.
+ @param NotifyHandle Points to the unique handle assigned to the
+ registered notification.
+
+
+ @retval EFI_SUCCESS The notification function was registered
+ successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necessary
+ data structures.
+ @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardRegisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_DATA *KeyData,
+ IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
+ OUT VOID **NotifyHandle
+ )
+{
+ EFI_STATUS Status;
+ VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
+ EFI_TPL OldTpl;
+ VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *NewNotify;
+ LIST_ENTRY *Link;
+ VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
+
+ if (KeyData == NULL ||
+ NotifyHandle == NULL ||
+ KeyNotificationFunction == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (This);
+
+ //
+ // Enter critical section
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ //
+ // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already
+ // registered.
+ //
+ for (Link = VirtualKeyboardPrivate->NotifyList.ForwardLink;
+ Link != &VirtualKeyboardPrivate->NotifyList;
+ Link = Link->ForwardLink) {
+ CurrentNotify = CR (
+ Link,
+ VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
+ NotifyEntry,
+ VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+ );
+ if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
+ if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
+ *NotifyHandle = CurrentNotify;
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+ }
+ }
+
+ //
+ // Allocate resource to save the notification function
+ //
+
+ NewNotify = (VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY));
+ if (NewNotify == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ NewNotify->Signature = VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
+ NewNotify->KeyNotificationFn = KeyNotificationFunction;
+ CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
+ InsertTailList (&VirtualKeyboardPrivate->NotifyList, &NewNotify->NotifyEntry);
+
+ *NotifyHandle = NewNotify;
+ Status = EFI_SUCCESS;
+
+Exit:
+ //
+ // Leave critical section and return
+ //
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+
+}
+
+/**
+ Remove a registered notification function from a particular keystroke.
+
+ @param This Protocol instance pointer.
+ @param NotificationHandle The handle of the notification function
+ being unregistered.
+
+ @retval EFI_SUCCESS The notification function was unregistered
+ successfully.
+ @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardUnregisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN VOID *NotificationHandle
+ )
+{
+ EFI_STATUS Status;
+ VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
+ EFI_TPL OldTpl;
+ LIST_ENTRY *Link;
+ VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
+
+ //
+ // Check incoming notification handle
+ //
+ if (NotificationHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *) NotificationHandle)->Signature !=
+ VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VirtualKeyboardPrivate = TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS (This);
+
+ //
+ // Enter critical section
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ for (Link = VirtualKeyboardPrivate->NotifyList.ForwardLink;
+ Link != &VirtualKeyboardPrivate->NotifyList;
+ Link = Link->ForwardLink) {
+ CurrentNotify = CR (
+ Link,
+ VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
+ NotifyEntry,
+ VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+ );
+ if (CurrentNotify == NotificationHandle) {
+ //
+ // Remove the notification function from NotifyList and free resources
+ //
+ RemoveEntryList (&CurrentNotify->NotifyEntry);
+
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+ }
+
+ //
+ // Can not find the specified Notification Handle
+ //
+ Status = EFI_INVALID_PARAMETER;
+
+Exit:
+ //
+ // Leave critical section and return
+ //
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ Timer event handler: read a series of scancodes from 8042
+ and put them into memory scancode buffer.
+ it read as much scancodes to either fill
+ the memory buffer or empty the keyboard buffer.
+ It is registered as running under TPL_NOTIFY
+
+ @param Event The timer event
+ @param Context A KEYBOARD_CONSOLE_IN_DEV pointer
+
+**/
+VOID
+EFIAPI
+VirtualKeyboardTimerHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_TPL OldTpl;
+ LIST_ENTRY *Link;
+ EFI_KEY_DATA KeyData;
+ VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
+ VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
+ VIRTUAL_KBD_KEY VirtualKey;
+
+ VirtualKeyboardPrivate = Context;
+
+ //
+ // Enter critical section
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ if (VirtualKeyboardPrivate->PlatformVirtual &&
+ VirtualKeyboardPrivate->PlatformVirtual->Query) {
+ if (VirtualKeyboardPrivate->PlatformVirtual->Query (&VirtualKey) ==
+ FALSE) {
+ goto Exit;
+ }
+ // Found key
+ KeyData.Key.ScanCode = VirtualKey.Key.ScanCode;
+ KeyData.Key.UnicodeChar = VirtualKey.Key.UnicodeChar;
+ KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID;
+ KeyData.KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;
+ if (VirtualKeyboardPrivate->PlatformVirtual->Clear) {
+ VirtualKeyboardPrivate->PlatformVirtual->Clear (&VirtualKey);
+ }
+ } else {
+ goto Exit;
+ }
+
+ //
+ // Signal KeyNotify process event if this key pressed matches any key registered.
+ //
+ for (Link = VirtualKeyboardPrivate->NotifyList.ForwardLink;
+ Link != &VirtualKeyboardPrivate->NotifyList;
+ Link = Link->ForwardLink) {
+ CurrentNotify = CR (
+ Link,
+ VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
+ NotifyEntry,
+ VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+ );
+ if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
+ //
+ // The key notification function needs to run at TPL_CALLBACK
+ // while current TPL is TPL_NOTIFY. It will be invoked in
+ // KeyNotifyProcessHandler() which runs at TPL_CALLBACK.
+ //
+ Enqueue (&VirtualKeyboardPrivate->QueueForNotify, &KeyData);
+ gBS->SignalEvent (VirtualKeyboardPrivate->KeyNotifyProcessEvent);
+ break;
+ }
+ }
+
+ Enqueue (&VirtualKeyboardPrivate->Queue, &KeyData);
+
+Exit:
+ //
+ // Leave critical section and return
+ //
+ gBS->RestoreTPL (OldTpl);
+}
+
+/**
+ Process key notify.
+
+ @param Event Indicates the event that invoke this function.
+ @param Context Indicates the calling context.
+**/
+VOID
+EFIAPI
+KeyNotifyProcessHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ VIRTUAL_KEYBOARD_DEV *VirtualKeyboardPrivate;
+ EFI_KEY_DATA KeyData;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *NotifyList;
+ VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
+ EFI_TPL OldTpl;
+
+ VirtualKeyboardPrivate = (VIRTUAL_KEYBOARD_DEV *) Context;
+
+ //
+ // Invoke notification functions.
+ //
+ NotifyList = &VirtualKeyboardPrivate->NotifyList;
+ while (TRUE) {
+ //
+ // Enter critical section
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ Status = Dequeue (&VirtualKeyboardPrivate->QueueForNotify, &KeyData);
+ //
+ // Leave critical section
+ //
+ gBS->RestoreTPL (OldTpl);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ for (Link = GetFirstNode (NotifyList);
+ !IsNull (NotifyList, Link);
+ Link = GetNextNode (NotifyList, Link)) {
+ CurrentNotify = CR (Link,
+ VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
+ NotifyEntry,
+ VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+ );
+ if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
+ CurrentNotify->KeyNotificationFn (&KeyData);
+ }
+ }
+ }
+}
+
+/**
+ The user Entry Point for module VirtualKeyboard. The user code starts with
+ this function.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeVirtualKeyboard(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gVirtualKeyboardDriverBinding,
+ ImageHandle,
+ &gVirtualKeyboardComponentName,
+ &gVirtualKeyboardComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/VirtualKeyboard.h b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/VirtualKeyboard.h
new file mode 100644
index 00000000..75b77c34
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/VirtualKeyboard.h
@@ -0,0 +1,537 @@
+/** @file
+
+Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2018, Linaro Ltd. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _VIRTUAL_KEYBOARD_H_
+#define _VIRTUAL_KEYBOARD_H_
+
+
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/PlatformVirtualKeyboard.h>
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/SimpleTextInEx.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+
+//
+// Driver Binding Externs
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gVirtualKeyboardDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gVirtualKeyboardComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gVirtualKeyboardComponentName2;
+
+
+//
+// VIRTUAL Keyboard Defines
+//
+#define CHAR_SCANCODE 0xe0
+#define CHAR_ESC 0x1b
+
+#define KEYBOARD_TIMEOUT 65536 // 0.07s
+#define KEYBOARD_WAITFORVALUE_TIMEOUT 1000000 // 1s
+#define KEYBOARD_BAT_TIMEOUT 4000000 // 4s
+#define KEYBOARD_TIMER_INTERVAL 500000 // 0.5s
+
+#define QUEUE_MAX_COUNT 32
+
+#define KEYBOARD_SCAN_CODE_MAX_COUNT 32
+
+//
+// VIRTUAL Keyboard Device Structure
+//
+#define VIRTUAL_KEYBOARD_DEV_SIGNATURE SIGNATURE_32 ('V', 'K', 'B', 'D')
+#define VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE SIGNATURE_32 ('v', 'k', 'c', 'n')
+
+typedef struct _VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY {
+ UINTN Signature;
+ EFI_KEY_DATA KeyData;
+ EFI_KEY_NOTIFY_FUNCTION KeyNotificationFn;
+ LIST_ENTRY NotifyEntry;
+} VIRTUAL_KEYBOARD_CONSOLE_IN_EX_NOTIFY;
+
+typedef struct {
+ UINTN Front;
+ UINTN Rear;
+ EFI_KEY_DATA Buffer[QUEUE_MAX_COUNT];
+} SIMPLE_QUEUE;
+
+typedef struct {
+ UINT8 Buffer[KEYBOARD_SCAN_CODE_MAX_COUNT];
+ UINTN Head;
+ UINTN Tail;
+} SCAN_CODE_QUEUE;
+
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE Handle;
+ PLATFORM_VIRTUAL_KBD_PROTOCOL *PlatformVirtual;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL SimpleTextIn;
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL SimpleTextInputEx;
+
+ //
+ // Buffer storing EFI_KEY_DATA
+ //
+ SIMPLE_QUEUE Queue;
+ SIMPLE_QUEUE QueueForNotify;
+
+ //
+ // Notification Function List
+ //
+ LIST_ENTRY NotifyList;
+ EFI_EVENT KeyNotifyProcessEvent;
+ EFI_EVENT TimerEvent;
+} VIRTUAL_KEYBOARD_DEV;
+
+#define VIRTUAL_KEYBOARD_DEV_FROM_THIS(a) CR (a, VIRTUAL_KEYBOARD_DEV, SimpleTextIn, VIRTUAL_KEYBOARD_DEV_SIGNATURE)
+#define TEXT_INPUT_EX_VIRTUAL_KEYBOARD_DEV_FROM_THIS(a) \
+ CR (a, \
+ VIRTUAL_KEYBOARD_DEV, \
+ SimpleTextInputEx, \
+ VIRTUAL_KEYBOARD_DEV_SIGNATURE \
+ )
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gVirtualKeyboardDriverBinding;
+
+//
+// Driver Binding Protocol functions
+//
+
+/**
+ Check whether the driver supports this device.
+
+ @param This The Udriver binding protocol.
+ @param Controller The controller handle to check.
+ @param RemainingDevicePath The remaining device path.
+
+ @retval EFI_SUCCESS The driver supports this controller.
+ @retval other This device isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starts the device with this driver.
+
+ @param This The driver binding instance.
+ @param Controller Handle of device to bind driver to.
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS The controller is controlled by the driver.
+ @retval Other This controller cannot be started.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop the device handled by this driver.
+
+ @param This The driver binding protocol.
+ @param Controller The controller to release.
+ @param NumberOfChildren The number of handles in ChildHandleBuffer.
+ @param ChildHandleBuffer The array of child handle.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+ @retval Others Fail to uninstall protocols attached on the device.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+/**
+ 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
+VirtualKeyboardComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+//
+// Simple Text Input Protocol functions
+//
+/**
+ Reset the Keyboard and do BAT test for it, if (ExtendedVerification == TRUE) then do some extra keyboard validations.
+
+ @param This Pointer of simple text Protocol.
+ @param ExtendedVerification Whether perform the extra validation of keyboard. True: perform; FALSE: skip.
+
+ @retval EFI_SUCCESS The command byte is written successfully.
+ @retval EFI_DEVICE_ERROR Errors occurred during resetting keyboard.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardReset (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Reset the input device and optionally run diagnostics
+
+ @param This Protocol instance pointer.
+ @param ExtendedVerification Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could
+ not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardResetEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Set certain state for the input device.
+
+ @param This Protocol instance pointer.
+ @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the
+ state for the input device.
+
+ @retval EFI_SUCCESS The device state was set successfully.
+ @retval EFI_DEVICE_ERROR The device is not functioning correctly and could
+ not have the setting adjusted.
+ @retval EFI_UNSUPPORTED The device does not have the ability to set its state.
+ @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardSetState (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_TOGGLE_STATE *KeyToggleState
+ );
+
+/**
+ Register a notification function for a particular keystroke for the input device.
+
+ @param This Protocol instance pointer.
+ @param KeyData A pointer to a buffer that is filled in with the keystroke
+ information data for the key that was pressed.
+ @param KeyNotificationFunction Points to the function to be called when the key
+ sequence is typed specified by KeyData.
+ @param NotifyHandle Points to the unique handle assigned to the registered notification.
+
+
+ @retval EFI_SUCCESS The notification function was registered successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necessary data structures.
+ @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardRegisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_DATA *KeyData,
+ IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
+ OUT VOID **NotifyHandle
+ );
+
+/**
+ Remove a registered notification function from a particular keystroke.
+
+ @param This Protocol instance pointer.
+ @param NotificationHandle The handle of the notification function being unregistered.
+
+ @retval EFI_SUCCESS The notification function was unregistered successfully.
+ @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardUnregisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN VOID *NotificationHandle
+ );
+
+//
+// Private worker functions
+//
+/**
+ Free keyboard notify list.
+
+ @param ListHead The list head
+
+ @retval EFI_SUCCESS Free the notify list successfully
+ @retval EFI_INVALID_PARAMETER ListHead is invalid.
+
+**/
+EFI_STATUS
+VirtualKeyboardFreeNotifyList (
+ IN OUT LIST_ENTRY *ListHead
+ );
+
+/**
+ Check if key is registered.
+
+ @param RegsiteredData A pointer to a buffer that is filled in with the keystroke
+ state data for the key that was registered.
+ @param InputData A pointer to a buffer that is filled in with the keystroke
+ state data for the key that was pressed.
+
+ @retval TRUE Key be pressed matches a registered key.
+ @retval FALSE Match failed.
+
+**/
+BOOLEAN
+IsKeyRegistered (
+ IN EFI_KEY_DATA *RegsiteredData,
+ IN EFI_KEY_DATA *InputData
+ );
+
+/**
+ Waiting on the keyboard event, if there's any key pressed by the user, signal the event
+
+ @param Event The event that be signalled when any key has been struck.
+ @param Context Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
+
+**/
+VOID
+EFIAPI
+VirtualKeyboardWaitForKey (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Waiting on the keyboard event, if there's any key pressed by the user, signal the event
+
+ @param Event The event that be signalled when any key has been struck.
+ @param Context Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
+
+**/
+VOID
+EFIAPI
+VirtualKeyboardWaitForKeyEx (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Timer event handler: read a series of key stroke from 8042
+ and put them into memory key buffer.
+ It is registered as running under TPL_NOTIFY
+
+ @param Event The timer event
+ @param Context A VIRTUAL_KEYBOARD_DEV pointer
+
+**/
+VOID
+EFIAPI
+VirtualKeyboardTimerHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Process key notify.
+
+ @param Event Indicates the event that invoke this function.
+ @param Context Indicates the calling context.
+**/
+VOID
+EFIAPI
+KeyNotifyProcessHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Read out the scan code of the key that has just been stroked.
+
+ @param This Pointer of simple text Protocol.
+ @param Key Pointer for store the key that read out.
+
+ @retval EFI_SUCCESS The key is read out successfully.
+ @retval other The key reading failed.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardReadKeyStroke (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ OUT EFI_INPUT_KEY *Key
+ );
+
+/**
+ Reads the next keystroke from the input device. The WaitForKey Event can
+ be used to test for existence of a keystroke via WaitForEvent () call.
+
+ @param This Protocol instance pointer.
+ @param KeyData A pointer to a buffer that is filled in with the keystroke
+ state data for the key that was pressed.
+
+ @retval EFI_SUCCESS The keystroke information was returned.
+ @retval EFI_NOT_READY There was no keystroke data available.
+ @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
+ hardware errors.
+ @retval EFI_INVALID_PARAMETER KeyData is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+VirtualKeyboardReadKeyStrokeEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ OUT EFI_KEY_DATA *KeyData
+ );
+
+#endif /* _VIRTUAL_KEYBOARD_H_ */
diff --git a/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/VirtualKeyboardDxe.inf b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/VirtualKeyboardDxe.inf
new file mode 100644
index 00000000..e74b3069
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/EmbeddedPkg/Drivers/VirtualKeyboardDxe/VirtualKeyboardDxe.inf
@@ -0,0 +1,54 @@
+## @file
+# Virtual Keyboard driver.
+#
+# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2018, Linaro Ltd. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010019
+ BASE_NAME = VirtualKeyboardDxe
+ FILE_GUID = 88079b18-b42b-44aa-a6f2-b83911075e89
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeVirtualKeyboard
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64
+#
+# DRIVER_BINDING = gVirtualKeyboardDriverBinding
+# COMPONENT_NAME = gVirtualKeyboardComponentName
+#
+
+[Sources.common]
+ ComponentName.c
+ VirtualKeyboard.c
+
+[Packages]
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ IoLib
+ ReportStatusCodeLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+
+[Protocols]
+ gEfiDriverBindingProtocolGuid
+ gEfiSimpleTextInProtocolGuid
+ gEfiSimpleTextInputExProtocolGuid
+ gPlatformVirtualKeyboardProtocolGuid
+
+[Depex]
+ TRUE