rand: Add ChaCha20-based CSPRNG, among other things

We now have RNG!

- Implement ChaCha20-based cryptographically secure random number generator (CSPRNG) in `src/drivers/rand/random.c` and its header in `src/drivers/rand/random.h`.
- Modify VFS to support directory operations, including opening directories and reading directory entries.
- Update syscall interface to include new syscalls for directory handling: `SYS_OPEN_DIR` and `SYS_READ_ENTRIES`.
- Enhance file creation in EXT2 to allow specifying file modes.
- Refactor VFS file handling to accommodate new flags and modes.
- Update user-space application in `user/include/mlibc/helloworld.c` to demonstrate file operations including `touch`, `ls`, and `cat`.
- Clean up debug print statements in EXT2 file system code.
- Worked on proper error handling and return codes across VFS and syscall implementations.

It's only a small step but we're getting closer to making error codes standardized

We also setup SSE exactly as we should've the first time we introduced it in commit 9a9b91c

We have added it correctly to the user stack trampoline (hopefully), so there shouldn't be any issues now.

Signed-off-by: kaguya <vpshinomiya@protonmail.com>
This commit is contained in:
kaguya
2026-05-03 00:46:59 -04:00
parent 9a16250a1b
commit ef14a52b49
20 changed files with 716 additions and 79 deletions
+202
View File
@@ -0,0 +1,202 @@
#include "random.h"
#include "fs/vfs.h"
#include "libk/stdio.h"
#include "arch/x86_64/sys/tsc.h"
#include "arch/x86_64/sys/pit.h"
#include "errno.h"
#include <stdbool.h>
#include <string.h>
#include "limine.h"
/* ChaCha20 core (public-domain, 20-round) */
static inline void chacha20_quarterround(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d) {
*a += *b; *d ^= *a; *d = (*d << 16) | (*d >> 16);
*c += *d; *b ^= *c; *b = (*b << 12) | (*b >> 20);
*a += *b; *d ^= *a; *d = (*d << 8) | (*d >> 24);
*c += *d; *b ^= *c; *b = (*b << 7) | (*b >> 25);
}
static void chacha20_block(uint32_t state[16], uint8_t output[64]) {
uint32_t x[16];
for (int i = 0; i < 16; ++i) x[i] = state[i];
for (int i = 0; i < 10; ++i) { /* 10 double-rounds = 20 rounds */
/* column rounds */
chacha20_quarterround(&x[0], &x[4], &x[8], &x[12]);
chacha20_quarterround(&x[1], &x[5], &x[9], &x[13]);
chacha20_quarterround(&x[2], &x[6], &x[10], &x[14]);
chacha20_quarterround(&x[3], &x[7], &x[11], &x[15]);
/* diagonal rounds */
chacha20_quarterround(&x[0], &x[5], &x[10], &x[15]);
chacha20_quarterround(&x[1], &x[6], &x[11], &x[12]);
chacha20_quarterround(&x[2], &x[7], &x[8], &x[13]);
chacha20_quarterround(&x[3], &x[4], &x[9], &x[14]);
}
for (int i = 0; i < 16; ++i) {
x[i] += state[i];
((uint32_t*)output)[i] = x[i];
}
}
/* Global ChaCha20 PRNG state */
static uint8_t rng_key[32];
static uint64_t rng_counter = 0;
static bool rng_seeded = false;
static void rng_generate(uint8_t *buf, size_t len) {
size_t i = 0;
while (len > 0) {
uint32_t state[16];
static const uint32_t sigma[4] = {0x61707865, 0x3320646e, 0x79622d32, 0x6b206574};
state[0] = sigma[0]; state[1] = sigma[1]; state[2] = sigma[2]; state[3] = sigma[3];
for (int j = 0; j < 8; ++j)
state[4 + j] = ((uint32_t*)rng_key)[j];
state[12] = (uint32_t)rng_counter;
state[13] = (uint32_t)(rng_counter >> 32);
state[14] = 0xdeadbeef; /* fixed nonce (PRNG only) */
state[15] = 0xbeefdead;
uint8_t block[64];
chacha20_block(state, block);
size_t copy = (len < 64) ? len : 64;
for (size_t k = 0; k < copy; ++k)
buf[i + k] = block[k];
i += copy;
len -= copy;
rng_counter++;
}
}
static void rng_add_entropy(const uint8_t *data, size_t len) {
if (len == 0 || !data) return;
for (size_t i = 0; i < len; ++i)
rng_key[i % 32] ^= data[i];
/* stir (forward secrecy) */
uint8_t discard[64];
rng_generate(discard, 64);
rng_seeded = true;
}
int random_read(void* buf, size_t len) {
if (len == 0) return 0;
if (!buf) return -EFAULT;
if (!rng_seeded) return -EAGAIN; /* should never happen after init */
rng_generate((uint8_t*)buf, len);
return (int)len;
}
int random_write(const void* buf, size_t len) {
if (len == 0) return 0;
if (!buf) return -EFAULT;
rng_add_entropy((const uint8_t*)buf, len);
return (int)len;
}
int getrandom(void *buf, size_t buflen, unsigned int flags)
{
if (!buf) return -EFAULT;
if (buflen == 0) return 0;
if (flags & GRND_INSECURE) {
// maybe fall back to weaker RNG?
}
if (!rng_seeded) {
if (flags & GRND_NONBLOCK)
return -EAGAIN;
// could block here in the future
return -EAGAIN;
}
rng_generate((uint8_t*)buf, buflen);
return (int)buflen;
}
void random_init(void) {
printf("Initializing ChaCha20-based CSPRNG for /dev/random and /dev/urandom...\n");
uint8_t entropy[64] = {0};
size_t epos = 0;
/* === SEEDING SOURCES === */
/* 1. Limine boot timestamp (wall-clock) */
extern volatile struct limine_date_at_boot_request boot_request;
if (boot_request.response) {
uint64_t ts = boot_request.response->timestamp;
if (epos + sizeof(ts) <= sizeof(entropy)) {
memcpy(entropy + epos, &ts, sizeof(ts));
epos += sizeof(ts);
}
}
/* 2. Multiple TSC samples (high-resolution jitter) */
for (int i = 0; i < 4; ++i) {
uint64_t tsc_val = rdtsc();
if (epos + sizeof(tsc_val) <= sizeof(entropy)) {
memcpy(entropy + epos, &tsc_val, sizeof(tsc_val));
epos += sizeof(tsc_val);
}
}
/* 3. PIT tick counter */
uint64_t pit_ticks = PIT_GetTicks();
if (epos + sizeof(pit_ticks) <= sizeof(entropy)) {
memcpy(entropy + epos, &pit_ticks, sizeof(pit_ticks));
epos += sizeof(pit_ticks);
}
/* 4. RDRAND (hardware TRNG) if present */
{
uint32_t eax, ebx, ecx, edx;
asm volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(1));
if (ecx & (1u << 30)) {
printf("RDRAND detected - using hardware RNG for seeding\n");
for (int i = 0; i < 4 && epos + 8 <= sizeof(entropy); ++i) {
uint64_t rd;
asm volatile("1: rdrand %0\n\tjnc 1b" : "=r"(rd));
memcpy(entropy + epos, &rd, sizeof(rd));
epos += sizeof(rd);
}
}
}
/* 5. Unix seconds from PIT (time-based entropy) */
extern uint64_t g_Unixseconds;
uint64_t unix_sec = g_Unixseconds;
if (epos + sizeof(unix_sec) <= sizeof(entropy)) {
memcpy(entropy + epos, &unix_sec, sizeof(unix_sec));
epos += sizeof(unix_sec);
}
/* 6. Final TSC padding (extra jitter) */
while (epos < 32) {
uint64_t t = rdtsc();
memcpy(entropy + epos, &t, (epos + 8 <= 32) ? 8 : (32 - epos));
epos += (epos + 8 <= 32) ? 8 : (32 - epos);
}
/* Initialise ChaCha20 key from collected entropy */
memcpy(rng_key, entropy, 32);
rng_counter = rdtsc(); /* random starting counter */
rng_seeded = true;
printf("ChaCha20 RNG seeded with %zu bytes of entropy (TSC, PIT, RDRAND, boot time, unix time, etc.)\n", epos);
/* Register both devices (open as "/dev/random" and "/dev/urandom") */
VFS_RegisterCharDev("/dev/random", random_read, random_write);
VFS_RegisterCharDev("/dev/urandom", random_read, random_write);
printf("Registered chardevs: /dev/random and /dev/urandom (ChaCha20 CSPRNG)\n");
}
+12
View File
@@ -0,0 +1,12 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#define GRND_NONBLOCK 0x0001
#define GRND_RANDOM 0x0002
#define GRND_INSECURE 0x0004
void random_init(void);
int random_read(void* buf, size_t len);
int random_write(const void* buf, size_t len);
int getrandom(void *buf, size_t buflen, unsigned int flags);
+6 -12
View File
@@ -100,7 +100,6 @@ bool ext2_read_superblock(void) {
static bool ext2_write_superblock_internal(void) {
uint8_t* tmp = kmalloc(1024);
printf("test4");
if (!tmp) return false;
memset(tmp, 0, 1024);
memcpy(tmp, &sb, sizeof(ext2_superblock_t));
@@ -179,11 +178,8 @@ static bool ext2_write_gdt(void) {
}
static void ext2_sync(void) {
printf("test1");
ext2_write_superblock_internal();
printf("test2");
ext2_write_gdt_internal();
printf("test3");
}
// ── bitmap allocators ─────────────────────────────────────────────────────────
@@ -344,8 +340,6 @@ bool ext2_read_inode_internal(uint32_t inum, ext2_inode_t* out) {
if (!ext2_read_block_raw(gdt[g].bg_inode_table + block_off, buf)) {
kfree(buf); return false;
}
printf("ext2_read_inode: inum=%u group=%u idx=%u block_off=%u inode_off=%u\n",
inum + 1, g, idx, block_off, inode_off);
memcpy(out, buf + inode_off * sb.s_inode_size, sizeof(ext2_inode_t));
kfree(buf);
return true;
@@ -537,8 +531,8 @@ static void ext2_free_inode_blocks(ext2_inode_t* inode) {
// ── file I/O ─────────────────────────────────────────────────────────────────
bool ext2_read_file_internal(ext2_inode_t* inode, uint8_t* buf) {
if ((inode->i_mode & 0xF000) != EXT2_S_IFREG) {
printf("EXT2: not a regular file\n");
if (((inode->i_mode & 0xF000) != EXT2_S_IFREG) && ((inode->i_mode & 0xF000) != EXT2_S_IFDIR)) {
printf("EXT2: not a regular file or directory\n");
return false;
}
uint32_t size = inode->i_size;
@@ -1012,7 +1006,7 @@ bool ext2_write_file_from_root(const char* name, const uint8_t* data,
// ── create / delete ───────────────────────────────────────────────────────────
bool ext2_create_file_internal(ext2_inode_t* dir, uint32_t dir_inum,
const char* name, uint32_t* out_inum)
const char* name, uint16_t mode, uint32_t* out_inum)
{
if (dir_lookup_internal(dir, name)) {
printf("EXT2: already exists: %s\n", name);
@@ -1023,7 +1017,7 @@ bool ext2_create_file_internal(ext2_inode_t* dir, uint32_t dir_inum,
if (!inum) return false;
ext2_inode_t inode = {0};
inode.i_mode = EXT2_S_IFREG | 0644;
inode.i_mode = mode;
inode.i_links_count = 1;
inode.i_atime = inode.i_ctime = inode.i_mtime = (uint32_t)g_Unixseconds;
ext2_write_inode_internal(inum, &inode);
@@ -1038,11 +1032,11 @@ bool ext2_create_file_internal(ext2_inode_t* dir, uint32_t dir_inum,
}
bool ext2_create_file(ext2_inode_t* dir, uint32_t dir_inum,
const char* name, uint32_t* out_inum)
const char* name, uint16_t mode, uint32_t* out_inum)
{
uint64_t flags;
spinlock_acquire_irqsave(&s_ext2_lock, &flags);
bool resp = ext2_create_file_internal(dir, dir_inum, name, out_inum);
bool resp = ext2_create_file_internal(dir, dir_inum, name, mode, out_inum);
spinlock_release_irqrestore(&s_ext2_lock, flags);
return resp;
}
+1 -1
View File
@@ -198,7 +198,7 @@ bool ext2_write_file_from_root(const char* name, const uint8_t* data,
// ── create / delete ───────────────────────────────────────────────────────────
bool ext2_create_file(ext2_inode_t* dir, uint32_t dir_inum,
const char* name, uint32_t* out_inum);
const char* name, uint16_t mode, uint32_t* out_inum);
bool ext2_mkdir(ext2_inode_t* parent, uint32_t parent_inum,
const char* name, uint32_t* out_inum);
bool ext2_unlink(ext2_inode_t* dir, uint32_t dir_inum, const char* name);
+76 -42
View File
@@ -5,10 +5,12 @@
#include "libk/stdio.h"
#include "mm/memory.h"
#include "libk/string.h"
#include "libk/errno.h"
#include "drivers/input/input.h"
static spinlock_t s_vfs_lock = SPINLOCK_INIT;
static vfs_file_t vfs_fd_table[VFS_MAX_FDS];
vfs_dir_t vfs_dir_table[VFS_MAX_DIRS];
typedef struct {
const char* path;
@@ -26,7 +28,7 @@ int VFS_RegisterCharDev(const char* path,
{
if (s_num_chardevs >= VFS_MAX_CHARDEVS) {
printf("VFS: too many char devices!\n");
return -1;
return -ENFILE;
}
s_chardevs[s_num_chardevs].path = path;
s_chardevs[s_num_chardevs].read = read;
@@ -36,11 +38,11 @@ int VFS_RegisterCharDev(const char* path,
return 0;
}
fd_t VFS_Open_internal(const char* path)
static fd_t VFS_Open_internal(const char* path, int flags, unsigned int mode)
{
const char* p = path;
if (*p == '/') p++;
// ── chardevs (flags/mode ignored for now) ───────────────────────────────
for (int i = 0; i < s_num_chardevs; i++) {
if (strcmp(s_chardevs[i].path, p) == 0) {
for (int fd = 4; fd < VFS_MAX_FDS; fd++) {
@@ -52,48 +54,81 @@ fd_t VFS_Open_internal(const char* path)
return fd;
}
}
return -1;
return -EMFILE;
}
}
// ── EXT2 files ──────────────────────────────────────────────────────────
uint32_t ino = ext2_resolve_path(p);
if (ino == 0)
return -1;
// find free fd
for (int i = 4; i < VFS_MAX_FDS; i++)
{
if (!vfs_fd_table[i].used)
{
if (ino != 0) {
// file exists
if ((flags & O_CREAT) && (flags & O_EXCL)) {
return -EEXIST;
}
// O_TRUNC ?
if (flags & O_TRUNC) {
ext2_inode_t inode;
if (!ext2_read_inode(ino, &inode)) {
return -EIO;
}
if (!ext2_truncate(&inode, ino, 0)) {
return -EIO;
}
}
} else {
// does not exist
if (!(flags & O_CREAT)) {
return -ENOENT;
}
// Create new regular file in root (simple filename only for now)
ext2_inode_t root;
if (!ext2_read_inode(2, &root)) {
return -EIO;
}
uint32_t new_ino;
uint16_t file_mode = EXT2_S_IFREG | (mode & 0777); // respect user-supplied perms
if (!ext2_create_file(&root, 2, p, file_mode, &new_ino)) {
return -EIO;
}
ino = new_ino;
}
// ── allocate fd and fill table ──────────────────────────────────────────
for (int i = 4; i < VFS_MAX_FDS; i++) {
if (!vfs_fd_table[i].used) {
vfs_fd_table[i].used = true;
vfs_fd_table[i].type = VFS_NODE_EXT2;
vfs_fd_table[i].type = VFS_NODE_FILE;
vfs_fd_table[i].offset = 0;
vfs_fd_table[i].ext2.inode_num = ino;
if (!ext2_read_inode(ino, &vfs_fd_table[i].ext2.inode))
return -1;
if (!ext2_read_inode(ino, &vfs_fd_table[i].ext2.inode)) {
vfs_fd_table[i].used = false;
return -EIO;
}
return i;
}
}
return -1;
return -EMFILE;
}
fd_t VFS_Open(const char* path) {
uint64_t flags;
spinlock_acquire_irqsave(&s_vfs_lock, &flags);
fd_t fd = VFS_Open_internal(path);
spinlock_release_irqrestore(&s_vfs_lock, flags);
fd_t VFS_Open(const char* path, int flags, unsigned int mode) {
uint64_t spin_flags;
spinlock_acquire_irqsave(&s_vfs_lock, &spin_flags);
fd_t fd = VFS_Open_internal(path, flags, mode);
spinlock_release_irqrestore(&s_vfs_lock, spin_flags);
return fd;
}
int VFS_Close_internal(fd_t fd)
{
if (fd < 0 || fd >= VFS_MAX_FDS)
return -1;
return -EBADF;
vfs_fd_table[fd].used = false;
return 0;
@@ -110,7 +145,7 @@ int VFS_Close(fd_t fd) {
int VFS_Read_internal(fd_t fd, uint8_t* buf, size_t size)
{
if (fd < 0 || fd >= VFS_MAX_FDS)
return -1;
return -EBADF;
if (fd == VFS_FD_STDIN) {
return input_read_console(buf, size);
@@ -119,11 +154,11 @@ int VFS_Read_internal(fd_t fd, uint8_t* buf, size_t size)
vfs_file_t* file = &vfs_fd_table[fd];
if (!file->used)
return -1;
return -EBADF;
switch (file->type)
{
case VFS_NODE_EXT2:
case VFS_NODE_FILE:
{
uint32_t file_size = file->ext2.inode.i_size;
@@ -137,11 +172,11 @@ int VFS_Read_internal(fd_t fd, uint8_t* buf, size_t size)
// naive: read whole file then slice
uint8_t* tmp = kmalloc(file_size);
if (!tmp) {
return -1;
return -ENOMEM;
}
if (!ext2_read_file(&file->ext2.inode, tmp)) {
kfree(tmp);
return -1;
return -EIO;
}
for (size_t i = 0; i < size; i++)
@@ -156,12 +191,12 @@ int VFS_Read_internal(fd_t fd, uint8_t* buf, size_t size)
{
int idx = file->chardev.dev_idx;
if (idx < 0 || idx >= s_num_chardevs || !s_chardevs[idx].read)
return -1;
return -ENXIO;
return s_chardevs[idx].read(buf, size);
}
default:
return -1;
return -EINVAL;
}
}
@@ -179,15 +214,14 @@ int VFS_Write_internal(fd_t file, uint8_t* data, size_t size)
switch (file)
{
case VFS_FD_STDIN:
return 0;
return -EINVAL;
case VFS_FD_STDOUT:
for (size_t i = 0; i < size; i++)
putchar(data[i]);
return size;
case VFS_FD_STDERR:
for (size_t i = 0; i < size; i++)
for (size_t i = 0; i < size; i++) {
putchar(data[i]);
e9_putc(data[i]);
}
return size;
case VFS_FD_DEBUG:
@@ -200,14 +234,14 @@ int VFS_Write_internal(fd_t file, uint8_t* data, size_t size)
}
if (file < 0 || file >= VFS_MAX_FDS)
return -1;
return -EBADF;
vfs_file_t* f = &vfs_fd_table[file];
if (!f->used)
return -1;
return -EBADF;
if (f->type == VFS_NODE_EXT2)
if (f->type == VFS_NODE_FILE)
{
if (!ext2_write_file(
&f->ext2.inode,
@@ -215,7 +249,7 @@ int VFS_Write_internal(fd_t file, uint8_t* data, size_t size)
data,
size,
EXT2_WRITE_APPEND))
return -1;
return -EIO;
return size;
}
@@ -225,10 +259,10 @@ int VFS_Write_internal(fd_t file, uint8_t* data, size_t size)
int idx = f->chardev.dev_idx;
if (idx >= 0 && idx < s_num_chardevs && s_chardevs[idx].write)
return s_chardevs[idx].write(data, size);
return -1;
return -ENXIO;
}
return -1;
return -EINVAL;
}
int VFS_Write(fd_t file, uint8_t* data, size_t size)
+45 -2
View File
@@ -4,10 +4,27 @@
#include <stdbool.h>
#include "ext2.h"
#define O_RDONLY 0
#define O_WRONLY 1
#define O_RDWR 2
#define O_ACCMODE 3
#define O_CREAT 0100
#define O_EXCL 0200
#define O_NOCTTY 0400
#define O_TRUNC 01000
#define O_APPEND 02000
#define O_NONBLOCK 04000
#define O_DSYNC 010000
typedef int fd_t;
#define VFS_MAX_FDS 32
#define VFS_MAX_DIRS 64
#define VFS_FD_STDIN 0
#define VFS_FD_STDOUT 1
#define VFS_FD_STDERR 2
@@ -15,7 +32,8 @@ typedef int fd_t;
typedef enum {
VFS_NODE_NONE,
VFS_NODE_EXT2,
VFS_NODE_FILE,
VFS_NODE_DIR,
VFS_NODE_CHARDEV
} vfs_node_type_t;
@@ -37,8 +55,33 @@ typedef struct {
bool used;
} vfs_file_t;
typedef struct {
bool used;
uint32_t inode;
size_t offset;
vfs_node_type_t type;
} vfs_dir_t;
typedef uint64_t ino_t;
typedef int64_t off_t;
#define IFTODT(mode) (((mode) & 0170000) >> 12)
#define __MLIBC_DIRENT_BODY ino_t d_ino; \
off_t d_off; \
unsigned short d_reclen; \
unsigned char d_type; \
char d_name[1024];
struct dirent {
__MLIBC_DIRENT_BODY
};
extern vfs_dir_t vfs_dir_table[VFS_MAX_DIRS];
// API
fd_t VFS_Open(const char* path);
fd_t VFS_Open(const char* path, int flags, unsigned int mode);
int VFS_Read(fd_t fd, uint8_t* buf, size_t size);
int VFS_Write(fd_t fd, uint8_t* data, size_t size);
int VFS_Close(fd_t fd);
+8 -2
View File
@@ -32,6 +32,7 @@
#include "arch/x86_64/sys/ioapic.h"
#include "drivers/input/ps2.h"
#include "sched/scheduler.h"
#include "drivers/rand/random.h"
uintptr_t g_hhdm_offset;
@@ -89,6 +90,7 @@ __attribute__((used, section(".limine_requests_end")))
static volatile uint64_t limine_requests_end_marker[] = LIMINE_REQUESTS_END_MARKER;
uint8_t g_clean_fxstate[512] __attribute__((aligned(16)));
// Halt and catch fire function.
@@ -211,6 +213,8 @@ void init_simd(void) {
// Initialize FPU/SSE state
__asm__ volatile ("fninit");
__asm__ volatile ("fxsave %0" : "=m"(g_clean_fxstate));
}
@@ -432,17 +436,19 @@ void kmain(void) {
input_init();
ps2_kbd_init();
random_init();
gdt_load_tss((size_t)&kernel_tss);
kernel_tss.rsp0 = rsp;
syscall_init();
enable_fsgsbase_if_supported();
init_simd();
sched_init();
enable_fsgsbase_if_supported();
init_simd();
start_userspace();
+4
View File
@@ -42,6 +42,8 @@ sched_context_switch:
# from->rsp = RSP (rdi = struct cpu_context *from, offset 0 = rsp)
movq %rsp, 0(%rdi)
fxsave 16(%rdi)
# Switch address space (CR3) if needed
# to->cr3 is at offset 8 in struct cpu_context
movq 8(%rsi), %rax
@@ -59,6 +61,8 @@ sched_context_switch:
# to->rsp is at offset 0 (rsi = struct cpu_context *to)
movq 0(%rsi), %rsp
fxrstor 16(%rsi)
# Restore incoming task's callee-saved registers
popq %r15
popq %r14
+3
View File
@@ -379,6 +379,8 @@ static task_t *alloc_task(const char *name, bool is_user) {
if (!task) return NULL;
memset(task, 0, sizeof(task_t));
memcpy(task->ctx.fxstate, g_clean_fxstate, 512);
strncpy(task->name, name, sizeof(task->name) - 1);
task->is_user = is_user;
task->state = TASK_RUNNING;
@@ -491,6 +493,7 @@ void sched_init(void) {
while (1) asm volatile("hlt");
}
memset(boot, 0, sizeof(task_t));
memcpy(boot->ctx.fxstate, g_clean_fxstate, 512);
strncpy(boot->name, "boot", 63);
boot->pid = alloc_pid(); /* pid 1 */
boot->state = TASK_RUNNING;
+4
View File
@@ -41,6 +41,9 @@
#define SIGSYS 31
#define _NSIG 32
/* Clean FXSAVE state used to initialize every new task */
extern uint8_t g_clean_fxstate[512] __attribute__((aligned(16)));
typedef void (*sighandler_t)(int signum);
#define SIG_DFL ((sighandler_t)0) /* default action */
#define SIG_IGN ((sighandler_t)1) /* ignore signal */
@@ -116,6 +119,7 @@ typedef enum task_state {
struct cpu_context {
uint64_t rsp; /* Saved kernel stack pointer */
uint64_t cr3; /* Physical address of PML4 (0 = stay on kernel map) */
uint8_t fxstate[512] __attribute__((aligned(16))); /* FPU/SSE state (FXSAVE area) */
};
/* =====================================================================
+31 -9
View File
@@ -1,14 +1,36 @@
/* ── struct task offsets ─────────────────────────────────────────────────── */
.equ TASK_KERNEL_STACK, 160
.equ TASK_KERNEL_STACK_SIZE, 168
.equ TASK_USER_ENTRY, 176
.equ TASK_USER_STACK_TOP, 184
.equ TASK_TLS_FS_BASE, 208
.equ TASK_PHDR_VA, 216
.equ TASK_PHENT, 224
.equ TASK_PHNUM, 226
.equ TASK_CTX, 0
.equ TASK_CTX_RSP, 0
.equ TASK_CTX_CR3, 8
.equ TASK_CTX_FXSTATE, 16
.equ TASK_PID, 528 /* update if` struct changes */
.equ TASK_PPID, 532
.equ TASK_NAME, 536
.equ TASK_IS_USER, 600
.equ TASK_POLICY, 604
.equ TASK_STATIC_PRIO, 608
.equ TASK_NICE, 612
.equ TASK_PRIO, 616
.equ TASK_STATE, 620 # enum (4 bytes)
.equ TASK_NEED_RESCHED, 624 # bool (1 byte)
.equ TASK_VRUNTIME, 632
.equ TASK_SUM_EXEC_RUNTIME,640
.equ TASK_TIME_SLICE, 648
.equ TASK_SLICE_START, 656
.equ TASK_PAGEMAP, 664
.equ TASK_KERNEL_STACK, 672
.equ TASK_KERNEL_STACK_SIZE,680
.equ TASK_USER_ENTRY, 688
.equ TASK_USER_STACK_TOP, 696
.equ TASK_KTHREAD_ENTRY, 704
.equ TASK_KTHREAD_ARG, 712
.equ TASK_TLS_FS_BASE, 720
.equ TASK_PHDR_VA, 728
.equ TASK_PHENT, 736 # uint16_t
.equ TASK_PHNUM, 738 # uint16_t
/* ── GDT selectors ───────────────────────────────────────────────────────── */
.equ SEL_USER_DS, 0x1B /* ring-3 data (index 3, RPL 3) */
+145 -1
View File
@@ -9,6 +9,7 @@
#include "mm/memory.h"
#include "libk/errno.h"
#include "mp/futex.h"
#include "drivers/rand/random.h"
#define MSR_EFER 0xC0000080
#define MSR_STAR 0xC0000081
@@ -63,12 +64,145 @@ uint64_t syscall_handler(uint64_t num,
case SYS_OPEN:
{
const char* path = (const char*)arg1;
return (uint64_t)VFS_Open(path);
int flags = (int)arg2;
unsigned int mode = (unsigned int)arg3;
return (uint64_t)VFS_Open(path, flags, mode);
}
case SYS_OPEN_DIR:
{
const char* path = (const char*)arg1;
int* out_handle = (int*)arg2;
if (!path || !out_handle)
return -EINVAL;
uint32_t ino = ext2_resolve_path(path);
if (ino == 0)
return -ENOENT;
ext2_inode_t inode;
if (!ext2_read_inode(ino, &inode))
return -EIO;
if (!(inode.i_mode & EXT2_S_IFDIR))
return -ENOTDIR;
// allocate dir handle (safe offset so it never collides with real fds)
for (int i = 0; i < VFS_MAX_DIRS; i++)
{
if (!vfs_dir_table[i].used)
{
vfs_dir_table[i].used = true;
vfs_dir_table[i].inode = ino;
vfs_dir_table[i].offset = 0;
vfs_dir_table[i].type = 1;
*out_handle = VFS_MAX_FDS + i; // e.g. 32 + i
return 0;
}
}
return -EMFILE;
}
case SYS_READ_ENTRIES:
{
int handle = (int)arg1;
void *buf = (void*)arg2;
size_t max = (size_t)arg3;
size_t *out = (size_t*)arg4;
if (!buf || !out)
return -EINVAL;
// Directory handles are at VFS_MAX_FDS + idx
int idx = handle - VFS_MAX_FDS;
if (idx < 0 || idx >= VFS_MAX_DIRS) {
return -EBADF;
}
vfs_dir_t *d = &vfs_dir_table[idx];
if (!d->used) {
return -EBADF;
}
ext2_inode_t dir_inode;
if (!ext2_read_inode(d->inode, &dir_inode)) {
return -EIO;
}
if (dir_inode.i_size == 0) {
*out = 0;
return 0;
}
uint8_t *tmp = kmalloc(dir_inode.i_size);
if (!tmp) {
return -ENOMEM;
}
// Read the raw directory blocks (same format as regular files)
if (!ext2_read_file(&dir_inode, tmp)) {
kfree(tmp);
return -EIO;
}
size_t pos = 0;
size_t out_pos = 0;
size_t index = 0;
while (pos < dir_inode.i_size && out_pos + sizeof(struct dirent) < max)
{
ext2_dir_entry_t *e = (ext2_dir_entry_t*)(tmp + pos);
if (e->inode != 0)
{
if (index++ >= d->offset)
{
struct dirent *out_ent = (struct dirent*)((uint8_t*)buf + out_pos);
memset(out_ent, 0, sizeof(struct dirent));
out_ent->d_ino = e->inode;
out_ent->d_off = index;
out_ent->d_reclen = sizeof(struct dirent);
out_ent->d_type = IFTODT(e->file_type);
size_t n = e->name_len;
if (n >= sizeof(out_ent->d_name))
n = sizeof(out_ent->d_name) - 1;
memcpy(out_ent->d_name, e->name, n);
out_ent->d_name[n] = '\0';
out_pos += sizeof(struct dirent);
}
}
pos += e->rec_len;
}
d->offset = index;
*out = out_pos;
kfree(tmp);
return 0;
}
case SYS_CLOSE:
{
int fd = (int)arg1;
if (fd >= VFS_MAX_FDS && fd < VFS_MAX_FDS + VFS_MAX_DIRS) {
int idx = fd - VFS_MAX_FDS;
if (idx >= 0 && idx < VFS_MAX_DIRS && vfs_dir_table[idx].used) {
vfs_dir_table[idx].used = false;
return 0;
}
return -EBADF;
}
return (uint64_t)VFS_Close(fd);
}
@@ -262,6 +396,16 @@ uint64_t syscall_handler(uint64_t num,
}
}
case SYS_GETRANDOM:
{
void *buf = (void*)arg1;
size_t buflen = (size_t)arg2;
unsigned int flags = (unsigned int)arg3;
return (int64_t)getrandom(buf, buflen, flags);
}
default:
{
printf("Unknown syscall: %lu\n", num);
+5 -1
View File
@@ -25,8 +25,12 @@
#define SYS_FUTEX 202
#define SYS_EXIT_GROUP 231
#define SYS_TCB_SET 300
#define SYS_GETRANDOM 318
#define SYS_OPEN_DIR 319
#define SYS_READ_ENTRIES 320
typedef int64_t off_t;
// Memory protection flags (Linux compatible)