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
451
kernel/sys/sys_proc.c
Normal file
451
kernel/sys/sys_proc.c
Normal file
|
|
@ -0,0 +1,451 @@
|
|||
#include "types.h"
|
||||
#include "defs.h"
|
||||
#include "param.h"
|
||||
#include "memlayout.h"
|
||||
#include "mmu.h"
|
||||
#include "proc.h"
|
||||
#include "x86.h"
|
||||
#include "syscall.h"
|
||||
#include "posix.h"
|
||||
#include "uaccess.h"
|
||||
#include "errno.h"
|
||||
|
||||
addr_t sys_fork(void) { return fork(); }
|
||||
addr_t sys_wait(void) { return wait(); }
|
||||
|
||||
// _exit(status)/exit_group(status): the low 8 bits of the argument are what
|
||||
// wait() reports back through WEXITSTATUS.
|
||||
addr_t
|
||||
sys_exit(void)
|
||||
{
|
||||
int code = 0;
|
||||
argint(0, &code);
|
||||
exit(W_EXITCODE(code, 0));
|
||||
return 0;
|
||||
}
|
||||
addr_t sys_exit_group(void) { return sys_exit(); }
|
||||
|
||||
|
||||
addr_t
|
||||
sys_kill(void)
|
||||
{
|
||||
int pid, sig;
|
||||
argint(0, &pid);
|
||||
argint(1, &sig);
|
||||
|
||||
// POSIX target selection:
|
||||
// pid > 0 -> that process
|
||||
// pid == 0 -> every process in the caller's own group
|
||||
// pid == -1 -> every process we may signal (approximated as our group)
|
||||
// pid < -1 -> the process group with id -pid
|
||||
if (pid == 0 || pid == -1)
|
||||
return sigsend_pgrp(myproc()->pgid, sig) < 0 ? -ESRCH : 0;
|
||||
if (pid < -1)
|
||||
return sigsend_pgrp(-pid, sig) < 0 ? -ESRCH : 0;
|
||||
|
||||
// sig == 0: existence check only
|
||||
if (sig == 0)
|
||||
return proc_exists(pid) ? 0 : -ESRCH;
|
||||
|
||||
// Raise the signal for real: pending bit + wakeup, handler delivery on
|
||||
// the target's next syscall boundary, default action if unhandled.
|
||||
return sigsend(pid, sig) < 0 ? -ESRCH : 0;
|
||||
}
|
||||
|
||||
addr_t sys_getpid(void) { return myproc()->pid; }
|
||||
addr_t sys_getppid(void) { return myproc()->parent ? myproc()->parent->pid : 1; }
|
||||
addr_t sys_gettid(void) { return myproc()->pid; } // single-threaded: tid == pid
|
||||
|
||||
addr_t
|
||||
sys_waitpid(void)
|
||||
{
|
||||
int pid, options;
|
||||
addr_t statusp;
|
||||
// status is optional (NULL is standard, valid usage — waitpid(pid, NULL,
|
||||
// WNOHANG) — so this must NOT go through argptr(), which rejects a NULL/
|
||||
// unmapped pointer outright).
|
||||
if (argint(0, &pid) < 0 || argaddr(1, &statusp) < 0 || argint(2, &options) < 0)
|
||||
return -1;
|
||||
int status;
|
||||
int wpid = waitpid(pid, &status, options);
|
||||
if (wpid > 0 && statusp)
|
||||
put_user(status, statusp);
|
||||
return wpid;
|
||||
}
|
||||
|
||||
addr_t
|
||||
sys_wait4(void)
|
||||
{
|
||||
int pid, options;
|
||||
addr_t statusp;
|
||||
argint(0, &pid);
|
||||
argaddr(1, &statusp);
|
||||
argint(2, &options);
|
||||
int status;
|
||||
int wpid = waitpid(pid, &status, options);
|
||||
if (wpid <= 0)
|
||||
return wpid;
|
||||
if (statusp)
|
||||
put_user(status, statusp);
|
||||
return wpid;
|
||||
}
|
||||
|
||||
addr_t
|
||||
sys_clone(void)
|
||||
{
|
||||
int flags;
|
||||
argint(0, &flags);
|
||||
if (flags & (CLONE_VM | CLONE_THREAD | CLONE_SIGHAND))
|
||||
return -ENOSYS;
|
||||
return fork();
|
||||
}
|
||||
|
||||
addr_t
|
||||
sys_sleep(void)
|
||||
{
|
||||
int n;
|
||||
uint ticks0;
|
||||
if (argint(0, &n) < 0)
|
||||
return -1;
|
||||
acquire(&tickslock);
|
||||
ticks0 = ticks;
|
||||
while (ticks - ticks0 < (uint)n) {
|
||||
if (myproc()->killed) { release(&tickslock); return -1; }
|
||||
sleep(&ticks, &tickslock);
|
||||
}
|
||||
release(&tickslock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
addr_t
|
||||
sys_uptime(void)
|
||||
{
|
||||
uint xticks;
|
||||
acquire(&tickslock);
|
||||
xticks = ticks;
|
||||
release(&tickslock);
|
||||
return xticks;
|
||||
}
|
||||
|
||||
addr_t sys_reboot(void)
|
||||
{
|
||||
cprintf("System is rebooting...\n");
|
||||
outb(0xCF9, 0x06);
|
||||
outb(0x64, 0xFE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
addr_t sys_shutdown(void)
|
||||
{
|
||||
cprintf("System is shutting down...\n");
|
||||
outw(0x604, 0x2000);
|
||||
outw(0xB004, 0x2000);
|
||||
outw(0x4004, 0x3400);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// --- Sessions and process groups ---------------------------------------
|
||||
// Job control is defined entirely in terms of these. They used to be stubs
|
||||
// returning the caller's own pid, which made every process look like its own
|
||||
// group leader and left a shell's wait loop unable to make progress.
|
||||
|
||||
addr_t sys_setsid(void) { return proc_setsid(); }
|
||||
|
||||
addr_t
|
||||
sys_getsid(void)
|
||||
{
|
||||
int pid;
|
||||
argint(0, &pid);
|
||||
if (pid == 0 || pid == myproc()->pid)
|
||||
return myproc()->sid;
|
||||
return proc_exists(pid) ? (addr_t)myproc()->sid : (addr_t)-ESRCH;
|
||||
}
|
||||
|
||||
addr_t
|
||||
sys_getpgid(void)
|
||||
{
|
||||
int pid;
|
||||
argint(0, &pid);
|
||||
if (pid == 0 || pid == myproc()->pid)
|
||||
return myproc()->pgid;
|
||||
int g = proc_pgid(pid);
|
||||
return g < 0 ? (addr_t)-ESRCH : (addr_t)g;
|
||||
}
|
||||
|
||||
addr_t
|
||||
sys_setpgid(void)
|
||||
{
|
||||
int pid, pgid;
|
||||
argint(0, &pid);
|
||||
argint(1, &pgid);
|
||||
return proc_setpgid(pid, pgid);
|
||||
}
|
||||
|
||||
addr_t sys_getpgrp(void) { return myproc()->pgid; }
|
||||
|
||||
// --- User and group identity -------------------------------------------
|
||||
// Tracked for real now. Nothing *enforces* permissions with these yet -- the
|
||||
// on-disk format has no owner field until SchFS -- but they are no longer
|
||||
// invented, so getuid() after setuid() reports what actually happened.
|
||||
|
||||
addr_t sys_getuid(void) { return myproc()->uid; }
|
||||
addr_t sys_geteuid(void) { return myproc()->euid; }
|
||||
addr_t sys_getgid(void) { return myproc()->gid; }
|
||||
addr_t sys_getegid(void) { return myproc()->egid; }
|
||||
|
||||
// Privileged (euid 0) callers may set any id; an unprivileged caller may only
|
||||
// switch between its real and saved ids. Standard POSIX rule.
|
||||
addr_t
|
||||
sys_setuid(void)
|
||||
{
|
||||
int uid;
|
||||
argint(0, &uid);
|
||||
if (uid < 0)
|
||||
return -EINVAL;
|
||||
if (myproc()->euid == 0) {
|
||||
myproc()->uid = myproc()->euid = myproc()->suid = (uint)uid;
|
||||
return 0;
|
||||
}
|
||||
if ((uint)uid != myproc()->uid && (uint)uid != myproc()->suid)
|
||||
return -EPERM;
|
||||
myproc()->euid = (uint)uid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
addr_t
|
||||
sys_setgid(void)
|
||||
{
|
||||
int gid;
|
||||
argint(0, &gid);
|
||||
if (gid < 0)
|
||||
return -EINVAL;
|
||||
if (myproc()->euid == 0) {
|
||||
myproc()->gid = myproc()->egid = myproc()->sgid = (uint)gid;
|
||||
return 0;
|
||||
}
|
||||
if ((uint)gid != myproc()->gid && (uint)gid != myproc()->sgid)
|
||||
return -EPERM;
|
||||
myproc()->egid = (uint)gid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
addr_t sys_umask(void) { return 022; }
|
||||
|
||||
addr_t
|
||||
sys_setreuid(void)
|
||||
{
|
||||
int ruid, euid;
|
||||
argint(0, &ruid); argint(1, &euid);
|
||||
if (myproc()->euid != 0)
|
||||
return -EPERM;
|
||||
if (ruid >= 0) myproc()->uid = (uint)ruid;
|
||||
if (euid >= 0) myproc()->euid = (uint)euid;
|
||||
myproc()->suid = myproc()->euid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
addr_t
|
||||
sys_setregid(void)
|
||||
{
|
||||
int rgid, egid;
|
||||
argint(0, &rgid); argint(1, &egid);
|
||||
if (myproc()->euid != 0)
|
||||
return -EPERM;
|
||||
if (rgid >= 0) myproc()->gid = (uint)rgid;
|
||||
if (egid >= 0) myproc()->egid = (uint)egid;
|
||||
myproc()->sgid = myproc()->egid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
addr_t
|
||||
sys_setresuid(void)
|
||||
{
|
||||
int r, e, sv;
|
||||
argint(0, &r); argint(1, &e); argint(2, &sv);
|
||||
if (myproc()->euid != 0)
|
||||
return -EPERM;
|
||||
if (r >= 0) myproc()->uid = (uint)r;
|
||||
if (e >= 0) myproc()->euid = (uint)e;
|
||||
if (sv >= 0) myproc()->suid = (uint)sv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
addr_t
|
||||
sys_setresgid(void)
|
||||
{
|
||||
int r, e, sv;
|
||||
argint(0, &r); argint(1, &e); argint(2, &sv);
|
||||
if (myproc()->euid != 0)
|
||||
return -EPERM;
|
||||
if (r >= 0) myproc()->gid = (uint)r;
|
||||
if (e >= 0) myproc()->egid = (uint)e;
|
||||
if (sv >= 0) myproc()->sgid = (uint)sv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Linux-specific; the fs id follows the effective id here.
|
||||
addr_t sys_setfsuid(void) { return myproc()->euid; }
|
||||
addr_t sys_setfsgid(void) { return myproc()->egid; }
|
||||
|
||||
addr_t
|
||||
sys_getresuid(void)
|
||||
{
|
||||
addr_t rp, ep, sp;
|
||||
argaddr(0, &rp); argaddr(1, &ep); argaddr(2, &sp);
|
||||
if (rp) put_user(myproc()->uid, rp);
|
||||
if (ep) put_user(myproc()->euid, ep);
|
||||
if (sp) put_user(myproc()->suid, sp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
addr_t
|
||||
sys_getresgid(void)
|
||||
{
|
||||
addr_t rp, ep, sp;
|
||||
argaddr(0, &rp); argaddr(1, &ep); argaddr(2, &sp);
|
||||
if (rp) put_user(myproc()->gid, rp);
|
||||
if (ep) put_user(myproc()->egid, ep);
|
||||
if (sp) put_user(myproc()->sgid, sp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
addr_t sys_getgroups(void)
|
||||
{
|
||||
int size;
|
||||
argint(0, &size);
|
||||
return 0; // no supplementary groups
|
||||
}
|
||||
addr_t sys_setgroups(void) { return 0; }
|
||||
|
||||
// --- Process/scheduling extensions ---
|
||||
|
||||
addr_t sys_sched_yield(void) { return 0; }
|
||||
|
||||
addr_t sys_sched_getaffinity(void)
|
||||
{
|
||||
int pid, cpusetsize;
|
||||
addr_t maskp;
|
||||
argint(0, &pid); argint(1, &cpusetsize); argaddr(2, &maskp);
|
||||
if (maskp && cpusetsize > 0) {
|
||||
char *m = (char*)user_ptr(maskp, (uint64)cpusetsize);
|
||||
if (m) { memset(m, 0, cpusetsize); m[0] = 1; } // CPU 0 only
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
addr_t sys_sched_setaffinity(void) { return 0; }
|
||||
|
||||
addr_t sys_prctl(void)
|
||||
{
|
||||
int op;
|
||||
addr_t arg2;
|
||||
argint(0, &op);
|
||||
argaddr(1, &arg2);
|
||||
if (op == PR_SET_NAME) {
|
||||
char *name;
|
||||
if (argstr(1, &name) < 0) return -1;
|
||||
safestrcpy(myproc()->name, name, sizeof(myproc()->name));
|
||||
return 0;
|
||||
}
|
||||
if (op == PR_GET_NAME) {
|
||||
char *buf = (char*)user_ptr(arg2, 16);
|
||||
if (!buf) return -EFAULT;
|
||||
safestrcpy(buf, myproc()->name, 16);
|
||||
return 0;
|
||||
}
|
||||
return 0; // all other prctl ops: silently succeed
|
||||
}
|
||||
|
||||
addr_t sys_tgkill(void)
|
||||
{
|
||||
int tgid, tid, sig;
|
||||
argint(0, &tgid); argint(1, &tid); argint(2, &sig);
|
||||
// In our single-threaded model tgid == tid == pid.
|
||||
if (tgid <= 0) return 0;
|
||||
if (sig == 0) return proc_exists(tgid) ? 0 : -ESRCH;
|
||||
return sigsend(tgid, sig) < 0 ? -ESRCH : 0;
|
||||
}
|
||||
|
||||
addr_t sys_tkill(void)
|
||||
{
|
||||
int tid, sig;
|
||||
argint(0, &tid); argint(1, &sig);
|
||||
if (tid <= 0) return 0;
|
||||
if (sig == 0) return proc_exists(tid) ? 0 : -ESRCH;
|
||||
return sigsend(tid, sig) < 0 ? -ESRCH : 0;
|
||||
}
|
||||
|
||||
addr_t sys_pause(void)
|
||||
{
|
||||
// Sleep until next timer tick and return -EINTR (no real signal delivery).
|
||||
acquire(&tickslock);
|
||||
uint t0 = ticks;
|
||||
while (ticks == t0 && !myproc()->killed)
|
||||
sleep(&ticks, &tickslock);
|
||||
release(&tickslock);
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
addr_t sys_getrusage(void)
|
||||
{
|
||||
int who;
|
||||
struct rusage *ru;
|
||||
argint(0, &who);
|
||||
if (argptr(1, (char**)&ru, sizeof(*ru)) < 0) return -1;
|
||||
memset(ru, 0, sizeof(*ru));
|
||||
acquire(&tickslock);
|
||||
uint xt = ticks;
|
||||
release(&tickslock);
|
||||
ru->ru_utime.tv_sec = (long)(xt / 100);
|
||||
ru->ru_utime.tv_usec = (long)((xt % 100) * 10000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
addr_t sys_times(void)
|
||||
{
|
||||
addr_t bufaddr;
|
||||
argaddr(0, &bufaddr);
|
||||
if (bufaddr) {
|
||||
struct tms *t = (struct tms*)user_ptr(bufaddr, sizeof(*t));
|
||||
if (t) memset(t, 0, sizeof(*t));
|
||||
}
|
||||
acquire(&tickslock);
|
||||
uint xt = ticks;
|
||||
release(&tickslock);
|
||||
return (addr_t)xt; // return clock ticks since boot
|
||||
}
|
||||
|
||||
addr_t sys_sysinfo(void)
|
||||
{
|
||||
addr_t bufaddr;
|
||||
argaddr(0, &bufaddr);
|
||||
struct sysinfo *si = (struct sysinfo*)user_ptr(bufaddr, sizeof(*si));
|
||||
if (!si) return -EFAULT;
|
||||
memset(si, 0, sizeof(*si));
|
||||
acquire(&tickslock);
|
||||
uint xt = ticks;
|
||||
release(&tickslock);
|
||||
si->uptime = (long)(xt / 100);
|
||||
// Real values: PHYSTOP is the top of usable physical memory and the page
|
||||
// allocator knows exactly how much of it is still on the free list. These
|
||||
// used to be the constants 256MB/128MB, invented and always wrong.
|
||||
si->totalram = (uint64)PHYSTOP;
|
||||
si->freeram = kalloc_free_bytes();
|
||||
si->mem_unit = 1;
|
||||
si->procs = (uint16)proc_num();
|
||||
return 0;
|
||||
}
|
||||
|
||||
addr_t sys_waitid(void)
|
||||
{
|
||||
// Simplified: wait for any child, ignore idtype/id/options.
|
||||
int wpid = wait();
|
||||
if (wpid < 0) return -ECHILD;
|
||||
// siginfo_t pointer (arg 2) — zero-fill if provided.
|
||||
addr_t infop;
|
||||
argaddr(2, &infop);
|
||||
if (infop) {
|
||||
char *p = (char*)user_ptr(infop, 128); // sizeof(siginfo_t)
|
||||
if (p) memset(p, 0, 128);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in a new issue