1*8617a60dSAndroid Build Coastguard Worker /* Copyright 2020 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 /* For strdup */
7*8617a60dSAndroid Build Coastguard Worker #define _POSIX_C_SOURCE 200809L
8*8617a60dSAndroid Build Coastguard Worker
9*8617a60dSAndroid Build Coastguard Worker #include <fcntl.h>
10*8617a60dSAndroid Build Coastguard Worker #include <limits.h>
11*8617a60dSAndroid Build Coastguard Worker #include <stdbool.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 "2api.h"
21*8617a60dSAndroid Build Coastguard Worker #include "2return_codes.h"
22*8617a60dSAndroid Build Coastguard Worker #include "host_misc.h"
23*8617a60dSAndroid Build Coastguard Worker #include "flashrom.h"
24*8617a60dSAndroid Build Coastguard Worker #include "subprocess.h"
25*8617a60dSAndroid Build Coastguard Worker
26*8617a60dSAndroid Build Coastguard Worker #define FLASHROM_EXEC_NAME "flashrom"
27*8617a60dSAndroid Build Coastguard Worker
28*8617a60dSAndroid Build Coastguard Worker /**
29*8617a60dSAndroid Build Coastguard Worker * Helper to create a temporary file, and optionally write some data
30*8617a60dSAndroid Build Coastguard Worker * into it.
31*8617a60dSAndroid Build Coastguard Worker *
32*8617a60dSAndroid Build Coastguard Worker * @param data If data needs to be written to the file, a
33*8617a60dSAndroid Build Coastguard Worker * pointer to the buffer. Pass NULL to just
34*8617a60dSAndroid Build Coastguard Worker * create an empty temporary file.
35*8617a60dSAndroid Build Coastguard Worker * @param data_size The size of the buffer to write, if applicable.
36*8617a60dSAndroid Build Coastguard Worker * @param path_out An output pointer for the filename. Caller
37*8617a60dSAndroid Build Coastguard Worker * should free.
38*8617a60dSAndroid Build Coastguard Worker *
39*8617a60dSAndroid Build Coastguard Worker * @return VB2_SUCCESS on success, or a relevant error.
40*8617a60dSAndroid Build Coastguard Worker */
write_temp_file(const uint8_t * data,uint32_t data_size,char ** path_out)41*8617a60dSAndroid Build Coastguard Worker static vb2_error_t write_temp_file(const uint8_t *data, uint32_t data_size,
42*8617a60dSAndroid Build Coastguard Worker char **path_out)
43*8617a60dSAndroid Build Coastguard Worker {
44*8617a60dSAndroid Build Coastguard Worker int fd;
45*8617a60dSAndroid Build Coastguard Worker ssize_t write_rv;
46*8617a60dSAndroid Build Coastguard Worker vb2_error_t rv;
47*8617a60dSAndroid Build Coastguard Worker char *path;
48*8617a60dSAndroid Build Coastguard Worker mode_t umask_save;
49*8617a60dSAndroid Build Coastguard Worker
50*8617a60dSAndroid Build Coastguard Worker *path_out = NULL;
51*8617a60dSAndroid Build Coastguard Worker
52*8617a60dSAndroid Build Coastguard Worker path = strdup(VBOOT_TMP_DIR "/vb2_flashrom.XXXXXX");
53*8617a60dSAndroid Build Coastguard Worker
54*8617a60dSAndroid Build Coastguard Worker /* Set the umask before mkstemp for security considerations. */
55*8617a60dSAndroid Build Coastguard Worker umask_save = umask(077);
56*8617a60dSAndroid Build Coastguard Worker fd = mkstemp(path);
57*8617a60dSAndroid Build Coastguard Worker umask(umask_save);
58*8617a60dSAndroid Build Coastguard Worker if (fd < 0) {
59*8617a60dSAndroid Build Coastguard Worker rv = VB2_ERROR_WRITE_FILE_OPEN;
60*8617a60dSAndroid Build Coastguard Worker goto fail;
61*8617a60dSAndroid Build Coastguard Worker }
62*8617a60dSAndroid Build Coastguard Worker
63*8617a60dSAndroid Build Coastguard Worker while (data && data_size > 0) {
64*8617a60dSAndroid Build Coastguard Worker write_rv = write(fd, data, data_size);
65*8617a60dSAndroid Build Coastguard Worker if (write_rv < 0) {
66*8617a60dSAndroid Build Coastguard Worker close(fd);
67*8617a60dSAndroid Build Coastguard Worker unlink(path);
68*8617a60dSAndroid Build Coastguard Worker rv = VB2_ERROR_WRITE_FILE_DATA;
69*8617a60dSAndroid Build Coastguard Worker goto fail;
70*8617a60dSAndroid Build Coastguard Worker }
71*8617a60dSAndroid Build Coastguard Worker
72*8617a60dSAndroid Build Coastguard Worker data_size -= write_rv;
73*8617a60dSAndroid Build Coastguard Worker data += write_rv;
74*8617a60dSAndroid Build Coastguard Worker }
75*8617a60dSAndroid Build Coastguard Worker
76*8617a60dSAndroid Build Coastguard Worker close(fd);
77*8617a60dSAndroid Build Coastguard Worker *path_out = path;
78*8617a60dSAndroid Build Coastguard Worker return VB2_SUCCESS;
79*8617a60dSAndroid Build Coastguard Worker
80*8617a60dSAndroid Build Coastguard Worker fail:
81*8617a60dSAndroid Build Coastguard Worker free(path);
82*8617a60dSAndroid Build Coastguard Worker return rv;
83*8617a60dSAndroid Build Coastguard Worker }
84*8617a60dSAndroid Build Coastguard Worker
run_flashrom(const char * const argv[])85*8617a60dSAndroid Build Coastguard Worker static vb2_error_t run_flashrom(const char *const argv[])
86*8617a60dSAndroid Build Coastguard Worker {
87*8617a60dSAndroid Build Coastguard Worker int status = subprocess_run(argv, &subprocess_null, &subprocess_null,
88*8617a60dSAndroid Build Coastguard Worker &subprocess_null);
89*8617a60dSAndroid Build Coastguard Worker if (status) {
90*8617a60dSAndroid Build Coastguard Worker fprintf(stderr, "Flashrom invocation failed (exit status %d):",
91*8617a60dSAndroid Build Coastguard Worker status);
92*8617a60dSAndroid Build Coastguard Worker
93*8617a60dSAndroid Build Coastguard Worker for (const char *const *argp = argv; *argp; argp++)
94*8617a60dSAndroid Build Coastguard Worker fprintf(stderr, " %s", *argp);
95*8617a60dSAndroid Build Coastguard Worker
96*8617a60dSAndroid Build Coastguard Worker fprintf(stderr, "\n");
97*8617a60dSAndroid Build Coastguard Worker return VB2_ERROR_FLASHROM;
98*8617a60dSAndroid Build Coastguard Worker }
99*8617a60dSAndroid Build Coastguard Worker
100*8617a60dSAndroid Build Coastguard Worker return VB2_SUCCESS;
101*8617a60dSAndroid Build Coastguard Worker }
102*8617a60dSAndroid Build Coastguard Worker
flashrom_read(struct firmware_image * image,const char * region)103*8617a60dSAndroid Build Coastguard Worker vb2_error_t flashrom_read(struct firmware_image *image, const char *region)
104*8617a60dSAndroid Build Coastguard Worker {
105*8617a60dSAndroid Build Coastguard Worker char *tmpfile;
106*8617a60dSAndroid Build Coastguard Worker char region_param[PATH_MAX];
107*8617a60dSAndroid Build Coastguard Worker vb2_error_t rv;
108*8617a60dSAndroid Build Coastguard Worker
109*8617a60dSAndroid Build Coastguard Worker image->data = NULL;
110*8617a60dSAndroid Build Coastguard Worker image->size = 0;
111*8617a60dSAndroid Build Coastguard Worker
112*8617a60dSAndroid Build Coastguard Worker VB2_TRY(write_temp_file(NULL, 0, &tmpfile));
113*8617a60dSAndroid Build Coastguard Worker
114*8617a60dSAndroid Build Coastguard Worker if (region)
115*8617a60dSAndroid Build Coastguard Worker snprintf(region_param, sizeof(region_param), "%s:%s", region,
116*8617a60dSAndroid Build Coastguard Worker tmpfile);
117*8617a60dSAndroid Build Coastguard Worker
118*8617a60dSAndroid Build Coastguard Worker const char *const argv[] = {
119*8617a60dSAndroid Build Coastguard Worker FLASHROM_EXEC_NAME,
120*8617a60dSAndroid Build Coastguard Worker "-p",
121*8617a60dSAndroid Build Coastguard Worker image->programmer,
122*8617a60dSAndroid Build Coastguard Worker "-r",
123*8617a60dSAndroid Build Coastguard Worker region ? "-i" : tmpfile,
124*8617a60dSAndroid Build Coastguard Worker region ? region_param : NULL,
125*8617a60dSAndroid Build Coastguard Worker NULL,
126*8617a60dSAndroid Build Coastguard Worker };
127*8617a60dSAndroid Build Coastguard Worker
128*8617a60dSAndroid Build Coastguard Worker rv = run_flashrom(argv);
129*8617a60dSAndroid Build Coastguard Worker if (rv == VB2_SUCCESS)
130*8617a60dSAndroid Build Coastguard Worker rv = vb2_read_file(tmpfile, &image->data, &image->size);
131*8617a60dSAndroid Build Coastguard Worker
132*8617a60dSAndroid Build Coastguard Worker unlink(tmpfile);
133*8617a60dSAndroid Build Coastguard Worker free(tmpfile);
134*8617a60dSAndroid Build Coastguard Worker return rv;
135*8617a60dSAndroid Build Coastguard Worker }
136*8617a60dSAndroid Build Coastguard Worker
flashrom_write(struct firmware_image * image,const char * region)137*8617a60dSAndroid Build Coastguard Worker vb2_error_t flashrom_write(struct firmware_image *image, const char *region)
138*8617a60dSAndroid Build Coastguard Worker {
139*8617a60dSAndroid Build Coastguard Worker char *tmpfile;
140*8617a60dSAndroid Build Coastguard Worker char region_param[PATH_MAX];
141*8617a60dSAndroid Build Coastguard Worker vb2_error_t rv;
142*8617a60dSAndroid Build Coastguard Worker
143*8617a60dSAndroid Build Coastguard Worker VB2_TRY(write_temp_file(image->data, image->size, &tmpfile));
144*8617a60dSAndroid Build Coastguard Worker
145*8617a60dSAndroid Build Coastguard Worker if (region)
146*8617a60dSAndroid Build Coastguard Worker snprintf(region_param, sizeof(region_param), "%s:%s", region,
147*8617a60dSAndroid Build Coastguard Worker tmpfile);
148*8617a60dSAndroid Build Coastguard Worker
149*8617a60dSAndroid Build Coastguard Worker const char *const argv[] = {
150*8617a60dSAndroid Build Coastguard Worker FLASHROM_EXEC_NAME,
151*8617a60dSAndroid Build Coastguard Worker "-p",
152*8617a60dSAndroid Build Coastguard Worker image->programmer,
153*8617a60dSAndroid Build Coastguard Worker "--noverify-all",
154*8617a60dSAndroid Build Coastguard Worker "-w",
155*8617a60dSAndroid Build Coastguard Worker region ? "-i" : tmpfile,
156*8617a60dSAndroid Build Coastguard Worker region ? region_param : NULL,
157*8617a60dSAndroid Build Coastguard Worker NULL,
158*8617a60dSAndroid Build Coastguard Worker };
159*8617a60dSAndroid Build Coastguard Worker
160*8617a60dSAndroid Build Coastguard Worker rv = run_flashrom(argv);
161*8617a60dSAndroid Build Coastguard Worker unlink(tmpfile);
162*8617a60dSAndroid Build Coastguard Worker free(tmpfile);
163*8617a60dSAndroid Build Coastguard Worker return rv;
164*8617a60dSAndroid Build Coastguard Worker }
165