SchOS/include/core/defs.h
Nexoniarz a4ed556543 kernel: timers that fire, raw ping, and the sockets X needs
alarm() and setitimer() stored a countdown nothing counted down, so no
timer has ever fired; setitimer and getitimer were also registered with
no Linux number. alarmd now posts SIGALRM on the tick, while any process
has a timer armed. busybox's ping, /bin/ping on the Alpine root, sends
every request after the first from its SIGALRM handler.

It also opens SOCK_RAW, which was EPROTOTYPE. A raw ICMP socket is now a
ping socket whose reads start at the IP header. And a blocked socket
call gives up for a signal with a handler, not only for a kill: the
alarm woke recvfrom, and the wait put it straight back to sleep.

For Xorg: AF_UNIX abstract names, which read as the empty path and so as
EADDRINUSE ("server already running"); and getsockname and getpeername,
which did not exist, so libxcb sent no cookie and the server refused
every client.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
2026-10-24 19:44:10 +02:00

762 lines
34 KiB
C

#pragma once
struct buf;
struct context;
struct file;
struct inode;
struct pipe;
struct proc;
struct rtcdate;
struct spinlock;
struct sleeplock;
struct stat;
struct superblock;
struct trapframe;
struct dirent;
struct device;
// entryother.S / syscall.S
void syscall_entry(void);
void ignore_sysret(void);
// bio.c
void binit(void);
struct buf* bread(uint, uint64);
void brelse(struct buf*);
void bwrite(struct buf*);
// Modify without writing. The buffer stays dirty in the cache until an
// eviction or a bflush() takes it out; the caller is promising to ask for the
// ordering it needs explicitly rather than relying on write order.
void bdirty(struct buf*);
// Write out every dirty buffer for `dev`, then make the device commit them.
// Returns 0, or -1 if the device could not confirm durability.
int bflush(uint dev);
// console.c
struct termios;
void consoleinit(void);
// The terminal's line-discipline settings. TCGETS/TCSETS in sys_fs.c are the
// only callers; the console honours ICANON, ECHO, ECHOE, ECHONL, ISIG,
// ICRNL, INLCR, IGNCR, ISTRIP and VMIN.
void cons_get_termios(int minor, struct termios *);
void cons_set_termios(int minor, const struct termios *);
void cons_flush_input(int minor);
int cons_fg_pgrp(int minor);
void cons_set_fg_pgrp(int minor, int pg);
int console_vt_hotkey(int key);
extern uint vt_chord_mods; // kernel/dev/kbd.c -- the switch chord
extern uint vt_chord_base;
struct vt *vt_for_minor(int minor);
extern uint lapic_timer_hz; // measured, kernel/arch/x86_64/lapic.c
extern uint64 tsc_hz;
extern uint64 boot_tsc;
void monotonic(uint64 *sec, uint64 *usec);
int proc_write_schinit(int user_src, uint64 src, uint n);
int proc_wedge(const char *name);
void pciuser_init(void);
int pciuser_ioctl(uint64 request, uint64 argp);
int pciuser_read(struct inode*, uint64, char*, int);
int pciuser_write(struct inode*, uint64, char*, int);
int pciuser_mmio_ok(uint64 phys, uint64 len);
void pciuser_release_all(struct proc*);
int pciuser_owner_pid(int idx);
int proc_reincarnate(int status);
void proc_kill_init(void);
extern uint init_generation;
void cprintf(char*, ...);
// Boot chatter: always in the klog, on the screen only when boot_verbose.
// See the note above kinfo() in kernel/core/console.c for which is which.
void kinfo(char*, ...);
extern int boot_verbose;
extern int boot_debug;
// A log line: the serial port only, never the display.
//
// console_takeover() hands the framebuffer to userspace on the first exec, and
// after that the screen belongs to whoever is using the machine. A kernel
// message arriving then is not information they asked for -- it lands in the
// middle of their shell, or their editor, or a compositor's output. The DHCP
// lease is what made this necessary: it turns up seconds after the prompt does,
// so the first thing anyone sees after booting is the kernel talking over them.
//
// The same rule the boot path already follows, and the reason cons_serial_only
// starts set: the display is the product, the serial line is the diagnostics.
// klog is that rule for messages that cannot be timed to happen before
// userspace starts.
//
// A macro rather than a function because cprintf's varargs cannot be forwarded
// -- there is no vcprintf, and adding one to duplicate the formatter would cost
// more than it buys. cprintf holds cons.lock for the whole message, so the flag
// cannot be seen half-changed by another CPU printing at the same time.
//
// Nothing is lost: serial is where bootcheck reads from and where you want
// these when something is wrong, and anything a *user* should see belongs in a
// file they can read -- /proc/netif, for the example above.
extern int cons_serial_only;
#define klog(...) do { \
int _klog_was = cons_serial_only; \
cons_serial_only = 1; \
cprintf(__VA_ARGS__); \
cons_serial_only = _klog_was; \
} while (0)
void consoleintr(int(*)(void));
void panic(char*) __attribute__((noreturn));
// exec.c
int exec(char*, char**, char**);
// file.c
struct file* filealloc(void);
int fdalloc(struct file*);
// sys_event.c: eventfd, timerfd, signalfd and epoll, as files
// kernel/fs/lock.c
int lock_flock(struct file *f, int op);
int lock_fcntl(struct file *f, int cmd, addr_t arg);
void lock_close_fd(struct file *f);
void lock_close_file(struct file *f);
void lock_exit(int pid);
struct evobj;
void ev_close(struct evobj *);
int ev_poll(struct file *, int events);
int ev_read(struct file *, char *addr, int n);
int ev_write(struct file *, char *addr, int n);
void fileclose(struct file*);
struct file* filedup(struct file*);
void fileinit(void);
int fileread(struct file*, char*, int n);
int file_poll(struct file*, int events);
int filestat(struct file*, struct stat*);
int filewrite(struct file*, char*, int n);
// fs.c
void fsinit(int);
int dirlink(struct inode*, char*, uint64);
struct inode* dirlookup(struct inode*, char*, uint*);
// Remove the entry `name` at the cookie dirlookup returned in *poff.
int dirunlink(struct inode*, char*, uint);
// 1 if the directory holds no real entries, 0 if it does, -1 on error.
int dirempty(struct inode*);
// Fill `out` with getdents64 records starting at *poff, which is an opaque
// position the filesystem advances. Returns bytes written, 0 at end of
// directory. The inode must be locked.
int getdents(struct inode*, char *out, int cap, uint64 *poff);
// Mount table: a substitution applied during path resolution. Nothing on disk
// records a mount, so unmounting is forgetting.
void mountinit(void);
// 1 if the filesystem on this device refuses writes -- a mounted snapshot.
// Ask before mutating, not after: the create path panics on a failed dirlink.
int fs_readonly(uint dev);
int mount_add(uint dev, uint64 inum, uint fsdev, uint64 root,
const char *path, const char *source, const char *type);
// Walk the mount table for /proc/mounts. `path` and `source` need MAXPATH
// bytes, `type` 16. Returns 0 for a live entry, -1 for an empty slot.
int mount_get(int i, char *path, char *source, char *type,
uint *fsdev);
int mount_del_by_root(uint fsdev, uint64 root);
struct inode* ialloc(uint, short);
struct inode* iget(uint, uint64);
struct inode* idup(struct inode*);
void iinit(void);
void ilock(struct inode*);
void iput(struct inode*);
void iunlock(struct inode*);
void iunlockput(struct inode*);
void iupdate(struct inode*);
int namecmp(const char*, const char*);
struct inode* namei(char*);
struct inode* nameiparent(char*, char*);
struct inode* nameifrom(struct inode*, char*);
struct inode* nameiparentfrom(struct inode*, char*, char*);
int readi(struct inode*, int, uint64, uint64, uint);
void stati(struct inode*, struct stat*);
int writei(struct inode*, int, uint64, uint64, uint);
void itrunc(struct inode*);
void itrunc_to(struct inode*, uint64);
unsigned int BKDRHash(char * str);
uint tree_expand(struct inode *ip, uint off);
void tree_search(struct inode* dp, char* name, uint* poff, struct dirent* de,uint add);
void build_dir_tree(struct inode* dp,uint64 pinum);
// A socket node for AF_UNIX bind(2), and unlink by path for the failure that
// follows it. See the notes on each in kernel/sys/sys_fs.c.
struct inode* create_sock(char *path);
int unlink_path(char *path);
void readsb(int dev, struct superblock *sb);
// pci.c -- bus enumeration. Drivers that need to *find* their hardware use
// these; drivers for things that have lived at a fixed address since 1984
// (the PIC, the PIT, the legacy IDE ports) do not.
struct pci_dev;
struct pci_driver;
void pci_init(void);
uint32 pci_read32(uint8, uint8, uint8, uint8);
uint16 pci_read16(uint8, uint8, uint8, uint8);
uint8 pci_read8(uint8, uint8, uint8, uint8);
void pci_write32(uint8, uint8, uint8, uint8, uint32);
void pci_enable(struct pci_dev *, uint16 bits);
void pci_disable(struct pci_dev *, uint16 bits);
uint8 pci_find_cap(struct pci_dev *, uint8 id);
int pci_msi_enable(struct pci_dev *, int vector, int cpu);
int pci_count(void);
struct pci_dev *pci_get(int);
struct pci_dev *pci_find_class(uint8 class, uint8 subclass);
struct pci_dev *pci_find_id(uint16 vendor, uint16 device);
void pci_bind(const struct pci_driver *);
int pci_info(char *buf, int cap);
// drivers/registry.c -- the one list of every driver in the kernel.
void pci_bind_all(void);
// xhci.c — `echo u > /proc/sysrq`
void xhci_dump(void);
// ide.c
void ideinit(void);
void ideintr(void);
void iderw(struct buf*);
// For probes, not for reads: iderw() panics on an absent drive, so anything
// that is guessing whether a disk exists has to ask here first.
int ide_disk_present(int dev);
// ATA FLUSH CACHE: block until the drive has committed its write cache.
int ideflush(int dev);
// fs/schfs/kmount.c -- SchFS.
//
// Objects are named by 64-bit object id, not by a path: resolution is the
// caller's business, so these compose with a VFS rather than assuming one.
// Every schfs_k* that changes anything is one transaction and is durable by the
// time it returns.
struct schfs_inode;
// Mounting. Slot 0 is the root filesystem, mounted by proc.c before pid 1 has a
// working directory; schfs_kmount_dev takes any other SchFS disk and returns
// the filesystem device number it landed on, or a negative errno.
void schfs_kmount(uint bdev);
int schfs_kmount_dev(uint bdev);
int schfs_kumount(uint dev);
int schfs_kmounted(void);
// Read side. `dev` is a filesystem device number -- a live volume or a mounted
// snapshot -- not the block device underneath it.
uint64 schfs_klookup(uint dev, const char *path);
long schfs_kread_dev(uint dev, uint64 ino, uint64 off, void *buf,
unsigned n);
int schfs_kstat_dev(uint dev, uint64 ino, struct schfs_inode *out);
uint64 schfs_klookup_at_dev(uint dev, uint64 dir, const char *name,
unsigned len);
int schfs_kreaddir_dev(uint dev, uint64 dir,
int (*fn)(uint64, unsigned short, const char *,
unsigned, void *),
void *arg);
// Resume a directory walk at a tree key. The callback gets each entry's hash,
// which is what getdents hands back to userland as its position.
int schfs_kreaddir_from_dev(uint dev, uint64 dir, uint64 start_hash,
int (*fn)(uint64, unsigned short, const char *,
unsigned, uint64, void *),
void *arg);
uint64 schfs_kroot(uint dev);
void schfs_lockinfo(int slot, int *locked, int *owner_pid, int *depth);
int schfs_kinfo(char *buf, int cap);
// Write side. Each is one transaction and is durable by the time it returns,
// unless the caller has a bracket open -- see schfs_ktx_open.
int schfs_kcreate(uint dev, uint64 dir, const char *name,
unsigned namelen, unsigned short type, uint mode,
unsigned short major, unsigned short minor, uint64 *out);
long schfs_kwrite(uint dev, uint64 ino, uint64 off, const void *buf,
unsigned n);
int schfs_ktruncate(uint dev, uint64 ino, uint64 size);
int schfs_kunlink(uint dev, uint64 dir, const char *name,
unsigned namelen);
int schfs_klink(uint dev, uint64 dir, const char *name,
unsigned namelen, uint64 ino);
int schfs_krename(uint dev, uint64 olddir, const char *oldname,
unsigned oldlen, uint64 newdir, const char *newname,
unsigned newlen);
int schfs_ksetattr(uint dev, uint64 ino,
const struct schfs_inode *in);
int schfs_ksync(uint dev);
int schfs_ksync_all(void);
// Share src's data blocks with dst without copying. Both stay writable; the
// first write to either copies only the run it touches. Behind FICLONE.
int schfs_kreflink(uint dev, uint64 src, uint64 dst);
// Attributes, and the index over them. See kernel/fs/schfs/attr.c.
int schfs_kattr_set(uint dev, uint64 ino, const char *name,
unsigned namelen, const void *val, unsigned vallen,
unsigned short type);
int schfs_kattr_get(uint dev, uint64 ino, const char *name,
unsigned namelen, void *out, unsigned cap,
unsigned *vallen);
int schfs_kattr_del(uint dev, uint64 ino, const char *name,
unsigned namelen);
int schfs_kindex(uint dev, const char *name, unsigned namelen);
int schfs_kquery(uint dev, const char *name, unsigned namelen,
const void *val, unsigned vallen, uint64 *out, int cap);
// Bracket a run of changes into one transaction group. Every schfs_k* call made
// between open and close joins it and commits once, at the close; the bracket
// nests, and holds the volume lock for its whole extent. Costly to leave open —
// nothing else touches that volume meanwhile — so bracket a bounded piece of
// work such as one write(2), not a whole syscall's worth of unrelated steps.
// schfs_ktx_close returns the commit's status, or -1 if the caller had no
// bracket open.
void schfs_ktx_open(uint dev);
int schfs_ktx_close(uint dev);
// Volume counts for statfs. 0 if `dev` is a mounted SchFS volume (live or
// snapshot) and the counts are filled in, -1 if it is not.
int schfs_kstatfs(uint dev, uint64 *total, uint64 *freeblocks,
uint64 *objects);
// Pieces the VFS layer (fs/schfs/vfs.c) needs, where a directory entry and the
// object it names are separate operations. The VFS keeps the link count.
int schfs_kdirempty(uint dev, uint64 dir);
int schfs_kalloc_object(uint dev, unsigned short type, uint mode,
uint64 *out);
int schfs_kdiradd(uint dev, uint64 dir, const char *name,
unsigned len, uint64 ino, unsigned short type);
int schfs_kdirdel(uint dev, uint64 dir, const char *name,
unsigned len);
int schfs_kfree(uint dev, uint64 ino);
// A snapshot mounted read-only: the same block device with an older tree root.
// The read path takes a device number so the VFS can address either view; there
// is no write path, because a snapshot that could be written to would not be
// one. See kernel/fs/schfs/kmount.c.
// Returns the device number of the slot the snapshot landed in, or negative.
int schfs_ksnap_mount(uint dev, const char *name, unsigned namelen);
void schfs_ksnap_unmount(uint dev);
uint64 schfs_ksnap_root(uint dev);
// ramdisk.c
uint uptime(void);
// procfs.c
int procread(struct inode*, uint64, char*, int);
int procwrite(struct inode*, uint64, char*, int);
// Shared with the /proc filesystem (kernel/fs/procfs.c): one owns the
// namespace, the other the content.
int proc_gen_global(int id, char *buf, int cap);
int proc_write_sysrq(int user_src, uint64 src, uint n);
int procfs_mount(const char *target);
int devfs_mount(const char *target);
// input.c -- raw evdev event devices
void inputinit(void);
int inputread(struct inode*, uint64, char*, int);
int inputwrite(struct inode*, uint64, char*, int);
int inputready(struct inode*);
void inputclose(struct inode*);
void inputopen(struct inode*);
int input_ioctl(struct inode*, int request, addr_t arg);
int input_grab(int dev, int on);
int input_is_grabbed(int dev);
void input_report(int dev, int type, int code, int value);
// An absolute pointing device (usb-tablet). Coordinates are already in screen
// pixels; see input_mouse_abs in kernel/dev/input.c for why this is separate
// from the relative path.
void input_mouse_abs(int x, int y, int buttons);
void mouse_set_abs(int x, int y, int buttons);
void input_sync(int dev);
int input_ready(int dev);
void input_ps2_scancode(int raw, int e0);
void input_key(int hid_usage, int down);
int input_hid_keycode(int hid_usage);
void input_mouse(int dx, int dy, int buttons);
void ramdiskinit(void);
void ramdiskrw(struct buf*);
int ramdisk_present(void);
uint64 ramdisk_blocks(void);
// usb_storage.c
void usb_storage_rw(struct buf*);
int usb_storage_present(void);
// SCSI SYNCHRONIZE CACHE: the same barrier as ideflush, over bulk transport.
int usb_storage_flush(void);
void usb_storage_dump(void); // `echo s > /proc/sysrq`
// ioapic.c
void ioapicenable(int irq, int cpu);
void ioapicroute(int irq, int cpu, int level_low);
void ioapicmask(int irq);
extern uchar ioapicid;
void ioapicinit(void);
// dma.c — see include/core/dma.h for the full contract
void dma_init(void*, void*);
// watch.c -- hardware watchpoints on DR0-DR3. See docs/architecture/debugging.md, D4.
struct trapframe;
void watch_init(void);
void watch_sync(void);
int watch_trap(struct trapframe *tf);
// netuser.c -- /dev/netdev, an interface backed by a process. See netuser.h.
void netuser_init(void);
int netuser_read(struct inode*, uint64, char*, int);
int netuser_write(struct inode*, uint64, char*, int);
int netuser_ready(struct inode*);
int netuser_ioctl(uint64 request, uint64 argp);
void netuser_release_all(struct proc*);
// dbg.c -- /dev/dbg, the introspection registry. See include/core/dbg.h.
int dbg_read(struct inode*, uint64, char*, int);
void dbg_request_dump(void);
void dbg_thread_start(void);
int dbg_write(struct inode*, uint64, char*, int);
// klog.c -- the kernel log that outlives the kernel. See include/core/klog.h.
void klog_init(void *base, uint64 bytes);
void klog_putc(int c);
int klog_read(uint64 off, char *dst, int n);
uint64 klog_len(void);
uint64 klog_prev_bytes(void);
int klog_recovered(void);
int klog_render_syslog(char *dst, int cap);
// ksym.c -- naming a kernel address. See docs/architecture/debugging.md, D0.
int ksym_ready(void);
const char* ksym_lookup(uint64 addr, uint64 *off);
int ksym_fmt(char *buf, int cap, uint64 addr);
void *dma_alloc(uint64 size, uint64 align);
void dma_free(void*, uint64 size);
addr_t dma_phys(const void*);
// /dev/random and /dev/urandom. Seeded once at boot; see kernel/dev/cdev.c.
void random_init(void);
uint64 dma_free_bytes(void);
uint64 dma_total_bytes(void);
// kalloc.c
char* kalloc(void);
uint64 kalloc_free_bytes(void);
void kfree(char*);
void kinit1(void*, void*);
void kinit_high(void);
void kinit2(void);
// kbd.c
void kbdintr(void);
// mouse.c
void mouseinit(void);
void mouseintr(void);
void mouse_inject(int dx, int dy, int buttons);
int get_mouse_x(void);
int get_mouse_y(void);
uint8 get_mouse_buttons(void);
// lapic.c
void cmostime(struct rtcdate *r);
// time.c -- wall-clock time, from the RTC read once at boot plus uptime.
void time_init(void);
void wallclock(uint64 *sec, uint64 *usec);
extern uint64 boot_epoch;
int cpunum(void);
extern volatile uint* lapic;
void lapiceoi(void);
void lapicinit(void);
void lapicstartap(uchar, uint);
void microdelay(int);
// log.c
void initlog(int dev);
void log_write(struct buf*);
void begin_op();
void end_op();
// mp.c
extern int ismp;
void mpinit(void);
// pipe.c
int pipealloc(struct file**, struct file**);
void pipeclose(struct pipe*, int);
int piperead(struct pipe*, char*, int);
int pipewrite(struct pipe*, char*, int);
// net/unix.c
struct socket;
void sockinit(void);
struct socket* socknew(int domain, int type, int proto);
void sockclose(struct socket*);
void sockdup(struct socket*);
int sockread(struct socket*, char*, int);
int sockwrite(struct socket*, char*, int);
// The same two, carrying descriptors. See kernel/net/unix.c.
int sockread_fds(struct socket*, char*, int, struct file**, int*);
int sockwrite_fds(struct socket*, char*, int, struct file**, int);
int sockbind(struct socket*, const char *path, uint dev, uint64 ino);
int socklisten(struct socket*, int backlog);
struct socket* sockaccept(struct socket*);
int sockconnect(struct socket*, uint dev, uint64 ino);
int sockbind_abstract(struct socket*, uint64 key);
int sockname_unix(struct socket*, int peer, char *path);
int sockname_inet(struct socket*, int peer, uint *addr, ushort *port);
#define SOCK_ABSTRACT_DEV 0xFFFFFFFFu // no filesystem has it; see unix.c
int sockreadable(struct socket*);
int sock_hup(struct socket*);
int sock_shutdown(struct socket*, int how);
int sockpair(struct socket **a, struct socket **b);
const char* sockname(struct socket*);
// AF_INET addressing. Separate from sockbind/sockconnect because the families
// do not name the same kind of thing; `addr` and `port` are network order.
int sockrecvfrom(struct socket*, char *buf, int n,
uint *addr, ushort *port);
int socksendto(struct socket*, char *buf, int n,
uint addr, ushort port);
int sockbind_in(struct socket*, uint addr, ushort port);
int sockconnect_in(struct socket*, uint addr, ushort port);
int sock_domain(struct socket*);
// Socket options. The syscall layer does the user-memory marshalling and these
// do the work, because struct socket's fields live in kernel/net/unix.c and the
// syscall layer deliberately cannot see them.
int sockopt_set(struct socket*, int level, int name, int val);
int sockopt_get(struct socket*, int level, int name, int *out);
// net/inet.c -- AF_INET on lwIP's raw API. Called only from net/unix.c, which
// is where the per-domain dispatch lives.
void inet_init(void);
void* inet_new(int type, int proto);
int inet_bind(void *h, uint addr, ushort port);
int inet_listen(void *h, int backlog);
int inet_setopt(void *h, int level, int name, int val);
void* inet_accept(void *h);
int inet_connect(void *h, uint addr, ushort port);
int inet_read(void *h, char *buf, int n);
int inet_write(void *h, char *buf, int n);
int inet_name(void *h, int peer, uint *addr, ushort *port);
int inet_recvfrom(void *h, char *buf, int n,
uint *addr, ushort *port);
int inet_sendto(void *h, char *buf, int n,
uint addr, ushort port);
int inet_readable(void *h);
int inet_hup(void *h);
void inet_close(void *h);
// proc.c
void exit(int status);
// Start a kernel thread: a process that runs `fn` in kernel mode forever. It
// has no files, no cwd and no parent, and must never return. Returns the pid.
int kthread_create(void (*fn)(void), const char *name);
int fork(void);
int growproc(int64);
int kill(int);
int sigsend_pgrp(int pgid, int sig);
int proc_pgid(int pid);
int proc_setpgid(int pid, int pgid);
int proc_setsid(void);
int sigsend(int pid, int sig);
void alarm_arm(struct proc *p, uint after, uint every);
uint alarm_left(struct proc *p);
void alarm_thread_start(void);
int sig_default_kills(int sig);
int proc_exists(int);
int proc_num(void);
struct procinfo;
int proc_snapshot(int idx, struct procinfo *out);
int proc_snapshot_pid(int pid, struct procinfo *out);
void pinit(void);
void procdump(void);
void scheduler(void) __attribute__((noreturn));
void sched(void);
void sleep(void*, struct spinlock*);
int wait(void);
int waitpid(int, int*, int, uint64*, uint64*);
void wakeup(void*);
void yield(void);
int sched_slice_expired(void);
void sched_init_proc(struct proc*, int);
void sched_set_nice(struct proc*, int);
int proc_setnice(int, int);
int proc_getnice(int, int*);
void sinit(void);
void kstack_check_canary(const char *where);
// swtch.S
void swtch(struct context**, struct context*);
// spinlock.c
void acquire(struct spinlock*);
void getcallerpcs(void*, addr_t*);
void getstackpcs(addr_t*, addr_t*);
int holding(struct spinlock*);
void initlock(struct spinlock*, char*);
void release(struct spinlock*);
void pushcli(void);
void popcli(void);
// sleeplock.c
void acquiresleep(struct sleeplock*);
void releasesleep(struct sleeplock*);
int holdingsleep(struct sleeplock*);
void initsleeplock(struct sleeplock*, char*);
// string.c
int memcmp(const void*, const void*, uint64);
void* memmove(void*, const void*, uint64);
void* memset(void*, int, uint64);
char* safestrcpy(char*, const char*, int);
int strlen(const char*);
int strnlen(const char*, int);
int strcmp(const char*, const char*);
int strncmp(const char*, const char*, uint64);
char* strncpy(char*, const char*, int);
// syscall.c
void syscall(struct trapframe *);
void syscallinit(void);
void deliver_signals(struct trapframe *);
int argint(int, int*);
int argptr(int, char**, int);
int argstr(int, char**);
int argaddr(int, addr_t*);
int fetchaddr(addr_t, addr_t*);
int fetchstr(addr_t, char**);
int fetchint(addr_t, int*);
// trap.c
void idtinit(void);
extern uint ticks;
void tvinit(void);
extern struct spinlock tickslock;
// uart.c
void uartearlyinit(void);
void uartinit(void);
void uartintr(void);
void uartputc(int);
// Drawing, the text console and the framebuffer geometry are NOT declared
// here: they live in include/gfx/gfx.h, and the display drivers that back them in
// include/gfx/display.h. Declaring vga_fill_rect() here is what let the crash
// screen draw on one named driver.
// fb.c -- /dev/fb0, major 2.
void fbclose(struct inode*);
// Called from sys_mmap: a mapping of /dev/fb0 is a licence to draw with no
// further syscalls, so it is the last the kernel hears about it.
void fb_mapped(void);
// AudioEngine and /dev/dsp. kernel/dev/audio.c, include/dev/audio.h.
int dspread(struct inode*, uint64, char*, int);
int dspwrite(struct inode*, uint64, char*, int);
void dspclose(struct inode*);
int dsp_ioctl(int request, uint64 argp);
void audio_wait(struct device *);
// The crash screen, on displays other than the console's. kernel/dev/device.c.
void display_panic_present(void);
// Push the console's newly-drawn rows to a second display, if the kernel
// drives one. kernel/dev/device.c.
void display_mirror_console(void);
uint64 display_scanout_phys(void);
// Where a userspace display driver said it is scanning out, and which kernel
// driver it took the device from. kernel/dev/pciuser.c.
int pciuser_panic_surface(int idx, uint64 *paddr, int *w, int *h,
uint32 *stride,
const struct pci_driver **drv);
int fbread(struct inode*, uint64, char*, int);
int fbwrite(struct inode*, uint64, char*, int);
int fb_ioctl(int request, addr_t arg);
// dev/disk.c -- /dev/hdN, raw seekable access to a whole disk. The minor is the
// IDE device number. Writes bypass every filesystem above them.
int diskread(struct inode*, uint64, char*, int);
int diskwrite(struct inode*, uint64, char*, int);
// Network *drivers* are not declared here at all. They are reached through the
// netdev class in include/dev/netdev.h -- a driver publishes a vtable and nothing
// above it ever learns its name. Declaring e1000_transmit() here was what let
// the protocol stack call it directly.
// net/net.c -- the TCP/IP stack (lwIP). netinit starts the network thread;
// net_is_up reports whether an address has been obtained.
void netinit(void);
int net_is_up(void);
int net_is_ready(void);
void net_wake_counts(uint64 *rx, uint64 *tick);
int net_info(char *buf, int cap);
// net/lwip/ -- the port layer and the Ethernet interfaces, called only from
// net.c. One netif per bound network device; the index is that interface's.
void lwip_sys_init(void);
void lwip_sys_lock(void);
void lwip_sys_unlock(void);
int net_resolv(char *, int);
int net_eth_attach(struct device *);
int net_eth_detach(struct device *);
int net_detach(struct device *);
int net_attach_late(struct device *);
int net_eth_poll(void);
int net_eth_count(void);
void net_eth_counts(int i, uint64 *rx, uint64 *tx);
struct netif *net_eth_netif(int i);
uint netif_addr4(struct netif *);
uint netif_mask4(struct netif *);
uint ntohl_u32(uint);
uint htonl_u32(uint);
// rtnetlink: turn one request into a whole dump. See kernel/net/netlink.c.
int netlink_request(const char *req, uint reqlen,
char *out, uint outcap);
struct device *net_eth_device(int i);
// registry.c
// Platform devices, and the boot framebuffer. Takes the framebuffer address
// the loader handed over, because bringing that up is the first thing it does.
void platform_register_devices(uint64 fb_addr);
// drivers/gpu/vga -- the VBE framebuffer the loader programmed. Called only
// from registry.c; everything else draws through include/gfx/gfx.h.
void vga_fb_init(uint64 phys_addr);
uint64 vga_fb_phys(void);
int vga_fb_restore(void); // 0 = there is no fallback
uint64 vga_fb_size(void);
void e820_init(void);
int acpi_init(void);
// console.c / panic.c
void cons_panic_mode(void);
extern int cons_serial_only;
void console_takeover(void);
// vm.c
void seginit(void);
void kvmalloc(void);
// Map device registers. Returns a kernel address for `size` bytes of physical
// MMIO at `pa`, or 0 if the window is exhausted. Use this rather than P2V for
// anything that came out of a BAR: firmware may place a 64-bit BAR far above
// the 4 GB the direct map covers.
void* ioremap(uint64 pa, uint64 size);
pml4e_t* setupkvm(void);
char* uva2ka(pml4e_t*, char*);
addr_t allocuvm(pml4e_t*, uint64, uint64);
addr_t deallocuvm(pml4e_t*, uint64, uint64);
void freevm(pml4e_t*);
void inituvm(pml4e_t*, char*, uint64);
int loaduvm(pml4e_t*, char*, struct inode*, uint64, uint64);
pml4e_t* copyuvm(pml4e_t*, uint64);
void switchuvm(struct proc*);
void switchkvm(void);
int pipe_poll(struct pipe*, int readable, int writable);
int console_input_ready(int minor);
int copyin(pml4e_t*, addr_t, void*, uint64);
int copyout(pml4e_t*, addr_t, void*, uint64);
void vm_unmap_range(pml4e_t*, uint64, uint64);
// Unmap without freeing: for pages this process does not own — device memory
// and shared segments. vm_unmap_range() would hand them to kfree.
void vm_unmap_norelease(pml4e_t*, uint64, uint64);
void vm_walk_user(pml4e_t*, void (*)(void*, uint64, uint64, uint64), void*);
// Shared memory (sys_mem.c). shm_ref/shm_detach maintain the attachment
// count that decides when a segment's pages go back.
void shm_ref(int id);
char* shm_page(int id, int pg);
uint64 memfd_size(int id);
int memfd_truncate(int id, uint64 len);
int memfd_rw(int id, int user, uint64 buf, uint64 off, int n, int writing);
void shm_detach(int id);
void proc_release_shared(struct proc *);
int copy_vma_range(pml4e_t *dstpgdir, pml4e_t *srcpgdir, uint64 va, uint64 length, int is_fb);
void clearpteu(pml4e_t *pgdir, char *uva);
#define NELEM(x) (sizeof(x)/sizeof((x)[0]))