diff --git a/libsel4debug/CMakeLists.txt b/libsel4debug/CMakeLists.txt index 850cc5aad..0efe4885e 100644 --- a/libsel4debug/CMakeLists.txt +++ b/libsel4debug/CMakeLists.txt @@ -72,4 +72,13 @@ target_include_directories( sel4debug PUBLIC include "arch_include/${KernelArch}" sel4_arch_include/${KernelSel4Arch} ) -target_link_libraries(sel4debug PUBLIC muslc sel4 utils PRIVATE sel4debug_Config sel4_autoconf) +target_link_libraries( + sel4debug + PUBLIC + muslc + sel4 + utils + sel4vka + sel4vspace + PRIVATE sel4debug_Config sel4_autoconf +) diff --git a/libsel4debug/include/sel4debug/logbuffer.h b/libsel4debug/include/sel4debug/logbuffer.h new file mode 100644 index 000000000..687968def --- /dev/null +++ b/libsel4debug/include/sel4debug/logbuffer.h @@ -0,0 +1,100 @@ +/* + * Copyright 2020, Data61 + * Commonwealth Scientific and Industrial Research Organisation (CSIRO) + * ABN 41 687 119 230. + * + * This software may be distributed and modified according to the terms of + * the BSD 2-Clause license. Note that NO WARRANTY is provided. + * See "LICENSE_BSD2.txt" for details. + * + * @TAG(DATA61_BSD) + */ + +#pragma once + +/* Utilities for working with the debug log buffer */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Allocates and maps a new kernel log buffer. + * + * The large frame used for the kernel log buffer is placed in the frame + * argument and can be mapped into other address spaces. + */ +static int debug_log_buffer_init(vka_t *vka, vspace_t *vspace, vka_object_t *frame, seL4_LogBuffer *buffer) +{ +#ifdef CONFIG_KERNEL_DEBUG_LOG_BUFFER + int err; + void *volatile vaddr; + + err = vka_alloc_frame(vka, seL4_LogBufferBits, frame); + if (err != 0) { + return err; + } + + err = seL4_BenchmarkSetLogBuffer(frame->cptr); + if (err != 0) { + ZF_LOGE("Failed to set debug log buffer frame using cap %lu.\n", frame->cptr); + return err; + } + + vaddr = vspace_map_pages(vspace, &frame->cptr, NULL, seL4_AllRights, 1, seL4_LogBufferBits, 1); + if (vaddr == NULL) { + ZF_LOGE("Failed to map log buffer into VMM addrspace.\n"); + return -1; + } + + *buffer = seL4_LogBuffer_new(vaddr); + + ZF_LOGD("Log buffer (cptr %lu) mapped to vaddr %p.\n", frame->cptr, vaddr); + + return seL4_NoError; +#else + *buffer = seL4_LogBuffer_new(NULL); + return seL4_NoError; +#endif +} + +/* + * Reset the debug log buffer. + * + * All new events will be placed at the start of the buffer. + */ +static int debug_log_buffer_reset(seL4_LogBuffer *buffer) +{ + seL4_LogBuffer_reset(buffer); +#ifdef CONFIG_KERNEL_DEBUG_LOG_BUFFER + return seL4_BenchmarkResetLog(); +#else + return seL4_NoError; +#endif +} + +/* + * Finalise the debug log buffer. + * + * All new events will be placed at the start of the buffer. + */ +static void debug_log_buffer_finalise(seL4_LogBuffer *buffer) +{ +#ifdef CONFIG_KERNEL_DEBUG_LOG_BUFFER + seL4_LogBuffer_setSize(buffer, seL4_BenchmarkFinalizeLog()); +#else + seL4_LogBuffer_reset(buffer); +#endif +} + +/* + * Dump the debug log to the given output. + * + * This will also finalise the kernel log buffer, stopping subsequent + * output. + */ +int debug_log_buffer_dump_cbor64(seL4_LogBuffer *buffer, base64_t *streamer); diff --git a/libsel4debug/src/logbuffer.c b/libsel4debug/src/logbuffer.c new file mode 100644 index 000000000..546c7a3fc --- /dev/null +++ b/libsel4debug/src/logbuffer.c @@ -0,0 +1,121 @@ +/* + * Copyright 2020, Data61 + * Commonwealth Scientific and Industrial Research Organisation (CSIRO) + * ABN 41 687 119 230. + * + * This software may be distributed and modified according to the terms of + * the BSD 2-Clause license. Note that NO WARRANTY is provided. + * See "LICENSE_BSD2.txt" for details. + * + * @TAG(DATA61_BSD) + */ + +/* Utilities for working with the debug log buffer */ + +#include +#include +#include + +/* Strings tracked and compressed in the string domain */ +char *identifiers[] = { + /* Event type */ + "type", + "Unknown", + + /* None event */ + "None", + + /* Entry and exit events */ + "Entry", + "Exit", + "cpu-id", + "timestamp", + + /* NULL array terminator */ + NULL, +}; + +/* Number of fields in event other than the type fields */ +size_t field_count[seL4_NumLogTypeIds] = { + [seL4_Log_TypeId(None)] = 0, + [seL4_Log_TypeId(Entry)] = 2, + [seL4_Log_TypeId(Exit)] = 2, +}; + +/* + * Dump a single event as JSON + */ +static int event_cbor64(seL4_LogEvent *event, cbor64_domain_t *domain, base64_t *streamer) +{ + int event_type = seL4_LogEvent_type(event); + + /* Display the type */ + cbor64_map_length(streamer, field_count[event_type] + 1); + cbor64_utf8_ref(streamer, domain, "type"); + + switch (event_type) { + case seL4_Log_TypeId(None): { + cbor64_utf8_ref(streamer, domain, "None"); + break; + } + + case seL4_Log_TypeId(Entry): { + seL4_Log_Type(Entry) *entry = seL4_Log_Cast(Entry)event; + cbor64_utf8_ref(streamer, domain, "Entry"); + + cbor64_utf8_ref(streamer, domain, "cpu-id"); + cbor64_uint(streamer, event->data); + + cbor64_utf8_ref(streamer, domain, "timestamp"); + cbor64_uint(streamer, entry->timestamp); + break; + } + + case seL4_Log_TypeId(Exit): { + seL4_Log_Type(Exit) *exit = seL4_Log_Cast(Exit)event; + cbor64_utf8_ref(streamer, domain, "Exit"); + + cbor64_utf8_ref(streamer, domain, "cpu-id"); + cbor64_uint(streamer, event->data); + + cbor64_utf8_ref(streamer, domain, "timestamp"); + cbor64_uint(streamer, exit->timestamp); + break; + } + + default: { + cbor64_utf8_ref(streamer, domain, "Unknown"); + break; + } + } + + return 0; +} + +/* + * Dump the debug log to the given output + */ +int debug_log_buffer_dump_cbor64(seL4_LogBuffer *buffer, base64_t *streamer) +{ + /* Start a new string domain */ + cbor64_domain_t domain; + cbor64_string_ref_domain(streamer, identifiers, &domain); + + /* Stop logging events */ + debug_log_buffer_finalise(buffer); + + /* Create a copy of the log buffer to traverse the events */ + seL4_LogBuffer cursor = *buffer; + + cbor64_array_start(streamer); + seL4_LogEvent *event = seL4_LogBuffer_next(&cursor); + while (event != NULL) { + int err = event_cbor64(event, &domain, streamer); + if (err != 0) { + return err; + } + + event = seL4_LogBuffer_next(&cursor); + } + return cbor64_array_end(streamer); +}