summaryrefslogtreecommitdiff
path: root/util/cbfstool
diff options
context:
space:
mode:
authorRicardo Quesada <ricardoq@google.com>2021-08-16 11:25:52 -0700
committerFurquan Shaikh <furquan@google.com>2021-09-10 22:53:05 +0000
commit49a96a94634ca146969293c8f1ac12dba6bbd231 (patch)
tree35acd79010065000d84745fea713bb329b145127 /util/cbfstool
parent6db0f04fa24d3532b6c6f1069001a166764ac1db (diff)
elogtool: add "clear" command
Adds "clear" command to cbfsutil/elogtool tool. "clear" clears the RW_ELOG region by using either: * flashrom if no file is provided * or using file write if an input file is provided. The region is filled with ELOG_TYPE_EOL. And a ELOG_TYPE_LOG_CLEAR event is inserted. Additionally, it does a minor cleanup to command "list", like: * use buffer_end() * add "list" to the cmds struct * and make elog_read() very similar to elog_write() Usage: $ elogtool clear BUG=b:172210863 TEST=elogtool clear && elogtool list elogtool clear -f invalid.raw elogtool clear -f valid.raw Change-Id: Ia28a6eb34c82103ab078a0841b022e2e5e430585 Signed-off-by: Ricardo Quesada <ricardoq@google.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/56883 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Furquan Shaikh <furquan@google.com> Reviewed-by: Jack Rosenthal <jrosenth@chromium.org>
Diffstat (limited to 'util/cbfstool')
-rw-r--r--util/cbfstool/elogtool.c172
-rw-r--r--util/cbfstool/eventlog.c40
-rw-r--r--util/cbfstool/eventlog.h5
3 files changed, 172 insertions, 45 deletions
diff --git a/util/cbfstool/elogtool.c b/util/cbfstool/elogtool.c
index ba59eac514..4ab8494209 100644
--- a/util/cbfstool/elogtool.c
+++ b/util/cbfstool/elogtool.c
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause */
#include <getopt.h>
+#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -16,9 +17,24 @@
enum elogtool_return {
ELOGTOOL_EXIT_SUCCESS = 0,
ELOGTOOL_EXIT_BAD_ARGS,
- ELOGTOOL_EXIT_BAD_INPUT_PATH,
+ ELOGTOOL_EXIT_READ_ERROR,
+ ELOGTOOL_EXIT_WRITE_ERROR,
ELOGTOOL_EXIT_NOT_ENOUGH_MEMORY,
ELOGTOOL_EXIT_INVALID_ELOG_FORMAT,
+ ELOGTOOL_EXIT_NOT_ENOUGH_BUFFER_SPACE,
+};
+
+static int cmd_list(const struct buffer *);
+static int cmd_clear(const struct buffer *);
+
+static const struct {
+ const char *name;
+ int (*func)(const struct buffer *buf);
+ /* Whether it requires to write the buffer back */
+ bool write_back;
+} cmds[] = {
+ {"list", cmd_list, false},
+ {"clear", cmd_clear, true},
};
static struct option long_options[] = {
@@ -33,57 +49,81 @@ static void usage(char *invoked_as)
"USAGE:\n"
"\t%s COMMAND [-f <filename>]\n\n"
"where, COMMAND is:\n"
- " list = lists all the event logs in human readable format\n\n"
+ " list = lists all the event logs in human readable format\n"
+ " clear = clears all the event logs\n"
+ "\n"
"ARGS\n"
- "-f, --file <filename> Input file that holds event log partition.\n"
- " If empty it will try to read from the RW_ELOG ROM region\n"
+ "-f, --file <filename> File that holds event log partition.\n"
+ " If empty it will try to read/write from/to\n"
+ " the " ELOG_RW_REGION_NAME " using flashrom.\n"
"-h, --help Print this help\n",
invoked_as);
}
-// If filename is empty, read RW_ELOG from flashrom. Otherwise read the RW_ELOG from a file.
-// Buffer must be freed by caller.
-static int elog_read(const char *filename, struct buffer *buffer)
+/*
+ * If filename is empty, read RW_ELOG from flashrom.
+ * Otherwise read the RW_ELOG from a file.
+ * It fails if the ELOG header is invalid.
+ * On success, buffer must be freed by caller.
+ */
+static int elog_read(struct buffer *buffer, const char *filename)
{
if (filename == NULL) {
uint8_t *buf;
uint32_t buf_size;
- if (flashrom_read(FLASHROM_PROGRAMMER_INTERNAL_AP, "RW_ELOG", &buf, &buf_size)
- != VB2_SUCCESS) {
+ if (flashrom_read(FLASHROM_PROGRAMMER_INTERNAL_AP, ELOG_RW_REGION_NAME,
+ &buf, &buf_size) != VB2_SUCCESS) {
fprintf(stderr, "Could not read RW_ELOG region using flashrom\n");
- return ELOGTOOL_EXIT_BAD_INPUT_PATH;
+ return ELOGTOOL_EXIT_READ_ERROR;
}
buffer_init(buffer, NULL, buf, buf_size);
- } else {
- if (buffer_from_file(buffer, filename) != 0) {
- fprintf(stderr, "Could not read input file: %s\n", filename);
- return ELOGTOOL_EXIT_BAD_INPUT_PATH;
+ } else if (buffer_from_file(buffer, filename) != 0) {
+ fprintf(stderr, "Could not read input file: %s\n", filename);
+ return ELOGTOOL_EXIT_READ_ERROR;
+ }
+
+ if (elog_verify_header(buffer_get(buffer)) != CB_SUCCESS) {
+ fprintf(stderr, "FATAL: Invalid elog header\n");
+ buffer_delete(buffer);
+ return ELOGTOOL_EXIT_INVALID_ELOG_FORMAT;
+ }
+
+ return ELOGTOOL_EXIT_SUCCESS;
+}
+
+/*
+ * If filename is NULL, it saves the buffer using flashrom.
+ * Otherwise, it saves the buffer in the given filename.
+ */
+static int elog_write(struct buffer *buf, const char *filename)
+{
+ if (filename == NULL) {
+ if (flashrom_write(FLASHROM_PROGRAMMER_INTERNAL_AP, ELOG_RW_REGION_NAME,
+ buffer_get(buf), buffer_size(buf)) != VB2_SUCCESS) {
+ fprintf(stderr,
+ "Failed to write to RW_ELOG region using flashrom\n");
+ return ELOGTOOL_EXIT_WRITE_ERROR;
}
+ return ELOGTOOL_EXIT_SUCCESS;
}
- return 0;
+ if (buffer_write_file(buf, filename) != 0) {
+ fprintf(stderr, "Failed to write to file %s\n", filename);
+ return ELOGTOOL_EXIT_WRITE_ERROR;
+ }
+ return ELOGTOOL_EXIT_SUCCESS;
}
-static int elog_list_events(const struct buffer *buf)
+static int cmd_list(const struct buffer *buf)
{
const struct event_header *event;
- const void *data;
- uint32_t data_len;
unsigned int count = 0;
- data = buffer_get(buf);
- data_len = buffer_size(buf);
-
- if (elog_verify_header(data) != CB_SUCCESS) {
- fprintf(stderr, "FATAL: Invalid elog header\n");
- return ELOGTOOL_EXIT_INVALID_ELOG_FORMAT;
- }
-
- /* Point to first event */
- event = (const struct event_header *)(data + sizeof(struct elog_header));
+ /* Point to the first event */
+ event = buffer_get(buf) + sizeof(struct elog_header);
- while ((const void *)(event) < data + data_len) {
+ while ((const void *)(event) < buffer_end(buf)) {
if (event->type == ELOG_TYPE_EOL || event->length == 0)
break;
@@ -95,27 +135,52 @@ static int elog_list_events(const struct buffer *buf)
return ELOGTOOL_EXIT_SUCCESS;
}
-static int cmd_list(const char *filename)
+/*
+ * Clears the elog events from the given buffer, which is a valid RW_ELOG region.
+ * A LOG_CLEAR event is appended.
+ */
+static int cmd_clear(const struct buffer *b)
{
- int ret;
-
- // Returned buffer must be freed.
+ const struct event_header *event;
+ uint32_t used_data_size = 0;
struct buffer buf;
- ret = elog_read(filename, &buf);
- if (ret != 0)
- return ret;
+ void *data_offset;
+
+ /* Clone the buffer to avoid changing the offset of the original buffer */
+ buffer_clone(&buf, b);
+ /* eventlog_init_event() expects buffer to point to the event */
+ buffer_seek(&buf, sizeof(struct elog_header));
+
+ /*
+ * Calculate the size of the "used" buffer, needed for ELOG_TYPE_LOG_CLEAR.
+ * Then overwrite the entire buffer with ELOG_TYPE_EOL.
+ * Finally insert a LOG_CLEAR event into the buffer.
+ */
+ event = data_offset = buffer_get(&buf);
+ while ((const void *)(event) < buffer_end(&buf)) {
+ if (event->type == ELOG_TYPE_EOL || event->length == 0)
+ break;
- ret = elog_list_events(&buf);
+ used_data_size += event->length;
+ event = elog_get_next_event(event);
+ }
- buffer_delete(&buf);
- return ret;
-}
+ memset(data_offset, ELOG_TYPE_EOL, buffer_size(&buf));
+
+ if (!eventlog_init_event(&buf, ELOG_TYPE_LOG_CLEAR,
+ &used_data_size, sizeof(used_data_size)))
+ return ELOGTOOL_EXIT_NOT_ENOUGH_BUFFER_SPACE;
+ return ELOGTOOL_EXIT_SUCCESS;
+}
int main(int argc, char **argv)
{
+ char *filename = NULL;
+ struct buffer buf;
+ unsigned int i;
int argflag;
- char *input_file = NULL;
+ int ret;
if (argc < 2) {
usage(argv[0]);
@@ -140,7 +205,7 @@ int main(int argc, char **argv)
return ELOGTOOL_EXIT_BAD_ARGS;
}
- input_file = optarg;
+ filename = optarg;
break;
default:
@@ -154,8 +219,25 @@ int main(int argc, char **argv)
return ELOGTOOL_EXIT_BAD_ARGS;
}
- if (!strcmp(argv[optind], "list"))
- return cmd_list(input_file);
+ /* Returned buffer must be freed. */
+ ret = elog_read(&buf, filename);
+ if (ret)
+ return ret;
- return ELOGTOOL_EXIT_SUCCESS;
+ for (i = 0; i < ARRAY_SIZE(cmds); i++) {
+ if (!strcmp(cmds[i].name, argv[optind])) {
+ ret = cmds[i].func(&buf);
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(cmds))
+ ret = ELOGTOOL_EXIT_BAD_ARGS;
+
+ if (!ret && cmds[i].write_back)
+ ret = elog_write(&buf, filename);
+
+ buffer_delete(&buf);
+
+ return ret;
}
diff --git a/util/cbfstool/eventlog.c b/util/cbfstool/eventlog.c
index 2d99f9237a..8b03686ecd 100644
--- a/util/cbfstool/eventlog.c
+++ b/util/cbfstool/eventlog.c
@@ -11,6 +11,7 @@
#include <commonlib/bsd/elog.h>
#include <vb2_api.h>
+#include "common.h"
#include "valstr.h"
#define PATH_PCI_BUS_SHIFT 8
@@ -634,3 +635,42 @@ void eventlog_print_event(const struct event_header *event, int count)
eventlog_printf_ignore_separator_once = 1;
eventlog_printf("\n");
}
+
+/*
+ * Initializes the eventlog header with the given type and data,
+ * and calculates the checksum.
+ * buffer_get() points to the event to be initialized.
+ * On success it returns 1, otherwise 0.
+ */
+int eventlog_init_event(const struct buffer *buf, uint8_t type,
+ const void *data, int data_size)
+{
+ struct event_header *event;
+ time_t secs = time(NULL);
+ struct tm tm;
+
+ /* Must have at least size for data + checksum byte */
+ if (buffer_size(buf) < (size_t)data_size + 1)
+ return 0;
+
+ event = buffer_get(buf);
+
+ event->type = type;
+ gmtime_r(&secs, &tm);
+ elog_fill_timestamp(event, tm.tm_sec, tm.tm_min, tm.tm_hour,
+ tm.tm_mday, tm.tm_mon, tm.tm_year);
+
+ if (data && data_size) {
+ uint32_t *ptr = (uint32_t *)&event[1];
+ memcpy(ptr, data, data_size);
+ }
+
+ /* Header + data + checksum */
+ event->length = sizeof(*event) + data_size + 1;
+
+ /* Zero the checksum byte and then compute checksum */
+ elog_update_checksum(event, 0);
+ elog_update_checksum(event, -(elog_checksum_event(event)));
+
+ return 1;
+}
diff --git a/util/cbfstool/eventlog.h b/util/cbfstool/eventlog.h
index baecb21db6..1911b77e82 100644
--- a/util/cbfstool/eventlog.h
+++ b/util/cbfstool/eventlog.h
@@ -3,8 +3,13 @@
#ifndef EVENTLOG_H_
#define EVENTLOG_H_
+#include <stdint.h>
+
struct event_header;
+struct buffer;
void eventlog_print_event(const struct event_header *event, int count);
+int eventlog_init_event(const struct buffer *buf, uint8_t type,
+ const void *data, int data_size);
#endif // EVENTLOG_H_