linux/scripts/dtc/data.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
   4 */
   5
   6#include "dtc.h"
   7
   8void data_free(struct data d)
   9{
  10        struct marker *m, *nm;
  11
  12        m = d.markers;
  13        while (m) {
  14                nm = m->next;
  15                free(m->ref);
  16                free(m);
  17                m = nm;
  18        }
  19
  20        if (d.val)
  21                free(d.val);
  22}
  23
  24struct data data_grow_for(struct data d, int xlen)
  25{
  26        struct data nd;
  27        int newsize;
  28
  29        if (xlen == 0)
  30                return d;
  31
  32        nd = d;
  33
  34        newsize = xlen;
  35
  36        while ((d.len + xlen) > newsize)
  37                newsize *= 2;
  38
  39        nd.val = xrealloc(d.val, newsize);
  40
  41        return nd;
  42}
  43
  44struct data data_copy_mem(const char *mem, int len)
  45{
  46        struct data d;
  47
  48        d = data_grow_for(empty_data, len);
  49
  50        d.len = len;
  51        memcpy(d.val, mem, len);
  52
  53        return d;
  54}
  55
  56struct data data_copy_escape_string(const char *s, int len)
  57{
  58        int i = 0;
  59        struct data d;
  60        char *q;
  61
  62        d = data_add_marker(empty_data, TYPE_STRING, NULL);
  63        d = data_grow_for(d, len + 1);
  64
  65        q = d.val;
  66        while (i < len) {
  67                char c = s[i++];
  68
  69                if (c == '\\')
  70                        c = get_escape_char(s, &i);
  71
  72                q[d.len++] = c;
  73        }
  74
  75        q[d.len++] = '\0';
  76        return d;
  77}
  78
  79struct data data_copy_file(FILE *f, size_t maxlen)
  80{
  81        struct data d = empty_data;
  82
  83        d = data_add_marker(d, TYPE_NONE, NULL);
  84        while (!feof(f) && (d.len < maxlen)) {
  85                size_t chunksize, ret;
  86
  87                if (maxlen == -1)
  88                        chunksize = 4096;
  89                else
  90                        chunksize = maxlen - d.len;
  91
  92                d = data_grow_for(d, chunksize);
  93                ret = fread(d.val + d.len, 1, chunksize, f);
  94
  95                if (ferror(f))
  96                        die("Error reading file into data: %s", strerror(errno));
  97
  98                if (d.len + ret < d.len)
  99                        die("Overflow reading file into data\n");
 100
 101                d.len += ret;
 102        }
 103
 104        return d;
 105}
 106
 107struct data data_append_data(struct data d, const void *p, int len)
 108{
 109        d = data_grow_for(d, len);
 110        memcpy(d.val + d.len, p, len);
 111        d.len += len;
 112        return d;
 113}
 114
 115struct data data_insert_at_marker(struct data d, struct marker *m,
 116                                  const void *p, int len)
 117{
 118        d = data_grow_for(d, len);
 119        memmove(d.val + m->offset + len, d.val + m->offset, d.len - m->offset);
 120        memcpy(d.val + m->offset, p, len);
 121        d.len += len;
 122
 123        /* Adjust all markers after the one we're inserting at */
 124        m = m->next;
 125        for_each_marker(m)
 126                m->offset += len;
 127        return d;
 128}
 129
 130static struct data data_append_markers(struct data d, struct marker *m)
 131{
 132        struct marker **mp = &d.markers;
 133
 134        /* Find the end of the markerlist */
 135        while (*mp)
 136                mp = &((*mp)->next);
 137        *mp = m;
 138        return d;
 139}
 140
 141struct data data_merge(struct data d1, struct data d2)
 142{
 143        struct data d;
 144        struct marker *m2 = d2.markers;
 145
 146        d = data_append_markers(data_append_data(d1, d2.val, d2.len), m2);
 147
 148        /* Adjust for the length of d1 */
 149        for_each_marker(m2)
 150                m2->offset += d1.len;
 151
 152        d2.markers = NULL; /* So data_free() doesn't clobber them */
 153        data_free(d2);
 154
 155        return d;
 156}
 157
 158struct data data_append_integer(struct data d, uint64_t value, int bits)
 159{
 160        uint8_t value_8;
 161        fdt16_t value_16;
 162        fdt32_t value_32;
 163        fdt64_t value_64;
 164
 165        switch (bits) {
 166        case 8:
 167                value_8 = value;
 168                return data_append_data(d, &value_8, 1);
 169
 170        case 16:
 171                value_16 = cpu_to_fdt16(value);
 172                return data_append_data(d, &value_16, 2);
 173
 174        case 32:
 175                value_32 = cpu_to_fdt32(value);
 176                return data_append_data(d, &value_32, 4);
 177
 178        case 64:
 179                value_64 = cpu_to_fdt64(value);
 180                return data_append_data(d, &value_64, 8);
 181
 182        default:
 183                die("Invalid literal size (%d)\n", bits);
 184        }
 185}
 186
 187struct data data_append_re(struct data d, uint64_t address, uint64_t size)
 188{
 189        struct fdt_reserve_entry re;
 190
 191        re.address = cpu_to_fdt64(address);
 192        re.size = cpu_to_fdt64(size);
 193
 194        return data_append_data(d, &re, sizeof(re));
 195}
 196
 197struct data data_append_cell(struct data d, cell_t word)
 198{
 199        return data_append_integer(d, word, sizeof(word) * 8);
 200}
 201
 202struct data data_append_addr(struct data d, uint64_t addr)
 203{
 204        return data_append_integer(d, addr, sizeof(addr) * 8);
 205}
 206
 207struct data data_append_byte(struct data d, uint8_t byte)
 208{
 209        return data_append_data(d, &byte, 1);
 210}
 211
 212struct data data_append_zeroes(struct data d, int len)
 213{
 214        d = data_grow_for(d, len);
 215
 216        memset(d.val + d.len, 0, len);
 217        d.len += len;
 218        return d;
 219}
 220
 221struct data data_append_align(struct data d, int align)
 222{
 223        int newlen = ALIGN(d.len, align);
 224        return data_append_zeroes(d, newlen - d.len);
 225}
 226
 227struct data data_add_marker(struct data d, enum markertype type, char *ref)
 228{
 229        struct marker *m;
 230
 231        m = xmalloc(sizeof(*m));
 232        m->offset = d.len;
 233        m->type = type;
 234        m->ref = ref;
 235        m->next = NULL;
 236
 237        return data_append_markers(d, m);
 238}
 239
 240bool data_is_one_string(struct data d)
 241{
 242        int i;
 243        int len = d.len;
 244
 245        if (len == 0)
 246                return false;
 247
 248        for (i = 0; i < len-1; i++)
 249                if (d.val[i] == '\0')
 250                        return false;
 251
 252        if (d.val[len-1] != '\0')
 253                return false;
 254
 255        return true;
 256}
 257