Nico Huber has uploaded this change for review. ( https://review.coreboot.org/21814
Change subject: rpci: Use pci_dev struct pointer to avoid API breaks
......................................................................
rpci: Use pci_dev struct pointer to avoid API breaks
The pci_dev structure is never meant to be used as is, but always as a
pointer. By using the struct itself in undo_pci_write_data, we are risking
data corruption, or buffer overflows if the structure size changes.
This is especially apparent on my system where flashrom segfaults
because I compile it with pciutils 3.3.0 and I run it on a system
with pciutils 3.5.2. The struture size is different and causes a
struct with the wrong size to be sent to the library, with invalid
internal field values.
This has been discovered and discussed in Change ID 18925 [1]
[1] https://review.coreboot.org/#/c/18925/
Original-Change-Id: Icde2e587992ba964d4ff92c33aa659850ba06298
Original-Reviewed-on: https://review.coreboot.org/20784
Original-Tested-by: build bot (Jenkins) <no-reply(a)coreboot.org>
Original-Reviewed-by: Nico Huber <nico.h(a)gmx.de>
Change-Id: I58dc4f37c5ea29cbad30777ebc0e6c2e3c6ad446
Signed-off-by: Youness Alaoui <kakaroto(a)kakaroto.homelinux.net>
---
M chipset_enable.c
M pcidev.c
M programmer.h
3 files changed, 25 insertions(+), 9 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/14/21814/1
diff --git a/chipset_enable.c b/chipset_enable.c
index 20d2662..6a93d0d 100644
--- a/chipset_enable.c
+++ b/chipset_enable.c
@@ -843,6 +843,7 @@
* straints (e.g. on PCI domains, extended PCIe config space).
*/
struct pci_access *const pci_acc = pci_alloc();
+ struct pci_access *const saved_pacc = pacc;
if (!pci_acc) {
msg_perr("Can't allocate PCI accessor.\n");
return ret;
@@ -857,6 +858,9 @@
return ret;
}
+ /* Modify pacc so the rpci_write can register the undo callback with a
+ * device using the correct pci_access */
+ pacc = pci_acc;
enable_flash_ich_report_gcs(spi_dev, pch_generation, NULL);
const int ret_bc = enable_flash_ich_bios_cntl_config_space(spi_dev, pch_generation, 0xdc);
@@ -880,6 +884,7 @@
_freepci_ret:
pci_free_dev(spi_dev);
+ pacc = saved_pacc;
return ret;
}
diff --git a/pcidev.c b/pcidev.c
index 2c78063..f4e5542 100644
--- a/pcidev.c
+++ b/pcidev.c
@@ -160,6 +160,7 @@
return 1;
}
pci_cleanup(pacc);
+ pacc = NULL;
return 0;
}
@@ -259,7 +260,7 @@
};
struct undo_pci_write_data {
- struct pci_dev dev;
+ struct pci_dev *dev;
int reg;
enum pci_write_type type;
union {
@@ -272,22 +273,23 @@
int undo_pci_write(void *p)
{
struct undo_pci_write_data *data = p;
- if (pacc == NULL) {
- msg_perr("%s: Tried to undo PCI writes without a valid PCI context!\n"
- "Please report a bug at flashrom(a)flashrom.org\n", __func__);
+ if (pacc == NULL || data->dev == NULL) {
+ msg_perr("%s: Tried to undo PCI writes without a valid PCI %s!\n"
+ "Please report a bug at flashrom(a)flashrom.org\n",
+ __func__, data->dev == NULL ? "device" : "context");
return 1;
}
msg_pdbg("Restoring PCI config space for %02x:%02x:%01x reg 0x%02x\n",
- data->dev.bus, data->dev.dev, data->dev.func, data->reg);
+ data->dev->bus, data->dev->dev, data->dev->func, data->reg);
switch (data->type) {
case pci_write_type_byte:
- pci_write_byte(&data->dev, data->reg, data->bytedata);
+ pci_write_byte(data->dev, data->reg, data->bytedata);
break;
case pci_write_type_word:
- pci_write_word(&data->dev, data->reg, data->worddata);
+ pci_write_word(data->dev, data->reg, data->worddata);
break;
case pci_write_type_long:
- pci_write_long(&data->dev, data->reg, data->longdata);
+ pci_write_long(data->dev, data->reg, data->longdata);
break;
}
/* p was allocated in register_undo_pci_write. */
@@ -303,7 +305,11 @@
msg_gerr("Out of memory!\n"); \
exit(1); \
} \
- undo_pci_write_data->dev = *a; \
+ if (pacc) \
+ undo_pci_write_data->dev = pci_get_dev(pacc, \
+ a->domain, a->bus, a->dev, a->func); \
+ else \
+ undo_pci_write_data->dev = NULL; \
undo_pci_write_data->reg = b; \
undo_pci_write_data->type = pci_write_type_##c; \
undo_pci_write_data->c##data = pci_read_##c(dev, reg); \
diff --git a/programmer.h b/programmer.h
index ec00bd9..e58fd32 100644
--- a/programmer.h
+++ b/programmer.h
@@ -195,6 +195,11 @@
struct pci_dev *pcidev_init(const struct dev_entry *devs, int bar);
/* rpci_write_* are reversible writes. The original PCI config space register
* contents will be restored on shutdown.
+ * To clone the pci_dev instances internally, the `pacc` global
+ * variable has to reference a pci_access method that is compatible
+ * with the given pci_dev handle. The referenced pci_access (not
+ * the variable) has to stay valid until the shutdown handlers are
+ * finished.
*/
int rpci_write_byte(struct pci_dev *dev, int reg, uint8_t data);
int rpci_write_word(struct pci_dev *dev, int reg, uint16_t data);
--
To view, visit https://review.coreboot.org/21814
To unsubscribe, visit https://review.coreboot.org/settings
Gerrit-Project: flashrom
Gerrit-Branch: stable
Gerrit-MessageType: newchange
Gerrit-Change-Id: I58dc4f37c5ea29cbad30777ebc0e6c2e3c6ad446
Gerrit-Change-Number: 21814
Gerrit-PatchSet: 1
Gerrit-Owner: Nico Huber <nico.h(a)gmx.de>
Hello Urja Rannikko,
I'd like you to do a code review. Please visit
https://review.coreboot.org/21813
to review the following change.
Change subject: Enable continuous SPI reads
......................................................................
Enable continuous SPI reads
Previous unnecessary page-by-page reading is repurposed to
read by big naturally aligned areas (now chip size limited
to 16MB for future-proofing of 4 byte addressed multi-die chips)
and serprog hack for continuous reads is removed.
Original-Change-Id: Iadf909c9216578b1c5dacd4c4991bb436e32edc9
Original-Reviewed-on: https://review.coreboot.org/20223
Original-Reviewed-by: Nico Huber <nico.h(a)gmx.de>
Original-Tested-by: build bot (Jenkins) <no-reply(a)coreboot.org>
Change-Id: I8fdf4621847b1973e5d7344b369d63da5c62e16f
Signed-off-by: Urja Rannikko <urjaman(a)gmail.com>
---
M serprog.c
M spi25.c
2 files changed, 15 insertions(+), 35 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/13/21813/1
diff --git a/serprog.c b/serprog.c
index 98aac83..25c9944 100644
--- a/serprog.c
+++ b/serprog.c
@@ -303,15 +303,13 @@
unsigned int writecnt, unsigned int readcnt,
const unsigned char *writearr,
unsigned char *readarr);
-static int serprog_spi_read(struct flashctx *flash, uint8_t *buf,
- unsigned int start, unsigned int len);
static struct spi_master spi_master_serprog = {
.type = SPI_CONTROLLER_SERPROG,
.max_data_read = MAX_DATA_READ_UNLIMITED,
.max_data_write = MAX_DATA_WRITE_UNLIMITED,
.command = serprog_spi_send_command,
.multicommand = default_spi_send_multicommand,
- .read = serprog_spi_read,
+ .read = default_spi_read,
.write_256 = default_spi_write_256,
.write_aai = default_spi_write_aai,
};
@@ -931,25 +929,6 @@
readarr);
free(parmbuf);
return ret;
-}
-
-/* FIXME: This function is optimized so that it does not split each transaction
- * into chip page_size long blocks unnecessarily like spi_read_chunked. This has
- * the advantage that it is much faster for most chips, but breaks those with
- * non-continuous reads. When spi_read_chunked is fixed this method can be removed. */
-static int serprog_spi_read(struct flashctx *flash, uint8_t *buf,
- unsigned int start, unsigned int len)
-{
- unsigned int i, cur_len;
- const unsigned int max_read = spi_master_serprog.max_data_read;
- for (i = 0; i < len; i += cur_len) {
- int ret;
- cur_len = min(max_read, (len - i));
- ret = spi_nbyte_read(flash, start + i, buf + i, cur_len);
- if (ret)
- return ret;
- }
- return 0;
}
void *serprog_map(const char *descr, uintptr_t phys_addr, size_t len)
diff --git a/spi25.c b/spi25.c
index af4b6db..76242be 100644
--- a/spi25.c
+++ b/spi25.c
@@ -940,30 +940,31 @@
/*
* Read a part of the flash chip.
* FIXME: Use the chunk code from Michael Karcher instead.
- * Each page is read separately in chunks with a maximum size of chunksize.
+ * Each naturally aligned area is read separately in chunks with a maximum size of chunksize.
*/
int spi_read_chunked(struct flashctx *flash, uint8_t *buf, unsigned int start,
unsigned int len, unsigned int chunksize)
{
int rc = 0;
unsigned int i, j, starthere, lenhere, toread;
- unsigned int page_size = flash->chip->page_size;
+ /* Limit for multi-die 4-byte-addressing chips. */
+ unsigned int area_size = min(flash->chip->total_size * 1024, 16 * 1024 * 1024);
/* Warning: This loop has a very unusual condition and body.
- * The loop needs to go through each page with at least one affected
- * byte. The lowest page number is (start / page_size) since that
- * division rounds down. The highest page number we want is the page
+ * The loop needs to go through each area with at least one affected
+ * byte. The lowest area number is (start / area_size) since that
+ * division rounds down. The highest area number we want is the area
* where the last byte of the range lives. That last byte has the
- * address (start + len - 1), thus the highest page number is
- * (start + len - 1) / page_size. Since we want to include that last
- * page as well, the loop condition uses <=.
+ * address (start + len - 1), thus the highest area number is
+ * (start + len - 1) / area_size. Since we want to include that last
+ * area as well, the loop condition uses <=.
*/
- for (i = start / page_size; i <= (start + len - 1) / page_size; i++) {
- /* Byte position of the first byte in the range in this page. */
+ for (i = start / area_size; i <= (start + len - 1) / area_size; i++) {
+ /* Byte position of the first byte in the range in this area. */
/* starthere is an offset to the base address of the chip. */
- starthere = max(start, i * page_size);
- /* Length of bytes in the range in this page. */
- lenhere = min(start + len, (i + 1) * page_size) - starthere;
+ starthere = max(start, i * area_size);
+ /* Length of bytes in the range in this area. */
+ lenhere = min(start + len, (i + 1) * area_size) - starthere;
for (j = 0; j < lenhere; j += chunksize) {
toread = min(chunksize, lenhere - j);
rc = spi_nbyte_read(flash, starthere + j, buf + starthere - start + j, toread);
--
To view, visit https://review.coreboot.org/21813
To unsubscribe, visit https://review.coreboot.org/settings
Gerrit-Project: flashrom
Gerrit-Branch: stable
Gerrit-MessageType: newchange
Gerrit-Change-Id: I8fdf4621847b1973e5d7344b369d63da5c62e16f
Gerrit-Change-Number: 21813
Gerrit-PatchSet: 1
Gerrit-Owner: Nico Huber <nico.h(a)gmx.de>
Gerrit-Reviewer: Urja Rannikko <urjaman(a)gmail.com>