From bb9522350163b30749d0bdac0f70a9ec7a05545a Mon Sep 17 00:00:00 2001 From: belliash Date: Tue, 3 Jan 2023 00:10:24 +0100 Subject: [PATCH] Implement BlActivateSerialControllerIO() routine for activating I/O space access on PCI(E) serial controllers --- xtldr/efiutil.c | 117 ++++++++++++++++++++++++++++++++++++++++++ xtldr/includes/xtbl.h | 4 ++ 2 files changed, 121 insertions(+) diff --git a/xtldr/efiutil.c b/xtldr/efiutil.c index 243fc27..562f4b4 100644 --- a/xtldr/efiutil.c +++ b/xtldr/efiutil.c @@ -9,6 +9,108 @@ #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 +BlActivateSerialControllerIO() +{ + 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 = BlEfiMemoryAllocatePool(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 */ + BlEfiMemoryFreePool(PciHandle); + Status = BlEfiMemoryAllocatePool(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; +} + /** * This routine initializes the COM port debug console. * @@ -136,6 +238,21 @@ BlComPortInitialize() /* Initialize COM port */ Status = HlInitializeComPort(&EfiSerialPort, PortNumber, UlongToPtr(PortAddress), BaudRate); + + /* Port not found under supplied address */ + if(Status == STATUS_NOT_FOUND && PortAddress) + { + /* This might be PCI(E) serial controller, try to activate I/O space access first */ + EfiStatus = BlActivateSerialControllerIO(); + if(EfiStatus == STATUS_EFI_SUCCESS) + { + /* Try to reinitialize COM port */ + BlEfiPrint(L"Enabled I/O space access for all PCI(E) serial controllers found\n"); + Status = HlInitializeComPort(&EfiSerialPort, PortNumber, UlongToPtr(PortAddress), BaudRate); + } + } + + /* Check COM port initialization status code */ if(Status != STATUS_SUCCESS) { /* Serial port initialization failed, mark as not ready */ diff --git a/xtldr/includes/xtbl.h b/xtldr/includes/xtbl.h index 034edf5..20c7f62 100644 --- a/xtldr/includes/xtbl.h +++ b/xtldr/includes/xtbl.h @@ -32,6 +32,10 @@ EXTERN PVOID EfiLoaderStack; /* Serial port configuration */ EXTERN CPPORT EfiSerialPort; +XTCDECL +EFI_STATUS +BlActivateSerialControllerIO(); + XTCDECL EFI_STATUS BlAddVirtualMemoryMapping(IN PLIST_ENTRY MemoryMappings,