114 lines
3.8 KiB
C
114 lines
3.8 KiB
C
|
#include <lib/env.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <lib/nvram.h>
|
||
|
#include <debug.h>
|
||
|
#include <platform.h>
|
||
|
#include <arch.h>
|
||
|
|
||
|
|
||
|
#define BREADCRUMB_BUFFER_SIZE 256 // This is arbitrarily sized, should be large enough for
|
||
|
// sensible options of key/value
|
||
|
#define BREADCRUMB_MIN_SIZE 3 // Smallest size of a breadcrumb
|
||
|
|
||
|
typedef struct {
|
||
|
char* buffer; // Storage for the breadcrumbs
|
||
|
int buffer_len; // Length of breadcrumb buffer
|
||
|
int wrpos; // Current write position
|
||
|
} breadcrumb_store_t;
|
||
|
|
||
|
static bool initialized = false;
|
||
|
|
||
|
breadcrumb_store_t breadcrumb_store;
|
||
|
|
||
|
|
||
|
static char* bc_cur_pos (void)
|
||
|
{
|
||
|
ASSERT(breadcrumb_store.wrpos <= breadcrumb_store.buffer_len);
|
||
|
return &breadcrumb_store.buffer[breadcrumb_store.wrpos];
|
||
|
}
|
||
|
|
||
|
static int bc_remaining (void)
|
||
|
{
|
||
|
ASSERT(breadcrumb_store.wrpos <= breadcrumb_store.buffer_len);
|
||
|
return breadcrumb_store.buffer_len - breadcrumb_store.wrpos;
|
||
|
}
|
||
|
|
||
|
void _platform_init_breadcrumbs_internal(void)
|
||
|
{
|
||
|
if (!initialized) {
|
||
|
breadcrumb_store.buffer = malloc(BREADCRUMB_BUFFER_SIZE);
|
||
|
breadcrumb_store.wrpos = 0;
|
||
|
breadcrumb_store.buffer_len = BREADCRUMB_BUFFER_SIZE;
|
||
|
|
||
|
initialized = (breadcrumb_store.buffer != NULL);
|
||
|
dprintf(DEBUG_INFO, "breadcrumb store initialized at %p\n", breadcrumb_store.buffer);
|
||
|
platform_record_breadcrumb_marker("BOOT");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void _platform_record_breadcrumb_internal(const char* key, const char* val)
|
||
|
{
|
||
|
if (initialized && bc_remaining() > BREADCRUMB_MIN_SIZE) {
|
||
|
int count = (int)snprintf(bc_cur_pos(), bc_remaining(), "%s=%s, ", key, val);
|
||
|
|
||
|
if (count > 0)
|
||
|
breadcrumb_store.wrpos += strlen(bc_cur_pos());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void _platform_record_breadcrumb_marker_internal(const char* val)
|
||
|
{
|
||
|
if (initialized && bc_remaining() > BREADCRUMB_MIN_SIZE) {
|
||
|
int count = (int)snprintf(bc_cur_pos(), bc_remaining(), "<%s> ", val);
|
||
|
|
||
|
if (count > 0)
|
||
|
breadcrumb_store.wrpos += strlen(bc_cur_pos());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void _platform_record_breadcrumb_int_internal(const char* key, int val)
|
||
|
{
|
||
|
if (initialized && bc_remaining() > BREADCRUMB_MIN_SIZE) {
|
||
|
int count = (int)snprintf(bc_cur_pos(), bc_remaining(), "%s=%d, ", key, val);
|
||
|
|
||
|
if (count > 0)
|
||
|
breadcrumb_store.wrpos += strlen(bc_cur_pos());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void _platform_commit_breadcrumbs_internal(const char* envvar)
|
||
|
{
|
||
|
if (initialized) {
|
||
|
platform_record_breadcrumb_marker("DONE");
|
||
|
// We expect this buffer to always be NULL terminated since it was built using
|
||
|
// snprintf(), but just to be sure, make sure the end of the buffer is terminated.
|
||
|
breadcrumb_store.buffer[breadcrumb_store.buffer_len - 1] = '\0';
|
||
|
|
||
|
const char* existing_breadcrumbs = env_get(envvar);
|
||
|
if (existing_breadcrumbs) {
|
||
|
dprintf(DEBUG_INFO, "Existing breadcrumbs found: '%s'\n", existing_breadcrumbs);
|
||
|
// If there's already iBoot breadcrumbs, we should preserve them chronologically
|
||
|
// (earliest first). Since we need to prepend, we might as well swap it with
|
||
|
// a new buffer.
|
||
|
if (bc_remaining() < (int)strlen(existing_breadcrumbs)) {
|
||
|
// Existing breadcrumbs would not fit. Drop the oldest breadcrumbs first
|
||
|
existing_breadcrumbs += ((int)strlen(existing_breadcrumbs) - bc_remaining());
|
||
|
}
|
||
|
char* tmp_buf = malloc(BREADCRUMB_BUFFER_SIZE);
|
||
|
if (tmp_buf) {
|
||
|
int count = snprintf(tmp_buf, BREADCRUMB_BUFFER_SIZE, "%s%s", existing_breadcrumbs, breadcrumb_store.buffer);
|
||
|
if (count >= 0 && count < BREADCRUMB_BUFFER_SIZE)
|
||
|
breadcrumb_store.wrpos = count;
|
||
|
else
|
||
|
breadcrumb_store.wrpos = 0;
|
||
|
|
||
|
free(breadcrumb_store.buffer);
|
||
|
breadcrumb_store.buffer = tmp_buf;
|
||
|
}
|
||
|
}
|
||
|
dprintf(DEBUG_INFO, "Committing breadcrumbs [used %d of %d bytes]: Setting '%s'='%s'\n", breadcrumb_store.wrpos, breadcrumb_store.buffer_len, envvar, breadcrumb_store.buffer);
|
||
|
env_set(envvar, breadcrumb_store.buffer, ENV_PERSISTENT);
|
||
|
nvram_save();
|
||
|
initialized=false; // Stop recording breadcrumbs and make redundant commits a no-op.
|
||
|
}
|
||
|
}
|