[coreboot-gerrit] New patch to review for coreboot: coreboot: add rdevbs (region device byte stream)

Aaron Durbin (adurbin@chromium.org) gerrit at coreboot.org
Fri Sep 11 15:34:19 CET 2015


Aaron Durbin (adurbin at chromium.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/11624

-gerrit

commit 991d8f8029b9a04414f9c03cbccf932dc3a389d0
Author: Aaron Durbin <adurbin at chromium.org>
Date:   Fri Sep 11 09:49:12 2015 -0500

    coreboot: add rdevbs (region device byte stream)
    
    Add a region device byte stream object, rdevbs, which
    will perform designated endian operations for reading
    serialized objects out of a region device. The cbfs
    walking code was updated to show usage of the library.
    
    The implementation uses memory region device after
    performing a mapping on the original parent. The reason
    is absorb the communication costs of dealing with a
    controller and its external media.
    
    TEST=Booted glados.
    
    Change-Id: I60feb24ae1b2abadb23b23201f38c85ade5bcfbd
    Signed-off-by: Aaron Durbin <adurbin at chromium.org>
---
 src/include/region.h | 28 ++++++++++++++++++
 src/lib/cbfs.c       | 51 +++++++++++++++++++++-----------
 src/lib/region.c     | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 144 insertions(+), 17 deletions(-)

diff --git a/src/include/region.h b/src/include/region.h
index 82db854..1c9cb6d 100644
--- a/src/include/region.h
+++ b/src/include/region.h
@@ -154,4 +154,32 @@ void mmap_helper_device_init(struct mmap_helper_region_device *mdev,
 void *mmap_helper_rdev_mmap(const struct region_device *, size_t, size_t);
 int mmap_helper_rdev_munmap(const struct region_device *, void *);
 
+/* Interpret region_device as byte stream operations with endian conversions. */
+struct rdevbs;
+
+enum {
+	BE_BS, /* Big Endian */
+	LE_BS, /* Little Endian */
+};
+/*
+ * Initialize an rdev byte stream from parent for reading stream_size bytes
+ * using the providded endianness interpretation. Returns 0 on success, < 0
+ * on error.
+ */
+int rdevbs_init(struct rdevbs *bs, const struct region_device *parent,
+		size_t stream_offset, size_t stream_size, int endianness);
+
+/* Return 0 on success, < 0 on error. */
+int rdevbs_read(struct rdevbs *bs, void *dest, size_t size);
+
+/* Indicate that the bytream is complete and any resources can be freed. */
+void rdevbs_complete(struct rdevbs *bs);
+
+struct rdevbs {
+	const struct region_device *parent;
+	struct mem_region_device memdev;
+	size_t current_offset;
+	int endianness;
+};
+
 #endif /* _REGION_H_ */
diff --git a/src/lib/cbfs.c b/src/lib/cbfs.c
index abc4077..4075b7f 100644
--- a/src/lib/cbfs.c
+++ b/src/lib/cbfs.c
@@ -90,30 +90,47 @@ int cbfs_locate(struct region_device *fh, const struct cbfsd *cbfs,
 
 	/* Try to scan the entire cbfs region looking for file name. */
 	while (1) {
-		struct cbfs_file file;
-		const size_t fsz = sizeof(file);
+		uint8_t magic[8];
+		uint32_t flen;
+		uint32_t ftype;
+		uint32_t fchecksum;
+		uint32_t foffset;
+		const size_t fsz = sizeof(struct cbfs_file);
 		char *fname;
 		int name_match;
 		size_t datasz;
+		struct rdevbs bs;
+		size_t i;
 
 		DEBUG("Checking offset %zx\n", offset);
 
-		/* Can't read file. Nothing else to do but bail out. */
-		if (rdev_readat(rd, &file, offset, fsz) != fsz)
+		if (rdevbs_init(&bs, rd, offset, fsz, BE_BS))
 			break;
 
-		if (memcmp(file.magic, CBFS_FILE_MAGIC, sizeof(file.magic))) {
+		/* Joy. magic is a byte array w/o an endian encoding. */
+		for (i = 0; i < sizeof(magic); i++)
+			if (rdevbs_read(&bs, &magic[i], sizeof(magic[i])))
+				break;
+
+		if (rdevbs_read(&bs, &flen, sizeof(flen)))
+			break;
+		if (rdevbs_read(&bs, &ftype, sizeof(ftype)))
+			break;
+		if (rdevbs_read(&bs, &fchecksum, sizeof(fchecksum)))
+			break;
+		if (rdevbs_read(&bs, &foffset, sizeof(foffset)))
+			break;
+
+		rdevbs_complete(&bs);
+
+		if (memcmp(magic, CBFS_FILE_MAGIC, sizeof(magic))) {
 			offset++;
 			offset = ALIGN_UP(offset, CBFS_ALIGNMENT);
 			continue;
 		}
 
-		file.len = ntohl(file.len);
-		file.type = ntohl(file.type);
-		file.offset = ntohl(file.offset);
-
 		/* See if names match. */
-		fname = rdev_mmap(rd, offset + fsz, file.offset - fsz);
+		fname = rdev_mmap(rd, offset + fsz, foffset - fsz);
 
 		if (fname == NULL)
 			break;
@@ -123,23 +140,23 @@ int cbfs_locate(struct region_device *fh, const struct cbfsd *cbfs,
 
 		if (!name_match) {
 			DEBUG(" Unmatched '%s' at %zx\n", fname, offset);
-			offset += file.offset + file.len;
+			offset += foffset + flen;
 			offset = ALIGN_UP(offset, CBFS_ALIGNMENT);
 			continue;
 		}
 
-		if (type != NULL && *type != file.type) {
-			DEBUG(" Unmatched type %x at %zx\n", file.type, offset);
-			offset += file.offset + file.len;
+		if (type != NULL && *type != ftype) {
+			DEBUG(" Unmatched type %x at %zx\n", ftype, offset);
+			offset += foffset + flen;
 			offset = ALIGN_UP(offset, CBFS_ALIGNMENT);
 			continue;
 		}
 
-		LOG("Found @ offset %zx size %x\n", offset, file.len);
+		LOG("Found @ offset %zx size %x\n", offset, flen);
 		/* File and type match. Create a chained region_device to
 		 * represent the cbfs file. */
-		offset += file.offset;
-		datasz = file.len;
+		offset += foffset;
+		datasz = flen;
 		if (rdev_chain(fh, rd, offset, datasz))
 			break;
 
diff --git a/src/lib/region.c b/src/lib/region.c
index d5d3762..4dd4adc 100644
--- a/src/lib/region.c
+++ b/src/lib/region.c
@@ -17,6 +17,7 @@
  * Foundation, Inc.
  */
 
+#include <endian.h>
 #include <region.h>
 #include <string.h>
 
@@ -194,3 +195,84 @@ int mmap_helper_rdev_munmap(const struct region_device *rd, void *mapping)
 
 	return 0;
 }
+
+int rdevbs_init(struct rdevbs *bs, const struct region_device *parent,
+		size_t stream_offset, size_t stream_size, int endianness)
+{
+	void *mapping;
+
+	bs->parent = parent;
+	bs->current_offset = 0;
+	bs->endianness = endianness;
+	if (endianness != LE_BS && endianness != BE_BS)
+		return -1;
+
+	/*
+	 * One needs the object storage in order to read from the stream
+	 * efficiently. Otherwise there would be many small round trip
+	 * operations to the backing controller. Instead use a mapping of
+	 * the size to be consumed.
+	 */
+	mapping = rdev_mmap(parent, stream_offset, stream_size);
+
+	if (mapping == NULL)
+		return -1;
+
+	mem_region_device_init(&bs->memdev, mapping, stream_size);
+
+	return 0;
+}
+
+int rdevbs_read(struct rdevbs *bs, void *dest, size_t size)
+{
+	union {
+		uint64_t bits64;
+		uint32_t bits32;
+		uint16_t bits16;
+		uint8_t bits8;
+	} b;
+
+	if (size != sizeof(b.bits64) && size != sizeof(b.bits32) &&
+			size != sizeof(b.bits16) && size != sizeof(b.bits8))
+		return -1;
+
+	if (rdev_readat(&bs->memdev.rdev, &b, bs->current_offset, size) != size)
+		return -1;
+
+	if (bs->endianness == LE_BS) {
+		switch (size) {
+		case sizeof(b.bits64):
+			b.bits64 = le64toh(b.bits64);
+			break;
+		case sizeof(b.bits32):
+			b.bits32 = le32toh(b.bits32);
+			break;
+		case sizeof(b.bits16):
+			b.bits16 = le16toh(b.bits16);
+			break;
+		}
+	} else {
+		switch (size) {
+		case sizeof(b.bits64):
+			b.bits64 = be64toh(b.bits64);
+			break;
+		case sizeof(b.bits32):
+			b.bits32 = be32toh(b.bits32);
+			break;
+		case sizeof(b.bits16):
+			b.bits16 = be16toh(b.bits16);
+			break;
+		}
+	}
+
+	memcpy(dest, &b, size);
+	bs->current_offset += size;
+
+	return 0;
+}
+
+void rdevbs_complete(struct rdevbs *bs)
+{
+	rdev_munmap(bs->parent, bs->memdev.base);
+	bs->parent = NULL;
+}



More information about the coreboot-gerrit mailing list