Ricardo Quesada has uploaded this change for review.

View Change

elogtool: add "clear" command

Adds "clear" command to cbfsutil/elogtool tool.
"clear" clears the RW_ELOG using flashrom with ELOG_TYPE_EOL.
And inserts a ELOG_TYPE_LOG_CLEAR event.

Usage:
$ elogtool clear

BUG=b:172210863

Change-Id: Ia28a6eb34c82103ab078a0841b022e2e5e430585
Signed-off-by: Ricardo Quesada <ricardoq@google.com>
---
M src/commonlib/bsd/elog.c
M src/commonlib/bsd/include/commonlib/bsd/elog.h
M util/cbfstool/elogtool.c
M util/cbfstool/eventlog.c
M util/cbfstool/eventlog.h
5 files changed, 166 insertions(+), 6 deletions(-)

git pull ssh://review.coreboot.org:29418/coreboot refs/changes/83/56883/1
diff --git a/src/commonlib/bsd/elog.c b/src/commonlib/bsd/elog.c
index 6c927aa..27fe808 100644
--- a/src/commonlib/bsd/elog.c
+++ b/src/commonlib/bsd/elog.c
@@ -40,7 +40,55 @@
/* return the data associated to the event_header. */
const void *event_get_data(const struct event_header *event)
{
- // Pointing to the next event returns the data, since data is the first field
- // right after the header.
+ /*
+ * Pointing to the next event returns the data, since data is the first
+ * field right after the header.
+ */
return (const void *)(&event[1]);
}
+
+static inline uint8_t mybin2bcd(uint8_t val)
+{
+ return ((val / 10) << 4) | (val % 10);
+}
+
+/* Populate timestamp in event header with given time. */
+void elog_fill_timestamp(struct event_header *event, uint8_t sec, uint8_t min,
+ uint8_t hour, uint8_t mday, uint8_t mon, uint8_t year)
+{
+ event->second = mybin2bcd(sec);
+ event->minute = mybin2bcd(min);
+ event->hour = mybin2bcd(hour);
+ event->day = mybin2bcd(mday);
+ event->month = mybin2bcd(mon);
+ event->year = mybin2bcd(year % 100);
+
+ /* Basic sanity check of expected ranges. */
+ if (event->month > 0x12 || event->day > 0x31 || event->hour > 0x23 ||
+ event->minute > 0x59 || event->second > 0x59) {
+ event->year = 0;
+ event->month = 0;
+ event->day = 0;
+ event->hour = 0;
+ event->minute = 0;
+ event->second = 0;
+ }
+}
+
+/* Update the checksum at the last byte. */
+void elog_update_checksum(struct event_header *event, uint8_t checksum)
+{
+ uint8_t *event_data = (uint8_t *)event;
+ event_data[event->length - 1] = checksum;
+}
+
+/* Simple byte checksum for events. */
+uint8_t elog_checksum_event(struct event_header *event)
+{
+ uint8_t index, checksum = 0;
+ uint8_t *data = (uint8_t *)event;
+
+ for (index = 0; index < event->length; index++)
+ checksum += data[index];
+ return checksum;
+}
diff --git a/src/commonlib/bsd/include/commonlib/bsd/elog.h b/src/commonlib/bsd/include/commonlib/bsd/elog.h
index 0d41157..54e7ec4 100644
--- a/src/commonlib/bsd/include/commonlib/bsd/elog.h
+++ b/src/commonlib/bsd/include/commonlib/bsd/elog.h
@@ -313,5 +313,9 @@
enum cb_err elog_verify_header(const struct elog_header *header);
const struct event_header *elog_get_next_event(const struct event_header *event);
const void *event_get_data(const struct event_header *event);
+void elog_fill_timestamp(struct event_header *event, uint8_t sec, uint8_t min,
+ uint8_t hour, uint8_t mday, uint8_t mon, uint8_t year);
+void elog_update_checksum(struct event_header *event, uint8_t checksum);
+uint8_t elog_checksum_event(struct event_header *event);

#endif /* _COMMONLIB_BSD_ELOG_H_ */
diff --git a/util/cbfstool/elogtool.c b/util/cbfstool/elogtool.c
index ba59eac..7a05aff 100644
--- a/util/cbfstool/elogtool.c
+++ b/util/cbfstool/elogtool.c
@@ -33,7 +33,9 @@
"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 the contents RW_ELOG region from flash\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"
@@ -41,8 +43,11 @@
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.
+/*
+ * 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 == NULL) {
@@ -99,7 +104,7 @@
{
int ret;

- // Returned buffer must be freed.
+ /* Returned buffer must be freed. */
struct buffer buf;
ret = elog_read(filename, &buf);
if (ret != 0)
@@ -111,6 +116,74 @@
return ret;
}

+/*
+ * Clears the elog events from buf, which is a valid RW_ELOG region.
+ * A LOG_CLEAR event is appended.
+ */
+static int elog_clear_events(struct buffer *buf)
+{
+ const struct event_header *event;
+ uint32_t used_data_size = 0;
+ void* data_offset;
+ size_t data_size;
+
+ data_size = buf->size - sizeof(struct elog_header);
+ data_offset = buf->data + sizeof(struct elog_header);
+
+ /* Must have at least size for event + data + checksum */
+ if (data_size < sizeof(struct event_header) + sizeof(used_data_size) + 1)
+ return ELOGTOOL_EXIT_INVALID_ELOG_FORMAT;
+
+ /*
+ * Calculate the size of the "used" buffer, needed for ELOG_TYPE_LOG_CLEAR.
+ * Then overwritte the entire buffer with ELOG_TYPE_EOL.
+ * Finally insert a LOG_CLEAR event into the buffer.
+ */
+ event = (const struct event_header *)(data_offset);
+
+ while ((const char *)(event) < buf->data + buf->size) {
+ if (event->type == ELOG_TYPE_EOL || event->length == 0)
+ break;
+
+ used_data_size += event->length;
+ event = elog_get_next_event(event);
+ }
+
+ memset(data_offset, ELOG_TYPE_EOL, data_size);
+
+ eventlog_init_event(data_offset, ELOG_TYPE_LOG_CLEAR,
+ &used_data_size, sizeof(used_data_size));
+
+ return ELOGTOOL_EXIT_SUCCESS;
+}
+
+static int cmd_clear(void)
+{
+ int ret;
+
+ /* Returned buffer must be freed. */
+ struct buffer buf;
+ ret = elog_read(NULL, &buf);
+ if (ret != 0)
+ return ret;
+
+ ret = elog_clear_events(&buf);
+ if (ret != 0) {
+ buffer_delete(&buf);
+ return ret;
+ }
+
+ if (flashrom_write(FLASHROM_PROGRAMMER_INTERNAL_AP, "RW_ELOG",
+ (void *)buf.data, buf.size) != VB2_SUCCESS) {
+
+ fprintf(stderr,
+ "Failed to write to RW_ELOG region using flashrom\n");
+ ret = ELOGTOOL_EXIT_BAD_INPUT_PATH;
+ }
+
+ buffer_delete(&buf);
+ return ret;
+}

int main(int argc, char **argv)
{
@@ -157,5 +230,8 @@
if (!strcmp(argv[optind], "list"))
return cmd_list(input_file);

+ if (!strcmp(argv[optind], "clear"))
+ return cmd_clear();
+
return ELOGTOOL_EXIT_SUCCESS;
}
diff --git a/util/cbfstool/eventlog.c b/util/cbfstool/eventlog.c
index 2d99f92..67168c3 100644
--- a/util/cbfstool/eventlog.c
+++ b/util/cbfstool/eventlog.c
@@ -634,3 +634,31 @@
eventlog_printf_ignore_separator_once = 1;
eventlog_printf("\n");
}
+
+/*
+ * Initializes the eventlog header with the given type and data,
+ * and calculates the checksum.
+ */
+void eventlog_init_event(struct event_header *event, uint8_t type,
+ const void *data, int data_size)
+{
+ time_t secs = time(NULL);
+ struct tm tm;
+
+ 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) {
+ void *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)));
+}
diff --git a/util/cbfstool/eventlog.h b/util/cbfstool/eventlog.h
index baecb21..670a64e 100644
--- a/util/cbfstool/eventlog.h
+++ b/util/cbfstool/eventlog.h
@@ -3,8 +3,12 @@
#ifndef EVENTLOG_H_
#define EVENTLOG_H_

+#include <stdint.h>
+
struct event_header;

void eventlog_print_event(const struct event_header *event, int count);
+void eventlog_init_event(struct event_header* event, uint8_t type,
+ const void *data, int data_size);

#endif // EVENTLOG_H_

To view, visit change 56883. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: Ia28a6eb34c82103ab078a0841b022e2e5e430585
Gerrit-Change-Number: 56883
Gerrit-PatchSet: 1
Gerrit-Owner: Ricardo Quesada <ricardoq@google.com>
Gerrit-MessageType: newchange