Ctrl-C killed the shell. consoleread() breaks off the read in progress when
SIGINT arrives and returned -1 to do it -- and -1 is -EPERM by the time it
reaches a program, so every program that handles SIGINT by carrying on saw a
permanent error instead of an interrupted call:
zsh: error on TTY read: operation not permitted
schinitd: restarting os.schos.console-shell
and the next Ctrl-C did it to the replacement. EINTR now, which is what a
signal-interrupted read is required to give. Verified: Ctrl-C an interruptible
command, shell survives, zero restarts.
Same mistake, same file family: link, unlink, rename and renameat returned -1
on every error path. Callers branch on errno -- `if (unlink(p) < 0 && errno !=
ENOENT)` is the standard shape, and against EPERM it always complains -- which
is why zsh reported failures for things that had worked. They return ENOENT,
EEXIST, EXDEV, EISDIR, ENOTEMPTY and EFAULT now. About ninety other `return -1`s
remain in sys_fs.c; these four are done because these four were what a program
tripped over. /dev/mem's unknown minors return ENODEV rather than -1 too.
/dev/urandom was a linear congruential generator seeded with a **constant**, so
every boot produced the same bytes in the same order -- not weak, the same. A
key, a nonce, a temporary filename: shared with every SchOS machine that had
ever run. Seeded at boot from RDRAND where the CPU has it, from the cycle
counter and the wall clock where it does not, and re-stirred per byte. Still an
LCG and still not a CSPRNG; what changed is the part that was dangerous rather
than merely poor.
**Not fixed, and recorded as such:** rename() still will not replace an existing
target, so zsh's history save fails on every exit after the first. An attempt to
unlink the target first was reverted -- the directory is an HTree, dirunlink
followed by dirlink of the same name did not behave, and it panicked in
filewrite with the old file already gone. Losing both files is worse than
refusing, so it refuses until the HTree's slot reuse is understood.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VQ7Qx8E1q1M1bbCq8QLHS2
705 lines
31 KiB
C
705 lines
31 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;
|
|
|
|
// 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*);
|
|
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);
|
|
struct inode* divesymlink(struct inode *);
|
|
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);
|
|
void procfs_mount(void);
|
|
void devfs_mount(void);
|
|
|
|
// 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);
|
|
|
|
// 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/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/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/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);
|
|
|
|
// 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 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);
|
|
int socklisten(struct socket*, int backlog);
|
|
struct socket* sockaccept(struct socket*);
|
|
int sockconnect(struct socket*, const char *path);
|
|
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_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);
|
|
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);
|
|
void wakeup(void*);
|
|
void yield(void);
|
|
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.h, and the display drivers that back them in
|
|
// include/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);
|
|
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/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.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);
|
|
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]))
|