rumpk/libs/membrane/clib.c

479 lines
12 KiB
C

// SPDX-License-Identifier: LSL-1.0
// Copyright (c) 2026 Markus Maiwald
// Stewardship: Self Sovereign Society Foundation
#include <stddef.h>
#include <stdint.h>
#include <stdarg.h>
// Freestanding FILE stubs (Nim's system.nim references stderr)
struct _FILE { int dummy; };
typedef struct _FILE FILE;
static FILE _stdin_placeholder;
static FILE _stdout_placeholder;
static FILE _stderr_placeholder;
FILE *stdin = &_stdin_placeholder;
FILE *stdout = &_stdout_placeholder;
FILE *stderr = &_stderr_placeholder;
// Types needed for stubs
typedef int32_t pid_t;
typedef int32_t uid_t;
typedef int32_t gid_t;
typedef int64_t off_t;
typedef int32_t mode_t;
struct stat {
int st_mode;
};
int errno = 0;
void* memset(void* s, int c, size_t n);
// Basic memory stubs (Bump Allocator) - USERLAND ONLY
// Kernel gets malloc/free/calloc from stubs.zig
#ifdef RUMPK_USER
static uint8_t heap[4 * 1024 * 1024]; // 4MB Heap
static size_t heap_idx = 0;
void* malloc(size_t size) {
if (size == 0) return NULL;
size = (size + 7) & ~7; // Align to 8 bytes
if (heap_idx + size > sizeof(heap)) return NULL;
void* ptr = &heap[heap_idx];
heap_idx += size;
return ptr;
}
void free(void* ptr) {
(void)ptr;
}
void* calloc(size_t nmemb, size_t size) {
size_t total = nmemb * size;
void* ptr = malloc(total);
if (ptr) memset(ptr, 0, total);
return ptr;
}
#endif // RUMPK_USER
// Forward declarations
int write(int fd, const void *buf, size_t count);
int read(int fd, void *buf, size_t count);
int open(const char *pathname, int flags, ...);
int close(int fd);
void* memset(void* s, int c, size_t n);
// Basic memory stubs
// Basic memory stubs (Bump Allocator)
// LwIP Panic Handler (for Membrane stack)
extern void console_write(const void* p, size_t len);
size_t strlen(const char* s) {
size_t i = 0;
while(s[i]) i++;
return i;
}
// nexus_lwip_panic moved to sys_arch.c to avoid duplicate symbols
int strncmp(const char *s1, const char *s2, size_t n) {
for (size_t i = 0; i < n; i++) {
if (s1[i] != s2[i]) return (unsigned char)s1[i] - (unsigned char)s2[i];
if (s1[i] == 0) return 0;
}
return 0;
}
int atoi(const char* nptr) { return 0; }
double strtod(const char* nptr, char** endptr) {
const char *p = nptr;
double result = 0.0;
double sign = 1.0;
while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++;
if (*p == '-') { sign = -1.0; p++; }
else if (*p == '+') { p++; }
while (*p >= '0' && *p <= '9') {
result = result * 10.0 + (*p - '0');
p++;
}
if (*p == '.') {
double frac = 0.1;
p++;
while (*p >= '0' && *p <= '9') {
result += (*p - '0') * frac;
frac *= 0.1;
p++;
}
}
if (*p == 'e' || *p == 'E') {
p++;
int exp_sign = 1, exp_val = 0;
if (*p == '-') { exp_sign = -1; p++; }
else if (*p == '+') { p++; }
while (*p >= '0' && *p <= '9') {
exp_val = exp_val * 10 + (*p - '0');
p++;
}
double m = 1.0;
for (int i = 0; i < exp_val; i++)
m = exp_sign > 0 ? m * 10.0 : m * 0.1;
result *= m;
}
if (endptr) *endptr = (char*)p;
return sign * result;
}
double pow(double x, double y) { return 0.0; }
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);
extern uint64_t hal_get_time_ns(void);
extern void hal_console_write(const void* p, size_t len);
extern void hal_panic(const char* msg);
uint64_t syscall_get_time_ns(void) { return hal_get_time_ns(); }
void syscall_panic(void) { while(1); }
#endif
// Support for Nim system.nim
#ifndef OMIT_EXIT
void exit(int status) {
#ifdef RUMPK_KERNEL
while(1);
#else
syscall(1, (long)status, 0, 0); // SYS_EXIT
while(1);
#endif
}
void abort(void) {
exit(1);
}
#endif
size_t fwrite(const void* ptr, size_t size, size_t nmemb, void* stream) {
#ifdef RUMPK_KERNEL
hal_console_write(ptr, size * nmemb);
#else
write(1, ptr, size * nmemb); // Forward to stdout
#endif
return nmemb;
}
int fflush(void* stream) {
return 0;
}
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;
register long _a0 asm("a0") = a0;
register long _a1 asm("a1") = a1;
register long _a2 asm("a2") = a2;
asm volatile("ecall"
: "+r"(_a0)
: "r"(a7), "r"(_a1), "r"(_a2)
: "memory");
res = _a0;
#else
res = -1;
#endif
return res;
#endif
}
// IO stubs (Real Syscalls)
int write(int fd, const void *buf, size_t count) {
// 0x204 = SYS_WRITE
return (int)syscall(0x204, fd, (long)buf, count);
}
int read(int fd, void *buf, size_t count) {
// 0x203 = SYS_READ
return (int)syscall(0x203, fd, (long)buf, count);
}
int open(const char *pathname, int flags, ...) {
// 0x200 = SYS_OPEN
return (int)syscall(0x200, (long)pathname, flags, 0);
}
int close(int fd) {
// 0x201 = SYS_CLOSE
return (int)syscall(0x201, fd, 0, 0);
}
int execv(const char *path, char *const argv[]) {
// 0x600 = KEXEC (Replace current fiber/process)
// Note: argv is currently ignored by kernel kexec, it just runs the binary
return (int)syscall(0x600, (long)path, 0, 0);
}
// Robust Formatter
typedef struct {
char *buf;
size_t size;
size_t pos;
} OutCtx;
static void out_char(OutCtx *ctx, char c) {
if (ctx->buf && ctx->size > 0 && ctx->pos < ctx->size - 1) {
ctx->buf[ctx->pos] = c;
}
ctx->pos++;
}
static void out_num(OutCtx *ctx, unsigned long n, int base, int width, int zeropad, int upper) {
char buf[64];
const char *digits = upper ? "0123456789ABCDEF" : "0123456789abcdef";
int i = 0;
if (n == 0) buf[i++] = '0';
else while (n > 0) { buf[i++] = digits[n % base]; n /= base; }
while (i < width) buf[i++] = (zeropad ? '0' : ' ');
while (i > 0) out_char(ctx, buf[--i]);
}
static int vformat(OutCtx *ctx, const char *fmt, va_list ap) {
if (!fmt) return 0;
const char *p = fmt;
ctx->pos = 0;
while (*p) {
if (*p != '%') { out_char(ctx, *p++); continue; }
p++; // skip %
if (!*p) break;
int zeropad = 0, width = 0, l_mod = 0, h_mod = 0;
if (*p == '0') { zeropad = 1; p++; }
while (*p >= '0' && *p <= '9') { width = width * 10 + (*p - '0'); p++; }
while (*p == 'l') { l_mod++; p++; }
if (*p == 'h') { h_mod = 1; p++; }
if (!*p) break;
switch (*p) {
case 's': {
const char *s = va_arg(ap, const char *);
if (!s) s = "(null)";
while (*s) out_char(ctx, *s++);
break;
}
case 'c': out_char(ctx, (char)va_arg(ap, int)); break;
case 'd':
case 'i': {
long n = (l_mod >= 1) ? va_arg(ap, long) : va_arg(ap, int);
unsigned long un;
if (n < 0) { out_char(ctx, '-'); un = 0UL - (unsigned long)n; }
else un = (unsigned long)n;
out_num(ctx, un, 10, width, zeropad, 0);
break;
}
case 'u': {
unsigned long n = (l_mod >= 1) ? va_arg(ap, unsigned long) : va_arg(ap, unsigned int);
out_num(ctx, n, 10, width, zeropad, 0);
break;
}
case 'p':
case 'x':
case 'X': {
unsigned long n;
if (*p == 'p') n = (unsigned long)va_arg(ap, void *);
else n = (l_mod >= 1) ? va_arg(ap, unsigned long) : va_arg(ap, unsigned int);
out_num(ctx, n, 16, width, zeropad, (*p == 'X'));
break;
}
case '%': out_char(ctx, '%'); break;
default: out_char(ctx, '%'); out_char(ctx, *p); break;
}
p++;
}
if (ctx->buf && ctx->size > 0) {
size_t end = (ctx->pos < ctx->size) ? ctx->pos : ctx->size - 1;
ctx->buf[end] = '\0';
}
return (int)ctx->pos;
}
int vsnprintf(char *str, size_t size, const char *format, va_list ap) {
OutCtx ctx = { .buf = str, .size = size, .pos = 0 };
return vformat(&ctx, format, ap);
}
int snprintf(char *str, size_t size, const char *format, ...) {
va_list ap; va_start(ap, format);
int res = vsnprintf(str, size, format, ap);
va_end(ap);
return res;
}
int sprintf(char *str, const char *format, ...) {
va_list ap; va_start(ap, format);
int res = vsnprintf(str, (size_t)-1, format, ap);
va_end(ap);
return res;
}
int vprintf(const char *format, va_list ap) {
char tmp[1024];
int n = vsnprintf(tmp, sizeof(tmp), format, ap);
if (n > 0) console_write(tmp, (n < (int)sizeof(tmp)) ? (size_t)n : sizeof(tmp)-1);
return n;
}
int printf(const char *format, ...) {
va_list ap; va_start(ap, format);
int res = vprintf(format, ap);
va_end(ap);
return res;
}
// REDUNDANT REMOVED
// System stubs
extern void nexus_yield(void);
// void exit(int status) { while(1) { nexus_yield(); } } // Moved to libc_shim.zig
void (*signal(int sig, void (*func)(int)))(int) { return NULL; }
// LwIP Time - moved to sys_arch.c
// uint32_t sys_now() { return 0; }
// RNG for LwIP (Project Prometheus)
int libc_rand(void) {
static unsigned long next = 1;
next = next * 1103515245 + 12345;
return (unsigned int)(next/65536) % 32768;
}
// Utils
uint16_t htons(uint16_t h) {
return (h << 8) | (h >> 8);
}
void* memcpy(void* dest, const void* src, size_t n) {
uint8_t* d = dest;
const uint8_t* s = src;
for (size_t i = 0; i < n; i++) d[i] = s[i];
return dest;
}
void* memset(void* s, int c, size_t n) {
uint8_t* p = s;
for (size_t i = 0; i < n; i++) p[i] = (uint8_t)c;
return s;
}
int memcmp(const void *s1, const void *s2, size_t n) {
const unsigned char *p1 = (const unsigned char *)s1;
const unsigned char *p2 = (const unsigned char *)s2;
for (size_t i = 0; i < n; i++) {
if (p1[i] != p2[i]) return p1[i] - p2[i];
}
return 0;
}
#ifdef RUMPK_USER
void *memchr(const void *s, int c, size_t n) {
const unsigned char *p = (const unsigned char *)s;
for (size_t i = 0; i < n; i++) {
if (p[i] == (unsigned char)c) return (void *)(p + i);
}
return (void *)0;
}
#endif
void *memmove(void *dest, const void *src, size_t n) {
char *d = (char *)dest;
const char *s = (const char *)src;
if (d < s) {
for (size_t i = 0; i < n; i++) d[i] = s[i];
} else {
for (size_t i = n; i > 0; i--) d[i - 1] = s[i - 1];
}
return dest;
}
char *strchr(const char *s, int c) {
while (*s != (char)c) {
if (!*s++) return NULL;
}
return (char *)s;
}
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 *(const unsigned char*)s1 - *(const unsigned char*)s2;
}
size_t strspn(const char *s, const char *accept) {
const char *p = s;
const char *a;
while (*p) {
for (a = accept; *a; a++) {
if (*p == *a) break;
}
if (*a == '\0') return p - s;
p++;
}
return p - s;
}
size_t strcspn(const char *s, const char *reject) {
const char *p = s;
const char *r;
while (*p) {
for (r = reject; *r; r++) {
if (*p == *r) return p - s;
}
p++;
}
return p - s;
}
uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) {
static const uint32_t rtable[16] = {
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c,
};
const uint8_t *data = (const uint8_t *)buffer;
for (size_t i = 0; i < size; i++) {
crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 0)) & 0xf];
crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 4)) & 0xf];
}
return crc;
}
#ifdef RUMPK_KERNEL
void console_write(const void* p, size_t len) {
hal_console_write(p, len);
}
#else
void console_write(const void* p, size_t len) {
write(1, p, len);
}
#endif
void ion_egress_to_port(uint16_t port, void* pkt);
int execve(const char *pathname, char *const argv[], char *const envp[]) { return -1; }
pid_t fork(void) { return -1; }
pid_t wait(int *status) { return -1; }