diff options
Diffstat (limited to 'host/lib/flashrom.c')
-rw-r--r-- | host/lib/flashrom.c | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/host/lib/flashrom.c b/host/lib/flashrom.c new file mode 100644 index 00000000..061c5b84 --- /dev/null +++ b/host/lib/flashrom.c @@ -0,0 +1,158 @@ +/* Copyright 2020 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* For strdup */ +#define _POSIX_C_SOURCE 200809L + +#include <fcntl.h> +#include <limits.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "2api.h" +#include "2return_codes.h" +#include "host_misc.h" +#include "flashrom.h" +#include "subprocess.h" + +#define FLASHROM_EXEC_NAME "flashrom" + +/** + * Helper to create a temporary file, and optionally write some data + * into it. + * + * @param data If data needs to be written to the file, a + * pointer to the buffer. Pass NULL to just + * create an empty temporary file. + * @param data_size The size of the buffer to write, if applicable. + * @param path_out An output pointer for the filename. Caller + * should free. + * + * @return VB2_SUCCESS on success, or a relevant error. + */ +static vb2_error_t write_temp_file(const uint8_t *data, uint32_t data_size, + char **path_out) +{ + int fd; + ssize_t write_rv; + vb2_error_t rv; + char *path; + + *path_out = NULL; + path = strdup(P_tmpdir "/vb2_flashrom.XXXXXX"); + + fd = mkstemp(path); + if (fd < 0) { + rv = VB2_ERROR_WRITE_FILE_OPEN; + goto fail; + } + + while (data && data_size > 0) { + write_rv = write(fd, data, data_size); + if (write_rv < 0) { + close(fd); + unlink(path); + rv = VB2_ERROR_WRITE_FILE_DATA; + goto fail; + } + + data_size -= write_rv; + data += write_rv; + } + + close(fd); + *path_out = path; + return VB2_SUCCESS; + + fail: + free(path); + return rv; +} + +static vb2_error_t run_flashrom(const char *const argv[]) +{ + int status = subprocess_run(argv, &subprocess_null, &subprocess_null, + &subprocess_null); + if (status) { + fprintf(stderr, "Flashrom invocation failed (exit status %d):", + status); + + for (const char *const *argp = argv; *argp; argp++) + fprintf(stderr, " %s", *argp); + + fprintf(stderr, "\n"); + return VB2_ERROR_FLASHROM; + } + + return VB2_SUCCESS; +} + +vb2_error_t flashrom_read(const char *programmer, const char *region, + uint8_t **data_out, uint32_t *size_out) +{ + char *tmpfile; + char region_param[PATH_MAX]; + vb2_error_t rv; + + *data_out = NULL; + *size_out = 0; + + VB2_TRY(write_temp_file(NULL, 0, &tmpfile)); + + if (region) + snprintf(region_param, sizeof(region_param), "%s:%s", region, + tmpfile); + + const char *const argv[] = { + FLASHROM_EXEC_NAME, + "-p", + programmer, + "-r", + region ? "-i" : tmpfile, + region ? region_param : NULL, + NULL, + }; + + rv = run_flashrom(argv); + if (rv == VB2_SUCCESS) + rv = vb2_read_file(tmpfile, data_out, size_out); + + unlink(tmpfile); + free(tmpfile); + return rv; +} + +vb2_error_t flashrom_write(const char *programmer, const char *region, + uint8_t *data, uint32_t size) +{ + char *tmpfile; + char region_param[PATH_MAX]; + vb2_error_t rv; + + VB2_TRY(write_temp_file(data, size, &tmpfile)); + + if (region) + snprintf(region_param, sizeof(region_param), "%s:%s", region, + tmpfile); + + const char *const argv[] = { + FLASHROM_EXEC_NAME, + "-p", + programmer, + "-w", + region ? "-i" : tmpfile, + region ? region_param : NULL, + NULL, + }; + + rv = run_flashrom(argv); + unlink(tmpfile); + free(tmpfile); + return rv; +} |