// SPDX-License-Identifier: Apache-2.0 // SchOS — POSIX-compatibility types used by kernel syscall handlers. #pragma once #include "types.h" #include "date.h" struct iovec { void *iov_base; uint64 iov_len; }; // Linux's IOV_MAX. readv/writev used to cap iovcnt at 16 -- which is legal, // since POSIX only requires 16 -- and returned EINVAL above it. But programs // are written against the platform they run on, and on Linux that limit is // 1024: toybox's `yes` builds a 256-entry iovec and writev()s it in a loop, // so `yes | head -2` failed with "Invalid argument" before producing a single // byte. Nothing here costs per-entry memory; the count is just a loop bound. #define UIO_MAXIOV 1024 // Simplified termios (matches Linux x86_64 layout enough for basic use). struct termios { uint32 c_iflag; uint32 c_oflag; uint32 c_cflag; uint32 c_lflag; uint8 c_line; uint8 c_cc[19]; uint32 c_ispeed; uint32 c_ospeed; }; // Terminal flags, with Linux's values. The kernel honours the ones marked // below; the rest are accepted and stored so a program that sets them and // reads them back sees what it wrote, which is what cfmakeraw() and every // line-editing library actually check. // // c_iflag #define IGNBRK 0000001 #define BRKINT 0000002 #define IGNPAR 0000004 #define PARMRK 0000010 #define INPCK 0000020 #define ISTRIP 0000040 // honoured: strip the eighth bit #define INLCR 0000100 // honoured: NL -> CR on input #define IGNCR 0000200 // honoured: drop CR #define ICRNL 0000400 // honoured: CR -> NL on input #define IUCLC 0001000 #define IXON 0002000 #define IXANY 0004000 #define IXOFF 0010000 #define IMAXBEL 0020000 #define IUTF8 0040000 // c_oflag #define OPOST 0000001 // honoured: enable output processing #define OLCUC 0000002 #define ONLCR 0000004 // honoured: NL -> CR NL on output #define OCRNL 0000010 #define ONOCR 0000020 #define ONLRET 0000040 // c_cflag #define CS8 0000060 #define CREAD 0000200 #define HUPCL 0002000 #define CLOCAL 0004000 // c_lflag #define ISIG 0000001 // honoured: INTR/QUIT/SUSP generate signals #define ICANON 0000002 // honoured: line-at-a-time with editing #define ECHO 0000010 // honoured #define ECHOE 0000020 // honoured: ERASE rubs the character out #define ECHOK 0000040 #define ECHONL 0000100 // honoured: echo NL even with ECHO off #define NOFLSH 0000200 #define TOSTOP 0000400 #define IEXTEN 0100000 // c_cc indices (Linux order). VMIN/VTIME share slots with VEOF/VEOL, which is // why they are only meaningful in the mode the other pair is not. #define VINTR 0 #define VQUIT 1 #define VERASE 2 #define VKILL 3 #define VEOF 4 #define VTIME 5 #define VMIN 6 #define VSWTC 7 #define VSTART 8 #define VSTOP 9 #define VSUSP 10 #define VEOL 11 #define VREPRINT 12 #define VDISCARD 13 #define VWERASE 14 #define VLNEXT 15 #define VEOL2 16 struct winsize { uint16 ws_row; uint16 ws_col; uint16 ws_xpixel; uint16 ws_ypixel; }; struct rlimit { uint64 rlim_cur; uint64 rlim_max; }; // Linux ioctl codes we handle. #define TCGETS 0x5401 #define TCSETS 0x5402 #define TCSETSW 0x5403 #define TCSETSF 0x5404 #define TCFLSH 0x540B // TCFLSH queue selectors. Not a pointer -- these are the argument itself. #define TCIFLUSH 0 #define TCOFLUSH 1 #define TCIOFLUSH 2 #define TIOCGPGRP 0x540F #define TIOCSPGRP 0x5410 #define TIOCGWINSZ 0x5413 #define TIOCSWINSZ 0x5414 #define TIOCSCTTY 0x540E // Virtual terminal control, Linux's numbers. The argument to VT_ACTIVATE and // VT_WAITACTIVE is a 1-based terminal number passed by value, not a pointer. #define VT_OPENQRY 0x5600 // first free terminal, out through a pointer #define VT_GETMODE 0x5601 #define VT_SETMODE 0x5602 #define VT_GETSTATE 0x5603 // struct vt_stat #define VT_ACTIVATE 0x5606 #define VT_WAITACTIVE 0x5607 // VT_SETMODE modes. VT_AUTO is the kernel switching on its own; VT_PROCESS // means a program has taken switching over and the kernel must keep its hands // off the keyboard. #define VT_AUTO 0x00 #define VT_PROCESS 0x01 #define VT_ACKACQ 0x02 // VT_SETCHORD / VT_GETCHORD -- which key combination the kernel switches on. // SchOS's own, not Linux's: Linux hardcodes Ctrl+Alt+F and nobody has ever // needed to move it, because Linux is the host. A guest does need to move it, // because the right answer depends entirely on what the host grabs first -- // and that is not something the guest can discover. #define VT_GETCHORD 0x5620 #define VT_SETCHORD 0x5621 // Modifier bits, matched exactly. These mirror kernel/dev/kbd.h's values so // that userspace and the keyboard driver cannot drift apart. #define VTC_SHIFT 0x01 // kbd.h SHIFT (1<<0) #define VTC_CTRL 0x02 // kbd.h CTL (1<<1) #define VTC_ALT 0x04 // kbd.h ALT (1<<2) #define VTC_RALT 0x80 // kbd.h RALT (1<<7) -- NOT (1<<3); that is // CAPSLOCK, and bits 3..6 are the other locks // and the E0 prefix flag // Well-known base scancodes for the `base` field below. #define VTC_BASE_F1 0x3B // F1..F6 #define VTC_BASE_1 0x02 // the number row, 1..6 struct vt_chord { uint16 mods; // exactly these modifiers held, and no others uint16 base; // scancode of the key meaning terminal 1 }; struct vt_mode { char mode; // VT_AUTO or VT_PROCESS char waitv; // unused here short relsig; // signal on release -- not delivered yet short acqsig; // signal on acquire -- not delivered yet short frsig; // unused }; struct vt_stat { uint16 v_active; // active terminal, 1-based uint16 v_signal; // unused; Linux keeps it for VT_SETMODE uint16 v_state; // bitmask of terminals in use, bit 1 = tty1 }; #define TIOCGSERIAL 0x541E #define FIONREAD 0x541B // FICLONE: share another file's data blocks with this one. The argument is a // file descriptor, not a pointer. Linux's value, so `cp --reflink` works. #define FICLONE 0x40049409 #define TIOCEXCL 0x540C #define TIOCNXCL 0x540D // arch_prctl commands #define ARCH_SET_GS 0x1001 #define ARCH_SET_FS 0x1002 #define ARCH_GET_FS 0x1003 #define ARCH_GET_GS 0x1004 // clone flags (subset) #define CLONE_VM 0x00000100 #define CLONE_THREAD 0x00010000 #define CLONE_SIGHAND 0x00000800 // futex ops #define FUTEX_WAIT 0 #define FUTEX_WAKE 1 #define FUTEX_WAIT_PRIVATE 128 #define FUTEX_WAKE_PRIVATE 129 // Resource limit codes (POSIX) #define RLIMIT_AS 9 #define RLIMIT_STACK 3 #define RLIMIT_NOFILE 7 // clock IDs #define CLOCK_REALTIME 0 #define CLOCK_MONOTONIC 1 struct timespec { long tv_sec; long tv_nsec; }; struct itimerval { struct timeval it_interval; struct timeval it_value; }; struct rusage { struct timeval ru_utime; struct timeval ru_stime; long ru_maxrss; long ru_ixrss; long ru_idrss; long ru_isrss; long ru_minflt; long ru_majflt; long ru_nswap; long ru_inblock; long ru_oublock; long ru_msgsnd; long ru_msgrcv; long ru_nsignals; long ru_nvcsw; long ru_nivcsw; }; struct tms { long tms_utime; long tms_stime; long tms_cutime; long tms_cstime; }; struct sysinfo { long uptime; uint64 loads[3]; uint64 totalram; uint64 freeram; uint64 sharedram; uint64 bufferram; uint64 totalswap; uint64 freeswap; uint16 procs; uint16 pad; uint32 pad2; uint64 totalhigh; uint64 freehigh; uint32 mem_unit; char _f[8]; }; // Must match Linux's x86-64 struct statfs field for field, because the programs // reading it were compiled against Linux's. // // f_fsid is the trap. Linux's fsid_t is `struct { int val[2]; }` -- eight bytes // in total, not two eight-byte words -- and declaring it as int64[2] made this // struct one slot too long from f_fsid onwards. Everything after it landed in // the wrong place: userland read f_frsize out of f_namelen and got 255, so df // computed its block counts in units of 255 bytes and reported a 32 MB root // filesystem as 1992 KB. It went unnoticed for as long as it did because every // field here used to be an invented constant, so the numbers were meaningless // whichever slot they came from. struct statfs { int64 f_type; int64 f_bsize; int64 f_blocks; int64 f_bfree; int64 f_bavail; int64 f_files; int64 f_ffree; int32 f_fsid[2]; int64 f_namelen; int64 f_frsize; int64 f_flags; int64 f_spare[4]; }; // at-syscall dirfd sentinel #define AT_FDCWD (-100) #define AT_REMOVEDIR 0x200 #define AT_SYMLINK_NOFOLLOW 0x100 #define AT_EMPTY_PATH 0x1000 #define AT_NO_AUTOMOUNT 0x800 // prctl options #define PR_SET_NAME 15 #define PR_GET_NAME 16 #define PR_SET_DUMPABLE 4 #define PR_GET_DUMPABLE 3 // signal numbers (Linux x86_64 values), used by kill dispatch and // default-action classification in sigsend() #define SIGHUP 1 #define SIGINT 2 #define SIGQUIT 3 #define SIGILL 4 #define SIGABRT 6 #define SIGBUS 7 #define SIGFPE 8 #define SIGKILL 9 #define SIGUSR1 10 #define SIGSEGV 11 #define SIGUSR2 12 #define SIGPIPE 13 #define SIGALRM 14 #define SIGTERM 15 #define SIGCHLD 17 #define SIGCONT 18 #define SIGSTOP 19 // Job-control and the remaining standard signals. A shell needs the TSTP/ // TTIN/TTOU trio to implement ^Z and background-job terminal access at all; // they were simply absent, so any reference to them failed to compile. #define SIGTRAP 5 #define SIGTSTP 20 #define SIGTTIN 21 #define SIGTTOU 22 #define SIGURG 23 #define SIGXCPU 24 #define SIGXFSZ 25 #define SIGVTALRM 26 #define SIGPROF 27 #define SIGWINCH 28 #define SIGIO 29 #define SIGPWR 30 #define SIGSYS 31 // getrusage who #define RUSAGE_SELF 0 #define RUSAGE_CHILDREN (-1) // fallocate mode #define FALLOC_FL_KEEP_SIZE 1 // poll(2) event bits (Linux values) #define POLLIN 0x001 #define POLLPRI 0x002 #define POLLOUT 0x004 #define POLLERR 0x008 #define POLLHUP 0x010 #define POLLNVAL 0x020 struct pollfd { int fd; short events; short revents; };