From e302f662bb8964b82ad2d97caa9407ac80508e05 Mon Sep 17 00:00:00 2001 From: Rafal Kupiec Date: Sun, 3 Dec 2023 10:22:24 +0100 Subject: [PATCH] Implement BmActivateSerialIOController() routine --- xtldr2/CMakeLists.txt | 1 + xtldr2/hardware.c | 112 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 xtldr2/hardware.c diff --git a/xtldr2/CMakeLists.txt b/xtldr2/CMakeLists.txt index 6ffbf47..5ebd7a1 100644 --- a/xtldr2/CMakeLists.txt +++ b/xtldr2/CMakeLists.txt @@ -10,6 +10,7 @@ include_directories( list(APPEND XTLDR_SOURCE ${XTLDR_SOURCE_DIR}/console.c ${XTLDR_SOURCE_DIR}/globals.c + ${XTLDR_SOURCE_DIR}/hardware.c ${XTLDR_SOURCE_DIR}/memory.c ${XTLDR_SOURCE_DIR}/string.c ${XTLDR_SOURCE_DIR}/xtldr.c) diff --git a/xtldr2/hardware.c b/xtldr2/hardware.c new file mode 100644 index 0000000..3f3c8b3 --- /dev/null +++ b/xtldr2/hardware.c @@ -0,0 +1,112 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtldr/hardware.c + * DESCRIPTION: XT Boot Manager EFI hardware support + * DEVELOPERS: Rafal Kupiec + */ + +#include + + +/** + * Enables I/O space access to all serial controllers found on the PCI(E) root bridge. + * + * @return This routine returns a status code. + * + * @since XT 1.0 + */ +XTCDECL +EFI_STATUS +BmActivateSerialIOController() +{ + EFI_GUID PciGuid = EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID; + PEFI_PCI_ROOT_BRIDGE_IO_PROTOCOL PciDev; + USHORT Bus, Device, Function, Command; + UINT_PTR Index, PciHandleSize; + PEFI_HANDLE PciHandle = NULL; + PCI_COMMON_HEADER PciHeader; + EFI_STATUS Status; + UINT64 Address; + + /* Allocate memory for single EFI_HANDLE, what should be enough in most cases */ + PciHandleSize = sizeof(EFI_HANDLE); + Status = BmAllocateEfiPool(PciHandleSize, (PVOID*)&PciHandle); + if(Status != STATUS_EFI_SUCCESS) + { + /* Memory allocation failure */ + return Status; + } + + /* Get all instances of PciRootBridgeIo */ + Status = EfiSystemTable->BootServices->LocateHandle(ByProtocol, &PciGuid, NULL, &PciHandleSize, PciHandle); + if(Status == STATUS_EFI_BUFFER_TOO_SMALL) + { + /* Reallocate more memory as requested by UEFI */ + BmFreeEfiPool(PciHandle); + Status = BmAllocateEfiPool(PciHandleSize, (PVOID*)&PciHandle); + if(Status != STATUS_EFI_SUCCESS) + { + /* Memory reallocation failure */ + return Status; + } + + /* Second attempt to get instances of PciRootBridgeIo */ + Status = EfiSystemTable->BootServices->LocateHandle(ByProtocol, &PciGuid, NULL, &PciHandleSize, PciHandle); + } + + /* Make sure successfully obtained PciRootBridgeIo instances */ + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to get PciRootBridgeIo instances */ + return Status; + } + + /* Enumerate all devices for each handle, which decides a segment and a bus number range */ + for(Index = 0; Index < (PciHandleSize / sizeof(EFI_HANDLE)); Index++) + { + /* Get inferface from the protocol */ + Status = EfiSystemTable->BootServices->HandleProtocol(PciHandle[Index], &PciGuid, (PVOID*)&PciDev); + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to get interface */ + return Status; + } + + /* Enumerate whole PCI bridge */ + for(Bus = 0; Bus <= PCI_MAX_BRIDGE_NUMBER; Bus++) + { + /* Enumerate all devices for each bus */ + for(Device = 0; Device < PCI_MAX_DEVICES; Device++) + { + /* Enumerate all functions for each devices */ + for(Function = 0; Function < PCI_MAX_FUNCTION; Function++) + { + /* Read configuration space */ + Address = ((UINT64)((((UINT_PTR) Bus) << 24) + (((UINT_PTR) Device) << 16) + + (((UINT_PTR) Function) << 8) + ((UINT_PTR) 0))); + PciDev->Pci.Read(PciDev, 2, Address, sizeof (PciHeader) / sizeof (UINT32), &PciHeader); + + /* Check if device exists */ + if(PciHeader.VendorId == PCI_INVALID_VENDORID) + { + /* Skip non-existen device */ + continue; + } + + /* Check if device is serial controller or multiport serial controller */ + if(PciHeader.BaseClass == 0x07 && (PciHeader.SubClass == 0x00 || PciHeader.SubClass == 0x02)) + { + /* Enable I/O space access */ + Address |= 0x4; + Command = PCI_ENABLE_IO_SPACE; + Status = PciDev->Pci.Write(PciDev, 1, Address, 1, &Command); + } + } + } + } + } + + /* Return SUCCESS */ + return STATUS_EFI_SUCCESS; +}