SchOS/include/uapi/posix.h
Nexoniarz 54b25708c3 Demand paging, the RTL8168H, links that come up late, and Ctrl+Alt+F1..F12
- Anonymous memory can be reserved without being backed: large mappings,
  MAP_NORESERVE and PROT_NONE are recorded and each page appears, zeroed,
  on first touch -- from trap() for the program, from uva2ka() for the
  kernel on its behalf. WebKit reserves 4 GB at start and touches a sliver;
  backing it all failed with ENOMEM and Epiphany aborted.
- r8169: the 8168G generation and later (the laptop's 8168H, XID 541) are
  taken from the firmware's out-of-band mode, get their PLL powered, the
  receive gate opened, and their PHY reached through the OCP window. The
  PHY's power-down bit is cleared; the old code kept it while restarting
  autonegotiation. Untested on the hardware so far.
- The network thread follows each device's link into lwIP. The link was
  read once at attach, 0.02 s into boot; real autonegotiation takes
  seconds, so on hardware the interface stayed down for good.
- Twelve terminals, switched with Ctrl+Alt+F1..F12 by default: the keys X
  uses, so the console and the desktop agree. AltGr+F-key is gone from
  the defaults (chvt -c altgr+F brings it back).
- SO_PASSCRED on Unix sockets, with SCM_CREDENTIALS delivered by recvmsg.
  WebKit sets it on its IPC sockets and aborted when refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
2026-10-25 11:27:48 +01:00

451 lines
14 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
// SchOS — POSIX-compatibility types used by kernel syscall handlers.
#pragma once
#include "core/types.h"
#include "core/date.h"
// struct iovec is declared in two headers on purpose, and guarded so that
// including both is not an error.
//
// posix.h has it because readv/writev need it; this file has it because a
// userspace program including <socket.h> for sendmsg must get a complete
// struct msghdr without also having to know about a kernel header. Both
// definitions are identical and both are Linux's layout.
//
// The guard is not cosmetic. C23 permits redeclaring a struct with identical
// members and GCC 15 defaults to C23, so the duplicate was invisible on the
// gcc path -- while clang defaults to gnu17 and rejected it, which broke the
// one toolchain shell.nix exists to provide and which the UEFI loader needs.
#ifndef SCH_IOVEC_DEFINED
#define SCH_IOVEC_DEFINED
struct iovec {
void *iov_base;
uint64 iov_len;
};
#endif
// 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_RELDISP 0x5605 // by value: 1 release, 0 refuse, VT_ACKACQ
#define VT_ACTIVATE 0x5606
#define VT_WAITACTIVE 0x5607
#define VT_DISALLOCATE 0x5608
// The console's keyboard and display modes, which a display server sets on
// the terminal it takes: KD_GRAPHICS so the console stops drawing on it, and
// K_OFF so keys stop reaching its tty -- the server reads them from
// /dev/input instead. Linux's numbers.
#define KIOCSOUND 0x4B2F
#define KDMKTONE 0x4B30
#define KDGETLED 0x4B31
#define KDSETLED 0x4B32
#define KDGKBTYPE 0x4B33
#define KDSETMODE 0x4B3A
#define KDGETMODE 0x4B3B
#define KDGKBMODE 0x4B44
#define KDSKBMODE 0x4B45
#define KDGKBLED 0x4B64
#define KDSKBLED 0x4B65
#define KD_TEXT 0x00
#define KD_GRAPHICS 0x01
#define K_RAW 0x00
#define K_XLATE 0x01
#define K_MEDIUMRAW 0x02
#define K_UNICODE 0x03
#define K_OFF 0x04
#define KB_101 0x02
// 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<n> 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
// KB_GETLAYOUT / KB_SETLAYOUT / KB_LISTLAYOUT -- which keyboard layout the
// console uses. SchOS's own, and deliberately not Linux's KDGKBENT: that
// interface hands over one key of one table at a time and expects userspace to
// own the whole map, which means a `loadkeys` that ships its own data files and
// a boot that is broken until one is loaded. The layouts live in the kernel
// here, and userspace names the one it wants.
#define KB_GETLAYOUT 0x5622 // fill in the active layout
#define KB_SETLAYOUT 0x5623 // switch to the layout named in `name`
#define KB_LISTLAYOUT 0x5624 // describe layout `index`; -EINVAL past end
struct kb_layout {
uint16 index; // in for KB_LISTLAYOUT, out for KB_GETLAYOUT
char name[16]; // "us", "pl", "de"
char desc[96]; // human-readable, for `loadkeys -l`
};
// 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; see vt_switch()
short acqsig; // signal on acquire
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_EACCESS 0x200
#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
// sigprocmask(2)'s `how`. Linux's values. The kernel has always implemented
// these -- sys_sigprocmask() branches on 0, 1 and 2 with the names in comments
// -- but never named them, so anything outside the kernel had to spell the
// number and hope it had the right one.
#define SIG_BLOCK 0
#define SIG_UNBLOCK 1
#define SIG_SETMASK 2
#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)
// mmap(2) protection and flags.
//
// These lived only in kernel/sys/sys_mem.c, so every userspace caller wrote
// its own copy -- cmd/fbinfo had one and cmd/pcitest wanted a third. Two
// private copies of a number the kernel compares against is a mismatch
// waiting to happen, and the symptom would be a mapping with the wrong
// permissions rather than an error.
#define PROT_NONE 0x0
#define PROT_READ 0x1
#define PROT_WRITE 0x2
#define PROT_EXEC 0x4
#define MAP_SHARED 0x01
#define MAP_PRIVATE 0x02
#define MAP_FIXED 0x10
#define MAP_ANONYMOUS 0x20
#define MAP_NORESERVE 0x4000
// waitpid() options. The kernel tests `options & 1`; this is that bit, named.
#define WNOHANG 0x001
#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;
};