the chipset will deny any access to addresses outside the defined regions and
these registers are RO even if the configuration is not locked down.
this usually indicates a broken BIOS/flash descriptor and can only mitigated by
not accessing addresses outside the regions with a layout file.

the implementation is not for merge.
most of the routines should probably be moved to layout.c or similar and
integrated with a generic layout entry data structure (think of a struct that
is able to hold all information needed to define one line of a (future) layout 
file
i.e. address range, name, access rights, lock status etc.).

Signed-off-by: Stefan Tauner <[email protected]>
---
 ichspi.c |  136 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 136 insertions(+), 0 deletions(-)

diff --git a/ichspi.c b/ichspi.c
index fd42ba3..896ac5e 100644
--- a/ichspi.c
+++ b/ichspi.c
@@ -1446,6 +1446,118 @@ static int ich_spi_send_multicommand(struct spi_command 
*cmds)
 #define ICH_BRWA(x)  ((x >>  8) & 0xff)
 #define ICH_BRRA(x)  ((x >>  0) & 0xff)
 
+struct range {
+       uint32_t offset;
+       uint32_t size;
+       struct range *next;
+};
+
+static void prettyprint_range_list(struct range *cur)
+{
+       unsigned int i = 0;
+       while (cur != NULL) {
+               msg_pspew("#%d: offset=0x%08x, size=0x%08x\n",
+                         i++, cur->offset, cur->size);
+               cur = cur->next;
+       }
+}
+
+/* Frees every element in the list */
+static void free_range_list(struct range *cur)
+{
+       struct range *next;
+       while (cur != NULL) {
+               next = cur->next;
+               free(cur);
+               cur = next;
+       }
+}
+
+/* Unifies a *sorted* list of ranges. This means that overlapping regions are
+ * combined to a single region. The given list r is modifed and returned.
+ */
+static struct range *unify_range_list(struct range *const r)
+{
+       struct range *cur = r;
+       struct range *next;
+       while (cur != NULL && cur->next != NULL) {
+               next = cur->next;
+               if (cur->offset + cur->size >= next->offset) {
+                       cur->size = next->offset + next->size - cur->offset;
+                       cur->next = next->next;
+                       free(next);
+               } else
+                       cur = cur->next;
+       }
+       return r;
+}
+
+/* Unifies two *sorted* lists of ranges into a third one.
+ * Returns the newly allocated third list, or NULL if inputs are empty lists or
+ * an error occurred.
+ */
+static struct range *unify_range_lists(struct range *const r1, struct range 
*const r2)
+{
+       struct range *cur = NULL;
+       struct range *new = NULL;
+       struct range *cur1 = r1;
+       struct range *cur2 = r2;
+
+       /* first, iterate over all entries from the first range.
+        * compare them to the lowest, unprocessed element of the second one
+        * and copy the one with the smaller offset over to the new list.
+        * this ensures that the new list is sorted all the time.
+        */
+       while (cur1 != NULL) {
+               /* first element of the new list handled as special case */
+               if (cur == NULL) {
+                       cur = malloc(sizeof(struct range));
+                       new = cur;
+               } else {
+                       cur->next = malloc(sizeof(struct range));
+                       cur = cur->next;
+               }
+               if (cur == NULL) {
+                       free_range_list(new);
+                       return NULL;
+               }
+               cur->next = NULL;
+               if (cur2 == NULL || cur1->offset < cur2->offset) {
+                       cur->offset = cur1->offset;
+                       cur->size = cur1->size;
+                       cur1 = cur1->next;
+               } else {
+                       cur->offset = cur2->offset;
+                       cur->size = cur2->size;
+                       cur2 = cur2->next;
+               }
+       }
+
+       /* then copy over the remaining elements from the second list */
+       while (cur2 != NULL) {
+               /* first element of the new list handled as special case */
+               if (cur == NULL) {
+                       cur = malloc(sizeof(struct range));
+                       new = cur;
+               } else {
+                       cur->next = malloc(sizeof(struct range));
+                       cur = cur->next;
+               }
+               if (cur == NULL) {
+                       free_range_list(new);
+                       return NULL;
+               }
+               cur->next = NULL;
+               cur->offset = cur2->offset;
+               cur->size = cur2->size;
+               cur2 = cur2->next;
+       }
+
+       return unify_range_list(new);
+}
+
+static struct range *ich_ranges = NULL;
+
 static void do_ich9_spi_frap(uint32_t frap, int i)
 {
        static const char *const access_names[4] = {
@@ -1456,6 +1568,7 @@ static void do_ich9_spi_frap(uint32_t frap, int i)
                "Gigabit Ethernet", "Platform Data"
        };
        uint32_t base, limit;
+       struct range cur;
        int rwperms = (((ICH_BRWA(frap) >> i) & 1) << 1) |
                      (((ICH_BRRA(frap) >> i) & 1) << 0);
        int offset = ICH9_REG_FREG0 + i * 4;
@@ -1472,6 +1585,11 @@ static void do_ich9_spi_frap(uint32_t frap, int i)
                return;
        }
 
+       cur.size = (limit | 0x0fff) + 1 - base;
+       cur.offset = base;
+       cur.next = NULL;
+       
+       ich_ranges = unify_range_lists(ich_ranges, &cur);
        msg_pdbg("0x%08x-0x%08x is %s\n", base, (limit | 0x0fff),
                 access_names[rwperms]);
 }
@@ -1675,6 +1793,7 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void 
*rcrb,
                        /* Decode and print FREGx and FRAP registers */
                        for (i = 0; i < 5; i++)
                                do_ich9_spi_frap(tmp, i);
+                       prettyprint_range_list(ich_ranges);
                }
 
                /* try to disable PR locks before printing them */
@@ -1732,6 +1851,7 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void 
*rcrb,
                msg_pdbg("\n");
                { /* to be able to declare variables here */
                struct ich_descriptors desc = {{ 0 }};
+               uint32_t flash_size;
                if (desc_valid) {
                        if (read_ich_descriptors_via_fdo(ich_spibar, &desc) ==
                            ICH_RET_OK)
@@ -1758,11 +1878,27 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, 
void *rcrb,
                        }
                        hwseq.size_comp0 = getFCBA_component_density(&desc, 0);
                        hwseq.size_comp1 = getFCBA_component_density(&desc, 1);
+                       flash_size = hwseq.size_comp0 + hwseq.size_comp1;
                        register_spi_programmer(&spi_programmer_ich_hwseq);
                } else {
+                       flash_size = getFCBA_component_density(&desc, 0);
                        register_spi_programmer(&spi_programmer_ich9);
                        ich_init_opcodes();
                }
+               if (ich_ranges != NULL)
+                       if (ich_ranges->next != NULL ||
+                           ich_ranges->offset != 0 ||
+                           ich_ranges->size != flash_size)
+                               msg_pinfo("WARNING: The regions defined by the "
+                                         "FREG registers do not cover the "
+                                         "whole flash\naddress space. The "
+                                         "chipset will deny access to any "
+                                         "address outside the defined\n"
+                                         "regions. Please use a layout file "
+                                         "to mitigate this and send us a log "
+                                         "with maximum\nverbosity (-VVV) to "
+                                         "[email protected], thanks!\n\n");
+                       
                }
                ich_init_opcodes();
                break;
-- 
1.7.1


_______________________________________________
flashrom mailing list
[email protected]
http://www.flashrom.org/mailman/listinfo/flashrom

Reply via email to