blob: db7104d69aa9770435df6b0d34beb3b64afdc160 [file] [log] [blame]
Norman James6a58a272015-10-07 14:34:16 -05001/*
2 */
3#include <stdlib.h>
4#include <stdio.h>
5#include <string.h>
6
7#include <ccan/endian/endian.h>
8
9#include "libffs.h"
10
11enum ffs_type {
12 ffs_type_flash,
13 ffs_type_image,
14};
15
16struct ffs_handle {
17 struct ffs_hdr hdr; /* Converted header */
18 enum ffs_type type;
19 struct flash_chip *chip;
20 uint32_t flash_offset;
21 uint32_t max_size;
22 void *cache;
23 uint32_t cached_size;
24};
25
26static uint32_t ffs_checksum(void* data, size_t size)
27{
28 uint32_t i, csum = 0;
29
30 for (i = csum = 0; i < (size/4); i++)
31 csum ^= ((uint32_t *)data)[i];
32 return csum;
33}
34
35static int ffs_check_convert_header(struct ffs_hdr *dst, struct ffs_hdr *src)
36{
37 dst->magic = be32_to_cpu(src->magic);
38 if (dst->magic != FFS_MAGIC)
39 return FFS_ERR_BAD_MAGIC;
40 dst->version = be32_to_cpu(src->version);
41 if (dst->version != FFS_VERSION_1)
42 return FFS_ERR_BAD_VERSION;
43 if (ffs_checksum(src, FFS_HDR_SIZE) != 0)
44 return FFS_ERR_BAD_CKSUM;
45 dst->size = be32_to_cpu(src->size);
46 dst->entry_size = be32_to_cpu(src->entry_size);
47 dst->entry_count = be32_to_cpu(src->entry_count);
48 dst->block_size = be32_to_cpu(src->block_size);
49 dst->block_count = be32_to_cpu(src->block_count);
50
51 return 0;
52}
53
54int ffs_open_flash(struct flash_chip *chip, uint32_t offset,
55 uint32_t max_size, struct ffs_handle **ffs)
56{
57 struct ffs_hdr hdr;
58 struct ffs_handle *f;
59 uint32_t fl_size, erase_size;
60 int rc;
61
62 if (!ffs)
63 return FLASH_ERR_PARM_ERROR;
64 *ffs = NULL;
65
66 /* Grab some info about our flash chip */
67 rc = flash_get_info(chip, NULL, &fl_size, &erase_size);
68 if (rc) {
69 FL_ERR("FFS: Error %d retrieving flash info\n", rc);
70 return rc;
71 }
72 if ((offset + max_size) < offset)
73 return FLASH_ERR_PARM_ERROR;
74 if ((offset + max_size) > fl_size)
75 return FLASH_ERR_PARM_ERROR;
76
77 /* Read flash header */
78 rc = flash_read(chip, offset, &hdr, sizeof(hdr));
79 if (rc) {
80 FL_ERR("FFS: Error %d reading flash header\n", rc);
81 return rc;
82 }
83
84 /* Allocate ffs_handle structure and start populating */
85 f = malloc(sizeof(*f));
86 if (!f)
87 return FLASH_ERR_MALLOC_FAILED;
88 memset(f, 0, sizeof(*f));
89 f->type = ffs_type_flash;
90 f->flash_offset = offset;
91 f->max_size = max_size ? max_size : (fl_size - offset);
92 f->chip = chip;
93
94 /* Convert and check flash header */
95 rc = ffs_check_convert_header(&f->hdr, &hdr);
96 if (rc) {
97 FL_ERR("FFS: Error %d checking flash header\n", rc);
98 free(f);
99 return rc;
100 }
101
102 /*
103 * Decide how much of the image to grab to get the whole
104 * partition map.
105 */
106 f->cached_size = f->hdr.block_size * f->hdr.size;
107 FL_DBG("FFS: Partition map size: 0x%x\n", f->cached_size);
108
109 /* Align to erase size */
110 f->cached_size |= (erase_size - 1);
111 f->cached_size &= ~(erase_size - 1);
112 FL_DBG("FFS: Aligned to: 0x%x\n", f->cached_size);
113
114 /* Allocate cache */
115 f->cache = malloc(f->cached_size);
116 if (!f->cache) {
117 free(f);
118 return FLASH_ERR_MALLOC_FAILED;
119 }
120
121 /* Read the cached map */
122 rc = flash_read(chip, offset, f->cache, f->cached_size);
123 if (rc) {
124 FL_ERR("FFS: Error %d reading flash partition map\n", rc);
125 free(f);
126 }
127 if (rc == 0)
128 *ffs = f;
129 return rc;
130}
131
132#if 0 /* XXX TODO: For FW updates so we can copy nvram around */
133int ffs_open_image(void *image, uint32_t size, uint32_t offset,
134 struct ffs_handle **ffs)
135{
136}
137#endif
138
139void ffs_close(struct ffs_handle *ffs)
140{
141 if (ffs->cache)
142 free(ffs->cache);
143 free(ffs);
144}
145
146static struct ffs_entry *ffs_get_part(struct ffs_handle *ffs, uint32_t index,
147 uint32_t *out_offset)
148{
149 uint32_t esize = ffs->hdr.entry_size;
150 uint32_t offset = FFS_HDR_SIZE + index * esize;
151
152 if (index > ffs->hdr.entry_count)
153 return NULL;
154 if (out_offset)
155 *out_offset = offset;
156 return (struct ffs_entry *)(ffs->cache + offset);
157}
158
159static int ffs_check_convert_entry(struct ffs_entry *dst, struct ffs_entry *src)
160{
161 if (ffs_checksum(src, FFS_ENTRY_SIZE) != 0)
162 return FFS_ERR_BAD_CKSUM;
163 memcpy(dst->name, src->name, sizeof(dst->name));
164 dst->base = be32_to_cpu(src->base);
165 dst->size = be32_to_cpu(src->size);
166 dst->pid = be32_to_cpu(src->pid);
167 dst->id = be32_to_cpu(src->id);
168 dst->type = be32_to_cpu(src->type);
169 dst->flags = be32_to_cpu(src->flags);
170 dst->actual = be32_to_cpu(src->actual);
171
172 return 0;
173}
174
175int ffs_lookup_part(struct ffs_handle *ffs, const char *name,
176 uint32_t *part_idx)
177{
178 struct ffs_entry ent;
179 uint32_t i;
180 int rc;
181
182 /* Lookup the requested partition */
183 for (i = 0; i < ffs->hdr.entry_count; i++) {
184 struct ffs_entry *src_ent = ffs_get_part(ffs, i, NULL);
185 rc = ffs_check_convert_entry(&ent, src_ent);
186 if (rc) {
187 FL_ERR("FFS: Bad entry %d in partition map\n", i);
188 continue;
189 }
190 if (!strncmp(name, ent.name, sizeof(ent.name)))
191 break;
192 }
193 if (i >= ffs->hdr.entry_count)
194 return FFS_ERR_PART_NOT_FOUND;
195 if (part_idx)
196 *part_idx = i;
197 return 0;
198}
199
200int ffs_part_info(struct ffs_handle *ffs, uint32_t part_idx,
201 char **name, uint32_t *start,
202 uint32_t *total_size, uint32_t *act_size)
203{
204 struct ffs_entry *raw_ent;
205 struct ffs_entry ent;
206 char *n;
207 int rc;
208
209 if (part_idx >= ffs->hdr.entry_count)
210 return FFS_ERR_PART_NOT_FOUND;
211
212 raw_ent = ffs_get_part(ffs, part_idx, NULL);
213 if (!raw_ent)
214 return FFS_ERR_PART_NOT_FOUND;
215
216 rc = ffs_check_convert_entry(&ent, raw_ent);
217 if (rc) {
218 FL_ERR("FFS: Bad entry %d in partition map\n", part_idx);
219 return rc;
220 }
221 if (start)
222 *start = ent.base * ffs->hdr.block_size;
223 if (total_size)
224 *total_size = ent.size * ffs->hdr.block_size;
225 if (act_size)
226 *act_size = ent.actual;
227 if (name) {
228 n = malloc(PART_NAME_MAX + 1);
229 memset(n, 0, PART_NAME_MAX + 1);
230 strncpy(n, ent.name, PART_NAME_MAX);
231 *name = n;
232 }
233 return 0;
234}
235
236int ffs_update_act_size(struct ffs_handle *ffs, uint32_t part_idx,
237 uint32_t act_size)
238{
239 struct ffs_entry *ent;
240 uint32_t offset;
241
242 if (part_idx >= ffs->hdr.entry_count) {
243 FL_DBG("FFS: Entry out of bound\n");
244 return FFS_ERR_PART_NOT_FOUND;
245 }
246
247 ent = ffs_get_part(ffs, part_idx, &offset);
248 if (!ent) {
249 FL_DBG("FFS: Entry not found\n");
250 return FFS_ERR_PART_NOT_FOUND;
251 }
252 FL_DBG("FFS: part index %d at offset 0x%08x\n",
253 part_idx, offset);
254
255 if (ent->actual == cpu_to_be32(act_size)) {
256 FL_DBG("FFS: ent->actual alrady matches: 0x%08x==0x%08x\n",
257 cpu_to_be32(act_size), ent->actual);
258 return 0;
259 }
260 ent->actual = cpu_to_be32(act_size);
261 ent->checksum = ffs_checksum(ent, FFS_ENTRY_SIZE_CSUM);
262 if (!ffs->chip)
263 return 0;
264 return flash_smart_write(ffs->chip, offset, ent, FFS_ENTRY_SIZE);
265}