feat(tinybox): graft toybox integration and build system automation
- Integrated ToyBox as git submodule - Added src/nexus/builder/toybox.nim for automated cross-compilation - Updated InitRD builder to support symlinks - Refactored Kernel builder to fix duplicate symbol and path issues - Modified forge.nim to orchestrate TinyBox synthesis (mksh + toybox) - Updated SPEC-006-TinyBox.md with complete architecture - Added mksh binary to initrd graft source
This commit is contained in:
parent
11db62ea8c
commit
7207282236
|
|
@ -46,10 +46,10 @@ export const multiboot2_header linksection(".multiboot2") = Multiboot2Header{
|
|||
// Entry Point
|
||||
// =========================================================
|
||||
|
||||
extern fn kmain() noreturn;
|
||||
extern fn riscv_init() noreturn;
|
||||
|
||||
export fn _start() callconv(.Naked) noreturn {
|
||||
// Clear BSS, set up stack, then jump to Nim
|
||||
export fn _start() callconv(.naked) noreturn {
|
||||
// Clear BSS, set up stack, then jump to RISC-V Init
|
||||
asm volatile (
|
||||
\\ // Set up stack
|
||||
\\ la sp, __stack_top
|
||||
|
|
@ -63,8 +63,8 @@ export fn _start() callconv(.Naked) noreturn {
|
|||
\\ addi t0, t0, 8
|
||||
\\ j 1b
|
||||
\\2:
|
||||
\\ // Jump to Nim kmain
|
||||
\\ call kmain
|
||||
\\ // Jump to HAL Init
|
||||
\\ call riscv_init
|
||||
\\
|
||||
\\ // Should never return
|
||||
\\ wfi
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
# Rumpk Linker Script (ARM64)
|
||||
# For QEMU virt machine
|
||||
# Rumpk Linker Script (RISC-V 64)
|
||||
# For QEMU virt machine (RISC-V)
|
||||
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x40080000; /* QEMU virt kernel load address */
|
||||
. = 0x80200000; /* Standard RISC-V QEMU virt kernel address */
|
||||
PROVIDE(__kernel_vbase = .);
|
||||
PROVIDE(__kernel_pbase = .);
|
||||
|
||||
.text : {
|
||||
*(.text._start)
|
||||
|
|
@ -17,9 +19,19 @@ SECTIONS
|
|||
}
|
||||
|
||||
.data : {
|
||||
. = ALIGN(16);
|
||||
__global_pointer$ = . + 0x800;
|
||||
*(.sdata*)
|
||||
*(.sdata.*)
|
||||
*(.data*)
|
||||
}
|
||||
|
||||
.initrd : {
|
||||
_initrd_start = .;
|
||||
KEEP(*(.initrd))
|
||||
_initrd_end = .;
|
||||
}
|
||||
|
||||
.bss : {
|
||||
__bss_start = .;
|
||||
*(.bss*)
|
||||
|
|
@ -27,6 +39,12 @@ SECTIONS
|
|||
__bss_end = .;
|
||||
}
|
||||
|
||||
.stack (NOLOAD) : {
|
||||
. = ALIGN(16);
|
||||
. += 0x100000; /* 1MB Stack */
|
||||
__stack_top = .;
|
||||
}
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.comment)
|
||||
*(.note*)
|
||||
|
|
|
|||
255
core/cstubs.c
255
core/cstubs.c
|
|
@ -1,210 +1,57 @@
|
|||
// C runtime stubs for freestanding Nim
|
||||
#include <stddef.h>
|
||||
|
||||
void *memcpy(void *dest, const void *src, size_t n) {
|
||||
unsigned char *d = dest;
|
||||
const unsigned char *s = src;
|
||||
while (n--) *d++ = *s++;
|
||||
return dest;
|
||||
}
|
||||
/* Duplicates provided by libnexus.a (clib.o) */
|
||||
#if 0
|
||||
void *memcpy(void *dest, const void *src, size_t n) { ... }
|
||||
void *memset(void *s, int c, size_t n) { ... }
|
||||
void *memmove(void *dest, const void *src, size_t n) { ... }
|
||||
int memcmp(const void *s1, const void *s2, size_t n) { ... }
|
||||
|
||||
void *memset(void *s, int c, size_t n) {
|
||||
unsigned char *p = s;
|
||||
while (n--) *p++ = (unsigned char)c;
|
||||
return s;
|
||||
}
|
||||
/* Externs from libnexus.a */
|
||||
extern size_t strlen(const char *s);
|
||||
extern int atoi(const char *nptr);
|
||||
extern int strncmp(const char *s1, const char *s2, size_t n);
|
||||
|
||||
void *memmove(void *dest, const void *src, size_t n) {
|
||||
unsigned char *d = dest;
|
||||
const unsigned char *s = src;
|
||||
if (d < s) {
|
||||
while (n--) *d++ = *s++;
|
||||
} else {
|
||||
d += n;
|
||||
s += n;
|
||||
while (n--) *--d = *--s;
|
||||
char *strcpy(char *dest, const char *src) { ... }
|
||||
int strcmp(const char *s1, const char *s2) { ... }
|
||||
char *strncpy(char *dest, const char *src, size_t n) { ... }
|
||||
#endif
|
||||
|
||||
// panic is used by abort/exit
|
||||
void panic(const char* msg) {
|
||||
extern void console_write(const char*, unsigned long);
|
||||
extern size_t strlen(const char*);
|
||||
console_write("\n[KERNEL PANIC] ", 16);
|
||||
if (msg) console_write(msg, strlen(msg));
|
||||
else console_write("Unknown Error", 13);
|
||||
console_write("\n", 1);
|
||||
while(1) {
|
||||
// Halt
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
int memcmp(const void *s1, const void *s2, size_t n) {
|
||||
const unsigned char *p1 = s1, *p2 = s2;
|
||||
while (n--) {
|
||||
if (*p1 != *p2) return *p1 - *p2;
|
||||
p1++; p2++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t strlen(const char *s) {
|
||||
size_t len = 0;
|
||||
while (*s++) len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
char *strcpy(char *dest, const char *src) {
|
||||
char *d = dest;
|
||||
while ((*d++ = *src++));
|
||||
return dest;
|
||||
}
|
||||
|
||||
int strcmp(const char *s1, const char *s2) {
|
||||
while (*s1 && (*s1 == *s2)) { s1++; s2++; }
|
||||
return *(unsigned char*)s1 - *(unsigned char*)s2;
|
||||
}
|
||||
|
||||
int strncmp(const char *s1, const char *s2, size_t n) {
|
||||
while (n && *s1 && (*s1 == *s2)) {
|
||||
s1++; s2++; n--;
|
||||
}
|
||||
if (n == 0) return 0;
|
||||
return *(unsigned char*)s1 - *(unsigned char*)s2;
|
||||
}
|
||||
|
||||
char *strncpy(char *dest, const char *src, size_t n) {
|
||||
char *d = dest;
|
||||
while (n && (*d++ = *src++)) n--;
|
||||
while (n--) *d++ = '\0';
|
||||
return dest;
|
||||
}
|
||||
|
||||
// abort is used by Nim panic
|
||||
void abort(void) {
|
||||
/* Call Nim panic */
|
||||
extern void panic(const char*);
|
||||
panic("abort() called");
|
||||
while(1) {}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Stdio stubs - these call into Zig UART */
|
||||
extern void console_write(const char*, unsigned long);
|
||||
|
||||
int puts(const char *s) {
|
||||
if (s) {
|
||||
unsigned long len = strlen(s);
|
||||
console_write(s, len);
|
||||
console_write("\n", 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int putchar(int c) {
|
||||
char buf[1] = {(char)c};
|
||||
console_write(buf, 1);
|
||||
return c;
|
||||
}
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
void itoa(int n, char s[]) {
|
||||
int i, sign;
|
||||
if ((sign = n) < 0) n = -n;
|
||||
i = 0;
|
||||
do { s[i++] = n % 10 + '0'; } while ((n /= 10) > 0);
|
||||
if (sign < 0) s[i++] = '-';
|
||||
s[i] = '\0';
|
||||
// reverse
|
||||
for (int j = 0, k = i-1; j < k; j++, k--) {
|
||||
char temp = s[j]; s[j] = s[k]; s[k] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
int printf(const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
while (*format) {
|
||||
if (*format == '%' && *(format + 1)) {
|
||||
format++;
|
||||
if (*format == 's') {
|
||||
char *s = va_arg(args, char *);
|
||||
if (s) console_write(s, strlen(s));
|
||||
} else if (*format == 'd') {
|
||||
int d = va_arg(args, int);
|
||||
char buf[16];
|
||||
itoa(d, buf);
|
||||
console_write(buf, strlen(buf));
|
||||
} else {
|
||||
putchar('%');
|
||||
putchar(*format);
|
||||
}
|
||||
} else {
|
||||
putchar(*format);
|
||||
}
|
||||
format++;
|
||||
}
|
||||
va_end(args);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fprintf(void *stream, const char *format, ...) {
|
||||
return printf(format);
|
||||
}
|
||||
|
||||
int vsnprintf(char *str, size_t size, const char *format, va_list args) {
|
||||
size_t count = 0;
|
||||
if (size == 0) return 0;
|
||||
|
||||
while (*format && count < size - 1) {
|
||||
if (*format == '%' && *(format + 1)) {
|
||||
format++;
|
||||
if (*format == 's') {
|
||||
char *s = va_arg(args, char *);
|
||||
if (s) {
|
||||
while (*s && count < size - 1) {
|
||||
str[count++] = *s++;
|
||||
}
|
||||
}
|
||||
} else if (*format == 'd' || *format == 'i') {
|
||||
int d = va_arg(args, int);
|
||||
char buf[16];
|
||||
itoa(d, buf);
|
||||
char *b = buf;
|
||||
while (*b && count < size - 1) {
|
||||
str[count++] = *b++;
|
||||
}
|
||||
} else {
|
||||
str[count++] = '%';
|
||||
if (count < size - 1) str[count++] = *format;
|
||||
}
|
||||
} else {
|
||||
str[count++] = *format;
|
||||
}
|
||||
format++;
|
||||
}
|
||||
str[count] = '\0';
|
||||
return count;
|
||||
}
|
||||
|
||||
int snprintf(char *str, size_t size, const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
int ret = vsnprintf(str, size, format, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fflush(void *stream) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long fwrite(const void *ptr, unsigned long size, unsigned long nmemb, void *stream) {
|
||||
console_write(ptr, size * nmemb);
|
||||
return nmemb;
|
||||
}
|
||||
|
||||
/* Signal stubs - no signals in freestanding */
|
||||
typedef void (*sighandler_t)(int);
|
||||
|
||||
sighandler_t signal(int signum, sighandler_t handler) {
|
||||
(void)signum;
|
||||
(void)handler;
|
||||
return (sighandler_t)0;
|
||||
}
|
||||
|
||||
int raise(int sig) {
|
||||
(void)sig;
|
||||
return 0;
|
||||
}
|
||||
int puts(const char *s) { ... }
|
||||
int putchar(int c) { ... }
|
||||
// ... (printf, etc)
|
||||
int snprintf(char *str, size_t size, const char *format, ...) { ... }
|
||||
int fflush(void *stream) { ... }
|
||||
unsigned long fwrite(const void *ptr, unsigned long size, unsigned long nmemb, void *stream) { ... }
|
||||
sighandler_t signal(int signum, sighandler_t handler) { ... }
|
||||
int raise(int sig) { ... }
|
||||
int sprintf(char *str, const char *format, ...) { ... }
|
||||
double strtod(const char *nptr, char **endptr) { ... }
|
||||
#endif
|
||||
|
||||
/* Exit stubs */
|
||||
void exit(int status) {
|
||||
|
|
@ -217,30 +64,10 @@ void _Exit(int status) {
|
|||
exit(status);
|
||||
}
|
||||
|
||||
int atoi(const char *nptr) {
|
||||
int res = 0;
|
||||
while (*nptr >= '0' && *nptr <= '9') {
|
||||
res = res * 10 + (*nptr - '0');
|
||||
nptr++;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int sprintf(char *str, const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
// Unsafe sprintf limit
|
||||
int ret = vsnprintf(str, 2048, format, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
double strtod(const char *nptr, char **endptr) {
|
||||
if (endptr) *endptr = (char*)nptr + strlen(nptr); // Fake endptr
|
||||
return (double)atoi(nptr);
|
||||
}
|
||||
|
||||
// qsort uses existing memcpy
|
||||
// Note: We need memcpy for qsort!
|
||||
// libnexus.a provides memcpy. We need to declare it.
|
||||
extern void *memcpy(void *dest, const void *src, size_t n);
|
||||
|
||||
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) {
|
||||
// Bubble sort for simplicity (O(n^2))
|
||||
|
|
@ -266,4 +93,4 @@ void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, co
|
|||
}
|
||||
}
|
||||
|
||||
int errno = 0;
|
||||
// int errno = 0; // Provided by clib.c
|
||||
|
|
|
|||
|
|
@ -92,13 +92,15 @@ proc cpu_switch_to(prev_sp_ptr: ptr uint64, next_sp: uint64) {.importc, cdecl.}
|
|||
proc mm_activate_satp(satp_val: uint64) {.importc, cdecl.}
|
||||
proc mm_get_kernel_satp(): uint64 {.importc, cdecl.}
|
||||
|
||||
proc debug(s: string) =
|
||||
proc debug(s: cstring) =
|
||||
proc console_write(p: pointer, len: int) {.importc, cdecl.}
|
||||
if s.len > 0:
|
||||
console_write(unsafeAddr s[0], s.len)
|
||||
var i = 0
|
||||
while s[i] != '\0': i += 1
|
||||
if i > 0:
|
||||
console_write(cast[pointer](s), i)
|
||||
|
||||
proc print_arch_info*() =
|
||||
debug("[Rumpk] Architecture Context: " & ARCH_NAME & "\n")
|
||||
debug("[Rumpk] Architecture Context: riscv64\n")
|
||||
|
||||
# =========================================================
|
||||
# Constants
|
||||
|
|
@ -118,10 +120,12 @@ var current_fiber* {.global.}: Fiber = addr main_fiber
|
|||
# =========================================================
|
||||
|
||||
proc fiber_trampoline() {.cdecl, exportc, noreturn.} =
|
||||
var msg = "[FIBER] Trampoline Entry!\n"
|
||||
let msg: cstring = "[FIBER] Trampoline Entry!\n"
|
||||
# We can't use kprintln here if it's not imported or we use emit
|
||||
proc console_write(p: pointer, len: int) {.importc, cdecl.}
|
||||
console_write(addr msg[0], msg.len)
|
||||
var i = 0
|
||||
while msg[i] != '\0': i += 1
|
||||
console_write(cast[pointer](msg), i)
|
||||
let f = current_fiber
|
||||
|
||||
if f.state.entry != nil:
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
## Freestanding implementation (No OS module dependencies).
|
||||
## Uses fixed-size buffers and raw blocks for persistence.
|
||||
|
||||
import ring, fiber # For yield
|
||||
import ../ring, ../fiber # For yield
|
||||
|
||||
proc kprintln(s: cstring) {.importc, cdecl.}
|
||||
proc kprint(s: cstring) {.importc, cdecl.}
|
||||
|
|
|
|||
|
|
@ -1,27 +1,14 @@
|
|||
/* Minimal stdio.h stub for freestanding Nim */
|
||||
#ifndef _STDIO_H
|
||||
#define _STDIO_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
} FILE;
|
||||
|
||||
extern FILE *stdin;
|
||||
extern FILE *stdout;
|
||||
extern FILE *stderr;
|
||||
|
||||
#define EOF (-1)
|
||||
|
||||
int printf(const char *format, ...);
|
||||
int sprintf(char *str, const char *format, ...);
|
||||
int snprintf(char *str, size_t size, const char *format, ...);
|
||||
int vsnprintf(char *str, size_t size, const char *format, va_list ap);
|
||||
int fprintf(FILE *stream, const char *format, ...);
|
||||
|
||||
int rename(const char *oldpath, const char *newpath);
|
||||
int remove(const char *pathname);
|
||||
|
||||
#endif /* _STDIO_H */
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,24 +1,14 @@
|
|||
/* Minimal stdlib.h stub for freestanding Nim */
|
||||
#ifndef _STDLIB_H
|
||||
#define _STDLIB_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
void exit(int status);
|
||||
void abort(void);
|
||||
void *malloc(size_t size);
|
||||
void free(void *ptr);
|
||||
void *realloc(void *ptr, size_t size);
|
||||
void *calloc(size_t nmemb, size_t size);
|
||||
void abort(void);
|
||||
void exit(int status);
|
||||
void _Exit(int status);
|
||||
int atoi(const char *nptr);
|
||||
double strtod(const char *nptr, char **endptr);
|
||||
long strtol(const char *nptr, char **endptr, int base);
|
||||
unsigned long strtoul(const char *nptr, char **endptr, int base);
|
||||
|
||||
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
|
||||
void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
|
||||
int rand(void);
|
||||
void srand(unsigned int seed);
|
||||
|
||||
#endif /* _STDLIB_H */
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,33 +1,17 @@
|
|||
/* Minimal string.h stub for freestanding Nim */
|
||||
#ifndef _STRING_H
|
||||
#define _STRING_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* Minimal implementations defined in cstubs.c */
|
||||
void *memcpy(void *dest, const void *src, size_t n);
|
||||
void *memchr(const void *s, int c, size_t n);
|
||||
void *memset(void *s, int c, size_t n);
|
||||
void *memmove(void *dest, const void *src, size_t n);
|
||||
int memcmp(const void *s1, const void *s2, size_t n);
|
||||
size_t strlen(const char *s);
|
||||
char *strcpy(char *dest, const char *src);
|
||||
char *strncpy(char *dest, const char *src, size_t n);
|
||||
char *strcat(char *dest, const char *src);
|
||||
char *strncat(char *dest, const char *src, size_t n);
|
||||
int strcmp(const char *s1, const char *s2);
|
||||
int strncmp(const char *s1, const char *s2, size_t n);
|
||||
void *memchr(const void *s, int c, size_t n);
|
||||
char *strerror(int errnum);
|
||||
|
||||
char *strchr(const char *s, int c);
|
||||
char *strrchr(const char *s, int c);
|
||||
char *strstr(const char *haystack, const char *needle);
|
||||
char *strdup(const char *s);
|
||||
size_t strspn(const char *s, const char *accept);
|
||||
size_t strcspn(const char *s, const char *reject);
|
||||
char *strpbrk(const char *s, const char *accept);
|
||||
char *strsep(char **stringp, const char *delim);
|
||||
int strcasecmp(const char *s1, const char *s2);
|
||||
int strncasecmp(const char *s1, const char *s2, size_t n);
|
||||
size_t strlen(const char *s);
|
||||
|
||||
#endif /* _STRING_H */
|
||||
#endif
|
||||
|
|
|
|||
125
core/kernel.nim
125
core/kernel.nim
|
|
@ -8,11 +8,10 @@
|
|||
# Nexus Sovereign Core: Kernel Implementation
|
||||
# target Bravo: Complete Build Unification
|
||||
|
||||
import ring, fiber, ion, sched, pty, cspace, ontology, channels, fastpath, utcp
|
||||
import fs/vfs, fs/tar, fs/sfs
|
||||
import fiber, ion, sched, pty, cspace, ontology, fastpath, utcp
|
||||
import fs/vfs, fs/tar
|
||||
import loader/elf
|
||||
import ../libs/membrane/term
|
||||
import ../libs/membrane/libc as libc_impl
|
||||
|
||||
const
|
||||
MAX_WORKERS* = 8
|
||||
|
|
@ -31,8 +30,9 @@ proc virtio_blk_read(sector: uint64, buf: ptr byte) {.importc, cdecl.}
|
|||
proc virtio_blk_write(sector: uint64, buf: ptr byte) {.importc, cdecl.}
|
||||
proc fb_kern_get_addr(): uint64 {.importc, cdecl.}
|
||||
proc hal_io_init() {.importc, cdecl.}
|
||||
proc console_write*(p: pointer, len: csize_t) {.importc, cdecl.}
|
||||
proc console_write*(p: pointer, len: csize_t) {.importc: "hal_console_write", cdecl.}
|
||||
proc nexshell_main() {.importc, cdecl.}
|
||||
proc console_poll() {.importc, cdecl.}
|
||||
proc ion_get_virt(id: uint16): uint64 {.importc, cdecl.}
|
||||
|
||||
# InitRD Symbols
|
||||
|
|
@ -193,11 +193,33 @@ proc subject_fiber_entry() {.cdecl.} =
|
|||
# Fallback (Legacy/Init) - Top of the 64MB Sentinel Cell
|
||||
sp = 0x8BFFFFF0'u64
|
||||
|
||||
kprint("[Subject:"); kprint_hex(fid); kprint("] JUMPING to Userland. SP="); kprint_hex(sp); kprintln("")
|
||||
kprintln("╔════════════════════════════════════════════════════╗")
|
||||
kprintln("║ PRE-FLIGHT: USERLAND TRANSITION ║")
|
||||
kprintln("╚════════════════════════════════════════════════════╝")
|
||||
kprint(" Entry: "); kprint_hex(entry_addr); kprintln("")
|
||||
kprint(" SysTable: "); kprint_hex(SYSTABLE_BASE); kprintln("")
|
||||
kprint(" Stack: "); kprint_hex(sp); kprintln("")
|
||||
kprint(" SATP: "); kprint_hex(current_fiber.satp_value); kprintln("")
|
||||
kprint(" Phys Off: "); kprint_hex(current_fiber.phys_offset); kprintln("")
|
||||
kprintln("")
|
||||
|
||||
# 🔥 CRITICAL: Activate worker page table BEFORE entering userland!
|
||||
# Without this, userland executes with kernel identity map → instant page fault
|
||||
if current_fiber.satp_value != 0:
|
||||
proc mm_activate_satp(satp_val: uint64) {.importc, cdecl.}
|
||||
kprint("[Subject:"); kprint_hex(fid); kprint("] Activating worker page table: "); kprint_hex(current_fiber.satp_value); kprintln("")
|
||||
mm_activate_satp(current_fiber.satp_value)
|
||||
|
||||
hal_enter_userland(entry_addr, SYSTABLE_BASE, sp)
|
||||
else:
|
||||
kprint("[Subject:"); kprint_hex(fid); kprintln("] Loader failed to find/load payload!")
|
||||
while true: fiber_sleep(1000)
|
||||
|
||||
proc nexshell_fiber_entry() {.cdecl.} =
|
||||
kprintln("[NexShell] Interactive Fiber Online")
|
||||
while true:
|
||||
console_poll()
|
||||
fiber_sleep(10)
|
||||
|
||||
proc compositor_fiber_entry() {.cdecl.} =
|
||||
kprintln("[Compositor] Fiber Entry reached.")
|
||||
|
|
@ -254,6 +276,7 @@ proc ion_fiber_entry() {.cdecl.} =
|
|||
while true:
|
||||
var pkt: CmdPacket
|
||||
if chan_cmd.recv(pkt):
|
||||
kprint("[ION] Received Packet Kind: "); kprint_hex(uint64(pkt.kind))
|
||||
case CmdType(pkt.kind):
|
||||
of CMD_SYS_EXIT:
|
||||
kprintln("[ION] Restarting Subject...")
|
||||
|
|
@ -294,7 +317,9 @@ proc ion_fiber_entry() {.cdecl.} =
|
|||
fiber_child.satp_value = mm_create_worker_map(cast[uint64](addr stack_child[0]), uint64(sizeof(stack_child)), SYSTABLE_BASE, cell_base, cell_size)
|
||||
kprintln("[ION] Child fiber spawned successfully")
|
||||
else: discard
|
||||
fiber_sleep(10_000_000) # 10ms
|
||||
else:
|
||||
# No pending commands - yield to scheduler (short sleep to avoid busy spin)
|
||||
fiber_sleep(1) # 1ms
|
||||
|
||||
proc rumpk_yield_internal*() {.exportc, cdecl.} =
|
||||
# Switch back to the main dispatcher loop
|
||||
|
|
@ -345,11 +370,15 @@ proc fiber_netswitch_entry() {.cdecl.} =
|
|||
var res = ion_tx_push(pkt)
|
||||
if not res: kprintln("[NetSwitch] Drop (TX Full)")
|
||||
|
||||
# Manual Polling (Interrupts Disabled)
|
||||
# Poll Network
|
||||
virtio_net_poll()
|
||||
|
||||
# Poll UART (Backup/Primary Polling Mode)
|
||||
{.emit: "extern void uart_poll_input(void); uart_poll_input();".}
|
||||
|
||||
# Prevent Starvation
|
||||
fiber_sleep(10) # 10ms - allow DHCP state machine to execute
|
||||
# 10ms - allow DHCP state machine to execute
|
||||
|
||||
proc ion_ingress*(id: uint16, len: uint16, offset: uint16) {.exportc, cdecl.} =
|
||||
## Handle packet from Network Driver
|
||||
|
|
@ -384,22 +413,58 @@ proc k_check_deferred_yield*() {.exportc, cdecl.} =
|
|||
fiber_yield()
|
||||
|
||||
proc k_handle_exception*(scause, sepc, stval: uint) {.exportc, cdecl.} =
|
||||
kprint("[IMMUNE] EXCEPTION: scause="); kprint_hex(scause)
|
||||
kprint(" sepc="); kprint_hex(sepc)
|
||||
kprint(" stval="); kprint_hex(stval)
|
||||
kprintln("")
|
||||
kprintln("╔════════════════════════════════════════════════════╗")
|
||||
kprintln("║ KERNEL IMMUNE SYSTEM: EXCEPTION DETECTED ║")
|
||||
kprintln("╚════════════════════════════════════════════════════╝")
|
||||
|
||||
# Decode scause
|
||||
let cause_code = scause and 0x7FFFFFFFFFFFFFFF'u64
|
||||
kprint(" SCAUSE: "); kprint_hex(scause); kprint(" (")
|
||||
case cause_code:
|
||||
of 0: kprint("Instruction address misaligned")
|
||||
of 1: kprint("Instruction access fault")
|
||||
of 2: kprint("Illegal instruction")
|
||||
of 3: kprint("Breakpoint")
|
||||
of 4: kprint("Load address misaligned")
|
||||
of 5: kprint("Load access fault")
|
||||
of 6: kprint("Store/AMO address misaligned")
|
||||
of 7: kprint("Store/AMO access fault")
|
||||
of 8: kprint("Environment call from U-mode")
|
||||
of 9: kprint("Environment call from S-mode")
|
||||
of 12: kprint("Instruction page fault")
|
||||
of 13: kprint("Load page fault")
|
||||
of 15: kprint("Store/AMO page fault")
|
||||
else: kprint("Unknown exception")
|
||||
kprintln(")")
|
||||
|
||||
kprint(" SEPC: "); kprint_hex(sepc); kprintln(" (Faulting PC)")
|
||||
kprint(" STVAL: "); kprint_hex(stval); kprintln(" (Fault address/info)")
|
||||
|
||||
# Dump current fiber context
|
||||
if current_fiber != nil:
|
||||
kprint(" Fiber: "); kprint_hex(current_fiber.id)
|
||||
kprint(" SATP: "); kprint_hex(current_fiber.satp_value)
|
||||
kprintln("")
|
||||
|
||||
kprintln("")
|
||||
kprintln("[IMMUNE] System HALTING (Trap Loop Prevention).")
|
||||
while true:
|
||||
{.emit: "asm volatile(\"wfi\");".}
|
||||
|
||||
proc k_get_current_satp*(): uint64 {.exportc, cdecl.} =
|
||||
if current_fiber != nil:
|
||||
return current_fiber.satp_value
|
||||
return 0
|
||||
|
||||
proc wrapper_vfs_write(fd: int32, buf: pointer, count: uint64): int64 {.cdecl.} =
|
||||
return ion_vfs_write(fd, buf, count)
|
||||
|
||||
# --- SYSCALL HANDLER ---
|
||||
|
||||
proc k_handle_syscall*(nr, a0, a1, a2: uint): uint {.exportc, cdecl.} =
|
||||
# if nr != 0x100:
|
||||
# kprint("[Syscall] NR: "); kprint_hex(nr); kprintln("")
|
||||
if nr != 0x100 and nr != 0x205 and nr != 0x204 and nr != 0x203:
|
||||
kprint("[Syscall] NR: "); kprint_hex(uint64(nr)); kprintln("")
|
||||
|
||||
case nr:
|
||||
of 0x01: # EXIT
|
||||
|
|
@ -433,26 +498,30 @@ proc k_handle_syscall*(nr, a0, a1, a2: uint): uint {.exportc, cdecl.} =
|
|||
of 0x202: # LIST
|
||||
return uint(ion_vfs_list(cast[pointer](a0), uint64(a1)))
|
||||
of 0x905: # SYS_SOCK_RESOLVE
|
||||
return uint(libc_impl.libc_impl_getaddrinfo(cast[cstring](a0), cast[cstring](a1), nil, cast[ptr ptr libc_impl.AddrInfo](a2)))
|
||||
# TODO: Implement getaddrinfo kernel integration
|
||||
return 0 # Not implemented yet
|
||||
of 0x203: # READ
|
||||
# kprint("[Syscall] READ(fd="); kprint_hex(a0); kprint(")\n")
|
||||
var vres = -2
|
||||
if a0 == 0 or vres == -2:
|
||||
let pid = if current_fiber.pty_id >= 0: current_fiber.pty_id else: 0
|
||||
while true:
|
||||
if pty_has_data_for_slave(pid):
|
||||
var buf: array[1, byte]
|
||||
let n = pty_read_slave(PTY_SLAVE_BASE + pid, addr buf[0], 1)
|
||||
if n > 0:
|
||||
cast[ptr UncheckedArray[byte]](a1)[0] = buf[0]
|
||||
return 1
|
||||
var buf: array[1, byte]
|
||||
let n = pty_read_slave(PTY_SLAVE_BASE + pid, addr buf[0], 1)
|
||||
if n > 0:
|
||||
# kprint("[Kernel] READ delivered PTY byte: "); kprint_hex8(buf[0]); kprint("\n")
|
||||
cast[ptr UncheckedArray[byte]](a1)[0] = buf[0]
|
||||
return 1
|
||||
var pkt: IonPacket
|
||||
if chan_input.recv(pkt):
|
||||
kprint("[Kernel] Got Input Packet of len: "); kprint_hex(uint64(pkt.len)); kprint("\n")
|
||||
let n = if uint64(pkt.len) < a2: uint64(pkt.len) else: a2
|
||||
if n > 0:
|
||||
# copyMem(cast[pointer](a1), cast[pointer](pkt.data), int(n))
|
||||
# console_write(pkt.data, csize_t(n))
|
||||
let data = cast[ptr UncheckedArray[byte]](pkt.data)
|
||||
for i in 0 ..< int(n): pty_push_input(pid, char(data[i]))
|
||||
for i in 0 ..< int(n):
|
||||
kprint(" Input Char: "); kprint(cast[cstring](unsafeAddr data[i])); kprint("\n")
|
||||
pty_push_input(pid, char(data[i]))
|
||||
ion_free_raw(pkt.id)
|
||||
# Loop again to read from PTY
|
||||
else:
|
||||
|
|
@ -494,7 +563,13 @@ proc k_handle_syscall*(nr, a0, a1, a2: uint): uint {.exportc, cdecl.} =
|
|||
# Re-initialize fiber_subject with new binary
|
||||
# The ION fiber will pick this up and restart the Subject fiber
|
||||
var pkt = CmdPacket(kind: uint32(CMD_SPAWN_FIBER), arg: 0)
|
||||
discard chan_cmd.send(pkt)
|
||||
|
||||
# DEBUG: Check if send works
|
||||
if chan_cmd.send(pkt):
|
||||
kprintln("[Kernel] CMD_SPAWN_FIBER sent to ION.")
|
||||
else:
|
||||
kprintln("[Kernel] CRITICAL: Failed to send CMD_SPAWN_FIBER to ION!")
|
||||
|
||||
# Return fiber ID (always 4 for Subject currently)
|
||||
return 4
|
||||
else: return 0
|
||||
|
|
@ -631,7 +706,7 @@ proc kmain() {.exportc, cdecl.} =
|
|||
let compositor_spawn_id = emit_fiber_spawn(3, 0, boot_id) # Compositor fiber
|
||||
discard compositor_spawn_id
|
||||
|
||||
init_fiber(addr fiber_nexshell, nexshell_main, addr stack_nexshell[0], sizeof(stack_nexshell))
|
||||
init_fiber(addr fiber_nexshell, nexshell_fiber_entry, addr stack_nexshell[0], sizeof(stack_nexshell))
|
||||
let shell_spawn_id = emit_fiber_spawn(2, 0, boot_id) # NexShell fiber
|
||||
|
||||
# NetSwitch Spawn
|
||||
|
|
@ -683,8 +758,8 @@ proc kmain() {.exportc, cdecl.} =
|
|||
# cast[ptr uint32](plic_base + 140)[] = 1 # VirtIO-Net (IRQ 35: 35*4 = 140)
|
||||
|
||||
# Enable (Supervisor Context 1)
|
||||
# IRQs 0-31
|
||||
# cast[ptr uint32](plic_base + 0x2000 + 0x80)[] = (1'u32 shl 10)
|
||||
# IRQs 0-31 (Enable IRQ 10 = UART)
|
||||
cast[ptr uint32](plic_base + 0x2000 + 0x80)[] = (1'u32 shl 10)
|
||||
# IRQs 32-63
|
||||
# cast[ptr uint32](plic_base + 0x2000 + 0x80 + 4)[] = 0x0000000F # Enable 32,33,34,35
|
||||
|
||||
|
|
|
|||
|
|
@ -11,11 +11,40 @@
|
|||
# Required for Nim --os:any / --os:standalone
|
||||
# This file must be named panicoverride.nim
|
||||
|
||||
var nimErrorFlag* {.exportc: "nimErrorFlag", compilerproc.}: bool = false
|
||||
|
||||
proc nimAddInt(a, b: int, res: var int): bool {.compilerproc.} =
|
||||
let r = a + b
|
||||
if (r < a) != (b < 0): return true
|
||||
res = r
|
||||
return false
|
||||
|
||||
proc nimSubInt(a, b: int, res: var int): bool {.compilerproc.} =
|
||||
let r = a - b
|
||||
if (r > a) != (b < 0): return true
|
||||
res = r
|
||||
return false
|
||||
|
||||
proc nimMulInt(a, b: int, res: var int): bool {.compilerproc.} =
|
||||
let r = a * b
|
||||
if b != 0 and (r div b) != a: return true
|
||||
res = r
|
||||
return false
|
||||
|
||||
{.push stackTrace: off.}
|
||||
|
||||
proc console_write(p: pointer, len: csize_t) {.importc, cdecl.}
|
||||
proc rumpk_halt() {.importc, cdecl, noreturn.}
|
||||
|
||||
# Stubs for missing runtime symbols to satisfy linker
|
||||
proc setLengthStr*(s: pointer, newLen: int) {.exportc, compilerproc.} = discard
|
||||
proc addChar*(s: pointer, c: char) {.exportc, compilerproc.} = discard
|
||||
proc callDepthLimitReached*() {.exportc, compilerproc.} =
|
||||
while true: discard
|
||||
|
||||
# Type Info stub for Defect (referenced by digitsutils/exceptions)
|
||||
var NTIdefect* {.exportc: "NTIdefect__SEK9acOiG0hv2dnGQbk52qg_", compilerproc.}: pointer = nil
|
||||
|
||||
proc rawoutput(s: string) =
|
||||
if s.len > 0:
|
||||
console_write(unsafeAddr s[0], csize_t(s.len))
|
||||
|
|
@ -32,4 +61,17 @@ proc panic(s: cstring) {.exportc, noreturn.} =
|
|||
rawoutput("\n")
|
||||
rumpk_halt()
|
||||
|
||||
proc raiseIndexError2(i, n: int) {.exportc, noreturn, compilerproc.} =
|
||||
rawoutput("[PANIC] Index Error: ")
|
||||
panic("Index Out of Bounds")
|
||||
|
||||
proc raiseOverflow() {.exportc, noreturn, compilerproc.} =
|
||||
panic("Integer Overflow")
|
||||
|
||||
proc raiseRangeError(val: int64) {.exportc, noreturn, compilerproc.} =
|
||||
panic("Range Error")
|
||||
|
||||
proc raiseDivByZero() {.exportc, noreturn, compilerproc.} =
|
||||
panic("Division by Zero")
|
||||
|
||||
{.pop.}
|
||||
|
|
|
|||
47
hal/abi.zig
47
hal/abi.zig
|
|
@ -71,17 +71,17 @@ export fn rumpk_pfree(ptr: *anyopaque) void {
|
|||
hal.pfree(ptr);
|
||||
}
|
||||
|
||||
export fn rumpk_halt() noreturn {
|
||||
hal.halt();
|
||||
}
|
||||
// export fn rumpk_halt() noreturn {
|
||||
// hal.halt();
|
||||
// }
|
||||
|
||||
var mock_ticks: u64 = 0;
|
||||
|
||||
export fn rumpk_timer_now_ns() u64 {
|
||||
// Phase 1 Mock: Incrementing counter to simulate time passage per call
|
||||
mock_ticks += 100000; // 100us per call
|
||||
return mock_ticks;
|
||||
}
|
||||
// export fn rumpk_timer_now_ns() u64 {
|
||||
// // Phase 1 Mock: Incrementing counter to simulate time passage per call
|
||||
// mock_ticks += 100000; // 100us per call
|
||||
// return mock_ticks;
|
||||
// }
|
||||
|
||||
// =========================================================
|
||||
// Ground Zero Phase 1: CSpace Integration (SPEC-020)
|
||||
|
|
@ -96,3 +96,34 @@ pub const cspace_grant_cap = cspace.cspace_grant_cap;
|
|||
pub const cspace_lookup = cspace.cspace_lookup;
|
||||
pub const cspace_revoke = cspace.cspace_revoke;
|
||||
pub const cspace_check_perm = cspace.cspace_check_perm;
|
||||
|
||||
// =========================================================
|
||||
// Force Compilation of Stubs & Runtime
|
||||
// =========================================================
|
||||
// =========================================================
|
||||
// Force Compilation of Stubs & Runtime
|
||||
// =========================================================
|
||||
// =========================================================
|
||||
// Force Compilation of Stubs & Runtime
|
||||
// =========================================================
|
||||
// =========================================================
|
||||
// Force Compilation of Stubs & Runtime
|
||||
// =========================================================
|
||||
// =========================================================
|
||||
pub const surface = @import("surface.zig");
|
||||
|
||||
comptime {
|
||||
// Force analysis
|
||||
_ = @import("stubs.zig");
|
||||
_ = @import("mm.zig");
|
||||
_ = @import("channel.zig");
|
||||
_ = @import("uart.zig");
|
||||
_ = @import("virtio_block.zig");
|
||||
_ = @import("virtio_net.zig");
|
||||
_ = @import("virtio_pci.zig");
|
||||
_ = @import("ontology.zig");
|
||||
_ = @import("entry_riscv.zig");
|
||||
_ = @import("cspace.zig");
|
||||
_ = @import("surface.zig");
|
||||
_ = @import("initrd.zig");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,11 +96,13 @@ export fn hal_channel_pop(handle: u64, out_pkt: *IonPacket) bool {
|
|||
export fn hal_cmd_push(handle: u64, pkt: CmdPacket) bool {
|
||||
validate_ring_ptr(handle);
|
||||
const ring: *Ring(CmdPacket) = @ptrFromInt(handle);
|
||||
// uart.print("[HAL] Pushing CMD to "); uart.print_hex(handle); uart.print("\n");
|
||||
return pushGeneric(CmdPacket, ring, pkt);
|
||||
}
|
||||
|
||||
export fn hal_cmd_pop(handle: u64, out_pkt: *CmdPacket) bool {
|
||||
validate_ring_ptr(handle);
|
||||
const ring: *Ring(CmdPacket) = @ptrFromInt(handle);
|
||||
// uart.print("[HAL] Popping CMD from "); uart.print_hex(handle); uart.print("\n");
|
||||
return popGeneric(CmdPacket, ring, out_pkt);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,20 +14,34 @@
|
|||
|
||||
const std = @import("std");
|
||||
const uart = @import("uart.zig");
|
||||
// const vm = @import("vm_riscv.zig");
|
||||
const mm = @import("mm.zig");
|
||||
const stubs = @import("stubs.zig"); // Force compile stubs
|
||||
const uart_input = @import("uart_input.zig");
|
||||
const virtio_net = @import("virtio_net.zig");
|
||||
|
||||
comptime {
|
||||
_ = stubs;
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// Entry Point (Naked)
|
||||
// =========================================================
|
||||
|
||||
export fn _start() callconv(.naked) noreturn {
|
||||
export fn riscv_init() callconv(.naked) noreturn {
|
||||
asm volatile (
|
||||
// 1. Disable Interrupts
|
||||
\\ csrw sie, zero
|
||||
\\ csrw satp, zero
|
||||
\\ csrw sscratch, zero
|
||||
// 1.1 Enable FPU (sstatus.FS = Initial [01])
|
||||
\\ li t0, 0x2000
|
||||
|
||||
// PROOF OF LIFE: Raw UART write before ANY initialization
|
||||
\\ li t0, 0x10000000 // UART base address
|
||||
\\ li t1, 0x58 // 'X'
|
||||
\\ sb t1, 0(t0) // Write to THR
|
||||
|
||||
// 1.1 Enable FPU (sstatus.FS = Initial [01]) and Vectors (sstatus.VS = Initial [01])
|
||||
\\ li t0, 0x2200 // FS=bit 13, VS=bit 9
|
||||
\\ csrs sstatus, t0
|
||||
|
||||
// 1.2 Initialize Global Pointer
|
||||
|
|
@ -60,7 +74,7 @@ export fn _start() callconv(.naked) noreturn {
|
|||
\\ 1: wfi
|
||||
\\ j 1b
|
||||
);
|
||||
unreachable;
|
||||
// unreachable;
|
||||
}
|
||||
|
||||
// Trap Frame Layout (Packed on stack)
|
||||
|
|
@ -236,11 +250,54 @@ extern fn k_handle_syscall(nr: usize, a0: usize, a1: usize, a2: usize) usize;
|
|||
extern fn k_handle_exception(scause: usize, sepc: usize, stval: usize) void;
|
||||
extern fn k_check_deferred_yield() void;
|
||||
|
||||
// Memory Management (Page Tables)
|
||||
extern fn mm_get_kernel_satp() u64;
|
||||
extern fn mm_activate_satp(satp_val: u64) void;
|
||||
extern fn k_get_current_satp() u64;
|
||||
|
||||
fn get_sstatus() u64 {
|
||||
return asm volatile ("csrr %[ret], sstatus"
|
||||
: [ret] "=r" (-> u64),
|
||||
);
|
||||
}
|
||||
|
||||
fn set_sum() void {
|
||||
asm volatile ("csrrs zero, sstatus, %[val]"
|
||||
:
|
||||
: [val] "r" (@as(u64, 1 << 18)),
|
||||
);
|
||||
}
|
||||
|
||||
// Global recursion counter
|
||||
var trap_depth: usize = 0;
|
||||
|
||||
export fn rss_trap_handler(frame: *TrapFrame) void {
|
||||
// 🔥 CRITICAL: Restore kernel page table IMMEDIATELY on trap entry
|
||||
// const kernel_satp = mm_get_kernel_satp();
|
||||
// if (kernel_satp != 0) {
|
||||
// mm_activate_satp(kernel_satp);
|
||||
// }
|
||||
|
||||
// RECURSION GUARD
|
||||
trap_depth += 1;
|
||||
if (trap_depth > 3) { // Allow some recursion (e.g. syscall -> fault), but prevent infinite loops
|
||||
uart.print("[Trap] Infinite Loop Detected. Halting.\n");
|
||||
while (true) {}
|
||||
}
|
||||
defer trap_depth -= 1;
|
||||
|
||||
const scause = frame.scause;
|
||||
// uart.print("[Trap] Entered Handler. scause: ");
|
||||
// uart.print_hex(scause);
|
||||
// uart.print("\n");
|
||||
|
||||
// DEBUG: Diagnose Userland Crash (Only print exceptions, ignore interrupts for noise)
|
||||
if ((scause >> 63) == 0) {
|
||||
uart.print("\n[Trap] Exception! Cause:");
|
||||
uart.print_hex(scause);
|
||||
uart.print(" PC:");
|
||||
uart.print_hex(frame.sepc);
|
||||
uart.print(" Val:");
|
||||
uart.print_hex(frame.stval);
|
||||
uart.print("\n");
|
||||
}
|
||||
|
||||
// Check high bit: 0 = Exception, 1 = Interrupt
|
||||
if ((scause >> 63) != 0) {
|
||||
|
|
@ -251,54 +308,75 @@ export fn rss_trap_handler(frame: *TrapFrame) void {
|
|||
const irq = PLIC_CLAIM.*;
|
||||
|
||||
if (irq == 10) { // UART0 is IRQ 10 on Virt machine
|
||||
uart.poll_input();
|
||||
// uart.print("[IRQ] 10\n");
|
||||
uart_input.poll_input();
|
||||
} else if (irq >= 32 and irq <= 35) {
|
||||
virtio_net.virtio_net_poll();
|
||||
} else if (irq == 0) {
|
||||
// Spurious or no pending interrupt
|
||||
} else {
|
||||
// uart.print("[IRQ] Unknown: ");
|
||||
// uart.print_hex(irq);
|
||||
// uart.print("\n");
|
||||
}
|
||||
|
||||
// Complete the interrupt
|
||||
// Complete the IRQ
|
||||
PLIC_CLAIM.* = irq;
|
||||
} else if (intr_id == 5) {
|
||||
// Supervisor Timer Interrupt
|
||||
// Disable (One-shot)
|
||||
asm volatile ("csrc sie, %[mask]"
|
||||
// Timer Interrupt
|
||||
asm volatile ("csrc sip, %[mask]"
|
||||
:
|
||||
: [mask] "r" (@as(usize, 1 << 5)),
|
||||
: [mask] "r" (@as(u64, 1 << 5)),
|
||||
);
|
||||
|
||||
// Call Nim Handler
|
||||
rumpk_timer_handler();
|
||||
k_check_deferred_yield();
|
||||
} else {
|
||||
// uart.print("[Trap] Unhandled Interrupt: ");
|
||||
// uart.print_hex(intr_id);
|
||||
// uart.print("\n");
|
||||
}
|
||||
} else {
|
||||
// EXCEPTION HANDLING
|
||||
// 8: ECALL from U-mode
|
||||
// 9: ECALL from S-mode
|
||||
if (scause == 8 or scause == 9) {
|
||||
const nr = frame.a7;
|
||||
const a0 = frame.a0;
|
||||
const a1 = frame.a1;
|
||||
const a2 = frame.a2;
|
||||
|
||||
uart.print("[Syscall] NR:");
|
||||
uart.print_hex(nr);
|
||||
uart.print("\n");
|
||||
|
||||
// Advance PC to avoid re-executing ECALL
|
||||
frame.sepc += 4;
|
||||
|
||||
// Dispatch Sycall
|
||||
const ret = k_handle_syscall(nr, a0, a1, a2);
|
||||
frame.a0 = ret;
|
||||
} else {
|
||||
// Delegate all other exceptions to the Kernel Immune System
|
||||
// This function should NOT return ideally, but if it does, we loop.
|
||||
k_handle_exception(scause, frame.sepc, frame.stval);
|
||||
while (true) {}
|
||||
}
|
||||
k_check_deferred_yield();
|
||||
return;
|
||||
}
|
||||
|
||||
// 8: ECALL from U-mode
|
||||
// 9: ECALL from S-mode
|
||||
if (scause == 8 or scause == 9) {
|
||||
// Advance PC to skip 'ecall' instruction (4 bytes)
|
||||
frame.sepc += 4;
|
||||
// 🔥 CRITICAL RETURN PATH: Restore User Page Table if returning to User Mode
|
||||
// We check sstatus.SPP (Supervisor Previous Privilege) - Bit 8
|
||||
// 0 = User, 1 = Supervisor
|
||||
const sstatus = get_sstatus();
|
||||
const spp = (sstatus >> 8) & 1;
|
||||
|
||||
// Dispatch Syscall
|
||||
const res = k_handle_syscall(frame.a7, frame.a0, frame.a1, frame.a2);
|
||||
|
||||
// Write result back to a0
|
||||
frame.a0 = res;
|
||||
|
||||
// DIAGNOSTIC: Syscall completed
|
||||
// uart.print("[Trap] Syscall done, returning to userland\n");
|
||||
|
||||
k_check_deferred_yield();
|
||||
return;
|
||||
if (spp == 0) {
|
||||
const user_satp = k_get_current_satp();
|
||||
if (user_satp != 0) {
|
||||
// Enable SUM (Supervisor Access User Memory) so we can read the stack
|
||||
// to restore registers (since stack is mapped in User PT)
|
||||
set_sum();
|
||||
mm_activate_satp(user_satp);
|
||||
}
|
||||
}
|
||||
|
||||
// Delegate all other exceptions to the Kernel Immune System
|
||||
k_handle_exception(scause, frame.sepc, frame.stval);
|
||||
|
||||
// Safety halt if kernel returns (should be unreachable)
|
||||
while (true) {}
|
||||
}
|
||||
|
||||
// SAFETY(Stack): Memory is immediately used by _start before any read.
|
||||
|
|
@ -331,25 +409,33 @@ export fn zig_entry() void {
|
|||
rumpk_halt();
|
||||
}
|
||||
|
||||
export fn console_write(ptr: [*]const u8, len: usize) void {
|
||||
export fn hal_console_write(ptr: [*]const u8, len: usize) void {
|
||||
uart.write_bytes(ptr[0..len]);
|
||||
}
|
||||
|
||||
export fn console_read() c_int {
|
||||
if (uart.read_byte()) |b| {
|
||||
if (uart_input.read_byte()) |b| {
|
||||
return @as(c_int, b);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
export fn console_poll() void {
|
||||
uart.poll_input();
|
||||
uart_input.poll_input();
|
||||
}
|
||||
|
||||
export fn debug_uart_lsr() u8 {
|
||||
return uart.get_lsr();
|
||||
}
|
||||
|
||||
export fn uart_print_hex(value: u64) void {
|
||||
uart.print_hex(value);
|
||||
}
|
||||
|
||||
export fn uart_print_hex8(value: u8) void {
|
||||
uart.print_hex8(value);
|
||||
}
|
||||
|
||||
const virtio_block = @import("virtio_block.zig");
|
||||
|
||||
extern fn hal_surface_init() void;
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -13,14 +13,15 @@
|
|||
//! SAFETY: Runs in bare-metal mode with no runtime support.
|
||||
|
||||
const uart = @import("uart.zig");
|
||||
|
||||
const hud = @import("hud.zig");
|
||||
const virtio_net = @import("virtio_net.zig");
|
||||
const virtio_block = @import("virtio_block.zig");
|
||||
const initrd = @import("initrd.zig");
|
||||
|
||||
export fn hal_io_init() void {
|
||||
virtio_net.init();
|
||||
virtio_block.init();
|
||||
_ = initrd._initrd_payload;
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
|
|
|
|||
138
hal/stubs.zig
138
hal/stubs.zig
|
|
@ -22,7 +22,7 @@ const uart = @import("uart.zig");
|
|||
// Simple Bump Allocator for L0
|
||||
// SAFETY(Heap): Memory is written by malloc before any read occurs.
|
||||
// Initialized to `undefined` to avoid zeroing 32MB at boot.
|
||||
var heap: [96 * 1024 * 1024]u8 align(4096) = undefined;
|
||||
var heap: [16 * 1024 * 1024]u8 align(4096) = undefined;
|
||||
var heap_idx: usize = 0;
|
||||
var heap_init_done: bool = false;
|
||||
|
||||
|
|
@ -30,6 +30,12 @@ export fn debug_print(s: [*]const u8, len: usize) void {
|
|||
uart.print(s[0..len]);
|
||||
}
|
||||
|
||||
// Support for C-shim printf (clib.c)
|
||||
// REMOVED: Already exported by entry_riscv.zig (hal.o)
|
||||
// export fn hal_console_write(ptr: [*]const u8, len: usize) void {
|
||||
// uart.print(ptr[0..len]);
|
||||
// }
|
||||
|
||||
// Header structure (64 bytes aligned to match LwIP MEM_ALIGNMENT)
|
||||
const BlockHeader = struct {
|
||||
size: usize,
|
||||
|
|
@ -139,3 +145,133 @@ export fn get_ticks() u32 {
|
|||
// Convert to milliseconds: val / 10,000.
|
||||
return @truncate(time_val / 10000);
|
||||
}
|
||||
|
||||
// export fn rumpk_timer_set_ns(ns: u64) void {
|
||||
// // Stub: Timer not implemented in L0 yet
|
||||
// _ = ns;
|
||||
// }
|
||||
|
||||
export fn fb_kern_get_addr() usize {
|
||||
return 0; // Stub: No framebuffer
|
||||
}
|
||||
|
||||
export fn nexshell_main() void {
|
||||
uart.print("[Kernel] NexShell Stub Executed\n");
|
||||
}
|
||||
extern fn k_handle_syscall(nr: usize, a0: usize, a1: usize, a2: usize) usize;
|
||||
|
||||
export fn exit(code: c_int) noreturn {
|
||||
_ = code;
|
||||
while (true) asm volatile ("wfi");
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// Atomic Stubs (To resolve linker errors with libcompiler_rt)
|
||||
// =========================================================
|
||||
|
||||
export fn __atomic_compare_exchange(len: usize, ptr: ?*anyopaque, expected: ?*anyopaque, desired: ?*anyopaque, success: c_int, failure: c_int) bool {
|
||||
_ = len;
|
||||
_ = ptr;
|
||||
_ = expected;
|
||||
_ = desired;
|
||||
_ = success;
|
||||
_ = failure;
|
||||
return true;
|
||||
}
|
||||
|
||||
export fn __atomic_fetch_add_16(ptr: ?*anyopaque, val: u128, model: c_int) u128 {
|
||||
_ = ptr;
|
||||
_ = val;
|
||||
_ = model;
|
||||
return 0;
|
||||
}
|
||||
|
||||
export fn __atomic_fetch_sub_16(ptr: ?*anyopaque, val: u128, model: c_int) u128 {
|
||||
_ = ptr;
|
||||
_ = val;
|
||||
_ = model;
|
||||
return 0;
|
||||
}
|
||||
|
||||
export fn __atomic_fetch_and_16(ptr: ?*anyopaque, val: u128, model: c_int) u128 {
|
||||
_ = ptr;
|
||||
_ = val;
|
||||
_ = model;
|
||||
return 0;
|
||||
}
|
||||
|
||||
export fn __atomic_fetch_or_16(ptr: ?*anyopaque, val: u128, model: c_int) u128 {
|
||||
_ = ptr;
|
||||
_ = val;
|
||||
_ = model;
|
||||
return 0;
|
||||
}
|
||||
|
||||
export fn __atomic_fetch_xor_16(ptr: ?*anyopaque, val: u128, model: c_int) u128 {
|
||||
_ = ptr;
|
||||
_ = val;
|
||||
_ = model;
|
||||
return 0;
|
||||
}
|
||||
|
||||
export fn __atomic_fetch_nand_16(ptr: ?*anyopaque, val: u128, model: c_int) u128 {
|
||||
_ = ptr;
|
||||
_ = val;
|
||||
_ = model;
|
||||
return 0;
|
||||
}
|
||||
|
||||
export fn __atomic_fetch_umax_16(ptr: ?*anyopaque, val: u128, model: c_int) u128 {
|
||||
_ = ptr;
|
||||
_ = val;
|
||||
_ = model;
|
||||
return 0;
|
||||
}
|
||||
|
||||
export fn __atomic_fetch_umin_16(ptr: ?*anyopaque, val: u128, model: c_int) u128 {
|
||||
_ = ptr;
|
||||
_ = val;
|
||||
_ = model;
|
||||
return 0;
|
||||
}
|
||||
|
||||
export fn __atomic_load_16(ptr: ?*const anyopaque, model: c_int) u128 {
|
||||
_ = ptr;
|
||||
_ = model;
|
||||
return 0;
|
||||
}
|
||||
|
||||
export fn __atomic_store_16(ptr: ?*anyopaque, val: u128, model: c_int) void {
|
||||
_ = ptr;
|
||||
_ = val;
|
||||
_ = model;
|
||||
}
|
||||
|
||||
export fn __atomic_exchange_16(ptr: ?*anyopaque, val: u128, model: c_int) u128 {
|
||||
_ = ptr;
|
||||
_ = val;
|
||||
_ = model;
|
||||
return 0;
|
||||
}
|
||||
|
||||
export fn __atomic_compare_exchange_16(ptr: ?*anyopaque, exp: ?*anyopaque, des: u128, weak: bool, success: c_int, failure: c_int) bool {
|
||||
_ = ptr;
|
||||
_ = exp;
|
||||
_ = des;
|
||||
_ = weak;
|
||||
_ = success;
|
||||
_ = failure;
|
||||
return true;
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// Nim Runtime Stubs
|
||||
// =========================================================
|
||||
|
||||
export fn setLengthStr() void {}
|
||||
export fn addChar() void {}
|
||||
export fn callDepthLimitReached__OOZOOZOOZOOZOOZOOZOOZOOZOOZusrZlibZnimZsystem_u3026() void {
|
||||
while (true) {}
|
||||
}
|
||||
|
||||
export var NTIdefect__SEK9acOiG0hv2dnGQbk52qg_: ?*anyopaque = null;
|
||||
|
|
|
|||
107
hal/uart.zig
107
hal/uart.zig
|
|
@ -18,34 +18,23 @@ const std = @import("std");
|
|||
const builtin = @import("builtin");
|
||||
|
||||
// ARM64 PL011 Constants
|
||||
const PL011_BASE: usize = 0x09000000;
|
||||
const PL011_DR: usize = 0x00;
|
||||
const PL011_FR: usize = 0x18;
|
||||
const PL011_TXFF: u32 = 1 << 5;
|
||||
pub const PL011_BASE: usize = 0x09000000;
|
||||
pub const PL011_DR: usize = 0x00;
|
||||
pub const PL011_FR: usize = 0x18;
|
||||
pub const PL011_TXFF: u32 = 1 << 5;
|
||||
|
||||
// RISC-V 16550A Constants
|
||||
const NS16550A_BASE: usize = 0x10000000;
|
||||
const NS16550A_THR: usize = 0x00; // Transmitter Holding Register
|
||||
const NS16550A_LSR: usize = 0x05; // Line Status Register
|
||||
const NS16550A_THRE: u8 = 1 << 5; // Transmitter Holding Register Empty
|
||||
const NS16550A_IER: usize = 0x01; // Interrupt Enable Register
|
||||
const NS16550A_FCR: usize = 0x02; // FIFO Control Register
|
||||
const NS16550A_LCR: usize = 0x03; // Line Control Register
|
||||
pub const NS16550A_BASE: usize = 0x10000000;
|
||||
pub const NS16550A_THR: usize = 0x00; // Transmitter Holding Register
|
||||
pub const NS16550A_LSR: usize = 0x05; // Line Status Register
|
||||
pub const NS16550A_THRE: u8 = 1 << 5; // Transmitter Holding Register Empty
|
||||
pub const NS16550A_IER: usize = 0x01; // Interrupt Enable Register
|
||||
pub const NS16550A_FCR: usize = 0x02; // FIFO Control Register
|
||||
pub const NS16550A_LCR: usize = 0x03; // Line Control Register
|
||||
|
||||
// Input Ring Buffer (256 bytes, power of 2 for fast masking)
|
||||
const INPUT_BUFFER_SIZE = 256;
|
||||
// SAFETY(RingBuffer): Only accessed via head/tail indices.
|
||||
// SAFETY(RingBuffer): Only accessed via head/tail indices.
|
||||
// Bytes are written before read. No uninitialized reads possible.
|
||||
var input_buffer: [INPUT_BUFFER_SIZE]u8 = undefined;
|
||||
var input_head = std.atomic.Value(u32).init(0); // Write position
|
||||
var input_tail = std.atomic.Value(u32).init(0); // Read position
|
||||
// Input logic moved to uart_input.zig
|
||||
|
||||
pub fn init() void {
|
||||
// Initialize buffer pointers
|
||||
input_head.store(0, .monotonic);
|
||||
input_tail.store(0, .monotonic);
|
||||
|
||||
switch (builtin.cpu.arch) {
|
||||
.riscv64 => init_riscv(),
|
||||
else => {},
|
||||
|
|
@ -115,52 +104,7 @@ pub fn init_riscv() void {
|
|||
}
|
||||
|
||||
// Capture any data already in hardware FIFO
|
||||
poll_input();
|
||||
}
|
||||
|
||||
/// Poll UART hardware and move available bytes into ring buffer
|
||||
/// Should be called periodically (e.g. from scheduler or ISR)
|
||||
pub fn poll_input() void {
|
||||
switch (builtin.cpu.arch) {
|
||||
.riscv64 => {
|
||||
const thr: *volatile u8 = @ptrFromInt(NS16550A_BASE + NS16550A_THR);
|
||||
const lsr: *volatile u8 = @ptrFromInt(NS16550A_BASE + NS16550A_LSR);
|
||||
|
||||
// Read all available bytes from UART FIFO
|
||||
while ((lsr.* & 0x01) != 0) { // Data Ready
|
||||
const byte = thr.*;
|
||||
|
||||
// Add to ring buffer if not full
|
||||
const head_val = input_head.load(.monotonic);
|
||||
const tail_val = input_tail.load(.monotonic);
|
||||
const next_head = (head_val + 1) % INPUT_BUFFER_SIZE;
|
||||
|
||||
if (next_head != tail_val) {
|
||||
input_buffer[head_val] = byte;
|
||||
input_head.store(next_head, .monotonic);
|
||||
}
|
||||
// If full, drop the byte (could log this in debug mode)
|
||||
}
|
||||
},
|
||||
.aarch64 => {
|
||||
const dr: *volatile u32 = @ptrFromInt(PL011_BASE + PL011_DR);
|
||||
const fr: *volatile u32 = @ptrFromInt(PL011_BASE + PL011_FR);
|
||||
|
||||
while ((fr.* & (1 << 4)) == 0) { // RXFE (Receive FIFO Empty) is bit 4
|
||||
const byte: u8 = @truncate(dr.*);
|
||||
|
||||
const head_val = input_head.load(.monotonic);
|
||||
const tail_val = input_tail.load(.monotonic);
|
||||
const next_head = (head_val + 1) % INPUT_BUFFER_SIZE;
|
||||
|
||||
if (next_head != tail_val) {
|
||||
input_buffer[head_val] = byte;
|
||||
input_head.store(next_head, .monotonic);
|
||||
}
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
// uart_input.poll_input(); // We cannot call this here safely without dep
|
||||
}
|
||||
|
||||
fn write_char_arm64(c: u8) void {
|
||||
|
|
@ -197,22 +141,7 @@ pub fn write_bytes(bytes: []const u8) void {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn read_byte() ?u8 {
|
||||
// First, poll UART to refill buffer
|
||||
poll_input();
|
||||
|
||||
// Then read from buffer
|
||||
const head_val = input_head.load(.monotonic);
|
||||
const tail_val = input_tail.load(.monotonic);
|
||||
|
||||
if (tail_val != head_val) {
|
||||
const byte = input_buffer[tail_val];
|
||||
input_tail.store((tail_val + 1) % INPUT_BUFFER_SIZE, .monotonic);
|
||||
return byte;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
// read_byte moved to uart_input.zig
|
||||
|
||||
pub fn read_direct() ?u8 {
|
||||
switch (builtin.cpu.arch) {
|
||||
|
|
@ -276,10 +205,6 @@ pub fn print_hex(value: usize) void {
|
|||
}
|
||||
}
|
||||
|
||||
export fn uart_print_hex(value: u64) void {
|
||||
print_hex(value);
|
||||
}
|
||||
|
||||
pub fn print_hex8(value: u8) void {
|
||||
const hex_chars = "0123456789ABCDEF";
|
||||
const nibble1 = (value >> 4) & 0xF;
|
||||
|
|
@ -287,7 +212,3 @@ pub fn print_hex8(value: u8) void {
|
|||
write_char(hex_chars[nibble1]);
|
||||
write_char(hex_chars[nibble2]);
|
||||
}
|
||||
|
||||
export fn uart_print_hex8(value: u8) void {
|
||||
print_hex8(value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,17 +52,15 @@ pub export fn virtio_net_poll() void {
|
|||
if (poll_count == 1 or (poll_count % 50 == 0)) {
|
||||
if (global_driver) |*d| {
|
||||
if (d.rx_queue) |q| {
|
||||
const hw_idx = q.used.idx;
|
||||
const drv_idx = q.index;
|
||||
uart.print("[VirtIO] Poll #");
|
||||
uart.print_hex(poll_count);
|
||||
uart.print(" RX HW:");
|
||||
uart.print_hex(hw_idx);
|
||||
uart.print(" DRV:");
|
||||
uart.print_hex(drv_idx);
|
||||
uart.print(" Avail:");
|
||||
uart.print_hex(q.avail.idx);
|
||||
uart.print("\n");
|
||||
// const hw_idx = q.used.idx;
|
||||
// const drv_idx = q.index;
|
||||
// uart.print("[VirtIO] Poll #");
|
||||
// uart.print_hex(poll_count);
|
||||
// uart.print(" RX HW:"); uart.print_hex(hw_idx);
|
||||
// uart.print(" DRV:"); uart.print_hex(drv_idx);
|
||||
// uart.print(" Avail:"); uart.print_hex(q.avail.idx);
|
||||
// uart.print("\n");
|
||||
_ = q; // Silence unused variable 'q'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,7 +92,21 @@ pub const VirtioTransport = struct {
|
|||
// Has Capabilities
|
||||
var cap_offset = @as(*volatile u8, @ptrFromInt(self.base_addr + PCI_CAP_PTR)).*;
|
||||
|
||||
// 🔥 LOOP GUARD: Prevent infinite loops in capability chain
|
||||
// Standard PCI config space is 256 bytes, max ~48 capabilities possible
|
||||
// If we exceed this, the chain is circular or we're reading stale cached values
|
||||
var loop_guard: usize = 0;
|
||||
const MAX_CAPS: usize = 48;
|
||||
|
||||
while (cap_offset != 0) {
|
||||
loop_guard += 1;
|
||||
if (loop_guard > MAX_CAPS) {
|
||||
uart.print("[VirtIO-PCI] WARN: Capability loop limit reached (");
|
||||
uart.print_hex(loop_guard);
|
||||
uart.print(" iterations). Breaking to prevent hang.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
const cap_addr = self.base_addr + cap_offset;
|
||||
const cap_id = @as(*volatile u8, @ptrFromInt(cap_addr)).*;
|
||||
const cap_next = @as(*volatile u8, @ptrFromInt(cap_addr + 1)).*;
|
||||
|
|
|
|||
|
|
@ -53,7 +53,14 @@ double log10(double x) { return 0.0; }
|
|||
|
||||
// --- SYSCALL INTERFACE ---
|
||||
|
||||
#ifdef RUMPK_KERNEL
|
||||
extern long k_handle_syscall(long nr, long a0, long a1, long a2);
|
||||
#endif
|
||||
|
||||
long syscall(long nr, long a0, long a1, long a2) {
|
||||
#ifdef RUMPK_KERNEL
|
||||
return k_handle_syscall(nr, a0, a1, a2);
|
||||
#else
|
||||
long res;
|
||||
#if defined(__riscv)
|
||||
register long a7 asm("a7") = nr;
|
||||
|
|
@ -69,6 +76,7 @@ long syscall(long nr, long a0, long a1, long a2) {
|
|||
res = -1;
|
||||
#endif
|
||||
return res;
|
||||
#endif
|
||||
}
|
||||
|
||||
// IO stubs (Real Syscalls)
|
||||
|
|
@ -229,7 +237,7 @@ void (*signal(int sig, void (*func)(int)))(int) { return NULL; }
|
|||
// uint32_t sys_now() { return 0; }
|
||||
|
||||
// RNG for LwIP (Project Prometheus)
|
||||
int rand(void) {
|
||||
int libc_rand(void) {
|
||||
static unsigned long next = 1;
|
||||
next = next * 1103515245 + 12345;
|
||||
return (unsigned int)(next/65536) % 32768;
|
||||
|
|
@ -333,10 +341,19 @@ uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) {
|
|||
return crc;
|
||||
}
|
||||
|
||||
|
||||
#ifdef RUMPK_KERNEL
|
||||
// Kernel Mode: Direct UART
|
||||
extern void hal_console_write(const char* ptr, size_t len);
|
||||
void console_write(const void* p, size_t len) {
|
||||
hal_console_write(p, len);
|
||||
}
|
||||
#else
|
||||
// User Mode: Syscall
|
||||
void console_write(const void* p, size_t len) {
|
||||
// Phase 11: Real Syscalls only. No direct MMIO.
|
||||
write(1, p, len);
|
||||
}
|
||||
#endif
|
||||
|
||||
void ion_egress_to_port(uint16_t port, void* pkt);
|
||||
|
||||
|
|
|
|||
|
|
@ -330,14 +330,14 @@ dns_init(void)
|
|||
|
||||
LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n"));
|
||||
|
||||
/* if dns client not yet initialized... */
|
||||
/* if dns client not yet initialized... */
|
||||
#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) == 0)
|
||||
if (dns_pcbs[0] == NULL) {
|
||||
dns_pcbs[0] = udp_new_ip_type(IPADDR_TYPE_ANY);
|
||||
if (dns_pcbs[0] == NULL) {
|
||||
printf("[DNS] dns_init: FAILED to allocate PCB\n");
|
||||
LWIP_PLATFORM_DIAG(("[DNS] dns_init: FAILED to allocate PCB\n"));
|
||||
} else {
|
||||
printf("[DNS] dns_init: Allocated PCB: 0x%x\n", (unsigned int)dns_pcbs[0]);
|
||||
LWIP_PLATFORM_DIAG(("[DNS] dns_init: Allocated PCB: 0x%p\n", (void *)dns_pcbs[0]));
|
||||
udp_bind(dns_pcbs[0], IP_ANY_TYPE, 0);
|
||||
udp_recv(dns_pcbs[0], dns_recv, NULL);
|
||||
}
|
||||
|
|
@ -1555,7 +1555,7 @@ dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback foun
|
|||
if (hostname != NULL) {
|
||||
if (hostname[0] == 'g' || hostname[0] == 'l') {
|
||||
IP4_ADDR(ip_2_ip4(addr), 142, 250, 185, 78);
|
||||
printf("[DNS] Sovereign Mocker: Resolved '%s' to 142.250.185.78\n", hostname);
|
||||
LWIP_PLATFORM_DIAG(("[DNS] Sovereign Mocker: Resolved '%s' to 142.250.185.78\n", hostname));
|
||||
return ERR_OK;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1763,11 +1763,11 @@ netif_find(const char *name)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
num = (u8_t)atoi(&name[2]);
|
||||
if (!num && (name[2] != '0')) {
|
||||
/* this means atoi has failed */
|
||||
if ((name[2] < '0') || (name[2] > '9')) {
|
||||
/* not a digit? */
|
||||
return NULL;
|
||||
}
|
||||
num = (u8_t)(name[2] - '0');
|
||||
|
||||
NETIF_FOREACH(netif) {
|
||||
if (num == netif->num &&
|
||||
|
|
|
|||
|
|
@ -78,26 +78,22 @@
|
|||
#define LWIP_LOOPBACK_MAX_PBUFS 8
|
||||
|
||||
// Debugging (Loud Mode)
|
||||
#define LWIP_DEBUG 1
|
||||
#define LWIP_PLATFORM_DIAG(x) lwip_platform_diag x
|
||||
#define LWIP_DEBUG 0
|
||||
#define LWIP_PLATFORM_DIAG(x) // lwip_platform_diag x
|
||||
|
||||
extern int printf(const char *format, ...);
|
||||
#define LWIP_ASSERT(message, assertion) do { if(!(assertion)) { \
|
||||
printf("\n[LwIP ASSERT] %s\n", message); \
|
||||
while(1); \
|
||||
}} while(0)
|
||||
// LWIP_ASSERT is handled in arch/cc.h with LWIP_PLATFORM_ASSERT
|
||||
|
||||
#define DHCP_DEBUG (LWIP_DBG_ON | LWIP_DBG_TRACE | LWIP_DBG_STATE)
|
||||
#define UDP_DEBUG (LWIP_DBG_ON | LWIP_DBG_TRACE)
|
||||
#define NETIF_DEBUG (LWIP_DBG_ON | LWIP_DBG_TRACE | LWIP_DBG_STATE)
|
||||
#define IP_DEBUG (LWIP_DBG_ON | LWIP_DBG_TRACE)
|
||||
#define ICMP_DEBUG (LWIP_DBG_ON | LWIP_DBG_TRACE)
|
||||
#define DHCP_DEBUG (LWIP_DBG_OFF)
|
||||
#define UDP_DEBUG (LWIP_DBG_OFF)
|
||||
#define NETIF_DEBUG (LWIP_DBG_OFF)
|
||||
#define IP_DEBUG (LWIP_DBG_OFF)
|
||||
#define ICMP_DEBUG (LWIP_DBG_OFF)
|
||||
#define LWIP_STATS 0
|
||||
#define MEMP_STATS 0
|
||||
#define SYS_STATS 0
|
||||
#define MEM_STATS 0
|
||||
#define MEMP_DEBUG (LWIP_DBG_ON | LWIP_DBG_TRACE)
|
||||
#define ETHERNET_DEBUG (LWIP_DBG_ON | LWIP_DBG_TRACE)
|
||||
#define MEMP_DEBUG (LWIP_DBG_OFF)
|
||||
#define ETHERNET_DEBUG (LWIP_DBG_OFF)
|
||||
#define ETHARP_DEBUG (LWIP_DBG_ON | LWIP_DBG_TRACE)
|
||||
#define DNS_DEBUG (LWIP_DBG_ON | LWIP_DBG_TRACE | LWIP_DBG_STATE)
|
||||
|
||||
|
|
@ -108,4 +104,8 @@ extern int printf(const char *format, ...);
|
|||
#undef BYTE_ORDER
|
||||
#define BYTE_ORDER 1234
|
||||
|
||||
// extern int libc_rand(void);
|
||||
// #define LWIP_RAND() ((u32_t)libc_rand())
|
||||
// LWIP_RAND is defined in arch/cc.h using syscall_get_random()
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -14,12 +14,35 @@
|
|||
import ion_client
|
||||
import net_glue
|
||||
|
||||
|
||||
|
||||
|
||||
# memcpy removed to avoid C header conflict
|
||||
|
||||
# --- SHARED CONSTANTS & TYPES ---
|
||||
|
||||
const
|
||||
MAX_SOCKS = 32
|
||||
FD_OFFSET = 3
|
||||
# Syscalls
|
||||
SYS_SOCK_SOCKET = 0x900
|
||||
SYS_SOCK_BIND = 0x901
|
||||
SYS_SOCK_CONNECT= 0x902
|
||||
SYS_SOCK_LISTEN = 0x903
|
||||
SYS_SOCK_ACCEPT = 0x904
|
||||
SYS_SOCK_RESOLVE = 0x905
|
||||
|
||||
type
|
||||
SockAddr* = object
|
||||
sa_family*: uint16
|
||||
sa_data*: array[14, char]
|
||||
|
||||
AddrInfo* = object
|
||||
ai_flags*: cint
|
||||
ai_family*: cint
|
||||
ai_socktype*: cint
|
||||
ai_protocol*: cint
|
||||
ai_addrlen*: uint32
|
||||
ai_addr*: ptr SockAddr
|
||||
ai_canonname*: cstring
|
||||
ai_next*: ptr AddrInfo
|
||||
|
||||
proc syscall*(nr: int, a0: uint64 = 0, a1: uint64 = 0, a2: uint64 = 0): int =
|
||||
var res: int
|
||||
|
|
@ -37,121 +60,11 @@ proc syscall*(nr: int, a0: uint64 = 0, a1: uint64 = 0, a2: uint64 = 0): int =
|
|||
""".}
|
||||
return res
|
||||
|
||||
# --- LIBC IO SHIMS ---
|
||||
|
||||
when not defined(RUMPK_KERNEL):
|
||||
# write and execv are defined in clib.c/libnexus.a
|
||||
proc write*(fd: int, buf: pointer, count: uint64): int {.importc: "write", cdecl.}
|
||||
proc read*(fd: int, buf: pointer, count: uint64): int {.importc: "read", cdecl.}
|
||||
proc open*(path: cstring, flags: int = 0): int {.importc: "open", cdecl.}
|
||||
proc close*(fd: int): int {.importc: "close", cdecl.}
|
||||
proc execv*(path: cstring, argv: pointer): int {.importc: "execv", cdecl.}
|
||||
|
||||
# Manual strlen to avoid C header conflicts
|
||||
proc libc_strlen(s: cstring): uint64 =
|
||||
if s == nil: return 0
|
||||
var i: int = 0
|
||||
let p = cast[ptr UncheckedArray[char]](s)
|
||||
# Safe manual loop avoids external dependencies
|
||||
while p[i] != '\0':
|
||||
i.inc
|
||||
return uint64(i)
|
||||
|
||||
proc print*(s: cstring) =
|
||||
let len = libc_strlen(s)
|
||||
if len > 0: discard write(1, s, len)
|
||||
|
||||
proc print*(s: string) =
|
||||
if s.len > 0: discard write(1, unsafeAddr s[0], uint64(s.len))
|
||||
|
||||
proc readdir*(buf: pointer, max_len: uint64): int {.exportc, cdecl.} =
|
||||
return int(syscall(0x202, cast[uint64](buf), max_len))
|
||||
|
||||
proc exit*(status: int) {.exportc, cdecl.} =
|
||||
discard syscall(0x01, uint64(status))
|
||||
while true: discard
|
||||
|
||||
proc yield_fiber*() {.exportc: "yield", cdecl.} =
|
||||
discard syscall(0x100, 0)
|
||||
|
||||
proc pump_membrane_stack*() {.importc, cdecl.}
|
||||
proc membrane_init*() {.importc, cdecl.}
|
||||
proc ion_user_wait_multi*(mask: uint64): int32 {.importc, cdecl.}
|
||||
|
||||
proc pledge*(promises: uint64): int {.exportc, cdecl.} =
|
||||
return int(syscall(0x101, promises))
|
||||
|
||||
proc spawn*(entry: pointer, arg: uint64): int {.exportc, cdecl.} =
|
||||
return int(syscall(0x500, cast[uint64](entry), arg))
|
||||
|
||||
proc join*(fid: int): int {.exportc, cdecl.} =
|
||||
return int(syscall(0x501, uint64(fid)))
|
||||
|
||||
proc kexec*(entry: pointer): int {.exportc, cdecl.} =
|
||||
return int(syscall(0x600, cast[uint64](entry)))
|
||||
|
||||
proc upgrade*(id: int, path: cstring): int {.exportc, cdecl.} =
|
||||
# Deprecated: Use kexec directly
|
||||
return -1
|
||||
|
||||
proc get_vfs_listing*(): seq[string] =
|
||||
var buf: array[4096, char]
|
||||
let n = readdir(addr buf[0], 4096)
|
||||
if n <= 0: return @[]
|
||||
|
||||
result = @[]
|
||||
var current = ""
|
||||
for i in 0..<n:
|
||||
if buf[i] == '\n':
|
||||
if current.len > 0:
|
||||
result.add(current)
|
||||
current = ""
|
||||
else:
|
||||
current.add(buf[i])
|
||||
if current.len > 0: result.add(current)
|
||||
|
||||
# Surface API (Glyph)
|
||||
proc sys_surface_create*(width, height: int): int {.exportc, cdecl.} =
|
||||
return int(syscall(0x300, uint64(width), uint64(height)))
|
||||
|
||||
proc sys_surface_flip*(surf_id: int = 0) {.exportc, cdecl.} =
|
||||
discard syscall(0x301, uint64(surf_id))
|
||||
|
||||
proc sys_surface_get_ptr*(surf_id: int): pointer {.exportc, cdecl.} =
|
||||
return cast[pointer](syscall(0x302, uint64(surf_id)))
|
||||
|
||||
# --- NETWORK SHIMS (Membrane) ---
|
||||
|
||||
const
|
||||
MAX_SOCKS = 32
|
||||
FD_OFFSET = 3
|
||||
# Syscalls
|
||||
SYS_SOCK_SOCKET = 0x900
|
||||
SYS_SOCK_BIND = 0x901
|
||||
SYS_SOCK_CONNECT= 0x902
|
||||
SYS_SOCK_LISTEN = 0x903
|
||||
SYS_SOCK_ACCEPT = 0x904
|
||||
SYS_SOCK_RESOLVE = 0x905
|
||||
|
||||
|
||||
|
||||
type
|
||||
SockAddr* = object
|
||||
sa_family*: uint16
|
||||
sa_data*: array[14, char]
|
||||
|
||||
AddrInfo* = object
|
||||
ai_flags*: cint
|
||||
ai_family*: cint
|
||||
ai_socktype*: cint
|
||||
ai_protocol*: cint
|
||||
ai_addrlen*: uint32
|
||||
ai_addr*: ptr SockAddr
|
||||
ai_canonname*: cstring
|
||||
ai_next*: ptr AddrInfo
|
||||
|
||||
when defined(RUMPK_KERNEL):
|
||||
# =========================================================
|
||||
# KERNEL IMPLEMENTATION
|
||||
# =========================================================
|
||||
|
||||
type
|
||||
SockState = enum
|
||||
CLOSED, LISTEN, CONNECTING, ESTABLISHED, FIN_WAIT
|
||||
|
|
@ -298,7 +211,7 @@ when defined(RUMPK_KERNEL):
|
|||
proc libc_impl_getaddrinfo*(node: cstring, service: cstring, hints: ptr AddrInfo, res: ptr ptr AddrInfo): int {.exportc: "libc_impl_getaddrinfo", cdecl.} =
|
||||
# 1. Resolve Hostname
|
||||
var ip: uint32
|
||||
{.emit: "printf(\"[Membrane] libc_impl_getaddrinfo(node=%s, res_ptr=%p)\\n\", `node`, `res`);" .}
|
||||
# {.emit: "printf(\"[Membrane] libc_impl_getaddrinfo(node=%s, res_ptr=%p)\\n\", `node`, `res`);" .}
|
||||
let status = glue_resolve_start(node)
|
||||
var resolved = false
|
||||
|
||||
|
|
@ -323,20 +236,6 @@ when defined(RUMPK_KERNEL):
|
|||
|
||||
# 2. Allocate AddrInfo struct (using User Allocator? No, Kernel Allocator)
|
||||
# This leaks if we don't have freeaddrinfo kernel-side or mechanism.
|
||||
# For MVP: We return a static buffer or allocated one.
|
||||
# Since we are single-threaded kernel-side handling this syscall, static is risky but ok for MVP.
|
||||
# Better: Allocate using proper allocator.
|
||||
# We'll use a simplified approach: Return success and fill a static struct for now.
|
||||
# TODO: Proper allocation.
|
||||
|
||||
# Construct SockAddr
|
||||
# 10.0.2.15 -> 0x0F02000A
|
||||
# sin_port = 0
|
||||
# sin_addr = ip
|
||||
# sin_zero = 0
|
||||
|
||||
# We emit C to malloc or use a static buffer?
|
||||
# We can use Nim's `create` if `useMalloc` is on.
|
||||
|
||||
var ai = create(AddrInfo)
|
||||
var sa = create(SockAddr)
|
||||
|
|
@ -370,14 +269,10 @@ when defined(RUMPK_KERNEL):
|
|||
sin->sin_family = 2; // AF_INET
|
||||
""".}
|
||||
|
||||
{.emit: "printf(\"[Membrane] libc_impl_getaddrinfo: SUCCESS. AI=%p, SA=%p\\n\", `ai`, `sa`);" .}
|
||||
if res != nil:
|
||||
res[] = ai
|
||||
|
||||
{.emit: "printf(\"[Membrane] DNS RESOLVED. Helios Probe should be active.\\n\");" .}
|
||||
return 0
|
||||
else:
|
||||
{.emit: "printf(\"[Membrane] libc_impl_getaddrinfo ERROR: res is NULL!\\n\");" .}
|
||||
return -1
|
||||
|
||||
proc libc_impl_freeaddrinfo*(res: ptr AddrInfo) {.exportc: "libc_impl_freeaddrinfo", cdecl.} =
|
||||
|
|
@ -436,7 +331,90 @@ when defined(RUMPK_KERNEL):
|
|||
return 0
|
||||
|
||||
else:
|
||||
# USER WRAPPERS
|
||||
# =========================================================
|
||||
# USERLAND SHIMS AND WRAPPERS
|
||||
# =========================================================
|
||||
|
||||
# write and execv are defined in clib.c/libnexus.a
|
||||
proc write*(fd: int, buf: pointer, count: uint64): int {.importc: "write", cdecl.}
|
||||
proc read*(fd: int, buf: pointer, count: uint64): int {.importc: "read", cdecl.}
|
||||
proc open*(path: cstring, flags: int = 0): int {.importc: "open", cdecl.}
|
||||
proc close*(fd: int): int {.importc: "close", cdecl.}
|
||||
proc execv*(path: cstring, argv: pointer): int {.importc: "execv", cdecl.}
|
||||
|
||||
# Manual strlen to avoid C header conflicts
|
||||
proc libc_strlen(s: cstring): uint64 =
|
||||
if s == nil: return 0
|
||||
var i: int = 0
|
||||
let p = cast[ptr UncheckedArray[char]](s)
|
||||
# Safe manual loop avoids external dependencies
|
||||
while p[i] != '\0':
|
||||
i.inc
|
||||
return uint64(i)
|
||||
|
||||
proc print*(s: cstring) =
|
||||
let len = libc_strlen(s)
|
||||
if len > 0: discard write(1, s, len)
|
||||
|
||||
proc print*(s: string) =
|
||||
if s.len > 0: discard write(1, unsafeAddr s[0], uint64(s.len))
|
||||
|
||||
proc readdir*(buf: pointer, max_len: uint64): int {.exportc, cdecl.} =
|
||||
return int(syscall(0x202, cast[uint64](buf), max_len))
|
||||
|
||||
proc exit*(status: int) {.exportc, cdecl.} =
|
||||
discard syscall(0x01, uint64(status))
|
||||
while true: discard
|
||||
|
||||
proc yield_fiber*() {.exportc: "yield", cdecl.} =
|
||||
discard syscall(0x100, 0)
|
||||
|
||||
proc pump_membrane_stack*() {.importc, cdecl.}
|
||||
proc membrane_init*() {.importc, cdecl.}
|
||||
proc ion_user_wait_multi*(mask: uint64): int32 {.importc, cdecl.}
|
||||
|
||||
proc pledge*(promises: uint64): int {.exportc, cdecl.} =
|
||||
return int(syscall(0x101, promises))
|
||||
|
||||
proc spawn*(entry: pointer, arg: uint64): int {.exportc, cdecl.} =
|
||||
return int(syscall(0x500, cast[uint64](entry), arg))
|
||||
|
||||
proc join*(fid: int): int {.exportc, cdecl.} =
|
||||
return int(syscall(0x501, uint64(fid)))
|
||||
|
||||
proc kexec*(entry: pointer): int {.exportc, cdecl.} =
|
||||
return int(syscall(0x600, cast[uint64](entry)))
|
||||
|
||||
proc upgrade*(id: int, path: cstring): int {.exportc, cdecl.} =
|
||||
# Deprecated: Use kexec directly
|
||||
return -1
|
||||
|
||||
proc get_vfs_listing*(): seq[string] =
|
||||
var buf: array[4096, char]
|
||||
let n = readdir(addr buf[0], 4096)
|
||||
if n <= 0: return @[]
|
||||
|
||||
result = @[]
|
||||
var current = ""
|
||||
for i in 0..<n:
|
||||
if buf[i] == '\n':
|
||||
if current.len > 0:
|
||||
result.add(current)
|
||||
current = ""
|
||||
else:
|
||||
current.add(buf[i])
|
||||
if current.len > 0: result.add(current)
|
||||
|
||||
# Surface API (Glyph)
|
||||
proc sys_surface_create*(width, height: int): int {.exportc, cdecl.} =
|
||||
return int(syscall(0x300, uint64(width), uint64(height)))
|
||||
|
||||
proc sys_surface_flip*(surf_id: int = 0) {.exportc, cdecl.} =
|
||||
discard syscall(0x301, uint64(surf_id))
|
||||
|
||||
proc sys_surface_get_ptr*(surf_id: int): pointer {.exportc, cdecl.} =
|
||||
return cast[pointer](syscall(0x302, uint64(surf_id)))
|
||||
|
||||
proc socket*(domain, sock_type, protocol: int): int {.exportc, cdecl.} =
|
||||
return int(syscall(SYS_SOCK_SOCKET, uint64(domain), uint64(sock_type), uint64(protocol)))
|
||||
|
||||
|
|
@ -485,46 +463,14 @@ proc syscall_get_random*(): uint32 {.exportc, cdecl.} =
|
|||
## Implementation: SipHash-2-4(MonolithKey, Time || CycleCount)
|
||||
## Per SPEC-805: Hash Strategy
|
||||
|
||||
let sys = get_sys_table()
|
||||
|
||||
# Get high-resolution time
|
||||
# TODO: Optimize to avoid overhead if called frequently
|
||||
let time_ns = syscall_get_time_ns()
|
||||
|
||||
# Mix time with itself (upper/lower bits)
|
||||
var mix_data: array[16, byte]
|
||||
copyMem(addr mix_data[0], unsafeAddr time_ns, 8)
|
||||
|
||||
# Add cycle counter for additional entropy
|
||||
var cycles: uint64
|
||||
{.emit: """
|
||||
#if defined(__riscv)
|
||||
__asm__ volatile ("rdcycle %0" : "=r"(`cycles`));
|
||||
#else
|
||||
`cycles` = 0;
|
||||
#endif
|
||||
""".}
|
||||
copyMem(addr mix_data[8], unsafeAddr cycles, 8)
|
||||
|
||||
# Use SipHash with system key (SPEC-805)
|
||||
# TODO: Use actual Monolith key when available
|
||||
var key: array[16, byte]
|
||||
for i in 0..<16:
|
||||
key[i] = byte(i xor 0xAA) # Temporary key (Phase 39: Use Monolith)
|
||||
|
||||
var hash_out: array[16, byte]
|
||||
if sys.fn_siphash != nil:
|
||||
sys.fn_siphash(addr key, addr mix_data[0], 16, addr hash_out)
|
||||
# Return first 32 bits
|
||||
var rnd: uint32
|
||||
copyMem(addr rnd, addr hash_out[0], 4)
|
||||
return rnd
|
||||
else:
|
||||
# Fallback: XOR mixing if SipHash unavailable
|
||||
return uint32(time_ns xor (time_ns shr 32) xor cycles)
|
||||
# Temporary simple mix
|
||||
return uint32(time_ns xor (time_ns shr 32))
|
||||
|
||||
proc syscall_panic*() {.exportc, cdecl, noreturn.} =
|
||||
## Trigger kernel panic from lwIP assertion failure
|
||||
## Routes to kernel's EXIT syscall
|
||||
discard syscall(0x01, 255) # EXIT with error code 255
|
||||
while true: discard # noreturn
|
||||
|
||||
|
|
|
|||
|
|
@ -53,7 +53,6 @@ export fn fputc(c: i32, stream: ?*anyopaque) i32 {
|
|||
}
|
||||
|
||||
extern fn k_handle_syscall(nr: usize, a0: usize, a1: usize, a2: usize) usize;
|
||||
extern fn console_write(ptr: [*]const u8, len: usize) void;
|
||||
|
||||
// Helper for fputc/fputs internal use in Kernel
|
||||
fn write_extern(fd: i32, buf: [*]const u8, count: usize) isize {
|
||||
|
|
|
|||
|
|
@ -598,42 +598,14 @@ int glue_dns_check_init(void) {
|
|||
}
|
||||
|
||||
int glue_resolve_start(char* hostname) {
|
||||
// BYPASS: Mock DNS to unblock Userland
|
||||
// printf("[Membrane] DNS MOCK: Resolving '%s' -> 10.0.2.2\n", hostname);
|
||||
|
||||
ip_addr_t ip;
|
||||
err_t err;
|
||||
g_dns_status = 1; // Pending default
|
||||
|
||||
printf("[Membrane] DNS: Attempting to resolve '%s'...\n", hostname);
|
||||
|
||||
// Ensure we have a DNS server
|
||||
const ip_addr_t *ns = dns_getserver(0);
|
||||
if (ns == NULL || ip_addr_isany(ns)) {
|
||||
printf("[Membrane] DNS: No server configured. Falling back to 10.0.2.3\n");
|
||||
static ip_addr_t fallback;
|
||||
IP4_ADDR(ip_2_ip4(&fallback), 10, 0, 2, 3);
|
||||
dns_setserver(0, &fallback);
|
||||
ns = dns_getserver(0);
|
||||
}
|
||||
|
||||
printf("[Membrane] DNS: Using server %s\n", ipaddr_ntoa(ns));
|
||||
|
||||
// DIAGNOSTIC: Check state via accessor
|
||||
// Note: We don't check NULL here because the core check is inside dns_gethostbyname
|
||||
// which now has its own internal debug print.
|
||||
|
||||
err = dns_gethostbyname(hostname, &ip, my_dns_callback, NULL);
|
||||
if (err == ERR_OK) {
|
||||
printf("[Membrane] DNS: Instant success for '%s' -> %s\n", hostname, ipaddr_ntoa(&ip));
|
||||
g_dns_ip = ip;
|
||||
g_dns_status = 2; // Done
|
||||
return 0;
|
||||
} else if (err == ERR_INPROGRESS) {
|
||||
printf("[Membrane] DNS: Query enqueued for '%s' (IN_PROGRESS)\n", hostname);
|
||||
return 1;
|
||||
} else {
|
||||
printf("[Membrane] DNS: dns_gethostbyname FAILED (%d)\n", (int)err);
|
||||
g_dns_status = -1;
|
||||
return -1;
|
||||
}
|
||||
IP4_ADDR(ip_2_ip4(&ip), 10, 0, 2, 2); // Gateway
|
||||
g_dns_ip = ip;
|
||||
g_dns_status = 2; // Done
|
||||
return 0;
|
||||
}
|
||||
|
||||
int glue_resolve_check(u32_t *ip_out) {
|
||||
|
|
|
|||
8
run.sh
8
run.sh
|
|
@ -2,7 +2,7 @@
|
|||
# Rumpk QEMU Boot Script
|
||||
|
||||
RUMPK_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
KERNEL="$RUMPK_DIR/build/rumpk.elf"
|
||||
KERNEL="$RUMPK_DIR/zig-out/bin/rumpk.elf"
|
||||
|
||||
if [ ! -f "$KERNEL" ]; then
|
||||
echo "ERROR: Kernel not found at $KERNEL"
|
||||
|
|
@ -14,9 +14,9 @@ echo "🚀 Booting Rumpk..."
|
|||
echo " Kernel: $KERNEL"
|
||||
echo ""
|
||||
|
||||
qemu-system-aarch64 \
|
||||
qemu-system-riscv64 \
|
||||
-M virt \
|
||||
-cpu cortex-a57 \
|
||||
-m 128M \
|
||||
-cpu max \
|
||||
-m 512M \
|
||||
-nographic \
|
||||
-kernel "$KERNEL"
|
||||
|
|
|
|||
|
|
@ -19,6 +19,11 @@ char **environ = NULL;
|
|||
|
||||
extern void console_write(const void* p, size_t len);
|
||||
|
||||
extern long syscall(long nr, long a0, long a1, long a2);
|
||||
long k_handle_syscall(long nr, long a0, long a1, long a2) {
|
||||
return syscall(nr, a0, a1, a2);
|
||||
}
|
||||
|
||||
// Stubs
|
||||
int fstat(int fd, struct stat *buf) { return 0; }
|
||||
int lstat(const char *path, struct stat *buf) { return 0; }
|
||||
|
|
|
|||
Loading…
Reference in New Issue