From 88b26b845cab11be3f925e2fb52b805f7f8f992a Mon Sep 17 00:00:00 2001 From: Aaron Durbin Date: Fri, 24 Mar 2017 17:10:51 -0500 Subject: commonlib: add input and output buffer helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce ibuf and obuf structures for helping manage memory buffers. The ibuf, an input buffer, can be read from and the obuf, an output buffer, can be written to. Helper functions are provided for serializing values in different endian formats. This library is provided to for common buffer management routines such that the same code doesn't have to re-written in different and less consistent forms. BUG=b:36598499 Change-Id: I5247237f68b658906ec6916bbbb286d57d6df5ee Signed-off-by: Aaron Durbin Reviewed-on: https://review.coreboot.org/19062 Tested-by: build bot (Jenkins) Reviewed-by: Furquan Shaikh Reviewed-by: Philippe Mathieu-Daudé --- src/commonlib/Makefile.inc | 7 + src/commonlib/include/commonlib/iobuf.h | 162 ++++++++++++ src/commonlib/iobuf.c | 422 ++++++++++++++++++++++++++++++++ 3 files changed, 591 insertions(+) create mode 100644 src/commonlib/include/commonlib/iobuf.h create mode 100644 src/commonlib/iobuf.c (limited to 'src/commonlib') 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 +#include + +/* + * 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 +#include +#include + +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; +} -- cgit v1.2.3