*.img
*.log
*.elf
+*.a
# ISO staging: keep config, ignore generated kernel binaries
iso/boot/*.bin
$(MKINITRD): tools/mkinitrd.c
@gcc tools/mkinitrd.c -o $(MKINITRD)
+ULIBC_DIR := user/ulibc
+ULIBC_LIB := $(ULIBC_DIR)/libulibc.a
+
+$(ULIBC_LIB):
+ @$(MAKE) -C $(ULIBC_DIR) --no-print-directory
+
$(USER_ELF): user/init.c user/linker.ld
@i686-elf-gcc -m32 -I include -ffreestanding -fno-pie -no-pie -nostdlib -Wl,-T,user/linker.ld -o $(USER_ELF) user/init.c user/errno.c
--- /dev/null
+# ulibc — Minimal C library for AdrOS userspace
+CC := i686-elf-gcc
+AS := i686-elf-as
+AR := i686-elf-ar
+
+CFLAGS := -m32 -ffreestanding -fno-pie -no-pie -nostdlib -O2 -Wall -Wextra -Iinclude
+ASFLAGS := --32
+
+SRC_C := $(wildcard src/*.c)
+SRC_S := $(wildcard src/*.S)
+OBJ := $(SRC_C:.c=.o) $(SRC_S:.S=.o)
+
+all: libulibc.a
+
+libulibc.a: $(OBJ)
+ @$(AR) rcs $@ $^
+ @echo " AR $@"
+
+src/%.o: src/%.c
+ @$(CC) $(CFLAGS) -c $< -o $@
+ @echo " CC $<"
+
+src/%.o: src/%.S
+ @$(AS) $(ASFLAGS) $< -o $@
+ @echo " AS $<"
+
+clean:
+ rm -f src/*.o libulibc.a
+
+.PHONY: all clean
--- /dev/null
+#ifndef ULIBC_ERRNO_H
+#define ULIBC_ERRNO_H
+
+extern int errno;
+
+#define EPERM 1
+#define ENOENT 2
+#define ESRCH 3
+#define EINTR 4
+#define EIO 5
+#define ENXIO 6
+#define EBADF 9
+#define ECHILD 10
+#define EAGAIN 11
+#define ENOMEM 12
+#define EACCES 13
+#define EFAULT 14
+#define EEXIST 17
+#define ENOTDIR 20
+#define EISDIR 21
+#define EINVAL 22
+#define EMFILE 24
+#define ENOSPC 28
+#define EPIPE 32
+#define ENOSYS 38
+#define ENOTEMPTY 39
+
+/* Convert raw syscall return to errno-style */
+static inline int __syscall_ret(int r) {
+ if (r < 0) {
+ errno = -r;
+ return -1;
+ }
+ return r;
+}
+
+#endif
--- /dev/null
+#ifndef ULIBC_STDIO_H
+#define ULIBC_STDIO_H
+
+#include <stddef.h>
+#include <stdarg.h>
+
+int putchar(int c);
+int puts(const char* s);
+int printf(const char* fmt, ...) __attribute__((format(printf, 1, 2)));
+int vprintf(const char* fmt, va_list ap);
+int snprintf(char* buf, size_t size, const char* fmt, ...) __attribute__((format(printf, 3, 4)));
+int vsnprintf(char* buf, size_t size, const char* fmt, va_list ap);
+
+#endif
--- /dev/null
+#ifndef ULIBC_STDLIB_H
+#define ULIBC_STDLIB_H
+
+#include <stddef.h>
+
+void* malloc(size_t size);
+void free(void* ptr);
+void* calloc(size_t nmemb, size_t size);
+void* realloc(void* ptr, size_t size);
+
+int atoi(const char* s);
+void exit(int status) __attribute__((noreturn));
+
+#ifndef NULL
+#define NULL ((void*)0)
+#endif
+
+#endif
--- /dev/null
+#ifndef ULIBC_STRING_H
+#define ULIBC_STRING_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+void* memcpy(void* dst, const void* src, size_t n);
+void* memset(void* s, int c, size_t n);
+void* memmove(void* dst, const void* src, size_t n);
+int memcmp(const void* a, const void* b, size_t n);
+size_t strlen(const char* s);
+char* strcpy(char* dst, const char* src);
+char* strncpy(char* dst, const char* src, size_t n);
+int strcmp(const char* a, const char* b);
+int strncmp(const char* a, const char* b, size_t n);
+char* strchr(const char* s, int c);
+char* strrchr(const char* s, int c);
+char* strcat(char* dst, const char* src);
+
+#endif
--- /dev/null
+#ifndef ULIBC_SYSCALL_H
+#define ULIBC_SYSCALL_H
+
+#include <stdint.h>
+
+enum {
+ SYS_WRITE = 1,
+ SYS_EXIT = 2,
+ SYS_GETPID = 3,
+ SYS_OPEN = 4,
+ SYS_READ = 5,
+ SYS_CLOSE = 6,
+ SYS_WAITPID = 7,
+ SYS_LSEEK = 9,
+ SYS_FSTAT = 10,
+ SYS_STAT = 11,
+ SYS_DUP = 12,
+ SYS_DUP2 = 13,
+ SYS_PIPE = 14,
+ SYS_EXECVE = 15,
+ SYS_FORK = 16,
+ SYS_GETPPID = 17,
+ SYS_POLL = 18,
+ SYS_KILL = 19,
+ SYS_SELECT = 20,
+ SYS_IOCTL = 21,
+ SYS_SETSID = 22,
+ SYS_SETPGID = 23,
+ SYS_GETPGRP = 24,
+ SYS_SIGACTION = 25,
+ SYS_SIGPROCMASK = 26,
+ SYS_SIGRETURN = 27,
+ SYS_MKDIR = 28,
+ SYS_UNLINK = 29,
+ SYS_GETDENTS = 30,
+ SYS_FCNTL = 31,
+ SYS_CHDIR = 32,
+ SYS_GETCWD = 33,
+ SYS_PIPE2 = 34,
+ SYS_DUP3 = 35,
+ SYS_OPENAT = 36,
+ SYS_FSTATAT = 37,
+ SYS_UNLINKAT = 38,
+ SYS_RENAME = 39,
+ SYS_RMDIR = 40,
+ SYS_BRK = 41,
+ SYS_NANOSLEEP = 42,
+ SYS_CLOCK_GETTIME = 43,
+ SYS_MMAP = 44,
+ SYS_MUNMAP = 45,
+};
+
+/* Raw syscall wrappers — up to 5 args via INT 0x80 */
+static inline int _syscall0(int nr) {
+ int ret;
+ __asm__ volatile("int $0x80" : "=a"(ret) : "a"(nr) : "memory");
+ return ret;
+}
+
+static inline int _syscall1(int nr, int a1) {
+ int ret;
+ __asm__ volatile("int $0x80" : "=a"(ret) : "a"(nr), "b"(a1) : "memory");
+ return ret;
+}
+
+static inline int _syscall2(int nr, int a1, int a2) {
+ int ret;
+ __asm__ volatile("int $0x80" : "=a"(ret) : "a"(nr), "b"(a1), "c"(a2) : "memory");
+ return ret;
+}
+
+static inline int _syscall3(int nr, int a1, int a2, int a3) {
+ int ret;
+ __asm__ volatile("int $0x80" : "=a"(ret) : "a"(nr), "b"(a1), "c"(a2), "d"(a3) : "memory");
+ return ret;
+}
+
+static inline int _syscall4(int nr, int a1, int a2, int a3, int a4) {
+ int ret;
+ __asm__ volatile("int $0x80" : "=a"(ret) : "a"(nr), "b"(a1), "c"(a2), "d"(a3), "S"(a4) : "memory");
+ return ret;
+}
+
+static inline int _syscall5(int nr, int a1, int a2, int a3, int a4, int a5) {
+ int ret;
+ __asm__ volatile("int $0x80" : "=a"(ret) : "a"(nr), "b"(a1), "c"(a2), "d"(a3), "S"(a4), "D"(a5) : "memory");
+ return ret;
+}
+
+#endif
--- /dev/null
+#ifndef ULIBC_UNISTD_H
+#define ULIBC_UNISTD_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+
+#define STDIN_FILENO 0
+#define STDOUT_FILENO 1
+#define STDERR_FILENO 2
+
+int read(int fd, void* buf, size_t count);
+int write(int fd, const void* buf, size_t count);
+int open(const char* path, int flags);
+int close(int fd);
+int lseek(int fd, int offset, int whence);
+int dup(int oldfd);
+int dup2(int oldfd, int newfd);
+int pipe(int fds[2]);
+int fork(void);
+int execve(const char* path, const char* const* argv, const char* const* envp);
+int getpid(void);
+int getppid(void);
+int chdir(const char* path);
+int getcwd(char* buf, size_t size);
+int mkdir(const char* path);
+int unlink(const char* path);
+int rmdir(const char* path);
+int setsid(void);
+int setpgid(int pid, int pgid);
+int getpgrp(void);
+void* brk(void* addr);
+
+void _exit(int status) __attribute__((noreturn));
+
+#endif
--- /dev/null
+/*
+ * ulibc crt0 — C runtime startup for AdrOS userspace
+ * Entry point: _start → main() → exit()
+ */
+.section .text
+.global _start
+.extern main
+.extern exit
+
+_start:
+ /* Set up user data segments */
+ mov $0x23, %ax
+ mov %ax, %ds
+ mov %ax, %es
+ mov %ax, %fs
+ mov %ax, %gs
+
+ /* Call main() — no argc/argv yet */
+ push $0 /* envp = NULL */
+ push $0 /* argv = NULL */
+ push $0 /* argc = 0 */
+ call main
+ add $12, %esp
+
+ /* exit(main return value) */
+ push %eax
+ call exit
+
+ /* Should never reach here */
+1: jmp 1b
+
+.section .note.GNU-stack,"",@progbits
--- /dev/null
+int errno = 0;
--- /dev/null
+#include "stdio.h"
+#include "unistd.h"
+#include "string.h"
+#include <stdarg.h>
+
+int putchar(int c) {
+ char ch = (char)c;
+ write(STDOUT_FILENO, &ch, 1);
+ return c;
+}
+
+int puts(const char* s) {
+ int len = (int)strlen(s);
+ write(STDOUT_FILENO, s, (size_t)len);
+ write(STDOUT_FILENO, "\n", 1);
+ return len + 1;
+}
+
+/* Minimal vsnprintf supporting: %d %i %u %x %X %s %c %p %% */
+int vsnprintf(char* buf, size_t size, const char* fmt, va_list ap) {
+ size_t pos = 0;
+
+#define PUTC(c) do { if (pos < size - 1) buf[pos] = (c); pos++; } while(0)
+
+ if (size == 0) {
+ /* Just count characters */
+ while (*fmt) { pos++; fmt++; }
+ return (int)pos;
+ }
+
+ while (*fmt) {
+ if (*fmt != '%') {
+ PUTC(*fmt);
+ fmt++;
+ continue;
+ }
+ fmt++; /* skip '%' */
+
+ /* Flags */
+ int pad_zero = 0;
+ int left_align = 0;
+ while (*fmt == '0' || *fmt == '-') {
+ if (*fmt == '0') pad_zero = 1;
+ if (*fmt == '-') left_align = 1;
+ fmt++;
+ }
+ if (left_align) pad_zero = 0;
+
+ /* Width */
+ int width = 0;
+ while (*fmt >= '0' && *fmt <= '9') {
+ width = width * 10 + (*fmt - '0');
+ fmt++;
+ }
+
+ /* Specifier */
+ char tmp[32];
+ int tmplen = 0;
+ const char* str = 0;
+
+ switch (*fmt) {
+ case 'd':
+ case 'i': {
+ int v = va_arg(ap, int);
+ int neg = 0;
+ unsigned int uv;
+ if (v < 0) { neg = 1; uv = (unsigned int)(-(v + 1)) + 1; }
+ else { uv = (unsigned int)v; }
+ if (uv == 0) { tmp[tmplen++] = '0'; }
+ else { while (uv) { tmp[tmplen++] = (char)('0' + uv % 10); uv /= 10; } }
+ if (neg) tmp[tmplen++] = '-';
+ /* reverse */
+ for (int i = 0; i < tmplen / 2; i++) {
+ char t = tmp[i]; tmp[i] = tmp[tmplen-1-i]; tmp[tmplen-1-i] = t;
+ }
+ str = tmp;
+ break;
+ }
+ case 'u': {
+ unsigned int v = va_arg(ap, unsigned int);
+ if (v == 0) { tmp[tmplen++] = '0'; }
+ else { while (v) { tmp[tmplen++] = (char)('0' + v % 10); v /= 10; } }
+ for (int i = 0; i < tmplen / 2; i++) {
+ char t = tmp[i]; tmp[i] = tmp[tmplen-1-i]; tmp[tmplen-1-i] = t;
+ }
+ str = tmp;
+ break;
+ }
+ case 'x':
+ case 'X':
+ case 'p': {
+ const char* hex = (*fmt == 'X') ? "0123456789ABCDEF" : "0123456789abcdef";
+ unsigned int v;
+ if (*fmt == 'p') {
+ v = (unsigned int)(uintptr_t)va_arg(ap, void*);
+ tmp[tmplen++] = '0';
+ tmp[tmplen++] = 'x';
+ } else {
+ v = va_arg(ap, unsigned int);
+ }
+ int start = tmplen;
+ if (v == 0) { tmp[tmplen++] = '0'; }
+ else { while (v) { tmp[tmplen++] = hex[v & 0xF]; v >>= 4; } }
+ /* reverse the hex digits only */
+ for (int i = start; i < start + (tmplen - start) / 2; i++) {
+ int j = start + (tmplen - start) - 1 - (i - start);
+ char t = tmp[i]; tmp[i] = tmp[j]; tmp[j] = t;
+ }
+ str = tmp;
+ break;
+ }
+ case 's': {
+ str = va_arg(ap, const char*);
+ if (!str) str = "(null)";
+ tmplen = (int)strlen(str);
+ break;
+ }
+ case 'c': {
+ tmp[0] = (char)va_arg(ap, int);
+ tmplen = 1;
+ str = tmp;
+ break;
+ }
+ case '%':
+ PUTC('%');
+ fmt++;
+ continue;
+ case '\0':
+ goto done;
+ default:
+ PUTC('%');
+ PUTC(*fmt);
+ fmt++;
+ continue;
+ }
+ fmt++;
+
+ if (str && tmplen == 0) tmplen = (int)strlen(str);
+
+ /* Padding */
+ int pad = width - tmplen;
+ if (!left_align && pad > 0) {
+ char pc = pad_zero ? '0' : ' ';
+ for (int i = 0; i < pad; i++) PUTC(pc);
+ }
+ for (int i = 0; i < tmplen; i++) PUTC(str[i]);
+ if (left_align && pad > 0) {
+ for (int i = 0; i < pad; i++) PUTC(' ');
+ }
+ }
+
+done:
+ if (pos < size) buf[pos] = '\0';
+ else if (size > 0) buf[size - 1] = '\0';
+ return (int)pos;
+
+#undef PUTC
+}
+
+int snprintf(char* buf, size_t size, const char* fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ int r = vsnprintf(buf, size, fmt, ap);
+ va_end(ap);
+ return r;
+}
+
+int vprintf(const char* fmt, va_list ap) {
+ char buf[1024];
+ int n = vsnprintf(buf, sizeof(buf), fmt, ap);
+ if (n > 0) {
+ int w = n;
+ if (w > (int)(sizeof(buf) - 1)) w = (int)(sizeof(buf) - 1);
+ write(STDOUT_FILENO, buf, (size_t)w);
+ }
+ return n;
+}
+
+int printf(const char* fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ int r = vprintf(fmt, ap);
+ va_end(ap);
+ return r;
+}
--- /dev/null
+#include "stdlib.h"
+#include "unistd.h"
+#include "string.h"
+
+/*
+ * Minimal bump allocator using brk() syscall.
+ * No free() support yet — memory is only reclaimed on process exit.
+ * A proper free-list allocator can be added later.
+ */
+static void* heap_base = 0;
+static void* heap_end = 0;
+
+void* malloc(size_t size) {
+ if (size == 0) return (void*)0;
+
+ /* Align to 8 bytes */
+ size = (size + 7) & ~(size_t)7;
+
+ if (!heap_base) {
+ heap_base = brk(0);
+ heap_end = heap_base;
+ }
+
+ void* old_end = heap_end;
+ void* new_end = (void*)((char*)heap_end + size);
+ void* result = brk(new_end);
+
+ if ((unsigned int)result < (unsigned int)new_end) {
+ return (void*)0; /* OOM */
+ }
+
+ heap_end = new_end;
+ return old_end;
+}
+
+void free(void* ptr) {
+ /* Bump allocator: no-op for now */
+ (void)ptr;
+}
+
+void* calloc(size_t nmemb, size_t size) {
+ size_t total = nmemb * size;
+ if (nmemb != 0 && total / nmemb != size) return (void*)0;
+ void* p = malloc(total);
+ if (p) memset(p, 0, total);
+ return p;
+}
+
+void* realloc(void* ptr, size_t size) {
+ if (!ptr) return malloc(size);
+ if (size == 0) { free(ptr); return (void*)0; }
+ /* Bump allocator: just allocate new and copy.
+ * We don't know the old size, so copy 'size' bytes
+ * (caller must ensure old block >= size). */
+ void* new_ptr = malloc(size);
+ if (new_ptr) memcpy(new_ptr, ptr, size);
+ return new_ptr;
+}
+
+int atoi(const char* s) {
+ int n = 0;
+ int neg = 0;
+ while (*s == ' ' || *s == '\t') s++;
+ if (*s == '-') { neg = 1; s++; }
+ else if (*s == '+') { s++; }
+ while (*s >= '0' && *s <= '9') {
+ n = n * 10 + (*s - '0');
+ s++;
+ }
+ return neg ? -n : n;
+}
+
+void exit(int status) {
+ _exit(status);
+}
--- /dev/null
+#include "string.h"
+
+void* memcpy(void* dst, const void* src, size_t n) {
+ uint8_t* d = (uint8_t*)dst;
+ const uint8_t* s = (const uint8_t*)src;
+ for (size_t i = 0; i < n; i++) d[i] = s[i];
+ return dst;
+}
+
+void* memset(void* s, int c, size_t n) {
+ uint8_t* p = (uint8_t*)s;
+ for (size_t i = 0; i < n; i++) p[i] = (uint8_t)c;
+ return s;
+}
+
+void* memmove(void* dst, const void* src, size_t n) {
+ uint8_t* d = (uint8_t*)dst;
+ const uint8_t* s = (const uint8_t*)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 dst;
+}
+
+int memcmp(const void* a, const void* b, size_t n) {
+ const uint8_t* x = (const uint8_t*)a;
+ const uint8_t* y = (const uint8_t*)b;
+ for (size_t i = 0; i < n; i++) {
+ if (x[i] != y[i]) return (int)x[i] - (int)y[i];
+ }
+ return 0;
+}
+
+size_t strlen(const char* s) {
+ size_t n = 0;
+ while (s[n]) n++;
+ return n;
+}
+
+char* strcpy(char* dst, const char* src) {
+ size_t i = 0;
+ while (src[i]) { dst[i] = src[i]; i++; }
+ dst[i] = 0;
+ return dst;
+}
+
+char* strncpy(char* dst, const char* src, size_t n) {
+ size_t i = 0;
+ while (i < n && src[i]) { dst[i] = src[i]; i++; }
+ while (i < n) { dst[i] = 0; i++; }
+ return dst;
+}
+
+int strcmp(const char* a, const char* b) {
+ while (*a && *a == *b) { a++; b++; }
+ return (int)(unsigned char)*a - (int)(unsigned char)*b;
+}
+
+int strncmp(const char* a, const char* b, size_t n) {
+ for (size_t i = 0; i < n; i++) {
+ if (a[i] != b[i]) return (int)(unsigned char)a[i] - (int)(unsigned char)b[i];
+ if (a[i] == 0) break;
+ }
+ return 0;
+}
+
+char* strchr(const char* s, int c) {
+ while (*s) {
+ if (*s == (char)c) return (char*)s;
+ s++;
+ }
+ return (c == 0) ? (char*)s : (void*)0;
+}
+
+char* strrchr(const char* s, int c) {
+ const char* last = (void*)0;
+ while (*s) {
+ if (*s == (char)c) last = s;
+ s++;
+ }
+ if (c == 0) return (char*)s;
+ return (char*)last;
+}
+
+char* strcat(char* dst, const char* src) {
+ char* p = dst;
+ while (*p) p++;
+ while (*src) *p++ = *src++;
+ *p = 0;
+ return dst;
+}
--- /dev/null
+#include "unistd.h"
+#include "syscall.h"
+#include "errno.h"
+
+int read(int fd, void* buf, size_t count) {
+ return __syscall_ret(_syscall3(SYS_READ, fd, (int)buf, (int)count));
+}
+
+int write(int fd, const void* buf, size_t count) {
+ return __syscall_ret(_syscall3(SYS_WRITE, fd, (int)buf, (int)count));
+}
+
+int open(const char* path, int flags) {
+ return __syscall_ret(_syscall2(SYS_OPEN, (int)path, flags));
+}
+
+int close(int fd) {
+ return __syscall_ret(_syscall1(SYS_CLOSE, fd));
+}
+
+int lseek(int fd, int offset, int whence) {
+ return __syscall_ret(_syscall3(SYS_LSEEK, fd, offset, whence));
+}
+
+int dup(int oldfd) {
+ return __syscall_ret(_syscall1(SYS_DUP, oldfd));
+}
+
+int dup2(int oldfd, int newfd) {
+ return __syscall_ret(_syscall2(SYS_DUP2, oldfd, newfd));
+}
+
+int pipe(int fds[2]) {
+ return __syscall_ret(_syscall1(SYS_PIPE, (int)fds));
+}
+
+int fork(void) {
+ return __syscall_ret(_syscall0(SYS_FORK));
+}
+
+int execve(const char* path, const char* const* argv, const char* const* envp) {
+ return __syscall_ret(_syscall3(SYS_EXECVE, (int)path, (int)argv, (int)envp));
+}
+
+int getpid(void) {
+ return _syscall0(SYS_GETPID);
+}
+
+int getppid(void) {
+ return _syscall0(SYS_GETPPID);
+}
+
+int chdir(const char* path) {
+ return __syscall_ret(_syscall1(SYS_CHDIR, (int)path));
+}
+
+int getcwd(char* buf, size_t size) {
+ return __syscall_ret(_syscall2(SYS_GETCWD, (int)buf, (int)size));
+}
+
+int mkdir(const char* path) {
+ return __syscall_ret(_syscall1(SYS_MKDIR, (int)path));
+}
+
+int unlink(const char* path) {
+ return __syscall_ret(_syscall1(SYS_UNLINK, (int)path));
+}
+
+int rmdir(const char* path) {
+ return __syscall_ret(_syscall1(SYS_RMDIR, (int)path));
+}
+
+int setsid(void) {
+ return __syscall_ret(_syscall0(SYS_SETSID));
+}
+
+int setpgid(int pid, int pgid) {
+ return __syscall_ret(_syscall2(SYS_SETPGID, pid, pgid));
+}
+
+int getpgrp(void) {
+ return __syscall_ret(_syscall0(SYS_GETPGRP));
+}
+
+void* brk(void* addr) {
+ return (void*)_syscall1(SYS_BRK, (int)addr);
+}
+
+void _exit(int status) {
+ _syscall1(SYS_EXIT, status);
+ for (;;) __asm__ volatile("hlt");
+}