# ISO staging: keep config, ignore generated kernel binaries
iso/boot/*.bin
+iso/bin/
# Static analysis artifacts
compile_commands.json
SYSCALL_SHUTDOWN = 133,
SYSCALL_GETPEERNAME = 134,
SYSCALL_GETSOCKNAME = 135,
+ SYSCALL_UNAME = 136,
};
#endif
return;
}
+ if (syscall_no == SYSCALL_UNAME) {
+ /* struct utsname: 5 fields of 65 bytes each = 325 bytes */
+ void* user_buf = (void*)sc_arg0(regs);
+ if (!user_buf) { sc_ret(regs) = (uint32_t)-EFAULT; return; }
+ if (user_range_ok(user_buf, 325) == 0) { sc_ret(regs) = (uint32_t)-EFAULT; return; }
+
+ struct {
+ char sysname[65];
+ char nodename[65];
+ char release[65];
+ char version[65];
+ char machine[65];
+ } uts;
+ memset(&uts, 0, sizeof(uts));
+ strcpy(uts.sysname, "AdrOS");
+ strcpy(uts.nodename, "adros");
+ strcpy(uts.release, "1.0.0");
+ strcpy(uts.version, "AdrOS 1.0.0 POSIX");
+ strcpy(uts.machine, "i686");
+
+ if (copy_to_user(user_buf, &uts, sizeof(uts)) < 0) {
+ sc_ret(regs) = (uint32_t)-EFAULT; return;
+ }
+ sc_ret(regs) = 0;
+ return;
+ }
+
sc_ret(regs) = (uint32_t)-ENOSYS;
}
{"gettimeofday" "\\[init\\] gettimeofday OK"}
{"mprotect" "\\[init\\] mprotect OK"}
{"getrlimit/setrlimit" "\\[init\\] getrlimit/setrlimit OK"}
+ {"uname" "\\[init\\] uname OK"}
{"LZ4 Frame decomp" "\\[INITRD\\] LZ4"}
}
SYSCALL_MPROTECT = 128,
SYSCALL_GETRLIMIT = 129,
SYSCALL_SETRLIMIT = 130,
+ SYSCALL_UNAME = 136,
};
enum {
return __syscall_fix(ret);
}
+struct utsname {
+ char sysname[65];
+ char nodename[65];
+ char release[65];
+ char version[65];
+ char machine[65];
+};
+
+static int sys_uname(struct utsname* buf) {
+ int ret;
+ __asm__ volatile("int $0x80" : "=a"(ret) : "a"(SYSCALL_UNAME), "b"(buf) : "memory");
+ return __syscall_fix(ret);
+}
+
static int sys_setrlimit(int resource, const struct rlimit* rlim) {
int ret;
__asm__ volatile("int $0x80" : "=a"(ret) : "a"(SYSCALL_SETRLIMIT), "b"(resource), "c"(rlim) : "memory");
(void)sys_write(1, wbad, (uint32_t)(sizeof(wbad) - 1));
}
+ // G1: uname syscall test
+ {
+ struct utsname uts;
+ for (uint32_t i = 0; i < sizeof(uts); i++) ((char*)&uts)[i] = 0;
+ int r = sys_uname(&uts);
+ if (r < 0) {
+ sys_write(1, "[init] uname failed\n", (uint32_t)(sizeof("[init] uname failed\n") - 1));
+ sys_exit(1);
+ }
+ /* Verify sysname == "AdrOS" */
+ if (uts.sysname[0] != 'A' || uts.sysname[1] != 'd' || uts.sysname[2] != 'r' ||
+ uts.sysname[3] != 'O' || uts.sysname[4] != 'S' || uts.sysname[5] != 0) {
+ sys_write(1, "[init] uname sysname bad\n", (uint32_t)(sizeof("[init] uname sysname bad\n") - 1));
+ sys_exit(1);
+ }
+ /* Verify machine == "i686" */
+ if (uts.machine[0] != 'i' || uts.machine[1] != '6' || uts.machine[2] != '8' || uts.machine[3] != '6') {
+ sys_write(1, "[init] uname machine bad\n", (uint32_t)(sizeof("[init] uname machine bad\n") - 1));
+ sys_exit(1);
+ }
+ sys_write(1, "[init] uname OK\n", (uint32_t)(sizeof("[init] uname OK\n") - 1));
+ }
+
(void)sys_write(1, "[init] execve(/bin/echo)\n",
(uint32_t)(sizeof("[init] execve(/bin/echo)\n") - 1));
static const char* const argv[] = {"echo", "[echo]", "hello", "from", "echo", 0};
#define ULIBC_DIRENT_H
#include <stdint.h>
+#include <stddef.h>
struct dirent {
uint32_t d_ino;
#define DT_BLK 6
#define DT_LNK 10
+typedef struct _DIR {
+ int fd;
+ int pos;
+ int len;
+ char buf[4096];
+} DIR;
+
+DIR* opendir(const char* name);
+struct dirent* readdir(DIR* dirp);
+int closedir(DIR* dirp);
+void rewinddir(DIR* dirp);
+
#endif
--- /dev/null
+#ifndef ULIBC_POLL_H
+#define ULIBC_POLL_H
+
+#define POLLIN 0x0001
+#define POLLPRI 0x0002
+#define POLLOUT 0x0004
+#define POLLERR 0x0008
+#define POLLHUP 0x0010
+#define POLLNVAL 0x0020
+
+struct pollfd {
+ int fd;
+ short events;
+ short revents;
+};
+
+typedef unsigned int nfds_t;
+
+int poll(struct pollfd* fds, nfds_t nfds, int timeout);
+
+#endif
int sigpending(uint32_t* set);
int sigsuspend(const uint32_t* mask);
+/* sigset_t manipulation macros (signal mask is a 32-bit bitmask) */
+typedef uint32_t sigset_t;
+
+#define _SIGMASK(sig) (1U << ((sig) - 1))
+
+static inline int sigemptyset(sigset_t* set) { *set = 0; return 0; }
+static inline int sigfillset(sigset_t* set) { *set = 0xFFFFFFFFU; return 0; }
+static inline int sigaddset(sigset_t* set, int sig) {
+ if (sig < 1 || sig > 32) return -1;
+ *set |= _SIGMASK(sig); return 0;
+}
+static inline int sigdelset(sigset_t* set, int sig) {
+ if (sig < 1 || sig > 32) return -1;
+ *set &= ~_SIGMASK(sig); return 0;
+}
+static inline int sigismember(const sigset_t* set, int sig) {
+ if (sig < 1 || sig > 32) return -1;
+ return (*set & _SIGMASK(sig)) ? 1 : 0;
+}
+
+#define SIG_BLOCK 0
+#define SIG_UNBLOCK 1
+#define SIG_SETMASK 2
+
#define SS_DISABLE 2
typedef struct {
void* ss_sp;
void perror(const char* s);
int fileno(FILE* fp);
FILE* fdopen(int fd, const char* mode);
+void clearerr(FILE* fp);
+int ungetc(int c, FILE* fp);
+int getc(FILE* fp);
+int putc(int c, FILE* fp);
+
+typedef long ssize_t;
+ssize_t getline(char** lineptr, size_t* n, FILE* stream);
+ssize_t getdelim(char** lineptr, size_t* n, int delim, FILE* stream);
+
+FILE* popen(const char* command, const char* type);
+int pclose(FILE* fp);
+
+FILE* tmpfile(void);
+char* tmpnam(char* s);
#endif
--- /dev/null
+#ifndef ULIBC_SYS_UTSNAME_H
+#define ULIBC_SYS_UTSNAME_H
+
+#define _UTSNAME_LENGTH 65
+
+struct utsname {
+ char sysname[_UTSNAME_LENGTH];
+ char nodename[_UTSNAME_LENGTH];
+ char release[_UTSNAME_LENGTH];
+ char version[_UTSNAME_LENGTH];
+ char machine[_UTSNAME_LENGTH];
+};
+
+int uname(struct utsname* buf);
+
+#endif
SYS_SHUTDOWN = 133,
SYS_GETPEERNAME = 134,
SYS_GETSOCKNAME = 135,
+ SYS_UNAME = 136,
};
/* Raw syscall wrappers — up to 5 args via INT 0x80 */
void _exit(int status) __attribute__((noreturn));
+/* sysconf / pathconf constants */
+#define _SC_CLK_TCK 2
+#define _SC_PAGE_SIZE 30
+#define _SC_PAGESIZE _SC_PAGE_SIZE
+#define _SC_OPEN_MAX 4
+#define _SC_NGROUPS_MAX 3
+#define _SC_CHILD_MAX 1
+#define _SC_ARG_MAX 0
+#define _SC_HOST_NAME_MAX 180
+#define _SC_LOGIN_NAME_MAX 71
+#define _SC_LINE_MAX 43
+
+#define _PC_PATH_MAX 4
+#define _PC_NAME_MAX 3
+#define _PC_PIPE_BUF 5
+#define _PC_LINK_MAX 0
+
+long sysconf(int name);
+long pathconf(const char* path, int name);
+long fpathconf(int fd, int name);
+
+int gethostname(char* name, size_t len);
+char* ttyname(int fd);
+int pipe2(int fds[2], int flags);
+
/* Environment pointer (set by crt0) */
extern char** __environ;
--- /dev/null
+#include "dirent.h"
+#include "unistd.h"
+#include "fcntl.h"
+#include "stdlib.h"
+#include "string.h"
+#include "syscall.h"
+#include "errno.h"
+
+/* AdrOS getdents returns fixed-size entries: { uint32_t ino; char name[256]; } = 260 bytes */
+#define ADROS_DIRENT_SIZE 260
+
+DIR* opendir(const char* name) {
+ int fd = open(name, O_RDONLY);
+ if (fd < 0) return (void*)0;
+ DIR* d = (DIR*)malloc(sizeof(DIR));
+ if (!d) { close(fd); errno = ENOMEM; return (void*)0; }
+ d->fd = fd;
+ d->pos = 0;
+ d->len = 0;
+ return d;
+}
+
+static struct dirent _de_static;
+
+struct dirent* readdir(DIR* dirp) {
+ if (!dirp) return (void*)0;
+
+ /* Refill buffer if exhausted */
+ if (dirp->pos >= dirp->len) {
+ int n = getdents(dirp->fd, dirp->buf, sizeof(dirp->buf));
+ if (n <= 0) return (void*)0;
+ dirp->len = n;
+ dirp->pos = 0;
+ }
+
+ if (dirp->pos + ADROS_DIRENT_SIZE > dirp->len) return (void*)0;
+
+ char* ent = dirp->buf + dirp->pos;
+ uint32_t ino;
+ memcpy(&ino, ent, 4);
+ _de_static.d_ino = ino;
+ _de_static.d_reclen = ADROS_DIRENT_SIZE;
+ _de_static.d_type = DT_UNKNOWN;
+ strncpy(_de_static.d_name, ent + 4, 255);
+ _de_static.d_name[255] = '\0';
+ dirp->pos += ADROS_DIRENT_SIZE;
+ return &_de_static;
+}
+
+int closedir(DIR* dirp) {
+ if (!dirp) return -1;
+ int r = close(dirp->fd);
+ free(dirp);
+ return r;
+}
+
+void rewinddir(DIR* dirp) {
+ if (!dirp) return;
+ lseek(dirp->fd, 0, SEEK_SET);
+ dirp->pos = 0;
+ dirp->len = 0;
+}
--- /dev/null
+#include "poll.h"
+#include "syscall.h"
+#include "errno.h"
+
+int poll(struct pollfd* fds, nfds_t nfds, int timeout) {
+ int r = _syscall3(SYS_POLL, (int)fds, (int)nfds, timeout);
+ return __syscall_ret(r);
+}
#include "stdio.h"
#include "unistd.h"
#include "string.h"
+#include "stdlib.h"
#include <stdarg.h>
static FILE _stdin_file = { .fd = 0, .flags = _STDIO_READ };
va_end(ap);
return r;
}
+
+void clearerr(FILE* fp) {
+ if (fp) fp->flags &= ~(_STDIO_EOF | _STDIO_ERR);
+}
+
+int ungetc(int c, FILE* fp) {
+ if (!fp || c == EOF) return EOF;
+ /* Simple 1-byte pushback: store in buf_pos-1 if possible */
+ if (fp->buf_pos > 0) {
+ fp->buf_pos--;
+ fp->buf[fp->buf_pos] = (char)c;
+ } else if (fp->buf_len < (int)sizeof(fp->buf)) {
+ /* Shift buffer right by 1 */
+ for (int i = fp->buf_len; i > 0; i--)
+ fp->buf[i] = fp->buf[i - 1];
+ fp->buf[0] = (char)c;
+ fp->buf_len++;
+ } else {
+ return EOF;
+ }
+ fp->flags &= ~_STDIO_EOF;
+ return (unsigned char)c;
+}
+
+int getc(FILE* fp) { return fgetc(fp); }
+int putc(int c, FILE* fp) { return fputc(c, fp); }
+
+ssize_t getdelim(char** lineptr, size_t* n, int delim, FILE* stream) {
+ if (!lineptr || !n || !stream) { return -1; }
+
+ if (!*lineptr || *n == 0) {
+ *n = 128;
+ *lineptr = (char*)malloc(*n);
+ if (!*lineptr) return -1;
+ }
+
+ size_t pos = 0;
+ int c;
+ while ((c = fgetc(stream)) != EOF) {
+ if (pos + 2 > *n) {
+ size_t newn = *n * 2;
+ char* tmp = (char*)realloc(*lineptr, newn);
+ if (!tmp) return -1;
+ *lineptr = tmp;
+ *n = newn;
+ }
+ (*lineptr)[pos++] = (char)c;
+ if (c == delim) break;
+ }
+ if (pos == 0 && c == EOF) return -1;
+ (*lineptr)[pos] = '\0';
+ return (ssize_t)pos;
+}
+
+ssize_t getline(char** lineptr, size_t* n, FILE* stream) {
+ return getdelim(lineptr, n, '\n', stream);
+}
+
+FILE* popen(const char* command, const char* type) {
+ int fds[2];
+ extern int pipe(int[2]);
+ extern int fork(void);
+ extern int execl(const char*, const char*, ...);
+ extern int dup2(int, int);
+ extern int close(int);
+ extern void _exit(int);
+
+ if (pipe(fds) < 0) return (FILE*)0;
+
+ int pid = fork();
+ if (pid < 0) {
+ close(fds[0]);
+ close(fds[1]);
+ return (FILE*)0;
+ }
+ if (pid == 0) {
+ /* Child */
+ if (type[0] == 'r') {
+ close(fds[0]);
+ dup2(fds[1], 1);
+ close(fds[1]);
+ } else {
+ close(fds[1]);
+ dup2(fds[0], 0);
+ close(fds[0]);
+ }
+ execl("/bin/sh", "sh", "-c", command, (char*)0);
+ _exit(127);
+ }
+ /* Parent */
+ if (type[0] == 'r') {
+ close(fds[1]);
+ return fdopen(fds[0], "r");
+ } else {
+ close(fds[0]);
+ return fdopen(fds[1], "w");
+ }
+}
+
+int pclose(FILE* fp) {
+ extern int waitpid(int, int*, int);
+ if (!fp) return -1;
+ int fd = fileno(fp);
+ (void)fd;
+ fclose(fp);
+ int status = 0;
+ waitpid(-1, &status, 0);
+ return status;
+}
+
+FILE* tmpfile(void) {
+ static int tmpcount = 0;
+ char name[32];
+ extern int getpid(void);
+ snprintf(name, sizeof(name), "/tmp/.tmpf_%d_%d", getpid(), tmpcount++);
+ return fopen(name, "w+");
+}
+
+char* tmpnam(char* s) {
+ static char buf[32];
+ static int count = 0;
+ snprintf(buf, sizeof(buf), "/tmp/tmp_%d", count++);
+ if (s) { strcpy(s, buf); return s; }
+ return buf;
+}
--- /dev/null
+#include "unistd.h"
+#include "errno.h"
+
+long sysconf(int name) {
+ switch (name) {
+ case _SC_CLK_TCK: return 100;
+ case _SC_PAGE_SIZE: return 4096;
+ case _SC_OPEN_MAX: return 64;
+ case _SC_NGROUPS_MAX: return 0;
+ case _SC_CHILD_MAX: return 128;
+ case _SC_ARG_MAX: return 131072;
+ case _SC_HOST_NAME_MAX: return 64;
+ case _SC_LOGIN_NAME_MAX: return 32;
+ case _SC_LINE_MAX: return 2048;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
+
+long pathconf(const char* path, int name) {
+ (void)path;
+ switch (name) {
+ case _PC_PATH_MAX: return 256;
+ case _PC_NAME_MAX: return 255;
+ case _PC_PIPE_BUF: return 4096;
+ case _PC_LINK_MAX: return 127;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
+
+long fpathconf(int fd, int name) {
+ (void)fd;
+ return pathconf("/", name);
+}
--- /dev/null
+#include "sys/utsname.h"
+#include "syscall.h"
+#include "errno.h"
+
+int uname(struct utsname* buf) {
+ int r = _syscall1(SYS_UNAME, (int)buf);
+ return __syscall_ret(r);
+}