#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; // 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); extern int tty_fg_pgrp; // 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(struct termios *); void cons_set_termios(const struct termios *); void cprintf(char*, ...); void consoleintr(int(*)(void)); void panic(char*) __attribute__((noreturn)); // exec.c int exec(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); 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); 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); // 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*); void *dma_alloc(uint64 size, uint64 align); void dma_free(void*, uint64 size); addr_t dma_phys(const 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); void sockclose(struct socket*); void sockdup(struct socket*); int sockread(struct socket*, char*, int); int sockwrite(struct socket*, char*, 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*); // proc.c void exit(int status); 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 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); // vga.c void vga_init(uint64); void vga_draw_pixel(int, int, uint32); void vga_draw_char(int, int, uchar, uint32); void vga_puts(int, int, char*, uint32); void vga_putc(int, uint32); void vga_clear(uint32); void vga_screen_reset(void); void vga_set_bg(uint32); // The mode actually in use. The resolution is a boot-time choice now, so no // caller may hardcode it. uint32 vga_get_width(void); uint32 vga_get_height(void); // Crash-screen primitives: the panic handler lays itself out rather than // printing. See kernel/core/panic.c. int vga_ready(void); void vga_dims(int *w, int *h); int vga_char_w(void); int vga_char_h(void); // Framebuffer geometry. vga.c reads the VBE mode info, so it is the only // thing that knows where the framebuffer is; nobody else may assume. uint64 vga_fb_phys(void); uint64 vga_fb_size(void); uint32 vga_fb_stride(void); uint32 vga_fb_bpp(void); volatile uchar *vga_fb_ptr(void); // 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); // drivers/net/e1000 -- raw Ethernet. No protocol stack above it yet, so these // are the whole interface: queue a frame, take a frame, and the MAC. int e1000_transmit(const void *frame, int len); int e1000_receive(void *out, int cap); const unsigned char *e1000_mac(void); void e1000_selftest(void); // registry.c void platform_register_devices(void); void e820_init(void); int acpi_init(void); void vga_fill_rect(int x, int y, int w, int h, uint32); void vga_fill_circle(int cx, int cy, int r, uint32); void vga_text_at(int, int, const char*, uint32); void vga_draw_logo(int x, int y, uint32 color, uint32 bg); void vga_logo_centered(int cy, uint32 color, uint32 bg); // Cursor addressing and erasing, for the console's ANSI escape parser. int vga_cols(void); int vga_rows(void); void vga_cursor_get(int *col, int *row); void vga_cursor_set(int col, int row); void vga_erase_display(int mode); void vga_erase_line(int mode); // 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(void); 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); // 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]))