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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@ jobs:

- name: Compile & Link
run: |
meson setup build
meson setup build -Dexclude_extra_objects=true -Dautomatic_post=true
ninja -C build

- name: Artifact Analysis
run: |
timeout 10s ninja -C build runmin || true
timeout 30s ninja -C build runmin || true

grep -q "1KCSWF23Z456789" build/bootstrap.log
! grep -i "panic\|fault\|crash\|oops\|error" build/serial.log
! grep -i "panic\|fault\|crash\|oops\|error\|failed" build/serial.log

ls -la build/voidframe.krnl
test -s build/voidframe.krnl
Expand Down
125 changes: 125 additions & 0 deletions arch/x86_64/cpu/Cpu.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "Cpu.h"
#include "Console.h"
#include "Io.h"
#include "stdbool.h"

static CpuFeatures cpu_features = {0};
Expand Down Expand Up @@ -74,3 +75,127 @@ void CpuInit(void) {
CpuFeatures* GetCpuFeatures(void) {
return &cpu_features;
}

static void DumpGP(RegistersDumpT* dump) {
// General purpose (tricky - we're using some of these!)
asm volatile (
"movq %%rax, %0\n"
"movq %%rbx, %1\n"
"movq %%rcx, %2\n"
"movq %%rdx, %3\n"
"movq %%rsi, %4\n"
"movq %%rdi, %5\n"
"movq %%rbp, %6\n"
"movq %%rsp, %7\n"
"movq %%r8, %8\n"
"movq %%r9, %9\n"
"movq %%r10, %10\n"
"movq %%r11, %11\n"
"movq %%r12, %12\n"
"movq %%r13, %13\n"
"movq %%r14, %14\n"
"movq %%r15, %15\n"
: "=m"(dump->rax), "=m"(dump->rbx), "=m"(dump->rcx), "=m"(dump->rdx),
"=m"(dump->rsi), "=m"(dump->rdi), "=m"(dump->rbp), "=m"(dump->rsp),
"=m"(dump->r8), "=m"(dump->r9), "=m"(dump->r10), "=m"(dump->r11),
"=m"(dump->r12), "=m"(dump->r13), "=m"(dump->r14), "=m"(dump->r15)
:
: "memory"
);

// Get RIP (tricky - need to use a call trick)
asm volatile (
"call 1f\n"
"1: popq %0\n"
: "=r"(dump->rip)
);

// Get RFLAGS
asm volatile (
"pushfq\n"
"popq %0\n"
: "=r"(dump->rflags)
);

// Segment registers
asm volatile (
"movw %%cs, %0\n"
"movw %%ds, %1\n"
"movw %%es, %2\n"
"movw %%fs, %3\n"
"movw %%gs, %4\n"
"movw %%ss, %5\n"
: "=m"(dump->cs), "=m"(dump->ds), "=m"(dump->es),
"=m"(dump->fs), "=m"(dump->gs), "=m"(dump->ss)
);
}

// Control registers (DANGEROUS - save/restore interrupts)
static void DumpCR(RegistersDumpT* dump) {
unsigned long flags = save_irq_flags();
cli(); // Critical section

asm volatile ("movq %%cr0, %0" : "=r"(dump->cr0));
asm volatile ("movq %%cr2, %0" : "=r"(dump->cr2)); // Page fault address
asm volatile ("movq %%cr3, %0" : "=r"(dump->cr3)); // Page directory
asm volatile ("movq %%cr4, %0" : "=r"(dump->cr4));

// CR8 (TPR - Task Priority Register) only in x64
asm volatile ("movq %%cr8, %0" : "=r"(dump->cr8));

restore_irq_flags(flags);
}

// Debug registers
static void DumpDR(RegistersDumpT* dump) {
asm volatile ("movq %%dr0, %0" : "=r"(dump->dr0));
asm volatile ("movq %%dr1, %0" : "=r"(dump->dr1));
asm volatile ("movq %%dr2, %0" : "=r"(dump->dr2));
asm volatile ("movq %%dr3, %0" : "=r"(dump->dr3));
asm volatile ("movq %%dr6, %0" : "=r"(dump->dr6)); // Debug status
asm volatile ("movq %%dr7, %0" : "=r"(dump->dr7)); // Debug control
}

// MSRs (Model Specific Registers)
static void DumpMSR(RegistersDumpT* dump) {
dump->efer = rdmsr(0xC0000080); // Extended features
dump->star = rdmsr(0xC0000081); // Syscall target
dump->lstar = rdmsr(0xC0000082); // Long mode syscall target
dump->cstar = rdmsr(0xC0000083); // Compat mode syscall
dump->sfmask = rdmsr(0xC0000084); // Syscall flag mask
dump->fs_base = rdmsr(0xC0000100); // FS base
dump->gs_base = rdmsr(0xC0000101); // GS base
dump->kernel_gs_base = rdmsr(0xC0000102); // Kernel GS base
}

void DumpRegisters(RegistersDumpT* dump) {
DumpGP(dump);
DumpCR(dump);
DumpDR(dump);
DumpMSR(dump);
}

void PrintRegisters(const RegistersDumpT* dump) {
PrintKernelF("=== VoidFrame registers dump x64 ===\n");
PrintKernelF("RAX: 0x%016lx RBX: 0x%016lx\n", dump->rax, dump->rbx);
PrintKernelF("RCX: 0x%016lx RDX: 0x%016lx\n", dump->rcx, dump->rdx);
PrintKernelF("RSI: 0x%016lx RDI: 0x%016lx\n", dump->rsi, dump->rdi);
PrintKernelF("RBP: 0x%016lx RSP: 0x%016lx\n", dump->rbp, dump->rsp);
PrintKernelF("R8: 0x%016lx R9: 0x%016lx\n", dump->r8, dump->r9);
PrintKernelF("R10: 0x%016lx R11: 0x%016lx\n", dump->r10, dump->r11);
PrintKernelF("R12: 0x%016lx R13: 0x%016lx\n", dump->r12, dump->r13);
PrintKernelF("R14: 0x%016lx R15: 0x%016lx\n", dump->r14, dump->r15);
PrintKernelF("RIP: 0x%016lx CR0: 0x%016lx\n", dump->rip, dump->cr0);
PrintKernelF("CR2: 0x%016lx CR3: 0x%016lx\n", dump->cr2, dump->cr3);
PrintKernelF("CR4: 0x%016lx CR8: 0x%016lx\n", dump->cr4, dump->cr8);
PrintKernelF("DR0: 0x%016lx DR1: 0x%016lx\n", dump->dr0, dump->dr1);
PrintKernelF("DR2: 0x%016lx DR3: 0x%016lx\n", dump->dr2, dump->dr3);
PrintKernelF("DR6: 0x%016lx DR7: 0x%016lx\n", dump->dr6, dump->dr7);
PrintKernelF("FS: 0x%016lx GS: 0x%016lx\n", dump->fs, dump->gs);
PrintKernelF("ES: 0x%016lx DS: 0x%016lx\n", dump->es, dump->ds);
PrintKernelF("SS: 0x%016lx CS: 0x%016lx\n", dump->ss, dump->cs);
PrintKernelF("EFER: 0x%016lx STAR: 0x%016lx\n", dump->efer, dump->star);
PrintKernelF("LSTAR: 0x%016lx CSTAR: 0x%016lx\n", dump->lstar, dump->cstar);
PrintKernelF("SFMASK:0x%016lx KGSBASE:0x%016lx\n", dump->sfmask, dump->kernel_gs_base);
PrintKernelF("FSBASE:0x%016lx GSBASE:0x%016lx\n", dump->fs_base, dump->gs_base);
}
27 changes: 26 additions & 1 deletion arch/x86_64/cpu/Cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#define CPU_H

#include "stdint.h"
#include <stdbool.h> // For bool type
#include "stdbool.h"

typedef struct {
bool sse;
Expand All @@ -23,6 +23,28 @@ typedef struct Registers {
uint64_t rsp, ss;
} __attribute__((packed)) Registers;

typedef struct {
// General purpose registers
uint64_t rax, rbx, rcx, rdx;
uint64_t rsi, rdi, rbp, rsp;
uint64_t r8, r9, r10, r11, r12, r13, r14, r15;
uint64_t rip, rflags;

// Segment registers
uint16_t cs, ds, es, fs, gs, ss;

// Control registers
uint64_t cr0, cr2, cr3, cr4;
uint64_t cr8; // Only in 64-bit mode

// Debug registers
uint64_t dr0, dr1, dr2, dr3, dr6, dr7;

// MSRs (selected important ones)
uint64_t efer, star, lstar, cstar, sfmask;
uint64_t fs_base, gs_base, kernel_gs_base;
} RegistersDumpT;

void CpuInit(void);
CpuFeatures* GetCpuFeatures(void);

Expand All @@ -36,4 +58,7 @@ static inline void __attribute__((always_inline)) delay(uint64_t cycles) {
while (cycles--) __asm__ volatile ("nop");
}

void DumpRegisters(RegistersDumpT* dump);
void PrintRegisters(const RegistersDumpT* dump);

#endif // CPU_H
10 changes: 9 additions & 1 deletion arch/x86_64/interrupts/Interrupts.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,15 @@ asmlinkage void InterruptHandler(Registers* regs) {

// Print detailed information
PrintDetailedFaultInfo(&ctx, regs);
delay(100000000);
RegistersDumpT dump = {0};
DumpRegisters(&dump);
// Override with fault context where applicable
dump.rip = regs->rip;
dump.cs = regs->cs;
dump.rflags = regs->rflags;
dump.rsp = regs->rsp;
dump.ss = regs->ss;
PrintRegisters(&dump);
// Still panic, but now with much more info
Comment on lines +74 to 83
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Double-fault safety and panic CLI ordering — please verify.

Printing on DF can triple-fault unless ISR #8 uses an IST stack; also ensure PanicFromInterrupt disables interrupts as its first instruction.


🏁 Script executed:

#!/bin/bash
# 1) Verify DF (vector 8) uses IST in IDT setup / ASM stubs
rg -n -C3 -i 'double\s*fault|isr8|vector\s*8|ist' arch/x86_64

# 2) Confirm PanicFromInterrupt (and other panic entry points) execute cli first
rg -n -C3 'PanicFromInterrupt\s*\(|KernelPanicHandler\s*\(|Panic\w*\(' kernel | sed -n '1,200p'
rg -n 'asm\s+volatile\("cli"\)' kernel

Length of output: 27567


Ensure double-fault uses an IST stack; panic CLI ordering is correct

  • arch/x86_64/idt/Idt.c:295 currently calls
    IdtSetGate(8, (uint64_t)isr8, kernelCodeSegment, flags);
    without an IST index—assign a dedicated IST (and configure TSS.istN) for vector 8 to avoid triple-faults.
  • No change needed for PanicFromInterrupt or other panic entry points—all invoke cli() as their first instruction.

PanicFromInterrupt(ctx.fault_reason, regs);
break;
Expand Down
2 changes: 1 addition & 1 deletion docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ typedef struct {
| `context` | Stores the CPU register state (`rip`, `rsp`, etc.) when the process is not running. This is crucial for context switching. |
| `priority` | The process's current priority level in the scheduler. This value can change dynamically. |
| `base_priority` | The initial priority assigned at creation, used to reset a process's priority. |
| `privilege_level` | The security privilege level (`PROC_PRIV_SYSTEM` or `PROC_PRIV_USER`). |
| `privilege_level` | The security privilege level (`PROC_PRIV_SYSTEM` or `PROC_PRIV_NORM`). |
| `token` | A `SecurityToken` structure used by the Astra security system to verify the process's integrity. |
| `scheduler_node` | A pointer to the node that links this PCB into the scheduler's priority queues. |
| `cpu_time_accumulated` | Total system ticks this process has spent running on the CPU. |
Expand Down
5 changes: 4 additions & 1 deletion kernel/core/Kernel.c
Original file line number Diff line number Diff line change
Expand Up @@ -803,7 +803,6 @@ void KernelMainHigherHalf(void) {

// Initialize core systems
PXS2();

PrintKernelSuccess("System: Kernel initialization complete\n");
PrintKernelSuccess("System: Initializing interrupts...\n");

Expand All @@ -814,6 +813,10 @@ void KernelMainHigherHalf(void) {

g_HasKernelStarted = true;

#ifdef VF_CONFIG_AUTOMATIC_POST
ExecuteCommand("post");
#endif

sti();

while (1) {
Expand Down
77 changes: 77 additions & 0 deletions kernel/etc/POST.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#include "POST.h"
#include "Console.h"
#include "KernelHeap.h"
#include "PMem.h"
#include "Panic.h"
#include "Serial.h"
#include "VMem.h"
#include "stdbool.h"

#define N 512
void * ptrs[N] = {0};

uint64_t seed = 0x12345;
uint64_t rnd() { seed = seed * 6364136223846793005ULL + 1; return seed; }

bool SerialTest() {
for (int i = 0; i < 128; i++) {
if (SerialWrite(".") < 0) return false;
}
return true;
}

bool MemoryTest() {
for (int i = 1; i < 1000; i++) {
size_t sz = (i % 7 == 0) ? 4096 : (i % 100 + 1);
void *ptr = KernelMemoryAlloc(sz);
if (!ptr) return false;
KernelFree(ptr);
}
//
for (int i = 0; i < N; i++) ptrs[i] = KernelMemoryAlloc(128);

// free every other block
for (int i = 0; i < N; i += 2) KernelFree(ptrs[i]);

// re-allocate in different sizes
for (int i = 0; i < N/2; i++) {
ptrs[i] = KernelMemoryAlloc((i % 2) ? 64 : 256);
}

for (int iter = 0; iter < 100000; iter++) {
int idx = rnd() % N;
if (ptrs[idx]) {
KernelFree(ptrs[idx]);
ptrs[idx] = NULL;
} else {
size_t sz = (rnd() % 8192) + 1; // 1–8K
ptrs[idx] = KernelMemoryAlloc(sz);
if (!ptrs[idx]) PANIC("OOM during fuzz");
}
}

for (uintptr_t addr = 0x400000; addr < 0x800000; addr += 0x1000) {
void* frame = AllocPage();
VMemMap(addr, (uint64_t)frame, PAGE_PRESENT | PAGE_WRITABLE);
VMemUnmap(addr, PAGE_SIZE);
FreePage(frame);
}
Comment on lines +53 to +58
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Check map/unmap return codes and handle page alloc failure.

Ignoring errors risks leaking mapped pages or freeing still-mapped frames.

-    for (uintptr_t addr = 0x400000; addr < 0x800000; addr += 0x1000) {
-        void* frame = AllocPage();
-        VMemMap(addr, (uint64_t)frame, PAGE_PRESENT | PAGE_WRITABLE);
-        VMemUnmap(addr, PAGE_SIZE);
-        FreePage(frame);
-    }
+    for (uintptr_t addr = 0x400000; addr < 0x800000; addr += 0x1000) {
+        void* frame = AllocPage();
+        if (!frame) return false;
+        int rc = VMemMap(addr, (uint64_t)frame, PAGE_PRESENT | PAGE_WRITABLE);
+        if (rc != VMEM_SUCCESS) { FreePage(frame); return false; }
+        rc = VMemUnmap(addr, PAGE_SIZE);
+        if (rc != VMEM_SUCCESS) { FreePage(frame); return false; }
+        FreePage(frame);
+    }

Committable suggestion skipped: line range outside the PR's diff.


for (int i = 0; i < 1000; i++) {
size_t sz = (i % 500) + 1;
uint8_t *p = (uint8_t*)KernelMemoryAlloc(sz);
for (size_t j = 0; j < sz; j++) p[j] = (uint8_t)(i ^ j);
for (size_t j = 0; j < sz; j++)
if (p[j] != (uint8_t)(i ^ j)) PANIC("Memory corruption!");
KernelFree(p);
}

return true;
}
Comment on lines +69 to +70
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Free any remaining fuzz allocations to avoid a boot-time leak.

POST runs once but leaking kernel heap here is avoidable.

-    return true;
+    // Cleanup any remaining allocations from fuzzing
+    for (int i = 0; i < N; i++) {
+        if (ptrs[i]) { KernelFree(ptrs[i]); ptrs[i] = NULL; }
+    }
+    return true;

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In kernel/etc/POST.c around lines 69-70, the function returns true without
freeing any remaining fuzz allocations, causing a boot-time kernel-heap leak;
locate the container(s) used to track fuzz allocations (e.g., fuzz buffer
list/array/struct and any count fields), iterate over each stored allocation and
call the appropriate kernel free function for each entry, clear or reset the
container/count after freeing, and ensure any ownership flags are updated so no
double-free occurs before returning true.


void POSTHandler(const char * args) {
(void)args;
if (!SerialTest()) PrintKernelWarning("Serial test failed\n");
if (!MemoryTest()) PrintKernelWarning("Memory test failed\n");
PrintKernelSuccess("POST test passed\n");
}
6 changes: 6 additions & 0 deletions kernel/etc/POST.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef VOIDFRAME_POST_H
#define VOIDFRAME_POST_H

void POSTHandler(const char * args);

#endif // VOIDFRAME_POST_H
Loading