Initial commit: Schunix as it stands before the SchOS rename
An x86-64 operating system built from xv6, now largely rewritten: SMP, a copy-on-write root filesystem (SchFS), PCI/USB/virtio drivers, a TTF rasteriser, and a Linux-numbered syscall ABI. No history before this point -- the tree was never under version control. This commit exists so the rename that follows has something to undo to.
This commit is contained in:
commit
d0f7acf9eb
275 changed files with 51417 additions and 0 deletions
124
cmd/init/main.c
Normal file
124
cmd/init/main.c
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Schunix — minimal init (PID 1)
|
||||
|
||||
#include "types.h"
|
||||
#include "user.h"
|
||||
#include "fcntl.h"
|
||||
|
||||
static void
|
||||
xputs(int fd, const char *s)
|
||||
{
|
||||
int n = 0;
|
||||
while (s[n]) n++;
|
||||
write(fd, (void *)s, n);
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
if (getpid() != 1)
|
||||
exit();
|
||||
|
||||
// Open console as fd 0; dup to fd 1 (stdout) and fd 2 (stderr).
|
||||
if (open("console", O_RDWR) < 0) {
|
||||
mknod("console", 1, 1);
|
||||
open("console", O_RDWR);
|
||||
}
|
||||
dup(0);
|
||||
dup(0);
|
||||
|
||||
// --- /dev ------------------------------------------------------------
|
||||
// Minor numbers under major 1 follow Linux's mem-major layout where it
|
||||
// costs nothing (null=2, zero=5, full=7, random=8, urandom=9).
|
||||
// /dev/hole (was minor 4) is gone: it backed an abandoned experiment and
|
||||
// nothing has referenced it since.
|
||||
mkdir("/dev");
|
||||
mknod("/dev/console", 1, 1);
|
||||
mknod("/dev/null", 1, 2);
|
||||
mknod("/dev/keyboard", 1, 3);
|
||||
mknod("/dev/zero", 1, 5);
|
||||
mknod("/dev/full", 1, 7);
|
||||
mknod("/dev/random", 1, 8);
|
||||
mknod("/dev/urandom", 1, 9);
|
||||
mknod("/dev/fb0", 2, 0);
|
||||
mknod("/dev/mouse", 3, 1);
|
||||
mknod("/dev/tty", 1, 1); // alias for console — must pass TCGETS ioctl
|
||||
mknod("/dev/ttyS0", 4, 64);
|
||||
mknod("/dev/stdin", 1, 1);
|
||||
mknod("/dev/stdout", 1, 1);
|
||||
mknod("/dev/stderr", 1, 1);
|
||||
|
||||
// Raw input events, Linux evdev layout (kernel/dev/input.c). /dev/keyboard
|
||||
// and /dev/mouse above are the old character-and-position interfaces; these
|
||||
// are the ones with key releases and button transitions, which is what a
|
||||
// game or a compositor needs and what neither of the others can express.
|
||||
mkdir("/dev/input");
|
||||
mknod("/dev/input/event0", 7, 0); // keyboard
|
||||
mknod("/dev/input/event1", 7, 1); // mouse
|
||||
|
||||
// --- /proc -----------------------------------------------------------
|
||||
// Synthesised status files, major 6 (kernel/dev/procfs.c). These are the
|
||||
// global ones; per-process /proc/<pid>/ directories need synthetic
|
||||
// directory support in the filesystem, which does not exist yet.
|
||||
mkdir("/proc");
|
||||
// /proc is a real filesystem now (kernel/fs/procfs.c), not a handful of
|
||||
// mknod'd nodes: it has to be, because one directory per process cannot be
|
||||
// created ahead of time. This is what makes `ps` and `top` work.
|
||||
//
|
||||
// The mknod'd global files below still happen, and are simply covered by
|
||||
// the mount. They stay for now so that a failure here degrades to the old
|
||||
// behaviour instead of losing /proc entirely.
|
||||
mount("proc", "/proc", "proc", 0, 0);
|
||||
mknod("/proc/meminfo", 6, 1);
|
||||
mknod("/proc/uptime", 6, 2);
|
||||
mknod("/proc/cpuinfo", 6, 3);
|
||||
mknod("/proc/version", 6, 4);
|
||||
mknod("/proc/stat", 6, 5);
|
||||
mknod("/proc/loadavg", 6, 6);
|
||||
mknod("/proc/mounts", 6, 7);
|
||||
mknod("/proc/filesystems", 6, 8);
|
||||
// SchFS volume summary: label, generation, free space, and the root
|
||||
// directory. Reachable whether or not the volume is mounted into the
|
||||
// namespace, which is what makes it useful when a mount has gone wrong.
|
||||
mknod("/proc/schfs", 6, 9);
|
||||
// Write 'c' here to crash on purpose. The crash screen is otherwise the
|
||||
// one part of the system that can only be seen by having a bug.
|
||||
mknod("/proc/sysrq", 6, 10);
|
||||
mknod("/proc/pci", 6, 11);
|
||||
mknod("/proc/interrupts", 6, 12);
|
||||
|
||||
mkdir("/sys");
|
||||
|
||||
xputs(1, "\nSchunix\n");
|
||||
xputs(1, "init: ready (pid 1)\n");
|
||||
|
||||
for (;;) {
|
||||
int pid = fork();
|
||||
if (pid < 0) {
|
||||
xputs(2, "init: fork failed\n");
|
||||
sleep(100);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
// exec.c auto-enables Linux ABI for musl binaries (entry >= 0x100000).
|
||||
// Do NOT call enable_linux_abi() here — it corrupts Schunix syscall
|
||||
// numbers for the exec/exit calls that follow in this child.
|
||||
// Standardized naming: the shell is always /bin/sh, regardless of
|
||||
// which implementation backs it (dash, mksh, etc.) — no ksh/mksh/
|
||||
// other aliases are looked up here.
|
||||
static char *argv[] = { "sh", 0 };
|
||||
exec("/bin/sh", argv);
|
||||
xputs(2, "init: no shell found; place sh in /bin\n");
|
||||
exit();
|
||||
}
|
||||
|
||||
// Reap zombies; the loop restarts the shell when it exits.
|
||||
int wpid;
|
||||
while ((wpid = wait()) >= 0 && wpid != pid)
|
||||
;
|
||||
// Brief pause before restarting so we don't spin on a missing shell.
|
||||
sleep(100);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in a new issue