Ricardo Quesada has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/56866 )
Change subject: elogtool: add "clear" command ......................................................................
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: I7ea64ea748ee4c3647b0256be51203464a54c2dd 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, 160 insertions(+), 1 deletion(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/66/56866/1
diff --git a/src/commonlib/bsd/elog.c b/src/commonlib/bsd/elog.c index 6c927aa..a538dd3 100644 --- a/src/commonlib/bsd/elog.c +++ b/src/commonlib/bsd/elog.c @@ -44,3 +44,56 @@ // 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; +} \ No newline at end of file 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..4b05f6c 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" @@ -111,6 +113,76 @@ 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; + + /* + * We calcualte the size of the "used" buffer, needed for ELOG_TYPE_LOG_CLEAR. + * Then we overwritte the entire buffer with ELOG_TYPE_EOL. + * Finally we 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; + + /* Fallthrough */ + } + + buffer_delete(&buf); + return ret; +}
int main(int argc, char **argv) { @@ -157,5 +229,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..ccec32b 100644 --- a/util/cbfstool/eventlog.c +++ b/util/cbfstool/eventlog.c @@ -634,3 +634,27 @@ eventlog_printf_ignore_separator_once = 1; eventlog_printf("\n"); } + +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..e968e83 100644 --- a/util/cbfstool/eventlog.h +++ b/util/cbfstool/eventlog.h @@ -3,8 +3,11 @@ #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_