On Sat, May 13, 2023 at 02:54:51AM -0500, Glenn Washburn wrote: > From: "pet...@infradead.org" <pet...@infradead.org> > > Loosely based on early_pci_serial_init() from Linux, allow GRUB to make > use of PCI serial devices. > > Specifically, my Alderlake NUC exposes the Intel AMT SoL UART as a PCI > enumerated device but doesn't include it in the EFI tables. > > Tested and confirmed working on a "Lenovo P360 Tiny" with Intel AMT > enabled. This specific machine has (from lspci -vv): > > 00:16.3 Serial controller: Intel Corporation Device 7aeb (rev 11) (prog-if 02 > [16550]) > DeviceName: Onboard - Other > Subsystem: Lenovo Device 330e > Control: I/O+ Mem+ BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr- > Stepping- SERR- FastB2B- DisINTx- > Status: Cap+ 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=fast >TAbort- > <TAbort- <MAbort- >SERR- <PERR- INTx- > Interrupt: pin D routed to IRQ 19 > Region 0: I/O ports at 40a0 [size=8] > Region 1: Memory at b4224000 (32-bit, non-prefetchable) [size=4K] > Capabilities: [40] MSI: Enable- Count=1/1 Maskable- 64bit+ > Address: 0000000000000000 Data: 0000 > Capabilities: [50] Power Management version 3 > Flags: PMEClk- DSI+ D1- D2- AuxCurrent=0mA > PME(D0-,D1-,D2-,D3hot-,D3cold-) > Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME- > Kernel driver in use: serial > > >>From which the following config (/etc/default/grub) gets a working > serial setup: > > GRUB_CMDLINE_LINUX="console=tty0 earlyprintk=pciserial,00:16.3,115200 > console=ttyS0,115200" > GRUB_SERIAL_COMMAND="serial --port=0x40a0 --speed=115200" > GRUB_TERMINAL="serial console" > > Documentation is added to note that serial devices found on the PCI bus will > be exposed as "pci,XX:XX.X" and how to find serial terminal logical names. > Also, some minor documentation improvements were added. > > This can be tested in QEMU by adding a pci-serial device, eg. using the option > "-device pci-serial". > > Signed-off-by: Peter Zijlstra (Intel) <pet...@infradead.org> > Tested-by: Glenn Washburn <developm...@efficientek.com> > Signed-off-by: Glenn Washburn <developm...@efficientek.com> > --- > docs/grub.texi | 13 ++++-- > grub-core/Makefile.core.def | 1 + > grub-core/term/pci/serial.c | 91 +++++++++++++++++++++++++++++++++++++ > grub-core/term/serial.c | 6 ++- > include/grub/pci.h | 5 ++ > include/grub/serial.h | 4 ++ > 6 files changed, 116 insertions(+), 4 deletions(-) > create mode 100644 grub-core/term/pci/serial.c > > diff --git a/docs/grub.texi b/docs/grub.texi > index a3e9ce2d1ac7..477919ee901b 100644 > --- a/docs/grub.texi > +++ b/docs/grub.texi > @@ -2716,8 +2716,7 @@ grub> @kbd{terminal_input serial; terminal_output > serial} > The command @command{serial} initializes the serial unit 0 with the > speed 9600bps. The serial unit 0 is usually called @samp{COM1}, so, if > you want to use COM2, you must specify @samp{--unit=1} instead. This > -command accepts many other options, so please refer to @ref{serial}, > -for more details. > +command accepts many other options, @pxref{serial} for more details. > > Without argument or with @samp{--port=auto}, GRUB will attempt to use > ACPI when available to auto-detect the default serial port and its > @@ -4186,6 +4185,9 @@ Additionally, an MMIO address can be suffixed with: > @samp{.q} for 64-bit long long word access > @end itemize > > +Also, @var{port} can be of the form @samp{pci,XX:XX.X} to indicate a serial > +device exposed on the PCI bus. > + > @var{speed} is the transmission speed; default is 9600. @var{word} and > @var{stop} are the number of data bits and stop bits. Data bits must > be in the range 5-8 and stop bits must be 1 or 2. Default is 8 data > @@ -4201,10 +4203,15 @@ The serial port is not used as a communication > channel unless the > @command{terminal_input} or @command{terminal_output} command is used > (@pxref{terminal_input}, @pxref{terminal_output}). > > +Note, valid @var{port} values, excluding IO port addresses, can be found > +by listing terminals with @command{terminal_output}, selecting all names > +prefixed by @samp{serial_} and removing that prefix. > + > Examples: > @example > -serial --port=3f8 --speed=9600 > +serial --port=0x3f8 --speed=9600 > serial --port=mmio,fefb0000.l --speed=115200 > +serial --port=pci,00:16.3 --speed=115200 > @end example > > See also @ref{Serial terminal}. > diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def > index 801df7c21de6..fb4cc066c526 100644 > --- a/grub-core/Makefile.core.def > +++ b/grub-core/Makefile.core.def > @@ -2064,6 +2064,7 @@ module = { > ieee1275 = term/ieee1275/serial.c; > mips_arc = term/arc/serial.c; > efi = term/efi/serial.c; > + x86 = term/pci/serial.c; > > enable = terminfomodule; > enable = ieee1275; > diff --git a/grub-core/term/pci/serial.c b/grub-core/term/pci/serial.c > new file mode 100644 > index 000000000000..0b8fe815f5ca > --- /dev/null > +++ b/grub-core/term/pci/serial.c > @@ -0,0 +1,91 @@ > +/* > + * GRUB -- GRand Unified Bootloader > + * Copyright (C) 2023 Free Software Foundation, Inc. > + * > + * GRUB is free software: you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation, either version 3 of the License, or > + * (at your option) any later version. > + * > + * GRUB is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. > + */ > + > +#include <grub/serial.h> > +#include <grub/term.h> > +#include <grub/types.h> > +#include <grub/pci.h> > +#include <grub/mm.h> > +#include <grub/misc.h> > + > +static int > +find_pciserial (grub_pci_device_t dev, grub_pci_id_t pciid __attribute__ > ((unused)), void *data __attribute__ ((unused))) > +{ > + grub_pci_address_t cmd_addr, class_addr, bar_addr; > + struct grub_serial_port *port; > + grub_uint32_t class, bar; > + grub_uint16_t cmdreg; > + grub_err_t err; > + > + cmd_addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND); > + cmdreg = grub_pci_read (cmd_addr); > + > + class_addr = grub_pci_make_address (dev, GRUB_PCI_REG_REVISION); > + class = grub_pci_read (class_addr); > + > + bar_addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG0); > + bar = grub_pci_read (bar_addr); > + > + /* 16550 compattible MODEM or SERIAL */ > + if (((class >> 16) != GRUB_PCI_CLASS_COMMUNICATION_MODEM && > + (class >> 16) != GRUB_PCI_CLASS_COMMUNICATION_SERIAL) || > + ((class >> 8) & 0xff) != GRUB_PCI_SERIAL_16550_COMPATIBLE) > + return 0; > + > + if ((bar & GRUB_PCI_ADDR_SPACE_MASK) != GRUB_PCI_ADDR_SPACE_IO) > + return 0; > + > + port = grub_zalloc (sizeof (*port)); > + if (port == NULL) > + return 0; > + > + port->name = grub_xasprintf ("pci,%02x:%02x.%x", > + grub_pci_get_bus (dev), > + grub_pci_get_device (dev), > + grub_pci_get_function (dev)); > + if (port->name == NULL) > + goto fail; > + > + grub_pci_write (cmd_addr, cmdreg | GRUB_PCI_COMMAND_IO_ENABLED); > + > + port->driver = &grub_ns8250_driver; > + port->port = bar & GRUB_PCI_ADDR_IO_MASK; > + err = grub_serial_config_defaults (port); > + if (err != GRUB_ERR_NONE) > + { > + grub_print_error (); > + goto fail; > + } > + > + err = grub_serial_register (port); > + if (err != GRUB_ERR_NONE) > + goto fail; > + > + return 0; > + > + fail: > + grub_free (port->name); > + grub_free (port); > + return 0; > +} > + > +void > +grub_pciserial_init (void) > +{ > + grub_pci_iterate (find_pciserial, NULL); > +} > diff --git a/grub-core/term/serial.c b/grub-core/term/serial.c > index c65ffc63cecb..05db4cf177c2 100644 > --- a/grub-core/term/serial.c > +++ b/grub-core/term/serial.c > @@ -255,7 +255,8 @@ grub_cmd_serial (grub_extcmd_context_t ctxt, int argc, > char **args) > > if (state[OPTION_PORT].set) > { > - if (grub_strncmp (state[OPTION_PORT].arg, "mmio,", sizeof ("mmio,") - > 1) == 0) > + if (grub_strncmp (state[OPTION_PORT].arg, "mmio,", sizeof ("mmio,") - > 1) == 0 || > + grub_strncmp (state[OPTION_PORT].arg, "pci,", sizeof ("pci,") - 1) == > 0) > grub_snprintf (pname, sizeof (pname), "%s", state[1].arg); > else > grub_snprintf (pname, sizeof (pname), "port%lx", > @@ -505,6 +506,9 @@ GRUB_MOD_INIT(serial) > #ifdef GRUB_MACHINE_ARC > grub_arcserial_init (); > #endif > +#ifdef GRUB_HAS_PCI
I think this... > + grub_pciserial_init (); > +#endif > } > > GRUB_MOD_FINI(serial) > diff --git a/include/grub/pci.h b/include/grub/pci.h > index 262c89b748bb..b228bb1b71fd 100644 > --- a/include/grub/pci.h > +++ b/include/grub/pci.h > @@ -80,8 +80,13 @@ > > #define GRUB_PCI_STATUS_DEVSEL_TIMING_SHIFT 9 > #define GRUB_PCI_STATUS_DEVSEL_TIMING_MASK 0x0600 > + > #define GRUB_PCI_CLASS_SUBCLASS_VGA 0x0300 > #define GRUB_PCI_CLASS_SUBCLASS_USB 0x0c03 > +#define GRUB_PCI_CLASS_COMMUNICATION_SERIAL 0x0700 > +#define GRUB_PCI_CLASS_COMMUNICATION_MODEM 0x0703 > + > +#define GRUB_PCI_SERIAL_16550_COMPATIBLE 0x02 > > #ifndef ASM_FILE > > diff --git a/include/grub/serial.h b/include/grub/serial.h > index a955c076d892..9226d51f5831 100644 > --- a/include/grub/serial.h > +++ b/include/grub/serial.h > @@ -210,6 +210,10 @@ grub_arcserial_init (void); > struct grub_serial_port *grub_arcserial_add_port (const char *path); > #endif > > +#ifdef GRUB_HAS_PCI ... and this should be changed to #if defined(__i386__) && defined(__x86_64__) Otherwise Reviewed-by: Daniel Kiper <daniel.ki...@oracle.com>... I can do the changes mentioned above before push. Peter, Glenn, thank you for adding this feature. > +void grub_pciserial_init (void); > +#endif > + > struct grub_serial_port *grub_serial_find (const char *name); > extern struct grub_serial_driver grub_ns8250_driver; > void EXPORT_FUNC(grub_serial_unregister_driver) (struct grub_serial_driver > *driver); Daniel _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel