Branch data Line data Source code
1 : : // SPDX-License-Identifier: Apache-2.0
2 : : /* Copyright 2013-2019 IBM Corp. */
3 : :
4 : : #include <limits.h>
5 : : #include <stdlib.h>
6 : : #include <stdio.h>
7 : : #include <string.h>
8 : :
9 : : #ifndef __SKIBOOT__
10 : : #include <sys/types.h>
11 : : #include <unistd.h>
12 : : #endif
13 : :
14 : : #include "ffs.h"
15 : :
16 : : #define __unused __attribute__((unused))
17 : : #define HDR_ENTRIES_NUM 30
18 : :
19 : : struct ffs_handle {
20 : : struct ffs_hdr hdr; /* Converted header */
21 : : uint32_t toc_offset;
22 : : uint32_t max_size;
23 : : /* The converted header knows how big this is */
24 : : struct __ffs_hdr *cache;
25 : : struct blocklevel_device *bl;
26 : : };
27 : :
28 : 0 : static uint32_t ffs_checksum(void* data, size_t size)
29 : : {
30 : 0 : uint32_t i, csum = 0;
31 : :
32 : 0 : for (i = csum = 0; i < (size/4); i++)
33 : 0 : csum ^= ((uint32_t *)data)[i];
34 : 0 : return csum;
35 : : }
36 : :
37 : : /* Helper functions for typesafety and size safety */
38 : 0 : static uint32_t ffs_hdr_checksum(struct __ffs_hdr *hdr)
39 : : {
40 : : return ffs_checksum(hdr, sizeof(struct __ffs_hdr));
41 : : }
42 : :
43 : 0 : static uint32_t ffs_entry_checksum(struct __ffs_entry *ent)
44 : : {
45 : 0 : return ffs_checksum(ent, sizeof(struct __ffs_entry));
46 : : }
47 : :
48 : 0 : static size_t ffs_hdr_raw_size(int num_entries)
49 : : {
50 : 0 : return sizeof(struct __ffs_hdr) + num_entries * sizeof(struct __ffs_entry);
51 : : }
52 : :
53 : 0 : static int ffs_num_entries(struct ffs_hdr *hdr)
54 : : {
55 : 0 : if (hdr->count == 0)
56 : 0 : FL_DBG("%s returned zero!\n", __func__);
57 : 0 : return hdr->count;
58 : : }
59 : :
60 : 0 : static int ffs_check_convert_header(struct ffs_hdr *dst, struct __ffs_hdr *src)
61 : : {
62 : 0 : if (be32_to_cpu(src->magic) != FFS_MAGIC)
63 : : return FFS_ERR_BAD_MAGIC;
64 : 0 : dst->version = be32_to_cpu(src->version);
65 : 0 : if (dst->version != FFS_VERSION_1)
66 : : return FFS_ERR_BAD_VERSION;
67 : 0 : if (ffs_hdr_checksum(src) != 0)
68 : : return FFS_ERR_BAD_CKSUM;
69 : 0 : if (be32_to_cpu(src->entry_size) != sizeof(struct __ffs_entry))
70 : : return FFS_ERR_BAD_SIZE;
71 : 0 : if ((be32_to_cpu(src->entry_size) * be32_to_cpu(src->entry_count)) >
72 : 0 : (be32_to_cpu(src->block_size) * be32_to_cpu(src->size)))
73 : : return FLASH_ERR_PARM_ERROR;
74 : :
75 : 0 : dst->block_size = be32_to_cpu(src->block_size);
76 : 0 : dst->size = be32_to_cpu(src->size) * dst->block_size;
77 : 0 : dst->block_count = be32_to_cpu(src->block_count);
78 : 0 : dst->entries_size = be32_to_cpu(src->entry_count);
79 : :
80 : 0 : return 0;
81 : : }
82 : :
83 : 0 : static int ffs_entry_user_to_flash(struct ffs_hdr *hdr __unused,
84 : : struct __ffs_entry_user *dst, struct ffs_entry_user *src)
85 : : {
86 : 0 : memset(dst, 0, sizeof(struct __ffs_entry_user));
87 : 0 : dst->datainteg = cpu_to_be16(src->datainteg);
88 : 0 : dst->vercheck = src->vercheck;
89 : 0 : dst->miscflags = src->miscflags;
90 : :
91 : 0 : return 0;
92 : : }
93 : :
94 : 0 : static int ffs_entry_user_to_cpu(struct ffs_hdr *hdr __unused,
95 : : struct ffs_entry_user *dst, struct __ffs_entry_user *src)
96 : : {
97 : 0 : memset(dst, 0, sizeof(struct ffs_entry_user));
98 : 0 : dst->datainteg = be16_to_cpu(src->datainteg);
99 : 0 : dst->vercheck = src->vercheck;
100 : 0 : dst->miscflags = src->miscflags;
101 : :
102 : 0 : return 0;
103 : : }
104 : :
105 : 0 : static int ffs_entry_to_flash(struct ffs_hdr *hdr,
106 : : struct __ffs_entry *dst, struct ffs_entry *src)
107 : : {
108 : 0 : int rc, index;
109 : :
110 : 0 : if (!hdr || !dst || !src)
111 : : return -1;
112 : :
113 : 0 : for (index = 0; index < hdr->count && hdr->entries[index] != src; index++);
114 : :
115 : 0 : if (index == hdr->count)
116 : : return FFS_ERR_PART_NOT_FOUND;
117 : 0 : index++; /* On flash indexes start at 1 */
118 : : /*
119 : : * So that the checksum gets calculated correctly at least the
120 : : * dst->checksum must be zero before calling ffs_entry_checksum()
121 : : * memset()ting the entire struct to zero is probably wise as it
122 : : * appears the reserved fields are always zero.
123 : : */
124 : 0 : memset(dst, 0, sizeof(*dst));
125 : :
126 : 0 : memcpy(dst->name, src->name, sizeof(dst->name));
127 : 0 : dst->name[FFS_PART_NAME_MAX] = '\0';
128 : 0 : dst->base = cpu_to_be32(src->base / hdr->block_size);
129 : 0 : dst->size = cpu_to_be32(src->size / hdr->block_size);
130 : 0 : dst->pid = cpu_to_be32(src->pid);
131 : 0 : dst->id = cpu_to_be32(index);
132 : 0 : dst->type = cpu_to_be32(src->type); /* TODO: Check that it is valid? */
133 : 0 : dst->flags = cpu_to_be32(src->flags);
134 : 0 : dst->actual = cpu_to_be32(src->actual);
135 : 0 : rc = ffs_entry_user_to_flash(hdr, &dst->user, &src->user);
136 : 0 : dst->checksum = ffs_entry_checksum(dst);
137 : :
138 : 0 : return rc;
139 : : }
140 : :
141 : 0 : static int ffs_entry_to_cpu(struct ffs_hdr *hdr,
142 : : struct ffs_entry *dst, struct __ffs_entry *src)
143 : : {
144 : 0 : int rc;
145 : :
146 : 0 : if (ffs_entry_checksum(src) != 0)
147 : : return FFS_ERR_BAD_CKSUM;
148 : :
149 : 0 : memcpy(dst->name, src->name, sizeof(dst->name));
150 : 0 : dst->name[FFS_PART_NAME_MAX] = '\0';
151 : 0 : dst->base = be32_to_cpu(src->base) * hdr->block_size;
152 : 0 : dst->size = be32_to_cpu(src->size) * hdr->block_size;
153 : 0 : dst->actual = be32_to_cpu(src->actual);
154 : 0 : dst->pid = be32_to_cpu(src->pid);
155 : 0 : dst->type = be32_to_cpu(src->type); /* TODO: Check that it is valid? */
156 : 0 : dst->flags = be32_to_cpu(src->flags);
157 : 0 : rc = ffs_entry_user_to_cpu(hdr, &dst->user, &src->user);
158 : :
159 : 0 : return rc;
160 : : }
161 : :
162 : 0 : char *ffs_entry_user_to_string(struct ffs_entry_user *user)
163 : : {
164 : 0 : char *ret;
165 : :
166 : 0 : if (!user)
167 : : return NULL;
168 : :
169 : 0 : ret = strdup("----------");
170 : 0 : if (!ret)
171 : : return NULL;
172 : :
173 : 0 : if (user->datainteg & FFS_ENRY_INTEG_ECC)
174 : 0 : ret[0] = 'E';
175 : :
176 : 0 : if (user->vercheck & FFS_VERCHECK_SHA512V)
177 : 0 : ret[1] = 'L';
178 : :
179 : 0 : if (user->vercheck & FFS_VERCHECK_SHA512EC)
180 : 0 : ret[2] = 'I';
181 : :
182 : 0 : if (user->miscflags & FFS_MISCFLAGS_PRESERVED)
183 : 0 : ret[3] = 'P';
184 : :
185 : 0 : if (user->miscflags & FFS_MISCFLAGS_READONLY)
186 : 0 : ret[4] = 'R';
187 : :
188 : 0 : if (user->miscflags & FFS_MISCFLAGS_BACKUP)
189 : 0 : ret[5] = 'B';
190 : :
191 : 0 : if (user->miscflags & FFS_MISCFLAGS_REPROVISION)
192 : 0 : ret[6] = 'F';
193 : :
194 : 0 : if (user->miscflags & FFS_MISCFLAGS_GOLDEN)
195 : 0 : ret[7] = 'G';
196 : :
197 : 0 : if (user->miscflags & FFS_MISCFLAGS_CLEARECC)
198 : 0 : ret[8] = 'C';
199 : :
200 : 0 : if (user->miscflags & FFS_MISCFLAGS_VOLATILE)
201 : 0 : ret[9] = 'V';
202 : :
203 : : return ret;
204 : : }
205 : :
206 : 0 : int ffs_string_to_entry_user(const char *flags, int nflags,
207 : : struct ffs_entry_user *user)
208 : : {
209 : 0 : int i;
210 : :
211 : 0 : if (!user || !flags)
212 : : return FLASH_ERR_PARM_ERROR;
213 : :
214 : 0 : memset(user, 0, sizeof(struct ffs_entry_user));
215 : 0 : for (i = 0; i < nflags; i++) {
216 : 0 : switch (flags[i]) {
217 : 0 : case 'E':
218 : 0 : user->datainteg |= FFS_ENRY_INTEG_ECC;
219 : 0 : break;
220 : 0 : case 'L':
221 : 0 : user->vercheck |= FFS_VERCHECK_SHA512V;
222 : 0 : break;
223 : 0 : case 'I':
224 : 0 : user->vercheck |= FFS_VERCHECK_SHA512EC;
225 : 0 : break;
226 : 0 : case 'P':
227 : 0 : user->miscflags |= FFS_MISCFLAGS_PRESERVED;
228 : 0 : break;
229 : 0 : case 'R':
230 : 0 : user->miscflags |= FFS_MISCFLAGS_READONLY;
231 : 0 : break;
232 : 0 : case 'B':
233 : 0 : user->miscflags |= FFS_MISCFLAGS_BACKUP;
234 : 0 : break;
235 : 0 : case 'F':
236 : 0 : user->miscflags |= FFS_MISCFLAGS_REPROVISION;
237 : 0 : break;
238 : 0 : case 'G':
239 : 0 : user->miscflags |= FFS_MISCFLAGS_GOLDEN;
240 : 0 : break;
241 : 0 : case 'C':
242 : 0 : user->miscflags |= FFS_MISCFLAGS_CLEARECC;
243 : 0 : break;
244 : 0 : case 'V':
245 : 0 : user->miscflags |= FFS_MISCFLAGS_VOLATILE;
246 : 0 : break;
247 : 0 : default:
248 : 0 : FL_DBG("Unknown flag '%c'\n", flags[i]);
249 : : return FLASH_ERR_PARM_ERROR;
250 : : }
251 : : }
252 : :
253 : : return 0;
254 : : }
255 : :
256 : 0 : bool has_flag(struct ffs_entry *ent, uint16_t flag)
257 : : {
258 : 0 : return ((ent->user.miscflags & flag) != 0);
259 : : }
260 : :
261 : 0 : static struct ffs_entry *__ffs_entry_get(struct ffs_handle *ffs, uint32_t index)
262 : : {
263 : 0 : if (index >= ffs->hdr.count)
264 : : return NULL;
265 : 0 : return ffs->hdr.entries[index];
266 : : }
267 : :
268 : 0 : struct ffs_entry *ffs_entry_get(struct ffs_handle *ffs, uint32_t index)
269 : : {
270 : 0 : struct ffs_entry *ret = __ffs_entry_get(ffs, index);
271 : 0 : if (ret)
272 : 0 : ret->ref++;
273 : 0 : return ret;
274 : : }
275 : :
276 : 0 : struct ffs_entry *ffs_entry_put(struct ffs_entry *ent)
277 : : {
278 : 0 : if (!ent)
279 : : return NULL;
280 : :
281 : 0 : ent->ref--;
282 : 0 : if (ent->ref == 0) {
283 : 0 : free(ent);
284 : 0 : ent = NULL;
285 : : }
286 : :
287 : : return ent;
288 : : }
289 : :
290 : 0 : bool has_ecc(struct ffs_entry *ent)
291 : : {
292 : 0 : return ((ent->user.datainteg & FFS_ENRY_INTEG_ECC) != 0);
293 : : }
294 : :
295 : 0 : int ffs_init(uint32_t offset, uint32_t max_size, struct blocklevel_device *bl,
296 : : struct ffs_handle **ffs, bool mark_ecc)
297 : : {
298 : 0 : struct __ffs_hdr blank_hdr;
299 : 0 : struct __ffs_hdr raw_hdr;
300 : 0 : struct ffs_handle *f;
301 : 0 : uint64_t total_size;
302 : 0 : int rc, i;
303 : :
304 : 0 : if (!ffs || !bl)
305 : : return FLASH_ERR_PARM_ERROR;
306 : 0 : *ffs = NULL;
307 : :
308 : 0 : rc = blocklevel_get_info(bl, NULL, &total_size, NULL);
309 : 0 : if (rc) {
310 : 0 : FL_ERR("FFS: Error %d retrieving flash info\n", rc);
311 : 0 : return rc;
312 : : }
313 : 0 : if (total_size > UINT_MAX)
314 : : return FLASH_ERR_VERIFY_FAILURE;
315 : 0 : if ((offset + max_size) < offset)
316 : : return FLASH_ERR_PARM_ERROR;
317 : :
318 : 0 : if ((max_size > total_size))
319 : : return FLASH_ERR_PARM_ERROR;
320 : :
321 : : /* Read flash header */
322 : 0 : rc = blocklevel_read(bl, offset, &raw_hdr, sizeof(raw_hdr));
323 : 0 : if (rc) {
324 : 0 : FL_ERR("FFS: Error %d reading flash header\n", rc);
325 : 0 : return rc;
326 : : }
327 : :
328 : : /*
329 : : * Flash controllers can get deconfigured or otherwise upset, when this
330 : : * happens they return all 0xFF bytes.
331 : : * An __ffs_hdr consisting of all 0xFF cannot be valid and it would be
332 : : * nice to drop a hint to the user to help with debugging. This will
333 : : * help quickly differentiate between flash corruption and standard
334 : : * type 'reading from the wrong place' errors vs controller errors or
335 : : * reading erased data.
336 : : */
337 : 0 : memset(&blank_hdr, UINT_MAX, sizeof(struct __ffs_hdr));
338 : 0 : if (memcmp(&blank_hdr, &raw_hdr, sizeof(struct __ffs_hdr)) == 0) {
339 : 0 : FL_ERR("FFS: Reading the flash has returned all 0xFF.\n");
340 : 0 : FL_ERR(" Are you reading erased flash?\n");
341 : 0 : FL_ERR(" Is something else using the flash controller?\n");
342 : 0 : return FLASH_ERR_BAD_READ;
343 : : }
344 : :
345 : : /* Allocate ffs_handle structure and start populating */
346 : 0 : f = calloc(1, sizeof(*f));
347 : 0 : if (!f)
348 : : return FLASH_ERR_MALLOC_FAILED;
349 : :
350 : 0 : f->toc_offset = offset;
351 : 0 : f->max_size = max_size;
352 : 0 : f->bl = bl;
353 : :
354 : : /* Convert and check flash header */
355 : 0 : rc = ffs_check_convert_header(&f->hdr, &raw_hdr);
356 : 0 : if (rc) {
357 : 0 : FL_INF("FFS: Flash header not found. Code: %d\n", rc);
358 : 0 : goto out;
359 : : }
360 : :
361 : : /* Check header is sane */
362 : 0 : if ((f->hdr.block_count * f->hdr.block_size) > max_size) {
363 : 0 : rc = FLASH_ERR_PARM_ERROR;
364 : 0 : FL_ERR("FFS: Flash header exceeds max flash size\n");
365 : 0 : goto out;
366 : : }
367 : :
368 : 0 : f->hdr.entries = calloc(f->hdr.entries_size, sizeof(struct ffs_entry *));
369 : :
370 : : /*
371 : : * Grab the entire partition header
372 : : */
373 : : /* Check for overflow or a silly size */
374 : 0 : if (!f->hdr.size || f->hdr.size % f->hdr.block_size != 0) {
375 : 0 : rc = FLASH_ERR_MALLOC_FAILED;
376 : 0 : FL_ERR("FFS: Cache size overflow (0x%x * 0x%x)\n",
377 : : f->hdr.block_size, f->hdr.size);
378 : 0 : goto out;
379 : : }
380 : :
381 : 0 : FL_DBG("FFS: Partition map size: 0x%x\n", f->hdr.size);
382 : :
383 : : /* Allocate cache */
384 : 0 : f->cache = malloc(f->hdr.size);
385 : 0 : if (!f->cache) {
386 : 0 : rc = FLASH_ERR_MALLOC_FAILED;
387 : 0 : goto out;
388 : : }
389 : :
390 : : /* Read the cached map */
391 : 0 : rc = blocklevel_read(bl, offset, f->cache, f->hdr.size);
392 : 0 : if (rc) {
393 : 0 : FL_ERR("FFS: Error %d reading flash partition map\n", rc);
394 : 0 : goto out;
395 : : }
396 : :
397 : 0 : for (i = 0; i < f->hdr.entries_size; i++) {
398 : 0 : struct ffs_entry *ent = calloc(1, sizeof(struct ffs_entry));
399 : 0 : if (!ent) {
400 : 0 : rc = FLASH_ERR_MALLOC_FAILED;
401 : 0 : goto out;
402 : : }
403 : :
404 : 0 : f->hdr.entries[f->hdr.count++] = ent;
405 : 0 : ent->ref = 1;
406 : 0 : rc = ffs_entry_to_cpu(&f->hdr, ent, &f->cache->entries[i]);
407 : 0 : if (rc) {
408 : 0 : FL_DBG("FFS: Failed checksum for partition %s\n",
409 : : f->cache->entries[i].name);
410 : 0 : goto out;
411 : : }
412 : :
413 : 0 : if (mark_ecc && has_ecc(ent)) {
414 : 0 : rc = blocklevel_ecc_protect(bl, ent->base, ent->size);
415 : 0 : if (rc) {
416 : 0 : FL_ERR("Failed to blocklevel_ecc_protect(0x%08x, 0x%08x)\n",
417 : : ent->base, ent->size);
418 : 0 : goto out;
419 : : }
420 : : }
421 : : }
422 : :
423 : 0 : out:
424 : 0 : if (rc == 0)
425 : 0 : *ffs = f;
426 : : else
427 : 0 : ffs_close(f);
428 : :
429 : : return rc;
430 : : }
431 : :
432 : 0 : static void __hdr_free(struct ffs_hdr *hdr)
433 : : {
434 : 0 : int i;
435 : :
436 : 0 : if (!hdr)
437 : : return;
438 : :
439 : 0 : for (i = 0; i < hdr->count; i++)
440 : 0 : ffs_entry_put(hdr->entries[i]);
441 : 0 : free(hdr->entries);
442 : : }
443 : :
444 : 0 : void ffs_hdr_free(struct ffs_hdr *hdr)
445 : : {
446 : 0 : __hdr_free(hdr);
447 : 0 : free(hdr);
448 : 0 : }
449 : :
450 : 0 : void ffs_close(struct ffs_handle *ffs)
451 : : {
452 : 0 : __hdr_free(&ffs->hdr);
453 : :
454 : 0 : if (ffs->cache)
455 : 0 : free(ffs->cache);
456 : :
457 : 0 : free(ffs);
458 : 0 : }
459 : :
460 : 0 : int ffs_lookup_part(struct ffs_handle *ffs, const char *name,
461 : : uint32_t *part_idx)
462 : : {
463 : 0 : struct ffs_entry **ents = ffs->hdr.entries;
464 : 0 : int i;
465 : :
466 : 0 : for (i = 0;
467 : 0 : i < ffs->hdr.count &&
468 : 0 : strncmp(name, ents[i]->name, FFS_PART_NAME_MAX);
469 : 0 : i++);
470 : :
471 : 0 : if (i == ffs->hdr.count)
472 : : return FFS_ERR_PART_NOT_FOUND;
473 : :
474 : 0 : if (part_idx)
475 : 0 : *part_idx = i;
476 : : return 0;
477 : : }
478 : :
479 : 0 : int ffs_part_info(struct ffs_handle *ffs, uint32_t part_idx,
480 : : char **name, uint32_t *start,
481 : : uint32_t *total_size, uint32_t *act_size, bool *ecc)
482 : : {
483 : 0 : struct ffs_entry *ent;
484 : 0 : char *n;
485 : :
486 : 0 : ent = __ffs_entry_get(ffs, part_idx);
487 : 0 : if (!ent)
488 : : return FFS_ERR_PART_NOT_FOUND;
489 : :
490 : 0 : if (start)
491 : 0 : *start = ent->base;
492 : 0 : if (total_size)
493 : 0 : *total_size = ent->size;
494 : 0 : if (act_size)
495 : 0 : *act_size = ent->actual;
496 : 0 : if (ecc)
497 : 0 : *ecc = has_ecc(ent);
498 : :
499 : 0 : if (name) {
500 : 0 : n = calloc(1, FFS_PART_NAME_MAX + 1);
501 : 0 : if (!n)
502 : : return FLASH_ERR_MALLOC_FAILED;
503 : 0 : memcpy(n, ent->name, FFS_PART_NAME_MAX);
504 : 0 : *name = n;
505 : : }
506 : : return 0;
507 : : }
508 : :
509 : : /*
510 : : * There are quite a few ways one might consider two ffs_handles to be the
511 : : * same. For the purposes of this function we are trying to detect a fairly
512 : : * specific scenario:
513 : : * Consecutive calls to ffs_next_side() may succeed but have gone circular.
514 : : * It is possible that the OTHER_SIDE partition in one TOC actually points
515 : : * back to the TOC to first ffs_handle.
516 : : * This function compares for this case, therefore the requirements are
517 : : * simple, the underlying blocklevel_devices must be the same along with
518 : : * the toc_offset and the max_size.
519 : : */
520 : 0 : bool ffs_equal(struct ffs_handle *one, struct ffs_handle *two)
521 : : {
522 : 0 : return (!one && !two) || (one && two && one->bl == two->bl
523 : : && one->toc_offset == two->toc_offset
524 : 0 : && one->max_size == two->max_size);
525 : : }
526 : :
527 : 0 : int ffs_next_side(struct ffs_handle *ffs, struct ffs_handle **new_ffs,
528 : : bool mark_ecc)
529 : : {
530 : 0 : int rc;
531 : 0 : uint32_t index, offset, max_size;
532 : :
533 : 0 : if (!ffs || !new_ffs)
534 : : return FLASH_ERR_PARM_ERROR;
535 : :
536 : 0 : *new_ffs = NULL;
537 : :
538 : 0 : rc = ffs_lookup_part(ffs, "OTHER_SIDE", &index);
539 : 0 : if (rc)
540 : : return rc;
541 : :
542 : 0 : rc = ffs_part_info(ffs, index, NULL, &offset, &max_size, NULL, NULL);
543 : 0 : if (rc)
544 : : return rc;
545 : :
546 : 0 : return ffs_init(offset, max_size, ffs->bl, new_ffs, mark_ecc);
547 : : }
548 : :
549 : 0 : int ffs_entry_add(struct ffs_hdr *hdr, struct ffs_entry *entry)
550 : : {
551 : 0 : const char *smallest_name;
552 : 0 : uint32_t smallest_base, toc_base;
553 : 0 : int i;
554 : :
555 : 0 : FL_DBG("LIBFFS: Adding '%s' at 0x%08x..0x%08x\n",
556 : : entry->name, entry->base, entry->base + entry->size);
557 : :
558 : 0 : if (hdr->count == 0) {
559 : 0 : FL_DBG("LIBFFS: Adding an entry to an empty header\n");
560 : 0 : hdr->entries[hdr->count++] = entry;
561 : : }
562 : 0 : if (entry->base + entry->size > hdr->block_size * hdr->block_count)
563 : : return FFS_ERR_BAD_PART_SIZE;
564 : :
565 : 0 : smallest_base = entry->base;
566 : 0 : smallest_name = entry->name;
567 : 0 : toc_base = 0;
568 : : /*
569 : : * TODO: This may have assumed entries was sorted
570 : : */
571 : 0 : for (i = 0; i < hdr->count; i++) {
572 : 0 : struct ffs_entry *ent = hdr->entries[i];
573 : :
574 : : /* Don't allow same names to differ only by case */
575 : 0 : if (strncasecmp(entry->name, ent->name, FFS_PART_NAME_MAX) == 0)
576 : : return FFS_ERR_BAD_PART_NAME;
577 : :
578 : 0 : if (entry->base >= ent->base && entry->base < ent->base + ent->size)
579 : : return FFS_ERR_BAD_PART_BASE;
580 : :
581 : 0 : if (entry->base + entry->size > ent->base &&
582 : 0 : entry->base + entry->size < ent->base + ent->size)
583 : : return FFS_ERR_BAD_PART_SIZE;
584 : :
585 : 0 : if (entry->actual > entry->size)
586 : : return FFS_ERR_BAD_PART_SIZE;
587 : :
588 : 0 : if (entry->pid != FFS_PID_TOPLEVEL)
589 : : return FFS_ERR_BAD_PART_PID;
590 : :
591 : : /* First partition is the partition table */
592 : 0 : if (i == 0) {
593 : : toc_base = ent->base;
594 : : } else {
595 : : /*
596 : : * We're looking for the partition directly
597 : : * after the toc to make sure we don't
598 : : * overflow onto it.
599 : : */
600 : 0 : if (ent->base < smallest_base && ent->base > toc_base) {
601 : 0 : smallest_base = ent->base;
602 : 0 : smallest_name = ent->name;
603 : : }
604 : : }
605 : : }
606 : : /* If the smallest base is before the TOC, don't worry */
607 : 0 : if (smallest_base > toc_base && (hdr->count + 1) * sizeof(struct __ffs_entry) +
608 : 0 : sizeof(struct __ffs_hdr) + toc_base > smallest_base) {
609 : 0 : fprintf(stderr, "Adding partition '%s' would cause partition '%s' at "
610 : : "0x%08x to overlap with the header\n", entry->name, smallest_name,
611 : : smallest_base);
612 : 0 : return FFS_ERR_BAD_PART_BASE;
613 : : }
614 : :
615 : 0 : if (hdr->count == hdr->entries_size) {
616 : 0 : struct ffs_entry **old = hdr->entries;
617 : :
618 : 0 : hdr->entries = realloc(hdr->entries,
619 : 0 : (HDR_ENTRIES_NUM + hdr->entries_size) * sizeof(struct ffs_entry *));
620 : 0 : if (!hdr->entries) {
621 : 0 : hdr->entries = old;
622 : 0 : return FLASH_ERR_MALLOC_FAILED;
623 : : }
624 : 0 : hdr->entries_size += HDR_ENTRIES_NUM;
625 : : }
626 : 0 : entry->ref++;
627 : 0 : hdr->entries[hdr->count++] = entry;
628 : :
629 : 0 : return 0;
630 : : }
631 : :
632 : 0 : int ffs_hdr_finalise(struct blocklevel_device *bl, struct ffs_hdr *hdr)
633 : : {
634 : 0 : int num_entries, i, rc = 0;
635 : 0 : struct __ffs_hdr *real_hdr;
636 : :
637 : 0 : num_entries = ffs_num_entries(hdr);
638 : :
639 : : /* A TOC shouldn't have zero partitions */
640 : 0 : if (num_entries == 0)
641 : : return FFS_ERR_BAD_SIZE;
642 : :
643 : 0 : real_hdr = malloc(ffs_hdr_raw_size(num_entries));
644 : 0 : if (!real_hdr)
645 : : return FLASH_ERR_MALLOC_FAILED;
646 : :
647 : : /*
648 : : * So that the checksum gets calculated correctly at least the
649 : : * real_hdr->checksum must be zero before calling ffs_hdr_checksum()
650 : : * memset()ting the entire struct to zero is probably wise as it
651 : : * appears the reserved fields are always zero.
652 : : */
653 : 0 : memset(real_hdr, 0, sizeof(*real_hdr));
654 : :
655 : 0 : hdr->part->size = ffs_hdr_raw_size(num_entries) + hdr->block_size;
656 : : /*
657 : : * So actual is in bytes. ffs_entry_to_flash() don't do the
658 : : * block_size division that we're relying on
659 : : */
660 : 0 : hdr->part->actual = (hdr->part->size / hdr->block_size) * hdr->block_size;
661 : 0 : real_hdr->magic = cpu_to_be32(FFS_MAGIC);
662 : 0 : real_hdr->version = cpu_to_be32(hdr->version);
663 : 0 : real_hdr->size = cpu_to_be32(hdr->part->size / hdr->block_size);
664 : 0 : real_hdr->entry_size = cpu_to_be32(sizeof(struct __ffs_entry));
665 : 0 : real_hdr->entry_count = cpu_to_be32(num_entries);
666 : 0 : real_hdr->block_size = cpu_to_be32(hdr->block_size);
667 : 0 : real_hdr->block_count = cpu_to_be32(hdr->block_count);
668 : 0 : real_hdr->checksum = ffs_hdr_checksum(real_hdr);
669 : :
670 : 0 : for (i = 0; i < hdr->count; i++) {
671 : 0 : rc = ffs_entry_to_flash(hdr, real_hdr->entries + i, hdr->entries[i]);
672 : 0 : if (rc) {
673 : 0 : fprintf(stderr, "Couldn't format all entries for new TOC\n");
674 : 0 : goto out;
675 : : }
676 : : }
677 : :
678 : : /* Don't really care if this fails */
679 : 0 : blocklevel_erase(bl, hdr->part->base, hdr->size);
680 : 0 : rc = blocklevel_write(bl, hdr->part->base, real_hdr,
681 : : ffs_hdr_raw_size(num_entries));
682 : 0 : if (rc)
683 : 0 : goto out;
684 : :
685 : 0 : out:
686 : 0 : free(real_hdr);
687 : 0 : return rc;
688 : : }
689 : :
690 : 0 : int ffs_entry_user_set(struct ffs_entry *ent, struct ffs_entry_user *user)
691 : : {
692 : 0 : if (!ent || !user)
693 : : return -1;
694 : :
695 : : /*
696 : : * Don't allow the user to specify anything we dont't know about.
697 : : * Rationale: This is the library providing access to the FFS structures.
698 : : * If the consumer of the library knows more about FFS structures then
699 : : * questions need to be asked.
700 : : * The other possibility is that they've unknowningly supplied invalid
701 : : * flags, we should tell them.
702 : : */
703 : 0 : if (user->chip)
704 : : return -1;
705 : 0 : if (user->compresstype)
706 : : return -1;
707 : 0 : if (user->datainteg & ~(FFS_ENRY_INTEG_ECC))
708 : : return -1;
709 : 0 : if (user->vercheck & ~(FFS_VERCHECK_SHA512V | FFS_VERCHECK_SHA512EC))
710 : : return -1;
711 : 0 : if (user->miscflags & ~(FFS_MISCFLAGS_PRESERVED | FFS_MISCFLAGS_BACKUP |
712 : : FFS_MISCFLAGS_READONLY | FFS_MISCFLAGS_REPROVISION |
713 : : FFS_MISCFLAGS_VOLATILE | FFS_MISCFLAGS_GOLDEN |
714 : : FFS_MISCFLAGS_CLEARECC))
715 : : return -1;
716 : :
717 : 0 : memcpy(&ent->user, user, sizeof(*user));
718 : 0 : return 0;
719 : : }
720 : :
721 : 0 : struct ffs_entry_user ffs_entry_user_get(struct ffs_entry *ent)
722 : : {
723 : 0 : struct ffs_entry_user user = { 0 };
724 : :
725 : 0 : if (ent)
726 : 0 : memcpy(&user, &ent->user, sizeof(user));
727 : :
728 : 0 : return user;
729 : : }
730 : :
731 : 0 : int ffs_entry_new(const char *name, uint32_t base, uint32_t size, struct ffs_entry **r)
732 : : {
733 : 0 : struct ffs_entry *ret;
734 : :
735 : 0 : ret = calloc(1, sizeof(*ret));
736 : 0 : if (!ret)
737 : : return FLASH_ERR_MALLOC_FAILED;
738 : :
739 : 0 : strncpy(ret->name, name, FFS_PART_NAME_MAX);
740 : 0 : ret->name[FFS_PART_NAME_MAX] = '\0';
741 : 0 : ret->base = base;
742 : 0 : ret->size = size;
743 : 0 : ret->actual = size;
744 : 0 : ret->pid = FFS_PID_TOPLEVEL;
745 : 0 : ret->type = FFS_TYPE_DATA;
746 : 0 : ret->ref = 1;
747 : :
748 : 0 : *r = ret;
749 : 0 : return 0;
750 : : }
751 : :
752 : 0 : int ffs_entry_set_act_size(struct ffs_entry *ent, uint32_t actual_size)
753 : : {
754 : 0 : if (!ent)
755 : : return -1;
756 : :
757 : 0 : if (actual_size > ent->size)
758 : : return FFS_ERR_BAD_PART_SIZE;
759 : :
760 : 0 : ent->actual = actual_size;
761 : :
762 : 0 : return 0;
763 : : }
764 : :
765 : 0 : int ffs_hdr_new(uint32_t block_size, uint32_t block_count,
766 : : struct ffs_entry **e, struct ffs_hdr **r)
767 : : {
768 : 0 : struct ffs_hdr *ret;
769 : 0 : struct ffs_entry *part_table;
770 : 0 : int rc;
771 : :
772 : 0 : ret = calloc(1, sizeof(*ret));
773 : 0 : if (!ret)
774 : : return FLASH_ERR_MALLOC_FAILED;
775 : :
776 : 0 : ret->version = FFS_VERSION_1;
777 : 0 : ret->block_size = block_size;
778 : 0 : ret->block_count = block_count;
779 : 0 : ret->entries = calloc(HDR_ENTRIES_NUM, sizeof(struct ffs_entry *));
780 : 0 : ret->entries_size = HDR_ENTRIES_NUM;
781 : :
782 : 0 : if (!e || !(*e)) {
783 : : /* Don't know how big it will be, ffs_hdr_finalise() will fix */
784 : 0 : rc = ffs_entry_new("part", 0, 0, &part_table);
785 : 0 : if (rc) {
786 : 0 : free(ret);
787 : 0 : return rc;
788 : : }
789 : 0 : if (e)
790 : 0 : *e = part_table;
791 : : } else {
792 : 0 : part_table = *e;
793 : : }
794 : :
795 : : /* If the user still holds a ref to e, then inc the refcount */
796 : 0 : if (e)
797 : 0 : part_table->ref++;
798 : :
799 : 0 : ret->part = part_table;
800 : :
801 : 0 : part_table->pid = FFS_PID_TOPLEVEL;
802 : 0 : part_table->type = FFS_TYPE_PARTITION;
803 : 0 : part_table->flags = FFS_FLAGS_PROTECTED;
804 : :
805 : 0 : ret->entries[0] = part_table;
806 : 0 : ret->count = 1;
807 : :
808 : 0 : *r = ret;
809 : :
810 : 0 : return 0;
811 : : }
812 : :
813 : 0 : int ffs_update_act_size(struct ffs_handle *ffs, uint32_t part_idx,
814 : : uint32_t act_size)
815 : : {
816 : 0 : struct ffs_entry *ent;
817 : 0 : struct __ffs_entry raw_ent;
818 : 0 : uint32_t offset;
819 : 0 : int rc;
820 : :
821 : 0 : ent = __ffs_entry_get(ffs, part_idx);
822 : 0 : if (!ent) {
823 : 0 : FL_DBG("FFS: Entry not found\n");
824 : 0 : return FFS_ERR_PART_NOT_FOUND;
825 : : }
826 : 0 : offset = ffs->toc_offset + ffs_hdr_raw_size(part_idx);
827 : 0 : FL_DBG("FFS: part index %d at offset 0x%08x\n",
828 : : part_idx, offset);
829 : :
830 : 0 : if (ent->actual == act_size) {
831 : 0 : FL_DBG("FFS: ent->actual alrady matches: 0x%08x==0x%08x\n",
832 : : act_size, ent->actual);
833 : 0 : return 0;
834 : : }
835 : 0 : ent->actual = act_size;
836 : :
837 : 0 : rc = ffs_entry_to_flash(&ffs->hdr, &raw_ent, ent);
838 : 0 : if (rc)
839 : : return rc;
840 : :
841 : 0 : return blocklevel_smart_write(ffs->bl, offset, &raw_ent, sizeof(struct __ffs_entry));
842 : : }
|