util/cbfstool: Port elogtool to libflashrom

This also uncouples cbfstool from being overly Chromium
specific. However the main objective is to not subprocess
flashrom any more and instead use the programmatic API.

BUG=b:207808292
TEST=built and ran `elogtool (list|clear|add 0x16 C0FFEE)`.

Change-Id: I79df2934b9b0492a554a4fecdd533a0abe1df231
Signed-off-by: Edward O'Callaghan <quasisec@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/59714
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Sam McNally <sammc@google.com>
This commit is contained in:
Edward O'Callaghan 2021-11-29 11:02:46 +11:00 committed by Edward O'Callaghan
parent e565f75221
commit d74b8d9c99
4 changed files with 254 additions and 11 deletions

View File

@ -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"

View File

@ -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;

210
util/cbfstool/uflashrom.c Normal file
View File

@ -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;
}

17
util/cbfstool/uflashrom.h Normal file
View File

@ -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 */