summaryrefslogtreecommitdiffstats
path: root/OvmfPkg
diff options
context:
space:
mode:
authorHao Wu <hao.a.wu@intel.com>2019-03-18 10:43:27 +0800
committerHao Wu <hao.a.wu@intel.com>2019-03-27 13:13:56 +0800
commita5cc178aeb1a59e446bcd20f9dd8a53b475664d9 (patch)
tree7cea45474dcb012f253aba9c8917702862d0dcb2 /OvmfPkg
parente259ad9b64528aab3840e7b7b50284ee5f5a4242 (diff)
downloadedk2-a5cc178aeb1a59e446bcd20f9dd8a53b475664d9.tar.gz
edk2-a5cc178aeb1a59e446bcd20f9dd8a53b475664d9.tar.bz2
edk2-a5cc178aeb1a59e446bcd20f9dd8a53b475664d9.zip
OvmfPkg: Add an Super IO bus driver
REF:https://bugzilla.tianocore.org/show_bug.cgi?id=1495 There is a plan to remove the IntelFrameworkModulePkg: https://bugzilla.tianocore.org/show_bug.cgi?id=1605 This patch will a new OVMF Super I/O bus driver which will create the below child devices: * COM 1 UART * COM 2 UART * PS/2 Keyboard and installs the Super I/O Protocol on them. Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Ray Ni <ray.ni@intel.com> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Hao Wu <hao.a.wu@intel.com> Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Acked-by: Laszlo Ersek <lersek@redhat.com> Tested-by: Anthony PERARD <anthony.perard@citrix.com>
Diffstat (limited to 'OvmfPkg')
-rw-r--r--OvmfPkg/OvmfPkgIa32.dsc1
-rw-r--r--OvmfPkg/OvmfPkgIa32X64.dsc1
-rw-r--r--OvmfPkg/OvmfPkgX64.dsc1
-rw-r--r--OvmfPkg/SioBusDxe/ComponentName.c167
-rw-r--r--OvmfPkg/SioBusDxe/SioBusDxe.c622
-rw-r--r--OvmfPkg/SioBusDxe/SioBusDxe.h332
-rw-r--r--OvmfPkg/SioBusDxe/SioBusDxe.inf54
-rw-r--r--OvmfPkg/SioBusDxe/SioBusDxe.uni21
-rw-r--r--OvmfPkg/SioBusDxe/SioService.c405
-rw-r--r--OvmfPkg/SioBusDxe/SioService.h221
10 files changed, 1825 insertions, 0 deletions
diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
index 1710ab5a88..3be0314146 100644
--- a/OvmfPkg/OvmfPkgIa32.dsc
+++ b/OvmfPkg/OvmfPkgIa32.dsc
@@ -752,6 +752,7 @@
#
# ISA Support
#
+ OvmfPkg/SioBusDxe/SioBusDxe.inf
PcAtChipsetPkg/IsaAcpiDxe/IsaAcpi.inf
IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.inf
IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/IsaSerialDxe.inf
diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
index 5bceef3116..3b85c2e6af 100644
--- a/OvmfPkg/OvmfPkgIa32X64.dsc
+++ b/OvmfPkg/OvmfPkgIa32X64.dsc
@@ -761,6 +761,7 @@
#
# ISA Support
#
+ OvmfPkg/SioBusDxe/SioBusDxe.inf
PcAtChipsetPkg/IsaAcpiDxe/IsaAcpi.inf
IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.inf
IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/IsaSerialDxe.inf
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index 3f5d948dbb..104b2e79a5 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -759,6 +759,7 @@
#
# ISA Support
#
+ OvmfPkg/SioBusDxe/SioBusDxe.inf
PcAtChipsetPkg/IsaAcpiDxe/IsaAcpi.inf
IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.inf
IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/IsaSerialDxe.inf
diff --git a/OvmfPkg/SioBusDxe/ComponentName.c b/OvmfPkg/SioBusDxe/ComponentName.c
new file mode 100644
index 0000000000..668a2c6a7a
--- /dev/null
+++ b/OvmfPkg/SioBusDxe/ComponentName.c
@@ -0,0 +1,167 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for SioBusDxe driver.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "SioBusDxe.h"
+
+//
+// Driver name table
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSioBusDriverNameTable[] = {
+ { "eng;en", L"OVMF Sio Bus Driver" },
+ { NULL , NULL }
+};
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gSioBusComponentName = {
+ SioBusComponentNameGetDriverName,
+ SioBusComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSioBusComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SioBusComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SioBusComponentNameGetControllerName,
+ "en"
+};
+
+
+/**
+ 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL
+ or EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param[in] Language 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[out] DriverName 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
+SioBusComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mSioBusDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gSioBusComponentName)
+ );
+}
+
+/**
+ 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL
+ or EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param[in] ControllerHandle 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[in] ChildHandle 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[in] Language 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[out] ControllerName 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
+SioBusComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/OvmfPkg/SioBusDxe/SioBusDxe.c b/OvmfPkg/SioBusDxe/SioBusDxe.c
new file mode 100644
index 0000000000..0cf9a2b524
--- /dev/null
+++ b/OvmfPkg/SioBusDxe/SioBusDxe.c
@@ -0,0 +1,622 @@
+/** @file
+ The SioBusDxe driver is used to create child devices on the ISA bus and
+ installs the Super I/O protocols on them.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "SioBusDxe.h"
+
+//
+// SioBus Driver Binding Protocol
+//
+EFI_DRIVER_BINDING_PROTOCOL gSioBusDriverBinding = {
+ SioBusDriverBindingSupported,
+ SioBusDriverBindingStart,
+ SioBusDriverBindingStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is
+ provided, it further tests to see if this driver supports creating a handle
+ for the specified child device.
+
+ This function checks to see if the driver specified by This supports the
+ device specified by ControllerHandle. Drivers will typically use the device
+ path attached to ControllerHandle and/or the services from the bus I/O
+ abstraction attached to ControllerHandle to determine if the driver supports
+ ControllerHandle. This function may be called many times during platform
+ initialization. In order to reduce boot times, the tests performed by this
+ function must be very small, and take as little time as possible to execute.
+ This function must not change the state of any hardware devices, and this
+ function must be aware that the device specified by ControllerHandle may
+ already be managed by the same driver or a different driver. This function
+ must match its calls to AllocatePages() with FreePages(), AllocatePool() with
+ FreePool(), and OpenProtocol() with CloseProtocol(). Since ControllerHandle
+ may have been previously started by the same driver, if a protocol is already
+ in the opened state, then it must not be closed with CloseProtocol(). This is
+ required to guarantee the state of ControllerHandle is not modified by this
+ function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
+ instance.
+ @param[in] ControllerHandle The handle of the controller to test. This
+ handle must support a protocol interface
+ that supplies an I/O abstraction to the
+ driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a
+ device path. This parameter is ignored by
+ device drivers, and is optional for bus
+ drivers. For bus drivers, if this parameter
+ is not NULL, then the bus driver must
+ determine if the bus controller specified by
+ ControllerHandle and the child controller
+ specified by RemainingDevicePath are both
+ supported by this bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the
+ driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed
+ by the driver specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed
+ by a different driver or an application that
+ requires exclusive access.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the
+ driver specified by This.
+
+**/
+EFI_STATUS
+EFIAPI
+SioBusDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 Pci;
+ UINTN SegmentNumber;
+ UINTN BusNumber;
+ UINTN DeviceNumber;
+ UINTN FunctionNumber;
+
+ //
+ // Get PciIo protocol instance
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID**)&PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof(Pci) / sizeof(UINT32),
+ &Pci);
+
+ if (!EFI_ERROR (Status)) {
+ Status = EFI_UNSUPPORTED;
+ if ((Pci.Hdr.Command & 0x03) == 0x03) {
+ if (Pci.Hdr.ClassCode[2] == PCI_CLASS_BRIDGE) {
+ //
+ // See if this is a standard PCI to ISA Bridge from the Base Code and
+ // Class Code
+ //
+ if (Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA) {
+ Status = EFI_SUCCESS;
+ }
+
+ //
+ // See if this is an Intel PCI to ISA bridge in Positive Decode Mode
+ //
+ if (Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA_PDECODE &&
+ Pci.Hdr.VendorId == 0x8086) {
+ //
+ // See if this is on Function #0 to avoid false positives on
+ // PCI_CLASS_BRIDGE_OTHER that has the same value as
+ // PCI_CLASS_BRIDGE_ISA_PDECODE
+ //
+ Status = PciIo->GetLocation (
+ PciIo,
+ &SegmentNumber,
+ &BusNumber,
+ &DeviceNumber,
+ &FunctionNumber
+ );
+ if (!EFI_ERROR (Status) && FunctionNumber == 0) {
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_UNSUPPORTED;
+ }
+ }
+ }
+ }
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+/**
+ Starts a device controller or a bus controller.
+
+ The Start() function is designed to be invoked from the EFI boot service
+ ConnectController(). As a result, much of the error checking on the
+ parameters to Start() has been moved into this common boot service. It is
+ legal to call Start() from other locations, but the following calling
+ restrictions must be followed or the system behavior will not be
+ deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE.
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a
+ naturally aligned EFI_DEVICE_PATH_PROTOCOL.
+ 3. Prior to calling Start(), the Supported() function for the driver
+ specified by This must have been called with the same calling parameters,
+ and Supported() must have returned EFI_SUCCESS.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
+ instance.
+ @param[in] ControllerHandle The handle of the controller to start. This
+ handle must support a protocol interface
+ that supplies an I/O abstraction to the
+ driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a
+ device path. This parameter is ignored by
+ device drivers, and is optional for bus
+ drivers. For a bus driver, if this parameter
+ is NULL, then handles for all the children
+ of Controller are created by this driver. If
+ this parameter is not NULL and the first
+ Device Path Node is not the End of Device
+ Path Node, then only the handle for the
+ child device specified by the first Device
+ Path Node of RemainingDevicePath is created
+ by this driver. If the first Device Path
+ Node of RemainingDevicePath is the End of
+ Device Path Node, no child handle is created
+ by this driver.
+
+ @retval EFI_SUCCESS The device was started.
+ @retval EFI_DEVICE_ERROR The device could not be started due to a
+ device error.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+ @retval Others The driver failded to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+SioBusDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ UINT64 Supports;
+ UINT64 OriginalAttributes;
+ UINT64 Attributes;
+ BOOLEAN Enabled;
+ SIO_BUS_DRIVER_PRIVATE_DATA *Private;
+ UINT32 ChildDeviceNumber;
+
+ Enabled = FALSE;
+ Supports = 0;
+ OriginalAttributes = 0;
+ Private = NULL;
+
+ //
+ // Open the PCI I/O Protocol Interface
+ //
+ PciIo = NULL;
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID**) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Open Device Path Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return Status;
+ }
+
+ //
+ // Get supported PCI attributes
+ //
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Supports &= (UINT64) (EFI_PCI_IO_ATTRIBUTE_ISA_IO |
+ EFI_PCI_IO_ATTRIBUTE_ISA_IO_16);
+ if (Supports == 0 ||
+ Supports == (EFI_PCI_IO_ATTRIBUTE_ISA_IO |
+ EFI_PCI_IO_ATTRIBUTE_ISA_IO_16)) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationGet,
+ 0,
+ &OriginalAttributes
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Attributes = EFI_PCI_DEVICE_ENABLE |
+ Supports |
+ EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO;
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ Attributes,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Enabled = TRUE;
+
+ //
+ // Store the OriginalAttributes for the restore in BindingStop()
+ //
+ Private = AllocateZeroPool (sizeof (SIO_BUS_DRIVER_PRIVATE_DATA));
+ if (Private == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ Private->PciIo = PciIo;
+ Private->OriginalAttributes = OriginalAttributes;
+
+ Status = gBS->InstallProtocolInterface (
+ &Controller,
+ &gEfiCallerIdGuid,
+ EFI_NATIVE_INTERFACE,
+ Private
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Report status code for the start of general controller initialization
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_LPC | EFI_IOB_PC_INIT),
+ ParentDevicePath
+ );
+
+ //
+ // Report status code for the start of enabling devices on the bus
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_LPC | EFI_IOB_PC_ENABLE),
+ ParentDevicePath
+ );
+
+ //
+ // Create all the children upon the first entrance
+ //
+ ChildDeviceNumber = SioCreateAllChildDevices (
+ This,
+ Controller,
+ PciIo,
+ ParentDevicePath
+ );
+ if (ChildDeviceNumber == 0) {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+Done:
+ if (EFI_ERROR (Status)) {
+ if (PciIo != NULL && Enabled) {
+ PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSet,
+ OriginalAttributes,
+ NULL
+ );
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ if (Private != NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiCallerIdGuid,
+ Private,
+ NULL
+ );
+ FreePool (Private);
+ }
+
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Stops a device controller or a bus controller.
+
+ The Stop() function is designed to be invoked from the EFI boot service
+ DisconnectController(). As a result, much of the error checking on the
+ parameters to Stop() has been moved into this common boot service. It is
+ legal to call Stop() from other locations, but the following calling
+ restrictions must be followed or the system behavior will not be
+ deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous
+ call to this same driver's Start() function.
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a
+ valid EFI_HANDLE. In addition, all of these handles must have been created
+ in this driver's Start() function, and the Start() function must have
+ called OpenProtocol() on ControllerHandle with an Attribute of
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
+ instance.
+ @param[in] ControllerHandle A handle to the device being stopped. The
+ handle must support a bus specific I/O
+ protocol for the driver to use to stop the
+ device.
+ @param[in] NumberOfChildren The number of child device handles in
+ ChildHandleBuffer.
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be
+ NULL if NumberOfChildren is 0.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a
+ device error.
+
+**/
+EFI_STATUS
+EFIAPI
+SioBusDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ SIO_BUS_DRIVER_PRIVATE_DATA *Private;
+ UINTN Index;
+ BOOLEAN AllChildrenStopped;
+ EFI_SIO_PROTOCOL *Sio;
+ SIO_DEV *SioDevice;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ if (NumberOfChildren == 0) {
+ //
+ // Restore PCI attributes
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiCallerIdGuid,
+ (VOID **) &Private,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = Private->PciIo->Attributes (
+ Private->PciIo,
+ EfiPciIoAttributeOperationSet,
+ Private->OriginalAttributes,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiCallerIdGuid,
+ Private
+ );
+ FreePool (Private);
+
+ //
+ // Close the bus driver
+ //
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Stop all the children
+ //
+ AllChildrenStopped = TRUE;
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+ Status = gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiSioProtocolGuid,
+ (VOID **) &Sio,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ SioDevice = SIO_DEV_FROM_SIO (Sio);
+
+ //
+ // Close the child handle
+ //
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index]
+ );
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ SioDevice->DevicePath,
+ &gEfiSioProtocolGuid,
+ &SioDevice->Sio,
+ NULL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ FreePool (SioDevice->DevicePath);
+ FreePool (SioDevice);
+ } else {
+ //
+ // Re-open PCI IO Protocol on behalf of the child device
+ // because of failure of destroying the child device handle
+ //
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ }
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The entry point for the SioBusDxe driver.
+
+ @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
+SioBusDxeDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ //
+ // Install driver model protocol(s).
+ //
+ return EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gSioBusDriverBinding,
+ ImageHandle,
+ &gSioBusComponentName,
+ &gSioBusComponentName2
+ );
+}
diff --git a/OvmfPkg/SioBusDxe/SioBusDxe.h b/OvmfPkg/SioBusDxe/SioBusDxe.h
new file mode 100644
index 0000000000..1455c48f63
--- /dev/null
+++ b/OvmfPkg/SioBusDxe/SioBusDxe.h
@@ -0,0 +1,332 @@
+/** @file
+ The SioBusDxe driver is used to create child devices on the ISA bus and
+ installs the Super I/O protocols on them.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __SIO_BUS_DXE_H__
+#define __SIO_BUS_DXE_H__
+
+#include <Uefi.h>
+
+#include <IndustryStandard/Pci.h>
+
+#include <Protocol/PciIo.h>
+#include <Protocol/SuperIo.h>
+
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DevicePathLib.h>
+
+#include "SioService.h"
+
+//
+// SIO Bus driver private data structure
+//
+typedef struct {
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT64 OriginalAttributes;
+} SIO_BUS_DRIVER_PRIVATE_DATA;
+
+
+//
+// Global Variables
+//
+extern EFI_COMPONENT_NAME_PROTOCOL gSioBusComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gSioBusComponentName2;
+
+
+//
+// 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL
+ or EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param[in] Language 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[out] DriverName 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
+SioBusComponentNameGetDriverName (
+ 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[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL
+ or EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param[in] ControllerHandle 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[in] ChildHandle 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[in] Language 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[out] ControllerName 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
+SioBusComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+//
+// Driver Binding Protocol interfaces
+//
+
+/**
+ Tests to see if this driver supports a given controller. If a child device is
+ provided, it further tests to see if this driver supports creating a handle
+ for the specified child device.
+
+ This function checks to see if the driver specified by This supports the
+ device specified by ControllerHandle. Drivers will typically use the device
+ path attached to ControllerHandle and/or the services from the bus I/O
+ abstraction attached to ControllerHandle to determine if the driver supports
+ ControllerHandle. This function may be called many times during platform
+ initialization. In order to reduce boot times, the tests performed by this
+ function must be very small, and take as little time as possible to execute.
+ This function must not change the state of any hardware devices, and this
+ function must be aware that the device specified by ControllerHandle may
+ already be managed by the same driver or a different driver. This function
+ must match its calls to AllocatePages() with FreePages(), AllocatePool() with
+ FreePool(), and OpenProtocol() with CloseProtocol(). Since ControllerHandle
+ may have been previously started by the same driver, if a protocol is already
+ in the opened state, then it must not be closed with CloseProtocol(). This is
+ required to guarantee the state of ControllerHandle is not modified by this
+ function.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
+ instance.
+ @param[in] ControllerHandle The handle of the controller to test. This
+ handle must support a protocol interface
+ that supplies an I/O abstraction to the
+ driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a
+ device path. This parameter is ignored by
+ device drivers, and is optional for bus
+ drivers. For bus drivers, if this parameter
+ is not NULL, then the bus driver must
+ determine if the bus controller specified by
+ ControllerHandle and the child controller
+ specified by RemainingDevicePath are both
+ supported by this bus driver.
+
+ @retval EFI_SUCCESS The device specified by ControllerHandle and
+ RemainingDevicePath is supported by the
+ driver specified by This.
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed
+ by the driver specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed
+ by a different driver or an application that
+ requires exclusive access.
+ @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
+ RemainingDevicePath is not supported by the
+ driver specified by This.
+
+**/
+EFI_STATUS
+EFIAPI
+SioBusDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starts a device controller or a bus controller.
+
+ The Start() function is designed to be invoked from the EFI boot service
+ ConnectController(). As a result, much of the error checking on the
+ parameters to Start() has been moved into this common boot service. It is
+ legal to call Start() from other locations, but the following calling
+ restrictions must be followed or the system behavior will not be
+ deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE.
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a
+ naturally aligned EFI_DEVICE_PATH_PROTOCOL.
+ 3. Prior to calling Start(), the Supported() function for the driver
+ specified by This must have been called with the same calling parameters,
+ and Supported() must have returned EFI_SUCCESS.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
+ instance.
+ @param[in] ControllerHandle The handle of the controller to start. This
+ handle must support a protocol interface
+ that supplies an I/O abstraction to the
+ driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a
+ device path. This parameter is ignored by
+ device drivers, and is optional for bus
+ drivers. For a bus driver, if this parameter
+ is NULL, then handles for all the children
+ of Controller are created by this driver. If
+ this parameter is not NULL and the first
+ Device Path Node is not the End of Device
+ Path Node, then only the handle for the
+ child device specified by the first Device
+ Path Node of RemainingDevicePath is created
+ by this driver. If the first Device Path
+ Node of RemainingDevicePath is the End of
+ Device Path Node, no child handle is created
+ by this driver.
+
+ @retval EFI_SUCCESS The device was started.
+ @retval EFI_DEVICE_ERROR The device could not be started due to a
+ device error.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+ @retval Others The driver failded to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+SioBusDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stops a device controller or a bus controller.
+
+ The Stop() function is designed to be invoked from the EFI boot service
+ DisconnectController(). As a result, much of the error checking on the
+ parameters to Stop() has been moved into this common boot service. It is
+ legal to call Stop() from other locations, but the following calling
+ restrictions must be followed or the system behavior will not be
+ deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous
+ call to this same driver's Start() function.
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a
+ valid EFI_HANDLE. In addition, all of these handles must have been created
+ in this driver's Start() function, and the Start() function must have
+ called OpenProtocol() on ControllerHandle with an Attribute of
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
+ instance.
+ @param[in] ControllerHandle A handle to the device being stopped. The
+ handle must support a bus specific I/O
+ protocol for the driver to use to stop the
+ device.
+ @param[in] NumberOfChildren The number of child device handles in
+ ChildHandleBuffer.
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be
+ NULL if NumberOfChildren is 0.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a
+ device error.
+
+**/
+EFI_STATUS
+EFIAPI
+SioBusDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+#endif // __SIO_BUS_DXE_H__
diff --git a/OvmfPkg/SioBusDxe/SioBusDxe.inf b/OvmfPkg/SioBusDxe/SioBusDxe.inf
new file mode 100644
index 0000000000..5c462f1a8c
--- /dev/null
+++ b/OvmfPkg/SioBusDxe/SioBusDxe.inf
@@ -0,0 +1,54 @@
+## @file
+# The SioBusDxe driver is used to create child devices on the ISA bus and
+# installs the Super I/O protocols on them.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SioBusDxe
+ MODULE_UNI_FILE = SioBusDxe.uni
+ FILE_GUID = 864E1CA8-85EB-4D63-9DCC-6E0FC90FFD55
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = SioBusDxeDriverEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ ComponentName.c
+ SioService.c
+ SioService.h
+ SioBusDxe.c
+ SioBusDxe.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiLib
+ UefiBootServicesTableLib
+ DebugLib
+ ReportStatusCodeLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ DevicePathLib
+
+[Protocols]
+ gEfiPciIoProtocolGuid ## TO_START
+ gEfiSioProtocolGuid ## BY_START
diff --git a/OvmfPkg/SioBusDxe/SioBusDxe.uni b/OvmfPkg/SioBusDxe/SioBusDxe.uni
new file mode 100644
index 0000000000..4793180557
--- /dev/null
+++ b/OvmfPkg/SioBusDxe/SioBusDxe.uni
@@ -0,0 +1,21 @@
+// /** @file
+// The SioBusDxe driver is used to create child devices on the ISA bus and
+// installs the Super I/O protocols on them.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions
+// of the BSD License which accompanies this distribution. The
+// full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Manage ISA devices on the ISA bus"
+
+#string STR_MODULE_DESCRIPTION #language en-US "The SioBusDxe driver is used to create child devices on the ISA bus and installs the Super I/O protocols on them."
diff --git a/OvmfPkg/SioBusDxe/SioService.c b/OvmfPkg/SioBusDxe/SioService.c
new file mode 100644
index 0000000000..6a97a4a2c0
--- /dev/null
+++ b/OvmfPkg/SioBusDxe/SioService.c
@@ -0,0 +1,405 @@
+/** @file
+ The SioBusDxe driver is used to create child devices on the ISA bus and
+ installs the Super I/O protocols on them.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "SioBusDxe.h"
+
+//
+// Super I/O Protocol interfaces
+//
+EFI_SIO_PROTOCOL mSioInterface = {
+ SioRegisterAccess,
+ SioGetResources,
+ SioSetResources,
+ SioPossibleResources,
+ SioModify
+};
+
+//
+// COM 1 UART Controller
+//
+GLOBAL_REMOVE_IF_UNREFERENCED
+SIO_RESOURCES_IO mCom1Resources = {
+ { { ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR }, 0x3F8, 8 },
+ { ACPI_END_TAG_DESCRIPTOR, 0 }
+};
+
+//
+// COM 2 UART Controller
+//
+GLOBAL_REMOVE_IF_UNREFERENCED
+SIO_RESOURCES_IO mCom2Resources = {
+ { { ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR }, 0x2F8, 8 },
+ { ACPI_END_TAG_DESCRIPTOR, 0 }
+};
+
+//
+// PS/2 Keyboard Controller
+//
+GLOBAL_REMOVE_IF_UNREFERENCED
+SIO_RESOURCES_IO mPs2KeyboardDeviceResources = {
+ { { ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR }, 0x60, 5 },
+ { ACPI_END_TAG_DESCRIPTOR, 0 }
+};
+
+//
+// Table of SIO Controllers
+//
+GLOBAL_REMOVE_IF_UNREFERENCED
+SIO_DEVICE_INFO mDevicesInfo[] = {
+ {
+ EISA_PNP_ID (0x501),
+ 0,
+ { (ACPI_SMALL_RESOURCE_HEADER *) &mCom1Resources }
+ }, // COM 1 UART Controller
+ {
+ EISA_PNP_ID (0x501),
+ 1,
+ { (ACPI_SMALL_RESOURCE_HEADER *) &mCom2Resources }
+ }, // COM 2 UART Controller
+ {
+ EISA_PNP_ID(0x303),
+ 0,
+ { (ACPI_SMALL_RESOURCE_HEADER *) &mPs2KeyboardDeviceResources }
+ } // PS/2 Keyboard Controller
+};
+
+//
+// ACPI Device Path Node template
+//
+GLOBAL_REMOVE_IF_UNREFERENCED
+ACPI_HID_DEVICE_PATH mAcpiDeviceNodeTemplate = {
+ { // Header
+ ACPI_DEVICE_PATH,
+ ACPI_DP,
+ {
+ (UINT8) (sizeof (ACPI_HID_DEVICE_PATH)),
+ (UINT8) ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8)
+ }
+ },
+ 0x0, // HID
+ 0x0 // UID
+};
+
+
+/**
+ Provides a low level access to the registers for the Super I/O.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] Write Specifies the type of the register operation.
+ If this parameter is TRUE, Value is interpreted
+ as an input parameter and the operation is a
+ register write. If this parameter is FALSE,
+ Value is interpreted as an output parameter and
+ the operation is a register read.
+ @param[in] ExitCfgMode Exit Configuration Mode Indicator. If this
+ parameter is set to TRUE, the Super I/O driver
+ will turn off configuration mode of the Super
+ I/O prior to returning from this function. If
+ this parameter is set to FALSE, the Super I/O
+ driver will leave Super I/O in the
+ configuration mode. The Super I/O driver must
+ track the current state of the Super I/O and
+ enable the configuration mode of Super I/O if
+ necessary prior to register access.
+ @param[in] Register Register number.
+ @param[in,out] Value If Write is TRUE, Value is a pointer to the
+ buffer containing the byte of data to be
+ written to the Super I/O register. If Write is
+ FALSE, Value is a pointer to the destination
+ buffer for the byte of data to be read from the
+ Super I/O register.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER The Value is NULL.
+ @retval EFI_INVALID_PARAMETER Invalid Register number.
+
+**/
+EFI_STATUS
+EFIAPI
+SioRegisterAccess (
+ IN CONST EFI_SIO_PROTOCOL *This,
+ IN BOOLEAN Write,
+ IN BOOLEAN ExitCfgMode,
+ IN UINT8 Register,
+ IN OUT UINT8 *Value
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Provides an interface to get a list of the current resources consumed by the
+ device in the ACPI Resource Descriptor format.
+
+ GetResources() returns a list of resources currently consumed by the device.
+ The ResourceList is a pointer to the buffer containing resource descriptors
+ for the device. The descriptors are in the format of Small or Large ACPI
+ resource descriptor as defined by ACPI specification (2.0 & 3.0). The buffer
+ of resource descriptors is terminated with the 'End tag' resource descriptor.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[out] ResourceList A pointer to an ACPI resource descriptor list
+ that defines the current resources used by the
+ device.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER ResourceList is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+SioGetResources (
+ IN CONST EFI_SIO_PROTOCOL *This,
+ OUT ACPI_RESOURCE_HEADER_PTR *ResourceList
+ )
+{
+ SIO_DEV *SioDevice;
+
+ if (ResourceList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SioDevice = SIO_DEV_FROM_SIO (This);
+ if (SioDevice->DeviceIndex < ARRAY_SIZE (mDevicesInfo)) {
+ *ResourceList = mDevicesInfo[SioDevice->DeviceIndex].Resources;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Sets the resources for the device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] ResourceList Pointer to the ACPI resource descriptor list.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER ResourceList is invalid.
+ @retval EFI_ACCESS_DENIED Some of the resources in ResourceList are in
+ use.
+
+**/
+EFI_STATUS
+EFIAPI
+SioSetResources (
+ IN CONST EFI_SIO_PROTOCOL *This,
+ IN ACPI_RESOURCE_HEADER_PTR ResourceList
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Provides a collection of resource descriptor lists. Each resource descriptor
+ list in the collection defines a combination of resources that can
+ potentially be used by the device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[out] ResourceCollection Collection of the resource descriptor
+ lists.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER ResourceCollection is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+SioPossibleResources (
+ IN CONST EFI_SIO_PROTOCOL *This,
+ OUT ACPI_RESOURCE_HEADER_PTR *ResourceCollection
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Provides an interface for a table based programming of the Super I/O
+ registers.
+
+ The Modify() function provides an interface for table based programming of
+ the Super I/O registers. This function can be used to perform programming of
+ multiple Super I/O registers with a single function call. For each table
+ entry, the Register is read, its content is bitwise ANDed with AndMask, and
+ then ORed with OrMask before being written back to the Register. The Super
+ I/O driver must track the current state of the Super I/O and enable the
+ configuration mode of Super I/O if necessary prior to table processing. Once
+ the table is processed, the Super I/O device has to be returned to the
+ original state.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] Command A pointer to an array of NumberOfCommands
+ EFI_SIO_REGISTER_MODIFY structures. Each
+ structure specifies a single Super I/O register
+ modify operation.
+ @param[in] NumberOfCommands Number of elements in the Command array.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER Command is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+SioModify (
+ IN CONST EFI_SIO_PROTOCOL *This,
+ IN CONST EFI_SIO_REGISTER_MODIFY *Command,
+ IN UINTN NumberOfCommands
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Create the child device with a given device index.
+
+ @param[in] This The EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] Controller The handle of ISA bus controller.
+ @param[in] PciIo The pointer to the PCI protocol.
+ @param[in] ParentDevicePath Device path of the ISA bus controller.
+ @param[in] DeviceIndex Index of the device supported by this driver.
+
+ @retval EFI_SUCCESS The child device has been created successfully.
+ @retval Others Error occured during the child device creation.
+
+**/
+EFI_STATUS
+SioCreateChildDevice (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
+ IN UINT32 DeviceIndex
+ )
+{
+ EFI_STATUS Status;
+ SIO_DEV *SioDevice;
+
+ //
+ // Initialize the SIO_DEV structure
+ //
+ SioDevice = AllocateZeroPool (sizeof (SIO_DEV));
+ if (SioDevice == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SioDevice->Signature = SIO_DEV_SIGNATURE;
+ SioDevice->Handle = NULL;
+ SioDevice->PciIo = PciIo;
+
+ //
+ // Construct the child device path
+ //
+ mAcpiDeviceNodeTemplate.HID = mDevicesInfo[DeviceIndex].Hid;
+ mAcpiDeviceNodeTemplate.UID = mDevicesInfo[DeviceIndex].Uid;
+ SioDevice->DevicePath = AppendDevicePathNode (
+ ParentDevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &mAcpiDeviceNodeTemplate
+ );
+ if (SioDevice->DevicePath == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ CopyMem (&SioDevice->Sio, &mSioInterface, sizeof (EFI_SIO_PROTOCOL));
+ SioDevice->DeviceIndex = DeviceIndex;
+
+ //
+ // Create a child handle and install Device Path and Super I/O protocols
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &SioDevice->Handle,
+ &gEfiDevicePathProtocolGuid,
+ SioDevice->DevicePath,
+ &gEfiSioProtocolGuid,
+ &SioDevice->Sio,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ SioDevice->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ SioDevice->Handle,
+ &gEfiDevicePathProtocolGuid,
+ SioDevice->DevicePath,
+ &gEfiSioProtocolGuid,
+ &SioDevice->Sio,
+ NULL
+ );
+ }
+
+Done:
+ if (EFI_ERROR (Status)) {
+ if (SioDevice->DevicePath != NULL) {
+ FreePool (SioDevice->DevicePath);
+ }
+
+ FreePool (SioDevice);
+ }
+
+ return Status;
+}
+
+/**
+ Create all the ISA child devices on the ISA bus controller (PCI to ISA
+ bridge).
+
+ @param[in] This The EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] Controller The handle of ISA bus controller.
+ @param[in] PciIo The pointer to the PCI protocol.
+ @param[in] ParentDevicePath Device path of the ISA bus controller.
+
+ @retval The number of child device that is successfully created.
+
+**/
+UINT32
+SioCreateAllChildDevices (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath
+ )
+{
+ UINT32 Index;
+ UINT32 ChildDeviceNumber;
+ EFI_STATUS Status;
+
+ ChildDeviceNumber = 0;
+
+ for (Index = 0; Index < ARRAY_SIZE (mDevicesInfo); Index++) {
+ Status = SioCreateChildDevice (
+ This,
+ Controller,
+ PciIo,
+ ParentDevicePath,
+ Index
+ );
+ if (!EFI_ERROR (Status)) {
+ ChildDeviceNumber++;
+ }
+ }
+
+ return ChildDeviceNumber;
+}
diff --git a/OvmfPkg/SioBusDxe/SioService.h b/OvmfPkg/SioBusDxe/SioService.h
new file mode 100644
index 0000000000..758703dd89
--- /dev/null
+++ b/OvmfPkg/SioBusDxe/SioService.h
@@ -0,0 +1,221 @@
+/** @file
+ The SioBusDxe driver is used to create child devices on the ISA bus and
+ installs the Super I/O protocols on them.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __SIO_SERVICE_H__
+#define __SIO_SERVICE_H__
+
+#pragma pack(1)
+
+typedef struct {
+ EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR Io;
+ EFI_ACPI_END_TAG_DESCRIPTOR End;
+} SIO_RESOURCES_IO;
+
+#pragma pack()
+
+typedef struct {
+ UINT32 Hid;
+ UINT32 Uid;
+ ACPI_RESOURCE_HEADER_PTR Resources;
+} SIO_DEVICE_INFO;
+
+//
+// SIO device private data structure
+//
+typedef struct {
+ UINT32 Signature;
+ EFI_HANDLE Handle;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ EFI_SIO_PROTOCOL Sio;
+ UINT32 DeviceIndex;
+} SIO_DEV;
+#define SIO_DEV_SIGNATURE SIGNATURE_32 ('S', 'I', 'O', 'D')
+#define SIO_DEV_FROM_SIO(a) CR (a, SIO_DEV, Sio, SIO_DEV_SIGNATURE)
+
+
+//
+// Super I/O Protocol interfaces
+//
+
+/**
+ Provides a low level access to the registers for the Super I/O.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] Write Specifies the type of the register operation.
+ If this parameter is TRUE, Value is interpreted
+ as an input parameter and the operation is a
+ register write. If this parameter is FALSE,
+ Value is interpreted as an output parameter and
+ the operation is a register read.
+ @param[in] ExitCfgMode Exit Configuration Mode Indicator. If this
+ parameter is set to TRUE, the Super I/O driver
+ will turn off configuration mode of the Super
+ I/O prior to returning from this function. If
+ this parameter is set to FALSE, the Super I/O
+ driver will leave Super I/O in the
+ configuration mode. The Super I/O driver must
+ track the current state of the Super I/O and
+ enable the configuration mode of Super I/O if
+ necessary prior to register access.
+ @param[in] Register Register number.
+ @param[in,out] Value If Write is TRUE, Value is a pointer to the
+ buffer containing the byte of data to be
+ written to the Super I/O register. If Write is
+ FALSE, Value is a pointer to the destination
+ buffer for the byte of data to be read from the
+ Super I/O register.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER The Value is NULL.
+ @retval EFI_INVALID_PARAMETER Invalid Register number.
+
+**/
+EFI_STATUS
+EFIAPI
+SioRegisterAccess (
+ IN CONST EFI_SIO_PROTOCOL *This,
+ IN BOOLEAN Write,
+ IN BOOLEAN ExitCfgMode,
+ IN UINT8 Register,
+ IN OUT UINT8 *Value
+ );
+
+/**
+ Provides an interface to get a list of the current resources consumed by the
+ device in the ACPI Resource Descriptor format.
+
+ GetResources() returns a list of resources currently consumed by the device.
+ The ResourceList is a pointer to the buffer containing resource descriptors
+ for the device. The descriptors are in the format of Small or Large ACPI
+ resource descriptor as defined by ACPI specification (2.0 & 3.0). The buffer
+ of resource descriptors is terminated with the 'End tag' resource descriptor.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[out] ResourceList A pointer to an ACPI resource descriptor list
+ that defines the current resources used by the
+ device.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER ResourceList is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+SioGetResources (
+ IN CONST EFI_SIO_PROTOCOL *This,
+ OUT ACPI_RESOURCE_HEADER_PTR *ResourceList
+ );
+
+/**
+ Sets the resources for the device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] ResourceList Pointer to the ACPI resource descriptor list.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER ResourceList is invalid.
+ @retval EFI_ACCESS_DENIED Some of the resources in ResourceList are in
+ use.
+
+**/
+EFI_STATUS
+EFIAPI
+SioSetResources (
+ IN CONST EFI_SIO_PROTOCOL *This,
+ IN ACPI_RESOURCE_HEADER_PTR ResourceList
+ );
+
+/**
+ Provides a collection of resource descriptor lists. Each resource descriptor
+ list in the collection defines a combination of resources that can
+ potentially be used by the device.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[out] ResourceCollection Collection of the resource descriptor
+ lists.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER ResourceCollection is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+SioPossibleResources (
+ IN CONST EFI_SIO_PROTOCOL *This,
+ OUT ACPI_RESOURCE_HEADER_PTR *ResourceCollection
+ );
+
+/**
+ Provides an interface for a table based programming of the Super I/O
+ registers.
+
+ The Modify() function provides an interface for table based programming of
+ the Super I/O registers. This function can be used to perform programming of
+ multiple Super I/O registers with a single function call. For each table
+ entry, the Register is read, its content is bitwise ANDed with AndMask, and
+ then ORed with OrMask before being written back to the Register. The Super
+ I/O driver must track the current state of the Super I/O and enable the
+ configuration mode of Super I/O if necessary prior to table processing. Once
+ the table is processed, the Super I/O device has to be returned to the
+ original state.
+
+ @param[in] This Indicates a pointer to the calling context.
+ @param[in] Command A pointer to an array of NumberOfCommands
+ EFI_SIO_REGISTER_MODIFY structures. Each
+ structure specifies a single Super I/O register
+ modify operation.
+ @param[in] NumberOfCommands Number of elements in the Command array.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_INVALID_PARAMETER Command is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+SioModify (
+ IN CONST EFI_SIO_PROTOCOL *This,
+ IN CONST EFI_SIO_REGISTER_MODIFY *Command,
+ IN UINTN NumberOfCommands
+ );
+
+//
+// Internal functions
+//
+
+/**
+ Create all the ISA child devices on the ISA bus controller (PCI to ISA
+ bridge).
+
+ @param[in] This The EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] Controller The handle of ISA bus controller.
+ @param[in] PciIo The pointer to the PCI protocol.
+ @param[in] ParentDevicePath Device path of the ISA bus controller.
+
+ @retval The number of child device that is successfully created.
+
+**/
+UINT32
+SioCreateAllChildDevices (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath
+ );
+
+#endif // __SIO_SERVICE_H__