Magic‐1 Computer Bootloader Analysis - retrotruestory/M1DEV GitHub Wiki
-
UART Communication (Dual Ports)
- Primary UART (UART0) at 0xFFF0 for console
- Secondary UART (UART1) at 0xFFE0 for auxiliary
- Configurable baud rates (1200-38400)
- Hardware flow control (RTS/CTS)
- Software flow control (XON/XOFF)
-
IDE/CF Storage Interface
- Support for Master/Slave IDE devices
- Compact Flash in True IDE mode
- 8-bit data transfer mode for CF
- CHS and LBA addressing modes
- 512-byte sector operations
-
Real-Time Clock
- Base address 0xFFD0
- Time/date registers
- Interrupt control
- Hold/busy status monitoring
-
Paging System
- 22-bit physical address space
- 2KB page size
- Page attributes (Present, Writeable, SRAM/Device, Wait states)
- Split code/data pages (32 each)
- Device memory mapping in last page
- Initial Setup
void setup_address_space() {
// 1. Set up initial page table mapping
// 2. Enable paging
// 3. Copy ROM to SRAM (0x20000-0x27FFF)
// 4. Remap supervisor space
}
- Hardware Initialization
- UART configuration
- RTC setup
- IDE/CF detection and initialization
- Page table setup
- Post codes for debug (0x01-0x0A)
- Boot Image Management
typedef struct {
int pid;
char name[16];
char free;
char loaded;
char default_image;
char split;
} t_process;
- Image Management
- Support for 8 boot images
- Intel HEX file loading
- Split/unified code/data spaces
- PID-based image isolation
- Default image selection
- Storage Operations
- Sector read/write abstraction
- Drive identification
- Error handling and recovery
- CHS/LBA translation
- Security
- Password protection for critical operations
- Command access control
- System state validation
S - Set active drive
P - Show image table
3 - Display drive info
L - Load boot image (Intel hex)
Z - Set default boot image
D - Delete boot image
B - Boot an image
R - Read image table from disk
W - Write boot images to disk
Q - Toggle pre-boot pause
- Boot Image Loading
void read_intel_hex(unsigned int slot) {
// 1. Parse Intel HEX records
// 2. Validate checksums
// 3. Write to appropriate memory space
// 4. Handle split/unified spaces
}
- Image Staging
void stage_boot_image(int slot) {
// 1. Map transfer pages
// 2. Copy image to physical memory
// 3. Set up page tables
// 4. Handle device page mapping
}
- Drive Operations
void read_sector(int sector, char *buf, int drive) {
// 1. Check drive presence
// 2. Handle CF vs IDE
// 3. Calculate CHS if needed
// 4. Perform transfer
}
- Hardware Errors
- IDE status checking
- Timeout monitoring
- Error recovery procedures
- Diagnostic reporting
- Data Validation
- Checksum verification
- Address range checking
- Device presence validation
- Command parameter validation
- Hardware
- Magic-1 CPU
- Dual UART ports
- IDE/CF interface
- Real-time clock
- Front panel switches
- Memory
- ROM for initial boot
- SRAM for execution
- Device memory space
- Storage
- IDE drive or CF card
- Formatted with boot sectors
- Image table structure
This analysis provides the core information needed to implement a compatible bootloader. The code is well-structured with clear separation of hardware abstraction, boot management, and user interface components.
- Physical Address Space: 22-bit (4MB)
- Page Size: 2KB fixed
- Memory Map:
0x00000-0x1FFFF: SRAM (128KB)
0x20000-0x2FFFF: ROM Copy Area
0xFFA00-0xFFFF0: Device Space
#define UART0_BASE 0xFFF0 // Console
#define UART1_BASE 0xFFE0 // Auxiliary
Register Map:
typedef struct {
uint8_t DATA; // 0x0: Data I/O
uint8_t IER; // 0x1: Interrupt Enable
union {
uint8_t IIR; // 0x2: Interrupt ID (Read)
uint8_t FCR; // 0x2: FIFO Control (Write)
};
uint8_t LCR; // 0x3: Line Control
uint8_t MCR; // 0x4: Modem Control
uint8_t LSR; // 0x5: Line Status
uint8_t MSR; // 0x6: Modem Status
uint8_t SCRATCH; // 0x7: Scratch Register
} UART_Registers;
stateDiagram-v2
[*] --> PowerOn
PowerOn --> InitHardware
InitHardware --> LoadPageTable
LoadPageTable --> CopyROM
CopyROM --> CommandLoop
CommandLoop --> BootImage
BootImage --> [*]
typedef struct {
unsigned int present : 1; // 0x8000
unsigned int writeable : 1; // 0x4000
unsigned int sram : 1; // 0x2000
unsigned int wait : 1; // 0x1000
unsigned int address : 12; // Physical page number
} PageTableEntry;
typedef struct {
char name[PNAME_SIZE];
uint8_t split; // Code/Data split flag
uint16_t entry_point;
uint32_t load_addr;
uint32_t size;
uint8_t loaded;
uint8_t default_boot;
} BootImage;
#define NUM_IMAGES 8
typedef BootImage ImageTable[NUM_IMAGES];
- Paging System:
void paging_control(void) {
/* Page Table Structure:
* - 64 entries per process
* - 32 code pages (0x0000-0xFFFF)
* - 32 data pages (0x0000-0xFFFF)
* - Last page reserved for devices
*/
// Sample page table initialization
for(int i = 0; i < 64; i++) {
if(i < 32) {
// Code pages
write_code_pte(i, PAGE_PRESENT | PAGE_SRAM |
(physical_page << 12));
} else {
// Data pages
write_data_pte(i - 32, PAGE_PRESENT | PAGE_WRITEABLE |
PAGE_SRAM | (physical_page << 12));
}
}
}
- Hardware Initialization Sequence:
void init_hardware(void) {
// Post code for tracking boot progress
to_post(0x01);
// Configure UARTs
init_uart(UART0_BASE, B38400);
init_uart(UART1_BASE, B9600);
// Reset and detect IDE/CF
ide_reset();
// Initialize RTC
rtc_init();
to_post(0x0A); // Hardware init complete
}
This concludes Part 1 of the analysis, focusing on core architecture.
The bootloader initializes in stages defined in bcrt0.s
:
_start:
_interrupt_vector:
sbr over_ivec
defw unhandled_exception ; IRQ5 (RTC)
defw unhandled_exception ; IRQ4 (unassigned)
defw unhandled_exception ; IRQ3 (UART0)
defw unhandled_exception ; IRQ2 (UART1)
defw unhandled_exception ; IRQ1 (IDE)
defw unhandled_exception ; IRQ0 (unassigned)
The page table management is implemented through these key functions:
typedef struct page_table_entry {
uint16_t flags;
uint32_t physical_addr;
} pte_t;
void write_page_table_entry(uint8_t pid, uint8_t page_num, pte_t *entry) {
uint32_t pte_addr = (pid << 7) | (page_num & 0x3F);
uint16_t *pt_base = (uint16_t *)0x10000; // Page table base
pt_base[pte_addr] = entry->flags |
((entry->physical_addr >> 11) & 0x0FFF);
}
void map_device_page(uint8_t pid) {
pte_t device_pte = {
.flags = PAGE_PRESENT | PAGE_DEVICE | PAGE_WAIT,
.physical_addr = 0xFF000
};
write_page_table_entry(pid, 63, &device_pte);
}
Boot images are managed using a standardized format:
#define IMAGE_HEADER_MAGIC 0x4D31 // "M1"
typedef struct {
uint16_t magic; // Magic number for validation
uint16_t entry_point; // Code entry point
uint32_t code_size; // Size of code segment
uint32_t data_size; // Size of data segment
uint8_t split; // Split code/data flag
uint8_t reserved[7]; // Padding for alignment
char name[16]; // Image name
uint16_t checksum; // Header checksum
} boot_image_header_t;
The IDE/CF interface implementation:
#define IDE_BASE 0xFFB0
#define IDE_DATA (IDE_BASE + 0)
#define IDE_ERROR (IDE_BASE + 1)
#define IDE_SECCOUNT (IDE_BASE + 2)
#define IDE_SECNUM (IDE_BASE + 3)
#define IDE_CYLLOW (IDE_BASE + 4)
#define IDE_CYLHIGH (IDE_BASE + 5)
#define IDE_DRVHEAD (IDE_BASE + 6)
#define IDE_STATUS (IDE_BASE + 7)
int read_sector(uint32_t lba, uint8_t *buffer) {
// Select drive and wait for ready
outb(IDE_DRVHEAD, 0xE0 | ((lba >> 24) & 0x0F));
while(!(inb(IDE_STATUS) & 0x40)); // Wait for DRDY
// Set up LBA registers
outb(IDE_SECCOUNT, 1);
outb(IDE_SECNUM, lba & 0xFF);
outb(IDE_CYLLOW, (lba >> 8) & 0xFF);
outb(IDE_CYLHIGH, (lba >> 16) & 0xFF);
// Issue READ command
outb(IDE_STATUS, 0x20);
// Wait for DRQ and transfer data
while(!(inb(IDE_STATUS) & 0x08));
for(int i = 0; i < 512; i++) {
buffer[i] = inb(IDE_DATA);
}
return (inb(IDE_STATUS) & 0x01) ? -1 : 0; // Check for error
}
The bootloader implements a command processor that handles user input and executes corresponding functions:
typedef struct command {
char key; // Single character command
void (*handler)(void); // Command handler function
const char *description; // Help text
uint8_t requires_password; // Security flag
} command_t;
static const command_t commands[] = {
{'S', handle_set_drive, "Set active drive", 0},
{'P', handle_show_images, "Show image table", 0},
{'L', handle_load_image, "Load boot image", 1},
{'B', handle_boot_image, "Boot an image", 0},
{'D', handle_delete_image, "Delete image", 1},
{0, NULL, NULL, 0} // Terminator
};
void command_loop(void) {
char cmd;
while(1) {
print_prompt();
cmd = get_char(CONSOLE);
for(const command_t *cp = commands; cp->key; cp++) {
if(toupper(cmd) == cp->key) {
if(cp->requires_password && !verify_password()) {
printf("Access denied\n");
break;
}
cp->handler();
break;
}
}
}
}
The bootloader uses a robust UART communication layer for user interaction:
typedef struct uart_interface {
volatile uint8_t *base;
uint16_t tx_head;
uint16_t tx_tail;
uint16_t rx_head;
uint16_t rx_tail;
uint8_t tx_buffer[256];
uint8_t rx_buffer[256];
} uart_t;
static uart_t r_uart0 = { .base = (uint8_t*)UART0_BASE };
static uart_t r_uart1 = { .base = (uint8_t*)UART1_BASE };
int uart_putchar(uart_t *uart, char c) {
while(!(uart->base[UART_LSR] & UART_XMIT_READY)) {
// Wait for transmitter
}
uart->base[UART_DATA] = c;
return 0;
}
int uart_getchar(uart_t *uart) {
while(!(uart->base[UART_LSR] & UART_DATA_READY)) {
// Wait for receiver
}
return uart->base[UART_DATA];
}
The Intel HEX file parser for loading boot images:
#define MAX_RECORD_SIZE 32
typedef struct {
uint8_t length;
uint16_t address;
uint8_t type;
uint8_t data[MAX_RECORD_SIZE];
uint8_t checksum;
} hex_record_t;
int parse_hex_record(char *line, hex_record_t *record) {
uint8_t computed_checksum = 0;
if(line[0] != ':') return -1;
// Parse record length
record->length = hex_to_byte(line + 1);
computed_checksum += record->length;
// Parse address
record->address = hex_to_word(line + 3);
computed_checksum += (record->address >> 8) & 0xFF;
computed_checksum += record->address & 0xFF;
// Parse record type
record->type = hex_to_byte(line + 7);
computed_checksum += record->type;
// Parse data bytes
for(int i = 0; i < record->length; i++) {
record->data[i] = hex_to_byte(line + 9 + (i * 2));
computed_checksum += record->data[i];
}
// Verify checksum
record->checksum = hex_to_byte(line + 9 + (record->length * 2));
computed_checksum = (uint8_t)(-(int8_t)computed_checksum);
return (computed_checksum == record->checksum) ? 0 : -1;
}
The bootloader implements a secure password verification system for protected commands:
#define PASSWORD_HASH_SIZE 32
#define SALT_SIZE 16
typedef struct {
uint8_t hash[PASSWORD_HASH_SIZE];
uint8_t salt[SALT_SIZE];
} password_store_t;
static password_store_t stored_password;
bool verify_password(void) {
char password[64];
uint8_t computed_hash[PASSWORD_HASH_SIZE];
printf("Enter password: ");
get_string(password, sizeof(password), ECHO_PASSWORD);
compute_hash(password, stored_password.salt, computed_hash);
return (memcmp(computed_hash, stored_password.hash,
PASSWORD_HASH_SIZE) == 0);
}
typedef enum {
ERR_NONE = 0,
ERR_HARDWARE = -1,
ERR_TIMEOUT = -2,
ERR_CHECKSUM = -3,
ERR_INVALID_IMAGE = -4,
ERR_WRITE_PROTECTED = -5
} error_code_t;
typedef struct {
error_code_t code;
const char *message;
uint8_t fatal;
} error_info_t;
static const error_info_t error_table[] = {
{ERR_NONE, "Success", 0},
{ERR_HARDWARE, "Hardware failure", 1},
{ERR_TIMEOUT, "Operation timeout", 0},
{ERR_CHECKSUM, "Checksum error", 0},
{ERR_INVALID_IMAGE, "Invalid boot image", 0},
{ERR_WRITE_PROTECTED, "Write protected", 0}
};
void handle_error(error_code_t code) {
for(const error_info_t *ep = error_table; ep->message; ep++) {
if(ep->code == code) {
printf("Error: %s\n", ep->message);
// Log error to diagnostic port
diagnostic_log(ep->message, ep->code);
if(ep->fatal) {
printf("Fatal error - system halted\n");
while(1) {
// System halt
asm volatile("halt");
}
}
return;
}
}
}
#define WATCHDOG_BASE 0xFFC0
#define WATCHDOG_TIMEOUT 1000 // milliseconds
typedef struct {
volatile uint16_t counter;
volatile uint16_t control;
} watchdog_t;
static watchdog_t *const watchdog = (watchdog_t*)WATCHDOG_BASE;
void init_watchdog(void) {
watchdog->control = 0x0001; // Enable watchdog
watchdog->counter = WATCHDOG_TIMEOUT;
}
void pet_watchdog(void) {
watchdog->counter = WATCHDOG_TIMEOUT;
}
void watchdog_isr(void) {
// Handle watchdog timeout
handle_error(ERR_TIMEOUT);
}
#define MAX_LOG_ENTRIES 32
typedef struct {
uint32_t timestamp;
error_code_t code;
char message[64];
} log_entry_t;
static struct {
log_entry_t entries[MAX_LOG_ENTRIES];
uint8_t head;
uint8_t count;
} error_log;
void diagnostic_log(const char *message, error_code_t code) {
log_entry_t *entry = &error_log.entries[error_log.head];
entry->timestamp = get_rtc_time();
entry->code = code;
strncpy(entry->message, message, sizeof(entry->message) - 1);
error_log.head = (error_log.head + 1) % MAX_LOG_ENTRIES;
if(error_log.count < MAX_LOG_ENTRIES) {
error_log.count++;
}
}
#pragma pack(1)
typedef struct {
uint16_t magic; // Magic number 0x4D31 ("M1")
uint16_t version; // Format version
uint32_t load_address; // Load address for image
uint32_t entry_point; // Execution start address
uint32_t code_size; // Size of code segment
uint32_t data_size; // Size of data segment
uint8_t flags; // Image flags
char name[16]; // Image name (null-terminated)
uint32_t checksum; // CRC32 of image
} BootImageHeader;
#pragma pack()
static bool validate_boot_image(const BootImageHeader* header) {
if (header->magic != MAGIC_SIGNATURE) {
log_error("Invalid magic number in boot image");
return false;
}
uint32_t computed_crc = crc32(0, (uint8_t*)header + sizeof(header->checksum),
sizeof(BootImageHeader) - sizeof(header->checksum));
if (computed_crc != header->checksum) {
log_error("Boot image checksum mismatch");
return false;
}
// Validate memory boundaries
if (header->load_address + header->code_size + header->data_size > MAX_MEMORY) {
log_error("Image exceeds memory boundaries");
return false;
}
return true;
}
typedef struct {
uint32_t start_addr;
uint32_t size;
bool is_code;
} MemoryRegion;
static bool allocate_image_memory(const BootImageHeader* header,
MemoryRegion* code_region,
MemoryRegion* data_region) {
// Allocate code segment
code_region->start_addr = header->load_address;
code_region->size = header->code_size;
code_region->is_code = true;
// Set up page tables for code region
for (uint32_t addr = code_region->start_addr;
addr < code_region->start_addr + code_region->size;
addr += PAGE_SIZE) {
if (!map_page(addr, PAGE_PRESENT | PAGE_EXECUTE)) {
return false;
}
}
// Similar setup for data region
data_region->start_addr = code_region->start_addr + code_region->size;
data_region->size = header->data_size;
data_region->is_code = false;
return true;
}
typedef struct {
uint32_t offset;
uint32_t type;
uint32_t addend;
} RelocationEntry;
static bool relocate_image(uint8_t* image_base,
const RelocationEntry* relocations,
size_t reloc_count) {
for (size_t i = 0; i < reloc_count; i++) {
uint32_t* target = (uint32_t*)(image_base + relocations[i].offset);
switch (relocations[i].type) {
case RELOC_ABSOLUTE:
*target = relocations[i].addend + (uint32_t)image_base;
break;
case RELOC_RELATIVE:
*target = relocations[i].addend +
(*target - (uint32_t)image_base);
break;
default:
log_error("Unknown relocation type");
return false;
}
}
return true;
}
void execute_boot_image(const BootImageHeader* header) {
typedef void (*entry_point_t)(void);
entry_point_t entry = (entry_point_t)header->entry_point;
// Disable interrupts
asm volatile("cli");
// Switch to image's page table
switch_page_table(header->page_table);
// Jump to entry point
entry();
// Should never return
log_error("Boot image returned to loader");
while(1) { }
}
The system initialization is handled by a modular set of functions starting with the primary boot sequence:
.section .text
.global _start
_start:
# Initialize stack pointer
li sp, 0x8000
# Clear BSS section
la a0, __bss_start
la a1, __bss_end
call clear_bss
# Jump to C initialization
j main_init
struct MemoryTiming {
uint8_t refresh_rate;
uint8_t cas_latency;
uint8_t ras_timing;
uint8_t wait_states;
};
static void init_memory_controller(void) {
volatile uint16_t* const MEM_CTRL = (uint16_t*)0xFF00;
const struct MemoryTiming timing = {
.refresh_rate = 15, // 15ms refresh
.cas_latency = 2, // CAS Latency 2
.ras_timing = 3, // RAS timing
.wait_states = 1 // 1 wait state
};
*MEM_CTRL = (timing.refresh_rate << 12) |
(timing.cas_latency << 8) |
(timing.ras_timing << 4) |
timing.wait_states;
}
typedef struct {
uint16_t base_addr;
uint16_t baud_rate;
uint8_t data_bits;
uint8_t stop_bits;
uint8_t parity;
} UartConfig;
static void configure_uart(const UartConfig* config) {
// Set divisor latch
uint16_t divisor = UART_CLOCK / (16 * config->baud_rate);
outb(config->base_addr + LCR, 0x80); // Enable DLAB
outb(config->base_addr + DLL, divisor & 0xFF);
outb(config->base_addr + DLH, (divisor >> 8) & 0xFF);
// Configure line settings
uint8_t lcr = ((config->data_bits - 5) & 0x3) |
((config->stop_bits - 1) << 2) |
(config->parity << 3);
outb(config->base_addr + LCR, lcr);
// Enable FIFOs
outb(config->base_addr + FCR, 0x07);
}
#define NUM_VECTORS 16
typedef struct {
uint32_t vector_addr;
void (*handler)(void);
uint8_t priority;
} InterruptVector;
static void setup_interrupt_vectors(void) {
static const InterruptVector vectors[] = {
{ 0x00, nmi_handler, 0 },
{ 0x04, uart0_handler, 2 },
{ 0x08, uart1_handler, 2 },
{ 0x0C, timer_handler, 1 },
{ 0x10, ide_handler, 3 },
{ 0x14, rtc_handler, 4 }
};
for (int i = 0; i < sizeof(vectors)/sizeof(vectors[0]); i++) {
// Write vector address and handler
*(uint32_t*)vectors[i].vector_addr = (uint32_t)vectors[i].handler;
// Set interrupt priority
set_interrupt_priority(i, vectors[i].priority);
}
}
#define CLOCK_BASE 0xFF20
#define PLL_CTRL (CLOCK_BASE + 0)
#define CLK_DIV (CLOCK_BASE + 2)
struct ClockConfig {
uint8_t pll_mult; // PLL multiplier (2-16)
uint8_t pll_div; // PLL divider (1-8)
uint8_t sys_div; // System clock divider
uint8_t periph_div; // Peripheral clock divider
};
static void configure_system_clocks(const struct ClockConfig* config) {
// Configure PLL
uint16_t pll_ctrl = (config->pll_mult << 8) | config->pll_div;
outw(PLL_CTRL, pll_ctrl);
// Wait for PLL lock
while (!(inw(PLL_CTRL) & 0x8000)) {
continue;
}
// Set clock dividers
uint16_t div_ctrl = (config->sys_div << 8) | config->periph_div;
outw(CLK_DIV, div_ctrl);
}
#define IDE_BASE 0xFFB0
#define IDE_DATA (IDE_BASE + 0)
#define IDE_ERROR (IDE_BASE + 1)
#define IDE_FEATURES (IDE_BASE + 1)
#define IDE_SECCOUNT (IDE_BASE + 2)
#define IDE_SECTOR (IDE_BASE + 3)
#define IDE_CYLLOW (IDE_BASE + 4)
#define IDE_CYLHIGH (IDE_BASE + 5)
#define IDE_DRVHEAD (IDE_BASE + 6)
#define IDE_STATUS (IDE_BASE + 7)
#define IDE_COMMAND (IDE_BASE + 7)
typedef struct {
uint8_t present; // Device presence flag
uint8_t is_cf; // CompactFlash flag
uint16_t cylinders; // Number of cylinders
uint8_t heads; // Number of heads
uint8_t sectors; // Sectors per track
uint32_t capacity; // Total capacity in sectors
} ide_device_t;
static ide_device_t devices[2] = {0}; // Master and Slave
static int identify_device(uint8_t device) {
uint16_t buffer[256];
uint8_t status, cl, ch;
// Select device
outb(IDE_DRVHEAD, device ? 0xB0 : 0xA0);
delay_ms(1);
// Check for CompactFlash signature
cl = inb(IDE_CYLLOW);
ch = inb(IDE_CYLHIGH);
if (cl == 0x14 && ch == 0xEB) {
devices[device].is_cf = 1;
}
// Issue IDENTIFY command
outb(IDE_COMMAND, 0xEC);
status = inb(IDE_STATUS);
if (status == 0) {
return -1; // Device not present
}
// Wait for data ready
while (((status = inb(IDE_STATUS)) & 0x80) != 0);
// Read identification space
for (int i = 0; i < 256; i++) {
buffer[i] = inw(IDE_DATA);
}
// Parse identification data
devices[device].present = 1;
devices[device].cylinders = buffer[1];
devices[device].heads = buffer[3];
devices[device].sectors = buffer[6];
devices[device].capacity = buffer[60] | (buffer[61] << 16);
return 0;
}
#define SECTOR_SIZE 512
typedef enum {
TRANSFER_READ,
TRANSFER_WRITE
} transfer_mode_t;
static int transfer_sectors(uint8_t device, uint32_t lba,
uint8_t count, void* buffer,
transfer_mode_t mode) {
uint8_t cmd = (mode == TRANSFER_READ) ? 0x20 : 0x30;
// Select device and write parameters
outb(IDE_DRVHEAD, (device ? 0xF0 : 0xE0) | ((lba >> 24) & 0x0F));
outb(IDE_SECCOUNT, count);
outb(IDE_SECTOR, lba & 0xFF);
outb(IDE_CYLLOW, (lba >> 8) & 0xFF);
outb(IDE_CYLHIGH, (lba >> 16) & 0xFF);
// Issue command
outb(IDE_COMMAND, cmd);
for (int i = 0; i < count; i++) {
// Wait for DRQ
while ((inb(IDE_STATUS) & 0x08) == 0) {
if (inb(IDE_STATUS) & 0x01) {
return -1; // Error
}
}
// Transfer data
if (mode == TRANSFER_READ) {
for (int j = 0; j < SECTOR_SIZE/2; j++) {
((uint16_t*)buffer)[j] = inw(IDE_DATA);
}
} else {
for (int j = 0; j < SECTOR_SIZE/2; j++) {
outw(IDE_DATA, ((uint16_t*)buffer)[j]);
}
}
buffer = (uint8_t*)buffer + SECTOR_SIZE;
}
return 0;
}
The Magic-1 uses a two-level page table system with separate code and data spaces.
#define PAGE_SIZE 2048 // 2KB pages
#define PAGE_TABLE_ENTRIES 64 // 32 code + 32 data pages
#define PAGE_PRESENT 0x8000
#define PAGE_WRITEABLE 0x4000
#define PAGE_SRAM 0x2000
#define PAGE_WAIT 0x1000
typedef struct {
uint16_t entries[PAGE_TABLE_ENTRIES];
} PageTable;
typedef struct {
uint16_t ptb; // Page Table Base
PageTable *table; // Pointer to page table
uint8_t pid; // Process ID (0-7)
} MMUContext;
Here's the core MMU implementation:
static MMUContext current_context;
static uint32_t translate_address(uint16_t virtual_addr, bool is_code) {
uint8_t page_index = (virtual_addr >> 11) & 0x1F;
uint16_t offset = virtual_addr & 0x7FF;
// Add 32 to page_index for data pages
if (!is_code) {
page_index += 32;
}
uint16_t pte = current_context.table->entries[page_index];
if (!(pte & PAGE_PRESENT)) {
handle_page_fault(virtual_addr);
return 0xFFFFFFFF;
}
uint32_t physical_page = pte & 0x0FFF;
return (physical_page << 11) | offset;
}
void mmu_switch_context(uint8_t pid) {
current_context.pid = pid;
current_context.ptb = pid << 7; // PTB = PID * 128
current_context.table = (PageTable*)(0x10000 + current_context.ptb);
// Update hardware PTB register
outw(MMU_PTB_REG, current_context.ptb);
}
int mmu_map_page(uint8_t page_num, uint32_t physical_addr, uint16_t flags) {
if (page_num >= PAGE_TABLE_ENTRIES) {
return -1;
}
uint16_t pte = (physical_addr >> 11) & 0x0FFF;
pte |= flags & 0xF000;
current_context.table->entries[page_num] = pte;
return 0;
}
void handle_page_fault(uint16_t fault_addr) {
uint8_t fault_page = (fault_addr >> 11) & 0x3F;
bool is_code = fault_page < 32;
// Log the fault
printf("Page fault: addr=0x%04X page=%d %s\n",
fault_addr, fault_page, is_code ? "code" : "data");
if (is_code) {
// Handle code page fault
load_code_page(fault_page);
} else {
// Handle data page fault
allocate_data_page(fault_page - 32);
}
}
static void load_code_page(uint8_t page_num) {
// Allocate physical page
uint32_t phys_addr = allocate_physical_page();
// Load page contents from boot image
load_page_from_image(page_num, (void*)phys_addr);
// Map the page
mmu_map_page(page_num, phys_addr,
PAGE_PRESENT | PAGE_SRAM);
}
The boot image begins with a header that defines the image characteristics and loading requirements:
#pragma pack(push, 1)
typedef struct {
uint16_t magic; /* 'M1' (0x4D31) */
uint8_t version; /* Format version (current: 1) */
uint8_t flags; /* Image flags */
uint32_t load_address; /* Base load address */
uint32_t entry_point; /* Execution entry point */
uint32_t code_size; /* Size of code segment */
uint32_t data_size; /* Size of data segment */
uint32_t bss_size; /* Size of BSS segment */
char name[16]; /* Image name (null-terminated) */
uint32_t checksum; /* CRC-32 of image content */
} BootImageHeader;
#pragma pack(pop)
Here's the core image loading functionality:
#include "boot_image.h"
#include "mmu.h"
#include "crc32.h"
#define MAX_IMAGE_SIZE (512 * 1024) /* 512KB maximum image size */
static uint8_t image_buffer[MAX_IMAGE_SIZE];
int load_boot_image(const char* image_name) {
BootImageHeader* header = (BootImageHeader*)image_buffer;
int status;
/* Read image from storage */
status = read_image_from_storage(image_name, image_buffer, MAX_IMAGE_SIZE);
if (status < 0) {
return status;
}
/* Validate header */
if (header->magic != 0x4D31) {
return -1; /* Invalid magic number */
}
/* Verify checksum */
uint32_t computed_crc = crc32(0,
image_buffer + sizeof(BootImageHeader),
header->code_size + header->data_size);
if (computed_crc != header->checksum) {
return -2; /* Checksum mismatch */
}
/* Map memory regions */
status = map_image_memory(header);
if (status < 0) {
return status;
}
/* Copy segments to memory */
copy_segments(header);
return 0;
}
static int map_image_memory(const BootImageHeader* header) {
uint32_t code_pages = (header->code_size + PAGE_SIZE - 1) / PAGE_SIZE;
uint32_t data_pages = (header->data_size + PAGE_SIZE - 1) / PAGE_SIZE;
uint32_t bss_pages = (header->bss_size + PAGE_SIZE - 1) / PAGE_SIZE;
/* Map code pages */
for (uint32_t i = 0; i < code_pages; i++) {
uint32_t phys_addr = allocate_physical_page();
if (phys_addr == 0xFFFFFFFF) {
return -1; /* Out of memory */
}
mmu_map_page(i, phys_addr,
PAGE_PRESENT | PAGE_SRAM | PAGE_WAIT);
}
/* Map data and BSS pages */
for (uint32_t i = 0; i < data_pages + bss_pages; i++) {
uint32_t phys_addr = allocate_physical_page();
if (phys_addr == 0xFFFFFFFF) {
return -1;
}
mmu_map_page(32 + i, phys_addr,
PAGE_PRESENT | PAGE_SRAM | PAGE_WRITEABLE | PAGE_WAIT);
}
return 0;
}
#define DEBUG_UART_BASE 0xFFE0
#define DEBUG_BUFFER_SIZE 256
typedef struct {
char buffer[DEBUG_BUFFER_SIZE];
uint16_t head;
uint16_t tail;
uint8_t echo_enabled;
} DebugConsole;
#include "debug_console.h"
static const struct {
const char* cmd;
void (*handler)(int argc, char* argv[]);
const char* help;
} debug_commands[] = {
{"dump", cmd_memory_dump, "Display memory contents"},
{"regs", cmd_show_regs, "Show CPU registers"},
{"mmu", cmd_show_mmu, "Display MMU status"},
{"trace", cmd_set_trace, "Set instruction trace"},
{"break", cmd_breakpoint, "Set/clear breakpoint"},
{"step", cmd_single_step, "Single step execution"},
{NULL, NULL, NULL}
};
struct DebugState {
uint32_t breakpoints[4];
uint8_t bp_count;
uint8_t trace_enabled;
uint8_t single_step;
uint16_t last_pc;
} debug_state;
void cmd_memory_dump(int argc, char* argv[]) {
uint32_t addr = parse_hex_arg(argv[1]);
uint16_t count = (argc > 2) ? parse_hex_arg(argv[2]) : 16;
for (uint16_t i = 0; i < count; i += 16) {
printf("%04X: ", addr + i);
// Display hex values
for (int j = 0; j < 16; j++) {
printf("%02X ", read_memory_byte(addr + i + j));
if (j == 7) printf("- ");
}
// Display ASCII representation
printf(" |");
for (int j = 0; j < 16; j++) {
uint8_t byte = read_memory_byte(addr + i + j);
printf("%c", (byte >= 32 && byte <= 126) ? byte : '.');
}
printf("|\n");
}
}
void trace_instruction(uint16_t pc, uint16_t opcode) {
static char disasm_buffer[64];
if (!debug_state.trace_enabled) {
return;
}
// Disassemble instruction
disassemble_instruction(pc, opcode, disasm_buffer);
// Display registers alongside instruction
printf("%04X: %-32s A=%04X B=%04X C=%04X SP=%04X\n",
pc, disasm_buffer,
get_register(REG_A),
get_register(REG_B),
get_register(REG_C),
get_register(REG_SP));
}
int set_breakpoint(uint16_t addr) {
if (debug_state.bp_count >= 4) {
printf("Error: Maximum breakpoints reached\n");
return -1;
}
// Save original instruction
uint16_t original = read_memory_word(addr);
// Insert breakpoint instruction (TRAP)
write_memory_word(addr, 0xFFFF);
// Store breakpoint info
debug_state.breakpoints[debug_state.bp_count++] =
(addr << 16) | original;
printf("Breakpoint set at %04X\n", addr);
return 0;
}
The debug framework provides essential tools for development and troubleshooting of the Magic-1 bootloader.
#define ERR_SUCCESS 0x00
#define ERR_HARDWARE 0x01
#define ERR_MEMORY 0x02
#define ERR_TIMEOUT 0x03
#define ERR_CHECKSUM 0x04
#define ERR_INVALID_IMAGE 0x05
#define ERR_IO 0x06
#define ERR_MMU 0x07
#define ERR_PROTECTION 0x08
typedef struct error_info {
uint8_t code;
const char* message;
uint8_t severity;
uint8_t recoverable;
} error_info_t;
static const error_info_t error_table[] = {
{ERR_SUCCESS, "Operation successful", 0, 1},
{ERR_HARDWARE, "Hardware failure", 3, 0},
{ERR_MEMORY, "Memory allocation failed", 2, 1},
{ERR_TIMEOUT, "Operation timeout", 1, 1},
{ERR_CHECKSUM, "Checksum verification failed", 2, 1},
{ERR_INVALID_IMAGE,"Invalid boot image format", 2, 1},
{ERR_IO, "I/O error", 2, 1},
{ERR_MMU, "MMU configuration error", 3, 0},
{ERR_PROTECTION, "Protection violation", 3, 0},
{0, NULL, 0, 0}
};
#include "errors.h"
#define MAX_ERROR_STACK 16
#define ERROR_LOG_SIZE 32
typedef struct {
uint32_t timestamp;
uint8_t error_code;
uint16_t pc;
uint8_t context;
} error_record_t;
static struct {
error_record_t log[ERROR_LOG_SIZE];
uint8_t log_head;
uint8_t log_count;
uint8_t error_stack[MAX_ERROR_STACK];
uint8_t stack_ptr;
} error_context;
void handle_error(uint8_t error_code) {
const error_info_t *info = NULL;
// Find error info
for(const error_info_t *ep = error_table; ep->message; ep++) {
if(ep->code == error_code) {
info = ep;
break;
}
}
if(!info) {
printf("Unknown error code: 0x%02X\n", error_code);
return;
}
// Log the error
error_record_t *record = &error_context.log[error_context.log_head];
record->timestamp = get_system_time();
record->error_code = error_code;
record->pc = get_current_pc();
record->context = get_current_context();
error_context.log_head = (error_context.log_head + 1) % ERROR_LOG_SIZE;
if(error_context.log_count < ERROR_LOG_SIZE)
error_context.log_count++;
// Push to error stack
if(error_context.stack_ptr < MAX_ERROR_STACK)
error_context.error_stack[error_context.stack_ptr++] = error_code;
// Handle based on severity
switch(info->severity) {
case 3: // Fatal
printf("FATAL ERROR: %s\n", info->message);
system_halt();
break;
case 2: // Severe
printf("ERROR: %s\n", info->message);
if(!info->recoverable)
system_restart();
break;
case 1: // Warning
printf("Warning: %s\n", info->message);
break;
default:
break;
}
}
Creates a centralized system for managing hardware settings and boot parameters.
#pragma once
#include <stdint.h>
typedef struct {
struct {
uint16_t base_memory; // Base memory size in KB
uint16_t extended_memory; // Extended memory size in KB
uint8_t num_ide_drives; // Number of IDE drives detected
uint8_t cf_card_present; // CompactFlash card status
uint8_t uart_ports; // Bitmap of available UART ports
} hardware;
struct {
uint32_t load_address; // Boot image load address
uint8_t auto_boot; // Auto-boot flag
uint8_t boot_delay; // Boot delay in seconds
char default_image[16];// Default boot image name
} boot;
struct {
uint8_t debug_level; // Debug output level
uint16_t console_baud; // Console UART baud rate
uint8_t memory_wait; // Memory wait states
uint8_t ide_mode; // IDE interface mode
} settings;
} SystemConfig;
extern SystemConfig system_config;
#include "system_config.h"
#define MEMORY_TEST_PATTERN 0x55AA
#define MAX_MEMORY_SIZE 0x20000 // 128KB
static int detect_memory_size(void) {
uint16_t *mem_ptr = (uint16_t *)0;
uint16_t size = 0;
for(; size < MAX_MEMORY_SIZE; size += 1024) {
mem_ptr[size/2] = MEMORY_TEST_PATTERN;
if(mem_ptr[size/2] != MEMORY_TEST_PATTERN) {
break;
}
}
return size;
}
static void detect_uart_ports(void) {
static const uint16_t uart_bases[] = {0xFFF0, 0xFFE0};
uint8_t ports = 0;
for(int i = 0; i < 2; i++) {
// Write to scratch register
outb(uart_bases[i] + 7, 0x55);
if(inb(uart_bases[i] + 7) == 0x55) {
ports |= (1 << i);
}
}
system_config.hardware.uart_ports = ports;
}
int initialize_system_config(void) {
// Clear configuration structure
memset(&system_config, 0, sizeof(SystemConfig));
// Detect memory size
system_config.hardware.base_memory = detect_memory_size();
// Detect UART ports
detect_uart_ports();
// Detect IDE/CF devices
system_config.hardware.num_ide_drives = detect_ide_devices();
system_config.hardware.cf_card_present = detect_cf_card();
// Set default settings
system_config.settings.console_baud = 9600;
system_config.settings.debug_level = 1;
system_config.settings.memory_wait = 1;
return 0;
}
#define CONFIG_SECTOR_ADDR 0x1F000
#define CONFIG_MAGIC 0x4D31 // "M1"
typedef struct {
uint16_t magic;
uint16_t version;
uint16_t checksum;
SystemConfig config;
} ConfigBlock;
int save_system_config(void) {
ConfigBlock block;
block.magic = CONFIG_MAGIC;
block.version = 1;
memcpy(&block.config, &system_config, sizeof(SystemConfig));
// Calculate checksum
block.checksum = calculate_checksum(&block.config, sizeof(SystemConfig));
// Write to storage
return write_sector(CONFIG_SECTOR_ADDR, &block, sizeof(ConfigBlock));
}
int load_system_config(void) {
ConfigBlock block;
if(read_sector(CONFIG_SECTOR_ADDR, &block, sizeof(ConfigBlock)) != 0) {
return -1;
}
if(block.magic != CONFIG_MAGIC ||
block.checksum != calculate_checksum(&block.config, sizeof(SystemConfig))) {
return -1;
}
memcpy(&system_config, &block.config, sizeof(SystemConfig));
return 0;
}
Implements a modular driver system for hardware devices.
#pragma once
typedef enum {
DEVICE_UART,
DEVICE_IDE,
DEVICE_RTC,
DEVICE_CF,
DEVICE_MAX
} device_type_t;
typedef struct device_ops {
int (*init)(void *config);
int (*read)(void *buf, size_t count);
int (*write)(const void *buf, size_t count);
int (*ioctl)(int cmd, void *arg);
void (*shutdown)(void);
} device_ops_t;
typedef struct device_driver {
const char *name;
device_type_t type;
device_ops_t ops;
void *private_data;
uint8_t initialized;
} device_driver_t;
#include "driver_core.h"
#define MAX_DRIVERS 8
static struct {
device_driver_t *drivers[MAX_DRIVERS];
uint8_t driver_count;
} driver_manager;
int register_driver(device_driver_t *driver) {
if (driver_manager.driver_count >= MAX_DRIVERS) {
return -1;
}
driver_manager.drivers[driver_manager.driver_count++] = driver;
return 0;
}
device_driver_t *get_driver(device_type_t type) {
for (int i = 0; i < driver_manager.driver_count; i++) {
if (driver_manager.drivers[i]->type == type) {
return driver_manager.drivers[i];
}
}
return NULL;
}
#include "driver_core.h"
#define UART_RX_BUFFER_SIZE 256
#define UART_TX_BUFFER_SIZE 256
typedef struct {
uint16_t base_addr;
uint8_t rx_buffer[UART_RX_BUFFER_SIZE];
uint8_t tx_buffer[UART_TX_BUFFER_SIZE];
uint16_t rx_head, rx_tail;
uint16_t tx_head, tx_tail;
} uart_private_t;
static int uart_init(void *config) {
uart_private_t *priv = (uart_private_t *)config;
// Initialize UART hardware
outb(priv->base_addr + 3, 0x80); // Enable DLAB
outb(priv->base_addr + 0, 0x0C); // Set baud rate divisor
outb(priv->base_addr + 1, 0x00);
outb(priv->base_addr + 3, 0x03); // 8N1
outb(priv->base_addr + 2, 0x07); // Enable FIFOs
return 0;
}
static device_driver_t uart_driver = {
.name = "UART",
.type = DEVICE_UART,
.ops = {
.init = uart_init,
.read = uart_read,
.write = uart_write,
.ioctl = uart_ioctl,
.shutdown = uart_shutdown
}
};
This implements the core device driver framework for the Magic-1 bootloader.
The Magic-1 system uses a table-driven interrupt management system.
#define NUM_INTERRUPTS 8
#define VECTOR_TABLE_BASE 0x0000
typedef struct {
void (*handler)(void);
uint8_t priority;
uint8_t enabled;
uint32_t count;
const char* name;
} interrupt_vector_t;
static interrupt_vector_t interrupt_vectors[NUM_INTERRUPTS] = {
{ nmi_handler, 0, 1, 0, "NMI" },
{ timer_handler, 1, 1, 0, "Timer" },
{ uart0_handler, 2, 1, 0, "UART0" },
{ uart1_handler, 2, 1, 0, "UART1" },
{ ide_handler, 3, 1, 0, "IDE" },
{ rtc_handler, 4, 1, 0, "RTC" },
{ fault_handler, 0, 1, 0, "Fault" },
{ trap_handler, 0, 1, 0, "Trap" }
};
#define TIMER_BASE 0xFFD0
#define TIMER_COUNT (TIMER_BASE + 0)
#define TIMER_CONTROL (TIMER_BASE + 2)
#define TIMER_STATUS (TIMER_BASE + 4)
#define TIMER_ENABLE 0x01
#define TIMER_INTERRUPT 0x02
#define TIMER_RELOAD 0x04
typedef struct {
uint16_t reload_value;
uint32_t tick_count;
void (*callback)(void);
} timer_context_t;
static timer_context_t timer_ctx;
void init_timer(uint16_t reload_value, void (*callback)(void)) {
timer_ctx.reload_value = reload_value;
timer_ctx.callback = callback;
timer_ctx.tick_count = 0;
// Configure timer hardware
outw(TIMER_COUNT, reload_value);
outw(TIMER_CONTROL, TIMER_ENABLE | TIMER_INTERRUPT | TIMER_RELOAD);
}
void timer_handler(void) {
timer_ctx.tick_count++;
// Clear interrupt
outb(TIMER_STATUS, 0);
if (timer_ctx.callback) {
timer_ctx.callback();
}
}
#define INT_CTRL_BASE 0xFFC0
#define INT_MASK (INT_CTRL_BASE + 0)
#define INT_STATUS (INT_CTRL_BASE + 2)
#define INT_ACK (INT_CTRL_BASE + 4)
void enable_interrupt(uint8_t irq) {
uint16_t mask = inw(INT_MASK);
mask |= (1 << irq);
outw(INT_MASK, mask);
}
void disable_interrupt(uint8_t irq) {
uint16_t mask = inw(INT_MASK);
mask &= ~(1 << irq);
outw(INT_MASK, mask);
}
void acknowledge_interrupt(uint8_t irq) {
outw(INT_ACK, 1 << irq);
}
// Main interrupt dispatcher
void interrupt_dispatch(void) {
uint16_t status = inw(INT_STATUS);
for (int i = 0; i < NUM_INTERRUPTS; i++) {
if (status & (1 << i)) {
if (interrupt_vectors[i].enabled && interrupt_vectors[i].handler) {
interrupt_vectors[i].count++;
interrupt_vectors[i].handler();
}
acknowledge_interrupt(i);
}
}
}
Implements the main boot sequence controller:
typedef enum {
BOOT_STATE_INIT,
BOOT_STATE_HARDWARE_DETECT,
BOOT_STATE_MEMORY_TEST,
BOOT_STATE_LOAD_CONFIG,
BOOT_STATE_MOUNT_STORAGE,
BOOT_STATE_LOAD_IMAGE,
BOOT_STATE_EXECUTE
} boot_state_t;
typedef struct {
boot_state_t current_state;
uint8_t retry_count;
uint32_t start_time;
char error_message[64];
} boot_context_t;
#include "boot_manager.h"
#include "hardware_detect.h"
#include "memory_test.h"
#include "storage.h"
static boot_context_t boot_ctx;
int execute_boot_sequence(void) {
int status = 0;
// Initialize boot context
boot_ctx.current_state = BOOT_STATE_INIT;
boot_ctx.retry_count = 0;
boot_ctx.start_time = get_rtc_time();
while (boot_ctx.current_state != BOOT_STATE_EXECUTE) {
switch (boot_ctx.current_state) {
case BOOT_STATE_INIT:
status = initialize_core_hardware();
if (status == 0) {
boot_ctx.current_state = BOOT_STATE_HARDWARE_DETECT;
}
break;
case BOOT_STATE_HARDWARE_DETECT:
status = detect_hardware_configuration();
if (status == 0) {
boot_ctx.current_state = BOOT_STATE_MEMORY_TEST;
}
break;
case BOOT_STATE_MEMORY_TEST:
status = perform_memory_test();
if (status == 0) {
boot_ctx.current_state = BOOT_STATE_LOAD_CONFIG;
}
break;
case BOOT_STATE_LOAD_CONFIG:
status = load_system_configuration();
if (status == 0) {
boot_ctx.current_state = BOOT_STATE_MOUNT_STORAGE;
}
break;
case BOOT_STATE_MOUNT_STORAGE:
status = mount_boot_storage();
if (status == 0) {
boot_ctx.current_state = BOOT_STATE_LOAD_IMAGE;
}
break;
case BOOT_STATE_LOAD_IMAGE:
status = load_boot_image();
if (status == 0) {
boot_ctx.current_state = BOOT_STATE_EXECUTE;
}
break;
default:
sprintf(boot_ctx.error_message, "Invalid boot state: %d",
boot_ctx.current_state);
return -1;
}
if (status != 0) {
handle_boot_error(status);
if (++boot_ctx.retry_count >= MAX_BOOT_RETRIES) {
return -1;
}
}
}
return 0;
}
The storage system provides a unified interface for different storage devices:
#define SECTOR_SIZE 512
#define MAX_DEVICES 4
#define MAX_PARTITIONS 16
typedef enum {
STORAGE_IDE,
STORAGE_CF,
STORAGE_ROM
} storage_type_t;
typedef struct {
uint32_t start_sector;
uint32_t num_sectors;
uint8_t type;
uint8_t bootable;
} partition_entry_t;
typedef struct storage_device {
storage_type_t type;
uint8_t id;
uint32_t sector_count;
uint16_t sector_size;
// Device operations
int (*read_sector)(struct storage_device *dev, uint32_t sector, void *buffer);
int (*write_sector)(struct storage_device *dev, uint32_t sector, const void *buffer);
int (*ioctl)(struct storage_device *dev, int cmd, void *arg);
// Partition table
partition_entry_t partitions[MAX_PARTITIONS];
uint8_t partition_count;
// Device-specific data
void *private_data;
} storage_device_t;
#include "storage.h"
static struct {
storage_device_t *devices[MAX_DEVICES];
uint8_t device_count;
storage_device_t *boot_device;
} storage_manager;
int register_storage_device(storage_device_t *device) {
if (storage_manager.device_count >= MAX_DEVICES) {
return -1;
}
// Initialize device
if (scan_partitions(device) != 0) {
return -2;
}
storage_manager.devices[storage_manager.device_count++] = device;
// Set as boot device if bootable partition found
for (int i = 0; i < device->partition_count; i++) {
if (device->partitions[i].bootable) {
storage_manager.boot_device = device;
break;
}
}
return 0;
}
int read_storage_sectors(storage_device_t *dev,
uint32_t start_sector,
uint32_t count,
void *buffer) {
if (!dev || !dev->read_sector) {
return -1;
}
uint8_t *buf = (uint8_t *)buffer;
for (uint32_t i = 0; i < count; i++) {
int status = dev->read_sector(dev, start_sector + i,
buf + (i * dev->sector_size));
if (status != 0) {
return status;
}
}
return 0;
}
#define MBR_SIGNATURE 0xAA55
#define PARTITION_ENTRY_OFFSET 0x1BE
typedef struct {
uint8_t boot_flag;
uint8_t start_head;
uint16_t start_sector_cyl;
uint8_t type;
uint8_t end_head;
uint16_t end_sector_cyl;
uint32_t start_sector;
uint32_t num_sectors;
} __attribute__((packed)) mbr_partition_t;
int scan_partitions(storage_device_t *dev) {
uint8_t mbr[SECTOR_SIZE];
mbr_partition_t *part;
// Read MBR
if (dev->read_sector(dev, 0, mbr) != 0) {
return -1;
}
// Verify MBR signature
if (*(uint16_t *)&mbr[510] != MBR_SIGNATURE) {
return -2;
}
// Parse partition entries
dev->partition_count = 0;
part = (mbr_partition_t *)&mbr[PARTITION_ENTRY_OFFSET];
for (int i = 0; i < 4; i++, part++) {
if (part->type == 0) {
continue;
}
dev->partitions[dev->partition_count].start_sector = part->start_sector;
dev->partitions[dev->partition_count].num_sectors = part->num_sectors;
dev->partitions[dev->partition_count].type = part->type;
dev->partitions[dev->partition_count].bootable =
(part->boot_flag == 0x80);
dev->partition_count++;
}
return 0;
}
The console interface provides interactive control over the bootloader operations.
typedef struct command_handler {
const char* command; // Command string
const char* description; // Help text
uint8_t min_args; // Minimum arguments required
uint8_t max_args; // Maximum arguments allowed
int (*handler)(int argc, char* argv[]); // Command function
uint8_t requires_auth; // Whether authentication is required
} command_handler_t;
#define MAX_COMMAND_LENGTH 32
#define MAX_ARGS 8
#define COMMAND_BUFFER_SIZE 256
static const command_handler_t command_table[] = {
{
.command = "boot",
.description = "Boot specified image",
.min_args = 1,
.max_args = 2,
.handler = cmd_boot_image,
.requires_auth = 1
},
{
.command = "list",
.description = "List available boot images",
.min_args = 0,
.max_args = 0,
.handler = cmd_list_images,
.requires_auth = 0
},
{
.command = "set",
.description = "Set configuration parameter",
.min_args = 2,
.max_args = 2,
.handler = cmd_set_config,
.requires_auth = 1
},
{
.command = "help",
.description = "Show available commands",
.min_args = 0,
.max_args = 1,
.handler = cmd_show_help,
.requires_auth = 0
},
{ NULL, NULL, 0, 0, NULL, 0 } // Terminator
};
int process_command(const char* input) {
char buffer[COMMAND_BUFFER_SIZE];
char* argv[MAX_ARGS];
int argc = 0;
// Copy input to avoid modifying original
strncpy(buffer, input, COMMAND_BUFFER_SIZE);
buffer[COMMAND_BUFFER_SIZE - 1] = '\0';
// Parse command line
char* token = strtok(buffer, " \t");
while (token && argc < MAX_ARGS) {
argv[argc++] = token;
token = strtok(NULL, " \t");
}
if (argc == 0) {
return 0; // Empty command
}
// Find command handler
for (const command_handler_t* cmd = command_table; cmd->command; cmd++) {
if (strcmp(argv[0], cmd->command) == 0) {
// Check argument count
if (argc - 1 < cmd->min_args || argc - 1 > cmd->max_args) {
printf("Error: Invalid number of arguments\n");
printf("Usage: %s %s\n", cmd->command, cmd->description);
return -1;
}
// Check authentication if required
if (cmd->requires_auth && !is_authenticated()) {
printf("Error: Authentication required\n");
return -1;
}
// Execute command
return cmd->handler(argc, argv);
}
}
printf("Error: Unknown command '%s'\n", argv[0]);
return -1;
}
The security system implements basic password protection and access control for sensitive bootloader operations.
#define AUTH_TOKEN_LENGTH 32
#define MAX_PASSWORD_LENGTH 64
#define SALT_LENGTH 16
typedef struct {
uint8_t token[AUTH_TOKEN_LENGTH];
uint32_t creation_time;
uint32_t expiry_time;
} auth_token_t;
typedef struct {
uint8_t hash[AUTH_TOKEN_LENGTH];
uint8_t salt[SALT_LENGTH];
uint8_t attempts;
uint32_t lockout_until;
} auth_config_t;
#include "auth.h"
#include "crypto/sha256.h"
#define MAX_LOGIN_ATTEMPTS 3
#define LOCKOUT_DURATION 300 // 5 minutes in seconds
static auth_config_t auth_config;
static auth_token_t current_token;
static uint8_t is_authenticated_flag = 0;
int authenticate(const char* password) {
uint8_t hash[AUTH_TOKEN_LENGTH];
uint32_t current_time = get_rtc_time();
// Check lockout
if (auth_config.lockout_until > current_time) {
printf("Account is locked. Try again in %d seconds\n",
auth_config.lockout_until - current_time);
return -1;
}
// Calculate password hash with salt
sha256_context ctx;
sha256_init(&ctx);
sha256_update(&ctx, (uint8_t*)password, strlen(password));
sha256_update(&ctx, auth_config.salt, SALT_LENGTH);
sha256_final(&ctx, hash);
// Verify hash
if (memcmp(hash, auth_config.hash, AUTH_TOKEN_LENGTH) == 0) {
// Success - generate new auth token
generate_random_bytes(current_token.token, AUTH_TOKEN_LENGTH);
current_token.creation_time = current_time;
current_token.expiry_time = current_time + 3600; // 1 hour validity
auth_config.attempts = 0;
is_authenticated_flag = 1;
return 0;
}
// Failed attempt
auth_config.attempts++;
if (auth_config.attempts >= MAX_LOGIN_ATTEMPTS) {
auth_config.lockout_until = current_time + LOCKOUT_DURATION;
auth_config.attempts = 0;
}
return -1;
}
#include "auth.h"
void generate_random_bytes(uint8_t* buffer, size_t length) {
// Use hardware RTC as entropy source
uint32_t rtc_value;
uint8_t entropy[4];
for (size_t i = 0; i < length; i++) {
if (i % 4 == 0) {
rtc_value = get_rtc_time();
memcpy(entropy, &rtc_value, 4);
}
buffer[i] = entropy[i % 4] ^ (i * 0x5A); // Simple mixing function
}
}
int change_password(const char* old_password, const char* new_password) {
if (!is_authenticated() || strlen(new_password) > MAX_PASSWORD_LENGTH) {
return -1;
}
// Verify old password first
if (authenticate(old_password) != 0) {
return -1;
}
// Generate new salt
generate_random_bytes(auth_config.salt, SALT_LENGTH);
// Hash new password
sha256_context ctx;
sha256_init(&ctx);
sha256_update(&ctx, (uint8_t*)new_password, strlen(new_password));
sha256_update(&ctx, auth_config.salt, SALT_LENGTH);
sha256_final(&ctx, auth_config.hash);
// Save configuration
save_auth_config();
return 0;
}
The HAL provides a uniform interface to hardware components while isolating platform-specific details.
#pragma once
#include <stdint.h>
typedef enum {
HAL_SUCCESS = 0,
HAL_ERROR_INVALID_PARAM = -1,
HAL_ERROR_NOT_INITIALIZED = -2,
HAL_ERROR_HARDWARE = -3,
HAL_ERROR_TIMEOUT = -4
} hal_status_t;
/* Core HAL interface functions */
typedef struct {
/* System Control */
void (*reset_system)(void);
void (*halt_system)(void);
void (*delay_ms)(uint32_t ms);
/* Memory Management */
void* (*mem_map)(uint32_t phys_addr, size_t size);
void (*mem_unmap)(void* addr);
/* Interrupt Management */
void (*enable_irq)(uint8_t irq);
void (*disable_irq)(uint8_t irq);
/* I/O Operations */
uint8_t (*read_io8)(uint16_t port);
void (*write_io8)(uint16_t port, uint8_t value);
uint16_t (*read_io16)(uint16_t port);
void (*write_io16)(uint16_t port, uint16_t value);
} hal_ops_t;
#include "hal.h"
/* Hardware-specific definitions */
#define MAGIC1_CONTROL_REG 0xFFF0
#define MAGIC1_STATUS_REG 0xFFF2
#define MAGIC1_RESET_BIT 0x01
#define MAGIC1_HALT_BIT 0x02
static hal_ops_t magic1_hal_ops;
static void magic1_reset_system(void) {
/* Set reset bit in control register */
uint16_t ctrl = read_io16(MAGIC1_CONTROL_REG);
write_io16(MAGIC1_CONTROL_REG, ctrl | MAGIC1_RESET_BIT);
/* System should reset, but if we get here, halt */
while(1) { }
}
static void magic1_delay_ms(uint32_t ms) {
uint32_t cycles = ms * (CLOCK_FREQUENCY / 1000);
while(cycles--) {
__asm__ volatile("nop");
}
}
/* Initialize HAL operations structure */
void hal_init(void) {
magic1_hal_ops.reset_system = magic1_reset_system;
magic1_hal_ops.halt_system = magic1_halt_system;
magic1_hal_ops.delay_ms = magic1_delay_ms;
magic1_hal_ops.mem_map = magic1_mem_map;
magic1_hal_ops.mem_unmap = magic1_mem_unmap;
magic1_hal_ops.enable_irq = magic1_enable_irq;
magic1_hal_ops.disable_irq = magic1_disable_irq;
magic1_hal_ops.read_io8 = magic1_read_io8;
magic1_hal_ops.write_io8 = magic1_write_io8;
magic1_hal_ops.read_io16 = magic1_read_io16;
magic1_hal_ops.write_io16 = magic1_write_io16;
}
#include "unity.h"
#include "hal.h"
void setUp(void) {
hal_init();
}
void tearDown(void) {
/* Nothing to clean up */
}
void test_io_operations(void) {
/* Test 8-bit I/O */
write_io8(0xFF00, 0x55);
TEST_ASSERT_EQUAL_UINT8(0x55, read_io8(0xFF00));
/* Test 16-bit I/O */
write_io16(0xFF02, 0xAA55);
TEST_ASSERT_EQUAL_UINT16(0xAA55, read_io16(0xFF02));
}
void test_interrupt_management(void) {
/* Test IRQ enable/disable */
enable_irq(1);
TEST_ASSERT_BIT_HIGH(read_io16(MAGIC1_STATUS_REG), 1);
disable_irq(1);
TEST_ASSERT_BIT_LOW(read_io16(MAGIC1_STATUS_REG), 1);
}
The power management and system control module handles system states, power modes, and hardware configuration.
#pragma once
#include <stdint.h>
/* System power states */
typedef enum {
POWER_STATE_RUN, // Normal operation
POWER_STATE_IDLE, // CPU idle, peripherals active
POWER_STATE_STANDBY, // Low power mode, quick wake
POWER_STATE_SHUTDOWN // Full power down
} power_state_t;
/* Clock configuration */
typedef struct {
uint8_t pll_multiplier; // 1-16
uint8_t pll_divider; // 1-8
uint8_t cpu_divider; // 1-8
uint8_t periph_divider; // 1-8
uint32_t target_freq; // Desired CPU frequency
} clock_config_t;
#include "power_mgmt.h"
#define POWER_CTRL_REG 0xFFF4
#define CLOCK_CTRL_REG 0xFFF6
#define STATUS_REG 0xFFF8
#define PWR_MODE_MASK 0x03
#define PLL_LOCK_BIT 0x80
#define CLK_STABLE_BIT 0x40
static power_state_t current_power_state = POWER_STATE_RUN;
static clock_config_t current_clock_config;
int set_power_state(power_state_t new_state) {
uint16_t ctrl_reg;
if (new_state == current_power_state) {
return 0; // Already in requested state
}
// Read current control register
ctrl_reg = read_io16(POWER_CTRL_REG);
// Clear power mode bits
ctrl_reg &= ~PWR_MODE_MASK;
// Set new power mode
switch (new_state) {
case POWER_STATE_RUN:
ctrl_reg |= 0x00;
break;
case POWER_STATE_IDLE:
ctrl_reg |= 0x01;
break;
case POWER_STATE_STANDBY:
ctrl_reg |= 0x02;
break;
case POWER_STATE_SHUTDOWN:
ctrl_reg |= 0x03;
break;
default:
return -1;
}
// Update control register
write_io16(POWER_CTRL_REG, ctrl_reg);
// Wait for state change to complete
while ((read_io16(STATUS_REG) & PWR_MODE_MASK) !=
(ctrl_reg & PWR_MODE_MASK)) {
// Timeout check could be added here
}
current_power_state = new_state;
return 0;
}
#include "power_mgmt.h"
int configure_system_clock(const clock_config_t* config) {
uint16_t clock_ctrl;
uint32_t timeout = 1000; // Timeout counter
// Validate configuration
if (!config || config->pll_multiplier > 16 ||
config->pll_divider > 8 || config->cpu_divider > 8) {
return -1;
}
// Build clock control value
clock_ctrl = ((config->pll_multiplier - 1) << 12) |
((config->pll_divider - 1) << 9) |
((config->cpu_divider - 1) << 6) |
((config->periph_divider - 1) << 3);
// Update clock control register
write_io16(CLOCK_CTRL_REG, clock_ctrl);
// Wait for PLL lock and clock stabilization
while (timeout--) {
if ((read_io16(STATUS_REG) & (PLL_LOCK_BIT | CLK_STABLE_BIT)) ==
(PLL_LOCK_BIT | CLK_STABLE_BIT)) {
memcpy(¤t_clock_config, config, sizeof(clock_config_t));
return 0;
}
}
return -1; // Timeout waiting for clock stabilization
}
The boot image format follows a strict structure for reliability and security:
#define MAGIC_NUMBER 0x4D31 // "M1"
#define IMAGE_VERSION 0x0001
#define MAX_IMAGE_NAME 32
#define MAX_SIGNATURES 4
typedef struct {
uint16_t magic; // Magic number identifier
uint16_t version; // Image format version
uint32_t total_size; // Total image size including header
uint32_t entry_point; // Entry point address
uint32_t load_address; // Load address
uint32_t code_size; // Size of code segment
uint32_t data_size; // Size of data segment
uint32_t bss_size; // Size of BSS segment
uint32_t symbol_offset; // Offset to symbol table
uint32_t reloc_offset; // Offset to relocation table
uint8_t flags; // Image flags
uint8_t cpu_type; // Target CPU type
char name[MAX_IMAGE_NAME]; // Image name
uint8_t signatures[MAX_SIGNATURES][64]; // Digital signatures
uint32_t checksum; // CRC32 of image excluding header
} __attribute__((packed)) boot_image_header_t;
#include "boot_image.h"
#include "crypto/crc32.h"
#include "crypto/sha256.h"
static const uint8_t public_key[32] = {
0x55, 0xAA, /* ... public key data ... */
};
int verify_boot_image(const void* image_data, size_t size) {
const boot_image_header_t* header = (const boot_image_header_t*)image_data;
uint32_t computed_crc;
// Verify minimum size
if (size < sizeof(boot_image_header_t)) {
return -1;
}
// Check magic number and version
if (header->magic != MAGIC_NUMBER ||
header->version != IMAGE_VERSION) {
return -2;
}
// Verify total size
if (size < header->total_size) {
return -3;
}
// Calculate and verify checksum
computed_crc = crc32(0,
(uint8_t*)image_data + sizeof(boot_image_header_t),
header->total_size - sizeof(boot_image_header_t));
if (computed_crc != header->checksum) {
return -4;
}
// Verify digital signatures if present
if (header->flags & IMAGE_FLAG_SIGNED) {
if (verify_signatures(header) != 0) {
return -5;
}
}
return 0;
}
#include "boot_image.h"
#include "memory/mmu.h"
int load_boot_image(const void* image_data) {
const boot_image_header_t* header = (const boot_image_header_t*)image_data;
const uint8_t* data = (const uint8_t*)image_data;
void* load_addr;
// First verify the image
if (verify_boot_image(image_data, header->total_size) != 0) {
return -1;
}
// Allocate and map memory
load_addr = mmu_map_region(header->load_address,
header->total_size,
MMU_FLAG_READ | MMU_FLAG_WRITE | MMU_FLAG_EXEC);
if (!load_addr) {
return -2;
}
// Copy code segment
memcpy((void*)header->load_address,
data + sizeof(boot_image_header_t),
header->code_size);
// Copy data segment
memcpy((void*)(header->load_address + header->code_size),
data + sizeof(boot_image_header_t) + header->code_size,
header->data_size);
// Clear BSS segment
memset((void*)(header->load_address + header->code_size + header->data_size),
0,
header->bss_size);
// Process relocations if present
if (header->reloc_offset) {
process_relocations(header);
}
return 0;
}
The system initialization process follows a carefully orchestrated sequence of steps to bring the Magic-1 hardware to a known good state.
#define INIT_FLAG_MMU_ENABLED (1 << 0)
#define INIT_FLAG_CACHE_ENABLED (1 << 1)
#define INIT_FLAG_INTERRUPTS_ON (1 << 2)
typedef enum {
BOOT_PHASE_RESET,
BOOT_PHASE_EARLY_INIT,
BOOT_PHASE_HARDWARE_INIT,
BOOT_PHASE_MEMORY_INIT,
BOOT_PHASE_DEVICE_INIT,
BOOT_PHASE_FINAL_INIT
} boot_phase_t;
typedef struct {
boot_phase_t current_phase;
uint32_t flags;
uint32_t boot_time;
uint32_t error_code;
} boot_state_t;
.section .text.init
.global _start
_start:
# Disable interrupts
cli
# Set up initial stack
ldi sp, #0x8000
# Clear BSS section
ldi a0, #__bss_start
ldi a1, #__bss_end
ldi a2, #0
clear_bss:
cmp a0, a1
beq bss_done
st a2, (a0)
inc a0
br clear_bss
bss_done:
# Jump to C initialization
call boot_init
static boot_state_t boot_state = {
.current_phase = BOOT_PHASE_RESET,
.flags = 0,
.boot_time = 0,
.error_code = 0
};
void boot_init(void) {
// Early hardware initialization
early_hw_init();
boot_state.current_phase = BOOT_PHASE_EARLY_INIT;
// Initialize memory subsystem
if (init_memory() != 0) {
boot_state.error_code = ERR_MEMORY_INIT;
panic();
}
boot_state.current_phase = BOOT_PHASE_MEMORY_INIT;
// Enable MMU
if (mmu_init() == 0) {
boot_state.flags |= INIT_FLAG_MMU_ENABLED;
}
// Initialize essential devices
init_uart();
init_timer();
init_interrupt_controller();
boot_state.current_phase = BOOT_PHASE_DEVICE_INIT;
// Enable interrupts
sti();
boot_state.flags |= INIT_FLAG_INTERRUPTS_ON;
// Jump to main bootloader code
bootloader_main();
}
The Magic-1's memory management system handles address translation, cache control, and memory protection.
#include <stdint.h>
/* Memory protection flags */
#define MEM_PROT_READ (1 << 0)
#define MEM_PROT_WRITE (1 << 1)
#define MEM_PROT_EXEC (1 << 2)
/* Memory type definitions */
#define MEM_TYPE_RAM 0
#define MEM_TYPE_ROM 1
#define MEM_TYPE_DEVICE 2
struct memory_region {
uint32_t start; /* Start address */
uint32_t size; /* Region size */
uint8_t type; /* Memory type */
uint8_t protection; /* Protection flags */
uint8_t cacheable; /* Cache enable flag */
char name[16]; /* Region name */
};
#define CACHE_CTRL_REG 0xFFF2
#define CACHE_FLUSH_BIT 0x01
#define CACHE_ENABLE_BIT 0x02
void flush_cache(void) {
uint16_t ctrl;
/* Read current cache control */
ctrl = read_io16(CACHE_CTRL_REG);
/* Set flush bit */
write_io16(CACHE_CTRL_REG, ctrl | CACHE_FLUSH_BIT);
/* Wait for flush to complete */
while(read_io16(CACHE_CTRL_REG) & CACHE_FLUSH_BIT) {
/* Busy wait */
}
}
int configure_cache(int enable) {
uint16_t ctrl = read_io16(CACHE_CTRL_REG);
if(enable) {
ctrl |= CACHE_ENABLE_BIT;
} else {
ctrl &= ~CACHE_ENABLE_BIT;
}
write_io16(CACHE_CTRL_REG, ctrl);
return 0;
}
#define MAX_MEMORY_REGIONS 16
static struct memory_region regions[MAX_MEMORY_REGIONS];
static int num_regions = 0;
int register_memory_region(const struct memory_region *region) {
if(num_regions >= MAX_MEMORY_REGIONS) {
return -1;
}
/* Check for overlap with existing regions */
for(int i = 0; i < num_regions; i++) {
if((region->start < (regions[i].start + regions[i].size)) &&
((region->start + region->size) > regions[i].start)) {
return -2;
}
}
/* Add new region */
memcpy(®ions[num_regions], region, sizeof(struct memory_region));
num_regions++;
return 0;
}
The Magic-1's interrupt system provides prioritized hardware and software interrupt handling with nested interrupt support.
#define MAX_INTERRUPTS 16
#define IRQ_LEVELS 8
/* Interrupt vector definitions */
#define IRQ_NMI 0 /* Non-maskable interrupt */
#define IRQ_TIMER 1 /* System timer */
#define IRQ_UART0 2 /* Primary UART */
#define IRQ_UART1 3 /* Secondary UART */
#define IRQ_IDE 4 /* IDE interface */
#define IRQ_RTC 5 /* Real-time clock */
#define IRQ_FAULT 6 /* CPU fault */
#define IRQ_TRAP 7 /* Software trap */
/* Interrupt priority levels */
typedef enum {
IPL_NONE = 0,
IPL_LOW = 1,
IPL_MED = 4,
IPL_HIGH = 6,
IPL_NMI = 7
} ipl_t;
#include "interrupts.h"
typedef struct {
void (*handler)(void);
ipl_t priority;
uint32_t count;
const char *name;
} vector_entry_t;
static vector_entry_t vector_table[MAX_INTERRUPTS] = {
[IRQ_NMI] = { nmi_handler, IPL_NMI, 0, "NMI" },
[IRQ_TIMER] = { timer_handler, IPL_HIGH, 0, "Timer" },
[IRQ_UART0] = { uart0_handler, IPL_MED, 0, "UART0" },
[IRQ_UART1] = { uart1_handler, IPL_MED, 0, "UART1" },
[IRQ_IDE] = { ide_handler, IPL_LOW, 0, "IDE" },
[IRQ_RTC] = { rtc_handler, IPL_LOW, 0, "RTC" },
[IRQ_FAULT] = { fault_handler, IPL_NMI, 0, "Fault" },
[IRQ_TRAP] = { trap_handler, IPL_HIGH, 0, "Trap" }
};
/* Initialize vector table in hardware */
void init_vectors(void) {
for(int i = 0; i < MAX_INTERRUPTS; i++) {
if(vector_table[i].handler) {
write_vector(i, vector_table[i].handler);
set_vector_priority(i, vector_table[i].priority);
}
}
}
#define INT_CTRL_BASE 0xFFC0
#define INT_MASK_REG (INT_CTRL_BASE + 0)
#define INT_STATUS_REG (INT_CTRL_BASE + 2)
#define INT_ACK_REG (INT_CTRL_BASE + 4)
#define INT_PRIO_REG (INT_CTRL_BASE + 6)
static uint16_t interrupt_mask = 0;
static uint8_t current_ipl = IPL_NONE;
void enable_interrupt(uint8_t irq) {
if(irq < MAX_INTERRUPTS) {
interrupt_mask |= (1 << irq);
write_io16(INT_MASK_REG, interrupt_mask);
}
}
void set_ipl(uint8_t level) {
current_ipl = level;
write_io16(INT_PRIO_REG, level);
}
void interrupt_dispatch(void) {
uint16_t active = read_io16(INT_STATUS_REG);
for(int i = 0; i < MAX_INTERRUPTS; i++) {
if(active & (1 << i)) {
if(vector_table[i].handler &&
vector_table[i].priority > current_ipl) {
vector_table[i].count++;
vector_table[i].handler();
}
write_io16(INT_ACK_REG, 1 << i);
}
}
}
The Magic-1 hardware abstraction employs a modular driver system for managing various hardware components.
#include <stdint.h>
typedef enum {
DRIVER_STATUS_OK = 0,
DRIVER_STATUS_ERROR = -1,
DRIVER_STATUS_TIMEOUT = -2,
DRIVER_STATUS_NOT_SUPPORTED = -3
} driver_status_t;
typedef struct device_driver {
const char* name;
uint32_t base_address;
uint32_t irq_number;
/* Driver operations */
int (*init)(struct device_driver* driver);
int (*read)(struct device_driver* driver, void* buffer, size_t size);
int (*write)(struct device_driver* driver, const void* buffer, size_t size);
int (*ioctl)(struct device_driver* driver, uint32_t cmd, void* arg);
void (*irq_handler)(struct device_driver* driver);
void (*shutdown)(struct device_driver* driver);
/* Private data */
void* private_data;
} device_driver_t;
#include "driver_interface.h"
#define UART_RBR 0x00 /* Receive Buffer Register */
#define UART_THR 0x00 /* Transmit Holding Register */
#define UART_IER 0x01 /* Interrupt Enable Register */
#define UART_FCR 0x02 /* FIFO Control Register */
#define UART_LCR 0x03 /* Line Control Register */
#define UART_LSR 0x05 /* Line Status Register */
typedef struct {
uint8_t tx_fifo[16];
uint8_t rx_fifo[16];
uint8_t tx_head;
uint8_t tx_tail;
uint8_t rx_head;
uint8_t rx_tail;
} uart_private_t;
static int uart_init(device_driver_t* driver) {
uint16_t base = driver->base_address;
/* Initialize UART hardware */
outb(base + UART_LCR, 0x80); /* Enable DLAB */
outb(base + UART_RBR, 0x0C); /* Baud rate divisor */
outb(base + UART_IER, 0x00);
outb(base + UART_LCR, 0x03); /* 8N1 */
outb(base + UART_FCR, 0x07); /* Enable and clear FIFOs */
/* Allocate private data */
driver->private_data = malloc(sizeof(uart_private_t));
memset(driver->private_data, 0, sizeof(uart_private_t));
return DRIVER_STATUS_OK;
}
#include "driver_interface.h"
#define IDE_DATA 0x00
#define IDE_ERROR 0x01
#define IDE_STATUS 0x07
#define IDE_COMMAND 0x07
typedef struct {
uint8_t is_present;
uint8_t is_master;
uint16_t cylinders;
uint16_t heads;
uint16_t sectors;
} ide_private_t;
static int ide_init(device_driver_t* driver) {
uint16_t base = driver->base_address;
ide_private_t* priv;
/* Allocate private data */
driver->private_data = malloc(sizeof(ide_private_t));
priv = (ide_private_t*)driver->private_data;
/* Detect drive presence */
outb(base + IDE_COMMAND, 0xEC); /* IDENTIFY command */
if (inb(base + IDE_STATUS) == 0) {
priv->is_present = 0;
return DRIVER_STATUS_ERROR;
}
/* Read identification data */
for (int i = 0; i < 256; i++) {
uint16_t data = inw(base + IDE_DATA);
/* Process identification data */
}
return DRIVER_STATUS_OK;
}
The Magic-1 bootloader implements a minimal file system layer to handle boot images and configuration files.
#define FS_MAX_PATH 256
#define FS_MAX_NAME 64
#define FS_MAX_OPEN 8
#define FS_SECTOR_SIZE 512
typedef enum {
FS_TYPE_NONE = 0,
FS_TYPE_FAT16,
FS_TYPE_FAT32,
FS_TYPE_M1FS
} fs_type_t;
typedef struct {
char name[FS_MAX_NAME];
uint32_t size;
uint32_t start_sector;
uint8_t attributes;
uint32_t create_time;
uint32_t modify_time;
} fs_entry_t;
#define M1FS_MAGIC 0x4D314653 // "M1FS"
#define M1FS_VERSION 0x0100
#define M1FS_BLOCK_SIZE 2048
struct m1fs_superblock {
uint32_t magic;
uint16_t version;
uint16_t block_size;
uint32_t total_blocks;
uint32_t free_blocks;
uint32_t root_block;
uint8_t label[16];
uint8_t reserved[32];
} __attribute__((packed));
struct m1fs_directory_entry {
char name[FS_MAX_NAME];
uint32_t first_block;
uint32_t size;
uint8_t type;
uint8_t attributes;
uint32_t create_time;
uint32_t modify_time;
uint8_t reserved[16];
} __attribute__((packed));
typedef struct {
fs_entry_t entry;
uint32_t position;
uint8_t mode;
uint8_t dirty;
uint8_t* buffer;
} file_handle_t;
static file_handle_t open_files[FS_MAX_OPEN];
int fs_open(const char* path, uint8_t mode) {
int handle = -1;
fs_entry_t entry;
// Find free handle
for(int i = 0; i < FS_MAX_OPEN; i++) {
if(!open_files[i].buffer) {
handle = i;
break;
}
}
if(handle < 0) {
return -1; // No free handles
}
// Look up file entry
if(fs_lookup(path, &entry) != 0) {
return -2; // File not found
}
// Initialize handle
open_files[handle].entry = entry;
open_files[handle].position = 0;
open_files[handle].mode = mode;
open_files[handle].dirty = 0;
open_files[handle].buffer = malloc(FS_SECTOR_SIZE);
return handle;
}
The configuration management system handles bootloader settings, system parameters, and hardware configuration.
#define CONFIG_MAGIC 0x4D314346 // "M1CF"
#define MAX_CONFIG_SIZE 4096
#define MAX_KEY_LENGTH 32
#define MAX_VAL_LENGTH 128
typedef struct config_entry {
char key[MAX_KEY_LENGTH];
char value[MAX_VAL_LENGTH];
struct config_entry* next;
} config_entry_t;
typedef struct {
uint32_t magic;
uint16_t version;
uint16_t num_entries;
uint32_t checksum;
config_entry_t* entries;
} config_data_t;
static config_data_t config;
int save_config(void) {
uint8_t buffer[MAX_CONFIG_SIZE];
uint32_t offset = 0;
config_entry_t* entry;
// Write header
memcpy(buffer + offset, &config.magic, sizeof(uint32_t));
offset += sizeof(uint32_t);
memcpy(buffer + offset, &config.version, sizeof(uint16_t));
offset += sizeof(uint16_t);
memcpy(buffer + offset, &config.num_entries, sizeof(uint16_t));
offset += sizeof(uint16_t);
// Write entries
for(entry = config.entries; entry; entry = entry->next) {
uint8_t key_len = strlen(entry->key);
uint8_t val_len = strlen(entry->value);
buffer[offset++] = key_len;
memcpy(buffer + offset, entry->key, key_len);
offset += key_len;
buffer[offset++] = val_len;
memcpy(buffer + offset, entry->value, val_len);
offset += val_len;
}
// Calculate and write checksum
config.checksum = calculate_crc32(buffer, offset);
memcpy(buffer + offset, &config.checksum, sizeof(uint32_t));
offset += sizeof(uint32_t);
// Write to storage
return write_config_sector(buffer, offset);
}
const char* config_get(const char* key) {
config_entry_t* entry;
for(entry = config.entries; entry; entry = entry->next) {
if(strcmp(entry->key, key) == 0) {
return entry->value;
}
}
return NULL;
}
int config_set(const char* key, const char* value) {
config_entry_t* entry;
// Look for existing entry
for(entry = config.entries; entry; entry = entry->next) {
if(strcmp(entry->key, key) == 0) {
strncpy(entry->value, value, MAX_VAL_LENGTH - 1);
entry->value[MAX_VAL_LENGTH - 1] = '\0';
return 0;
}
}
// Create new entry
entry = malloc(sizeof(config_entry_t));
if(!entry) {
return -1;
}
strncpy(entry->key, key, MAX_KEY_LENGTH - 1);
entry->key[MAX_KEY_LENGTH - 1] = '\0';
strncpy(entry->value, value, MAX_VAL_LENGTH - 1);
entry->value[MAX_VAL_LENGTH - 1] = '\0';
// Add to list
entry->next = config.entries;
config.entries = entry;
config.num_entries++;
return 0;
}
First, let's define our debug interface structures:
#define DEBUG_BUFFER_SIZE 1024
#define MAX_BREAKPOINTS 8
#define MAX_WATCHPOINTS 4
typedef enum {
DEBUG_LEVEL_NONE = 0,
DEBUG_LEVEL_ERROR,
DEBUG_LEVEL_WARN,
DEBUG_LEVEL_INFO,
DEBUG_LEVEL_DEBUG
} debug_level_t;
typedef struct {
uint16_t address;
uint16_t original_opcode;
bool enabled;
char description[32];
} breakpoint_t;
typedef struct {
uint16_t address;
uint16_t size;
uint16_t last_value;
bool enabled;
void (*callback)(uint16_t addr, uint16_t old_val, uint16_t new_val);
} watchpoint_t;
static struct {
debug_level_t current_level;
breakpoint_t breakpoints[MAX_BREAKPOINTS];
watchpoint_t watchpoints[MAX_WATCHPOINTS];
char debug_buffer[DEBUG_BUFFER_SIZE];
uint16_t buffer_pos;
bool single_step_mode;
} debug_context;
void debug_init(void) {
debug_context.current_level = DEBUG_LEVEL_INFO;
debug_context.buffer_pos = 0;
debug_context.single_step_mode = false;
// Install debug trap handler
install_trap_handler(debug_trap_handler);
}
int set_breakpoint(uint16_t addr, const char* desc) {
for (int i = 0; i < MAX_BREAKPOINTS; i++) {
if (!debug_context.breakpoints[i].enabled) {
debug_context.breakpoints[i].address = addr;
debug_context.breakpoints[i].original_opcode = read_memory(addr);
debug_context.breakpoints[i].enabled = true;
strncpy(debug_context.breakpoints[i].description, desc, 31);
// Replace instruction with trap
write_memory(addr, 0xFFFF); // TRAP instruction
return i;
}
}
return -1; // No free breakpoints
}
void dump_memory(uint16_t start, uint16_t length) {
for (uint16_t addr = start; addr < start + length; addr += 16) {
printf("%04X: ", addr);
// Hex display
for (int i = 0; i < 16; i++) {
if (i == 8) printf("- ");
printf("%02X ", read_memory(addr + i));
}
printf(" |");
// ASCII display
for (int i = 0; i < 16; i++) {
uint8_t byte = read_memory(addr + i);
printf("%c", (byte >= 32 && byte <= 126) ? byte : '.');
}
printf("|\n");
}
}
void modify_memory(uint16_t addr, uint8_t value) {
if (is_memory_protected(addr)) {
debug_printf(DEBUG_LEVEL_ERROR,
"Cannot modify protected memory at %04X\n", addr);
return;
}
write_memory(addr, value);
}
First, let's define the command structure:
#define MAX_CMD_LENGTH 32
#define MAX_ARGS 8
#define MAX_HELP_TEXT 128
typedef struct command {
const char* name;
const char* help_text;
int min_args;
int max_args;
int (*handler)(int argc, char* argv[]);
bool requires_auth;
} command_t;
typedef enum {
CMD_SUCCESS = 0,
CMD_ERROR = -1,
CMD_NOT_FOUND = -2,
CMD_INVALID_ARGS = -3,
CMD_AUTH_REQUIRED = -4
} cmd_result_t;
static const command_t commands[] = {
{
.name = "boot",
.help_text = "boot <image_name> - Boot specified system image",
.min_args = 1,
.max_args = 1,
.handler = cmd_boot_handler,
.requires_auth = true
},
{
.name = "show",
.help_text = "show <config|memory|devices> - Display system information",
.min_args = 1,
.max_args = 2,
.handler = cmd_show_handler,
.requires_auth = false
},
// Null terminator
{NULL, NULL, 0, 0, NULL, false}
};
static cmd_result_t process_command_line(const char* input) {
char buffer[MAX_CMD_LENGTH];
char* args[MAX_ARGS];
int argc = 0;
// Skip leading whitespace
while (*input && isspace(*input)) input++;
if (*input == '\0') return CMD_SUCCESS; // Empty line
// Parse command and arguments
strncpy(buffer, input, MAX_CMD_LENGTH - 1);
buffer[MAX_CMD_LENGTH - 1] = '\0';
char* token = strtok(buffer, " \t");
while (token && argc < MAX_ARGS) {
args[argc++] = token;
token = strtok(NULL, " \t");
}
// Find and execute command
for (const command_t* cmd = commands; cmd->name; cmd++) {
if (strcmp(args[0], cmd->name) == 0) {
if (argc - 1 < cmd->min_args || argc - 1 > cmd->max_args) {
printf("Error: Invalid number of arguments\n");
printf("Usage: %s\n", cmd->help_text);
return CMD_INVALID_ARGS;
}
if (cmd->requires_auth && !is_authenticated()) {
printf("Error: Authentication required\n");
return CMD_AUTH_REQUIRED;
}
return cmd->handler(argc, args);
}
}
printf("Error: Unknown command '%s'\n", args[0]);
return CMD_NOT_FOUND;
}
The Magic-1 bootloader implements a robust error recovery mechanism to handle hardware failures, corrupted data, and system faults.
#define MAX_RECOVERY_ATTEMPTS 3
#define RECOVERY_LOG_SIZE 16
typedef enum {
RECOVERY_STATE_NORMAL,
RECOVERY_STATE_ATTEMPTING,
RECOVERY_STATE_FAILED,
RECOVERY_STATE_SUCCESS
} recovery_state_t;
typedef struct {
uint32_t timestamp;
uint16_t error_code;
uint8_t attempted_fixes;
recovery_state_t outcome;
} recovery_log_entry_t;
static struct {
recovery_state_t current_state;
uint8_t attempt_count;
recovery_log_entry_t log[RECOVERY_LOG_SIZE];
uint8_t log_index;
} recovery_context;
int attempt_recovery(uint16_t error_code) {
recovery_log_entry_t* entry;
if (recovery_context.attempt_count >= MAX_RECOVERY_ATTEMPTS) {
enter_fail_safe_mode();
return -1;
}
// Log recovery attempt
entry = &recovery_context.log[recovery_context.log_index];
entry->timestamp = get_system_time();
entry->error_code = error_code;
entry->attempted_fixes = recovery_context.attempt_count + 1;
recovery_context.current_state = RECOVERY_STATE_ATTEMPTING;
// Attempt recovery based on error code
switch (error_code) {
case ERR_CORRUPT_CONFIG:
if (restore_backup_config() == 0) {
entry->outcome = RECOVERY_STATE_SUCCESS;
return 0;
}
break;
case ERR_BOOT_IMAGE:
if (try_alternate_boot_image() == 0) {
entry->outcome = RECOVERY_STATE_SUCCESS;
return 0;
}
break;
case ERR_HARDWARE_TIMEOUT:
if (reset_hardware_interface() == 0) {
entry->outcome = RECOVERY_STATE_SUCCESS;
return 0;
}
break;
}
entry->outcome = RECOVERY_STATE_FAILED;
recovery_context.attempt_count++;
recovery_context.log_index = (recovery_context.log_index + 1) % RECOVERY_LOG_SIZE;
return -1;
}
The performance monitoring system tracks system metrics and provides diagnostic information for bootloader optimization.
#define MAX_PERF_COUNTERS 16
#define MAX_PERF_EVENTS 32
#define PERF_SAMPLE_WINDOW 1000 // ms
typedef enum {
PERF_METRIC_BOOT_TIME,
PERF_METRIC_DISK_OPS,
PERF_METRIC_CACHE_HITS,
PERF_METRIC_CACHE_MISSES,
PERF_METRIC_IRQ_COUNT,
PERF_METRIC_ERROR_COUNT
} perf_metric_t;
typedef struct {
perf_metric_t type;
const char* name;
uint32_t value;
uint32_t min;
uint32_t max;
uint32_t samples[PERF_SAMPLE_WINDOW];
} perf_counter_t;
static struct {
perf_counter_t counters[MAX_PERF_COUNTERS];
uint8_t counter_count;
uint32_t start_time;
bool monitoring_active;
} perf_context;
void init_performance_monitor(void) {
memset(&perf_context, 0, sizeof(perf_context));
perf_context.start_time = get_system_time();
// Register default counters
register_perf_counter(PERF_METRIC_BOOT_TIME, "Boot Time");
register_perf_counter(PERF_METRIC_DISK_OPS, "Disk Operations");
register_perf_counter(PERF_METRIC_CACHE_HITS, "Cache Hits");
register_perf_counter(PERF_METRIC_CACHE_MISSES, "Cache Misses");
perf_context.monitoring_active = true;
}
void update_perf_counter(perf_metric_t metric, uint32_t value) {
for (int i = 0; i < perf_context.counter_count; i++) {
perf_counter_t* counter = &perf_context.counters[i];
if (counter->type == metric) {
counter->value = value;
if (value < counter->min) counter->min = value;
if (value > counter->max) counter->max = value;
// Update rolling window
uint32_t index = get_system_time() % PERF_SAMPLE_WINDOW;
counter->samples[index] = value;
break;
}
}
}
void generate_performance_report(void) {
printf("\nPerformance Monitor Report\n");
printf("=========================\n");
printf("System uptime: %d ms\n\n", get_system_time() - perf_context.start_time);
for (int i = 0; i < perf_context.counter_count; i++) {
perf_counter_t* counter = &perf_context.counters[i];
printf("%-20s: current=%d, min=%d, max=%d\n",
counter->name,
counter->value,
counter->min,
counter->max);
}
}
The Magic-1 bootloader implements a comprehensive state management system to track and control system behavior during the boot process.
#define MAX_STATE_TRANSITIONS 16
#define MAX_STATE_HANDLERS 32
typedef enum {
SYSTEM_STATE_RESET,
SYSTEM_STATE_EARLY_INIT,
SYSTEM_STATE_HW_DETECT,
SYSTEM_STATE_MEMORY_INIT,
SYSTEM_STATE_DEVICE_INIT,
SYSTEM_STATE_BOOT_SELECT,
SYSTEM_STATE_LOADING,
SYSTEM_STATE_READY,
SYSTEM_STATE_ERROR,
SYSTEM_STATE_RECOVERY
} system_state_t;
typedef struct {
system_state_t current;
system_state_t previous;
uint32_t state_entry_time;
uint32_t state_duration;
uint8_t error_count;
bool recovery_mode;
} state_context_t;
static state_context_t state_ctx;
static state_handler_t state_handlers[MAX_STATE_HANDLERS];
typedef struct {
system_state_t from_state;
system_state_t to_state;
bool (*condition)(void);
void (*transition_handler)(void);
} state_transition_t;
static state_transition_t state_transitions[MAX_STATE_TRANSITIONS];
int transition_state(system_state_t new_state) {
uint32_t current_time = get_system_time();
// Check if transition is allowed
for (int i = 0; i < MAX_STATE_TRANSITIONS; i++) {
if (state_transitions[i].from_state == state_ctx.current &&
state_transitions[i].to_state == new_state) {
// Check transition condition if present
if (state_transitions[i].condition &&
!state_transitions[i].condition()) {
return -1;
}
// Execute transition handler if present
if (state_transitions[i].transition_handler) {
state_transitions[i].transition_handler();
}
// Update state context
state_ctx.previous = state_ctx.current;
state_ctx.current = new_state;
state_ctx.state_duration =
current_time - state_ctx.state_entry_time;
state_ctx.state_entry_time = current_time;
// Execute new state handler
if (state_handlers[new_state]) {
state_handlers[new_state]();
}
return 0;
}
}
return -1; // Invalid transition
}
void register_state_handlers(void) {
// Register core state handlers
state_handlers[SYSTEM_STATE_RESET] = handle_reset_state;
state_handlers[SYSTEM_STATE_EARLY_INIT] = handle_early_init;
state_handlers[SYSTEM_STATE_HW_DETECT] = handle_hardware_detection;
state_handlers[SYSTEM_STATE_MEMORY_INIT] = handle_memory_init;
state_handlers[SYSTEM_STATE_DEVICE_INIT] = handle_device_init;
// Register allowed state transitions
register_transition(SYSTEM_STATE_RESET, SYSTEM_STATE_EARLY_INIT, NULL);
register_transition(SYSTEM_STATE_EARLY_INIT, SYSTEM_STATE_HW_DETECT,
check_early_init_complete);
register_transition(SYSTEM_STATE_HW_DETECT, SYSTEM_STATE_MEMORY_INIT,
check_hardware_ready);
}
The boot media management system provides a uniform interface for accessing different boot storage devices.
#define MAX_BOOT_DEVICES 4
#define SECTOR_SIZE 512
#define MAX_RETRIES 3
typedef enum {
BOOT_MEDIA_IDE,
BOOT_MEDIA_CF,
BOOT_MEDIA_ROM,
BOOT_MEDIA_NET
} boot_media_type_t;
typedef struct {
boot_media_type_t type;
uint8_t id;
uint32_t sector_count;
bool bootable;
char description[32];
/* Device operations */
int (*init)(void);
int (*read_sectors)(uint32_t start, uint32_t count, void* buffer);
int (*write_sectors)(uint32_t start, uint32_t count, const void* buffer);
void (*shutdown)(void);
} boot_device_t;
static struct {
boot_device_t* devices[MAX_BOOT_DEVICES];
uint8_t device_count;
boot_device_t* active_device;
} boot_media_ctx;
int register_boot_device(boot_device_t* device) {
if (boot_media_ctx.device_count >= MAX_BOOT_DEVICES) {
return -1;
}
if (device->init && device->init() != 0) {
return -2;
}
boot_media_ctx.devices[boot_media_ctx.device_count++] = device;
// If this is the first bootable device, make it active
if (device->bootable && !boot_media_ctx.active_device) {
boot_media_ctx.active_device = device;
}
return 0;
}
typedef struct {
uint32_t sector;
uint32_t retry_count;
uint32_t last_error;
uint32_t timestamp;
} media_error_info_t;
int handle_media_error(boot_device_t* device, uint32_t sector, uint32_t error) {
static media_error_info_t error_info;
error_info.sector = sector;
error_info.last_error = error;
error_info.timestamp = get_system_time();
if (++error_info.retry_count > MAX_RETRIES) {
// Log critical error
log_critical("Boot media error: device=%d sector=%d error=0x%x",
device->id, sector, error);
return -1;
}
// Attempt recovery
switch (error) {
case ERR_TIMEOUT:
delay_ms(100 * error_info.retry_count);
break;
case ERR_CRC:
// Reset device controller
if (device->init) {
device->init();
}
break;
}
return 0; // Retry operation
}
The logging system provides centralized logging capabilities with different severity levels and output targets.
#define MAX_LOG_ENTRIES 256
#define MAX_LOG_MSG_LEN 128
#define LOG_SIGNATURE 0x4C4F4721 // "LOG!"
typedef enum {
LOG_LEVEL_DEBUG = 0,
LOG_LEVEL_INFO,
LOG_LEVEL_WARN,
LOG_LEVEL_ERROR,
LOG_LEVEL_FATAL
} log_level_t;
typedef struct {
uint32_t timestamp;
log_level_t level;
char message[MAX_LOG_MSG_LEN];
uint16_t source_line;
const char* source_file;
} log_entry_t;
struct log_buffer {
log_entry_t entries[MAX_LOG_ENTRIES];
uint16_t head;
uint16_t tail;
uint32_t total_entries;
uint32_t dropped_entries;
bool overflow;
};
static struct log_buffer log_ctx;
void log_message(log_level_t level, const char* file, int line, const char* fmt, ...) {
va_list args;
log_entry_t* entry;
// Check if buffer is full
if (((log_ctx.head + 1) % MAX_LOG_ENTRIES) == log_ctx.tail) {
log_ctx.dropped_entries++;
log_ctx.overflow = true;
// Move tail to make room
log_ctx.tail = (log_ctx.tail + 1) % MAX_LOG_ENTRIES;
}
entry = &log_ctx.entries[log_ctx.head];
entry->timestamp = get_system_time();
entry->level = level;
entry->source_line = line;
entry->source_file = file;
va_start(args, fmt);
vsnprintf(entry->message, MAX_LOG_MSG_LEN, fmt, args);
va_end(args);
log_ctx.head = (log_ctx.head + 1) % MAX_LOG_ENTRIES;
log_ctx.total_entries++;
// Output to debug console if enabled
if (is_debug_console_enabled()) {
output_to_debug_console(entry);
}
}
#define LOG_SECTOR_START 0x1F000
#define LOG_SECTORS_COUNT 8
int save_log_to_storage(void) {
uint8_t buffer[SECTOR_SIZE];
uint32_t current_sector = LOG_SECTOR_START;
uint16_t entries_per_sector = SECTOR_SIZE / sizeof(log_entry_t);
uint16_t current_entry = log_ctx.tail;
while (current_entry != log_ctx.head) {
uint16_t count = 0;
uint8_t* ptr = buffer;
// Fill sector buffer
while (count < entries_per_sector && current_entry != log_ctx.head) {
memcpy(ptr, &log_ctx.entries[current_entry], sizeof(log_entry_t));
ptr += sizeof(log_entry_t);
current_entry = (current_entry + 1) % MAX_LOG_ENTRIES;
count++;
}
// Write sector
if (write_sector(current_sector++, buffer) != 0) {
return -1;
}
}
return 0;
}
The bootloader implements a simple task scheduler to manage initialization and background tasks during the boot process.
#define MAX_TASKS 16
#define MAX_TASK_NAME 32
#define TASK_STACK_SIZE 256
typedef enum {
TASK_STATE_IDLE,
TASK_STATE_READY,
TASK_STATE_RUNNING,
TASK_STATE_BLOCKED,
TASK_STATE_SUSPENDED
} task_state_t;
typedef struct task {
char name[MAX_TASK_NAME];
task_state_t state;
uint8_t priority;
void (*entry_point)(void);
uint8_t stack[TASK_STACK_SIZE];
uint16_t stack_pointer;
uint32_t run_count;
uint32_t last_run;
struct task *next;
} task_t;
static struct {
task_t tasks[MAX_TASKS];
task_t *current_task;
task_t *idle_task;
uint8_t task_count;
uint32_t tick_count;
bool scheduling_enabled;
} scheduler_ctx;
task_t *create_task(const char *name, void (*entry)(void), uint8_t priority) {
if (scheduler_ctx.task_count >= MAX_TASKS) {
return NULL;
}
task_t *task = &scheduler_ctx.tasks[scheduler_ctx.task_count++];
strncpy(task->name, name, MAX_TASK_NAME - 1);
task->state = TASK_STATE_READY;
task->priority = priority;
task->entry_point = entry;
task->stack_pointer = TASK_STACK_SIZE - 1;
task->run_count = 0;
task->last_run = 0;
// Initialize task stack
task->stack[task->stack_pointer--] = (uint16_t)entry & 0xFF;
task->stack[task->stack_pointer--] = (uint16_t)entry >> 8;
task->stack[task->stack_pointer] = 0x00; // Initial status register
return task;
}
void schedule(void) {
task_t *next_task = NULL;
uint8_t highest_priority = 0xFF;
// Find highest priority ready task
for (int i = 0; i < scheduler_ctx.task_count; i++) {
task_t *task = &scheduler_ctx.tasks[i];
if (task->state == TASK_STATE_READY &&
task->priority < highest_priority) {
highest_priority = task->priority;
next_task = task;
}
}
if (!next_task) {
next_task = scheduler_ctx.idle_task;
}
if (next_task != scheduler_ctx.current_task) {
task_switch(next_task);
}
}
The boot progress monitoring system tracks and reports the status of the boot sequence, providing feedback through various output channels.
#define MAX_PROGRESS_STAGES 16
#define MAX_STAGE_DESC 64
typedef enum {
PROGRESS_NONE,
PROGRESS_STARTED,
PROGRESS_COMPLETED,
PROGRESS_FAILED,
PROGRESS_SKIPPED
} progress_state_t;
typedef struct {
char description[MAX_STAGE_DESC];
uint8_t percent;
uint32_t start_time;
uint32_t duration;
progress_state_t state;
} boot_stage_t;
static struct {
boot_stage_t stages[MAX_PROGRESS_STAGES];
uint8_t current_stage;
uint8_t total_stages;
uint32_t boot_start_time;
bool verbose_output;
} progress_ctx;
void init_boot_progress(void) {
memset(&progress_ctx, 0, sizeof(progress_ctx));
progress_ctx.boot_start_time = get_system_time();
// Register default boot stages
register_boot_stage("Hardware Detection", 10);
register_boot_stage("Memory Initialization", 20);
register_boot_stage("Device Initialization", 40);
register_boot_stage("Boot Image Loading", 70);
register_boot_stage("System Startup", 100);
}
void update_boot_progress(uint8_t stage, progress_state_t state) {
if (stage >= progress_ctx.total_stages) {
return;
}
boot_stage_t* current = &progress_ctx.stages[stage];
current->state = state;
if (state == PROGRESS_STARTED) {
current->start_time = get_system_time();
} else if (state == PROGRESS_COMPLETED || state == PROGRESS_FAILED) {
current->duration = get_system_time() - current->start_time;
}
display_progress();
}
void display_progress(void) {
const char* state_chars = "-+*!S"; // None, Started, Completed, Failed, Skipped
printf("\rBoot Progress: [");
for (int i = 0; i < progress_ctx.total_stages; i++) {
printf("%c", state_chars[progress_ctx.stages[i].state]);
}
printf("] %d%%", progress_ctx.stages[progress_ctx.current_stage].percent);
if (progress_ctx.verbose_output) {
printf("\n%s: %s",
progress_ctx.stages[progress_ctx.current_stage].description,
progress_ctx.stages[progress_ctx.current_stage].state == PROGRESS_FAILED ?
"FAILED" : "OK");
}
}
The HAL extensions provide additional hardware support and abstraction layers for specialized peripherals.
#define DMA_MAX_CHANNELS 4
#define DMA_BUFFER_SIZE 2048
typedef enum {
DMA_DIR_MEM_TO_MEM,
DMA_DIR_MEM_TO_DEV,
DMA_DIR_DEV_TO_MEM
} dma_direction_t;
struct dma_transfer {
void* src_addr;
void* dst_addr;
uint32_t size;
dma_direction_t direction;
void (*callback)(void* context);
void* context;
};
static struct {
struct dma_transfer active_transfers[DMA_MAX_CHANNELS];
uint8_t channel_mask;
uint32_t transfer_count;
} dma_ctx;
int hal_dma_start_transfer(uint8_t channel, struct dma_transfer* transfer) {
if (channel >= DMA_MAX_CHANNELS || (dma_ctx.channel_mask & (1 << channel))) {
return -1;
}
// Configure DMA hardware registers
uint16_t control = DMA_ENABLE;
if (transfer->direction == DMA_DIR_MEM_TO_DEV) {
control |= DMA_MEM_TO_DEV;
} else if (transfer->direction == DMA_DIR_DEV_TO_MEM) {
control |= DMA_DEV_TO_MEM;
}
outw(DMA_BASE + (channel * 8) + DMA_CONTROL, control);
outl(DMA_BASE + (channel * 8) + DMA_SRC_ADDR, (uint32_t)transfer->src_addr);
outl(DMA_BASE + (channel * 8) + DMA_DST_ADDR, (uint32_t)transfer->dst_addr);
outw(DMA_BASE + (channel * 8) + DMA_COUNT, transfer->size);
// Store transfer info
memcpy(&dma_ctx.active_transfers[channel], transfer, sizeof(struct dma_transfer));
dma_ctx.channel_mask |= (1 << channel);
return 0;
}
The runtime services provide essential functions that can be called during boot and passed to the loaded operating system.
#define MAX_SERVICES 16
#define SERVICE_NAME_MAX 32
typedef enum {
SVC_MEMORY,
SVC_CONSOLE,
SVC_STORAGE,
SVC_TIME,
SVC_CONFIG
} service_type_t;
typedef struct runtime_service {
char name[SERVICE_NAME_MAX];
service_type_t type;
uint32_t version;
void* interface;
bool (*init)(void);
void (*shutdown)(void);
} runtime_service_t;
static struct {
runtime_service_t services[MAX_SERVICES];
uint8_t service_count;
bool initialized;
} service_ctx;
int register_runtime_service(runtime_service_t* service) {
if (service_ctx.service_count >= MAX_SERVICES) {
return -1;
}
// Initialize service if needed
if (service->init && !service->init()) {
return -2;
}
// Add to service registry
memcpy(&service_ctx.services[service_ctx.service_count],
service, sizeof(runtime_service_t));
service_ctx.service_count++;
return 0;
}
void* get_service_interface(service_type_t type) {
for (int i = 0; i < service_ctx.service_count; i++) {
if (service_ctx.services[i].type == type) {
return service_ctx.services[i].interface;
}
}
return NULL;
}
The bootloader needs to pass various parameters and configuration data to the loaded operating system in a structured way.
#define BOOT_PARAM_MAGIC 0x4D314250 // "M1BP"
#define MAX_MEMORY_REGIONS 16
#define MAX_BOOT_MODULES 8
#define MAX_CMDLINE_LENGTH 256
/* Memory region descriptor */
struct memory_region {
uint32_t start;
uint32_t size;
uint32_t flags;
uint32_t type;
};
/* Boot module information */
struct boot_module {
uint32_t start;
uint32_t size;
char name[32];
uint32_t flags;
};
/* Main boot parameter block */
struct boot_params {
uint32_t magic;
uint32_t version;
uint32_t total_size;
/* Memory map */
uint32_t num_memory_regions;
struct memory_region memory_map[MAX_MEMORY_REGIONS];
/* Boot modules */
uint32_t num_modules;
struct boot_module modules[MAX_BOOT_MODULES];
/* Command line */
char cmdline[MAX_CMDLINE_LENGTH];
/* Video information */
uint16_t video_cols;
uint16_t video_rows;
uint32_t framebuffer_addr;
/* Runtime services */
uint32_t runtime_services_ptr;
/* Boot device info */
uint8_t boot_device_type;
uint8_t boot_device_id;
uint16_t boot_partition;
/* Checksum */
uint32_t checksum;
};
static struct boot_params boot_params;
void init_boot_params(void) {
memset(&boot_params, 0, sizeof(struct boot_params));
boot_params.magic = BOOT_PARAM_MAGIC;
boot_params.version = 0x0100; // Version 1.0
boot_params.total_size = sizeof(struct boot_params);
}
int add_memory_region(uint32_t start, uint32_t size, uint32_t type, uint32_t flags) {
if (boot_params.num_memory_regions >= MAX_MEMORY_REGIONS) {
return -1;
}
struct memory_region* region =
&boot_params.memory_map[boot_params.num_memory_regions++];
region->start = start;
region->size = size;
region->type = type;
region->flags = flags;
return 0;
}
void update_checksum(void) {
uint32_t* ptr = (uint32_t*)&boot_params;
uint32_t checksum = 0;
int count = (sizeof(struct boot_params) - sizeof(uint32_t)) / 4;
while (count--) {
checksum += *ptr++;
}
boot_params.checksum = ~checksum + 1; // Two's complement
}
The bootloader implements a compression framework to reduce boot image size and improve load times.
#define COMPRESS_MAGIC 0x4D31435A // "M1CZ"
#define MAX_CHUNK_SIZE 4096
#define MIN_CHUNK_SIZE 512
typedef enum {
COMPRESS_NONE = 0,
COMPRESS_RLE,
COMPRESS_LZ,
COMPRESS_HUFFMAN
} compression_type_t;
struct compressed_header {
uint32_t magic;
uint16_t version;
uint16_t type;
uint32_t original_size;
uint32_t compressed_size;
uint32_t chunk_size;
uint32_t num_chunks;
uint32_t checksum;
};
struct chunk_info {
uint32_t offset;
uint32_t comp_size;
uint32_t orig_size;
uint32_t checksum;
};
static uint8_t work_buffer[MAX_CHUNK_SIZE];
int decompress_boot_image(const uint8_t* src, uint8_t* dst, uint32_t* size) {
struct compressed_header* header = (struct compressed_header*)src;
struct chunk_info* chunks;
uint32_t offset = 0;
// Validate header
if (header->magic != COMPRESS_MAGIC) {
return -1;
}
// Get chunk table
chunks = (struct chunk_info*)(src + sizeof(struct compressed_header));
// Process each chunk
for (uint32_t i = 0; i < header->num_chunks; i++) {
int status;
switch (header->type) {
case COMPRESS_RLE:
status = decompress_rle(
src + chunks[i].offset,
chunks[i].comp_size,
dst + offset,
chunks[i].orig_size
);
break;
case COMPRESS_LZ:
status = decompress_lz(
src + chunks[i].offset,
chunks[i].comp_size,
dst + offset,
chunks[i].orig_size
);
break;
default:
return -2;
}
if (status != 0) {
return status;
}
offset += chunks[i].orig_size;
}
*size = header->original_size;
return 0;
}
The bootloader implements security measures to ensure system integrity and prevent unauthorized modifications.
#define SECURITY_VERSION 0x0100
#define HASH_SIZE 32
#define SIG_SIZE 64
#define KEY_SIZE 32
typedef enum {
SEC_LEVEL_NONE,
SEC_LEVEL_BASIC,
SEC_LEVEL_SECURE,
SEC_LEVEL_MAX
} security_level_t;
struct security_header {
uint16_t version;
uint16_t level;
uint8_t hash[HASH_SIZE];
uint8_t signature[SIG_SIZE];
uint32_t flags;
uint32_t timestamp;
};
static struct {
security_level_t current_level;
uint8_t public_key[KEY_SIZE];
bool secure_boot_enabled;
uint32_t boot_count;
} security_ctx;
int verify_boot_image(const uint8_t* image_data, size_t size) {
struct security_header* header;
uint8_t computed_hash[HASH_SIZE];
if (size < sizeof(struct security_header)) {
return -1;
}
header = (struct security_header*)image_data;
// Verify version compatibility
if (header->version > SECURITY_VERSION) {
return -2;
}
// Calculate image hash
sha256_calculate(image_data + sizeof(struct security_header),
size - sizeof(struct security_header),
computed_hash);
// Compare hashes
if (memcmp(computed_hash, header->hash, HASH_SIZE) != 0) {
return -3;
}
// Verify signature if secure boot enabled
if (security_ctx.secure_boot_enabled) {
if (!verify_signature(computed_hash,
header->signature,
security_ctx.public_key)) {
return -4;
}
}
return 0;
}
The network boot support allows loading boot images and configuration over the network interface.
#define NET_BOOT_PORT 69
#define MAX_PACKET_SIZE 1024
#define MAX_RETRIES 3
#define TIMEOUT_MS 1000
typedef enum {
NET_PROTO_TFTP,
NET_PROTO_HTTP,
NET_PROTO_CUSTOM
} net_protocol_t;
struct net_boot_config {
uint32_t server_ip;
uint16_t server_port;
net_protocol_t protocol;
char boot_file[128];
uint32_t timeout_ms;
};
static struct {
struct net_boot_config config;
uint8_t mac_addr[6];
uint32_t ip_addr;
bool link_up;
uint32_t bytes_received;
} net_ctx;
int init_network_boot(void) {
// Initialize network hardware
if (init_network_hardware() != 0) {
return -1;
}
// Wait for link
uint32_t timeout = 5000; // 5 seconds
while (!net_ctx.link_up && timeout > 0) {
check_link_status();
delay_ms(100);
timeout -= 100;
}
if (!net_ctx.link_up) {
return -2;
}
// Get network config via DHCP
if (get_network_config() != 0) {
return -3;
}
return 0;
}
#define TFTP_RRQ 1
#define TFTP_DATA 3
#define TFTP_ACK 4
#define TFTP_ERROR 5
struct tftp_packet {
uint16_t opcode;
union {
uint16_t block_num;
uint16_t error_code;
};
uint8_t data[512];
};
int download_boot_image_tftp(const char* filename, void* buffer, size_t* size) {
struct tftp_packet packet;
uint16_t block = 1;
size_t total = 0;
// Send initial RRQ
packet.opcode = htons(TFTP_RRQ);
strcpy((char*)packet.data, filename);
send_udp(net_ctx.config.server_ip, NET_BOOT_PORT, &packet,
strlen(filename) + 3);
// Receive data blocks
while (1) {
size_t received = receive_udp(&packet, sizeof(packet));
if (received < 4) continue;
switch (ntohs(packet.opcode)) {
case TFTP_DATA:
if (ntohs(packet.block_num) == block) {
memcpy(buffer + total, packet.data, received - 4);
total += received - 4;
send_tftp_ack(block++);
}
break;
case TFTP_ERROR:
return -1;
}
if (received < 516) break; // Last packet
}
*size = total;
return 0;
}
The bootloader implements various optimizations to reduce boot time and improve performance.
#define MAX_PROFILE_POINTS 32
#define PROFILE_NAME_LEN 32
typedef struct {
char name[PROFILE_NAME_LEN];
uint32_t start_time;
uint32_t duration;
uint32_t calls;
bool active;
} profile_point_t;
struct boot_profile {
profile_point_t points[MAX_PROFILE_POINTS];
uint8_t point_count;
uint32_t total_boot_time;
uint32_t boot_start_time;
};
static struct boot_profile profile_ctx;
void profile_start_point(const char* name) {
for (int i = 0; i < profile_ctx.point_count; i++) {
if (strcmp(profile_ctx.points[i].name, name) == 0) {
if (!profile_ctx.points[i].active) {
profile_ctx.points[i].start_time = get_system_time();
profile_ctx.points[i].active = true;
profile_ctx.points[i].calls++;
}
return;
}
}
// New profile point
if (profile_ctx.point_count < MAX_PROFILE_POINTS) {
profile_point_t* point = &profile_ctx.points[profile_ctx.point_count++];
strncpy(point->name, name, PROFILE_NAME_LEN - 1);
point->start_time = get_system_time();
point->active = true;
point->calls = 1;
}
}
void profile_end_point(const char* name) {
uint32_t end_time = get_system_time();
for (int i = 0; i < profile_ctx.point_count; i++) {
if (strcmp(profile_ctx.points[i].name, name) == 0) {
if (profile_ctx.points[i].active) {
profile_ctx.points[i].duration +=
end_time - profile_ctx.points[i].start_time;
profile_ctx.points[i].active = false;
}
break;
}
}
}
void print_profile_report(void) {
printf("\nBoot Profile Report\n");
printf("==================\n");
printf("Total Boot Time: %d ms\n\n",
get_system_time() - profile_ctx.boot_start_time);
printf("%-20s %10s %10s %10s\n", "Phase", "Calls", "Time(ms)", "%Total");
printf("-------------------------------------------------\n");
for (int i = 0; i < profile_ctx.point_count; i++) {
float percent = (profile_ctx.points[i].duration * 100.0f) /
profile_ctx.total_boot_time;
printf("%-20s %10d %10d %10.1f\n",
profile_ctx.points[i].name,
profile_ctx.points[i].calls,
profile_ctx.points[i].duration,
percent);
}
}
The configuration management system provides a flexible way to manage boot-time settings and parameters.
#define MAX_CONFIG_ENTRIES 64
#define MAX_KEY_LENGTH 32
#define MAX_VALUE_LENGTH 128
typedef enum {
CONFIG_TYPE_STRING,
CONFIG_TYPE_INTEGER,
CONFIG_TYPE_BOOLEAN,
CONFIG_TYPE_ARRAY
} config_type_t;
typedef struct {
char key[MAX_KEY_LENGTH];
config_type_t type;
union {
char str_value[MAX_VALUE_LENGTH];
int64_t int_value;
bool bool_value;
struct {
void* data;
size_t length;
} array;
};
} config_entry_t;
static struct {
config_entry_t entries[MAX_CONFIG_ENTRIES];
uint16_t entry_count;
bool modified;
char config_file[256];
} config_ctx;
int load_boot_config(const char* filename) {
FILE* fp = fopen(filename, "r");
if (!fp) {
return -1;
}
char line[256];
while (fgets(line, sizeof(line), fp)) {
char key[MAX_KEY_LENGTH];
char value[MAX_VALUE_LENGTH];
// Skip comments and empty lines
if (line[0] == '#' || line[0] == '\n') {
continue;
}
if (sscanf(line, "%31[^=]=%127[^\n]", key, value) == 2) {
// Trim whitespace
trim_string(key);
trim_string(value);
// Store configuration
set_config_value(key, value);
}
}
fclose(fp);
strncpy(config_ctx.config_file, filename, sizeof(config_ctx.config_file) - 1);
return 0;
}
The boot menu provides an interactive interface for selecting boot options and configuring system parameters.
#define MAX_MENU_ITEMS 16
#define MAX_ITEM_TEXT 64
#define MAX_MENU_DEPTH 4
typedef enum {
MENU_ACTION_BOOT,
MENU_ACTION_SUBMENU,
MENU_ACTION_COMMAND,
MENU_ACTION_EXIT
} menu_action_t;
typedef struct menu_item {
char text[MAX_ITEM_TEXT];
menu_action_t action;
union {
struct {
char image_name[32];
char parameters[64];
} boot;
struct menu* submenu;
void (*command)(void);
};
bool enabled;
} menu_item_t;
typedef struct menu {
char title[MAX_ITEM_TEXT];
menu_item_t items[MAX_MENU_ITEMS];
uint8_t item_count;
struct menu* parent;
} menu_t;
static struct {
menu_t* current_menu;
menu_t* root_menu;
uint8_t timeout;
bool timeout_enabled;
uint32_t last_input;
} menu_ctx;
void display_menu(menu_t* menu) {
clear_screen();
printf("\n%s\n", menu->title);
printf("==================\n\n");
for (int i = 0; i < menu->item_count; i++) {
if (menu->items[i].enabled) {
printf("%d. %s\n", i + 1, menu->items[i].text);
} else {
printf(" %s (Disabled)\n", menu->items[i].text);
}
}
if (menu->parent) {
printf("\n0. Back\n");
}
if (menu_ctx.timeout_enabled) {
printf("\nAutoboot in %d seconds...\n", menu_ctx.timeout);
}
printf("\nSelect option: ");
}
int handle_menu_input(char input) {
int selection = input - '0';
menu_item_t* item;
if (selection < 0 || selection > menu_ctx.current_menu->item_count) {
return -1;
}
if (selection == 0 && menu_ctx.current_menu->parent) {
menu_ctx.current_menu = menu_ctx.current_menu->parent;
return 0;
}
item = &menu_ctx.current_menu->items[selection - 1];
if (!item->enabled) {
return -1;
}
switch (item->action) {
case MENU_ACTION_BOOT:
return boot_system(item->boot.image_name, item->boot.parameters);
case MENU_ACTION_SUBMENU:
menu_ctx.current_menu = item->submenu;
break;
case MENU_ACTION_COMMAND:
item->command();
break;
case MENU_ACTION_EXIT:
return 1;
}
return 0;
}
Type 'next' for Part 46 covering Boot Process State Machine.
The boot process state machine manages the sequence of operations required to initialize the system and load the operating system.
typedef enum {
BOOT_STATE_RESET,
BOOT_STATE_EARLY_INIT,
BOOT_STATE_HARDWARE_INIT,
BOOT_STATE_MEMORY_INIT,
BOOT_STATE_DEVICE_INIT,
BOOT_STATE_LOAD_CONFIG,
BOOT_STATE_MENU,
BOOT_STATE_LOAD_IMAGE,
BOOT_STATE_PREPARE_EXIT,
BOOT_STATE_EXIT,
BOOT_STATE_ERROR
} boot_state_t;
typedef struct {
boot_state_t current;
boot_state_t previous;
uint32_t entry_time;
uint32_t timeout;
char error_message[128];
bool menu_enabled;
bool timeout_enabled;
} boot_context_t;
static boot_context_t boot_ctx;
static const struct {
boot_state_t state;
const char* name;
int (*handler)(void);
uint32_t timeout; // Maximum time in ms
} state_table[] = {
{ BOOT_STATE_RESET, "System Reset", handle_reset, 1000 },
{ BOOT_STATE_EARLY_INIT, "Early Init", handle_early_init, 2000 },
{ BOOT_STATE_HARDWARE_INIT, "Hardware Init", handle_hw_init, 5000 },
{ BOOT_STATE_MEMORY_INIT, "Memory Init", handle_mem_init, 3000 },
{ BOOT_STATE_DEVICE_INIT, "Device Init", handle_dev_init, 4000 },
{ BOOT_STATE_LOAD_CONFIG, "Load Config", handle_config, 2000 },
{ BOOT_STATE_MENU, "Boot Menu", handle_menu, 30000},
{ BOOT_STATE_LOAD_IMAGE, "Load Image", handle_load_image, 5000 },
{ BOOT_STATE_PREPARE_EXIT,"Prepare Exit", handle_prep_exit, 1000 },
{ BOOT_STATE_EXIT, "Exit Boot", handle_exit, 1000 },
{ BOOT_STATE_ERROR, "Error", handle_error, 0 },
{ 0, NULL, NULL, 0 }
};
int execute_boot_sequence(void) {
int status;
uint32_t current_time;
boot_ctx.current = BOOT_STATE_RESET;
boot_ctx.entry_time = get_system_time();
while (1) {
current_time = get_system_time();
// Execute current state handler
for (int i = 0; state_table[i].handler != NULL; i++) {
if (state_table[i].state == boot_ctx.current) {
// Check for timeout
if (state_table[i].timeout > 0 &&
(current_time - boot_ctx.entry_time) > state_table[i].timeout) {
sprintf(boot_ctx.error_message, "Timeout in state %s",
state_table[i].name);
boot_ctx.current = BOOT_STATE_ERROR;
break;
}
status = state_table[i].handler();
if (status != 0) {
boot_ctx.current = BOOT_STATE_ERROR;
}
break;
}
}
if (boot_ctx.current == BOOT_STATE_EXIT) {
return 0;
} else if (boot_ctx.current == BOOT_STATE_ERROR) {
return -1;
}
}
}
The boot storage management system provides a unified interface for accessing different storage devices and file systems during the boot process.
#define MAX_STORAGE_DEVICES 4
#define SECTOR_SIZE 512
#define MAX_RETRIES 3
typedef enum {
STORAGE_TYPE_IDE,
STORAGE_TYPE_FLASH,
STORAGE_TYPE_MMC,
STORAGE_TYPE_NET
} storage_type_t;
typedef struct storage_device {
storage_type_t type;
uint8_t id;
uint32_t sector_count;
bool bootable;
char name[32];
/* Device operations */
int (*init)(struct storage_device* dev);
int (*read_sectors)(struct storage_device* dev, uint32_t start,
uint32_t count, void* buffer);
int (*write_sectors)(struct storage_device* dev, uint32_t start,
uint32_t count, const void* buffer);
void (*shutdown)(struct storage_device* dev);
} storage_device_t;
static struct {
storage_device_t* devices[MAX_STORAGE_DEVICES];
uint8_t device_count;
storage_device_t* boot_device;
} storage_ctx;
int register_storage_device(storage_device_t* device) {
if (storage_ctx.device_count >= MAX_STORAGE_DEVICES) {
return -1;
}
// Initialize device
if (device->init && device->init(device) != 0) {
return -2;
}
storage_ctx.devices[storage_ctx.device_count++] = device;
// Update boot device if this is bootable
if (device->bootable && !storage_ctx.boot_device) {
storage_ctx.boot_device = device;
}
return 0;
}
The boot progress reporting system provides feedback about the boot sequence status through various output channels.
First, let's define our progress reporting structures:
#define MAX_PROGRESS_STAGES 16
#define MAX_STAGE_NAME 32
#define MAX_STATUS_MSG 64
typedef enum {
PROGRESS_PENDING,
PROGRESS_RUNNING,
PROGRESS_SUCCESS,
PROGRESS_FAILED,
PROGRESS_SKIPPED
} progress_state_t;
typedef struct {
char name[MAX_STAGE_NAME];
uint8_t percent;
progress_state_t state;
uint32_t start_time;
uint32_t duration;
char status[MAX_STATUS_MSG];
} progress_stage_t;
typedef struct {
progress_stage_t stages[MAX_PROGRESS_STAGES];
uint8_t current_stage;
uint8_t total_stages;
uint32_t boot_start_time;
bool verbose_mode;
} progress_context_t;
Here's the core progress manager implementation:
static progress_context_t progress_ctx;
void init_progress_manager(void) {
memset(&progress_ctx, 0, sizeof(progress_context_t));
progress_ctx.boot_start_time = get_system_time();
progress_ctx.verbose_mode = true;
// Register default boot stages
register_boot_stage("Hardware Detection", 0);
register_boot_stage("Memory Initialization", 20);
register_boot_stage("Device Initialization", 40);
register_boot_stage("Configuration Loading", 60);
register_boot_stage("Boot Image Loading", 80);
register_boot_stage("System Startup", 100);
}
void update_boot_progress(uint8_t stage, progress_state_t state, const char* msg) {
if (stage >= progress_ctx.total_stages) {
return;
}
progress_stage_t* current = &progress_ctx.stages[stage];
current->state = state;
if (msg) {
strncpy(current->status, msg, MAX_STATUS_MSG - 1);
}
if (state == PROGRESS_RUNNING) {
current->start_time = get_system_time();
} else if (state == PROGRESS_SUCCESS || state == PROGRESS_FAILED) {
current->duration = get_system_time() - current->start_time;
}
display_progress();
}
The memory management system handles dynamic memory allocation, memory mapping, and memory protection during the boot process.
#define PAGE_SIZE 2048
#define MAX_MEMORY_BLOCKS 256
#define MEMORY_ALIGNMENT 8
typedef struct memory_block {
void* address;
size_t size;
bool free;
struct memory_block* next;
} memory_block_t;
typedef struct {
void* heap_start;
void* heap_end;
size_t total_size;
size_t free_size;
memory_block_t blocks[MAX_MEMORY_BLOCKS];
uint16_t block_count;
} memory_manager_t;
static memory_manager_t memory_ctx;
void init_memory_manager(void* start, size_t size) {
memory_ctx.heap_start = (void*)((uintptr_t)(start + MEMORY_ALIGNMENT - 1)
& ~(MEMORY_ALIGNMENT - 1));
memory_ctx.heap_end = (void*)((uintptr_t)start + size);
memory_ctx.total_size = (uintptr_t)memory_ctx.heap_end -
(uintptr_t)memory_ctx.heap_start;
memory_ctx.free_size = memory_ctx.total_size;
memory_ctx.block_count = 1;
// Initialize first block as free
memory_ctx.blocks[0].address = memory_ctx.heap_start;
memory_ctx.blocks[0].size = memory_ctx.total_size;
memory_ctx.blocks[0].free = true;
memory_ctx.blocks[0].next = NULL;
}
void* boot_malloc(size_t size) {
size_t aligned_size = (size + MEMORY_ALIGNMENT - 1) & ~(MEMORY_ALIGNMENT - 1);
memory_block_t* block;
for (uint16_t i = 0; i < memory_ctx.block_count; i++) {
block = &memory_ctx.blocks[i];
if (block->free && block->size >= aligned_size) {
// Split block if possible
if (block->size > aligned_size + sizeof(memory_block_t)) {
memory_block_t* new_block = &memory_ctx.blocks[memory_ctx.block_count++];
new_block->address = block->address + aligned_size;
new_block->size = block->size - aligned_size;
new_block->free = true;
new_block->next = block->next;
block->size = aligned_size;
block->next = new_block;
}
block->free = false;
memory_ctx.free_size -= block->size;
return block->address;
}
}
return NULL;
}
The error handling system manages and responds to various error conditions during the boot process.
#define MAX_ERROR_STACK 16
#define MAX_ERROR_MSG 128
typedef enum {
ERR_NONE = 0,
ERR_HARDWARE_INIT,
ERR_MEMORY_INIT,
ERR_DEVICE_INIT,
ERR_CONFIG_LOAD,
ERR_IMAGE_LOAD,
ERR_CHECKSUM,
ERR_TIMEOUT,
ERR_FATAL
} error_code_t;
typedef struct {
error_code_t code;
char message[MAX_ERROR_MSG];
uint32_t timestamp;
const char* file;
int line;
} error_info_t;
static struct {
error_info_t error_stack[MAX_ERROR_STACK];
uint8_t stack_ptr;
bool panic_mode;
void (*error_callback)(error_info_t*);
} error_ctx;
void handle_error(error_code_t code, const char* msg, const char* file, int line) {
error_info_t* error;
// Push error to stack
if (error_ctx.stack_ptr < MAX_ERROR_STACK) {
error = &error_ctx.error_stack[error_ctx.stack_ptr++];
error->code = code;
strncpy(error->message, msg, MAX_ERROR_MSG - 1);
error->timestamp = get_system_time();
error->file = file;
error->line = line;
// Call error callback if registered
if (error_ctx.error_callback) {
error_ctx.error_callback(error);
}
// Enter panic mode for fatal errors
if (code == ERR_FATAL) {
error_ctx.panic_mode = true;
panic_handler();
}
}
}
void display_error_stack(void) {
printf("\nError Stack Trace:\n");
printf("=================\n");
for (int i = error_ctx.stack_ptr - 1; i >= 0; i--) {
error_info_t* error = &error_ctx.error_stack[i];
printf("[%08x] %s:%d - %s\n",
error->timestamp,
error->file,
error->line,
error->message);
}
}
The device discovery system automatically detects and initializes available boot devices during the boot process.
#define MAX_BOOT_DEVICES 8
#define MAX_DEVICE_NAME 32
typedef enum {
DEV_TYPE_IDE,
DEV_TYPE_FLASH,
DEV_TYPE_MMC,
DEV_TYPE_NET,
DEV_TYPE_UNKNOWN
} device_type_t;
typedef struct {
device_type_t type;
uint16_t vendor_id;
uint16_t device_id;
char name[MAX_DEVICE_NAME];
bool bootable;
void* device_data;
} boot_device_t;
static struct {
boot_device_t devices[MAX_BOOT_DEVICES];
uint8_t device_count;
bool discovery_complete;
} discovery_ctx;
int discover_boot_devices(void) {
// Scan IDE/ATA devices
scan_ide_devices();
// Scan MMC/SD devices
scan_mmc_devices();
// Scan network interfaces
scan_network_devices();
discovery_ctx.discovery_complete = true;
return discovery_ctx.device_count;
}
static void scan_ide_devices(void) {
uint16_t base_ports[] = { 0x1F0, 0x170 };
for (int i = 0; i < 2; i++) {
uint16_t base = base_ports[i];
uint8_t status = inb(base + 7); // Read status register
if (status != 0xFF) { // Device present
boot_device_t* dev = &discovery_ctx.devices[discovery_ctx.device_count++];
dev->type = DEV_TYPE_IDE;
dev->vendor_id = inw(base + 0);
dev->device_id = inw(base + 2);
snprintf(dev->name, MAX_DEVICE_NAME, "IDE%d", i);
dev->bootable = check_bootable(dev);
}
}
}
The reporting system tracks and logs the boot process status, providing detailed information about each stage of system initialization.
#define MAX_STATUS_ENTRIES 64
#define MAX_STATUS_MSG 128
#define MAX_COMPONENT_NAME 32
typedef enum {
STATUS_INFO,
STATUS_WARNING,
STATUS_ERROR,
STATUS_DEBUG
} status_type_t;
typedef struct {
uint32_t timestamp;
status_type_t type;
char component[MAX_COMPONENT_NAME];
char message[MAX_STATUS_MSG];
uint32_t sequence;
} status_entry_t;
static struct {
status_entry_t entries[MAX_STATUS_ENTRIES];
uint32_t entry_count;
uint32_t sequence_counter;
bool console_output;
bool file_output;
char log_file[256];
} status_ctx;
void report_status(status_type_t type, const char* component, const char* format, ...) {
status_entry_t* entry;
va_list args;
if (status_ctx.entry_count >= MAX_STATUS_ENTRIES) {
// Rotate entries if buffer full
memmove(&status_ctx.entries[0],
&status_ctx.entries[1],
sizeof(status_entry_t) * (MAX_STATUS_ENTRIES - 1));
status_ctx.entry_count--;
}
entry = &status_ctx.entries[status_ctx.entry_count++];
entry->timestamp = get_system_time();
entry->type = type;
entry->sequence = status_ctx.sequence_counter++;
strncpy(entry->component, component, MAX_COMPONENT_NAME - 1);
va_start(args, format);
vsnprintf(entry->message, MAX_STATUS_MSG - 1, format, args);
va_end(args);
// Output to console if enabled
if (status_ctx.console_output) {
const char* type_str[] = {"INFO", "WARN", "ERROR", "DEBUG"};
printf("[%08x][%s][%s] %s\n",
entry->timestamp,
type_str[entry->type],
entry->component,
entry->message);
}
}
The statistics system collects and analyzes performance metrics during the boot process.
#define MAX_STAT_COUNTERS 32
#define MAX_STAT_NAME 48
typedef enum {
STAT_TYPE_COUNTER,
STAT_TYPE_GAUGE,
STAT_TYPE_TIMER
} stat_type_t;
typedef struct {
char name[MAX_STAT_NAME];
stat_type_t type;
union {
uint64_t counter;
int64_t gauge;
struct {
uint32_t start;
uint32_t total;
uint32_t count;
} timer;
} value;
} boot_stat_t;
static struct {
boot_stat_t stats[MAX_STAT_COUNTERS];
uint16_t stat_count;
uint32_t boot_start_time;
bool collection_enabled;
} stats_ctx;
void init_boot_stats(void) {
memset(&stats_ctx, 0, sizeof(stats_ctx));
stats_ctx.boot_start_time = get_system_time();
stats_ctx.collection_enabled = true;
// Register core statistics
register_counter("memory.allocations");
register_counter("disk.reads");
register_counter("disk.errors");
register_gauge("memory.available");
register_timer("boot.total_time");
}
void update_stat(const char* name, int64_t value) {
boot_stat_t* stat = find_stat(name);
if (stat && stats_ctx.collection_enabled) {
switch (stat->type) {
case STAT_TYPE_COUNTER:
stat->value.counter += value;
break;
case STAT_TYPE_GAUGE:
stat->value.gauge = value;
break;
}
}
}
void start_timer(const char* name) {
boot_stat_t* stat = find_stat(name);
if (stat && stat->type == STAT_TYPE_TIMER) {
stat->value.timer.start = get_system_time();
}
}
void stop_timer(const char* name) {
boot_stat_t* stat = find_stat(name);
if (stat && stat->type == STAT_TYPE_TIMER) {
uint32_t duration = get_system_time() - stat->value.timer.start;
stat->value.timer.total += duration;
stat->value.timer.count++;
}
}
The verification system ensures system integrity and validates critical boot components.
#define MAX_VERIFY_CHECKS 32
#define HASH_LENGTH 32
typedef enum {
VERIFY_MEMORY,
VERIFY_DEVICE,
VERIFY_IMAGE,
VERIFY_CONFIG
} verify_type_t;
typedef struct {
verify_type_t type;
const char* component;
uint8_t expected_hash[HASH_LENGTH];
bool (*verify_func)(void* data);
bool required;
} verify_check_t;
static struct {
verify_check_t checks[MAX_VERIFY_CHECKS];
uint8_t check_count;
uint32_t last_verify;
bool verify_enabled;
} verify_ctx;
int register_verify_check(verify_check_t* check) {
if (verify_ctx.check_count >= MAX_VERIFY_CHECKS) {
return -1;
}
memcpy(&verify_ctx.checks[verify_ctx.check_count++],
check, sizeof(verify_check_t));
return 0;
}
bool verify_boot_components(void) {
bool success = true;
for (int i = 0; i < verify_ctx.check_count; i++) {
verify_check_t* check = &verify_ctx.checks[i];
bool result = check->verify_func(NULL);
if (!result && check->required) {
log_error("Verification failed for %s", check->component);
success = false;
}
}
verify_ctx.last_verify = get_system_time();
return success;
}
The monitoring system provides real-time insight into the boot process, tracking key metrics and system health.
#define MAX_MONITORS 16
#define MAX_SAMPLES 128
#define MONITOR_INTERVAL_MS 100
typedef enum {
MONITOR_CPU_USAGE,
MONITOR_MEMORY_USAGE,
MONITOR_DISK_IO,
MONITOR_TEMPERATURE
} monitor_type_t;
struct monitor_sample {
uint32_t timestamp;
int64_t value;
};
struct monitor_config {
monitor_type_t type;
const char* name;
uint32_t interval_ms;
int64_t warning_threshold;
int64_t critical_threshold;
void (*callback)(int64_t value);
};
static struct {
struct monitor_config configs[MAX_MONITORS];
struct monitor_sample samples[MAX_MONITORS][MAX_SAMPLES];
uint8_t monitor_count;
uint8_t sample_indices[MAX_MONITORS];
bool monitoring_active;
} monitor_ctx;
void update_monitors(void) {
uint32_t current_time = get_system_time();
for (int i = 0; i < monitor_ctx.monitor_count; i++) {
struct monitor_config* config = &monitor_ctx.configs[i];
// Check if it's time to sample
if ((current_time % config->interval_ms) == 0) {
int64_t value = sample_monitor(config->type);
uint8_t index = monitor_ctx.sample_indices[i];
// Store sample
monitor_ctx.samples[i][index].timestamp = current_time;
monitor_ctx.samples[i][index].value = value;
// Update index
monitor_ctx.sample_indices[i] = (index + 1) % MAX_SAMPLES;
// Check thresholds
if (value >= config->critical_threshold) {
log_critical("Monitor %s exceeded critical threshold: %lld",
config->name, value);
} else if (value >= config->warning_threshold) {
log_warning("Monitor %s exceeded warning threshold: %lld",
config->name, value);
}
// Execute callback if configured
if (config->callback) {
config->callback(value);
}
}
}
}
The configuration validation system ensures that boot parameters and settings are correct and consistent before the boot process begins.
#define MAX_VALIDATORS 32
#define MAX_ERROR_MSG 128
typedef enum {
VAL_TYPE_RANGE,
VAL_TYPE_ENUM,
VAL_TYPE_STRING,
VAL_TYPE_DEPENDENCY
} validator_type_t;
typedef struct {
const char* param_name;
validator_type_t type;
union {
struct {
int64_t min;
int64_t max;
} range;
struct {
const char** values;
int count;
} enum_values;
struct {
size_t min_len;
size_t max_len;
const char* pattern;
} string;
struct {
const char* depends_on;
const char* required_value;
} dependency;
};
bool required;
char error_msg[MAX_ERROR_MSG];
} config_validator_t;
static struct {
config_validator_t validators[MAX_VALIDATORS];
uint8_t validator_count;
bool validation_enabled;
} validator_ctx;
int validate_config_param(const char* param_name, const char* value) {
for (int i = 0; i < validator_ctx.validator_count; i++) {
config_validator_t* val = &validator_ctx.validators[i];
if (strcmp(val->param_name, param_name) == 0) {
switch (val->type) {
case VAL_TYPE_RANGE: {
int64_t num_val = strtoll(value, NULL, 0);
if (num_val < val->range.min || num_val > val->range.max) {
snprintf(val->error_msg, MAX_ERROR_MSG,
"Parameter %s value %ld outside range [%ld,%ld]",
param_name, num_val,
val->range.min, val->range.max);
return -1;
}
break;
}
case VAL_TYPE_ENUM: {
bool found = false;
for (int j = 0; j < val->enum_values.count; j++) {
if (strcmp(value, val->enum_values.values[j]) == 0) {
found = true;
break;
}
}
if (!found) {
snprintf(val->error_msg, MAX_ERROR_MSG,
"Invalid value for parameter %s", param_name);
return -1;
}
break;
}
}
return 0;
}
}
return -1; // Validator not found
}
The recovery system provides mechanisms to handle boot failures and restore system functionality.
#define MAX_RECOVERY_ATTEMPTS 3
#define MAX_RECOVERY_POINTS 8
typedef enum {
RECOVERY_NORMAL,
RECOVERY_FALLBACK,
RECOVERY_SAFE_MODE,
RECOVERY_EMERGENCY
} recovery_mode_t;
typedef struct {
uint32_t timestamp;
recovery_mode_t mode;
uint8_t boot_device;
uint32_t config_version;
char image_name[64];
} recovery_point_t;
static struct {
recovery_point_t points[MAX_RECOVERY_POINTS];
uint8_t point_count;
uint8_t attempt_count;
recovery_mode_t current_mode;
bool recovery_active;
} recovery_ctx;
int enter_recovery_mode(recovery_mode_t mode) {
if (recovery_ctx.attempt_count >= MAX_RECOVERY_ATTEMPTS) {
log_error("Maximum recovery attempts exceeded");
return -1;
}
recovery_ctx.current_mode = mode;
recovery_ctx.recovery_active = true;
recovery_ctx.attempt_count++;
// Create recovery point
if (recovery_ctx.point_count < MAX_RECOVERY_POINTS) {
recovery_point_t* point = &recovery_ctx.points[recovery_ctx.point_count++];
point->timestamp = get_system_time();
point->mode = mode;
point->boot_device = get_current_boot_device();
point->config_version = get_config_version();
strncpy(point->image_name, get_boot_image_name(), 63);
}
// Apply recovery strategy
switch (mode) {
case RECOVERY_FALLBACK:
return load_fallback_image();
case RECOVERY_SAFE_MODE:
return enter_safe_mode();
case RECOVERY_EMERGENCY:
return enter_emergency_shell();
default:
return -1;
}
}
The diagnostics system provides tools for analyzing and troubleshooting boot-time issues.
#define MAX_DIAG_TESTS 32
#define MAX_TEST_NAME 64
#define MAX_RESULT_MSG 128
typedef enum {
DIAG_STATUS_PASS,
DIAG_STATUS_FAIL,
DIAG_STATUS_SKIP,
DIAG_STATUS_ERROR
} diag_status_t;
typedef struct {
char name[MAX_TEST_NAME];
diag_status_t (*test_func)(void);
bool enabled;
uint32_t timeout_ms;
char result[MAX_RESULT_MSG];
} diagnostic_test_t;
static struct {
diagnostic_test_t tests[MAX_DIAG_TESTS];
uint8_t test_count;
bool diag_mode;
} diag_ctx;
void run_diagnostics(void) {
printf("\nRunning Boot Diagnostics\n");
printf("======================\n\n");
uint32_t pass_count = 0;
uint32_t fail_count = 0;
for (int i = 0; i < diag_ctx.test_count; i++) {
diagnostic_test_t* test = &diag_ctx.tests[i];
if (!test->enabled) {
continue;
}
printf("Running test: %s...", test->name);
uint32_t start_time = get_system_time();
diag_status_t status = test->test_func();
uint32_t duration = get_system_time() - start_time;
switch (status) {
case DIAG_STATUS_PASS:
printf("PASS (%dms)\n", duration);
pass_count++;
break;
case DIAG_STATUS_FAIL:
printf("FAIL (%dms)\n", duration);
printf(" Error: %s\n", test->result);
fail_count++;
break;
case DIAG_STATUS_SKIP:
printf("SKIP\n");
break;
case DIAG_STATUS_ERROR:
printf("ERROR (%dms)\n", duration);
printf(" Error: %s\n", test->result);
fail_count++;
break;
}
}
printf("\nDiagnostics Complete: %d passed, %d failed\n",
pass_count, fail_count);
}
The optimization system improves boot performance through caching, prefetching, and parallel initialization.
#define MAX_CACHE_ENTRIES 64
#define MAX_PREFETCH_QUEUE 32
#define CACHE_LINE_SIZE 256
typedef enum {
OPT_LEVEL_NONE,
OPT_LEVEL_BASIC,
OPT_LEVEL_AGGRESSIVE,
OPT_LEVEL_MAX
} opt_level_t;
struct cache_entry {
uint32_t address;
uint32_t size;
uint32_t access_count;
uint32_t last_access;
uint8_t data[CACHE_LINE_SIZE];
};
static struct {
struct cache_entry entries[MAX_CACHE_ENTRIES];
uint16_t entry_count;
uint32_t hits;
uint32_t misses;
bool enabled;
} cache_ctx;
void* optimized_read(uint32_t address, size_t size) {
// Check cache first
for (int i = 0; i < cache_ctx.entry_count; i++) {
struct cache_entry* entry = &cache_ctx.entries[i];
if (entry->address <= address &&
address + size <= entry->address + entry->size) {
cache_ctx.hits++;
entry->access_count++;
entry->last_access = get_system_time();
return entry->data + (address - entry->address);
}
}
// Cache miss - load from memory
cache_ctx.misses++;
if (cache_ctx.entry_count < MAX_CACHE_ENTRIES) {
struct cache_entry* new_entry = &cache_ctx.entries[cache_ctx.entry_count++];
new_entry->address = address & ~(CACHE_LINE_SIZE - 1);
new_entry->size = CACHE_LINE_SIZE;
new_entry->access_count = 1;
new_entry->last_access = get_system_time();
memcpy(new_entry->data, (void*)new_entry->address, CACHE_LINE_SIZE);
return new_entry->data + (address - new_entry->address);
}
// Cache full - return direct memory access
return (void*)address;
}
The security system implements core protection mechanisms to ensure secure boot operations and system integrity.
#define HASH_LENGTH 32
#define KEY_LENGTH 64
#define MAX_SIGNATURES 4
typedef enum {
SEC_LEVEL_DISABLED,
SEC_LEVEL_BASIC,
SEC_LEVEL_STRICT,
SEC_LEVEL_MAX
} security_level_t;
typedef struct {
uint8_t hash[HASH_LENGTH];
uint8_t signature[KEY_LENGTH];
uint32_t timestamp;
uint32_t flags;
} security_header_t;
static struct {
security_level_t current_level;
uint8_t public_key[KEY_LENGTH];
bool secure_boot;
uint32_t boot_count;
security_header_t last_boot;
} security_ctx;
int verify_boot_image(const uint8_t* image, size_t size) {
security_header_t* header = (security_header_t*)image;
uint8_t computed_hash[HASH_LENGTH];
// Verify image size
if (size < sizeof(security_header_t)) {
return -1;
}
// Calculate image hash
sha256_calculate(image + sizeof(security_header_t),
size - sizeof(security_header_t),
computed_hash);
// Compare hashes
if (memcmp(computed_hash, header->hash, HASH_LENGTH) != 0) {
log_error("Image hash verification failed");
return -2;
}
// Verify signature if secure boot enabled
if (security_ctx.secure_boot) {
if (!verify_signature(computed_hash,
header->signature,
security_ctx.public_key)) {
log_error("Image signature verification failed");
return -3;
}
}
// Store last successful boot info
memcpy(&security_ctx.last_boot, header, sizeof(security_header_t));
security_ctx.boot_count++;
return 0;
}
The logging system provides structured logging capabilities for tracking boot-time events and diagnostics.
#define LOG_BUFFER_SIZE 4096
#define MAX_LOG_ENTRY_SIZE 256
#define MAX_LOG_HANDLERS 8
typedef enum {
LOG_LEVEL_DEBUG,
LOG_LEVEL_INFO,
LOG_LEVEL_WARN,
LOG_LEVEL_ERROR,
LOG_LEVEL_FATAL
} log_level_t;
typedef struct {
uint32_t timestamp;
log_level_t level;
uint32_t sequence;
const char* source;
char message[MAX_LOG_ENTRY_SIZE];
} log_entry_t;
static struct {
uint8_t buffer[LOG_BUFFER_SIZE];
uint32_t write_pos;
uint32_t sequence;
log_level_t min_level;
void (*handlers[MAX_LOG_HANDLERS])(const log_entry_t*);
uint8_t handler_count;
} log_ctx;
void log_message(log_level_t level, const char* source, const char* fmt, ...) {
if (level < log_ctx.min_level) {
return;
}
va_list args;
log_entry_t entry;
// Initialize entry
entry.timestamp = get_system_time();
entry.level = level;
entry.sequence = log_ctx.sequence++;
entry.source = source;
// Format message
va_start(args, fmt);
vsnprintf(entry.message, MAX_LOG_ENTRY_SIZE - 1, fmt, args);
va_end(args);
// Write to circular buffer
size_t entry_size = sizeof(log_entry_t);
if (log_ctx.write_pos + entry_size > LOG_BUFFER_SIZE) {
log_ctx.write_pos = 0;
}
memcpy(&log_ctx.buffer[log_ctx.write_pos], &entry, entry_size);
log_ctx.write_pos += entry_size;
// Call registered handlers
for (int i = 0; i < log_ctx.handler_count; i++) {
if (log_ctx.handlers[i]) {
log_ctx.handlers[i](&entry);
}
}
}
The timing analysis system measures and profiles various aspects of the boot sequence for optimization purposes.
#define MAX_TIME_POINTS 64
#define MAX_TIMING_NAME 32
typedef struct {
char name[MAX_TIMING_NAME];
uint32_t start_time;
uint32_t duration;
uint32_t min_time;
uint32_t max_time;
uint32_t count;
bool active;
} timing_point_t;
struct timing_context {
timing_point_t points[MAX_TIME_POINTS];
uint16_t point_count;
uint32_t boot_start;
bool timing_enabled;
};
static struct timing_context timing_ctx;
void start_timing(const char* name) {
for (int i = 0; i < timing_ctx.point_count; i++) {
timing_point_t* point = &timing_ctx.points[i];
if (strcmp(point->name, name) == 0) {
point->start_time = get_system_time();
point->active = true;
return;
}
}
// New timing point
if (timing_ctx.point_count < MAX_TIME_POINTS) {
timing_point_t* new_point = &timing_ctx.points[timing_ctx.point_count++];
strncpy(new_point->name, name, MAX_TIMING_NAME - 1);
new_point->start_time = get_system_time();
new_point->min_time = UINT32_MAX;
new_point->active = true;
}
}
void stop_timing(const char* name) {
uint32_t end_time = get_system_time();
for (int i = 0; i < timing_ctx.point_count; i++) {
timing_point_t* point = &timing_ctx.points[i];
if (strcmp(point->name, name) == 0 && point->active) {
uint32_t duration = end_time - point->start_time;
point->duration += duration;
point->count++;
point->active = false;
if (duration < point->min_time) {
point->min_time = duration;
}
if (duration > point->max_time) {
point->max_time = duration;
}
break;
}
}
}
The resource management system tracks and controls system resources during the boot process to ensure efficient allocation and prevent conflicts.
#define MAX_RESOURCES 32
#define MAX_RESOURCE_NAME 48
typedef enum {
RESOURCE_MEMORY,
RESOURCE_IO_PORT,
RESOURCE_IRQ,
RESOURCE_DMA
} resource_type_t;
typedef struct {
char name[MAX_RESOURCE_NAME];
resource_type_t type;
uint32_t start;
uint32_t size;
bool allocated;
const char* owner;
} resource_t;
static struct {
resource_t resources[MAX_RESOURCES];
uint16_t resource_count;
bool tracking_enabled;
uint32_t allocation_count;
} resource_ctx;
void* allocate_resource(resource_type_t type, uint32_t size, const char* owner) {
if (!resource_ctx.tracking_enabled) {
return NULL;
}
// Find available resource
for (int i = 0; i < resource_ctx.resource_count; i++) {
resource_t* res = &resource_ctx.resources[i];
if (!res->allocated && res->type == type && res->size >= size) {
res->allocated = true;
res->owner = owner;
resource_ctx.allocation_count++;
log_info("Resource allocated: %s by %s", res->name, owner);
return (void*)res->start;
}
}
log_error("Failed to allocate resource type %d size %d for %s",
type, size, owner);
return NULL;
}
The power management system controls system power states and transitions during the boot process.
#define MAX_POWER_STATES 8
#define MAX_STATE_NAME 32
typedef enum {
POWER_STATE_FULL, // Full power, all systems running
POWER_STATE_NORMAL, // Normal operation
POWER_STATE_SAVE, // Power saving mode
POWER_STATE_STANDBY, // Standby mode
POWER_STATE_OFF // Power off
} power_state_t;
struct power_transition {
power_state_t from_state;
power_state_t to_state;
uint32_t transition_time_ms;
void (*pre_transition)(void);
void (*post_transition)(void);
};
static struct {
power_state_t current_state;
power_state_t target_state;
struct power_transition transitions[MAX_POWER_STATES];
uint8_t transition_count;
uint32_t last_transition;
bool power_mgmt_enabled;
} power_ctx;
int set_power_state(power_state_t new_state) {
if (!power_ctx.power_mgmt_enabled) {
return -1;
}
// Find valid transition
for (int i = 0; i < power_ctx.transition_count; i++) {
struct power_transition* trans = &power_ctx.transitions[i];
if (trans->from_state == power_ctx.current_state &&
trans->to_state == new_state) {
// Execute pre-transition handler
if (trans->pre_transition) {
trans->pre_transition();
}
// Update hardware power state
uint16_t power_ctrl = read_power_control();
power_ctrl &= ~POWER_STATE_MASK;
power_ctrl |= (new_state << POWER_STATE_SHIFT);
write_power_control(power_ctrl);
// Wait for transition
delay_ms(trans->transition_time_ms);
// Execute post-transition handler
if (trans->post_transition) {
trans->post_transition();
}
power_ctx.current_state = new_state;
power_ctx.last_transition = get_system_time();
return 0;
}
}
return -1; // Invalid transition
}
The hardware detection system identifies and configures system components during early boot.
#define MAX_DEVICES 32
#define MAX_DEVICE_NAME 48
#define VENDOR_ID_MAGIC1 0x4D31
typedef enum {
DEV_CLASS_CPU,
DEV_CLASS_MEMORY,
DEV_CLASS_STORAGE,
DEV_CLASS_NETWORK,
DEV_CLASS_DISPLAY,
DEV_CLASS_INPUT
} device_class_t;
struct device_info {
char name[MAX_DEVICE_NAME];
device_class_t class;
uint16_t vendor_id;
uint16_t device_id;
uint16_t subsystem_id;
uint8_t revision;
bool enabled;
void* driver_data;
};
static struct {
struct device_info devices[MAX_DEVICES];
uint16_t device_count;
bool detection_complete;
} hw_ctx;
int detect_hardware(void) {
log_info("Starting hardware detection...");
// Detect CPU and core system components
detect_cpu_info();
// Scan system bus for devices
scan_system_bus();
// Detect memory configuration
detect_memory_config();
// Detect storage devices
detect_storage_devices();
hw_ctx.detection_complete = true;
log_info("Hardware detection complete. Found %d devices",
hw_ctx.device_count);
return hw_ctx.device_count;
}
static void scan_system_bus(void) {
// Scan IO space for Magic-1 devices
for (uint16_t addr = 0x100; addr < 0x1000; addr += 2) {
uint16_t vendor = read_io16(addr);
if (vendor == VENDOR_ID_MAGIC1) {
uint16_t device = read_io16(addr + 2);
register_device(addr, vendor, device);
}
}
}
The device initialization system manages the ordered startup sequence of detected hardware components.
#define MAX_INIT_HANDLERS 32
#define MAX_DEPENDENCIES 8
typedef enum {
INIT_PHASE_EARLY, // Basic hardware setup
INIT_PHASE_CORE, // Core system devices
INIT_PHASE_STORAGE, // Storage devices
INIT_PHASE_NET, // Network interfaces
INIT_PHASE_LATE // Optional devices
} init_phase_t;
struct init_handler {
const char* device_name;
init_phase_t phase;
int (*init_func)(void);
const char* dependencies[MAX_DEPENDENCIES];
bool initialized;
uint32_t init_time;
};
static struct {
struct init_handler handlers[MAX_INIT_HANDLERS];
uint16_t handler_count;
init_phase_t current_phase;
bool init_complete;
} init_ctx;
int initialize_devices(void) {
int result = 0;
for (init_phase_t phase = INIT_PHASE_EARLY; phase <= INIT_PHASE_LATE; phase++) {
init_ctx.current_phase = phase;
log_info("Starting device initialization phase %d", phase);
// Initialize all devices in current phase
for (int i = 0; i < init_ctx.handler_count; i++) {
struct init_handler* handler = &init_ctx.handlers[i];
if (handler->phase == phase && !handler->initialized) {
// Check dependencies
bool deps_met = true;
for (int d = 0; d < MAX_DEPENDENCIES && handler->dependencies[d]; d++) {
if (!is_device_initialized(handler->dependencies[d])) {
deps_met = false;
break;
}
}
if (deps_met) {
uint32_t start_time = get_system_time();
result = handler->init_func();
handler->init_time = get_system_time() - start_time;
if (result == 0) {
handler->initialized = true;
log_info("Initialized %s in %dms",
handler->device_name, handler->init_time);
} else {
log_error("Failed to initialize %s: error %d",
handler->device_name, result);
return result;
}
}
}
}
}
init_ctx.init_complete = true;
return 0;
}
The configuration management system handles dynamic configuration settings and their persistence during the boot process.
#define MAX_CONFIG_ENTRIES 128
#define MAX_KEY_LENGTH 64
#define MAX_VALUE_LENGTH 256
#define CONFIG_MAGIC 0x4D314346 // "M1CF"
typedef enum {
CONFIG_TYPE_STRING,
CONFIG_TYPE_INTEGER,
CONFIG_TYPE_BOOLEAN,
CONFIG_TYPE_ARRAY
} config_type_t;
struct config_entry {
char key[MAX_KEY_LENGTH];
config_type_t type;
union {
char string_value[MAX_VALUE_LENGTH];
int64_t int_value;
bool bool_value;
struct {
uint8_t* data;
size_t length;
} array_value;
};
};
static struct {
struct config_entry entries[MAX_CONFIG_ENTRIES];
uint16_t entry_count;
bool modified;
uint32_t last_save;
} config_ctx;
int set_config_value(const char* key, const void* value, config_type_t type) {
struct config_entry* entry = NULL;
// Look for existing entry
for (int i = 0; i < config_ctx.entry_count; i++) {
if (strcmp(config_ctx.entries[i].key, key) == 0) {
entry = &config_ctx.entries[i];
break;
}
}
// Create new entry if not found
if (!entry && config_ctx.entry_count < MAX_CONFIG_ENTRIES) {
entry = &config_ctx.entries[config_ctx.entry_count++];
strncpy(entry->key, key, MAX_KEY_LENGTH - 1);
}
if (!entry) {
return -1; // No space for new entry
}
// Update value based on type
entry->type = type;
switch (type) {
case CONFIG_TYPE_STRING:
strncpy(entry->string_value, (const char*)value, MAX_VALUE_LENGTH - 1);
break;
case CONFIG_TYPE_INTEGER:
entry->int_value = *(const int64_t*)value;
break;
case CONFIG_TYPE_BOOLEAN:
entry->bool_value = *(const bool*)value;
break;
case CONFIG_TYPE_ARRAY:
// Handle array values
break;
}
config_ctx.modified = true;
return 0;
}
The device tree system provides a structured representation of hardware devices and their relationships during boot.
#define MAX_DT_NODES 64
#define MAX_DT_PROPS 16
#define MAX_NODE_NAME 48
typedef enum {
DT_PROP_STRING,
DT_PROP_INTEGER,
DT_PROP_ARRAY,
DT_PROP_REFERENCE
} dt_prop_type_t;
struct dt_property {
char name[MAX_NODE_NAME];
dt_prop_type_t type;
union {
char* string_value;
uint64_t int_value;
struct {
void* data;
size_t length;
} array;
struct dt_node* ref;
};
};
struct dt_node {
char name[MAX_NODE_NAME];
struct dt_property properties[MAX_DT_PROPS];
uint8_t prop_count;
struct dt_node* parent;
struct dt_node* children[MAX_DT_NODES];
uint8_t child_count;
};
static struct {
struct dt_node root_node;
struct dt_node nodes[MAX_DT_NODES];
uint16_t node_count;
bool initialized;
} dt_ctx;
struct dt_node* create_dt_node(const char* name, struct dt_node* parent) {
if (dt_ctx.node_count >= MAX_DT_NODES) {
return NULL;
}
struct dt_node* node = &dt_ctx.nodes[dt_ctx.node_count++];
strncpy(node->name, name, MAX_NODE_NAME - 1);
node->parent = parent;
if (parent) {
if (parent->child_count < MAX_DT_NODES) {
parent->children[parent->child_count++] = node;
}
}
return node;
}
int add_dt_property(struct dt_node* node, const char* name,
dt_prop_type_t type, const void* value) {
if (node->prop_count >= MAX_DT_PROPS) {
return -1;
}
struct dt_property* prop = &node->properties[node->prop_count++];
strncpy(prop->name, name, MAX_NODE_NAME - 1);
prop->type = type;
switch (type) {
case DT_PROP_STRING:
prop->string_value = strdup((const char*)value);
break;
case DT_PROP_INTEGER:
prop->int_value = *(const uint64_t*)value;
break;
case DT_PROP_REFERENCE:
prop->ref = (struct dt_node*)value;
break;
case DT_PROP_ARRAY:
// Handle array properties
break;
}
return 0;
}
The firmware interface provides a standardized way to interact with platform firmware services during boot.
#define FW_MAX_SERVICES 16
#define FW_SERVICE_NAME_MAX 32
typedef enum {
FW_STATUS_SUCCESS = 0,
FW_STATUS_INVALID_PARAMETER = 1,
FW_STATUS_UNSUPPORTED = 2,
FW_STATUS_NOT_READY = 3,
FW_STATUS_DEVICE_ERROR = 4,
FW_STATUS_BUFFER_TOO_SMALL = 5
} fw_status_t;
struct fw_service {
char name[FW_SERVICE_NAME_MAX];
uint32_t version;
fw_status_t (*init)(void);
fw_status_t (*get_info)(void* buffer, size_t* size);
fw_status_t (*call)(uint32_t function, void* params);
};
static struct {
struct fw_service services[FW_MAX_SERVICES];
uint8_t service_count;
bool initialized;
} fw_ctx;
fw_status_t fw_register_service(const struct fw_service* service) {
if (fw_ctx.service_count >= FW_MAX_SERVICES) {
return FW_STATUS_BUFFER_TOO_SMALL;
}
struct fw_service* new_service = &fw_ctx.services[fw_ctx.service_count++];
memcpy(new_service, service, sizeof(struct fw_service));
if (new_service->init) {
return new_service->init();
}
return FW_STATUS_SUCCESS;
}
fw_status_t fw_call_service(const char* name, uint32_t function, void* params) {
for (int i = 0; i < fw_ctx.service_count; i++) {
if (strcmp(fw_ctx.services[i].name, name) == 0) {
return fw_ctx.services[i].call(function, params);
}
}
return FW_STATUS_UNSUPPORTED;
}
The memory protection system ensures secure memory access and isolation during the boot process.
#define MAX_PROTECTED_REGIONS 16
#define PAGE_SIZE 4096
typedef enum {
PROT_NONE = 0x0,
PROT_READ = 0x1,
PROT_WRITE = 0x2,
PROT_EXEC = 0x4
} mem_prot_flags_t;
struct protected_region {
void* start_addr;
size_t size;
mem_prot_flags_t flags;
const char* owner;
bool locked;
};
struct mpu_context {
struct protected_region regions[MAX_PROTECTED_REGIONS];
uint8_t region_count;
bool mpu_enabled;
};
static struct mpu_context mpu_ctx;
int protect_memory_region(void* addr, size_t size, mem_prot_flags_t flags, const char* owner) {
if (mpu_ctx.region_count >= MAX_PROTECTED_REGIONS) {
return -1;
}
// Align address and size to page boundaries
void* aligned_addr = (void*)((uintptr_t)addr & ~(PAGE_SIZE - 1));
size_t aligned_size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
struct protected_region* region = &mpu_ctx.regions[mpu_ctx.region_count++];
region->start_addr = aligned_addr;
region->size = aligned_size;
region->flags = flags;
region->owner = owner;
region->locked = false;
// Configure MPU hardware
uint32_t mpu_base = (uint32_t)aligned_addr;
uint32_t mpu_attr = flags | MPU_REGION_ENABLE;
write_mpu_region(mpu_ctx.region_count - 1, mpu_base, mpu_attr);
return 0;
}
The exception handling system manages hardware and software exceptions during the boot process, providing graceful error recovery and debugging information.
#define MAX_EXCEPTION_HANDLERS 16
#define MAX_EXCEPTION_NAME 32
#define EXCEPTION_STACK_SIZE 2048
typedef enum {
EXC_RESET = 0,
EXC_UNDEFINED_INSTRUCTION = 1,
EXC_MEMORY_FAULT = 2,
EXC_BUS_ERROR = 3,
EXC_ILLEGAL_ACCESS = 4,
EXC_DIVIDE_BY_ZERO = 5,
EXC_PRIVILEGED = 6
} exception_type_t;
struct exception_frame {
uint32_t r0;
uint32_t r1;
uint32_t r2;
uint32_t r3;
uint32_t r12;
uint32_t lr;
uint32_t pc;
uint32_t psr;
};
typedef void (*exception_handler_t)(exception_type_t type,
struct exception_frame* frame);
static struct {
exception_handler_t handlers[MAX_EXCEPTION_HANDLERS];
uint8_t handler_count;
uint32_t exception_stack[EXCEPTION_STACK_SIZE];
uint32_t exception_count;
bool handling_exception;
} exc_ctx;
void register_exception_handler(exception_handler_t handler) {
if (exc_ctx.handler_count < MAX_EXCEPTION_HANDLERS) {
exc_ctx.handlers[exc_ctx.handler_count++] = handler;
}
}
void __attribute__((interrupt)) handle_exception(void) {
struct exception_frame* frame;
exception_type_t type;
// Get exception information
type = get_exception_type();
frame = get_exception_frame();
// Prevent recursive exceptions
if (exc_ctx.handling_exception) {
panic_handler();
return;
}
exc_ctx.handling_exception = true;
exc_ctx.exception_count++;
// Call registered handlers
for (int i = 0; i < exc_ctx.handler_count; i++) {
if (exc_ctx.handlers[i]) {
exc_ctx.handlers[i](type, frame);
}
}
exc_ctx.handling_exception = false;
}
The cache management system optimizes memory access patterns during boot by managing instruction and data caches.
#define CACHE_LINE_SIZE 32
#define CACHE_WAYS 4
#define CACHE_SETS 256
typedef enum {
CACHE_TYPE_INSTRUCTION,
CACHE_TYPE_DATA,
CACHE_TYPE_UNIFIED
} cache_type_t;
struct cache_info {
cache_type_t type;
uint32_t line_size;
uint32_t ways;
uint32_t sets;
uint32_t total_size;
bool enabled;
};
struct cache_stats {
uint32_t hits;
uint32_t misses;
uint32_t evictions;
uint32_t writebacks;
};
static struct {
struct cache_info i_cache;
struct cache_info d_cache;
struct cache_stats i_stats;
struct cache_stats d_stats;
bool cache_enabled;
} cache_ctx;
void init_cache_controller(void) {
// Initialize instruction cache
cache_ctx.i_cache.type = CACHE_TYPE_INSTRUCTION;
cache_ctx.i_cache.line_size = CACHE_LINE_SIZE;
cache_ctx.i_cache.ways = CACHE_WAYS;
cache_ctx.i_cache.sets = CACHE_SETS;
cache_ctx.i_cache.total_size = CACHE_LINE_SIZE * CACHE_WAYS * CACHE_SETS;
// Initialize data cache
cache_ctx.d_cache.type = CACHE_TYPE_DATA;
cache_ctx.d_cache.line_size = CACHE_LINE_SIZE;
cache_ctx.d_cache.ways = CACHE_WAYS;
cache_ctx.d_cache.sets = CACHE_SETS;
cache_ctx.d_cache.total_size = CACHE_LINE_SIZE * CACHE_WAYS * CACHE_SETS;
// Clear statistics
memset(&cache_ctx.i_stats, 0, sizeof(struct cache_stats));
memset(&cache_ctx.d_stats, 0, sizeof(struct cache_stats));
// Enable caches
enable_caches();
cache_ctx.cache_enabled = true;
}
The interrupt management system handles hardware and software interrupts during the boot process, providing prioritized interrupt handling and routing.
#define MAX_IRQ_HANDLERS 32
#define MAX_IRQ_PRIORITY 16
typedef enum {
IRQ_TIMER = 0,
IRQ_UART = 1,
IRQ_DMA = 2,
IRQ_DISK = 3,
IRQ_NET = 4,
IRQ_GPIO = 5
} irq_number_t;
struct irq_handler {
void (*handler)(void* context);
void* context;
uint8_t priority;
bool enabled;
};
static struct {
struct irq_handler handlers[MAX_IRQ_HANDLERS];
uint32_t pending_irqs;
uint8_t current_priority;
bool interrupts_enabled;
} irq_ctx;
void register_irq_handler(irq_number_t irq, void (*handler)(void*),
void* context, uint8_t priority) {
if (irq < MAX_IRQ_HANDLERS) {
irq_ctx.handlers[irq].handler = handler;
irq_ctx.handlers[irq].context = context;
irq_ctx.handlers[irq].priority = priority;
irq_ctx.handlers[irq].enabled = true;
// Configure hardware interrupt controller
write_irq_priority(irq, priority);
enable_irq(irq);
}
}
void __attribute__((interrupt)) irq_dispatcher(void) {
uint32_t active_irqs = read_pending_irqs();
// Process IRQs in priority order
for (int i = 0; i < MAX_IRQ_HANDLERS; i++) {
if ((active_irqs & (1 << i)) && irq_ctx.handlers[i].enabled) {
if (irq_ctx.handlers[i].priority > irq_ctx.current_priority) {
irq_ctx.current_priority = irq_ctx.handlers[i].priority;
irq_ctx.handlers[i].handler(irq_ctx.handlers[i].context);
irq_ctx.current_priority = 0;
}
}
}
}
The timer management system provides precise timing services and delays during the boot process.
#define MAX_TIMERS 16
#define TIMER_BASE_FREQ 1000000 // 1MHz base frequency
typedef enum {
TIMER_MODE_ONESHOT,
TIMER_MODE_PERIODIC,
TIMER_MODE_PWM
} timer_mode_t;
struct timer_config {
uint32_t period_us; // Period in microseconds
timer_mode_t mode;
void (*callback)(void* context);
void* context;
bool enabled;
};
static struct {
struct timer_config timers[MAX_TIMERS];
uint8_t timer_count;
uint64_t system_ticks;
bool initialized;
} timer_ctx;
int init_timer_system(void) {
// Configure hardware timer base
write_timer_ctrl(TIMER_ENABLE | TIMER_INTERRUPT);
write_timer_prescale(TIMER_BASE_FREQ / 1000); // 1ms tick
write_timer_period(1000); // 1ms period
timer_ctx.initialized = true;
return 0;
}
int create_timer(const struct timer_config* config) {
if (timer_ctx.timer_count >= MAX_TIMERS) {
return -1;
}
struct timer_config* timer = &timer_ctx.timers[timer_ctx.timer_count++];
memcpy(timer, config, sizeof(struct timer_config));
// Configure hardware timer channel if available
if (timer->mode == TIMER_MODE_PERIODIC) {
configure_hw_timer(timer_ctx.timer_count - 1, timer->period_us);
}
return timer_ctx.timer_count - 1;
}
void __attribute__((interrupt)) timer_isr(void) {
timer_ctx.system_ticks++;
for (int i = 0; i < timer_ctx.timer_count; i++) {
struct timer_config* timer = &timer_ctx.timers[i];
if (timer->enabled && timer->callback) {
timer->callback(timer->context);
}
}
}
The power state management system handles system power transitions and power saving modes during boot.
#define MAX_POWER_STATES 8
#define MAX_POWER_HANDLERS 16
typedef enum {
POWER_STATE_FULL, // Full power mode
POWER_STATE_LOW, // Low power mode
POWER_STATE_STANDBY, // Standby mode
POWER_STATE_SLEEP // Deep sleep mode
} power_state_t;
struct power_transition {
power_state_t from_state;
power_state_t to_state;
uint32_t transition_time_ms;
int (*pre_transition)(void);
int (*post_transition)(void);
};
static struct {
power_state_t current_state;
struct power_transition transitions[MAX_POWER_STATES];
uint8_t transition_count;
void (*state_handlers[MAX_POWER_HANDLERS])(power_state_t);
uint8_t handler_count;
bool power_mgmt_enabled;
} power_ctx;
int transition_power_state(power_state_t target_state) {
// Find valid transition
for (int i = 0; i < power_ctx.transition_count; i++) {
struct power_transition* trans = &power_ctx.transitions[i];
if (trans->from_state == power_ctx.current_state &&
trans->to_state == target_state) {
// Execute pre-transition handler
if (trans->pre_transition && trans->pre_transition() != 0) {
return -1;
}
// Configure hardware power state
set_hw_power_state(target_state);
// Wait for transition
delay_ms(trans->transition_time_ms);
// Execute post-transition handler
if (trans->post_transition && trans->post_transition() != 0) {
return -2;
}
// Update state and notify handlers
power_ctx.current_state = target_state;
notify_power_handlers(target_state);
return 0;
}
}
return -3; // No valid transition found
}
The device enumeration system discovers and catalogs hardware devices present in the system during boot.
#define MAX_DEVICES 32
#define MAX_DEVICE_NAME 48
#define VENDOR_ID_MAGIC1 0x4D31
typedef enum {
BUS_TYPE_NONE,
BUS_TYPE_ISA,
BUS_TYPE_PCI,
BUS_TYPE_USB
} bus_type_t;
struct device_descriptor {
char name[MAX_DEVICE_NAME];
bus_type_t bus_type;
uint16_t vendor_id;
uint16_t device_id;
uint16_t class_code;
uint8_t revision;
void* driver;
bool active;
};
static struct {
struct device_descriptor devices[MAX_DEVICES];
uint16_t device_count;
bool enumeration_complete;
} enum_ctx;
int enumerate_devices(void) {
// Scan ISA bus
scan_isa_bus();
// Scan PCI bus if present
if (is_pci_present()) {
scan_pci_bus();
}
// Scan USB controllers if present
scan_usb_controllers();
enum_ctx.enumeration_complete = true;
return enum_ctx.device_count;
}
static void scan_isa_bus(void) {
// Scan known ISA ports for Magic-1 devices
for (uint16_t port = 0x100; port < 0x3FF; port += 2) {
uint16_t vendor = inw(port);
if (vendor == VENDOR_ID_MAGIC1) {
struct device_descriptor* dev =
&enum_ctx.devices[enum_ctx.device_count++];
dev->bus_type = BUS_TYPE_ISA;
dev->vendor_id = vendor;
dev->device_id = inw(port + 2);
identify_device(dev);
}
}
}