grub-devel
[Top][All Lists]
Advanced

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

[PATCH 3/3] serial: Improve detection of duplicate serial ports


From: Benjamin Herrenschmidt
Subject: [PATCH 3/3] serial: Improve detection of duplicate serial ports
Date: Fri, 23 Dec 2022 12:48:49 +1100

We currently rely on some pretty fragile comparison by name to
identify wether a serial port being configured is identical
---
 grub-core/term/arc/serial.c      |  4 +++
 grub-core/term/ieee1275/serial.c |  4 +++
 grub-core/term/ns8250.c          | 16 +++++++++
 grub-core/term/serial.c          | 57 +++++++++++++-------------------
 include/grub/serial.h            |  4 +++
 5 files changed, 51 insertions(+), 34 deletions(-)

diff --git a/grub-core/term/arc/serial.c b/grub-core/term/arc/serial.c
index 651f814ee..487aa1b30 100644
--- a/grub-core/term/arc/serial.c
+++ b/grub-core/term/arc/serial.c
@@ -106,6 +106,10 @@ grub_arcserial_add_port (const char *path)
   struct grub_serial_port *port;
   grub_err_t err;
 
+  FOR_SERIAL_PORTS (port)
+    if (grub_strcmp(path, port->name) == 0)
+      return port;
+
   port = grub_zalloc (sizeof (*port));
   if (!port)
     return NULL;
diff --git a/grub-core/term/ieee1275/serial.c b/grub-core/term/ieee1275/serial.c
index b4aa9d5c5..afbe8dcda 100644
--- a/grub-core/term/ieee1275/serial.c
+++ b/grub-core/term/ieee1275/serial.c
@@ -227,6 +227,10 @@ add_port (struct ofserial_hash_ent *ent)
   if (!ent->shortest)
     return NULL;
 
+  FOR_SERIAL_PORTS (port)
+    if (port->ent == ent)
+      return port;
+
   port = grub_zalloc (sizeof (*port));
   if (!port)
     return NULL;
diff --git a/grub-core/term/ns8250.c b/grub-core/term/ns8250.c
index 1eb6a30b6..074bd08ca 100644
--- a/grub-core/term/ns8250.c
+++ b/grub-core/term/ns8250.c
@@ -364,6 +364,14 @@ grub_serial_ns8250_add_port (grub_port_t port, struct 
grub_serial_config *config
         return &com_ports[i];
       }
 
+  FOR_SERIAL_PORTS (p)
+    if (!p->mmio && p->port == port)
+      {
+        if (config != NULL)
+          grub_serial_port_configure (p, config);
+        return p;
+      }
+
   grub_outb (0x5a, port + UART_SR);
   if (grub_inb (port + UART_SR) != 0x5a)
     return NULL;
@@ -409,6 +417,14 @@ grub_serial_ns8250_add_mmio (grub_addr_t addr, unsigned 
int acc_size,
         return &com_ports[i];
       }
 
+  FOR_SERIAL_PORTS (p)
+    if (p->mmio && p->mmio_base == addr)
+      {
+        if (config != NULL)
+          grub_serial_port_configure (p, config);
+        return p;
+      }
+
   p = grub_malloc (sizeof (*p));
   if (p == NULL)
     return NULL;
diff --git a/grub-core/term/serial.c b/grub-core/term/serial.c
index 275dd61af..e214d773b 100644
--- a/grub-core/term/serial.c
+++ b/grub-core/term/serial.c
@@ -37,8 +37,6 @@
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
-#define FOR_SERIAL_PORTS(var) FOR_LIST_ELEMENTS((var), (grub_serial_ports))
-
 enum
   {
     OPTION_UNIT,
@@ -65,7 +63,7 @@ static const struct grub_arg_option options[] =
   {0, 0, 0, 0, 0, 0}
 };
 
-static struct grub_serial_port *grub_serial_ports;
+struct grub_serial_port *grub_serial_ports;
 
 struct grub_serial_output_state
 {
@@ -147,26 +145,30 @@ grub_serial_find (const char *name)
 {
   struct grub_serial_port *port;
 
+  /*
+   * First look for an exact match by name, this will take care of
+   * things like "com0" which have already been created and that
+   * this function cannot re-create.
+   */
   FOR_SERIAL_PORTS (port)
     if (grub_strcmp (port->name, name) == 0)
-      break;
+      return port;
 
 #if (defined(__mips__) || defined (__i386__) || defined (__x86_64__)) && 
!defined(GRUB_MACHINE_EMU) && !defined(GRUB_MACHINE_ARC)
-  if (!port && grub_strncmp (name, "port", sizeof ("port") - 1) == 0
+  if (grub_strncmp (name, "port", sizeof ("port") - 1) == 0
       && grub_isxdigit (name [sizeof ("port") - 1]))
     {
       port = grub_serial_ns8250_add_port (grub_strtoul (&name[sizeof ("port") 
- 1],
                                                        0, 16), NULL);
-      if (port == NULL)
-        return NULL;
+      if (port != NULL)
+        return port;
     }
-  if (!port && grub_strncmp (name, "mmio,", sizeof ("mmio,") - 1) == 0
+  if (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
@@ -203,45 +205,32 @@ grub_serial_find (const char *name)
             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;
-        }
-
       port = grub_serial_ns8250_add_mmio (addr, acc_size, NULL);
-      if (port == NULL)
-        return NULL;
+      if (port != NULL)
+        return port;
     }
-  if (!port && grub_strcmp (name, "auto") == 0)
+  if (grub_strcmp (name, "auto") == 0)
     {
       /* Look for an SPCR if any. If not, default to com0 */
       port = grub_ns8250_spcr_init ();
-      if (port == NULL)
-        {
-          FOR_SERIAL_PORTS (port)
-            if (grub_strcmp (port->name, "com0") == 0)
-              break;
-       }
+      if (port != NULL)
+        return port;
+      FOR_SERIAL_PORTS (port)
+        if (grub_strcmp (port->name, "com0") == 0)
+          return port;
     }
 #endif
 
 #ifdef GRUB_MACHINE_IEEE1275
-  if (!port && grub_strncmp (name, "ieee1275/", sizeof ("ieee1275/") - 1) == 0)
+  if (grub_strncmp (name, "ieee1275/", sizeof ("ieee1275/") - 1) == 0)
     {
       port = grub_ofserial_add_port (&name[sizeof ("ieee1275/") - 1]);
-      if (port == NULL)
-        return NULL;
+      if (port != NULL)
+        return port;
     }
 #endif
 
-  return port;
+  return NULL;
 }
 
 static grub_err_t
diff --git a/include/grub/serial.h b/include/grub/serial.h
index 17ee0f08b..ce3ec10ec 100644
--- a/include/grub/serial.h
+++ b/include/grub/serial.h
@@ -219,4 +219,8 @@ extern void grub_serial_init (void);
 extern void grub_serial_fini (void);
 #endif
 
+extern struct grub_serial_port *grub_serial_ports;
+#define FOR_SERIAL_PORTS(var) FOR_LIST_ELEMENTS((var), (grub_serial_ports))
+
+
 #endif
-- 
2.34.1




reply via email to

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