From: Benjamin Herrenschmidt Date: Fri, 23 Dec 2022 01:47:59 +0000 (+1100) Subject: term/serial: Add ability to specify MMIO ports via "serial" command X-Git-Tag: grub-2.12-rc1~169 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c4e80163168cbc9c3a369fa6d866b6d967648337;p=thirdparty%2Fgrub.git term/serial: Add ability to specify MMIO ports via "serial" command This adds the ability to explicitly add an MMIO based serial port via the "serial" command. The syntax is: serial --port=mmio,{.b,.w,.l,.q} Signed-off-by: Benjamin Herrenschmidt Reviewed-by: Daniel Kiper --- diff --git a/docs/grub.texi b/docs/grub.texi index c69a11391..659885388 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -4168,8 +4168,24 @@ Commands usable anywhere in the menu and in the command-line. @deffn Command serial [@option{--unit=unit}] [@option{--port=port}] [@option{--speed=speed}] [@option{--word=word}] [@option{--parity=parity}] [@option{--stop=stop}] Initialize a serial device. @var{unit} is a number in the range 0-3 specifying which serial port to use; default is 0, which corresponds to -the port often called COM1. @var{port} is the I/O port where the UART -is to be found; if specified it takes precedence over @var{unit}. +the port often called COM1. + +@var{port} is the I/O port where the UART is to be found or, if prefixed +with @samp{mmio,}, the MMIO address of the UART. If specified it takes +precedence over @var{unit}. + +Additionally, an MMIO address can be suffixed with: +@itemize @bullet +@item +@samp{.b} for bytes access (default) +@item +@samp{.w} for 16-bit word access +@item +@samp{.l} for 32-bit long word access or +@item +@samp{.q} for 64-bit long long word access +@end itemize + @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 @@ -4185,6 +4201,12 @@ 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}). +Examples: +@example +serial --port=3f8 --speed=9600 +serial --port=mmio,fefb0000.l --speed=115200 +@end example + See also @ref{Serial terminal}. @end deffn diff --git a/grub-core/term/serial.c b/grub-core/term/serial.c index 8d01977b6..595e74b16 100644 --- a/grub-core/term/serial.c +++ b/grub-core/term/serial.c @@ -164,6 +164,70 @@ grub_serial_find (const char *name) if (grub_strcmp (port->name, name) == 0) break; } + if (!port && grub_strncmp (name, "mmio,", sizeof ("mmio,") - 1) == 0 + && grub_isxdigit (name [sizeof ("mmio,") - 1])) + { + const char *p1, *p = &name[sizeof ("mmio,") - 1]; + grub_addr_t addr = grub_strtoul (p, &p1, 16); + unsigned int acc_size = 1; + unsigned int nlen = p1 - p; + + /* + * If we reach here, we know there's a digit after "mmio,", so + * all we need to check is the validity of the character following + * the number, which should be a termination, or a dot followed by + * an access size. + */ + if (p1[0] != '\0' && p1[0] != '.') + { + grub_error (GRUB_ERR_BAD_ARGUMENT, N_("incorrect MMIO address syntax")); + return NULL; + } + if (p1[0] == '.') + switch(p1[1]) + { + case 'w': + acc_size = 2; + break; + case 'l': + acc_size = 3; + break; + case 'q': + acc_size = 4; + break; + case 'b': + acc_size = 1; + break; + default: + /* + * Should we abort for an unknown size? Let's just default + * to 1 byte, it would increase the chance that the user who + * did a typo can actually see the console. + */ + grub_error (GRUB_ERR_BAD_ARGUMENT, N_("incorrect MMIO access size")); + } + + /* + * Specifying the access size is optional an grub_serial_ns8250_add_mmio() + * will not add it to the name. So the original loop trying to match an + * existing port above might have missed this one. Let's do another + * search ignoring the access size part of the string. At this point + * nlen contains the length of the name up to the end of the address. + */ + FOR_SERIAL_PORTS (port) + if (grub_strncmp (port->name, name, nlen) == 0) { + break; + } + + name = grub_serial_ns8250_add_mmio (addr, acc_size, NULL); + if (name == NULL) + return NULL; + + FOR_SERIAL_PORTS (port) + if (grub_strcmp (port->name, name) == 0) { + break; + } + } #if (defined(__i386__) || defined(__x86_64__)) && !defined(GRUB_MACHINE_IEEE1275) && !defined(GRUB_MACHINE_QEMU) if (!port && grub_strcmp (name, "auto") == 0) @@ -215,8 +279,11 @@ grub_cmd_serial (grub_extcmd_context_t ctxt, int argc, char **args) if (state[OPTION_PORT].set) { - grub_snprintf (pname, sizeof (pname), "port%lx", - grub_strtoul (state[1].arg, 0, 0)); + if (grub_strncmp (state[OPTION_PORT].arg, "mmio,", sizeof ("mmio,") - 1) == 0) + grub_snprintf (pname, sizeof (pname), "%s", state[1].arg); + else + grub_snprintf (pname, sizeof (pname), "port%lx", + grub_strtoul (state[1].arg, 0, 0)); name = pname; }