1*8617a60dSAndroid Build Coastguard Worker /* Copyright 2014 The ChromiumOS Authors
2*8617a60dSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
3*8617a60dSAndroid Build Coastguard Worker * found in the LICENSE file.
4*8617a60dSAndroid Build Coastguard Worker */
5*8617a60dSAndroid Build Coastguard Worker
6*8617a60dSAndroid Build Coastguard Worker #include <errno.h>
7*8617a60dSAndroid Build Coastguard Worker #include <fcntl.h>
8*8617a60dSAndroid Build Coastguard Worker #include <getopt.h>
9*8617a60dSAndroid Build Coastguard Worker #include <inttypes.h>
10*8617a60dSAndroid Build Coastguard Worker #include <limits.h>
11*8617a60dSAndroid Build Coastguard Worker #include <stddef.h>
12*8617a60dSAndroid Build Coastguard Worker #include <stdint.h>
13*8617a60dSAndroid Build Coastguard Worker #include <stdio.h>
14*8617a60dSAndroid Build Coastguard Worker #include <stdlib.h>
15*8617a60dSAndroid Build Coastguard Worker #include <string.h>
16*8617a60dSAndroid Build Coastguard Worker #include <sys/stat.h>
17*8617a60dSAndroid Build Coastguard Worker #include <sys/types.h>
18*8617a60dSAndroid Build Coastguard Worker #include <unistd.h>
19*8617a60dSAndroid Build Coastguard Worker
20*8617a60dSAndroid Build Coastguard Worker #include "fmap.h"
21*8617a60dSAndroid Build Coastguard Worker #include "futility.h"
22*8617a60dSAndroid Build Coastguard Worker
23*8617a60dSAndroid Build Coastguard Worker static const char usage[] = "\n"
24*8617a60dSAndroid Build Coastguard Worker "Usage: " MYNAME " %s [OPTIONS] FILE AREA:file [AREA:file ...]\n"
25*8617a60dSAndroid Build Coastguard Worker "\n"
26*8617a60dSAndroid Build Coastguard Worker "Replace the contents of specific FMAP areas. This is the complement\n"
27*8617a60dSAndroid Build Coastguard Worker "of " MYNAME " dump_fmap -x FILE AREA [AREA ...]\n"
28*8617a60dSAndroid Build Coastguard Worker "\n"
29*8617a60dSAndroid Build Coastguard Worker "Options:\n"
30*8617a60dSAndroid Build Coastguard Worker " -o OUTFILE Write the result to this file, instead of modifying\n"
31*8617a60dSAndroid Build Coastguard Worker " the input file. This is safer, since there are no\n"
32*8617a60dSAndroid Build Coastguard Worker " safeguards against doing something stupid.\n"
33*8617a60dSAndroid Build Coastguard Worker "\n"
34*8617a60dSAndroid Build Coastguard Worker "Example:\n"
35*8617a60dSAndroid Build Coastguard Worker "\n"
36*8617a60dSAndroid Build Coastguard Worker " This will clear the RO_VPD area, and scramble VBLOCK_B:\n"
37*8617a60dSAndroid Build Coastguard Worker "\n"
38*8617a60dSAndroid Build Coastguard Worker " " MYNAME " %s image.bin RO_VPD:/dev/zero VBLOCK_B:/dev/urandom\n"
39*8617a60dSAndroid Build Coastguard Worker "\n";
40*8617a60dSAndroid Build Coastguard Worker
print_help(int argc,char * argv[])41*8617a60dSAndroid Build Coastguard Worker static void print_help(int argc, char *argv[])
42*8617a60dSAndroid Build Coastguard Worker {
43*8617a60dSAndroid Build Coastguard Worker printf(usage, argv[0], argv[0]);
44*8617a60dSAndroid Build Coastguard Worker }
45*8617a60dSAndroid Build Coastguard Worker
46*8617a60dSAndroid Build Coastguard Worker enum {
47*8617a60dSAndroid Build Coastguard Worker OPT_HELP = 1000,
48*8617a60dSAndroid Build Coastguard Worker };
49*8617a60dSAndroid Build Coastguard Worker static const struct option long_opts[] = {
50*8617a60dSAndroid Build Coastguard Worker /* name hasarg *flag val */
51*8617a60dSAndroid Build Coastguard Worker {"help", 0, NULL, OPT_HELP},
52*8617a60dSAndroid Build Coastguard Worker {NULL, 0, NULL, 0},
53*8617a60dSAndroid Build Coastguard Worker };
54*8617a60dSAndroid Build Coastguard Worker static const char *short_opts = ":o:";
55*8617a60dSAndroid Build Coastguard Worker
56*8617a60dSAndroid Build Coastguard Worker
copy_to_area(const char * file,uint8_t * buf,const uint32_t len,const char * area)57*8617a60dSAndroid Build Coastguard Worker static int copy_to_area(const char *file, uint8_t *buf,
58*8617a60dSAndroid Build Coastguard Worker const uint32_t len, const char *area)
59*8617a60dSAndroid Build Coastguard Worker {
60*8617a60dSAndroid Build Coastguard Worker int retval = 0;
61*8617a60dSAndroid Build Coastguard Worker
62*8617a60dSAndroid Build Coastguard Worker FILE *fp = fopen(file, "r");
63*8617a60dSAndroid Build Coastguard Worker if (!fp) {
64*8617a60dSAndroid Build Coastguard Worker ERROR("area %s: can't open %s for reading: %s\n",
65*8617a60dSAndroid Build Coastguard Worker area, file, strerror(errno));
66*8617a60dSAndroid Build Coastguard Worker return 1;
67*8617a60dSAndroid Build Coastguard Worker }
68*8617a60dSAndroid Build Coastguard Worker
69*8617a60dSAndroid Build Coastguard Worker size_t n = fread(buf, 1, len, fp);
70*8617a60dSAndroid Build Coastguard Worker if (!n) {
71*8617a60dSAndroid Build Coastguard Worker if (feof(fp))
72*8617a60dSAndroid Build Coastguard Worker ERROR("area %s: unexpected EOF on %s\n", area, file);
73*8617a60dSAndroid Build Coastguard Worker if (ferror(fp))
74*8617a60dSAndroid Build Coastguard Worker ERROR("area %s: can't read from %s: %s\n",
75*8617a60dSAndroid Build Coastguard Worker area, file, strerror(errno));
76*8617a60dSAndroid Build Coastguard Worker retval = 1;
77*8617a60dSAndroid Build Coastguard Worker } else if (n < len) {
78*8617a60dSAndroid Build Coastguard Worker WARN("area %s: %s size (%zu) smaller than area size %u; "
79*8617a60dSAndroid Build Coastguard Worker "erasing remaining data to 0xff\n",
80*8617a60dSAndroid Build Coastguard Worker area, file, n, len);
81*8617a60dSAndroid Build Coastguard Worker memset(buf + n, 0xff, len - n);
82*8617a60dSAndroid Build Coastguard Worker }
83*8617a60dSAndroid Build Coastguard Worker
84*8617a60dSAndroid Build Coastguard Worker if (fclose(fp)) {
85*8617a60dSAndroid Build Coastguard Worker ERROR("area %s: error closing %s: %s\n",
86*8617a60dSAndroid Build Coastguard Worker area, file, strerror(errno));
87*8617a60dSAndroid Build Coastguard Worker retval = 1;
88*8617a60dSAndroid Build Coastguard Worker }
89*8617a60dSAndroid Build Coastguard Worker
90*8617a60dSAndroid Build Coastguard Worker return retval;
91*8617a60dSAndroid Build Coastguard Worker }
92*8617a60dSAndroid Build Coastguard Worker
93*8617a60dSAndroid Build Coastguard Worker
do_load_fmap(int argc,char * argv[])94*8617a60dSAndroid Build Coastguard Worker static int do_load_fmap(int argc, char *argv[])
95*8617a60dSAndroid Build Coastguard Worker {
96*8617a60dSAndroid Build Coastguard Worker char *outfile = NULL;
97*8617a60dSAndroid Build Coastguard Worker int errorcnt = 0;
98*8617a60dSAndroid Build Coastguard Worker int i;
99*8617a60dSAndroid Build Coastguard Worker
100*8617a60dSAndroid Build Coastguard Worker opterr = 0; /* quiet, you */
101*8617a60dSAndroid Build Coastguard Worker while ((i = getopt_long(argc, argv, short_opts, long_opts, 0)) != -1) {
102*8617a60dSAndroid Build Coastguard Worker switch (i) {
103*8617a60dSAndroid Build Coastguard Worker case 'o':
104*8617a60dSAndroid Build Coastguard Worker outfile = optarg;
105*8617a60dSAndroid Build Coastguard Worker break;
106*8617a60dSAndroid Build Coastguard Worker case OPT_HELP:
107*8617a60dSAndroid Build Coastguard Worker print_help(argc, argv);
108*8617a60dSAndroid Build Coastguard Worker return !!errorcnt;
109*8617a60dSAndroid Build Coastguard Worker case '?':
110*8617a60dSAndroid Build Coastguard Worker if (optopt)
111*8617a60dSAndroid Build Coastguard Worker ERROR("Unrecognized option: -%c\n",
112*8617a60dSAndroid Build Coastguard Worker optopt);
113*8617a60dSAndroid Build Coastguard Worker else
114*8617a60dSAndroid Build Coastguard Worker ERROR("Unrecognized option\n");
115*8617a60dSAndroid Build Coastguard Worker errorcnt++;
116*8617a60dSAndroid Build Coastguard Worker break;
117*8617a60dSAndroid Build Coastguard Worker case ':':
118*8617a60dSAndroid Build Coastguard Worker ERROR("Missing argument to -%c\n", optopt);
119*8617a60dSAndroid Build Coastguard Worker errorcnt++;
120*8617a60dSAndroid Build Coastguard Worker break;
121*8617a60dSAndroid Build Coastguard Worker default:
122*8617a60dSAndroid Build Coastguard Worker FATAL("Unrecognized getopt output: %d\n", i);
123*8617a60dSAndroid Build Coastguard Worker }
124*8617a60dSAndroid Build Coastguard Worker }
125*8617a60dSAndroid Build Coastguard Worker
126*8617a60dSAndroid Build Coastguard Worker if (errorcnt) {
127*8617a60dSAndroid Build Coastguard Worker print_help(argc, argv);
128*8617a60dSAndroid Build Coastguard Worker return 1;
129*8617a60dSAndroid Build Coastguard Worker }
130*8617a60dSAndroid Build Coastguard Worker
131*8617a60dSAndroid Build Coastguard Worker if (argc - optind < 2) {
132*8617a60dSAndroid Build Coastguard Worker ERROR("You must specify an input file"
133*8617a60dSAndroid Build Coastguard Worker " and at least one AREA:file argument\n");
134*8617a60dSAndroid Build Coastguard Worker print_help(argc, argv);
135*8617a60dSAndroid Build Coastguard Worker return 1;
136*8617a60dSAndroid Build Coastguard Worker }
137*8617a60dSAndroid Build Coastguard Worker
138*8617a60dSAndroid Build Coastguard Worker const char *infile = argv[optind++];
139*8617a60dSAndroid Build Coastguard Worker
140*8617a60dSAndroid Build Coastguard Worker /* okay, let's do it ... */
141*8617a60dSAndroid Build Coastguard Worker if (!outfile)
142*8617a60dSAndroid Build Coastguard Worker outfile = (char *)infile;
143*8617a60dSAndroid Build Coastguard Worker else
144*8617a60dSAndroid Build Coastguard Worker if (futil_copy_file(infile, outfile) < 0)
145*8617a60dSAndroid Build Coastguard Worker exit(1);
146*8617a60dSAndroid Build Coastguard Worker
147*8617a60dSAndroid Build Coastguard Worker int fd;
148*8617a60dSAndroid Build Coastguard Worker uint8_t *buf;
149*8617a60dSAndroid Build Coastguard Worker uint32_t len;
150*8617a60dSAndroid Build Coastguard Worker errorcnt |= futil_open_and_map_file(outfile, &fd, FILE_RW, &buf, &len);
151*8617a60dSAndroid Build Coastguard Worker if (errorcnt)
152*8617a60dSAndroid Build Coastguard Worker goto done;
153*8617a60dSAndroid Build Coastguard Worker
154*8617a60dSAndroid Build Coastguard Worker FmapHeader *fmap = fmap_find(buf, len);
155*8617a60dSAndroid Build Coastguard Worker if (!fmap) {
156*8617a60dSAndroid Build Coastguard Worker ERROR("Can't find an FMAP in %s\n", infile);
157*8617a60dSAndroid Build Coastguard Worker errorcnt++;
158*8617a60dSAndroid Build Coastguard Worker goto done;
159*8617a60dSAndroid Build Coastguard Worker }
160*8617a60dSAndroid Build Coastguard Worker
161*8617a60dSAndroid Build Coastguard Worker for (i = optind; i < argc; i++) {
162*8617a60dSAndroid Build Coastguard Worker char *a = argv[i];
163*8617a60dSAndroid Build Coastguard Worker char *f = strchr(a, ':');
164*8617a60dSAndroid Build Coastguard Worker
165*8617a60dSAndroid Build Coastguard Worker if (!f || a == f || *(f+1) == '\0') {
166*8617a60dSAndroid Build Coastguard Worker ERROR("argument \"%s\" is bogus\n", a);
167*8617a60dSAndroid Build Coastguard Worker errorcnt++;
168*8617a60dSAndroid Build Coastguard Worker break;
169*8617a60dSAndroid Build Coastguard Worker }
170*8617a60dSAndroid Build Coastguard Worker *f++ = '\0';
171*8617a60dSAndroid Build Coastguard Worker
172*8617a60dSAndroid Build Coastguard Worker FmapAreaHeader *ah;
173*8617a60dSAndroid Build Coastguard Worker uint8_t *area_buf = fmap_find_by_name(buf, len, fmap, a, &ah);
174*8617a60dSAndroid Build Coastguard Worker if (!area_buf) {
175*8617a60dSAndroid Build Coastguard Worker ERROR("Can't find area \"%s\" in FMAP\n", a);
176*8617a60dSAndroid Build Coastguard Worker errorcnt++;
177*8617a60dSAndroid Build Coastguard Worker break;
178*8617a60dSAndroid Build Coastguard Worker }
179*8617a60dSAndroid Build Coastguard Worker
180*8617a60dSAndroid Build Coastguard Worker if (copy_to_area(f, area_buf, ah->area_size, a)) {
181*8617a60dSAndroid Build Coastguard Worker errorcnt++;
182*8617a60dSAndroid Build Coastguard Worker break;
183*8617a60dSAndroid Build Coastguard Worker }
184*8617a60dSAndroid Build Coastguard Worker }
185*8617a60dSAndroid Build Coastguard Worker
186*8617a60dSAndroid Build Coastguard Worker done:
187*8617a60dSAndroid Build Coastguard Worker errorcnt |= futil_unmap_and_close_file(fd, FILE_RW, buf, len);
188*8617a60dSAndroid Build Coastguard Worker return !!errorcnt;
189*8617a60dSAndroid Build Coastguard Worker }
190*8617a60dSAndroid Build Coastguard Worker
191*8617a60dSAndroid Build Coastguard Worker DECLARE_FUTIL_COMMAND(load_fmap, do_load_fmap, VBOOT_VERSION_ALL,
192*8617a60dSAndroid Build Coastguard Worker "Replace the contents of specified FMAP areas");
193