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