summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/commonlib/Makefile.inc7
-rw-r--r--src/commonlib/include/commonlib/iobuf.h162
-rw-r--r--src/commonlib/iobuf.c422
3 files changed, 591 insertions, 0 deletions
diff --git a/src/commonlib/Makefile.inc b/src/commonlib/Makefile.inc
index 3c375d5674..255a241cba 100644
--- a/src/commonlib/Makefile.inc
+++ b/src/commonlib/Makefile.inc
@@ -4,6 +4,13 @@ romstage-y += mem_pool.c
ramstage-y += mem_pool.c
postcar-y += mem_pool.c
+bootblock-y += iobuf.c
+verstage-y += iobuf.c
+romstage-y += iobuf.c
+ramstage-y += iobuf.c
+smm-y += iobuf.c
+postcar-y += iobuf.c
+
bootblock-y += region.c
verstage-y += region.c
romstage-y += region.c
diff --git a/src/commonlib/include/commonlib/iobuf.h b/src/commonlib/include/commonlib/iobuf.h
new file mode 100644
index 0000000000..c5a0f4c6fb
--- /dev/null
+++ b/src/commonlib/include/commonlib/iobuf.h
@@ -0,0 +1,162 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2017 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef COMMONLIB_IOBUF_H
+#define COMMONLIB_IOBUF_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+/*
+ * Two types are provided to aid in dealing with automatic buffer management
+ * for code that deals with serializing and deserializing data structures.
+ * The ibuf (input buffer) is read from while the obuf (output buffer) is
+ * written to. Both keep track of capacity of the buffer as well as current
+ * read or write cursor.
+ *
+ * When splicing or splitting ibufs of obufs the source object doesn't track
+ * reads or writes through the newly created objects back to the source object.
+ *
+ * Any function returning an int encodes the return values as < 0 on error
+ * and 0 on success. Any function returning a pointer returns NULL on error
+ * and non-NULL on success.
+ */
+
+struct ibuf {
+ const uint8_t *b;
+ size_t n_read;
+ size_t capacity;
+};
+
+struct obuf {
+ uint8_t *b;
+ size_t n_written;
+ size_t capacity;
+};
+
+/* Helper functions. */
+static inline size_t ibuf_capacity(const struct ibuf *ib)
+{
+ return ib->capacity;
+}
+
+static inline size_t ibuf_nr_read(const struct ibuf *ib)
+{
+ return ib->n_read;
+}
+
+static inline size_t ibuf_remaining(const struct ibuf *ib)
+{
+ return ibuf_capacity(ib) - ibuf_nr_read(ib);
+}
+
+static inline size_t obuf_capacity(const struct obuf *ob)
+{
+ return ob->capacity;
+}
+
+static inline size_t obuf_nr_written(const struct obuf *ob)
+{
+ return ob->n_written;
+}
+
+static inline size_t obuf_remaining(const struct obuf *ob)
+{
+ return obuf_capacity(ob) - obuf_nr_written(ob);
+}
+
+/* Initialize an ibuf with buffer and size of data. */
+void ibuf_init(struct ibuf *ib, const void *b, size_t sz);
+
+/* Create a new ibuf based on a subregion of the src ibuf. */
+int ibuf_splice(const struct ibuf *src, struct ibuf *dst, size_t off,
+ size_t sz);
+
+/* Same as ibuf_splice(), but start from last read byte offset. */
+int ibuf_splice_current(const struct ibuf *src, struct ibuf *dst, size_t sz);
+
+/* Split an ibuf into 2 new ibufs at provided boundary. */
+int ibuf_split(const struct ibuf *src, struct ibuf *a, struct ibuf *b,
+ size_t boundary);
+
+/* Out-of-band drain of ibuf by returning pointer to data of specified size. */
+const void *ibuf_oob_drain(struct ibuf *ib, size_t sz);
+
+/* Read arbitray data from input buffer. */
+int ibuf_read(struct ibuf *ib, void *data, size_t sz);
+
+/* Read big endian fixed size values. */
+int ibuf_read_be8(struct ibuf *ib, uint8_t *v);
+int ibuf_read_be16(struct ibuf *ib, uint16_t *v);
+int ibuf_read_be32(struct ibuf *ib, uint32_t *v);
+int ibuf_read_be64(struct ibuf *ib, uint64_t *v);
+
+/* Read little endian fixed size values. */
+int ibuf_read_le8(struct ibuf *ib, uint8_t *v);
+int ibuf_read_le16(struct ibuf *ib, uint16_t *v);
+int ibuf_read_le32(struct ibuf *ib, uint32_t *v);
+int ibuf_read_le64(struct ibuf *ib, uint64_t *v);
+
+/* Read native endian fixed size values. */
+int ibuf_read_n8(struct ibuf *ib, uint8_t *v);
+int ibuf_read_n16(struct ibuf *ib, uint16_t *v);
+int ibuf_read_n32(struct ibuf *ib, uint32_t *v);
+int ibuf_read_n64(struct ibuf *ib, uint64_t *v);
+
+/* Helper to create an ibuf from an obuf after an entity has written data. */
+void ibuf_from_obuf(struct ibuf *ib, const struct obuf *ob);
+
+/* Initialize an obuf with buffer and maximum capacity. */
+void obuf_init(struct obuf *ob, void *b, size_t sz);
+
+/* Provide the buffer and size of the written contents. */
+const void *obuf_contents(const struct obuf *ob, size_t *sz);
+
+/* Create a new obuf based on a subregion of the src obuf. */
+int obuf_splice(const struct obuf *src, struct obuf *dst, size_t off,
+ size_t sz);
+
+/* Same as obuf_splice(), but start from last written byte offset. */
+int obuf_splice_current(const struct obuf *src, struct obuf *dst, size_t sz);
+
+/* Split an obuf into 2 new obufs at provided boundary. */
+int obuf_split(const struct obuf *src, struct obuf *a, struct obuf *b,
+ size_t boundary);
+
+/* Fill the buffer out-of-band. The size is accounted for. */
+void *obuf_oob_fill(struct obuf *ob, size_t sz);
+
+/* Write arbitray data to output buffer. */
+int obuf_write(struct obuf *ob, const void *data, size_t sz);
+
+/* Write big endian fixed size values. */
+int obuf_write_be8(struct obuf *ob, uint8_t v);
+int obuf_write_be16(struct obuf *ob, uint16_t v);
+int obuf_write_be32(struct obuf *ob, uint32_t v);
+int obuf_write_be64(struct obuf *ob, uint64_t v);
+
+/* Write little endian fixed size values. */
+int obuf_write_le8(struct obuf *ob, uint8_t v);
+int obuf_write_le16(struct obuf *ob, uint16_t v);
+int obuf_write_le32(struct obuf *ob, uint32_t v);
+int obuf_write_le64(struct obuf *ob, uint64_t v);
+
+/* Write native endian fixed size values. */
+int obuf_write_n8(struct obuf *ob, uint8_t v);
+int obuf_write_n16(struct obuf *ob, uint16_t v);
+int obuf_write_n32(struct obuf *ob, uint32_t v);
+int obuf_write_n64(struct obuf *ob, uint64_t v);
+
+#endif
diff --git a/src/commonlib/iobuf.c b/src/commonlib/iobuf.c
new file mode 100644
index 0000000000..b73ee1929e
--- /dev/null
+++ b/src/commonlib/iobuf.c
@@ -0,0 +1,422 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2017 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <commonlib/endian.h>
+#include <commonlib/iobuf.h>
+#include <string.h>
+
+static int ibuf_check_size(const struct ibuf *ib, size_t sz)
+{
+ if (ibuf_remaining(ib) < sz)
+ return -1;
+
+ return 0;
+}
+
+void ibuf_init(struct ibuf *ib, const void *b, size_t sz)
+{
+ ib->b = b;
+ ib->n_read = 0;
+ ib->capacity = sz;
+}
+
+void ibuf_from_obuf(struct ibuf *ib, const struct obuf *ob)
+{
+ ibuf_init(ib, ob->b, ob->n_written);
+}
+
+int ibuf_splice(const struct ibuf *src, struct ibuf *dst, size_t off, size_t sz)
+{
+ size_t end = off + sz;
+ size_t capacity = ibuf_capacity(src);
+ size_t nr_read = ibuf_nr_read(src);
+
+ if (end < off || end < sz || end > capacity)
+ return -1;
+
+ ibuf_init(dst, &src->b[off], sz);
+
+ /* Handle previously read data in src. */
+ if (off < nr_read)
+ dst->n_read = nr_read - off;
+
+ return 0;
+}
+
+int ibuf_splice_current(const struct ibuf *src, struct ibuf *dst, size_t sz)
+{
+ return ibuf_splice(src, dst, ibuf_nr_read(src), sz);
+}
+
+int ibuf_split(const struct ibuf *src, struct ibuf *a, struct ibuf *b,
+ size_t boundary)
+{
+ if (ibuf_splice(src, a, 0, boundary))
+ return -1;
+
+ return ibuf_splice(src, b, boundary, ibuf_capacity(src) - boundary);
+}
+
+const void *ibuf_oob_drain(struct ibuf *ib, size_t sz)
+{
+ const void *b;
+
+ if (ibuf_check_size(ib, sz))
+ return NULL;
+
+ b = &ib->b[ib->n_read];
+ ib->n_read += sz;
+
+ return b;
+}
+
+int ibuf_read(struct ibuf *ib, void *data, size_t sz)
+{
+ const void *b = ibuf_oob_drain(ib, sz);
+
+ if (b == NULL)
+ return -1;
+
+ memcpy(data, b, sz);
+
+ return 0;
+}
+
+int ibuf_read_be8(struct ibuf *ib, uint8_t *v)
+{
+ size_t sz = sizeof(*v);
+
+ if (ibuf_check_size(ib, sz))
+ return -1;
+
+ *v = read_at_be8(ib->b, ib->n_read);
+ ib->n_read += sz;
+
+ return 0;
+}
+
+int ibuf_read_be16(struct ibuf *ib, uint16_t *v)
+{
+ size_t sz = sizeof(*v);
+
+ if (ibuf_check_size(ib, sz))
+ return -1;
+
+ *v = read_at_be16(ib->b, ib->n_read);
+ ib->n_read += sz;
+
+ return 0;
+}
+
+int ibuf_read_be32(struct ibuf *ib, uint32_t *v)
+{
+ size_t sz = sizeof(*v);
+
+ if (ibuf_check_size(ib, sz))
+ return -1;
+
+ *v = read_at_be32(ib->b, ib->n_read);
+ ib->n_read += sz;
+
+ return 0;
+}
+
+int ibuf_read_be64(struct ibuf *ib, uint64_t *v)
+{
+ size_t sz = sizeof(*v);
+
+ if (ibuf_check_size(ib, sz))
+ return -1;
+
+ *v = read_at_be64(ib->b, ib->n_read);
+ ib->n_read += sz;
+
+ return 0;
+}
+
+int ibuf_read_le8(struct ibuf *ib, uint8_t *v)
+{
+ size_t sz = sizeof(*v);
+
+ if (ibuf_check_size(ib, sz))
+ return -1;
+
+ *v = read_at_le8(ib->b, ib->n_read);
+ ib->n_read += sz;
+
+ return 0;
+}
+
+int ibuf_read_le16(struct ibuf *ib, uint16_t *v)
+{
+ size_t sz = sizeof(*v);
+
+ if (ibuf_check_size(ib, sz))
+ return -1;
+
+ *v = read_at_le16(ib->b, ib->n_read);
+ ib->n_read += sz;
+
+ return 0;
+}
+
+int ibuf_read_le32(struct ibuf *ib, uint32_t *v)
+{
+ size_t sz = sizeof(*v);
+
+ if (ibuf_check_size(ib, sz))
+ return -1;
+
+ *v = read_at_le32(ib->b, ib->n_read);
+ ib->n_read += sz;
+
+ return 0;
+}
+
+int ibuf_read_le64(struct ibuf *ib, uint64_t *v)
+{
+ size_t sz = sizeof(*v);
+
+ if (ibuf_check_size(ib, sz))
+ return -1;
+
+ *v = read_at_le64(ib->b, ib->n_read);
+ ib->n_read += sz;
+
+ return 0;
+}
+
+int ibuf_read_n8(struct ibuf *ib, uint8_t *v)
+{
+ return ibuf_read(ib, v, sizeof(*v));
+}
+
+int ibuf_read_n16(struct ibuf *ib, uint16_t *v)
+{
+ return ibuf_read(ib, v, sizeof(*v));
+}
+
+int ibuf_read_n32(struct ibuf *ib, uint32_t *v)
+{
+ return ibuf_read(ib, v, sizeof(*v));
+}
+
+int ibuf_read_n64(struct ibuf *ib, uint64_t *v)
+{
+ return ibuf_read(ib, v, sizeof(*v));
+}
+
+static int obuf_check_size(const struct obuf *ob, size_t sz)
+{
+ if (obuf_remaining(ob) < sz)
+ return -1;
+
+ return 0;
+}
+
+void obuf_init(struct obuf *ob, void *b, size_t sz)
+{
+ ob->b = b;
+ ob->n_written = 0;
+ ob->capacity = sz;
+}
+
+int obuf_splice(const struct obuf *src, struct obuf *dst, size_t off, size_t sz)
+{
+ size_t end = off + sz;
+ size_t capacity = obuf_capacity(src);
+ size_t nr_written = obuf_nr_written(src);
+
+ if (end < off || end < sz || end > capacity)
+ return -1;
+
+ obuf_init(dst, &src->b[off], sz);
+
+ /* Handle previously written data in src. */
+ if (off < nr_written)
+ dst->n_written = nr_written - off;
+
+ return 0;
+}
+
+int obuf_splice_current(const struct obuf *src, struct obuf *dst, size_t sz)
+{
+ return obuf_splice(src, dst, obuf_nr_written(src), sz);
+}
+
+int obuf_split(const struct obuf *src, struct obuf *a, struct obuf *b,
+ size_t boundary)
+{
+ if (obuf_splice(src, a, 0, boundary))
+ return -1;
+
+ return obuf_splice(src, b, boundary, obuf_capacity(src) - boundary);
+}
+
+void *obuf_oob_fill(struct obuf *ob, size_t sz)
+{
+ void *b;
+
+ if (obuf_check_size(ob, sz))
+ return NULL;
+
+ b = &ob->b[ob->n_written];
+ ob->n_written += sz;
+
+ return b;
+}
+
+int obuf_write(struct obuf *ob, const void *data, size_t sz)
+{
+ void *b;
+
+ b = obuf_oob_fill(ob, sz);
+ if (b == NULL)
+ return -1;
+
+ memcpy(b, data, sz);
+
+ return 0;
+}
+
+int obuf_write_be8(struct obuf *ob, uint8_t v)
+{
+ size_t sz = sizeof(v);
+
+ if (obuf_check_size(ob, sz))
+ return -1;
+
+ write_at_be8(ob->b, v, ob->n_written);
+ ob->n_written += sz;
+
+ return 0;
+}
+
+int obuf_write_be16(struct obuf *ob, uint16_t v)
+{
+ size_t sz = sizeof(v);
+
+ if (obuf_check_size(ob, sz))
+ return -1;
+
+ write_at_be16(ob->b, v, ob->n_written);
+ ob->n_written += sz;
+
+ return 0;
+}
+
+int obuf_write_be32(struct obuf *ob, uint32_t v)
+{
+ size_t sz = sizeof(v);
+
+ if (obuf_check_size(ob, sz))
+ return -1;
+
+ write_at_be32(ob->b, v, ob->n_written);
+ ob->n_written += sz;
+
+ return 0;
+}
+
+int obuf_write_be64(struct obuf *ob, uint64_t v)
+{
+ size_t sz = sizeof(v);
+
+ if (obuf_check_size(ob, sz))
+ return -1;
+
+ write_at_be64(ob->b, v, ob->n_written);
+ ob->n_written += sz;
+
+ return 0;
+}
+
+int obuf_write_le8(struct obuf *ob, uint8_t v)
+{
+ size_t sz = sizeof(v);
+
+ if (obuf_check_size(ob, sz))
+ return -1;
+
+ write_at_le8(ob->b, v, ob->n_written);
+ ob->n_written += sz;
+
+ return 0;
+}
+
+int obuf_write_le16(struct obuf *ob, uint16_t v)
+{
+ size_t sz = sizeof(v);
+
+ if (obuf_check_size(ob, sz))
+ return -1;
+
+ write_at_le16(ob->b, v, ob->n_written);
+ ob->n_written += sz;
+
+ return 0;
+}
+
+int obuf_write_le32(struct obuf *ob, uint32_t v)
+{
+ size_t sz = sizeof(v);
+
+ if (obuf_check_size(ob, sz))
+ return -1;
+
+ write_at_le32(ob->b, v, ob->n_written);
+ ob->n_written += sz;
+
+ return 0;
+}
+
+int obuf_write_le64(struct obuf *ob, uint64_t v)
+{
+ size_t sz = sizeof(v);
+
+ if (obuf_check_size(ob, sz))
+ return -1;
+
+ write_at_le64(ob->b, v, ob->n_written);
+ ob->n_written += sz;
+
+ return 0;
+}
+
+int obuf_write_n8(struct obuf *ob, uint8_t v)
+{
+ return obuf_write(ob, &v, sizeof(v));
+}
+
+int obuf_write_n16(struct obuf *ob, uint16_t v)
+{
+ return obuf_write(ob, &v, sizeof(v));
+}
+
+int obuf_write_n32(struct obuf *ob, uint32_t v)
+{
+ return obuf_write(ob, &v, sizeof(v));
+}
+
+int obuf_write_n64(struct obuf *ob, uint64_t v)
+{
+ return obuf_write(ob, &v, sizeof(v));
+}
+
+const void *obuf_contents(const struct obuf *ob, size_t *sz)
+{
+ *sz = obuf_nr_written(ob);
+ return ob->b;
+}