From a5cc178aeb1a59e446bcd20f9dd8a53b475664d9 Mon Sep 17 00:00:00 2001 From: Hao Wu Date: Mon, 18 Mar 2019 10:43:27 +0800 Subject: [PATCH] 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 Cc: Ray Ni Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Hao Wu Acked-by: Ard Biesheuvel Acked-by: Laszlo Ersek Tested-by: Anthony PERARD --- OvmfPkg/OvmfPkgIa32.dsc | 1 + OvmfPkg/OvmfPkgIa32X64.dsc | 1 + OvmfPkg/OvmfPkgX64.dsc | 1 + OvmfPkg/SioBusDxe/ComponentName.c | 167 ++++++++ OvmfPkg/SioBusDxe/SioBusDxe.c | 622 ++++++++++++++++++++++++++++++ OvmfPkg/SioBusDxe/SioBusDxe.h | 332 ++++++++++++++++ OvmfPkg/SioBusDxe/SioBusDxe.inf | 54 +++ OvmfPkg/SioBusDxe/SioBusDxe.uni | 21 + OvmfPkg/SioBusDxe/SioService.c | 405 +++++++++++++++++++ OvmfPkg/SioBusDxe/SioService.h | 221 +++++++++++ 10 files changed, 1825 insertions(+) create mode 100644 OvmfPkg/SioBusDxe/ComponentName.c create mode 100644 OvmfPkg/SioBusDxe/SioBusDxe.c create mode 100644 OvmfPkg/SioBusDxe/SioBusDxe.h create mode 100644 OvmfPkg/SioBusDxe/SioBusDxe.inf create mode 100644 OvmfPkg/SioBusDxe/SioBusDxe.uni create mode 100644 OvmfPkg/SioBusDxe/SioService.c create mode 100644 OvmfPkg/SioBusDxe/SioService.h 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.
+ + 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.
+ + 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.
+ + 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 + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#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.
+# +# 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.
+// +// 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.
+ + 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.
+ + 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__ -- 2.39.2