]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
kernel+init: migrate /dev /proc /tmp mounts to userspace init
authorTulio A M Mendes <[email protected]>
Wed, 20 May 2026 02:39:58 +0000 (23:39 -0300)
committerTulio A M Mendes <[email protected]>
Wed, 20 May 2026 02:39:58 +0000 (23:39 -0300)
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
rootfs/etc/init.d/rcS [new file with mode: 0644]
src/kernel/init.c
src/kernel/syscall.c
user/cmds/init/init.c

index 648e36042de55930f82e9ff74a2ee774a8f6f693..2a1a4a23bb360e0ec17332c22cb399c339bce1f5 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -255,14 +255,15 @@ USER_BIN_NAMES := $(filter-out init,$(USER_CMD_NAMES))
 
 # Build INITRD_FILES list: <elf>:<rootfs-path>
 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 (file)
index 0000000..130ef9e
--- /dev/null
@@ -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.
index 593172502c01593bbe10b142e93b031f53ded2c9..8b2e59b969ee6c28f39f259e7172053ea690a953 100644 (file)
@@ -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);
index 5017eb8326167529499f94d24a1a86827a9879fd..6b48af3bf4b3287810498cc0f883e266f483ae5b 100644 (file)
@@ -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;
index 002a1ba761def75d9692c3b8215ca63220f86d80..44f356ceb02a2235eb7dc873d842c0d0f3ef3512 100644 (file)
@@ -24,6 +24,7 @@
 #include <fcntl.h>
 #include <signal.h>
 #include <time.h>
+#include <sys/mount.h>
 
 #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);