Branch data Line data Source code
1 : : // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2 : : /*
3 : : * Display progress bars, while also writing whole or part
4 : : * of flash.
5 : : *
6 : : * Copyright 2013-2019 IBM Corp.
7 : : */
8 : :
9 : : #define _GNU_SOURCE
10 : :
11 : : #include <stdio.h>
12 : : #include <stdlib.h>
13 : : #include <string.h>
14 : : #include <fcntl.h>
15 : : #include <sys/mman.h>
16 : : #include <sys/types.h>
17 : : #include <sys/stat.h>
18 : : #include <unistd.h>
19 : : #include <byteswap.h>
20 : : #include <stdint.h>
21 : : #include <stdbool.h>
22 : : #include <getopt.h>
23 : : #include <limits.h>
24 : : #include <arpa/inet.h>
25 : : #include <assert.h>
26 : : #include <inttypes.h>
27 : :
28 : : #include <libflash/libflash.h>
29 : : #include <libflash/libffs.h>
30 : : #include <libflash/blocklevel.h>
31 : : #include <libflash/ecc.h>
32 : : #include <common/arch_flash.h>
33 : : #include "progress.h"
34 : :
35 : : #define __aligned(x) __attribute__((aligned(x)))
36 : :
37 : : struct flash_details {
38 : : struct blocklevel_device *bl;
39 : : int need_relock;
40 : : const char *name;
41 : : uint64_t toc;
42 : : uint64_t total_size;
43 : : uint32_t erase_granule;
44 : : bool mark_ecc;
45 : : };
46 : :
47 : : /* Full pflash version number (possibly includes gitid). */
48 : : extern const char version[];
49 : :
50 : : const char *flashfilename = NULL;
51 : : static bool must_confirm = true;
52 : : static bool dummy_run;
53 : : static bool bmc_flash;
54 : :
55 : : #define FILE_BUF_SIZE 0x10000
56 : : static uint8_t file_buf[FILE_BUF_SIZE] __aligned(0x1000);
57 : :
58 : 12 : static bool check_confirm(void)
59 : : {
60 : 12 : char yes[8], *p;
61 : :
62 : 12 : if (!must_confirm)
63 : : return true;
64 : :
65 : 16 : printf("WARNING ! This will modify your %s flash chip content !\n",
66 : 8 : bmc_flash ? "BMC" : "HOST");
67 : 8 : printf("Enter \"yes\" to confirm:");
68 : 8 : memset(yes, 0, sizeof(yes));
69 : 8 : if (!fgets(yes, 7, stdin))
70 : : return false;
71 : 8 : p = strchr(yes, 10);
72 : 8 : if (p)
73 : 8 : *p = 0;
74 : 8 : p = strchr(yes, 13);
75 : 8 : if (p)
76 : 0 : *p = 0;
77 : 8 : if (strcmp(yes, "yes")) {
78 : 0 : printf("Operation cancelled !\n");
79 : 0 : return false;
80 : : }
81 : 8 : must_confirm = false;
82 : 8 : return true;
83 : : }
84 : :
85 : 2 : static uint32_t print_ffs_info(struct ffs_handle *ffsh, uint32_t toc)
86 : : {
87 : 2 : struct ffs_entry *ent;
88 : 2 : uint32_t next_toc = toc;
89 : 2 : int rc;
90 : 2 : int i;
91 : :
92 : 2 : printf("\n");
93 : 2 : printf("TOC@0x%08x Partitions:\n", toc);
94 : 2 : printf("-----------\n");
95 : :
96 : 2 : for (i = 0;; i++) {
97 : 16 : uint32_t start, size, act, end;
98 : 16 : struct ffs_entry_user user;
99 : 16 : char *name = NULL, *flags;
100 : :
101 : 16 : rc = ffs_part_info(ffsh, i, &name, &start, &size, &act, NULL);
102 : 16 : if (rc == FFS_ERR_PART_NOT_FOUND)
103 : : break;
104 : :
105 : 14 : ent = ffs_entry_get(ffsh, i);
106 : 14 : if (rc || !ent) {
107 : 0 : fprintf(stderr, "Error %d scanning partitions\n",
108 : : !ent ? FFS_ERR_PART_NOT_FOUND : rc);
109 : 0 : goto out;
110 : : }
111 : :
112 : 14 : user = ffs_entry_user_get(ent);
113 : 14 : ffs_entry_put(ent);
114 : 14 : flags = ffs_entry_user_to_string(&user);
115 : 14 : if (!flags)
116 : 0 : goto out;
117 : :
118 : 14 : end = start + size;
119 : 14 : printf("ID=%02d %15s 0x%08x..0x%08x (actual=0x%08x) [%s]\n",
120 : : i, name, start, end, act, flags);
121 : :
122 : 14 : if (strcmp(name, "OTHER_SIDE") == 0)
123 : 0 : next_toc = start;
124 : :
125 : 14 : free(flags);
126 : 14 : out:
127 : 14 : free(name);
128 : : }
129 : :
130 : 2 : return next_toc;
131 : : }
132 : :
133 : 18 : static struct ffs_handle *open_ffs(struct flash_details *flash)
134 : : {
135 : 18 : struct ffs_handle *ffsh;
136 : 18 : int rc;
137 : :
138 : 36 : rc = ffs_init(flash->toc, flash->total_size,
139 : 18 : flash->bl, &ffsh, flash->mark_ecc);
140 : 18 : if (rc) {
141 : 0 : fprintf(stderr, "Error %d opening ffs !\n", rc);
142 : 0 : if (flash->toc) {
143 : 0 : fprintf(stderr, "You specified 0x%" PRIx64 " as the libffs TOC\n"
144 : : "Looks like it doesn't exist\n", flash->toc);
145 : 0 : return NULL;
146 : : }
147 : : }
148 : :
149 : 18 : return ffsh;
150 : : }
151 : :
152 : 2 : static void print_flash_info(struct flash_details *flash)
153 : : {
154 : 2 : struct ffs_handle *ffsh;
155 : 2 : uint32_t next_toc;
156 : 2 : uint32_t toc;
157 : :
158 : 2 : printf("Flash info:\n");
159 : 2 : printf("-----------\n");
160 : 2 : printf("Name = %s\n", flash->name);
161 : 4 : printf("Total size = %" PRIu64 "MB\t Flags E:ECC, P:PRESERVED, R:READONLY, "
162 : 2 : "B:BACKUP\n", flash->total_size >> 20);
163 : 4 : printf("Erase granule = %2d%-13sF:REPROVISION, V:VOLATILE, C:CLEARECC\n",
164 : 2 : flash->erase_granule >> 10, "KB");
165 : :
166 : 2 : if (bmc_flash)
167 : : return;
168 : :
169 : 2 : toc = flash->toc;
170 : :
171 : 2 : ffsh = open_ffs(flash);
172 : 2 : if (!ffsh)
173 : : return;
174 : :
175 : 2 : next_toc = print_ffs_info(ffsh, toc);
176 : 2 : ffs_close(ffsh);
177 : 2 : while(next_toc != toc) {
178 : 0 : struct ffs_handle *next_ffsh;
179 : :
180 : 0 : flash->toc = next_toc;
181 : 0 : next_ffsh = open_ffs(flash);
182 : 0 : if (!next_ffsh)
183 : : break;
184 : 0 : next_toc = print_ffs_info(next_ffsh, next_toc);
185 : 0 : ffs_close(next_ffsh);
186 : : }
187 : 2 : flash->toc = toc;
188 : : }
189 : :
190 : 16 : static struct ffs_handle *open_partition(struct flash_details *flash,
191 : : const char *name, uint32_t *index)
192 : : {
193 : 16 : struct ffs_handle *ffsh;
194 : 16 : int rc;
195 : :
196 : 16 : ffsh = open_ffs(flash);
197 : 16 : if (!ffsh)
198 : : return NULL;
199 : :
200 : 16 : if (!name)
201 : : /* Just open the FFS */
202 : : return ffsh;
203 : :
204 : : /* Find partition */
205 : 4 : rc = ffs_lookup_part(ffsh, name, index);
206 : 4 : if (rc == FFS_ERR_PART_NOT_FOUND) {
207 : 0 : fprintf(stderr, "Partition '%s' not found !\n", name);
208 : 0 : goto out;
209 : : }
210 : 4 : if (rc) {
211 : 0 : fprintf(stderr, "Error %d looking for partition '%s' !\n",
212 : : rc, name);
213 : 0 : goto out;
214 : : }
215 : : return ffsh;
216 : 0 : out:
217 : 0 : ffs_close(ffsh);
218 : 0 : return NULL;
219 : : }
220 : :
221 : 16 : static struct ffs_handle *lookup_partition_at_toc(struct flash_details *flash,
222 : : const char *name, uint32_t *index)
223 : : {
224 : 16 : return open_partition(flash, name, index);
225 : : }
226 : :
227 : 16 : static struct ffs_handle *lookup_partition_at_side(struct flash_details *flash,
228 : : int side, const char *name, uint32_t *index)
229 : : {
230 : 16 : uint32_t toc = 0;
231 : 16 : int rc;
232 : :
233 : 16 : if (side == 1) {
234 : 0 : struct ffs_handle *ffsh;
235 : 0 : uint32_t side_index;
236 : :
237 : 0 : ffsh = open_partition(flash, "OTHER_SIDE", &side_index);
238 : 0 : if (!ffsh)
239 : 0 : return NULL;
240 : :
241 : : /* Just need to know where it starts */
242 : 0 : rc = ffs_part_info(ffsh, side_index, NULL, &toc, NULL, NULL, NULL);
243 : 0 : ffs_close(ffsh);
244 : 0 : if (rc)
245 : : return NULL;
246 : : }
247 : :
248 : 16 : flash->toc = toc;
249 : 16 : return lookup_partition_at_toc(flash, name, index);
250 : : }
251 : :
252 : 2 : static int erase_chip(struct flash_details *flash)
253 : : {
254 : 2 : bool confirm;
255 : 2 : int rc;
256 : 2 : uint64_t pos;
257 : :
258 : 2 : printf("About to erase chip !\n");
259 : 2 : confirm = check_confirm();
260 : 2 : if (!confirm)
261 : : return 1;
262 : :
263 : 2 : printf("Erasing... (may take a while)\n");
264 : 2 : fflush(stdout);
265 : :
266 : 2 : if (dummy_run) {
267 : 0 : printf("skipped (dummy)\n");
268 : 0 : return 1;
269 : : }
270 : :
271 : : /*
272 : : * We could use arch_flash_erase_chip() here BUT everyone really
273 : : * likes the progress bars.
274 : : * Lets do an erase block at a time erase then...
275 : : */
276 : 2 : progress_init(flash->total_size);
277 : 5124 : for (pos = 0; pos < flash->total_size; pos += flash->erase_granule) {
278 : 5120 : rc = blocklevel_erase(flash->bl, pos, flash->erase_granule);
279 : 5120 : if (rc)
280 : : break;
281 : 5120 : progress_tick(pos);
282 : : }
283 : 2 : progress_end();
284 : 2 : if (rc) {
285 : 0 : fprintf(stderr, "Error %d erasing chip\n", rc);
286 : 0 : return rc;
287 : : }
288 : :
289 : 2 : printf("done !\n");
290 : 2 : return 0;
291 : : }
292 : :
293 : 6 : static int erase_range(struct flash_details *flash,
294 : : uint32_t start, uint32_t size, bool will_program,
295 : : struct ffs_handle *ffsh, int ffs_index)
296 : : {
297 : 6 : uint32_t done = 0, erase_mask = flash->erase_granule - 1;
298 : 6 : struct ffs_entry *toc;
299 : 6 : bool confirm;
300 : 6 : int rc;
301 : :
302 : 6 : printf("About to erase 0x%08x..0x%08x !\n", start, start + size);
303 : 6 : confirm = check_confirm();
304 : 6 : if (!confirm)
305 : : return 1;
306 : :
307 : 6 : if (dummy_run) {
308 : 0 : printf("skipped (dummy)\n");
309 : 0 : return 1;
310 : : }
311 : :
312 : 6 : printf("Erasing...\n");
313 : : /*
314 : : * blocklevel_smart_erase() can do the entire thing in one call
315 : : * BUT everyone really likes progress bars so break stuff up
316 : : */
317 : 6 : progress_init(size);
318 : 6 : if (start & erase_mask) {
319 : : /*
320 : : * Align to next erase block, or just do the entire
321 : : * thing if we fit within one erase block
322 : : */
323 : 0 : uint32_t first_size = MIN(size, (flash->erase_granule - (start & erase_mask)));
324 : :
325 : 0 : rc = blocklevel_smart_erase(flash->bl, start, first_size);
326 : 0 : if (rc) {
327 : 0 : fprintf(stderr, "Failed to blocklevel_smart_erase(): %d\n", rc);
328 : 0 : return 1;
329 : : }
330 : 0 : size -= first_size;
331 : 0 : done = first_size;
332 : 0 : start += first_size;
333 : : }
334 : 6 : progress_tick(done);
335 : 1542 : while (size & ~(erase_mask)) {
336 : 1536 : rc = blocklevel_smart_erase(flash->bl, start, flash->erase_granule);
337 : 1536 : if (rc) {
338 : 0 : fprintf(stderr, "Failed to blocklevel_smart_erase(): %d\n", rc);
339 : 0 : return 1;
340 : : }
341 : 1536 : start += flash->erase_granule;
342 : 1536 : size -= flash->erase_granule;
343 : 1536 : done += flash->erase_granule;
344 : 1536 : progress_tick(done);
345 : : }
346 : 6 : if (size) {
347 : 0 : rc = blocklevel_smart_erase(flash->bl, start, size);
348 : 0 : if (rc) {
349 : 0 : fprintf(stderr, "Failed to blocklevel_smart_erase(): %d\n", rc);
350 : 0 : return 1;
351 : : }
352 : 0 : done += size;
353 : 0 : progress_tick(done);
354 : : }
355 : 6 : progress_end();
356 : :
357 : 6 : if (!ffsh)
358 : : return 0;
359 : :
360 : : /* If this is a flash partition, mark it empty if we aren't
361 : : * going to program over it as well
362 : : */
363 : 4 : toc = ffs_entry_get(ffsh, 0);
364 : 4 : if (toc) {
365 : 4 : struct ffs_entry_user user;
366 : 4 : bool rw_toc;
367 : :
368 : 4 : user = ffs_entry_user_get(toc);
369 : 4 : rw_toc = !(user.miscflags & FFS_MISCFLAGS_READONLY);
370 : 4 : if (ffs_index >= 0 && !will_program && rw_toc) {
371 : 2 : printf("Updating actual size in partition header...\n");
372 : 2 : ffs_update_act_size(ffsh, ffs_index, 0);
373 : : }
374 : : }
375 : :
376 : : return 0;
377 : : }
378 : :
379 : 0 : static int set_ecc(struct flash_details *flash, uint32_t start, uint32_t size)
380 : : {
381 : 0 : uint32_t i = start + 8;
382 : 0 : uint8_t ecc = 0;
383 : 0 : bool confirm;
384 : 0 : int rc;
385 : :
386 : 0 : printf("About to erase and set ECC bits in region 0x%08x to 0x%08x\n", start, start + size);
387 : 0 : confirm = check_confirm();
388 : 0 : if (!confirm)
389 : : return 1;
390 : :
391 : 0 : rc = erase_range(flash, start, size, true, NULL, 0);
392 : 0 : if (rc) {
393 : 0 : fprintf(stderr, "Couldn't erase region to mark with ECC\n");
394 : 0 : return rc;
395 : : }
396 : :
397 : 0 : printf("Programming ECC bits...\n");
398 : 0 : progress_init(size);
399 : 0 : while (i < start + size) {
400 : 0 : rc = blocklevel_write(flash->bl, i, &ecc, sizeof(ecc));
401 : 0 : if (rc) {
402 : 0 : fprintf(stderr, "\nError setting ECC byte at 0x%08x\n", i);
403 : 0 : return rc;
404 : : }
405 : 0 : i += 9;
406 : 0 : progress_tick(i - start);
407 : : }
408 : 0 : progress_end();
409 : 0 : return 0;
410 : : }
411 : :
412 : 4 : static int program_file(struct blocklevel_device *bl,
413 : : const char *file, uint32_t start, uint32_t size,
414 : : struct ffs_handle *ffsh, int ffs_index)
415 : : {
416 : 4 : uint32_t actual_size = 0;
417 : 4 : struct ffs_entry *toc;
418 : 4 : int fd, rc = 0;
419 : 4 : bool confirm;
420 : :
421 : 4 : fd = open(file, O_RDONLY);
422 : 4 : if (fd == -1) {
423 : 0 : perror("Failed to open file");
424 : 0 : return 1;
425 : : }
426 : 4 : printf("About to program \"%s\" at 0x%08x..0x%08x !\n",
427 : : file, start, start + size);
428 : 4 : confirm = check_confirm();
429 : 4 : if (!confirm) {
430 : 0 : rc = 1;
431 : 0 : goto out;
432 : : }
433 : :
434 : 4 : if (dummy_run) {
435 : 0 : printf("skipped (dummy)\n");
436 : 0 : rc = 1;
437 : 0 : goto out;
438 : : }
439 : :
440 : 4 : printf("Programming & Verifying...\n");
441 : 4 : progress_init(size);
442 : 8 : while(size) {
443 : 4 : ssize_t len;
444 : :
445 : 4 : len = read(fd, file_buf, FILE_BUF_SIZE);
446 : 4 : if (len < 0) {
447 : 0 : perror("Error reading file");
448 : 0 : rc = 1;
449 : 0 : goto out;
450 : : }
451 : 4 : if (len == 0)
452 : : break;
453 : 4 : if (len > size)
454 : : len = size;
455 : 4 : size -= len;
456 : 4 : actual_size += len;
457 : 4 : rc = blocklevel_write(bl, start, file_buf, len);
458 : 4 : if (rc) {
459 : 0 : if (rc == FLASH_ERR_VERIFY_FAILURE)
460 : 0 : fprintf(stderr, "Verification failed for"
461 : : " chunk at 0x%08x\n", start);
462 : : else
463 : 0 : fprintf(stderr, "Flash write error %d for"
464 : : " chunk at 0x%08x\n", rc, start);
465 : 0 : goto out;
466 : : }
467 : 4 : start += len;
468 : 4 : progress_tick(actual_size);
469 : : }
470 : 4 : progress_end();
471 : :
472 : 4 : if (!ffsh)
473 : 2 : goto out;
474 : :
475 : : /* If this is a flash partition, adjust its size */
476 : 2 : toc = ffs_entry_get(ffsh, 0);
477 : 2 : if (toc) {
478 : 2 : struct ffs_entry_user user;
479 : 2 : bool rw_toc;
480 : :
481 : 2 : user = ffs_entry_user_get(toc);
482 : 2 : rw_toc = !(user.miscflags & FFS_MISCFLAGS_READONLY);
483 : 2 : if (ffs_index >= 0 && rw_toc) {
484 : 2 : printf("Updating actual size in partition header...\n");
485 : 2 : ffs_update_act_size(ffsh, ffs_index, actual_size);
486 : : }
487 : : }
488 : 0 : out:
489 : 4 : close(fd);
490 : 4 : return rc;
491 : : }
492 : :
493 : 0 : static int do_read_file(struct blocklevel_device *bl, const char *file,
494 : : uint32_t start, uint32_t size, uint32_t skip_size)
495 : : {
496 : 0 : int fd, rc = 0;
497 : 0 : uint32_t done = 0;
498 : :
499 : 0 : fd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 00666);
500 : 0 : if (fd == -1) {
501 : 0 : perror("Failed to open file");
502 : 0 : return 1;
503 : : }
504 : 0 : start += skip_size;
505 : 0 : size -= skip_size;
506 : :
507 : 0 : printf("Reading to \"%s\" from 0x%08x..0x%08x !\n",
508 : : file, start, start + size);
509 : :
510 : 0 : progress_init(size);
511 : 0 : while(size) {
512 : 0 : ssize_t len;
513 : :
514 : 0 : len = size > FILE_BUF_SIZE ? FILE_BUF_SIZE : size;
515 : 0 : rc = blocklevel_read(bl, start, file_buf, len);
516 : 0 : if (rc) {
517 : 0 : fprintf(stderr, "Flash read error %d for"
518 : : " chunk at 0x%08x\n", rc, start);
519 : : break;
520 : : }
521 : 0 : rc = write(fd, file_buf, len);
522 : : /*
523 : : * zero isn't strictly an error.
524 : : * Treat it as such so we can be sure we'lre always
525 : : * making forward progress.
526 : : */
527 : 0 : if (rc <= 0) {
528 : 0 : perror("Error writing file");
529 : 0 : break;
530 : : }
531 : 0 : start += rc;
532 : 0 : size -= rc;
533 : 0 : done += rc;
534 : 0 : progress_tick(done);
535 : : }
536 : 0 : progress_end();
537 : 0 : close(fd);
538 : 0 : return size ? rc : 0;
539 : : }
540 : :
541 : 0 : static int enable_4B_addresses(struct blocklevel_device *bl)
542 : : {
543 : 0 : int rc;
544 : :
545 : 0 : printf("Switching to 4-bytes address mode\n");
546 : :
547 : 0 : rc = arch_flash_4b_mode(bl, true);
548 : 0 : if (rc) {
549 : 0 : if (rc == -1) {
550 : 0 : fprintf(stderr, "Switching address mode not available on this architecture\n");
551 : : } else {
552 : 0 : fprintf(stderr, "Error %d enabling 4b mode\n", rc);
553 : : }
554 : : }
555 : :
556 : 0 : return rc;
557 : : }
558 : :
559 : 0 : static int disable_4B_addresses(struct blocklevel_device *bl)
560 : : {
561 : 0 : int rc;
562 : :
563 : 0 : printf("Switching to 3-bytes address mode\n");
564 : :
565 : 0 : rc = arch_flash_4b_mode(bl, false);
566 : 0 : if (rc) {
567 : 0 : if (rc == -1) {
568 : 0 : fprintf(stderr, "Switching address mode not available on this architecture\n");
569 : : } else {
570 : 0 : fprintf(stderr, "Error %d enabling 4b mode\n", rc);
571 : : }
572 : : }
573 : :
574 : 0 : return rc;
575 : : }
576 : :
577 : 12 : static void print_partition_detail(struct ffs_handle *ffsh, uint32_t part_id)
578 : : {
579 : 12 : uint32_t start, size, act, end;
580 : 12 : char *ent_name = NULL, *flags;
581 : 12 : struct ffs_entry *ent;
582 : 12 : int rc, l;
583 : :
584 : 12 : rc = ffs_part_info(ffsh, part_id, &ent_name, &start, &size,
585 : : &act, NULL);
586 : 12 : if (rc) {
587 : 0 : fprintf(stderr, "Partition with ID %d doesn't exist error: %d\n",
588 : : part_id, rc);
589 : 0 : goto out;
590 : : }
591 : :
592 : 12 : ent = ffs_entry_get(ffsh, part_id);
593 : 12 : if (!ent) {
594 : 0 : rc = FFS_ERR_PART_NOT_FOUND;
595 : 0 : fprintf(stderr, "Couldn't open partition entry\n");
596 : 0 : goto out;
597 : : }
598 : :
599 : 12 : printf("Detailed partition information\n");
600 : 12 : end = start + size;
601 : 12 : printf("Name:\n");
602 : 12 : printf("%s (ID=%02d)\n\n", ent_name, part_id);
603 : 12 : printf("%-10s %-10s %-10s\n", "Start", "End", "Actual");
604 : 12 : printf("0x%08x 0x%08x 0x%08x\n\n", start, end, act);
605 : :
606 : 12 : printf("Flags:\n");
607 : :
608 : 82 : l = asprintf(&flags, "%s%s%s%s%s%s%s", has_ecc(ent) ? "ECC [E]\n" : "",
609 : 12 : has_flag(ent, FFS_MISCFLAGS_PRESERVED) ? "PRESERVED [P]\n" : "",
610 : 12 : has_flag(ent, FFS_MISCFLAGS_READONLY) ? "READONLY [R]\n" : "",
611 : 12 : has_flag(ent, FFS_MISCFLAGS_BACKUP) ? "BACKUP [B]\n" : "",
612 : 12 : has_flag(ent, FFS_MISCFLAGS_REPROVISION) ?
613 : : "REPROVISION [F]\n" : "",
614 : 12 : has_flag(ent, FFS_MISCFLAGS_VOLATILE) ? "VOLATILE [V]\n" : "",
615 : 12 : has_flag(ent, FFS_MISCFLAGS_CLEARECC) ? "CLEARECC [C]\n" : "");
616 : 12 : ffs_entry_put(ent);
617 : 12 : if (l < 0) {
618 : 0 : fprintf(stderr, "Memory allocation failure printing flags!\n");
619 : 0 : goto out;
620 : : }
621 : :
622 : 12 : printf("%s", flags);
623 : 12 : free(flags);
624 : :
625 : 12 : out:
626 : 12 : free(ent_name);
627 : 12 : }
628 : :
629 : 4 : static void print_version(void)
630 : : {
631 : 4 : printf("Open-Power Flash tool %s\n", version);
632 : 4 : }
633 : :
634 : 4 : static void print_help(const char *pname)
635 : : {
636 : 4 : printf("Usage: %s [options] commands...\n\n", pname);
637 : 4 : printf(" Options:\n");
638 : 4 : printf("\t-a address, --address=address\n");
639 : 4 : printf("\t\tSpecify the start address for erasing, reading\n");
640 : 4 : printf("\t\tor flashing\n\n");
641 : 4 : printf("\t-s size, --size=size\n");
642 : 4 : printf("\t\tSpecify the size in bytes for erasing, reading\n");
643 : 4 : printf("\t\tor flashing\n\n");
644 : 4 : printf("\t-P part_name, --partition=part_name\n");
645 : 4 : printf("\t\tSpecify the partition whose content is to be erased\n");
646 : 4 : printf("\t\tprogrammed or read. This is an alternative to -a and -s\n");
647 : 4 : printf("\t\tif both -P and -s are specified, the smallest of the\n");
648 : 4 : printf("\t\ttwo will be used\n\n");
649 : 4 : printf("\t-f, --force\n");
650 : 4 : printf("\t\tDon't ask for confirmation before erasing or flashing\n\n");
651 : 4 : printf("\t-d, --dummy\n");
652 : 4 : printf("\t\tDon't write to flash\n\n");
653 : 4 : printf("\t--direct\n");
654 : 4 : printf("\t\tBypass all safety provided to you by the kernel driver\n");
655 : 4 : printf("\t\tand use the flash driver built into pflash.\n");
656 : 4 : printf("\t\tIf you have mtd devices and you use this command, the\n");
657 : 4 : printf("\t\tsystem may become unstable.\n");
658 : 4 : printf("\t\tIf you are reading this sentence then this flag is not\n");
659 : 4 : printf("\t\twhat you want! Using this feature without knowing\n");
660 : 4 : printf("\t\twhat it does can and likely will result in a bricked\n");
661 : 4 : printf("\t\tmachine\n\n");
662 : 4 : printf("\t-b, --bmc\n");
663 : 4 : printf("\t\tTarget BMC flash instead of host flash.\n");
664 : 4 : printf("\t\tNote: This carries a high chance of bricking your BMC if you\n");
665 : 4 : printf("\t\tdon't know what you're doing. Consider --mtd to be safe(r)\n\n");
666 : 4 : printf("\t-F filename, --flash-file filename\n");
667 : 4 : printf("\t\tTarget filename instead of actual flash.\n\n");
668 : 4 : printf("\t-S, --side\n");
669 : 4 : printf("\t\tSide of the flash on which to operate, 0 (default) or 1\n\n");
670 : 4 : printf("\t--skip=N\n");
671 : 4 : printf("\t\tSkip N number of bytes from the start when reading\n\n");
672 : 4 : printf("\t-T, --toc\n");
673 : 4 : printf("\t\tlibffs TOC on which to operate, defaults to 0.\n");
674 : 4 : printf("\t\tleading 0x is required for interpretation of a hex value\n\n");
675 : 4 : printf("\t-g\n");
676 : 4 : printf("\t\tEnable verbose libflash debugging\n\n");
677 : 4 : printf(" Commands:\n");
678 : 4 : printf("\t-4, --enable-4B\n");
679 : 4 : printf("\t\tSwitch the flash and controller to 4-bytes address\n");
680 : 4 : printf("\t\tmode (no confirmation needed).\n\n");
681 : 4 : printf("\t-3, --disable-4B\n");
682 : 4 : printf("\t\tSwitch the flash and controller to 3-bytes address\n");
683 : 4 : printf("\t\tmode (no confirmation needed).\n\n");
684 : 4 : printf("\t-r file, --read=file\n");
685 : 4 : printf("\t\tRead flash content from address into file, use -s\n");
686 : 4 : printf("\t\tto specify the size to read (or it will use the source\n");
687 : 4 : printf("\t\tfile size if used in conjunction with -p and -s is not\n");
688 : 4 : printf("\t\tspecified). When using -r together with -e or -p, the\n");
689 : 4 : printf("\t\tread will be performed first\n\n");
690 : 4 : printf("\t-E, --erase-all\n");
691 : 4 : printf("\t\tErase entire flash chip\n");
692 : 4 : printf("\t\t(Not supported on all chips/controllers)\n\n");
693 : 4 : printf("\t-e, --erase\n");
694 : 4 : printf("\t\tErase the specified region. If size or address are not\n");
695 : 4 : printf("\t\tspecified, but \'--program\' is used, then the file\n");
696 : 4 : printf("\t\tsize will be used (rounded to an erase block) and the\n");
697 : 4 : printf("\t\taddress defaults to 0.\n\n");
698 : 4 : printf("\t-p file, --program=file\n");
699 : 4 : printf("\t\tWill program the file to flash. If the address is not\n");
700 : 4 : printf("\t\tspecified, it will use 0. If the size is not specified\n");
701 : 4 : printf("\t\tit will use the file size. Otherwise it will limit to\n");
702 : 4 : printf("\t\tthe specified size (whatever is smaller). If used in\n");
703 : 4 : printf("\t\tconjunction with any erase command, the erase will\n");
704 : 4 : printf("\t\ttake place first.\n\n");
705 : 4 : printf("\t-t, --tune\n");
706 : 4 : printf("\t\tJust tune the flash controller & access size\n");
707 : 4 : printf("\t\tMust be used in conjuction with --direct\n");
708 : 4 : printf("\t\t(Implicit for all other operations)\n\n");
709 : 4 : printf("\t-c --clear\n");
710 : 4 : printf("\t\tUsed to ECC clear a partition of the flash\n");
711 : 4 : printf("\t\tMust be used in conjunction with -P. Will erase the\n");
712 : 4 : printf("\t\tpartition and then set all the ECC bits as they should be\n\n");
713 : 4 : printf("\t-9 --ecc\n");
714 : 4 : printf("\t\tEncode/Decode ECC where specified in the FFS header.\n");
715 : 4 : printf("\t\tThis 9 byte ECC method is used for some OpenPOWER\n");
716 : 4 : printf("\t\tpartitions.\n");
717 : 4 : printf("\t-i, --info\n");
718 : 4 : printf("\t\tDisplay some information about the flash.\n\n");
719 : 4 : printf("\t--detail\n");
720 : 4 : printf("\t\tDisplays detailed info about a particular partition.\n");
721 : 4 : printf("\t\tAccepts a numeric partition or can be used in conjuction\n");
722 : 4 : printf("\t\twith the -P flag.\n\n");
723 : 4 : printf("\t-h, --help\n");
724 : 4 : printf("\t\tThis message.\n\n");
725 : 4 : }
726 : :
727 : 26 : int main(int argc, char *argv[])
728 : : {
729 : 26 : const char *pname = argv[0];
730 : 26 : struct flash_details flash = { 0 };
731 : 26 : static struct ffs_handle *ffsh = NULL;
732 : 26 : uint32_t ffs_index;
733 : 26 : uint32_t address = 0, read_size = 0, detail_id = UINT_MAX;
734 : 26 : uint32_t write_size = 0, write_size_minus_ecc = 0;
735 : 26 : bool erase = false, do_clear = false;
736 : 26 : bool program = false, erase_all = false, info = false, do_read = false;
737 : 26 : bool enable_4B = false, disable_4B = false;
738 : 26 : bool show_help = false, show_version = false;
739 : 26 : bool no_action = false, tune = false;
740 : 26 : char *write_file = NULL, *read_file = NULL, *part_name = NULL;
741 : 26 : bool ffs_toc_seen = false, direct = false, print_detail = false;
742 : 26 : int flash_side = 0, skip_size = 0;
743 : 26 : int rc = 0;
744 : :
745 : 66 : while(1) {
746 : 92 : struct option long_opts[] = {
747 : : {"address", required_argument, NULL, 'a'},
748 : : {"size", required_argument, NULL, 's'},
749 : : {"partition", required_argument, NULL, 'P'},
750 : : {"bmc", no_argument, NULL, 'b'},
751 : : {"direct", no_argument, NULL, 'D'},
752 : : {"enable-4B", no_argument, NULL, '4'},
753 : : {"disable-4B", no_argument, NULL, '3'},
754 : : {"read", required_argument, NULL, 'r'},
755 : : {"erase-all", no_argument, NULL, 'E'},
756 : : {"erase", no_argument, NULL, 'e'},
757 : : {"program", required_argument, NULL, 'p'},
758 : : {"force", no_argument, NULL, 'f'},
759 : : {"flash-file", required_argument, NULL, 'F'},
760 : : {"info", no_argument, NULL, 'i'},
761 : : {"detail", optional_argument, NULL, 'm'},
762 : : {"tune", no_argument, NULL, 't'},
763 : : {"dummy", no_argument, NULL, 'd'},
764 : : {"help", no_argument, NULL, 'h'},
765 : : {"version", no_argument, NULL, 'v'},
766 : : {"debug", no_argument, NULL, 'g'},
767 : : {"side", required_argument, NULL, 'S'},
768 : : {"skip", required_argument, NULL, 'k'},
769 : : {"toc", required_argument, NULL, 'T'},
770 : : {"clear", no_argument, NULL, 'c'},
771 : : {"ecc", no_argument, NULL, '9'},
772 : : {NULL, 0, NULL, 0 }
773 : : };
774 : 92 : int c, oidx = 0;
775 : :
776 : 92 : c = getopt_long(argc, argv, "+:a:s:P:r:43Eep:fdihvbtgS:T:c9F:",
777 : : long_opts, &oidx);
778 : 92 : if (c == -1)
779 : : break;
780 : 66 : switch(c) {
781 : 4 : char *endptr;
782 : :
783 : 4 : case 'a':
784 : 4 : address = strtoul(optarg, &endptr, 0);
785 : 4 : if (*endptr != '\0') {
786 : 2 : rc = 1;
787 : 2 : no_action = true;
788 : : }
789 : 66 : break;
790 : 4 : case 's':
791 : 4 : read_size = write_size = strtoul(optarg, &endptr, 0);
792 : 4 : if (*endptr != '\0') {
793 : 2 : rc = 1;
794 : 2 : no_action = true;
795 : : }
796 : : break;
797 : 4 : case 'P':
798 : 4 : free(part_name);
799 : 4 : part_name = strdup(optarg);
800 : 4 : break;
801 : : case '4':
802 : : enable_4B = true;
803 : : break;
804 : 0 : case '3':
805 : 0 : disable_4B = true;
806 : 0 : break;
807 : 0 : case 'r':
808 : 0 : if (!optarg)
809 : : break;
810 : 0 : do_read = true;
811 : 0 : free(read_file);
812 : 0 : read_file = strdup(optarg);
813 : 0 : break;
814 : 2 : case 'E':
815 : 2 : erase_all = erase = true;
816 : 2 : break;
817 : 8 : case 'e':
818 : 8 : erase = true;
819 : 8 : break;
820 : 0 : case 'D':
821 : 0 : direct = true;
822 : 0 : break;
823 : 4 : case 'p':
824 : 4 : if (!optarg)
825 : : break;
826 : 4 : program = true;
827 : 4 : free(write_file);
828 : 4 : write_file = strdup(optarg);
829 : 4 : break;
830 : 0 : case 'f':
831 : 0 : must_confirm = false;
832 : 0 : break;
833 : 24 : case 'F':
834 : 24 : flashfilename = optarg;
835 : 24 : break;
836 : 0 : case 'd':
837 : 0 : must_confirm = false;
838 : 0 : dummy_run = true;
839 : 0 : break;
840 : 2 : case 'i':
841 : 2 : info = true;
842 : 2 : break;
843 : 0 : case 'b':
844 : 0 : bmc_flash = true;
845 : 0 : break;
846 : 0 : case 't':
847 : 0 : tune = true;
848 : 0 : break;
849 : 0 : case 'v':
850 : 0 : show_version = true;
851 : 0 : break;
852 : 2 : case 'h':
853 : 2 : show_help = show_version = true;
854 : 2 : break;
855 : 0 : case 'g':
856 : 0 : libflash_debug = true;
857 : 0 : break;
858 : 0 : case 'S':
859 : 0 : flash_side = atoi(optarg);
860 : 0 : break;
861 : 0 : case 'k':
862 : 0 : skip_size = strtoul(optarg, &endptr, 0);
863 : 0 : if (*endptr != '\0') {
864 : 0 : rc = 1;
865 : 0 : no_action = true;
866 : : }
867 : : break;
868 : 0 : case 'T':
869 : 0 : if (!optarg)
870 : : break;
871 : 0 : ffs_toc_seen = true;
872 : 0 : flash.toc = strtoul(optarg, &endptr, 0);
873 : 0 : if (*endptr != '\0') {
874 : 0 : rc = 1;
875 : 0 : no_action = true;
876 : : }
877 : : break;
878 : 0 : case 'c':
879 : 0 : do_clear = true;
880 : 0 : break;
881 : 12 : case 'm':
882 : 12 : print_detail = true;
883 : 12 : if (optarg) {
884 : 12 : detail_id = strtoul(optarg, &endptr, 0);
885 : 12 : if (*endptr != '\0') {
886 : 0 : rc = 1;
887 : 0 : no_action = true;
888 : : }
889 : : }
890 : : break;
891 : 0 : case '9':
892 : 0 : flash.mark_ecc = true;
893 : 0 : break;
894 : 0 : case ':':
895 : 0 : fprintf(stderr, "Unrecognised option \"%s\" to '%c'\n", optarg, optopt);
896 : 0 : no_action = true;
897 : 0 : break;
898 : 0 : case '?':
899 : 0 : fprintf(stderr, "Unrecognised option '%c'\n", optopt);
900 : 0 : no_action = true;
901 : 0 : break;
902 : 0 : default:
903 : 0 : fprintf(stderr , "Encountered unknown error parsing options\n");
904 : 0 : no_action = true;
905 : : }
906 : : }
907 : :
908 : 26 : if (optind < argc) {
909 : : /*
910 : : * It appears not everything passed to pflash was an option, best to
911 : : * not continue
912 : : */
913 : 0 : while (optind < argc)
914 : 0 : fprintf(stderr, "Unrecognised option or argument \"%s\"\n", argv[optind++]);
915 : :
916 : : no_action = true;
917 : : }
918 : :
919 : : /* Check if we need to access the flash at all (which will
920 : : * also tune them as a side effect
921 : : */
922 : 26 : no_action = no_action || (!erase && !program && !info && !do_read &&
923 : 14 : !enable_4B && !disable_4B && !tune && !do_clear && !print_detail);
924 : :
925 : : /* Nothing to do, if we didn't already, print usage */
926 : 26 : if (no_action && !show_version)
927 : : show_help = show_version = true;
928 : :
929 : 24 : if (show_version)
930 : 4 : print_version();
931 : 26 : if (show_help)
932 : 4 : print_help(pname);
933 : :
934 : 26 : if (no_action)
935 : 4 : goto out;
936 : :
937 : : /* --enable-4B and --disable-4B are mutually exclusive */
938 : 22 : if (enable_4B && disable_4B) {
939 : 0 : fprintf(stderr, "--enable-4B and --disable-4B are mutually"
940 : : " exclusive !\n");
941 : 0 : rc = 1;
942 : 0 : goto out;
943 : : }
944 : :
945 : : /* 4B not supported on BMC flash */
946 : 22 : if (enable_4B && bmc_flash) {
947 : 0 : fprintf(stderr, "--enable-4B not supported on BMC flash !\n");
948 : 0 : rc = 1;
949 : 0 : goto out;;
950 : : }
951 : :
952 : : /* partitions not supported on BMC flash */
953 : 22 : if (part_name && bmc_flash) {
954 : 0 : fprintf(stderr, "--partition not supported on BMC flash !\n");
955 : 0 : rc = 1;
956 : 0 : goto out;
957 : : }
958 : :
959 : 22 : if (print_detail && ((detail_id == UINT_MAX && !part_name)
960 : 12 : || (detail_id != UINT_MAX && part_name))) {
961 : 0 : fprintf(stderr, "--detail requires either a partition id or\n");
962 : 0 : fprintf(stderr, "a partition name with -P\n");
963 : : }
964 : :
965 : : /* part-name and erase-all make no sense together */
966 : 22 : if (part_name && erase_all) {
967 : 0 : fprintf(stderr, "--partition and --erase-all are mutually"
968 : : " exclusive !\n");
969 : 0 : rc = 1;
970 : 0 : goto out;
971 : : }
972 : :
973 : : /* Read command should always come with a file */
974 : 22 : if (do_read && !read_file) {
975 : 0 : fprintf(stderr, "Read with no file specified !\n");
976 : 0 : rc = 1;
977 : 0 : goto out;
978 : : }
979 : :
980 : : /* Skip only supported on read */
981 : 22 : if (skip_size && !do_read) {
982 : 0 : fprintf(stderr, "--skip requires a --read command !\n");
983 : 0 : rc = 1;
984 : 0 : goto out;
985 : : }
986 : :
987 : : /* Program command should always come with a file */
988 : 22 : if (program && !write_file) {
989 : 0 : fprintf(stderr, "Program with no file specified !\n");
990 : 0 : rc = 1;
991 : 0 : goto out;
992 : : }
993 : :
994 : : /* If both partition and address specified, error out */
995 : 22 : if (address && part_name) {
996 : 0 : fprintf(stderr, "Specify partition or address, not both !\n");
997 : 0 : rc = 1;
998 : 0 : goto out;
999 : : }
1000 : :
1001 : 22 : if (do_clear && !part_name) {
1002 : 0 : fprintf(stderr, "--clear only supported on a partition name\n");
1003 : 0 : rc = 1;
1004 : 0 : goto out;
1005 : : }
1006 : :
1007 : : /* Explicitly only support two sides */
1008 : 22 : if (flash_side != 0 && flash_side != 1) {
1009 : 0 : fprintf(stderr, "Unexpected value for --side '%d'\n", flash_side);
1010 : 0 : rc = 1;
1011 : 0 : goto out;
1012 : : }
1013 : :
1014 : 22 : if (ffs_toc_seen && flash_side) {
1015 : 0 : fprintf(stderr, "--toc and --side are exclusive");
1016 : 0 : rc = 1;
1017 : 0 : goto out;
1018 : : }
1019 : :
1020 : 22 : if (flashfilename && bmc_flash) {
1021 : 0 : fprintf(stderr, "Filename or bmc flash but not both\n");
1022 : 0 : rc = 1;
1023 : 0 : goto out;
1024 : : }
1025 : :
1026 : 22 : if (flashfilename && direct) {
1027 : 0 : fprintf(stderr, "Filename or direct access but not both\n");
1028 : 0 : rc = 1;
1029 : 0 : goto out;
1030 : : }
1031 : :
1032 : 22 : if (tune && !direct) {
1033 : 0 : fprintf(stderr, "It doesn't make sense to --tune without --direct\n");
1034 : 0 : rc = 1;
1035 : 0 : goto out;
1036 : : }
1037 : :
1038 : 22 : if (direct) {
1039 : : /* If -t is passed, then print a nice message */
1040 : 0 : if (tune)
1041 : 0 : printf("Flash and controller tuned\n");
1042 : :
1043 : 0 : if (arch_flash_access(NULL, bmc_flash ? BMC_DIRECT : PNOR_DIRECT) == ACCESS_INVAL) {
1044 : 0 : fprintf(stderr, "Can't access %s flash directly on this architecture\n",
1045 : 0 : bmc_flash ? "BMC" : "PNOR");
1046 : 0 : rc = 1;
1047 : 0 : goto out;
1048 : : }
1049 : 22 : } else if (!flashfilename) {
1050 : 0 : if (arch_flash_access(NULL, bmc_flash ? BMC_MTD : PNOR_MTD) == ACCESS_INVAL) {
1051 : 0 : fprintf(stderr, "Can't access %s flash through MTD on this system\n",
1052 : 0 : bmc_flash ? "BMC" : "PNOR");
1053 : 0 : rc = 1;
1054 : 0 : goto out;
1055 : : }
1056 : : }
1057 : :
1058 : 22 : if (arch_flash_init(&flash.bl, flashfilename, true)) {
1059 : 0 : fprintf(stderr, "Couldn't initialise architecture flash structures\n");
1060 : 0 : rc = 1;
1061 : 0 : goto out;
1062 : : }
1063 : :
1064 : 22 : rc = blocklevel_get_info(flash.bl, &flash.name,
1065 : : &flash.total_size, &flash.erase_granule);
1066 : 22 : if (rc) {
1067 : 0 : fprintf(stderr, "Error %d getting flash info\n", rc);
1068 : 0 : rc = 1;
1069 : 0 : goto close;
1070 : : }
1071 : :
1072 : : /* If file specified but not size, get size from file */
1073 : 22 : if (write_file && !write_size) {
1074 : 2 : struct stat stbuf;
1075 : :
1076 : 2 : if (stat(write_file, &stbuf)) {
1077 : 0 : perror("Failed to get file size");
1078 : 0 : rc = 1;
1079 : 0 : goto close;
1080 : : }
1081 : 2 : write_size = stbuf.st_size;
1082 : : }
1083 : :
1084 : : /* Only take ECC into account under some conditions later */
1085 : 22 : write_size_minus_ecc = write_size;
1086 : :
1087 : : /* If read specified and no read_size, use flash size */
1088 : 22 : if (do_read && !read_size && !part_name)
1089 : 0 : read_size = flash.total_size;
1090 : :
1091 : : /* We have a partition, adjust read/write size if needed */
1092 : 22 : if (part_name || print_detail) {
1093 : 16 : uint32_t pstart, pmaxsz, pactsize;
1094 : 16 : bool ecc, confirm;
1095 : :
1096 : 16 : if (ffs_toc_seen)
1097 : 0 : ffsh = lookup_partition_at_toc(&flash,
1098 : : part_name, &ffs_index);
1099 : : else
1100 : 16 : ffsh = lookup_partition_at_side(&flash, flash_side,
1101 : : part_name, &ffs_index);
1102 : 16 : if (!ffsh)
1103 : 0 : goto close;
1104 : :
1105 : 16 : if (!part_name)
1106 : 12 : ffs_index = detail_id;
1107 : :
1108 : 16 : rc = ffs_part_info(ffsh, ffs_index, NULL,
1109 : : &pstart, &pmaxsz, &pactsize, &ecc);
1110 : 16 : if (rc) {
1111 : 0 : fprintf(stderr,"Failed to get partition info\n");
1112 : 0 : goto close;
1113 : : }
1114 : :
1115 : 16 : if (!ecc && do_clear) {
1116 : 0 : fprintf(stderr, "The partition on which to do --clear "
1117 : : "does not have ECC, are you sure?\n");
1118 : 0 : confirm = check_confirm();
1119 : 0 : if (!confirm) {
1120 : 0 : rc = 1;
1121 : 0 : goto close;
1122 : : }
1123 : : /* Still confirm later on */
1124 : 0 : must_confirm = true;
1125 : : }
1126 : :
1127 : : /* Read size is obtained from partition "actual" size */
1128 : 16 : if (!read_size)
1129 : 16 : read_size = pactsize;
1130 : : /* If we're decoding ecc and partition is ECC'd, then adjust */
1131 : 16 : if (ecc && flash.mark_ecc)
1132 : 0 : read_size = ecc_buffer_size_minus_ecc(read_size);
1133 : :
1134 : : /* Write size is max size of partition */
1135 : 16 : if (!write_size)
1136 : 14 : write_size = pmaxsz;
1137 : :
1138 : : /* But write size can take into account ECC as well */
1139 : 16 : if (ecc && flash.mark_ecc)
1140 : 0 : write_size_minus_ecc = ecc_buffer_size_minus_ecc(write_size);
1141 : : else
1142 : : write_size_minus_ecc = write_size;
1143 : :
1144 : : /* Crop write size to partition size if --force was passed */
1145 : 16 : if ((write_size_minus_ecc > pmaxsz) && !must_confirm) {
1146 : 0 : printf("WARNING: Size (%d bytes) larger than partition"
1147 : : " (%d bytes), cropping to fit\n",
1148 : : write_size, pmaxsz);
1149 : 0 : write_size = pmaxsz;
1150 : 16 : } else if (write_size_minus_ecc > pmaxsz) {
1151 : 0 : printf("ERROR: Size (%d bytes) larger than partition"
1152 : : " (%d bytes). Use --force to force\n",
1153 : : write_size, pmaxsz);
1154 : 0 : goto close;
1155 : : }
1156 : :
1157 : : /* Set address */
1158 : 16 : address = pstart;
1159 : 6 : } else if (erase) {
1160 : 4 : if ((address | write_size) & (flash.erase_granule - 1)) {
1161 : 0 : if (must_confirm) {
1162 : 0 : printf("ERROR: Erase at 0x%08x for 0x%08x isn't erase block aligned\n",
1163 : : address, write_size);
1164 : 0 : printf("Use --force to force\n");
1165 : 0 : goto close;
1166 : : } else {
1167 : 0 : printf("WARNING: Erase at 0x%08x for 0x%08x isn't erase block aligned\n",
1168 : : address, write_size);
1169 : : }
1170 : : }
1171 : : }
1172 : :
1173 : : /* Process commands */
1174 : :
1175 : : /* Both enable and disable can't be set (we've checked) */
1176 : 22 : if (enable_4B)
1177 : 0 : rc = enable_4B_addresses(flash.bl);
1178 : 22 : if (disable_4B)
1179 : 0 : rc = disable_4B_addresses(flash.bl);
1180 : 22 : if (rc)
1181 : 0 : goto close;
1182 : :
1183 : 22 : if (info) {
1184 : : /*
1185 : : * Don't pass through modfied TOC value if the modification was done
1186 : : * because of --size, but still respect if it came from --toc (we
1187 : : * assume the user knows what they're doing in that case)
1188 : : */
1189 : 2 : print_flash_info(&flash);
1190 : : }
1191 : :
1192 : 22 : if (print_detail)
1193 : 12 : print_partition_detail(ffsh, ffs_index);
1194 : :
1195 : : /* Unlock flash (PNOR only) */
1196 : 22 : if ((erase || program || do_clear) && !bmc_flash && !flashfilename) {
1197 : 0 : flash.need_relock = arch_flash_set_wrprotect(flash.bl, false);
1198 : 0 : if (flash.need_relock == -1) {
1199 : 0 : fprintf(stderr, "Architecture doesn't support write protection on flash\n");
1200 : 0 : flash.need_relock = 0;
1201 : 0 : goto close;
1202 : : }
1203 : : }
1204 : 22 : rc = 0;
1205 : 22 : if (do_read)
1206 : 0 : rc = do_read_file(flash.bl, read_file, address, read_size, skip_size);
1207 : 22 : if (!rc && erase_all)
1208 : 2 : rc = erase_chip(&flash);
1209 : 20 : else if (!rc && erase)
1210 : 6 : rc = erase_range(&flash, address, write_size,
1211 : : program, ffsh, ffs_index);
1212 : 22 : if (!rc && program)
1213 : 4 : rc = program_file(flash.bl, write_file, address, write_size_minus_ecc,
1214 : : ffsh, ffs_index);
1215 : 22 : if (!rc && do_clear)
1216 : 0 : rc = set_ecc(&flash, address, write_size);
1217 : :
1218 : 22 : close:
1219 : 22 : if (flash.need_relock)
1220 : 0 : arch_flash_set_wrprotect(flash.bl, 1);
1221 : 22 : arch_flash_close(flash.bl, flashfilename);
1222 : 22 : if (ffsh)
1223 : 16 : ffs_close(ffsh);
1224 : 6 : out:
1225 : 26 : free(part_name);
1226 : 26 : free(read_file);
1227 : 26 : free(write_file);
1228 : :
1229 : 26 : return rc;
1230 : : }
|