diff options
Diffstat (limited to '')
-rw-r--r-- | scripts/dtc/data.c | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/scripts/dtc/data.c b/scripts/dtc/data.c new file mode 100644 index 0000000000..14734233ad --- /dev/null +++ b/scripts/dtc/data.c @@ -0,0 +1,256 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005. + */ + +#include "dtc.h" + +void data_free(struct data d) +{ + struct marker *m, *nm; + + m = d.markers; + while (m) { + nm = m->next; + free(m->ref); + free(m); + m = nm; + } + + if (d.val) + free(d.val); +} + +struct data data_grow_for(struct data d, unsigned int xlen) +{ + struct data nd; + unsigned int newsize; + + if (xlen == 0) + return d; + + nd = d; + + newsize = xlen; + + while ((d.len + xlen) > newsize) + newsize *= 2; + + nd.val = xrealloc(d.val, newsize); + + return nd; +} + +struct data data_copy_mem(const char *mem, int len) +{ + struct data d; + + d = data_grow_for(empty_data, len); + + d.len = len; + memcpy(d.val, mem, len); + + return d; +} + +struct data data_copy_escape_string(const char *s, int len) +{ + int i = 0; + struct data d; + char *q; + + d = data_add_marker(empty_data, TYPE_STRING, NULL); + d = data_grow_for(d, len + 1); + + q = d.val; + while (i < len) { + char c = s[i++]; + + if (c == '\\') + c = get_escape_char(s, &i); + + q[d.len++] = c; + } + + q[d.len++] = '\0'; + return d; +} + +struct data data_copy_file(FILE *f, size_t maxlen) +{ + struct data d = empty_data; + + d = data_add_marker(d, TYPE_NONE, NULL); + while (!feof(f) && (d.len < maxlen)) { + size_t chunksize, ret; + + if (maxlen == (size_t)-1) + chunksize = 4096; + else + chunksize = maxlen - d.len; + + d = data_grow_for(d, chunksize); + ret = fread(d.val + d.len, 1, chunksize, f); + + if (ferror(f)) + die("Error reading file into data: %s", strerror(errno)); + + if (d.len + ret < d.len) + die("Overflow reading file into data\n"); + + d.len += ret; + } + + return d; +} + +struct data data_append_data(struct data d, const void *p, int len) +{ + d = data_grow_for(d, len); + memcpy(d.val + d.len, p, len); + d.len += len; + return d; +} + +struct data data_insert_at_marker(struct data d, struct marker *m, + const void *p, int len) +{ + d = data_grow_for(d, len); + memmove(d.val + m->offset + len, d.val + m->offset, d.len - m->offset); + memcpy(d.val + m->offset, p, len); + d.len += len; + + /* Adjust all markers after the one we're inserting at */ + m = m->next; + for_each_marker(m) + m->offset += len; + return d; +} + +static struct data data_append_markers(struct data d, struct marker *m) +{ + struct marker **mp = &d.markers; + + /* Find the end of the markerlist */ + while (*mp) + mp = &((*mp)->next); + *mp = m; + return d; +} + +struct data data_merge(struct data d1, struct data d2) +{ + struct data d; + struct marker *m2 = d2.markers; + + d = data_append_markers(data_append_data(d1, d2.val, d2.len), m2); + + /* Adjust for the length of d1 */ + for_each_marker(m2) + m2->offset += d1.len; + + d2.markers = NULL; /* So data_free() doesn't clobber them */ + data_free(d2); + + return d; +} + +struct data data_append_integer(struct data d, uint64_t value, int bits) +{ + uint8_t value_8; + fdt16_t value_16; + fdt32_t value_32; + fdt64_t value_64; + + switch (bits) { + case 8: + value_8 = value; + return data_append_data(d, &value_8, 1); + + case 16: + value_16 = cpu_to_fdt16(value); + return data_append_data(d, &value_16, 2); + + case 32: + value_32 = cpu_to_fdt32(value); + return data_append_data(d, &value_32, 4); + + case 64: + value_64 = cpu_to_fdt64(value); + return data_append_data(d, &value_64, 8); + + default: + die("Invalid literal size (%d)\n", bits); + } +} + +struct data data_append_re(struct data d, uint64_t address, uint64_t size) +{ + struct fdt_reserve_entry re; + + re.address = cpu_to_fdt64(address); + re.size = cpu_to_fdt64(size); + + return data_append_data(d, &re, sizeof(re)); +} + +struct data data_append_cell(struct data d, cell_t word) +{ + return data_append_integer(d, word, sizeof(word) * 8); +} + +struct data data_append_addr(struct data d, uint64_t addr) +{ + return data_append_integer(d, addr, sizeof(addr) * 8); +} + +struct data data_append_byte(struct data d, uint8_t byte) +{ + return data_append_data(d, &byte, 1); +} + +struct data data_append_zeroes(struct data d, int len) +{ + d = data_grow_for(d, len); + + memset(d.val + d.len, 0, len); + d.len += len; + return d; +} + +struct data data_append_align(struct data d, int align) +{ + int newlen = ALIGN(d.len, align); + return data_append_zeroes(d, newlen - d.len); +} + +struct data data_add_marker(struct data d, enum markertype type, char *ref) +{ + struct marker *m; + + m = xmalloc(sizeof(*m)); + m->offset = d.len; + m->type = type; + m->ref = ref; + m->next = NULL; + + return data_append_markers(d, m); +} + +bool data_is_one_string(struct data d) +{ + int i; + int len = d.len; + + if (len == 0) + return false; + + for (i = 0; i < len-1; i++) + if (d.val[i] == '\0') + return false; + + if (d.val[len-1] != '\0') + return false; + + return true; +} |