diff --git a/boot/header.zig b/boot/header.zig index db90c5a..7748aea 100644 --- a/boot/header.zig +++ b/boot/header.zig @@ -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 diff --git a/boot/linker.ld b/boot/linker.ld index e4aa1cb..26b090f 100644 --- a/boot/linker.ld +++ b/boot/linker.ld @@ -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*) diff --git a/core/cstubs.c b/core/cstubs.c index 079a867..279d76a 100644 --- a/core/cstubs.c +++ b/core/cstubs.c @@ -1,210 +1,57 @@ // C runtime stubs for freestanding Nim #include -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 - -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 diff --git a/core/fiber.nim b/core/fiber.nim index f5f48f6..47f70ce 100644 --- a/core/fiber.nim +++ b/core/fiber.nim @@ -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: diff --git a/core/fs/sfs.nim b/core/fs/sfs.nim index c9a6bf0..4f2b6a8 100644 --- a/core/fs/sfs.nim +++ b/core/fs/sfs.nim @@ -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.} diff --git a/core/include/stdio.h b/core/include/stdio.h index eb32652..eab13d7 100644 --- a/core/include/stdio.h +++ b/core/include/stdio.h @@ -1,27 +1,14 @@ -/* Minimal stdio.h stub for freestanding Nim */ #ifndef _STDIO_H #define _STDIO_H #include #include -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 diff --git a/core/include/stdlib.h b/core/include/stdlib.h index 923d898..46f17ca 100644 --- a/core/include/stdlib.h +++ b/core/include/stdlib.h @@ -1,24 +1,14 @@ -/* Minimal stdlib.h stub for freestanding Nim */ #ifndef _STDLIB_H #define _STDLIB_H #include +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 diff --git a/core/include/string.h b/core/include/string.h index 38a5bbf..b54640d 100644 --- a/core/include/string.h +++ b/core/include/string.h @@ -1,33 +1,17 @@ -/* Minimal string.h stub for freestanding Nim */ #ifndef _STRING_H #define _STRING_H #include -/* 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 diff --git a/core/kernel.nim b/core/kernel.nim index 95c3706..47c7771 100644 --- a/core/kernel.nim +++ b/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 diff --git a/core/panicoverride.nim b/core/panicoverride.nim index a4aa678..d6b2059 100644 --- a/core/panicoverride.nim +++ b/core/panicoverride.nim @@ -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.} diff --git a/hal/abi.zig b/hal/abi.zig index 2c29391..7717529 100644 --- a/hal/abi.zig +++ b/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"); +} diff --git a/hal/channel.zig b/hal/channel.zig index a4b4413..425ae27 100644 --- a/hal/channel.zig +++ b/hal/channel.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); } diff --git a/hal/entry_riscv.zig b/hal/entry_riscv.zig index 2c07497..a25c577 100644 --- a/hal/entry_riscv.zig +++ b/hal/entry_riscv.zig @@ -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; diff --git a/hal/initrd/bin/mksh b/hal/initrd/bin/mksh new file mode 100755 index 0000000..2c0fd6f Binary files /dev/null and b/hal/initrd/bin/mksh differ diff --git a/hal/main.zig b/hal/main.zig index 02679ac..0a9a7c9 100644 --- a/hal/main.zig +++ b/hal/main.zig @@ -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; } // ========================================================= diff --git a/hal/stubs.zig b/hal/stubs.zig index ede1202..567765b 100644 --- a/hal/stubs.zig +++ b/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; diff --git a/hal/uart.zig b/hal/uart.zig index bc8c75a..9df642b 100644 --- a/hal/uart.zig +++ b/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); -} diff --git a/hal/virtio_net.zig b/hal/virtio_net.zig index 4dab4af..0efe020 100644 --- a/hal/virtio_net.zig +++ b/hal/virtio_net.zig @@ -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' } } } diff --git a/hal/virtio_pci.zig b/hal/virtio_pci.zig index 6544483..4bfe171 100644 --- a/hal/virtio_pci.zig +++ b/hal/virtio_pci.zig @@ -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)).*; diff --git a/libs/membrane/clib.c b/libs/membrane/clib.c index 466c216..ae02f95 100644 --- a/libs/membrane/clib.c +++ b/libs/membrane/clib.c @@ -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); diff --git a/libs/membrane/external/lwip/src/core/dns.c b/libs/membrane/external/lwip/src/core/dns.c index 24b5b46..210343f 100644 --- a/libs/membrane/external/lwip/src/core/dns.c +++ b/libs/membrane/external/lwip/src/core/dns.c @@ -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; } } diff --git a/libs/membrane/external/lwip/src/core/netif.c b/libs/membrane/external/lwip/src/core/netif.c index d3a0677..c954a3d 100644 --- a/libs/membrane/external/lwip/src/core/netif.c +++ b/libs/membrane/external/lwip/src/core/netif.c @@ -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 && diff --git a/libs/membrane/include/lwipopts.h b/libs/membrane/include/lwipopts.h index e340072..c980802 100644 --- a/libs/membrane/include/lwipopts.h +++ b/libs/membrane/include/lwipopts.h @@ -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 diff --git a/libs/membrane/libc.nim b/libs/membrane/libc.nim index 5e88fb5..b7288ab 100644 --- a/libs/membrane/libc.nim +++ b/libs/membrane/libc.nim @@ -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.. 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.. 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 - diff --git a/libs/membrane/libc_shim.zig b/libs/membrane/libc_shim.zig index fcba099..c921c92 100644 --- a/libs/membrane/libc_shim.zig +++ b/libs/membrane/libc_shim.zig @@ -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 { diff --git a/libs/membrane/net_glue.nim b/libs/membrane/net_glue.nim index d76a49f..916d452 100644 --- a/libs/membrane/net_glue.nim +++ b/libs/membrane/net_glue.nim @@ -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) { diff --git a/run.sh b/run.sh index 8081954..964fdd6 100755 --- a/run.sh +++ b/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" diff --git a/vendor/mksh/build_nexus.sh b/vendor/mksh/build_nexus.sh old mode 100644 new mode 100755 diff --git a/vendor/mksh/stubs_mksh.c b/vendor/mksh/stubs_mksh.c index 3f9c25c..c251c0d 100644 --- a/vendor/mksh/stubs_mksh.c +++ b/vendor/mksh/stubs_mksh.c @@ -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; }