186 lines
7.6 KiB
Python
186 lines
7.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Canonical ViperOS syscall table.
|
|
|
|
The kernel and vpsdk keep separate copies (vpsdk must not depend on VKernel),
|
|
so both files are generated from this list. Never edit the generated block
|
|
by hand:
|
|
|
|
# BEGIN GENERATED SYSCALL TABLE
|
|
...
|
|
# END GENERATED SYSCALL TABLE
|
|
|
|
Usage:
|
|
python Scripts/syscall_table.py --write # regenerate both files
|
|
python Scripts/syscall_table.py --check # fail if out of sync
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
|
|
TARGETS = [
|
|
ROOT / "VKernel" / "Kernel" / "intr" / "syscall.vp",
|
|
ROOT / "vpsdk" / "syscall.vp",
|
|
]
|
|
|
|
BEGIN = "# BEGIN GENERATED SYSCALL TABLE"
|
|
END = "# END GENERATED SYSCALL TABLE"
|
|
|
|
# (kind, payload...) kind: "section" | "entry"
|
|
# Entry numbers follow Linux x86-64; Linux calls we do not implement yet are
|
|
# simply absent (the dispatcher returns -ENOSYS for unknown numbers).
|
|
TABLE = [
|
|
("section", "Linux 对齐段(号 = Linux x86-64 的号)"),
|
|
("entry", "READ", 0, "read(fd, buf, count)"),
|
|
("entry", "WRITE", 1, "write(fd, buf, count)"),
|
|
("entry", "OPEN", 2, "open(path, flags) - Linux O_*"),
|
|
("entry", "CLOSE", 3, "close(fd)"),
|
|
("entry", "STAT", 4, "stat(path, fileinfo*) - legacy struct"),
|
|
("entry", "FSTAT", 5, "fstat(fd, struct stat*)"),
|
|
("entry", "POLL", 7, "poll(fds, nfds, timeout) - stub 0"),
|
|
("entry", "SEEK", 8, "lseek(fd, offset, whence) -> new offset"),
|
|
("entry", "MMAP", 9, "mmap(addr, len, prot, flags, fd, off)"),
|
|
("entry", "MPROTECT", 10, "mprotect(addr, len, prot)"),
|
|
("entry", "MUNMAP", 11, "munmap(addr, len)"),
|
|
("entry", "BRK", 12, "brk(addr) -> new break"),
|
|
("entry", "RT_SIGACTION", 13, "rt_sigaction() - bookkeeping"),
|
|
("entry", "RT_SIGPROCMASK", 14, "rt_sigprocmask() - bookkeeping"),
|
|
("entry", "RT_SIGRETURN", 15, "rt_sigreturn()"),
|
|
("entry", "IOCTL", 16, "ioctl(fd, request, arg)"),
|
|
("entry", "PREAD64", 17, "pread64(fd, buf, count, offset)"),
|
|
("entry", "PWRITE64", 18, "pwrite64(fd, buf, count, offset)"),
|
|
("entry", "READV", 19, "readv(fd, iov, iovcnt)"),
|
|
("entry", "WRITEV", 20, "writev(fd, iov, iovcnt)"),
|
|
("entry", "ACCESS", 21, "access(path, mode)"),
|
|
("entry", "PIPE", 22, "pipe(int[2])"),
|
|
("entry", "YIELD", 24, "sched_yield()"),
|
|
("entry", "MREMAP", 25, "mremap(old, oldsz, newsz, flags, newaddr)"),
|
|
("entry", "MADVISE", 28, "madvise(addr, len, advice)"),
|
|
("entry", "DUP", 32, "dup(fd)"),
|
|
("entry", "DUP2", 33, "dup2(oldfd, newfd)"),
|
|
("entry", "NANOSLEEP", 35, "nanosleep(req, rem)"),
|
|
("entry", "GETPID", 39, "getpid()"),
|
|
("entry", "CLONE", 56, "clone(flags, stack, ptid, ctid, tls)"),
|
|
("entry", "FORK", 57, "fork() - copy address space"),
|
|
("entry", "SPAWN", 59, "execve(path, argv, envp)"),
|
|
("entry", "THREAD_EXIT", 60, "exit(): retire current thread"),
|
|
("entry", "WAIT4", 61, "wait4(pid, status, options, rusage)"),
|
|
("entry", "KILL", 62, "kill(pid, sig) - bookkeeping"),
|
|
("entry", "UNAME", 63, "uname(utsname*)"),
|
|
("entry", "FCNTL", 72, "fcntl(fd, cmd, arg)"),
|
|
("entry", "GETCWD", 79, "getcwd(buf, size)"),
|
|
("entry", "CHDIR", 80, "chdir(path)"),
|
|
("entry", "RENAME", 82, "rename(old, new)"),
|
|
("entry", "MKDIR", 83, "mkdir(path)"),
|
|
("entry", "RMDIR", 84, "rmdir(path)"),
|
|
("entry", "REMOVE", 87, "unlink(path)"),
|
|
("entry", "READLINK", 89, "readlink(path, buf, size) - no symlinks"),
|
|
("entry", "GETUID", 102, "getuid()"),
|
|
("entry", "GETGID", 104, "getgid()"),
|
|
("entry", "GETEUID", 107, "geteuid()"),
|
|
("entry", "GETEGID", 108, "getegid()"),
|
|
("entry", "GETTIMEOFDAY", 96, "gettimeofday(tv, tz)"),
|
|
("entry", "GETPPID", 110, "getppid()"),
|
|
("entry", "ARCH_PRCTL", 158, "arch_prctl(code, addr)"),
|
|
("entry", "REBOOT_LINUX", 169, "reboot(magic1, magic2, cmd, arg)"),
|
|
("entry", "GETTID", 186, "gettid()"),
|
|
("entry", "FUTEX", 202, "futex(uaddr, op, val, timeout)"),
|
|
("entry", "GETDENTS64", 217, "getdents64(fd, buf, count)"),
|
|
("entry", "SET_TID_ADDRESS", 218, "set_tid_address(tidptr)"),
|
|
("entry", "CLOCK_GETTIME", 228, "clock_gettime(clockid, timespec*)"),
|
|
("entry", "CLOCK_GETRES", 229, "clock_getres(clockid, timespec*)"),
|
|
("entry", "EXIT", 231, "exit_group(): terminate all threads"),
|
|
("entry", "OPENAT", 257, "openat(dirfd, path, flags, mode)"),
|
|
("entry", "NEWFSTATAT", 262, "newfstatat(dirfd, path, stat*, flags)"),
|
|
("entry", "UNLINKAT", 263, "unlinkat(dirfd, path, flags)"),
|
|
("entry", "READLINKAT", 267, "readlinkat(dirfd, path, buf, size)"),
|
|
("entry", "FACCESSAT", 269, "faccessat(dirfd, path, mode, flags)"),
|
|
("entry", "SET_ROBUST_LIST", 273, "set_robust_list(head, len)"),
|
|
("entry", "DUP3", 292, "dup3(oldfd, newfd, flags)"),
|
|
("entry", "PIPE2", 293, "pipe2(int[2], flags)"),
|
|
("entry", "PRLIMIT64", 302, "prlimit64(pid, resource, new, old)"),
|
|
("entry", "GETRANDOM", 318, "getrandom(buf, len, flags)"),
|
|
("entry", "STATX", 332, "statx(...) - -ENOSYS, glibc falls back"),
|
|
("entry", "RSEQ", 334, "rseq(rseq, len, flags) - -ENOSYS"),
|
|
("section", "临时私有段(0x1000+):Linux 无对应,逐条迁出"),
|
|
("entry", "LOAD_SO", 0x1006, "TODO(userspace): dynamic library loading"),
|
|
("entry", "SO_CALL1", 0x1007, "TODO(userspace): dynamic library call"),
|
|
("entry", "REBOOT", 0x1008, "TODO(linux): reboot(169)"),
|
|
("entry", "SHUTDOWN", 0x1009, "TODO(linux): reboot(RB_POWER_OFF)"),
|
|
("entry", "SPAWN_PROC", 0x100A, "TODO(userspace): Terminal run helper"),
|
|
("entry", "THREAD_CREATE_OLD", 0x100B, "TODO(userspace): ViperOS thread_create"),
|
|
]
|
|
|
|
|
|
def render() -> str:
|
|
out = ["enum Syscall:"]
|
|
for item in TABLE:
|
|
if item[0] == "section":
|
|
out.append(f" # ---- {item[1]} ----")
|
|
continue
|
|
_, name, num, comment = item
|
|
value = f"0x{num:04X}" if num >= 0x1000 else f"{num}"
|
|
out.append(f" {name:<18}= {value:<7}# {comment}")
|
|
return "\n".join(out) + "\n"
|
|
|
|
|
|
def split_lines(text: str):
|
|
"""Split keeping line endings (the tree mixes CRLF and a few LF lines)."""
|
|
return text.splitlines(keepends=True)
|
|
|
|
|
|
def replace_block(text: str) -> str:
|
|
lines = split_lines(text)
|
|
b = e = -1
|
|
for i, line in enumerate(lines):
|
|
stripped = line.strip()
|
|
if stripped == BEGIN:
|
|
b = i
|
|
elif stripped == END:
|
|
e = i
|
|
break
|
|
if b < 0 or e < 0 or e <= b:
|
|
raise SystemExit(f"markers not found: {BEGIN} / {END}")
|
|
newline = "\r\n" if lines[b].endswith("\r\n") else "\n"
|
|
block = [ln + newline for ln in render().splitlines()]
|
|
return "".join(lines[: b + 1] + block + lines[e:])
|
|
|
|
|
|
def main() -> int:
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("--check", action="store_true")
|
|
ap.add_argument("--write", action="store_true")
|
|
args = ap.parse_args()
|
|
if not args.check and not args.write:
|
|
ap.error("pass --check or --write")
|
|
|
|
stale = []
|
|
for path in TARGETS:
|
|
if not path.exists():
|
|
print(f"[syscall] missing {path}")
|
|
return 1
|
|
with open(path, encoding="utf-8", newline="") as fh:
|
|
old = fh.read()
|
|
new = replace_block(old)
|
|
if new != old:
|
|
stale.append(path)
|
|
if args.write:
|
|
with open(path, "w", encoding="utf-8", newline="") as fh:
|
|
fh.write(new)
|
|
print(f"[syscall] updated {path.relative_to(ROOT)}")
|
|
else:
|
|
print(f"[syscall] ok {path.relative_to(ROOT)}")
|
|
|
|
if args.check and stale:
|
|
print("[syscall] out of sync; run: python Scripts/syscall_table.py --write")
|
|
return 1
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|