xref: /aosp_15_r20/external/vboot_reference/host/lib/flashrom.c (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
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