diff options
-rw-r--r-- | external/opal-prd/hostboot-interface.h | 4 | ||||
-rw-r--r-- | external/opal-prd/pnor.c | 32 |
2 files changed, 26 insertions, 10 deletions
diff --git a/external/opal-prd/hostboot-interface.h b/external/opal-prd/hostboot-interface.h index 1088178..a518f50 100644 --- a/external/opal-prd/hostboot-interface.h +++ b/external/opal-prd/hostboot-interface.h @@ -170,7 +170,7 @@ struct host_interfaces { * @param[in] i_offset: offset within the partition * @param[out] o_data: pointer to the data read * @param[in] i_sizeBytes: size of data to read - * @retval rc - non-zero on error + * @retval rc - number of bytes read, or non-zero on error * @platform OpenPOWER */ int (*pnor_read) ( uint32_t i_proc, const char* i_partitionName, @@ -183,7 +183,7 @@ struct host_interfaces { * @param[in] i_offset: offset withing the partition * @param[in] i_data: pointer to the data to write * @param[in] i_sizeBytes: size of data to write - * @retval rc - non-zero on error + * @retval rc - number of bytes written, or non-zero on error * @platform OpenPOWER */ int (*pnor_write) ( uint32_t i_proc, const char* i_partitionName, diff --git a/external/opal-prd/pnor.c b/external/opal-prd/pnor.c index e5609fe..e40d292 100644 --- a/external/opal-prd/pnor.c +++ b/external/opal-prd/pnor.c @@ -240,11 +240,16 @@ out: return rc; } +/* Similar to read(2), this performs partial operations where the number of + * bytes read/written may be less than size. + * + * Returns number of bytes written, or a negative value on failure. */ int pnor_operation(struct pnor *pnor, const char *name, uint64_t offset, - void *data, size_t size, enum pnor_op op) + void *data, size_t requested_size, enum pnor_op op) { int rc, fd; uint32_t pstart, psize, idx; + int size; if (!pnor->ffsh) { warnx("PNOR: ffs not initialised"); @@ -263,9 +268,23 @@ int pnor_operation(struct pnor *pnor, const char *name, uint64_t offset, return -ENOENT; } - if (size > psize || offset > psize || size + offset > psize) { - warnx("PNOR: offset (%ld) or size (%ld) out of bounds (%d)", - offset, size, psize); + if (offset > psize) { + warnx("PNOR: offset (%ld) out of bounds (%d)", offset, psize); + return -ERANGE; + } + + /* Large requests are trimmed */ + if (requested_size > psize) + size = psize; + else + size = requested_size; + + if (size + offset > psize) + size = psize - offset; + + if (size < 0) { + warnx("PNOR: size (%zd) and offset (%ld) out of bounds (%d)", + requested_size, offset, psize); return -ERANGE; } @@ -297,11 +316,8 @@ int pnor_operation(struct pnor *pnor, const char *name, uint64_t offset, if (rc < 0) warn("PNOR: MTD operation failed"); else if (rc != size) - warnx("PNOR: mtd operation returned %d, expected %zd", + warnx("PNOR: mtd operation returned %d, expected %d", rc, size); - else - rc = 0; - out: close(fd); |