grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v3 8/8] serial: Add ability to specify MMIO ports via 'serial'


From: Benjamin Herrenschmidt
Subject: [PATCH v3 8/8] serial: Add ability to specify MMIO ports via 'serial'
Date: Fri, 23 Dec 2022 12:47:59 +1100

This adds the ability to explicitely add an MMIO based serial port
via the 'serial' command. The syntax is:

serial --port=mmio,<hex_address>{.b,.w,.l,.q}

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

# Conflicts:
#       grub-core/term/serial.c
---
 docs/grub.texi          | 26 +++++++++++++--
 grub-core/term/serial.c | 71 +++++++++++++++++++++++++++++++++++++++--
 2 files changed, 93 insertions(+), 4 deletions(-)

diff --git a/docs/grub.texi b/docs/grub.texi
index fd22a69fa..502ca2ef7 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 d49261b48..d161e1d36 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 (!port && grub_strcmp (name, "auto") == 0)
     {
       /* Look for an SPCR if any. If not, default to com0 */
@@ -212,8 +276,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;
     }
 
-- 
2.34.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]