WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] [rfc 16/18] ioemu: non-destructive parsing of PCI assignemen

To: xen-devel@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-devel] [rfc 16/18] ioemu: non-destructive parsing of PCI assignement strings
From: Simon Horman <horms@xxxxxxxxxxxx>
Date: Tue, 17 Feb 2009 20:08:04 +1100
Cc: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
Delivery-date: Tue, 17 Feb 2009 01:34:31 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
References: <20090217090748.580007796@xxxxxxxxxxxx>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: quilt/0.46-1
Signed-off-by: Simon Horman <horms@xxxxxxxxxxxx>

--- 
Fri, 13 Feb 2009 13:45:22 +1100
* Fix parsing of vslot - the regex was incorrect
* Allow 0x to prefix hex values that are parsed

Fri, 13 Feb 2009 15:22:10 +1100
* Rebased
  from "Restore xenfb.h and atkbd_ translation tables for * xenfbfront"
  to "fix memory/fd leak in pt_msix_init()"
Index: ioemu-remote/hw/pass-through.c
===================================================================
--- ioemu-remote.orig/hw/pass-through.c 2009-02-17 17:56:46.000000000 +0900
+++ ioemu-remote/hw/pass-through.c      2009-02-17 17:57:25.000000000 +0900
@@ -28,6 +28,12 @@
 #include "pt-msi.h"
 #include "qemu-xen.h"
 
+#include <sys/types.h>
+#include <regex.h>
+
+#define PHP_DEV_OPT_MSITRANSLATE 0x01
+#define PHP_DEV_OPT_ERROR        0x80
+
 struct php_dev {
     struct pt_dev *pt_dev;
     uint8_t valid;
@@ -35,7 +41,7 @@ struct php_dev {
     uint8_t r_dev;
     uint8_t r_func;
     uint8_t v_devfn;
-    char *opt;
+    uint8_t opt;
 };
 static struct dpci_infos {
 
@@ -750,62 +756,199 @@ static void cpy_php_dev(struct php_dev *
     memcpy(dst, src, sizeof(*dst));
 }
 
-static int token_value(char *token)
+static char *regerror_log(int errcode, const regex_t *preg)
 {
-    return strtol(token, NULL, 16);
+    size_t len = 0, new_len;
+    char *buf = NULL;
+
+    while (1)
+    {
+        new_len = regerror(errcode, preg, buf, len);
+        if (new_len <= len)
+            break;
+        len = new_len;
+        if (!(buf = realloc(buf, len)))
+        {
+            PT_LOG("Error: can't allocate %lu bytes for rexex error message\n",
+                   len);
+            return NULL;
+        }
+    }
+
+    return buf;
 }
 
-static struct php_dev next_bdf(char **str)
+static int opt_cmp(const char *source, const char *match)
 {
-    char *token;
-    const char *delim = ":.-";
-    struct php_dev bdf;
+    return strncmp(source, match, strlen(match));
+}
 
-    memset(&bdf, 0, sizeof(bdf));
+#define RE_OPT_MSITRANSLATE "msitranslate=\\(yes\\|1\\|no\\|0\\)"
 
-    if ( !(*str) ||
-          ( !strchr(*str, ':') && !strchr(*str, '.')) )
-        return bdf;
+static uint8_t parse_opt(const char *str, size_t n, int8_t opt)
+{
+    regmatch_t pmatch[2];
+    regex_t preg;
+    int err, status = PHP_DEV_OPT_ERROR;
+    char *err_str;
 
-    token  = strsep(str, delim);
-    /* segment */
+    if ((err = regcomp(&preg, RE_OPT_MSITRANSLATE, 0)))
+    {
+        if ((err_str = regerror_log(err, &preg)))
+        {
+            PT_LOG("regcomp() failed: %s\n", err_str);
+        }
+        else
+        {
+            PT_LOG("regcomp() failed\n");
+        }
+        return PHP_DEV_OPT_ERROR;
+    }
+
+    while (n > 0)
+    {
+        if ((err = regexec(&preg, str, 2, pmatch, 0)))
+        {
+            PT_LOG("Error: unrecognized PCI assignment option at \"%s\"\n",
+                   str);
+            goto err;
+        }
 
-    token  = strsep(str, delim);
-    bdf.r_bus  = token_value(token);
+        if (!opt_cmp(str + pmatch[1].rm_so, "no") ||
+            !opt_cmp(str + pmatch[1].rm_so, "0"))
+        {
+            opt &= ~PHP_DEV_OPT_MSITRANSLATE;
+        }
+        else if (!opt_cmp(str + pmatch[1].rm_so, "yes") ||
+                 !opt_cmp(str + pmatch[1].rm_so, "1"))
+        {
+            opt |= PHP_DEV_OPT_MSITRANSLATE;
+        }
 
-    token  = strsep(str, delim);
-    bdf.r_dev  = token_value(token);
+        n -= pmatch[0].rm_eo;
+        str += pmatch[0].rm_eo;
+        if (!n)
+        {
+            break;
+        }
+        if (*str != ',')
+        {
+            PT_LOG("Error: trailing garbage in PCI assignment option at "
+                   "\"%s\"\n", str);
+            goto err;
+        }
+        n--;
+        str++;
+        if (!n)
+        {
+            break;
+        }
+    }
 
-    token  = strsep(str, delim);
-    bdf.opt = strchr(token, ',');
-    if (bdf.opt)
-        *(bdf.opt)++ = '\0';
+    status = opt;
+err:
+    regfree(&preg);
+    return status;
+}
 
-    bdf.r_func  = token_value(token);
+#define RE_SEG  "\\(0x\\)\\?[0-9a-fA-F]\\{4\\}"
+#define RE_BUS  "\\(0x\\)\\?\\([0-9a-fA-F]\\{2\\}\\)"
+#define RE_DEV  "\\(0x\\)\\?\\([01][0-9a-fA-F]\\)"
+#define RE_FUNC "\\(0x\\)\\?\\([0-7]\\)"
+#define RE_BDF  RE_SEG ":" RE_BUS ":" RE_DEV "\\." RE_FUNC
 
-    bdf.valid = 1;
+#define RE_OPT  "\\(,\\([^@-]\\+\\)\\)"
+#define RE_BDF_OPT RE_BDF RE_OPT "\\?"
 
-    return bdf;
-}
+#define RE_VDEV  "\\(0x\\)\\?\\([01]\\?[0-9a-fA-F]\\)"
+#define RE_BDF_OPT_SLOT RE_BDF_OPT "\\(@" RE_VDEV "\\)\\?"
 
-static int get_next_keyval(char **option, char **key, char **val)
+static struct php_dev *parse_bdf(const char *str)
 {
-    char *opt, *k, *v;
+    struct php_dev *list = NULL, *e;
+    regex_t preg;
+    regmatch_t pmatch[14];
+    int err, nmemb = 0;
+    char *err_str;
 
-    k = *option;
-    opt = strchr(k, ',');
-    if (opt)
-        *opt++ = '\0';
-    v = strchr(k, '=');
-    if (!v)
-        return -1;
-    *v++ = '\0';
+    if ((err = regcomp(&preg, RE_BDF_OPT_SLOT, 0)))
+    {
+        if ((err_str = regerror_log(err, &preg)))
+        {
+            PT_LOG("regcomp() failed: %s\n", err_str);
+        }
+        else
+        {
+            PT_LOG("regcomp() failed\n");
+        }
+        return NULL;
+    }
 
-    *key = k;
-    *val = v;
-    *option = opt;
+    while (1)
+    {
+        if ((err = regexec(&preg, str, 14, pmatch, 0)))
+        {
+            PT_LOG("Error: invalid PCI assignment \"%s\"\n", str);
+            goto err;
+        }
 
-    return 0;
+        list = realloc(list, (++nmemb + 1) * sizeof(*list));
+        e = list + nmemb - 1;
+        memset(e, 0, sizeof(*e) * 2);
+
+        e->r_bus = strtol(str + pmatch[3].rm_so, NULL, 16);
+        e->r_dev = strtol(str + pmatch[5].rm_so, NULL, 16);
+        e->r_func = strtol(str + pmatch[7].rm_so, NULL, 16);
+
+        if (pmatch[9].rm_so >= 0)
+        {
+           if (parse_opt(str + pmatch[9].rm_so,
+                         pmatch[9].rm_eo - pmatch[9].rm_so,
+                         direct_pci_msitranslate) & PHP_DEV_OPT_ERROR)
+           {
+               goto err;
+           }
+        }
+
+        if (pmatch[12].rm_so >= 0)
+        {
+            e->v_devfn = PCI_DEVFN(strtol(str + pmatch[12].rm_so, NULL, 16), 
0);
+        }
+
+        e->valid = 1;
+
+        str += pmatch[0].rm_eo;
+        if (!*str)
+        {
+            break;
+        }
+        if (*str != '-')
+        {
+            PT_LOG("Error: trailing garbage in PCI assignment at \"%s\"\n",
+                   str);
+            goto err;
+        }
+        str++;
+        /* A trailing '-' delimiter is ok */
+        if (!*str)
+        {
+            break;
+        }
+    }
+
+    regfree(&preg);
+    return list;
+
+err:
+    regfree(&preg);
+    if (list)
+        free(list);
+    return NULL;
+}
+
+static struct php_dev *next_bdf(struct php_dev *l)
+{
+    return (++l)->valid ? l : NULL;
 }
 
 static void msi_set_enable(struct pt_dev *ptdev, int en)
@@ -881,27 +1024,21 @@ found:
 /* Insert a new pass-through device into function 0 of a specific pci slot.
  * input  dom:bus:dev.func@slot
  */
-int insert_bdf_to_php_devfn(char *bdf_slt)
+int insert_bdf_to_php_devfn(const char *bdf_slt)
 {
-    int slot;
-    struct php_dev bdf;
-    char *bdf_str, *slt_str, *opt;
-    const char *delim="@";
-
-    bdf_str = strsep(&bdf_slt, delim);
-    slt_str = bdf_slt;
-    slot = token_value(slt_str);
+    struct php_dev *bdf;
+    int status;
 
-    bdf = next_bdf(&bdf_str);
-    if (!bdf.valid)
+    bdf = parse_bdf(bdf_slt);
+    if (!bdf)
     {
         return -1;
     }
 
-    bdf.v_devfn = PCI_DEVFN(slot, 0);
-
-    return insert_to_php_devfn(&bdf);
+    status = insert_to_php_devfn(bdf);
+    free(bdf);
 
+    return status;
 }
 
 /* Test if a pci devfn has a device
@@ -924,30 +1061,32 @@ int test_php_devfn(int devfn)
 }
 
 /* find the pci slot for pass-through dev with specified BDF */
-int bdf_to_php_devfn(char *bdf_str)
+int bdf_to_php_devfn(const char *bdf_str)
 {
-    int i;
-    struct php_dev bdf;
+    int i, status = -1;
+    struct php_dev *bdf;
 
-    bdf = next_bdf(&bdf_str);
-    if (!bdf.valid)
+    bdf = parse_bdf(bdf_str);
+    if (!bdf)
     {
         return -1;
     }
-    PT_LOG("%s: bdf: %04x:%02x.%x\n", __func__, bdf.r_bus, bdf.r_dev,
-           bdf.r_func);
+    PT_LOG("%s: bdf: %04x:%02x.%x\n", __func__, bdf->r_bus, bdf->r_dev,
+           bdf->r_func);
 
     /* locate the virtual pci slot for this VTd device */
     for ( i = 0; i < PHP_DEVFN_LEN; i++ )
     {
         if ( dpci_infos.php_devs[i].valid &&
-             cmp_php_dev(&dpci_infos.php_devs[i], &bdf) )
+             cmp_php_dev(&dpci_infos.php_devs[i], bdf) )
         {
-            return PHP_TO_PCI_DEVFN(i);
+            status = PHP_TO_PCI_DEVFN(i);
+            break;
         }
     }
 
-    return -1;
+    free(bdf);
+    return status;
 }
 
 /* Being called each time a mmio region has been updated */
@@ -3132,8 +3271,6 @@ static struct pt_dev * register_real_dev
     uint8_t e_device, e_intx;
     struct pci_config_cf8 machine_bdf;
     int free_devfn = -1;
-    char *key, *val;
-    int msi_translate;
 
     PT_LOG("Assigning real physical device %02x:%02x.%x ...\n",
         bdf->r_bus, bdf->r_dev, bdf->r_func);
@@ -3159,35 +3296,6 @@ static struct pt_dev * register_real_dev
         PT_LOG("Error: no free virtual PCI hot plug slot, "
                "thus no live migration.\n");
 
-    msi_translate = direct_pci_msitranslate;
-    while (bdf->opt) {
-        if (get_next_keyval(&bdf->opt, &key, &val)) {
-            PT_LOG("Error: unrecognized PCI assignment option \"%s\"\n",
-                   bdf->opt);
-            break;
-        }
-
-        if (strcmp(key, "msitranslate") == 0)
-        {
-            if (strcmp(val, "0") == 0 || strcmp(val, "no") == 0)
-            {
-                PT_LOG("Disable MSI translation via per device option\n");
-                msi_translate = 0;
-            }
-            else if (strcmp(val, "1") == 0 || strcmp(val, "yes") == 0)
-            {
-                PT_LOG("Enable MSI translation via per device option\n");
-                msi_translate = 1;
-            }
-            else
-                PT_LOG("Error: unrecognized value for msitranslate=\n");
-        }
-        else
-            PT_LOG("Error: unrecognized PCI assignment option \"%s=%s\"\n", 
key, val);
-
-    }
-
-
     /* Register device */
     assigned_device = (struct pt_dev *) pci_register_device(e_bus, e_dev_name,
                                 sizeof(struct pt_dev), free_devfn,
@@ -3203,7 +3311,10 @@ static struct pt_dev * register_real_dev
                 assigned_device;
 
     assigned_device->pci_dev = pci_dev;
-    assigned_device->msi_trans_cap = msi_translate;
+    if (bdf->opt & PHP_DEV_OPT_MSITRANSLATE)
+    {
+        assigned_device->msi_trans_cap = 1;
+    }
 
     /* Assign device */
     machine_bdf.reg = 0;
@@ -3384,9 +3495,6 @@ int power_on_php_devfn(int php_devfn)
     pt_dev = register_real_device(dpci_infos.e_bus, "DIRECT PCI",
                                   php_dev, PT_MACHINE_IRQ_AUTO,
                                   dpci_infos.pci_access);
-
-    php_dev->opt = NULL;
-
     php_dev->pt_dev = pt_dev;
 
     return 0;
@@ -3405,9 +3513,7 @@ int pt_init(PCIBus *e_bus, const char *d
     struct pci_access *pci_access;
     char *vslots;
     char slot_str[8];
-    char *direct_pci_head = NULL;
-    char *direct_pci_p = NULL;
-    struct php_dev bdf;
+    struct php_dev *list, *bdf;
 
     /* Initialize libpci */
     pci_access = pci_alloc();
@@ -3427,29 +3533,21 @@ int pt_init(PCIBus *e_bus, const char *d
         return 0;
     }
 
-    if ( !(direct_pci_head = direct_pci_p = strdup(direct_pci)) )
-        return 0;
-
     /* the virtual pci slots of all pass-through devs
      * with hex format: xx;xx...;
      */
     vslots = qemu_mallocz ( strlen(direct_pci) / 3 );
 
     /* Assign given devices to guest */
-    while (1)
+    for (bdf = list = parse_bdf(direct_pci); bdf; bdf = next_bdf(bdf))
     {
-        bdf = next_bdf(&direct_pci_p);
-        if (!bdf.valid)
-        {
-            break;
-        }
         /* Register real device with the emulated bus */
         pt_dev = register_real_device(e_bus, "DIRECT PCI",
-                                      &bdf, PT_MACHINE_IRQ_AUTO, pci_access);
+                                      bdf, PT_MACHINE_IRQ_AUTO, pci_access);
         if ( pt_dev == NULL )
         {
             PT_LOG("Error: Registration failed (%02x:%02x.%x)\n",
-                   bdf.r_bus, bdf.r_dev, bdf.r_func);
+                   bdf->r_bus, bdf->r_dev, bdf->r_func);
             goto err;
         }
 
@@ -3458,13 +3556,15 @@ int pt_init(PCIBus *e_bus, const char *d
     }
 
     /* Write virtual slots info to xenstore for Control panel use */
-    xenstore_write_vslots(vslots);
+    if (*vslots)
+    {
+        xenstore_write_vslots(vslots);
+    }
 
     status = 0;
 err:
     qemu_free(vslots);
-    free(direct_pci_head);
-
+    free(list);
     return status;
 }
 
Index: ioemu-remote/hw/pci.h
===================================================================
--- ioemu-remote.orig/hw/pci.h  2009-02-17 17:55:37.000000000 +0900
+++ ioemu-remote/hw/pci.h       2009-02-17 17:57:05.000000000 +0900
@@ -115,17 +115,17 @@ PCIBus *pci_bridge_init(PCIBus *bus, int
 #define PCI_DEVFN_IS_PHP(x)   ((x) >= PHP_DEVFN_START && (x) < PHP_DEVFN_END)
 #define PHP_DEVFN_IS_VALID(x) (PCI_DEVFN_IS_PHP(PHP_TO_PCI_DEVFN(x)))
 
-int insert_bdf_to_php_devfn(char *bfd_slt);
+int insert_bdf_to_php_devfn(const char *bfd_slt);
 int test_php_devfn(int devfn);
-int bdf_to_php_devfn(char *bfd_str);
+int bdf_to_php_devfn(const char *bfd_str);
 int power_on_php_devfn(int php_devfn);
 int power_off_php_devfn(int php_devfn);
 
 /* pci_emulation.c */
 #include "hw/pci_emulation.h"
  
-void do_pci_add(char *devname);
-void do_pci_del(char *devname);
+void do_pci_add(const char *devname);
+void do_pci_del(const char *devname);
 
 /* lsi53c895a.c */
 #define LSI_MAX_DEVS 7
Index: ioemu-remote/vl.c
===================================================================
--- ioemu-remote.orig/vl.c      2009-02-17 17:55:37.000000000 +0900
+++ ioemu-remote/vl.c   2009-02-17 17:57:05.000000000 +0900
@@ -3898,7 +3898,7 @@ void qemu_chr_close(CharDriverState *chr
 }
 
 #ifdef CONFIG_PASSTHROUGH
-void do_pci_del(char *devname)
+void do_pci_del(const char *devname)
 {
     int devfn;
     devfn = bdf_to_php_devfn(devname);
@@ -3906,7 +3906,7 @@ void do_pci_del(char *devname)
     acpi_php_del(devfn);
 }
 
-void do_pci_add(char *devname)
+void do_pci_add(const char *devname)
 {
     int devfn;
 

-- 

-- 
Simon Horman
  VA Linux Systems Japan K.K., Sydney, Australia Satellite Office
  H: www.vergenet.net/~horms/             W: www.valinux.co.jp/en


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

<Prev in Thread] Current Thread [Next in Thread>