summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--util/cbfstool/Makefile.inc13
-rw-r--r--util/cbfstool/elogtool.c25
-rw-r--r--util/cbfstool/uflashrom.c210
-rw-r--r--util/cbfstool/uflashrom.h17
4 files changed, 254 insertions, 11 deletions
diff --git a/util/cbfstool/Makefile.inc b/util/cbfstool/Makefile.inc
index 3787a56578..a568e9aef6 100644
--- a/util/cbfstool/Makefile.inc
+++ b/util/cbfstool/Makefile.inc
@@ -1,3 +1,5 @@
+HOSTPKGCONFIG ?= /usr/bin/pkg-config
+
compressionobj :=
compressionobj += compress.o
# LZ4
@@ -92,6 +94,7 @@ amdcompobj += xdr.o
elogobj :=
elogobj := elogtool.o
elogobj += eventlog.o
+elogobj += uflashrom.o
elogobj += valstr.o
elogobj += elog.o
elogobj += common.o
@@ -144,6 +147,12 @@ else
TOOLCFLAGS+=-std=c11
endif
+.PHONY: check-flashrom-presence
+check-flashrom-presence:
+ $(HOSTPKGCONFIG) --exists flashrom || \
+ (echo "Error: Ensure that pkg-config and flashrom are installed."; exit 1)
+
+FLASHROM := $$($(HOSTPKGCONFIG) --libs flashrom)
VBOOT_HOSTLIB = $(VBOOT_HOST_BUILD)/libvboot_host.a
$(VBOOT_HOSTLIB):
@@ -224,9 +233,9 @@ $(objutil)/cbfstool/amdcompress: $(addprefix $(objutil)/cbfstool/,$(amdcompobj))
printf " HOSTCC $(subst $(objutil)/,,$(@)) (link)\n"
$(HOSTCC) $(TOOLLDFLAGS) -o $@ $(addprefix $(objutil)/cbfstool/,$(amdcompobj)) -lz
-$(objutil)/cbfstool/elogtool: $(addprefix $(objutil)/cbfstool/,$(elogobj)) $(VBOOT_HOSTLIB)
+$(objutil)/cbfstool/elogtool: | check-flashrom-presence $(addprefix $(objutil)/cbfstool/,$(elogobj))
printf " HOSTCC $(subst $(objutil)/,,$(@)) (link)\n"
- $(HOSTCC) $(TOOLLDFLAGS) -o $@ $(addprefix $(objutil)/cbfstool/,$(elogobj)) $(VBOOT_HOSTLIB)
+ $(HOSTCC) $(TOOLLDFLAGS) -o $@ $(addprefix $(objutil)/cbfstool/,$(elogobj)) $(FLASHROM)
$(objutil)/cbfstool/cse_fpt: $(addprefix $(objutil)/cbfstool/,$(cse_fpt_obj))
printf " HOSTCC $(subst $(objutil)/,,$(@)) (link)\n"
diff --git a/util/cbfstool/elogtool.c b/util/cbfstool/elogtool.c
index 253e2ee95a..44823dd89a 100644
--- a/util/cbfstool/elogtool.c
+++ b/util/cbfstool/elogtool.c
@@ -11,9 +11,9 @@
#include <common.h>
#include <commonlib/bsd/elog.h>
-#include <flashrom.h>
#include "eventlog.h"
+#include "uflashrom.h"
/* Only refers to the data max size. The "-1" is the checksum byte */
#define ELOG_MAX_EVENT_DATA_SIZE (ELOG_MAX_EVENT_SIZE - sizeof(struct event_header) - 1)
@@ -78,16 +78,18 @@ static void usage(char *invoked_as)
*/
static int elog_read(struct buffer *buffer, const char *filename)
{
- if (filename == NULL) {
- uint8_t *buf;
- uint32_t buf_size;
+ struct firmware_programmer image = {
+ .programmer = FLASHROM_PROGRAMMER_INTERNAL_AP,
+ .data = NULL,
+ .size = 0,
+ };
- if (flashrom_read(FLASHROM_PROGRAMMER_INTERNAL_AP, ELOG_RW_REGION_NAME,
- &buf, &buf_size) != VB2_SUCCESS) {
+ if (filename == NULL) {
+ if (flashrom_read(&image, ELOG_RW_REGION_NAME) != 0) {
fprintf(stderr, "Could not read RW_ELOG region using flashrom\n");
return ELOGTOOL_EXIT_READ_ERROR;
}
- buffer_init(buffer, NULL, buf, buf_size);
+ buffer_init(buffer, NULL, image.data, image.size);
} else if (buffer_from_file(buffer, filename) != 0) {
fprintf(stderr, "Could not read input file: %s\n", filename);
return ELOGTOOL_EXIT_READ_ERROR;
@@ -108,9 +110,14 @@ static int elog_read(struct buffer *buffer, const char *filename)
*/
static int elog_write(struct buffer *buf, const char *filename)
{
+ struct firmware_programmer image = {
+ .programmer = FLASHROM_PROGRAMMER_INTERNAL_AP,
+ .data = buffer_get(buf),
+ .size = buffer_size(buf),
+ };
+
if (filename == NULL) {
- if (flashrom_write(FLASHROM_PROGRAMMER_INTERNAL_AP, ELOG_RW_REGION_NAME,
- buffer_get(buf), buffer_size(buf)) != VB2_SUCCESS) {
+ if (flashrom_write(&image, ELOG_RW_REGION_NAME) != 0) {
fprintf(stderr,
"Failed to write to RW_ELOG region using flashrom\n");
return ELOGTOOL_EXIT_WRITE_ERROR;
diff --git a/util/cbfstool/uflashrom.c b/util/cbfstool/uflashrom.c
new file mode 100644
index 0000000000..faa45b6b49
--- /dev/null
+++ b/util/cbfstool/uflashrom.c
@@ -0,0 +1,210 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libflashrom.h>
+
+#include "uflashrom.h"
+
+static int flashrom_print_cb(enum flashrom_log_level level, const char *fmt, va_list ap)
+{
+ int ret = 0;
+ FILE *output_type = stderr;
+
+ if (level > FLASHROM_MSG_INFO)
+ return ret;
+
+ ret = vfprintf(output_type, fmt, ap);
+ /* msg_*spew often happens inside chip accessors
+ * in possibly time-critical operations.
+ * If increasing verbosity, don't slow them down by flushing.
+ */
+ fflush(output_type);
+
+ return ret;
+}
+
+static size_t resize_buf_to_offset(uint8_t **buf, unsigned int start, unsigned int len)
+{
+ uint8_t *old = *buf; // make a copy to free the old heap.
+
+ *buf = calloc(1, len);
+ memcpy(*buf, &old[start], len);
+ free(old);
+
+ return len;
+}
+
+static uint8_t *resize_buf_from_offset(const uint8_t *buf, size_t len, unsigned int rstart,
+ unsigned int rlen)
+{
+ size_t nlen = rstart + rlen;
+ if (nlen > len)
+ return NULL;
+
+ uint8_t *nbuf = calloc(1, len); /* NOTE: full len buf required for writes. */
+ memcpy(nbuf + rstart, buf, rlen);
+
+ return nbuf;
+}
+
+/**
+ * @brief Reads from flash into a buffer with an optional region.
+ *
+ * @param image, containing the programmer to use, unallocated buffer and size.
+ * @param region, (optional) the string of the region to read from.
+ * @return 0 on success
+ */
+int flashrom_read(struct firmware_programmer *image, const char *region)
+{
+ int r = 0;
+ size_t len = 0;
+
+ struct flashrom_programmer *prog = NULL;
+ struct flashrom_flashctx *flashctx = NULL;
+ struct flashrom_layout *layout = NULL;
+
+ flashrom_set_log_callback((flashrom_log_callback *)&flashrom_print_cb);
+
+ r |= flashrom_init(1);
+ r |= flashrom_programmer_init(&prog, image->programmer, NULL);
+ r |= flashrom_flash_probe(&flashctx, prog, NULL);
+ if (r) {
+ r = -1;
+ goto err_cleanup;
+ }
+
+ len = flashrom_flash_getsize(flashctx);
+ if (region) {
+ r = flashrom_layout_read_fmap_from_rom(&layout, flashctx, 0, len);
+ if (r > 0) {
+ fprintf(stderr, "could not read fmap from rom, r=%d\n", r);
+ r = -1;
+ goto err_cleanup;
+ }
+ /* empty region causes seg fault in API. */
+ r |= flashrom_layout_include_region(layout, region);
+ if (r > 0) {
+ fprintf(stderr, "could not include region = '%s'\n", region);
+ r = -1;
+ goto err_cleanup;
+ }
+ flashrom_layout_set(flashctx, layout);
+ }
+ /* Due to how the libflashrom API works we first need a buffer sized
+ * to the entire flash and after the read has finished, find the
+ * the precise region size then resize the buffer accordingly.
+ */
+ image->data = calloc(1, len);
+ image->size = len;
+
+ r |= flashrom_image_read(flashctx, image->data, len);
+
+ /* Here we resize the buffer from being the entire flash down to the specific
+ * region size read and that we were interested in. Note that we only include
+ * a singular region.
+ */
+ if (region) {
+ unsigned int r_start, r_len;
+ flashrom_layout_get_region_range(layout, region, &r_start, &r_len);
+ image->size = resize_buf_to_offset(&image->data, r_start, r_len);
+ }
+
+err_cleanup:
+ flashrom_programmer_shutdown(prog);
+ if (layout)
+ flashrom_layout_release(layout);
+ if (flashctx)
+ flashrom_flash_release(flashctx);
+
+ return r;
+}
+
+/**
+ * @brief Writes flash from a buffer with an optional region.
+ *
+ * @param image, containing the programmer to use, allocated buffer and its size.
+ * @param region, (optional) the string of the region to write to.
+ * @return 0 on success
+ */
+int flashrom_write(struct firmware_programmer *image, const char *region)
+{
+ int r = 0;
+ size_t len = 0;
+ uint8_t *buf = image->data;
+
+ struct flashrom_programmer *prog = NULL;
+ struct flashrom_flashctx *flashctx = NULL;
+ struct flashrom_layout *layout = NULL;
+
+ flashrom_set_log_callback((flashrom_log_callback *)&flashrom_print_cb);
+
+ r |= flashrom_init(1);
+ r |= flashrom_programmer_init(&prog, image->programmer, NULL);
+ r |= flashrom_flash_probe(&flashctx, prog, NULL);
+ if (r) {
+ r = -1;
+ goto err_cleanup;
+ }
+
+ len = flashrom_flash_getsize(flashctx);
+ if (len == 0) {
+ fprintf(stderr, "zero sized flash detected\n");
+ r = -1;
+ goto err_cleanup;
+ }
+ if (region) {
+ r = flashrom_layout_read_fmap_from_buffer(
+ &layout, flashctx, (const uint8_t *)image->data, image->size);
+ if (r > 0) {
+ r = flashrom_layout_read_fmap_from_rom(&layout, flashctx, 0, len);
+ if (r > 0) {
+ fprintf(stderr, "could not read fmap from image or rom, r=%d\n",
+ r);
+ r = -1;
+ goto err_cleanup;
+ }
+ }
+ /* empty region causes seg fault in API. */
+ r |= flashrom_layout_include_region(layout, region);
+ if (r > 0) {
+ fprintf(stderr, "could not include region = '%s'\n", region);
+ r = -1;
+ goto err_cleanup;
+ }
+ flashrom_layout_set(flashctx, layout);
+
+ unsigned int r_start, r_len;
+ flashrom_layout_get_region_range(layout, region, &r_start, &r_len);
+ assert(r_len == image->size);
+ buf = resize_buf_from_offset(image->data, len, r_start, r_len);
+ if (!buf) {
+ r = -1;
+ goto err_cleanup_free;
+ }
+ } else if (image->size != len) {
+ r = -1;
+ goto err_cleanup;
+ }
+
+ flashrom_flag_set(flashctx, FLASHROM_FLAG_VERIFY_WHOLE_CHIP, false);
+ flashrom_flag_set(flashctx, FLASHROM_FLAG_VERIFY_AFTER_WRITE, true);
+
+ r |= flashrom_image_write(flashctx, buf, len, NULL);
+
+err_cleanup_free:
+ if (region)
+ free(buf);
+err_cleanup:
+ flashrom_programmer_shutdown(prog);
+ if (layout)
+ flashrom_layout_release(layout);
+ if (flashctx)
+ flashrom_flash_release(flashctx);
+
+ return r;
+}
diff --git a/util/cbfstool/uflashrom.h b/util/cbfstool/uflashrom.h
new file mode 100644
index 0000000000..1ef0085dd9
--- /dev/null
+++ b/util/cbfstool/uflashrom.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+
+#ifndef UFLASHROM_H
+#define UFLASHROM_H
+
+#define FLASHROM_PROGRAMMER_INTERNAL_AP "internal"
+
+struct firmware_programmer {
+ const char *programmer;
+ uint32_t size;
+ uint8_t *data;
+};
+
+int flashrom_read(struct firmware_programmer *image, const char *region);
+int flashrom_write(struct firmware_programmer *image, const char *region);
+
+#endif /* UFLASHROM_H */