[flashrom] [PATCH 4/5] ichspi: warn if regions defined by FREGs do not cover the whole flash space

Stefan Tauner stefan.tauner at student.tuwien.ac.at
Fri Oct 21 00:39:08 CEST 2011


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 <stefan.tauner at student.tuwien.ac.at>
---
 ichspi.c |  136 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 136 insertions(+), 0 deletions(-)

diff --git a/ichspi.c b/ichspi.c
index e296551..63c6f17 100644
--- a/ichspi.c
+++ b/ichspi.c
@@ -1397,6 +1397,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] = {
@@ -1407,6 +1519,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;
@@ -1423,6 +1536,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]);
 }
@@ -1515,6 +1633,7 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb,
 	int desc_valid = 0;
 	int hwseq_en = 0;
 	struct ich_descriptors desc = {{ 0 }};
+	uint32_t flash_size;
 
 	switch (ich_generation) {
 	case 7:
@@ -1625,6 +1744,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 */
@@ -1705,11 +1825,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_opaque_programmer(&opaque_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 "
+					  "flashrom at flashrom.org, thanks!\n\n");
+			
 		break;
 	}
 
-- 
1.7.1





More information about the flashrom mailing list