Page 1 of 1

Serial port on PCIEX and using it in UEFI

Posted: Thu Mar 12, 2020 1:48 am
by scribly
I'm having some issues with setting up and communicating with a serial port on a PCI Express card while in UEFI mode

When I boot in old compatibility mode I can scan for the pci device (vendor 0x1415) and find the port assigned (0xf010) and initialize it and work with it fine (sending and receiving is ok
But when I boot in UEFI mode the same code for controlling the serial port doesn't work anymore. (I checked with a uefi tool to enum the devices and it's still on the same port)

I'm guessing it's ACPI or something related but it'd help if I knew where to look (perhaps the pci card is powered down and it needs to be turned on, or the pcie card runs a csm firmware at boot ?)

Re: Serial port on PCIEX and using it in UEFI

Posted: Fri Mar 13, 2020 3:45 pm
by zaval
you are not supposed to program any peripheral device controller in UEFI, unless you write a UEFI driver for it, which you don't. instead, you should be using UEFI protocols for accessing appropriate hardware. you find your device handle, that supports the protocol, you need and you use functions of that protocol. read the UEFI spec. in your case, the protocols are input/output text protocols. the UEFI driver of the serial port controller creates handle for this port and attaches instances of these protocols to it, you search for them the common UEFI way - again, read the spec, it's described there way better, than anyone here would retell it. and I totally forgot, that in this case, you don't even need to search for anything - the active input/output devices are given to you through the EFI system table (ConsoleInHandle, ConIn, ConsoleOutHandle, ConOut)!

Re: Serial port on PCIEX and using it in UEFI

Posted: Wed Feb 23, 2022 3:39 am
by jzef
zaval wrote:you don't even need to search for anything - the active input/output devices are given to you through the EFI system table (ConsoleInHandle, ConIn, ConsoleOutHandle, ConOut)!
I tested the COM ports under UEFI Shell. To get UEFI Shell serial console in Putty on second PC you need to load appropriate .efi drivers:

1. Integrated COM port on the motherboard:

Code: Select all

load TerminalDxe.efi PciSioSerialDxe.efi
2. COM port on FTDI 232 USB:

Code: Select all

load TerminalDxe.efi FtdiUsbSerialDxe.efi
FTDI_USB_UEFI2.png
Drivers can be compiled from EDK2 (tianocore) sources or extract e.g. from OVMF-pure-efi.fd bios

I try the same with the RS232 PCIe card SER5427A but it doesn't work :(
Why is it not working? The driver PciSioSerialDxe.efi source code clearly states that it is intended for both Super I/O and PCI card:

https://github.com/tianocore/edk2/blob/ ... ialDxe.inf
## @file
# Serial driver for standard UARTS on a SIO chip or PCI/PCIE card.
#
# Produces the Serial I/O protocol for standard UARTS using Super I/O or PCI I/O.
#
# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.

Re: Serial port on PCIEX and using it in UEFI

Posted: Fri Sep 29, 2023 8:06 am
by jzef
I managed to run the redirect of the UEFI Shell console through the serial port on the PCIe card - instead of a PciSioSerialDxe.efi driver, I used SerialDxe.efi but using the BaseSerialPortLib16550.inf instead BaseSerialPortLibNull.inf library :D =D> =D>

Spec my PCIe SER5427A serial card:
  • one serial port
  • card are drived by a higher CLK (14.7456 Mhz), thus the actual baudarate is 8 times higher than the BIOS/DOS baudrate (default UART clock is 1843200 Hz)
  • access Port-Mapped I/O (PMIO) - in my configuration it is the port of D000 - under pure UEFI disabled by default
  • in my configuration PCIe serial card is on Bus Device Function 04 00 00
In the MdeModulePkg.dsc file, change:

Code: Select all

SerialPortLib|MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf
to

Code: Select all

SerialPortLib|MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.inf
In MdeModulePkg.dec file, change I/O port 03F8 to D000 and clock rate 1843200 to 14745600:

Code: Select all

gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase|0xD000|UINT64|0x00020002
gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate|14745600|UINT32|0x00010066
Now at UEFI Shell, just write a EFI\Boot\startup.nsh script that enable I/O access PCIe serial card and loads SerialDxe.efi and TerminalDxe.efi drivers:

Code: Select all

@echo -off
echo Switch ON PCIe Serial Card I/O access & load drivers
mm 04000004 1 ;PCI :1
load fs0:\SerialDxe_D000_Clock.efi fs0:\TerminalDxe.efi 
On the second PC we start Putty with baud rate 115200

P.S. Probably instead of enabling I/O access under UEFI Shell you need to properly configure the option PCI Serial Device Info at MdeModulePkg.dec - default is 0xFF:

Code: Select all

  ## PCI Serial Device Info. It is an array of Device, Function, and Power Management
  #  information that describes the path that contains zero or more PCI to PCI briges
  #  followed by a PCI serial device.  Each array entry is 4-bytes in length.  The
  #  first byte is the PCI Device Number, then second byte is the PCI Function Number,
  #  and the last two bytes are the offset to the PCI power management capabilities
  #  register used to manage the D0-D3 states.  If a PCI power management capabilities
  #  register is not present, then the last two bytes in the offset is set to 0.  The
  #  array is terminated by an array entry with a PCI Device Number of 0xFF.  For a
  #  non-PCI fixed address serial device, such as an ISA serial device, the value is 0xFF.
  # @Prompt Pci Serial Device Info
  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialPciDeviceInfo|{0xFF}|VOID*|0x00010067
I tried this way: {0x1c, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF} but after loading the SerialDxe.efi I have Device error :(

Dev 1C, Func 01 > PCI Express Root
Dev 00, Func 00 > Bridge PCI to PCI
Dev 00, Func 00 > My PCIe serial card

Re: Serial port on PCIEX and using it in UEFI

Posted: Fri Sep 29, 2023 11:55 am
by Octocontrabass
jzef wrote:

Code: Select all

  #  followed by a PCI serial device.  Each array entry is 4-bytes in length.  The
I tried this way: {0x1c, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF} but after loading the SerialDxe.efi I have Device error :(
You need four bytes for each device.

Re: Serial port on PCIEX and using it in UEFI

Posted: Sat Sep 30, 2023 12:46 am
by jzef
Octocontrabass wrote: You need four bytes for each device.
Thank you very much - I fixed source code and now it works good - no need use mm 04000004 1 -pci anymore :lol: :D =D>

MdeModulePkg.dec

Code: Select all

gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase|0xD000|UINT64|0x00020002
gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate|14745600|UINT32|0x00010066
gEfiMdeModulePkgTokenSpaceGuid.PcdSerialPciDeviceInfo|{0x1C, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}|VOID*|0x00010067
startup.nsh

Code: Select all

@echo -off
echo Load drivers for PCIe Serial Card & run UefiSeven
load fs0:\SerialDxe_D000_Clock_Info.efi fs0:\TerminalDxe.efi 
UefiSeven.efi
PCIe_serial_card_OK.png

Code: Select all

SerialDxe_PCIe.efi

fs0:\> dh 155
Handle 155 (7906DD18)
   Image (79109E40)   File:\/SerialDxe_PCIe.efi
     ParentHandle..: 79DA8818
     SystemTable...: 7D74CF18
     DeviceHandle..: 7A156118
     FilePath......: \/SerialDxe_PCIe.efi
     PdbFileName...: /root/MyWorkspace/Build/MdeModule/RELEASE_GCC49/X64/MdeModulePkg/Universal/SerialDxe/SerialDxe/DEBUG/SerialDxe.dll
     ImageBase.....: 7BB75000 - 7BB77380
     ImageSize.....: 2380
     CodeType......: BS_code
     DataType......: BS_data
   ImageDpath (7906C918)
      ACPI Device Path for Acpi
       HID PNP0A03, UID 0
      Hardware Device Path for PCI
       Function (2) Device (1F)
      Messaging Device Path for SATA
      Media Device Path for Hard Drive
       Partition (1) Start (0000000000000800) Size (0000000000032000)
      Media Device Path for File Path
       File '\'
      Media Device Path for File Path
       File 'SerialDxe_PCIe.efi'
      AsStr: 'PciRoot(0x0)/Pci(0x1f,0x2)/Sata(0x0,0x0)/HD(1,MBR,0x343daba5,0x800,0x32000)/\/SerialDxe_PCIe.efi'

PCIe card:

fs0:\> dh 12b -d
 12B: DevPath (..1)/Pci(0x0,0x0)/Pci(0x0,0x0))PciIo
     Controller Name    : <UNKNOWN>

     Device Path        : PciRoot(0x0)/Pci(0x1c,0x1)/Pci(0x0,0x0)/Pci(0x0,0x0)
     Controller Type    : DEVICE
     Configuration      : NO
     Diagnostics        : NO
     Managed by         : <NONE>
     Parent Controllers :
       Parent[50] : PciRoot(0x0)
     Child Controllers  : <NONE>

fs0:\> sermode
156(7906DB18) - (115200, N, 8, 1)

fs0:\> dh 156 -d
 156: DevPath (..eb627241)/Uart(115200,8,N,1))SerialIo
     Controller Name    : <UNKNOWN>

     Device Path        : VenHw(d3987d4b-971a-435f-8caf-4967eb627241)/Uart(115200,8,N,1)
     Controller Type    : ROOT
     Configuration      : NO
     Diagnostics        : NO
     Managed by :
       Drv[157] : Serial Terminal Driver
     Parent Controllers : <NONE>
     Child Controllers  :
       Child[158] : PC-ANSI Serial Console
I/O space access enabled: 1

Code: Select all

Vendor ID(0): 1FD4                     Device ID(2): 1999

Command(4): 0001
  (00)I/O space access enabled:       1  (01)Memory space access enabled:    0
  (02)Behave as bus master:           0  (03)Monitor special cycle enabled:  0
  (04)Mem Write & Invalidate enabled: 0  (05)Palette snooping is enabled:    0
  (06)Assert PERR# when parity error: 0  (07)Do address/data stepping:       0
  (08)SERR# driver enabled:           0  (09)Fast back-to-back transact...:  0
P.S. Unfortunately to debug Windows I still have to use baudrate 14400 in BCD and 115200 in WinDbg :?

Re: Serial port on PCIEX and using it in UEFI

Posted: Mon Oct 02, 2023 5:02 am
by jzef
I was able to compile the correct PciSioSerialDxe.efi driver for my PCIe SER5427A serial card :D 8)

It is not important what library BaseSerialPortLibNull.inf or BaseSerialPortLib16550.inf is in MdeModulePkg.dsc because the driver does not use any of them.

To make the driver work, all you need to configure the PCIe card in MdeModulePkg.dec accordingly in PcdPciSerialParameters:

Code: Select all

gEfiMdeModulePkgTokenSpaceGuid.PcdPciSerialParameters|{0xD4,0x1F, 0x99,0x19, 0x00,0x00,0xE1,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0xFF,0xFF}|VOID*|0x00010071

Code: Select all

--Vendor-  --Device-  -----ClockRate-----  ----------------Offset-----------------  -Bar  Stde  --RxFIFO-  --TxFIFO-  -Reserved  Terminate
0xD4,0x1F, 0x99,0x19, 0x00,0x00,0xE1,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0xFF,0xFF
Vendor, Device and ClockRate must be given as little-endian:

Vendor Device 1FD4 1999 > D4 1F 99 19
ClockRate my card 14745600 Hz > E10000 > 00 00 E1

That's all =D> =D> because my card have only I/O access address in BAR0

No need to configure PcdSerialRegisterBase, PcdSerialClockRate and PcdSerialPciDeviceInfo in MdeModulePkg.dec -defaults is 0x03F8, 1843200 and 0xFF because is not consumed by PciSioSerialDxe.inf - only consumed PcdPciSerialParameters:

Code: Select all

[Pcd]
  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate|115200    ## CONSUMES
  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits|8         ## CONSUMES
  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity|1           ## CONSUMES
  gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits|1         ## CONSUMES
  gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate|1843200 ## CONSUMES
  gEfiMdeModulePkgTokenSpaceGuid.PcdPciSerialParameters     ## CONSUMES

Code: Select all

PciSioSerialDxe_PCIe.efi

fs0:\> dh 155 -d
 155: Image(\/PciSioSerialDxe_PCIe.efi) ImageDevPath (..)/\/PciSioSerialDxe_PCIe.efi)DriverBinding ComponentName
     Driver Name    : PCI SIO Serial Driver
     Image Name     : \/PciSioSerialDxe_PCIe.efi
     Driver Version : 0000000A
     Driver Type    : BUS
     Configuration  : NO
     Diagnostics    : NO
     Managing       :
       Ctrl[12B] : PciRoot(0x0)/Pci(0x1c,0x1)/Pci(0x0,0x0)/Pci(0x0,0x0)
         Child[156] : PCI Serial Port #0

PCIe card:

fs0:\> dh 12b -d
 12B: DevPath (..1)/Pci(0x0,0x0)/Pci(0x0,0x0))PciIo
     Controller Name    : <UNKNOWN>

     Device Path        : PciRoot(0x0)/Pci(0x1c,0x1)/Pci(0x0,0x0)/Pci(0x0,0x0)
     Controller Type    : BUS
     Configuration      : NO
     Diagnostics        : NO
     Managed by :
       Drv[155] : PCI SIO Serial Driver
     Parent Controllers :
       Parent[50] : PciRoot(0x0)
     Child Controllers  :
       Child[156] : PCI Serial Port #0

fs0:\> sermode
156(7906D698) - (115200, N, 8, 1)

fs0:\> dh 156 -d
 156: DevPath (..(0x0,0x0)/Uart(115200,8,N,1))SerialIo
     Controller Name    : PCI Serial Port #0
     Device Path        : PciRoot(0x0)/Pci(0x1c,0x1)/Pci(0x0,0x0)/Pci(0x0,0x0)/Uart(115200,8,N,1)
     Controller Type    : BUS
     Configuration      : NO
     Diagnostics        : NO
     Managed by :
       Drv[157] : Serial Terminal Driver
     Parent Controllers :
       Parent[12B] : PciRoot(0x0)/Pci(0x1c,0x1)/Pci(0x0,0x0)/Pci(0x0,0x0)
     Child Controllers  :
       Child[158] : PC-ANSI Serial Console

Re: Serial port on PCIEX and using it in UEFI

Posted: Mon Oct 02, 2023 7:33 am
by jzef
Summary:

PCIe serial card with I/O access:
SerialDxe.efi need:
  • BaseSerialPortLib16550.inf
  • gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate (if non standard)
  • gEfiMdeModulePkgTokenSpaceGuid.PcdSerialPciDeviceInfo
PciSioSerialDxe.efi need:
  • gEfiMdeModulePkgTokenSpaceGuid.PcdPciSerialParameters (ClockRate inside)
I also tested other serial card - ExpressCard with only I/O access and PCIe with only MMIO but I could not start the drivers - SerialDxe.efi, PciSioSerialDxe.efi or do not work correctly :?

P.S. Please test your cards and pass the report whether it works or not in this topic or other :wink: