diff options
-rw-r--r-- | src/commonlib/Makefile.inc | 7 | ||||
-rw-r--r-- | src/commonlib/include/commonlib/iobuf.h | 162 | ||||
-rw-r--r-- | src/commonlib/iobuf.c | 422 |
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; +} |