Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
cmake_minimum_required(VERSION 3.5)

# (Not part of the boilerplate)
set(BOOTLOADER_EXTRA_COMPONENT_DIRS "${CMAKE_SOURCE_DIR}/bootloader_components")
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
# set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)

Expand Down
3 changes: 3 additions & 0 deletions bootloader_components/log_capture/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
idf_component_register(SRCS "bootloader_log_capture.c"
INCLUDE_DIRS "."
PRIV_REQUIRES bootloader_support)
80 changes: 80 additions & 0 deletions bootloader_components/log_capture/bootloader_log_capture.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#include "esp_attr.h"
#include "esp_log.h"
#include "bootloader_common.h"
#include "esp_rom_sys.h"
#include <stdarg.h>
#include <stdio.h>

#define RTC_LOG_MAGIC 0x80071062
#define RTC_LOG_BUFFER_SIZE (4 * 1024)

typedef struct {
uint32_t magic;
uint32_t checksum;
uint32_t len;
} rtc_log_header_t;

#define RTC_LOG_BASE_ADDR 0x600FE000 /* Start of RTC Fast RAM on ESP32-S3 */
#define S_RTC_HEADER (*(rtc_log_header_t *)RTC_LOG_BASE_ADDR)
#define S_RTC_BUFFER ((char *)(RTC_LOG_BASE_ADDR + sizeof(rtc_log_header_t)))

static uint32_t calculate_rtc_checksum(const rtc_log_header_t *h)
{
uint32_t checksum = h->magic;
checksum ^= h->len;
return checksum;
}

void rtc_write(const char *data, size_t len)
{
if (S_RTC_HEADER.magic != RTC_LOG_MAGIC || S_RTC_HEADER.checksum != calculate_rtc_checksum(&S_RTC_HEADER)) {
S_RTC_HEADER.magic = RTC_LOG_MAGIC;
S_RTC_HEADER.len = 0;
S_RTC_HEADER.checksum = calculate_rtc_checksum(&S_RTC_HEADER);
}

size_t available = RTC_LOG_BUFFER_SIZE - S_RTC_HEADER.len;
size_t to_copy = (len < available) ? len : available;
if (to_copy > 0) {
memcpy(&S_RTC_BUFFER[S_RTC_HEADER.len], data, to_copy);
S_RTC_HEADER.len += to_copy;
S_RTC_HEADER.checksum = calculate_rtc_checksum(&S_RTC_HEADER);
}
}

/* Character-level console interception via Archive Override */

typedef void (*putc_func_t)(char);

// Core ROM functions for character output on ESP32-S3
#define ROM_ETS_INSTALL_PUTC1 ((void (*)(putc_func_t))0x400005dc)
#define ROM_ETS_WRITE_CHAR_UART ((void (*)(char))0x400006b4)

extern void esp_rom_install_uart_printf(void);

/**
* Custom character output function that writes to both the original
* console channel (UART/USB) and our RTC log buffer.
*/
static void captured_putc(char c)
{
// Forward to original hardware output (UART0 default)
ROM_ETS_WRITE_CHAR_UART(c);

// Capture to RTC RAM
rtc_write(&c, 1);
}

/**
* Capture-aware override of the bootloader's console initialization.
* We will alias the standard 'bootloader_console_init' to this function
* in the linker script.
*/
void capture_bootloader_console_init(void)
{
// 1. Call standard ROM initialization for UART
esp_rom_install_uart_printf();

// 2. Hijack the character writer on channel 1
ROM_ETS_INSTALL_PUTC1(captured_putc);
}
3 changes: 3 additions & 0 deletions bootloader_components/log_capture/force_link.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/* Force the linker to include these symbols from the log_capture component */
EXTERN(rtc_write)
bootloader_console_init = capture_bootloader_console_init;
5 changes: 5 additions & 0 deletions bootloader_components/log_capture/project_include.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
if(BOOTLOADER_BUILD)
# Force the linker to include our symbols using a linker script EXTERN directive.
# This property is evaluated by the bootloader subproject.
idf_build_set_property(BOOTLOADER_LINKER_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/force_link.ld" APPEND)
endif()
2 changes: 0 additions & 2 deletions main/http_server/axe-os/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import { ScoreboardComponent } from './components/scoreboard/scoreboard.componen
import { ThemeConfigComponent } from './components/design/theme-config.component';
import { DesignComponent } from './components/design/design.component';
import { AppLayoutModule } from './layout/app.layout.module';
import { ANSIPipe } from './pipes/ansi.pipe';
import { DateAgoPipe } from './pipes/date-ago.pipe';
import { HashSuffixPipe } from './pipes/hash-suffix.pipe';
import { DiffSuffixPipe } from './pipes/diff-suffix.pipe';
Expand Down Expand Up @@ -66,7 +65,6 @@ const components = [
declarations: [
...components,

ANSIPipe,
DateAgoPipe,
SwarmComponent,
ScoreboardComponent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ <h2 class="mb-0 h-3rem">
</div>

<div id="logs" #scrollContainer>
<div *ngFor="let log of logs" [ngClass]="log.className">₿ {{log.text | ANSI}}</div>
<div *ngFor="let log of logs" [ngClass]="log.className">₿ {{log.text}}</div>
</div>
</form>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@
}
}

.ansi-red { color: #ff0000; }
.ansi-green { color: #00ff00; }
.ansi-yellow { color: #ffff00; }
.ansi-blue { color: #0000ff; }
.ansi-magenta { color: #ff00ff; }
.ansi-cyan { color: #00ffff; }
.ansi-white { color: #ffffff; }
.log-E { color: #ff0000; font-weight: bold; }
.log-W { color: #ffff00; }
.log-I { color: #00ff00; }
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { provideRouter } from '@angular/router';
import { ANSIPipe } from 'src/app/pipes/ansi.pipe';
import { InputTextModule } from 'primeng/inputtext';
import { CommonModule } from '@angular/common';
import { SystemApiService } from 'src/app/services/system.service';
Expand All @@ -17,7 +16,7 @@ describe('LogsComponent', () => {

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [LogsComponent, ANSIPipe],
declarations: [LogsComponent],
imports: [
CommonModule,
ButtonModule,
Expand Down
25 changes: 10 additions & 15 deletions main/http_server/axe-os/src/app/components/logs/logs.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,20 +58,16 @@ export class LogsComponent implements OnInit, OnDestroy, AfterViewChecked {
const completeLine = this.logBuffer;
this.logBuffer = '';

const matches = completeLine.matchAll(/\[(\d+;\d+)m(.*?)(?=\[|\n|$)/g);
let className = 'ansi-white'; // default color

for (const match of matches) {
const colorCode = match[1].split(';')[1];
switch (colorCode) {
case '31': className = 'ansi-red'; break;
case '32': className = 'ansi-green'; break;
case '33': className = 'ansi-yellow'; break;
case '34': className = 'ansi-blue'; break;
case '35': className = 'ansi-magenta'; break;
case '36': className = 'ansi-cyan'; break;
case '37': className = 'ansi-white'; break;
}
let className = '';
if (completeLine.length > 0) {
const prefix = completeLine[0];
switch(prefix) {
case 'E':
case 'W':
case 'I':
className = `log-${prefix}`;
break;
}
}

// Get current filter value from form
Expand Down Expand Up @@ -127,5 +123,4 @@ export class LogsComponent implements OnInit, OnDestroy, AfterViewChecked {
this.scrollContainer.nativeElement.scrollTo({ left: 0, top: this.scrollContainer.nativeElement.scrollHeight, behavior: 'smooth' });
}
}

}
8 changes: 0 additions & 8 deletions main/http_server/axe-os/src/app/pipes/ansi.pipe.spec.ts

This file was deleted.

13 changes: 0 additions & 13 deletions main/http_server/axe-os/src/app/pipes/ansi.pipe.ts

This file was deleted.

84 changes: 80 additions & 4 deletions main/log_buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,23 @@
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "esp_heap_caps.h"
#include "esp_bit_defs.h"
#include "esp_private/startup_internal.h"

#include "log_buffer.h"
#include "websocket.h"
#include "esp_cache.h"
#include "esp_psram.h"
#include "esp_system.h"
#include "esp_private/system_internal.h"
#include "esp_rom_sys.h"

static const char * TAG = "log_buffer";

// Increment this when log_buffer_header_t struct changes
#define LOG_BUFFER_MAGIC 0xB17A5E10
#define RTC_LOG_MAGIC 0x80071062

typedef struct {
uint32_t magic;
Expand All @@ -34,9 +42,22 @@ static uint32_t calculate_header_checksum(const log_buffer_header_t *h)
return checksum;
}

static uint32_t calculate_rtc_checksum(const rtc_log_header_t *h)
{
uint32_t checksum = h->magic;
checksum ^= h->len;
return checksum;
}

static EXT_RAM_NOINIT_ATTR log_buffer_header_t s_header;
static EXT_RAM_NOINIT_ATTR char s_buffer[LOG_BUFFER_SIZE];

static RTC_NOINIT_ATTR char s_rtc_log_area[RTC_LOG_BUFFER_SIZE + sizeof(rtc_log_header_t)];
#define RTC_LOG_BUFFER_INTERNAL (s_rtc_log_area)

#define S_RTC_HEADER (*(rtc_log_header_t *)RTC_LOG_BUFFER_INTERNAL)
#define S_RTC_BUFFER ((char *)(RTC_LOG_BUFFER_INTERNAL + sizeof(rtc_log_header_t)))

static SemaphoreHandle_t s_log_mutex = NULL;
static char s_vprintf_buffer[2048];

Expand Down Expand Up @@ -107,20 +128,65 @@ static int log_buffer_vprintf(const char *format, va_list args)
if (output) {
ring_write(output, needed);
websocket_log_notify();
fputs(output, stdout);

if (output != s_vprintf_buffer) {
free(output);
}
} else {
/* Emergency fallback if absolutely out of memory */
vprintf(format, args);
}

// Standard UART handover: use the original format and args
vprintf(format, args);

xSemaphoreGiveRecursive(s_log_mutex);
return needed;
}

static int log_buffer_vprintf_early(const char *format, va_list args)
{
// NO MUTEX here, we are in early boot
va_list args_copy;
va_copy(args_copy, args);
int needed = vsnprintf(s_vprintf_buffer, sizeof(s_vprintf_buffer), format, args_copy);
va_end(args_copy);

if (needed > 0) {
// Write to RTC buffer
size_t available = RTC_LOG_BUFFER_SIZE - S_RTC_HEADER.len;
size_t to_copy = (needed < available) ? needed : available;
if (to_copy > 0) {
memcpy(&S_RTC_BUFFER[S_RTC_HEADER.len], s_vprintf_buffer, to_copy);
S_RTC_HEADER.len += to_copy;
S_RTC_HEADER.checksum = calculate_rtc_checksum(&S_RTC_HEADER);
}
// Also print to UART
vprintf(format, args);
}
return needed;
}

void log_buffer_early_init(void)
{
// By using the 's_rtc_log_area' variable with RTC_NOINIT_ATTR,
// the linker automatically reserves this space from the RTC heap.

// Check RTC header
if (S_RTC_HEADER.magic != RTC_LOG_MAGIC || S_RTC_HEADER.checksum != calculate_rtc_checksum(&S_RTC_HEADER)) {
S_RTC_HEADER.magic = RTC_LOG_MAGIC;
S_RTC_HEADER.len = 0;
S_RTC_HEADER.checksum = calculate_rtc_checksum(&S_RTC_HEADER);
}

esp_log_set_vprintf(log_buffer_vprintf_early);
}

// Use ESP_SYSTEM_INIT_FN to ensure this is called as early as possible
// during application startup, before heap/PSRAM initialization logs are lost.
ESP_SYSTEM_INIT_FN(log_buffer_early_init_hook, CORE, BIT(0), 100)
{
log_buffer_early_init();
return ESP_OK;
}

void log_buffer_init(void)
{
s_log_mutex = xSemaphoreCreateRecursiveMutex();
Expand Down Expand Up @@ -148,6 +214,16 @@ void log_buffer_init(void)
ring_write(reboot_msg, strlen(reboot_msg));
}

// Drain RTC buffer into main buffer
if (S_RTC_HEADER.magic == RTC_LOG_MAGIC && S_RTC_HEADER.checksum == calculate_rtc_checksum(&S_RTC_HEADER)) {
if (S_RTC_HEADER.len > 0 && S_RTC_HEADER.len <= RTC_LOG_BUFFER_SIZE) {
ring_write(S_RTC_BUFFER, S_RTC_HEADER.len);
// Clear RTC buffer for next use
S_RTC_HEADER.len = 0;
S_RTC_HEADER.checksum = calculate_rtc_checksum(&S_RTC_HEADER);
}
}

esp_log_set_vprintf(log_buffer_vprintf);
}

Expand Down
11 changes: 11 additions & 0 deletions main/log_buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@
#include <stddef.h>
#include <stdint.h>

#define LOG_BUFFER_SIZE (512 * 1024) /* 512 KB */
#define RTC_LOG_BUFFER_SIZE (4 * 1024) /* 4 KB */
#define RTC_LOG_BASE_ADDR 0x600FE000 /* Start of RTC Fast RAM on ESP32-S3 */

typedef struct {
uint32_t magic;
uint32_t checksum;
uint32_t len;
} rtc_log_header_t;

void log_buffer_early_init(void);
void log_buffer_init(void);
uint64_t log_buffer_get_total_written(void);

Expand Down
3 changes: 2 additions & 1 deletion main/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ static const char * TAG = "bitaxe";

void app_main(void)
{
log_buffer_init();

if (esp_psram_is_initialized()) {
GLOBAL_STATE.psram_is_available = true;
log_buffer_init();
}

ESP_LOGI(TAG, "Welcome to the bitaxe - FOSS || GTFO!");
Expand Down
1 change: 0 additions & 1 deletion sdkconfig.defaults
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ CONFIG_ESP_WIFI_11KV_SUPPORT=y
CONFIG_FREERTOS_HZ=1000
CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y
CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y
CONFIG_LOG_COLORS=y
CONFIG_LWIP_MAX_SOCKETS=26
CONFIG_LWIP_IPV6=y
CONFIG_LWIP_IPV6_AUTOCONFIG=y
Expand Down
Loading