Sixty-five headers sat side by side in include/, so `#include "irq.h"` said nothing about where irq.h was or what it belonged to, and errno.h, stat.h and fcntl.h at the top shadowed the system's for any host tool built with -I./include. They are in folders now -- arch/ core/ fs/ dev/ gfx/ net/ uapi/ (and ldls/ for the Linux driver layer) -- and every include names the folder, as Linux's do: "core/proc.h". Done mechanically and checked the hard way: the kernel built from this tree disassembles identically to the one built from the tree before it. The full image boots, and userland is the same set of programs. Paths in docs and comments follow; docs/guides/layout.md has a table of what is where, and tools/fix-includes.py rewrites old-style includes from the folders in the tree, for code written before this. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
423 lines
13 KiB
C
423 lines
13 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_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<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 -- 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
|
|
// 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
|
|
|
|
// 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;
|
|
};
|