This patch is for testing only, and not for immediate merge.
libpci unhelpfully calls exit(1) instead of reporting an error if init fails. Fortunately, that part of libpci has not changed since the year 2000, so we can use a really evil hack to avoid that. We supply an alternative error printing function (which does not exit(1)) and this function detects which error is happening and hacks internal libpci structures in a way that avoids a later segfault due to NULL pointer dereference.
We MUST absolutely make sure that pci_init() in libpci will not change or this hack will explode spectacularly. Once we decide that this hack is the way to go, notifying the libpci maintainer is essential.
Apply this patch, then compile flashrom with make CONFIG_DUMMY=no CONFIG_INTERNAL=o CONFIG_SERPROG=no CONFIG_RAYER_SPI=no CONFIG_NIC3COM=no CONFIG_GFXNVIDIA=no CONFIG_SATASII=no CONFIG_FT2232_SPI=no CONFIG_DRKAISER=no CONFIG_NICREALTEK=no CONFIG_NICINTEL_SPI=no CONFIG_BUSPIRATE_SPI=no CONFIG_OGP_SPI=no CONFIG_SATAMV=no CONFIG_NICINTEL=yes
To check if the hack works, run "flashrom -V" and respond to this mail with the output. You should get a message near the end which says that programmer initialization failed.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-libpci_hack_avoid_exit1_during_init/pcidev.c =================================================================== --- flashrom-libpci_hack_avoid_exit1_during_init/pcidev.c (Revision 1362) +++ flashrom-libpci_hack_avoid_exit1_during_init/pcidev.c (Arbeitskopie) @@ -21,6 +21,8 @@
#include <stdlib.h> #include <string.h> +#include <stdio.h> +#include <stdarg.h> #include "flash.h" #include "programmer.h"
@@ -188,6 +190,58 @@ return 0; }
+/* Ugliest hack ever in flashrom! Should work for all libpci versions released + * in the year 2000 or later. Checked to make sense until at least version + * 3.1.8-test1. + */ +static void fake_libpci_method_init(struct pci_access *foo) +{ + msg_pinfo("Working around another pcilib crash\n"); + return; +} + +static struct { + char *name; /* name in all libpci versions */ + char *dummy1; /* Only present in some libpci versions */ + void *dummy2; + void (*init1)(struct pci_access *); /* init in older versions */ + void (*init2)(struct pci_access *); /* init in newer versions */ + void *dummy3; + void *dummy4; + void *dummy5; + void *dummy6; + void *dummy7; + void *dummy8; + void *dummy9; + void *dummy10; +} fake_libpci_methods = { + .name = "None", + .init1 = &fake_libpci_method_init, + .init2 = &fake_libpci_method_init, +}; + +static int pci_init_failed = 0; + +static void my_libpci_generic_error(char *msg, ...) +{ + va_list ap; + + msg_pinfo("pcilib: "); + va_start(ap, msg); + vprintf(msg, ap); + va_end(ap); + msg_pinfo("\n"); + if (!strcmp(msg, "Cannot find any working access method.")) { + /* Workaround for crash, very ugly. */ + msg_pinfo("Working around pcilib crash\n"); + pacc->methods = (void *)&fake_libpci_methods; + pci_init_failed = 1; + } else { + /* Any error in libpci would result in exit(1) by default. */ + exit(1); + } +} + uintptr_t pcidev_init(int bar, const struct pcidev_status *devs) { struct pci_dev *dev; @@ -198,7 +252,14 @@ uintptr_t addr = 0, curaddr = 0;
pacc = pci_alloc(); /* Get the pci_access structure */ + pacc->error = &my_libpci_generic_error; pci_init(pacc); /* Initialize the PCI library */ + /* pci_init returns void, so we have to hack it. */ + if (pci_init_failed) { + /* Yes, technically we would have to free stuff... */ + return 1; + } + pci_scan_bus(pacc); /* We want to get the list of devices */ pci_filter_init(pacc, &filter);