From ec4b30b08a7584c0c34ae77f07b880b37b3ec7a5 Mon Sep 17 00:00:00 2001 From: Tulio A M Mendes Date: Tue, 19 May 2026 23:39:58 -0300 Subject: [PATCH] kernel+init: migrate /dev /proc /tmp mounts to userspace init Add devfs, procfs, and auto-mkdir support to SYSCALL_MOUNT so that userspace can mount virtual filesystems via the mount() syscall. Userspace migration: - init (user/cmds/init/init.c) now calls mount() directly to mount devfs on /dev, procfs on /proc, and tmpfs on /tmp before spawning the shell or running inittab entries. - This mirrors how Linux init handles these mounts from userspace. Kernel fallback: - Kernel-side mounts for /dev, /proc, /tmp are kept as fallback for non-init boot paths (e.g. init=/sbin/fulltest). When /sbin/init runs, it re-mounts these; vfs_mount replaces existing entries so this is a harmless overlap. Other changes: - SYSCALL_MOUNT: add devfs and procfs as recognized fstype strings, with auto-mkdir of the mountpoint directory (like Linux mount(8)) - Makefile: add /etc/init.d/rcS to initrd (placeholder for future shell-script-based startup when shebang/-c support is added) - rootfs/etc/init.d/rcS: placeholder script --- Makefile | 5 +++-- rootfs/etc/init.d/rcS | 5 +++++ src/kernel/init.c | 9 +++++++++ src/kernel/syscall.c | 19 +++++++++++++++++++ user/cmds/init/init.c | 19 +++++++++++++++++++ 5 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 rootfs/etc/init.d/rcS diff --git a/Makefile b/Makefile index 648e3604..2a1a4a23 100644 --- a/Makefile +++ b/Makefile @@ -255,14 +255,15 @@ USER_BIN_NAMES := $(filter-out init,$(USER_CMD_NAMES)) # Build INITRD_FILES list: : FSTAB := rootfs/etc/fstab +RCS := rootfs/etc/init.d/rcS INITRD_FILES := $(FULLTEST_ELF):sbin/fulltest \ $(USER_BUILD)/cmds/init/init.elf:sbin/init \ $(foreach cmd,$(USER_BIN_NAMES),$(USER_BUILD)/cmds/$(cmd)/$(cmd).elf:bin/$(cmd)) \ $(LDSO_ELF):lib/ld.so $(ULIBC_SO):lib/libc.so \ $(PIE_SO):lib/libpietest.so $(PIE_ELF):bin/pie_test \ - $(FSTAB):etc/fstab + $(FSTAB):etc/fstab $(RCS):etc/init.d/rcS -INITRD_DEPS := $(MKINITRD) $(FULLTEST_ELF) $(USER_CMD_ELFS) $(LDSO_ELF) $(ULIBC_SO) $(PIE_SO) $(PIE_ELF) $(FSTAB) +INITRD_DEPS := $(MKINITRD) $(FULLTEST_ELF) $(USER_CMD_ELFS) $(LDSO_ELF) $(ULIBC_SO) $(PIE_SO) $(PIE_ELF) $(FSTAB) $(RCS) # doom (build via 'make doom', included in initrd if present) doom: $(DOOM_SENTINEL) $(ULIBC_LIB) $(ULIBC_SO) diff --git a/rootfs/etc/init.d/rcS b/rootfs/etc/init.d/rcS new file mode 100644 index 00000000..130ef9e0 --- /dev/null +++ b/rootfs/etc/init.d/rcS @@ -0,0 +1,5 @@ +#!/bin/sh +# /etc/init.d/rcS — System initialization script (run by init) +# Virtual filesystems (/dev, /proc, /tmp) are mounted by init directly +# via mount() syscalls before this script runs. +# Add additional startup commands below. diff --git a/src/kernel/init.c b/src/kernel/init.c index 59317250..8b2e59b9 100644 --- a/src/kernel/init.c +++ b/src/kernel/init.c @@ -213,6 +213,11 @@ int init_start(const struct boot_info* bi) { } } } + /* Create mount-point directories and mount virtual filesystems. + * When /sbin/init runs in userspace it re-mounts these (vfs_mount + * replaces existing entries, so it is a harmless no-op). When a + * different init= binary is used (e.g. fulltest), these kernel-side + * mounts ensure the system is functional. */ { int rc; rc = vfs_mkdir("/dev"); @@ -247,6 +252,10 @@ int init_start(const struct boot_info* bi) { tty_init(); pty_init(); + /* Mount devfs — kernel-side fallback so that any init= binary + * (including fulltest) has /dev available. When /sbin/init runs + * it re-mounts devfs via mount() syscall; vfs_mount replaces the + * existing entry so this is a harmless overlap. */ fs_node_t* dev = devfs_create_root(); if (dev) { (void)vfs_mount("/dev", dev); diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 5017eb83..6b48af3b 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -4911,12 +4911,30 @@ static void socket_syscall_dispatch(struct registers* regs, uint32_t syscall_no) kdev[sizeof(kdev)-1] = '\0'; ktype[sizeof(ktype)-1] = '\0'; + /* Virtual filesystems — no device argument needed */ if (strcmp(ktype, "tmpfs") == 0) { fs_node_t* tmp = tmpfs_create_root(); if (!tmp) { sc_ret(regs) = (uint32_t)-ENOMEM; return; } + (void)vfs_mkdir(kmp); /* auto-create mountpoint */ sc_ret(regs) = (uint32_t)vfs_mount(kmp, tmp); return; } + if (strcmp(ktype, "devfs") == 0) { + extern fs_node_t* devfs_create_root(void); + fs_node_t* dev = devfs_create_root(); + if (!dev) { sc_ret(regs) = (uint32_t)-ENOMEM; return; } + (void)vfs_mkdir(kmp); + sc_ret(regs) = (uint32_t)vfs_mount(kmp, dev); + return; + } + if (strcmp(ktype, "procfs") == 0) { + extern fs_node_t* procfs_create_root(void); + fs_node_t* proc = procfs_create_root(); + if (!proc) { sc_ret(regs) = (uint32_t)-ENOMEM; return; } + (void)vfs_mkdir(kmp); + sc_ret(regs) = (uint32_t)vfs_mount(kmp, proc); + return; + } /* Disk-based: parse /dev/hdX -> drive number */ const char* devname = kdev; @@ -4926,6 +4944,7 @@ static void socket_syscall_dispatch(struct registers* regs, uint32_t syscall_no) if (drive < 0) { sc_ret(regs) = (uint32_t)-ENODEV; return; } extern int init_mount_fs(const char* fstype, int drive, uint32_t lba, const char* mountpoint); + (void)vfs_mkdir(kmp); /* auto-create mountpoint */ int rc = init_mount_fs(ktype, drive, 0, kmp); sc_ret(regs) = (uint32_t)(rc < 0 ? -EIO : 0); return; diff --git a/user/cmds/init/init.c b/user/cmds/init/init.c index 002a1ba7..44f356ce 100644 --- a/user/cmds/init/init.c +++ b/user/cmds/init/init.c @@ -24,6 +24,7 @@ #include #include #include +#include #define MAX_ENTRIES 32 #define LINE_MAX 256 @@ -239,7 +240,22 @@ static void check_respawn(void) { } /* Default behavior when no inittab exists */ +/* Mount virtual filesystems (migrated from kernel-space). + * These must be done before spawning the shell since /dev/console + * is needed for terminal I/O. */ +static void mount_virtual_fs(void) { + if (mount("none", "/dev", "devfs", 0, NULL) < 0) + fprintf(stderr, "init: mount devfs on /dev failed\n"); + if (mount("none", "/proc", "procfs", 0, NULL) < 0) + fprintf(stderr, "init: mount procfs on /proc failed\n"); + if (mount("none", "/tmp", "tmpfs", 0, NULL) < 0) + fprintf(stderr, "init: mount tmpfs on /tmp failed\n"); +} + static void default_init(void) { + /* Mount virtual filesystems before anything else */ + mount_virtual_fs(); + /* Run /etc/init.d/rcS if it exists */ if (access("/etc/init.d/rcS", 0) == 0) { run_and_wait("/etc/init.d/rcS"); @@ -296,6 +312,9 @@ int main(int argc, char** argv) { printf("init: loaded %d inittab entries, runlevel %d\n", nentries, current_runlevel); + /* Mount virtual filesystems before running any inittab entries */ + mount_virtual_fs(); + /* Phase 1: sysinit entries */ run_action(ACT_SYSINIT, 1); -- 2.43.0