1*8617a60dSAndroid Build Coastguard Worker /* Copyright 2015 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 <err.h>
7*8617a60dSAndroid Build Coastguard Worker #include <errno.h>
8*8617a60dSAndroid Build Coastguard Worker #include <fcntl.h>
9*8617a60dSAndroid Build Coastguard Worker #include <ftw.h>
10*8617a60dSAndroid Build Coastguard Worker #include <inttypes.h>
11*8617a60dSAndroid Build Coastguard Worker #if !defined(__FreeBSD__)
12*8617a60dSAndroid Build Coastguard Worker #include <linux/major.h>
13*8617a60dSAndroid Build Coastguard Worker #endif
14*8617a60dSAndroid Build Coastguard Worker #include <stdbool.h>
15*8617a60dSAndroid Build Coastguard Worker #include <stdarg.h>
16*8617a60dSAndroid Build Coastguard Worker #include <stdlib.h>
17*8617a60dSAndroid Build Coastguard Worker #include <stdint.h>
18*8617a60dSAndroid Build Coastguard Worker #include <stdio.h>
19*8617a60dSAndroid Build Coastguard Worker #include <string.h>
20*8617a60dSAndroid Build Coastguard Worker #include <sys/stat.h>
21*8617a60dSAndroid Build Coastguard Worker #include <sys/types.h>
22*8617a60dSAndroid Build Coastguard Worker #include <sys/wait.h>
23*8617a60dSAndroid Build Coastguard Worker #include <unistd.h>
24*8617a60dSAndroid Build Coastguard Worker
25*8617a60dSAndroid Build Coastguard Worker #include "cgpt.h"
26*8617a60dSAndroid Build Coastguard Worker #include "cgpt_nor.h"
27*8617a60dSAndroid Build Coastguard Worker #include "subprocess.h"
28*8617a60dSAndroid Build Coastguard Worker
29*8617a60dSAndroid Build Coastguard Worker static const char FLASHROM_PATH[] = "/usr/sbin/flashrom";
30*8617a60dSAndroid Build Coastguard Worker
31*8617a60dSAndroid Build Coastguard Worker // Obtain the MTD size from its sysfs node.
GetMtdSize(const char * mtd_device,uint64_t * size)32*8617a60dSAndroid Build Coastguard Worker int GetMtdSize(const char *mtd_device, uint64_t *size) {
33*8617a60dSAndroid Build Coastguard Worker mtd_device = strrchr(mtd_device, '/');
34*8617a60dSAndroid Build Coastguard Worker if (mtd_device == NULL) {
35*8617a60dSAndroid Build Coastguard Worker errno = EINVAL;
36*8617a60dSAndroid Build Coastguard Worker return 1;
37*8617a60dSAndroid Build Coastguard Worker }
38*8617a60dSAndroid Build Coastguard Worker char *sysfs_name;
39*8617a60dSAndroid Build Coastguard Worker if (asprintf(&sysfs_name, "/sys/class/mtd%s/size", mtd_device) == -1) {
40*8617a60dSAndroid Build Coastguard Worker return 1;
41*8617a60dSAndroid Build Coastguard Worker }
42*8617a60dSAndroid Build Coastguard Worker FILE *fp = fopen(sysfs_name, "r");
43*8617a60dSAndroid Build Coastguard Worker free(sysfs_name);
44*8617a60dSAndroid Build Coastguard Worker if (fp == NULL) {
45*8617a60dSAndroid Build Coastguard Worker return 1;
46*8617a60dSAndroid Build Coastguard Worker }
47*8617a60dSAndroid Build Coastguard Worker int ret = (fscanf(fp, "%" PRIu64 "\n", size) != 1);
48*8617a60dSAndroid Build Coastguard Worker fclose(fp);
49*8617a60dSAndroid Build Coastguard Worker return ret;
50*8617a60dSAndroid Build Coastguard Worker }
51*8617a60dSAndroid Build Coastguard Worker
52*8617a60dSAndroid Build Coastguard Worker // TODO(b:184812319): Remove these functions and use subprocess_run everywhere.
ForkExecV(const char * cwd,const char * const argv[])53*8617a60dSAndroid Build Coastguard Worker int ForkExecV(const char *cwd, const char *const argv[]) {
54*8617a60dSAndroid Build Coastguard Worker pid_t pid = fork();
55*8617a60dSAndroid Build Coastguard Worker if (pid == -1) {
56*8617a60dSAndroid Build Coastguard Worker return -1;
57*8617a60dSAndroid Build Coastguard Worker }
58*8617a60dSAndroid Build Coastguard Worker int status = -1;
59*8617a60dSAndroid Build Coastguard Worker if (pid == 0) {
60*8617a60dSAndroid Build Coastguard Worker if (cwd && chdir(cwd) != 0) {
61*8617a60dSAndroid Build Coastguard Worker return -1;
62*8617a60dSAndroid Build Coastguard Worker }
63*8617a60dSAndroid Build Coastguard Worker execv(argv[0], (char *const *)argv);
64*8617a60dSAndroid Build Coastguard Worker // If this is reached, execv fails.
65*8617a60dSAndroid Build Coastguard Worker err(-1, "Cannot exec %s in %s.", argv[0], cwd);
66*8617a60dSAndroid Build Coastguard Worker } else {
67*8617a60dSAndroid Build Coastguard Worker if (waitpid(pid, &status, 0) != -1 && WIFEXITED(status))
68*8617a60dSAndroid Build Coastguard Worker return WEXITSTATUS(status);
69*8617a60dSAndroid Build Coastguard Worker }
70*8617a60dSAndroid Build Coastguard Worker return status;
71*8617a60dSAndroid Build Coastguard Worker }
72*8617a60dSAndroid Build Coastguard Worker
ForkExecL(const char * cwd,const char * cmd,...)73*8617a60dSAndroid Build Coastguard Worker static int ForkExecL(const char *cwd, const char *cmd, ...) {
74*8617a60dSAndroid Build Coastguard Worker int argc;
75*8617a60dSAndroid Build Coastguard Worker va_list ap;
76*8617a60dSAndroid Build Coastguard Worker va_start(ap, cmd);
77*8617a60dSAndroid Build Coastguard Worker for (argc = 1; va_arg(ap, char *) != NULL; ++argc);
78*8617a60dSAndroid Build Coastguard Worker va_end(ap);
79*8617a60dSAndroid Build Coastguard Worker
80*8617a60dSAndroid Build Coastguard Worker va_start(ap, cmd);
81*8617a60dSAndroid Build Coastguard Worker const char **argv = calloc(argc + 1, sizeof(char *));
82*8617a60dSAndroid Build Coastguard Worker if (argv == NULL) {
83*8617a60dSAndroid Build Coastguard Worker errno = ENOMEM;
84*8617a60dSAndroid Build Coastguard Worker va_end(ap);
85*8617a60dSAndroid Build Coastguard Worker return -1;
86*8617a60dSAndroid Build Coastguard Worker }
87*8617a60dSAndroid Build Coastguard Worker argv[0] = cmd;
88*8617a60dSAndroid Build Coastguard Worker int i;
89*8617a60dSAndroid Build Coastguard Worker for (i = 1; i < argc; ++i) {
90*8617a60dSAndroid Build Coastguard Worker argv[i] = va_arg(ap, char *);
91*8617a60dSAndroid Build Coastguard Worker }
92*8617a60dSAndroid Build Coastguard Worker va_end(ap);
93*8617a60dSAndroid Build Coastguard Worker
94*8617a60dSAndroid Build Coastguard Worker int ret = ForkExecV(cwd, argv);
95*8617a60dSAndroid Build Coastguard Worker free(argv);
96*8617a60dSAndroid Build Coastguard Worker return ret;
97*8617a60dSAndroid Build Coastguard Worker }
98*8617a60dSAndroid Build Coastguard Worker
read_write(int source_fd,uint64_t size,const char * src_name,int idx)99*8617a60dSAndroid Build Coastguard Worker static int read_write(int source_fd,
100*8617a60dSAndroid Build Coastguard Worker uint64_t size,
101*8617a60dSAndroid Build Coastguard Worker const char *src_name,
102*8617a60dSAndroid Build Coastguard Worker int idx) {
103*8617a60dSAndroid Build Coastguard Worker int ret = 1;
104*8617a60dSAndroid Build Coastguard Worker const int bufsize = 4096;
105*8617a60dSAndroid Build Coastguard Worker char *buf = malloc(bufsize);
106*8617a60dSAndroid Build Coastguard Worker if (buf == NULL) {
107*8617a60dSAndroid Build Coastguard Worker goto clean_exit;
108*8617a60dSAndroid Build Coastguard Worker }
109*8617a60dSAndroid Build Coastguard Worker
110*8617a60dSAndroid Build Coastguard Worker ret++;
111*8617a60dSAndroid Build Coastguard Worker char *dest;
112*8617a60dSAndroid Build Coastguard Worker if (asprintf(&dest, "%s_%d", src_name, idx) == -1) {
113*8617a60dSAndroid Build Coastguard Worker goto free_buf;
114*8617a60dSAndroid Build Coastguard Worker }
115*8617a60dSAndroid Build Coastguard Worker
116*8617a60dSAndroid Build Coastguard Worker ret++;
117*8617a60dSAndroid Build Coastguard Worker int dest_fd = open(dest, O_WRONLY | O_CLOEXEC | O_CREAT, 0600);
118*8617a60dSAndroid Build Coastguard Worker if (dest_fd < 0) {
119*8617a60dSAndroid Build Coastguard Worker goto free_dest;
120*8617a60dSAndroid Build Coastguard Worker }
121*8617a60dSAndroid Build Coastguard Worker
122*8617a60dSAndroid Build Coastguard Worker ret++;
123*8617a60dSAndroid Build Coastguard Worker uint64_t copied = 0;
124*8617a60dSAndroid Build Coastguard Worker ssize_t nr_read;
125*8617a60dSAndroid Build Coastguard Worker ssize_t nr_write;
126*8617a60dSAndroid Build Coastguard Worker while (copied < size) {
127*8617a60dSAndroid Build Coastguard Worker size_t to_read = size - copied;
128*8617a60dSAndroid Build Coastguard Worker if (to_read > bufsize) {
129*8617a60dSAndroid Build Coastguard Worker to_read = bufsize;
130*8617a60dSAndroid Build Coastguard Worker }
131*8617a60dSAndroid Build Coastguard Worker nr_read = read(source_fd, buf, to_read);
132*8617a60dSAndroid Build Coastguard Worker if (nr_read < 0) {
133*8617a60dSAndroid Build Coastguard Worker goto close_dest_fd;
134*8617a60dSAndroid Build Coastguard Worker }
135*8617a60dSAndroid Build Coastguard Worker nr_write = 0;
136*8617a60dSAndroid Build Coastguard Worker while (nr_write < nr_read) {
137*8617a60dSAndroid Build Coastguard Worker ssize_t s = write(dest_fd, buf + nr_write, nr_read - nr_write);
138*8617a60dSAndroid Build Coastguard Worker if (s < 0) {
139*8617a60dSAndroid Build Coastguard Worker goto close_dest_fd;
140*8617a60dSAndroid Build Coastguard Worker }
141*8617a60dSAndroid Build Coastguard Worker nr_write += s;
142*8617a60dSAndroid Build Coastguard Worker }
143*8617a60dSAndroid Build Coastguard Worker copied += nr_read;
144*8617a60dSAndroid Build Coastguard Worker }
145*8617a60dSAndroid Build Coastguard Worker
146*8617a60dSAndroid Build Coastguard Worker ret = 0;
147*8617a60dSAndroid Build Coastguard Worker
148*8617a60dSAndroid Build Coastguard Worker close_dest_fd:
149*8617a60dSAndroid Build Coastguard Worker close(dest_fd);
150*8617a60dSAndroid Build Coastguard Worker free_dest:
151*8617a60dSAndroid Build Coastguard Worker free(dest);
152*8617a60dSAndroid Build Coastguard Worker free_buf:
153*8617a60dSAndroid Build Coastguard Worker free(buf);
154*8617a60dSAndroid Build Coastguard Worker clean_exit:
155*8617a60dSAndroid Build Coastguard Worker return ret;
156*8617a60dSAndroid Build Coastguard Worker }
157*8617a60dSAndroid Build Coastguard Worker
split_gpt(const char * dir_name,const char * file_name)158*8617a60dSAndroid Build Coastguard Worker static int split_gpt(const char *dir_name, const char *file_name) {
159*8617a60dSAndroid Build Coastguard Worker int ret = 1;
160*8617a60dSAndroid Build Coastguard Worker char *source;
161*8617a60dSAndroid Build Coastguard Worker if (asprintf(&source, "%s/%s", dir_name, file_name) == -1) {
162*8617a60dSAndroid Build Coastguard Worker goto clean_exit;
163*8617a60dSAndroid Build Coastguard Worker }
164*8617a60dSAndroid Build Coastguard Worker
165*8617a60dSAndroid Build Coastguard Worker ret++;
166*8617a60dSAndroid Build Coastguard Worker int fd = open(source, O_RDONLY | O_CLOEXEC);
167*8617a60dSAndroid Build Coastguard Worker if (fd < 0) {
168*8617a60dSAndroid Build Coastguard Worker goto free_source;
169*8617a60dSAndroid Build Coastguard Worker }
170*8617a60dSAndroid Build Coastguard Worker
171*8617a60dSAndroid Build Coastguard Worker ret++;
172*8617a60dSAndroid Build Coastguard Worker struct stat stat;
173*8617a60dSAndroid Build Coastguard Worker if (fstat(fd, &stat) != 0 || (stat.st_size & 1) != 0) {
174*8617a60dSAndroid Build Coastguard Worker goto close_fd;
175*8617a60dSAndroid Build Coastguard Worker }
176*8617a60dSAndroid Build Coastguard Worker uint64_t half_size = stat.st_size / 2;
177*8617a60dSAndroid Build Coastguard Worker
178*8617a60dSAndroid Build Coastguard Worker ret++;
179*8617a60dSAndroid Build Coastguard Worker if (read_write(fd, half_size, source, 1) != 0 ||
180*8617a60dSAndroid Build Coastguard Worker read_write(fd, half_size, source, 2) != 0) {
181*8617a60dSAndroid Build Coastguard Worker goto close_fd;
182*8617a60dSAndroid Build Coastguard Worker }
183*8617a60dSAndroid Build Coastguard Worker
184*8617a60dSAndroid Build Coastguard Worker ret = 0;
185*8617a60dSAndroid Build Coastguard Worker close_fd:
186*8617a60dSAndroid Build Coastguard Worker close(fd);
187*8617a60dSAndroid Build Coastguard Worker free_source:
188*8617a60dSAndroid Build Coastguard Worker free(source);
189*8617a60dSAndroid Build Coastguard Worker clean_exit:
190*8617a60dSAndroid Build Coastguard Worker return ret;
191*8617a60dSAndroid Build Coastguard Worker }
192*8617a60dSAndroid Build Coastguard Worker
remove_file_or_dir(const char * fpath,const struct stat * sb,int typeflag,struct FTW * ftwbuf)193*8617a60dSAndroid Build Coastguard Worker static int remove_file_or_dir(const char *fpath, const struct stat *sb,
194*8617a60dSAndroid Build Coastguard Worker int typeflag, struct FTW *ftwbuf) {
195*8617a60dSAndroid Build Coastguard Worker return remove(fpath);
196*8617a60dSAndroid Build Coastguard Worker }
197*8617a60dSAndroid Build Coastguard Worker
RemoveDir(const char * dir)198*8617a60dSAndroid Build Coastguard Worker int RemoveDir(const char *dir) {
199*8617a60dSAndroid Build Coastguard Worker return nftw(dir, remove_file_or_dir, 20, FTW_DEPTH | FTW_PHYS);
200*8617a60dSAndroid Build Coastguard Worker }
201*8617a60dSAndroid Build Coastguard Worker
202*8617a60dSAndroid Build Coastguard Worker #define FLASHROM_RW_GPT_PRI "RW_GPT_PRIMARY:rw_gpt_1",
203*8617a60dSAndroid Build Coastguard Worker #define FLASHROM_RW_GPT_SEC "RW_GPT_SECONDARY:rw_gpt_2"
204*8617a60dSAndroid Build Coastguard Worker #define FLASHROM_RW_GPT "RW_GPT:rw_gpt"
205*8617a60dSAndroid Build Coastguard Worker
206*8617a60dSAndroid Build Coastguard Worker // Read RW_GPT from NOR flash to "rw_gpt" in a dir.
207*8617a60dSAndroid Build Coastguard Worker // TODO(b:184812319): Replace this function with flashrom_read.
ReadNorFlash(const char * dir)208*8617a60dSAndroid Build Coastguard Worker int ReadNorFlash(const char *dir) {
209*8617a60dSAndroid Build Coastguard Worker int ret = 0;
210*8617a60dSAndroid Build Coastguard Worker
211*8617a60dSAndroid Build Coastguard Worker // Read RW_GPT section from NOR flash to "rw_gpt".
212*8617a60dSAndroid Build Coastguard Worker ret++;
213*8617a60dSAndroid Build Coastguard Worker
214*8617a60dSAndroid Build Coastguard Worker char *cwd = getcwd(NULL, 0);
215*8617a60dSAndroid Build Coastguard Worker if (!cwd) {
216*8617a60dSAndroid Build Coastguard Worker Error("Cannot get current directory.\n");
217*8617a60dSAndroid Build Coastguard Worker return ret;
218*8617a60dSAndroid Build Coastguard Worker }
219*8617a60dSAndroid Build Coastguard Worker if (chdir(dir) < 0) {
220*8617a60dSAndroid Build Coastguard Worker Error("Cannot change directory.\n");
221*8617a60dSAndroid Build Coastguard Worker goto out_free;
222*8617a60dSAndroid Build Coastguard Worker }
223*8617a60dSAndroid Build Coastguard Worker const char *const argv[] = {FLASHROM_PATH, "-i", FLASHROM_RW_GPT, "-r"};
224*8617a60dSAndroid Build Coastguard Worker // Redirect stdout to /dev/null so that flashrom does not muck up cgpt's
225*8617a60dSAndroid Build Coastguard Worker // output.
226*8617a60dSAndroid Build Coastguard Worker if (subprocess_run(argv, &subprocess_null, &subprocess_null, NULL) != 0) {
227*8617a60dSAndroid Build Coastguard Worker Error("Cannot exec flashrom to read from RW_GPT section.\n");
228*8617a60dSAndroid Build Coastguard Worker } else {
229*8617a60dSAndroid Build Coastguard Worker ret = 0;
230*8617a60dSAndroid Build Coastguard Worker }
231*8617a60dSAndroid Build Coastguard Worker if (chdir(cwd) < 0) {
232*8617a60dSAndroid Build Coastguard Worker Error("Cannot change directory back to original.\n");
233*8617a60dSAndroid Build Coastguard Worker goto out_free;
234*8617a60dSAndroid Build Coastguard Worker }
235*8617a60dSAndroid Build Coastguard Worker
236*8617a60dSAndroid Build Coastguard Worker out_free:
237*8617a60dSAndroid Build Coastguard Worker free(cwd);
238*8617a60dSAndroid Build Coastguard Worker return ret;
239*8617a60dSAndroid Build Coastguard Worker }
240*8617a60dSAndroid Build Coastguard Worker
FlashromWriteRegion(const char * region)241*8617a60dSAndroid Build Coastguard Worker static int FlashromWriteRegion(const char *region)
242*8617a60dSAndroid Build Coastguard Worker {
243*8617a60dSAndroid Build Coastguard Worker const char *const argv[] = {FLASHROM_PATH, "-i", region, "-w", "--noverify-all"};
244*8617a60dSAndroid Build Coastguard Worker // Redirect stdout to /dev/null so that flashrom does not muck up cgpt's
245*8617a60dSAndroid Build Coastguard Worker // output.
246*8617a60dSAndroid Build Coastguard Worker if (subprocess_run(argv, &subprocess_null, &subprocess_null, NULL) != 0) {
247*8617a60dSAndroid Build Coastguard Worker Warning("Cannot write '%s' back with flashrom.\n", region);
248*8617a60dSAndroid Build Coastguard Worker return 1;
249*8617a60dSAndroid Build Coastguard Worker }
250*8617a60dSAndroid Build Coastguard Worker return 0;
251*8617a60dSAndroid Build Coastguard Worker }
252*8617a60dSAndroid Build Coastguard Worker
253*8617a60dSAndroid Build Coastguard Worker // Write "rw_gpt" back to NOR flash. We write the file in two parts for safety.
254*8617a60dSAndroid Build Coastguard Worker // TODO(b:184812319): Replace this function with flashrom_write.
WriteNorFlash(const char * dir)255*8617a60dSAndroid Build Coastguard Worker int WriteNorFlash(const char *dir) {
256*8617a60dSAndroid Build Coastguard Worker int ret = 0;
257*8617a60dSAndroid Build Coastguard Worker
258*8617a60dSAndroid Build Coastguard Worker ret++;
259*8617a60dSAndroid Build Coastguard Worker if (split_gpt(dir, "rw_gpt") != 0) {
260*8617a60dSAndroid Build Coastguard Worker Error("Cannot split rw_gpt in two.\n");
261*8617a60dSAndroid Build Coastguard Worker return ret;
262*8617a60dSAndroid Build Coastguard Worker }
263*8617a60dSAndroid Build Coastguard Worker ret++;
264*8617a60dSAndroid Build Coastguard Worker int nr_fails = 0;
265*8617a60dSAndroid Build Coastguard Worker
266*8617a60dSAndroid Build Coastguard Worker char *cwd = getcwd(NULL, 0);
267*8617a60dSAndroid Build Coastguard Worker if (!cwd) {
268*8617a60dSAndroid Build Coastguard Worker Error("Cannot get current directory.\n");
269*8617a60dSAndroid Build Coastguard Worker return ret;
270*8617a60dSAndroid Build Coastguard Worker }
271*8617a60dSAndroid Build Coastguard Worker if (chdir(dir) < 0) {
272*8617a60dSAndroid Build Coastguard Worker Error("Cannot change directory.\n");
273*8617a60dSAndroid Build Coastguard Worker goto out_free;
274*8617a60dSAndroid Build Coastguard Worker }
275*8617a60dSAndroid Build Coastguard Worker if (FlashromWriteRegion(FLASHROM_RW_GPT_PRI))
276*8617a60dSAndroid Build Coastguard Worker nr_fails++;
277*8617a60dSAndroid Build Coastguard Worker if (FlashromWriteRegion(FLASHROM_RW_GPT_SEC))
278*8617a60dSAndroid Build Coastguard Worker nr_fails++;
279*8617a60dSAndroid Build Coastguard Worker
280*8617a60dSAndroid Build Coastguard Worker if (chdir(cwd) < 0) {
281*8617a60dSAndroid Build Coastguard Worker Error("Cannot change directory back to original.\n");
282*8617a60dSAndroid Build Coastguard Worker goto out_free;
283*8617a60dSAndroid Build Coastguard Worker }
284*8617a60dSAndroid Build Coastguard Worker switch (nr_fails) {
285*8617a60dSAndroid Build Coastguard Worker case 0: ret = 0; break;
286*8617a60dSAndroid Build Coastguard Worker case 1: Warning("It might still be okay.\n"); break;
287*8617a60dSAndroid Build Coastguard Worker case 2: Error("Cannot write both parts back with flashrom.\n"); break;
288*8617a60dSAndroid Build Coastguard Worker }
289*8617a60dSAndroid Build Coastguard Worker
290*8617a60dSAndroid Build Coastguard Worker out_free:
291*8617a60dSAndroid Build Coastguard Worker free(cwd);
292*8617a60dSAndroid Build Coastguard Worker return ret;
293*8617a60dSAndroid Build Coastguard Worker }
294