summaryrefslogtreecommitdiffstats
path: root/OvmfPkg/Csm/LegacyBiosDxe/LegacySio.c
diff options
context:
space:
mode:
Diffstat (limited to 'OvmfPkg/Csm/LegacyBiosDxe/LegacySio.c')
-rw-r--r--OvmfPkg/Csm/LegacyBiosDxe/LegacySio.c477
1 files changed, 477 insertions, 0 deletions
diff --git a/OvmfPkg/Csm/LegacyBiosDxe/LegacySio.c b/OvmfPkg/Csm/LegacyBiosDxe/LegacySio.c
new file mode 100644
index 0000000000..17720a74f7
--- /dev/null
+++ b/OvmfPkg/Csm/LegacyBiosDxe/LegacySio.c
@@ -0,0 +1,477 @@
+/** @file
+ Collect Sio information from Native EFI Drivers.
+ Sio is floppy, parallel, serial, ... hardware
+
+Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "LegacyBiosInterface.h"
+
+/**
+ Collect EFI Info about legacy devices through Super IO interface.
+
+ @param SioPtr Pointer to SIO data.
+
+ @retval EFI_SUCCESS When SIO data is got successfully.
+ @retval EFI_NOT_FOUND When ISA IO interface is absent.
+
+**/
+EFI_STATUS
+LegacyBiosBuildSioDataFromSio (
+ IN DEVICE_PRODUCER_DATA_HEADER *SioPtr
+ )
+{
+ EFI_STATUS Status;
+ DEVICE_PRODUCER_SERIAL *SioSerial;
+ DEVICE_PRODUCER_PARALLEL *SioParallel;
+ DEVICE_PRODUCER_FLOPPY *SioFloppy;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+ UINTN ChildIndex;
+ EFI_SIO_PROTOCOL *Sio;
+ ACPI_RESOURCE_HEADER_PTR Resources;
+ EFI_ACPI_IO_PORT_DESCRIPTOR *IoResource;
+ EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *FixedIoResource;
+ EFI_ACPI_DMA_DESCRIPTOR *DmaResource;
+ EFI_ACPI_IRQ_NOFLAG_DESCRIPTOR *IrqResource;
+ UINT16 Address;
+ UINT8 Dma;
+ UINT8 Irq;
+ UINTN EntryCount;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ ACPI_HID_DEVICE_PATH *Acpi;
+
+ //
+ // Get the list of ISA controllers in the system
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSioProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Collect legacy information from each of the ISA controllers in the system
+ //
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiSioProtocolGuid, (VOID **) &Sio);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Address = MAX_UINT16;
+ Dma = MAX_UINT8;
+ Irq = MAX_UINT8;
+ Status = Sio->GetResources (Sio, &Resources);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Get the base address information from ACPI resource descriptor.
+ //
+ while (Resources.SmallHeader->Byte != ACPI_END_TAG_DESCRIPTOR) {
+ switch (Resources.SmallHeader->Byte) {
+ case ACPI_IO_PORT_DESCRIPTOR:
+ IoResource = (EFI_ACPI_IO_PORT_DESCRIPTOR *) Resources.SmallHeader;
+ Address = IoResource->BaseAddressMin;
+ break;
+
+ case ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR:
+ FixedIoResource = (EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *) Resources.SmallHeader;
+ Address = FixedIoResource->BaseAddress;
+ break;
+
+ case ACPI_DMA_DESCRIPTOR:
+ DmaResource = (EFI_ACPI_DMA_DESCRIPTOR *) Resources.SmallHeader;
+ Dma = (UINT8) LowBitSet32 (DmaResource->ChannelMask);
+ break;
+
+ case ACPI_IRQ_DESCRIPTOR:
+ case ACPI_IRQ_NOFLAG_DESCRIPTOR:
+ IrqResource = (EFI_ACPI_IRQ_NOFLAG_DESCRIPTOR *) Resources.SmallHeader;
+ Irq = (UINT8) LowBitSet32 (IrqResource->Mask);
+ break;
+
+ default:
+ break;
+ }
+
+ if (Resources.SmallHeader->Bits.Type == 0) {
+ Resources.SmallHeader = (ACPI_SMALL_RESOURCE_HEADER *) ((UINT8 *) Resources.SmallHeader
+ + Resources.SmallHeader->Bits.Length
+ + sizeof (*Resources.SmallHeader));
+ } else {
+ Resources.LargeHeader = (ACPI_LARGE_RESOURCE_HEADER *) ((UINT8 *) Resources.LargeHeader
+ + Resources.LargeHeader->Length
+ + sizeof (*Resources.LargeHeader));
+ }
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "LegacySio: Address/Dma/Irq = %x/%d/%d\n", Address, Dma, Irq));
+
+ DevicePath = DevicePathFromHandle (HandleBuffer[Index]);
+ if (DevicePath == NULL) {
+ continue;
+ }
+
+ Acpi = NULL;
+ while (!IsDevicePathEnd (DevicePath)) {
+ Acpi = (ACPI_HID_DEVICE_PATH *) DevicePath;
+ DevicePath = NextDevicePathNode (DevicePath);
+ }
+
+ if ((Acpi == NULL) || (DevicePathType (Acpi) != ACPI_DEVICE_PATH) ||
+ ((DevicePathSubType (Acpi) != ACPI_DP) && (DevicePathSubType (Acpi) != ACPI_EXTENDED_DP))
+ ) {
+ continue;
+ }
+
+ //
+ // See if this is an ISA serial port
+ //
+ // Ignore DMA resource since it is always returned NULL
+ //
+ if (Acpi->HID == EISA_PNP_ID (0x500) || Acpi->HID == EISA_PNP_ID (0x501)) {
+
+ if (Acpi->UID < 4 && Address != MAX_UINT16 && Irq != MAX_UINT8) {
+ //
+ // Get the handle of the child device that has opened the Super I/O Protocol
+ //
+ Status = gBS->OpenProtocolInformation (
+ HandleBuffer[Index],
+ &gEfiSioProtocolGuid,
+ &OpenInfoBuffer,
+ &EntryCount
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ for (ChildIndex = 0; ChildIndex < EntryCount; ChildIndex++) {
+ if ((OpenInfoBuffer[ChildIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
+ Status = gBS->HandleProtocol (OpenInfoBuffer[ChildIndex].ControllerHandle, &gEfiSerialIoProtocolGuid, (VOID **) &SerialIo);
+ if (!EFI_ERROR (Status)) {
+ SioSerial = &SioPtr->Serial[Acpi->UID];
+ SioSerial->Address = Address;
+ SioSerial->Irq = Irq;
+ SioSerial->Mode = DEVICE_SERIAL_MODE_NORMAL | DEVICE_SERIAL_MODE_DUPLEX_HALF;
+ break;
+ }
+ }
+ }
+
+ FreePool (OpenInfoBuffer);
+ }
+ }
+ //
+ // See if this is an ISA parallel port
+ //
+ // Ignore DMA resource since it is always returned NULL, port
+ // only used in output mode.
+ //
+ if (Acpi->HID == EISA_PNP_ID (0x400) || Acpi->HID == EISA_PNP_ID (0x401)) {
+ if (Acpi->UID < 3 && Address != MAX_UINT16 && Irq != MAX_UINT8 && Dma != MAX_UINT8) {
+ SioParallel = &SioPtr->Parallel[Acpi->UID];
+ SioParallel->Address = Address;
+ SioParallel->Irq = Irq;
+ SioParallel->Dma = Dma;
+ SioParallel->Mode = DEVICE_PARALLEL_MODE_MODE_OUTPUT_ONLY;
+ }
+ }
+ //
+ // See if this is an ISA floppy controller
+ //
+ if (Acpi->HID == EISA_PNP_ID (0x604)) {
+ if (Address != MAX_UINT16 && Irq != MAX_UINT8 && Dma != MAX_UINT8) {
+ Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
+ if (!EFI_ERROR (Status)) {
+ SioFloppy = &SioPtr->Floppy;
+ SioFloppy->Address = Address;
+ SioFloppy->Irq = Irq;
+ SioFloppy->Dma = Dma;
+ SioFloppy->NumberOfFloppy++;
+ }
+ }
+ }
+ //
+ // See if this is a mouse
+ // Always set mouse found so USB hot plug will work
+ //
+ // Ignore lower byte of HID. Pnp0fxx is any type of mouse.
+ //
+ // Hid = ResourceList->Device.HID & 0xff00ffff;
+ // PnpId = EISA_PNP_ID(0x0f00);
+ // if (Hid == PnpId) {
+ // if (ResourceList->Device.UID == 1) {
+ // Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiSimplePointerProtocolGuid, &SimplePointer);
+ // if (!EFI_ERROR (Status)) {
+ //
+ SioPtr->MousePresent = 0x01;
+ //
+ // }
+ // }
+ // }
+ //
+ }
+
+ FreePool (HandleBuffer);
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Collect EFI Info about legacy devices through ISA IO interface.
+
+ @param SioPtr Pointer to SIO data.
+
+ @retval EFI_SUCCESS When SIO data is got successfully.
+ @retval EFI_NOT_FOUND When ISA IO interface is absent.
+
+**/
+EFI_STATUS
+LegacyBiosBuildSioDataFromIsaIo (
+ IN DEVICE_PRODUCER_DATA_HEADER *SioPtr
+ )
+{
+ EFI_STATUS Status;
+ DEVICE_PRODUCER_SERIAL *SioSerial;
+ DEVICE_PRODUCER_PARALLEL *SioParallel;
+ DEVICE_PRODUCER_FLOPPY *SioFloppy;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+ UINTN ResourceIndex;
+ UINTN ChildIndex;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+ EFI_ISA_ACPI_RESOURCE_LIST *ResourceList;
+ EFI_ISA_ACPI_RESOURCE *IoResource;
+ EFI_ISA_ACPI_RESOURCE *DmaResource;
+ EFI_ISA_ACPI_RESOURCE *InterruptResource;
+ UINTN EntryCount;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;
+
+ //
+ // Get the list of ISA controllers in the system
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiIsaIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Collect legacy information from each of the ISA controllers in the system
+ //
+ for (Index = 0; Index < HandleCount; Index++) {
+
+ Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiIsaIoProtocolGuid, (VOID **) &IsaIo);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ ResourceList = IsaIo->ResourceList;
+
+ if (ResourceList == NULL) {
+ continue;
+ }
+ //
+ // Collect the resource types neededto fill in the SIO data structure
+ //
+ IoResource = NULL;
+ DmaResource = NULL;
+ InterruptResource = NULL;
+ for (ResourceIndex = 0;
+ ResourceList->ResourceItem[ResourceIndex].Type != EfiIsaAcpiResourceEndOfList;
+ ResourceIndex++
+ ) {
+ switch (ResourceList->ResourceItem[ResourceIndex].Type) {
+ case EfiIsaAcpiResourceIo:
+ IoResource = &ResourceList->ResourceItem[ResourceIndex];
+ break;
+
+ case EfiIsaAcpiResourceMemory:
+ break;
+
+ case EfiIsaAcpiResourceDma:
+ DmaResource = &ResourceList->ResourceItem[ResourceIndex];
+ break;
+
+ case EfiIsaAcpiResourceInterrupt:
+ InterruptResource = &ResourceList->ResourceItem[ResourceIndex];
+ break;
+
+ default:
+ break;
+ }
+ }
+ //
+ // See if this is an ISA serial port
+ //
+ // Ignore DMA resource since it is always returned NULL
+ //
+ if (ResourceList->Device.HID == EISA_PNP_ID (0x500) || ResourceList->Device.HID == EISA_PNP_ID (0x501)) {
+
+ if (ResourceList->Device.UID <= 3 &&
+ IoResource != NULL &&
+ InterruptResource != NULL
+ ) {
+ //
+ // Get the handle of the child device that has opened the ISA I/O Protocol
+ //
+ Status = gBS->OpenProtocolInformation (
+ HandleBuffer[Index],
+ &gEfiIsaIoProtocolGuid,
+ &OpenInfoBuffer,
+ &EntryCount
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ //
+ // We want resource for legacy even if no 32-bit driver installed
+ //
+ for (ChildIndex = 0; ChildIndex < EntryCount; ChildIndex++) {
+ if ((OpenInfoBuffer[ChildIndex].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
+ Status = gBS->HandleProtocol (OpenInfoBuffer[ChildIndex].ControllerHandle, &gEfiSerialIoProtocolGuid, (VOID **) &SerialIo);
+ if (!EFI_ERROR (Status)) {
+ SioSerial = &SioPtr->Serial[ResourceList->Device.UID];
+ SioSerial->Address = (UINT16) IoResource->StartRange;
+ SioSerial->Irq = (UINT8) InterruptResource->StartRange;
+ SioSerial->Mode = DEVICE_SERIAL_MODE_NORMAL | DEVICE_SERIAL_MODE_DUPLEX_HALF;
+ break;
+ }
+ }
+ }
+
+ FreePool (OpenInfoBuffer);
+ }
+ }
+ //
+ // See if this is an ISA parallel port
+ //
+ // Ignore DMA resource since it is always returned NULL, port
+ // only used in output mode.
+ //
+ if (ResourceList->Device.HID == EISA_PNP_ID (0x400) || ResourceList->Device.HID == EISA_PNP_ID (0x401)) {
+ if (ResourceList->Device.UID <= 2 &&
+ IoResource != NULL &&
+ InterruptResource != NULL &&
+ DmaResource != NULL
+ ) {
+ SioParallel = &SioPtr->Parallel[ResourceList->Device.UID];
+ SioParallel->Address = (UINT16) IoResource->StartRange;
+ SioParallel->Irq = (UINT8) InterruptResource->StartRange;
+ SioParallel->Dma = (UINT8) DmaResource->StartRange;
+ SioParallel->Mode = DEVICE_PARALLEL_MODE_MODE_OUTPUT_ONLY;
+ }
+ }
+ //
+ // See if this is an ISA floppy controller
+ //
+ if (ResourceList->Device.HID == EISA_PNP_ID (0x604)) {
+ if (IoResource != NULL && InterruptResource != NULL && DmaResource != NULL) {
+ Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
+ if (!EFI_ERROR (Status)) {
+ SioFloppy = &SioPtr->Floppy;
+ SioFloppy->Address = (UINT16) IoResource->StartRange;
+ SioFloppy->Irq = (UINT8) InterruptResource->StartRange;
+ SioFloppy->Dma = (UINT8) DmaResource->StartRange;
+ SioFloppy->NumberOfFloppy++;
+ }
+ }
+ }
+ //
+ // See if this is a mouse
+ // Always set mouse found so USB hot plug will work
+ //
+ // Ignore lower byte of HID. Pnp0fxx is any type of mouse.
+ //
+ // Hid = ResourceList->Device.HID & 0xff00ffff;
+ // PnpId = EISA_PNP_ID(0x0f00);
+ // if (Hid == PnpId) {
+ // if (ResourceList->Device.UID == 1) {
+ // Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiSimplePointerProtocolGuid, &SimplePointer);
+ // if (!EFI_ERROR (Status)) {
+ //
+ SioPtr->MousePresent = 0x01;
+ //
+ // }
+ // }
+ // }
+ //
+ }
+
+ FreePool (HandleBuffer);
+ return EFI_SUCCESS;
+}
+
+/**
+ Collect EFI Info about legacy devices.
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosBuildSioData (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ EFI_STATUS Status;
+ DEVICE_PRODUCER_DATA_HEADER *SioPtr;
+ EFI_HANDLE IsaBusController;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+
+ //
+ // Get the pointer to the SIO data structure
+ //
+ SioPtr = &Private->IntThunk->EfiToLegacy16BootTable.SioData;
+
+ //
+ // Zero the data in the SIO data structure
+ //
+ gBS->SetMem (SioPtr, sizeof (DEVICE_PRODUCER_DATA_HEADER), 0);
+
+ //
+ // Find the ISA Bus Controller used for legacy
+ //
+ Status = Private->LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformIsaBusHandle,
+ 0,
+ &HandleBuffer,
+ &HandleCount,
+ NULL
+ );
+ IsaBusController = HandleBuffer[0];
+ if (!EFI_ERROR (Status)) {
+ //
+ // Force ISA Bus Controller to produce all ISA devices
+ //
+ gBS->ConnectController (IsaBusController, NULL, NULL, TRUE);
+ }
+
+ Status = LegacyBiosBuildSioDataFromIsaIo (SioPtr);
+ if (EFI_ERROR (Status)) {
+ LegacyBiosBuildSioDataFromSio (SioPtr);
+ }
+
+ return EFI_SUCCESS;
+}