Initial commit: Schunix as it stands before the SchOS rename

An x86-64 operating system built from xv6, now largely rewritten: SMP,
a copy-on-write root filesystem (SchFS), PCI/USB/virtio drivers, a TTF
rasteriser, and a Linux-numbered syscall ABI.

No history before this point -- the tree was never under version control.
This commit exists so the rename that follows has something to undo to.
This commit is contained in:
Nexoniarz 2026-08-09 13:47:01 +02:00
commit d0f7acf9eb
275 changed files with 51417 additions and 0 deletions

21
include/asm.h Normal file
View file

@ -0,0 +1,21 @@
//
// assembler macros to create x86 segments
//
#define SEG_NULLASM \
.word 0, 0; \
.byte 0, 0, 0, 0
// The 0xC0 means the limit is in 4096-byte units
// and (for executable segments) 32-bit mode.
#define SEG_ASM(type,base,lim) \
.word (((lim) >> 12) & 0xffff), ((base) & 0xffff); \
.byte (((base) >> 16) & 0xff), (0x90 | (type)), \
(0xC0 | (((lim) >> 28) & 0xf)), (((base) >> 24) & 0xff)
#define STA_X 0x8 // Executable segment
#define STA_E 0x4 // Expand down (non-executable segments)
#define STA_C 0x4 // Conforming code segment (executable only)
#define STA_W 0x2 // Writeable (non-executable segments)
#define STA_R 0x2 // Readable (executable segments)
#define STA_A 0x1 // Accessed

14
include/buf.h Normal file
View file

@ -0,0 +1,14 @@
struct buf {
int flags;
uint dev;
uint blockno;
struct sleeplock lock;
uint refcnt;
struct buf *prev; // LRU cache list
struct buf *next;
struct buf *qnext; // disk queue
uchar data[BSIZE];
};
#define B_VALID 0x2 // buffer has been read from disk
#define B_DIRTY 0x4 // buffer needs to be written to disk

3
include/config_sinit.h Normal file
View file

@ -0,0 +1,3 @@
static char *const rcinitcmd[] = { "/bin/sh", NULL };
static char *const rcrebootcmd[] = { "/bin/halt", "-rb", NULL };
static char *const rcpoweroffcmd[] = { "/bin/halt", "-po", NULL };

15
include/date.h Normal file
View file

@ -0,0 +1,15 @@
#pragma once
struct rtcdate {
uint second;
uint minute;
uint hour;
uint day;
uint month;
uint year;
};
struct timeval {
long tv_sec;
long tv_usec;
};

466
include/defs.h Normal file
View file

@ -0,0 +1,466 @@
#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, uint);
void brelse(struct buf*);
void bwrite(struct buf*);
// 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);
int mount_add(uint dev, uint64 inum, uint fsdev, uint64 root);
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);
// 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;
void schfs_kmount(uint dev);
int schfs_kmounted(void);
uint64 schfs_klookup(const char *path);
int schfs_kstat(uint64 ino, struct schfs_inode *out);
long schfs_kread(uint64 ino, uint64 off, void *buf, unsigned n);
int schfs_kreaddir(uint64 dir,
int (*fn)(uint64, unsigned short, const char *,
unsigned, void *),
void *arg);
int schfs_kinfo(char *buf, int cap);
int schfs_kcreate(uint64 dir, const char *name, unsigned namelen,
unsigned short type, uint mode,
unsigned short major, unsigned short minor, uint64 *out);
long schfs_kwrite(uint64 ino, uint64 off, const void *buf,
unsigned n);
int schfs_ktruncate(uint64 ino, uint64 size);
int schfs_kunlink(uint64 dir, const char *name, unsigned namelen);
int schfs_klink(uint64 dir, const char *name, unsigned namelen,
uint64 ino);
int schfs_krename(uint64 olddir, const char *oldname,
unsigned oldlen, uint64 newdir, const char *newname,
unsigned newlen);
int schfs_ksetattr(uint64 ino, const struct schfs_inode *in);
int schfs_ksync(void);
// 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.
uint64 schfs_klookup_at(uint64 dir, const char *name, unsigned len);
int schfs_kdirempty(uint64 dir);
int schfs_kalloc_object(unsigned short type, uint mode,
uint64 *out);
int schfs_kdiradd(uint64 dir, const char *name, unsigned len,
uint64 ino, unsigned short type);
int schfs_kdirdel(uint64 dir, const char *name, unsigned len);
int schfs_kfree(uint64 ino);
uint64 schfs_kroot(void);
// ramdisk.c
uint uptime(void);
// procfs.c
int procread(struct inode*, uint, char*, int);
int procwrite(struct inode*, uint, 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*, uint, char*, int);
int inputwrite(struct inode*, uint, 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);
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);
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);
// 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*, uint, char*, int);
int fbwrite(struct inode*, uint, char*, int);
int fb_ioctl(int request, addr_t arg);
// 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);
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]))

89
include/device.h Normal file
View file

@ -0,0 +1,89 @@
#pragma once
// The device model: one list of everything attached, whatever bus found it.
//
// Before this there were two registries in kernel/drivers/registry.c -- one
// array of PCI drivers, one of USB drivers -- and nothing that knew about both.
// That is fine for binding drivers to hardware, which is all it was for, and
// useless for the three things wanted next:
//
// *Enumeration.* "What is in this machine, and what claimed it" had no
// answer that covered a USB disk and a PCI display at once. A device manager
// is exactly that question, so it needs exactly this list.
//
// *Classes.* A compositor should ask for "the display" and not care whether
// that is the VBE framebuffer or virtio-gpu. Without a class, every consumer
// hardcodes a driver, and adding the second driver means editing the
// consumers -- which is how a framebuffer address ends up hardcoded in three
// places, as it once was here.
//
// *A boundary for drivers that are not compiled in.* Drivers the user
// installs (see docs/drivers.md) have to attach somewhere that is not "an
// array in registry.c", because that array is fixed at link time.
//
// The shape is deliberately the one NeXTSTEP/macOS uses rather than Linux's:
// a device is an object with a class and an ops vtable, and consumers talk to
// the class. It is *not* a device tree -- there is no parent/child nesting
// here, only a flat list with a bus tag, because nothing yet needs to walk a
// hierarchy and a tree that nobody traverses is just a harder list.
#define DEV_NAMELEN 24
// Which bus found it. This is provenance, not capability -- what the device
// *does* is its class.
enum dev_bus {
DEVBUS_PLATFORM = 0, // found by looking, not by enumerating: PS/2, VBE
DEVBUS_PCI,
DEVBUS_USB,
DEVBUS_NBUS
};
// What it is. A consumer asks for a class and gets whatever is bound.
enum dev_class {
DEVCLASS_OTHER = 0,
DEVCLASS_DISPLAY,
DEVCLASS_INPUT,
DEVCLASS_STORAGE,
DEVCLASS_NET,
DEVCLASS_BUS, // a controller that finds more devices (xHCI, hubs)
DEVCLASS_NCLASS
};
struct device {
char name[DEV_NAMELEN]; // "vga0", "xhci0" -- unique, human-readable
char desc[48]; // free text for the enumerator
enum dev_bus bus;
enum dev_class class;
// Where it came from, for the enumerator to print. Zero when not applicable.
uint16 vendor, product;
uint8 b, s, f; // PCI bus/slot/func
const char *driver; // whatever claimed it, or 0 for unclaimed
void *ops; // class-specific vtable; see display.h
void *priv; // the driver's own state
int in_use;
};
#define NDEVICE 32
// Register a device. Returns it, or 0 if the table is full. The name is made
// unique by appending an index, so a caller passes "vga" and gets "vga0".
struct device *device_add(const char *base, enum dev_bus bus,
enum dev_class class, const char *driver);
// Set the human-readable description. Bounded copy into the fixed field, so
// callers do not each need to know how long it is.
void device_set_desc(struct device *, const char *);
// Walk. Returns 0 past the end; index is dense over registered devices.
struct device *device_at(int i);
int device_count(void);
// First device of a class with a bound driver, or 0. This is how a consumer
// finds "the display" without naming a driver.
struct device *device_find_class(enum dev_class class);
const char *dev_bus_name(enum dev_bus);
const char *dev_class_name(enum dev_class);

56
include/display.h Normal file
View file

@ -0,0 +1,56 @@
#pragma once
// The display class: what a consumer talks to instead of a driver.
//
// A compositor should ask for "the display" and get whatever is bound --
// today the VBE framebuffer, later virtio-gpu. Without this, every consumer
// names a driver, and adding the second display driver means editing all of
// them. That is not hypothetical here: the framebuffer's physical address was
// once hardcoded in three separate places.
//
// Found with device_find_class(DEVCLASS_DISPLAY); see include/device.h.
struct device;
struct display_mode {
int width, height;
int bpp;
uint32 stride; // bytes per row of the *visible* framebuffer
};
struct display_ops {
void (*mode)(struct device *, struct display_mode *);
// The buffer to draw into, and its stride. Returns 0 if double buffering is
// unavailable, in which case the caller should draw directly and accept
// tearing rather than not drawing at all.
//
// Allocated on first call, never at boot: it is around two megabytes at
// 800x600, and a machine whose compositor never starts should not pay that.
void *(*acquire)(struct device *, uint32 *stride_out);
// Copy a rectangle of the back buffer to the display. Coordinates are in
// pixels; the whole screen is (0, 0, width, height).
void (*present)(struct device *, int x, int y, int w, int h);
// Block until the display is between frames. Optional -- a driver that
// cannot tell leaves this null, and present() then simply tears less than
// drawing directly would.
void (*wait_vblank)(struct device *);
};
// The bound display, or 0. Convenience over device_find_class().
struct device *display_get(void);
// Wrappers that do nothing gracefully when there is no display or the driver
// left an op null, so callers are not each written around a maybe-null vtable.
int display_mode(struct display_mode *out);
void *display_acquire(uint32 *stride_out);
void display_present(int x, int y, int w, int h);
void display_wait_vblank(void);
// Drive the whole path once and draw a test pattern. `echo d > /proc/sysrq`.
void display_selftest(void);
// Draw a text specimen through the display class. `echo t > /proc/sysrq`.
void text_selftest(void);

43
include/dma.h Normal file
View file

@ -0,0 +1,43 @@
#pragma once
// Physically contiguous memory for devices that read and write it themselves.
//
// kalloc() hands out 4 KB pages from a free list, in whatever order they were
// released. That is exactly what a page table wants and exactly what a device
// cannot use: an xHCI command ring, a NIC's descriptor array or a virtio
// queue is a single physically contiguous object that the hardware walks
// without any idea that paging exists. Two kalloc'd pages are adjacent in the
// kernel's address space only by luck.
//
// So DMA memory comes from an arena carved out of the top of physical memory
// before kalloc ever sees it, and is handed out contiguous and aligned.
//
// On x86 this memory needs no special cacheability. The PCI bus is cache
// coherent: a device's write invalidates the corresponding cache line, and a
// CPU write is snooped out of the store buffer before the device sees stale
// data. Architectures without that guarantee need explicit cache maintenance
// around every descriptor access, and porting this file is where that would
// go. What is *not* free even here is ordering -- the compiler and the CPU
// will happily reorder stores to a ring, so a driver still needs a barrier
// between filling a descriptor and telling the device about it.
#define DMA_ARENA_BYTES (4*1024*1024)
void dma_init(void *vstart, void *vend);
// Zeroed, physically contiguous, at least `align`-aligned (align must be a
// power of two). Returns a kernel virtual address, or 0.
void *dma_alloc(uint64 size, uint64 align);
// `size` must be the size the allocation was made with, as in Linux's
// dma_free_coherent(). Tracking it here would mean a second table whose only
// job is to remember something the caller already knows.
void dma_free(void *p, uint64 size);
// The address to give the device. Kernel memory is direct-mapped, so this is
// just V2P -- but drivers should say what they mean, because on a machine
// with an IOMMU these stop being the same number.
addr_t dma_phys(const void *p);
uint64 dma_free_bytes(void);
uint64 dma_total_bytes(void);

165
include/e1000.h Normal file
View file

@ -0,0 +1,165 @@
#pragma once
// Intel 8254x gigabit Ethernet — the register and descriptor layout.
//
// From Intel's public "PCI/PCI-X Family of Gigabit Ethernet Controllers
// Software Developer's Manual" (317453). A public document with no licence on
// what you write from it, which is why this is written rather than ported: see
// docs/licensing.md and docs/roadmap.md §1.
//
// QEMU's `-device e1000` is an 82540EM and implements enough of the manual to
// be worth targeting; it is also what the default `-net nic` gives you.
#define E1000_VENDOR 0x8086
// The 8254x family: PCI/PCI-X gigabit controllers that share the register map,
// descriptor format and EEPROM interface this driver implements.
//
// The device IDs are transcribed from FreeBSD's `sys/dev/e1000/e1000_hw.h`
// (Copyright (c) 2001-2020, Intel Corporation, BSD 3-clause -- verified to
// carry no advertising clause; see docs/licensing.md and NOTICE). They are
// data, not logic: the driver below is still written from Intel's manual
// 317453, and nothing of FreeBSD's implementation is used.
//
// This matters more than it looks. The driver bound exactly one device -- the
// 82540EM QEMU emulates -- which is fine for a virtual machine and useless on
// the sort of second-hand hardware a system like this actually gets run on.
// These are the cards in every desktop and server of that generation.
//
// Deliberately *not* included: the PCIe 8257x parts (82571-82574) and anything
// newer. They present a similar register map but differ in NVM access and
// initialisation, and claiming a device this driver has not been shown to
// initialise is worse than not claiming it -- the card binds, reports a MAC of
// nonsense, and nothing works for reasons that look nothing like the cause.
#define E1000_DEV_82540EM 0x100E
#define E1000_DEV_82540EM_LOM 0x1015
#define E1000_DEV_82540EP_LOM 0x1016
#define E1000_DEV_82540EP 0x1017
#define E1000_DEV_82540EP_LP 0x101E
#define E1000_DEV_82541EI 0x1013
#define E1000_DEV_82541EI_MOBILE 0x1018
#define E1000_DEV_82541ER_LOM 0x1014
#define E1000_DEV_82541ER 0x1078
#define E1000_DEV_82541GI 0x1076
#define E1000_DEV_82541GI_MOBILE 0x1077
#define E1000_DEV_82541GI_LF 0x107C
#define E1000_DEV_82544EI_FIBER 0x1009
#define E1000_DEV_82544GC_COPPER 0x100C
#define E1000_DEV_82544GC_LOM 0x100D
#define E1000_DEV_82545EM_COPPER 0x100F
#define E1000_DEV_82545EM_FIBER 0x1011
#define E1000_DEV_82545GM_COPPER 0x1026
#define E1000_DEV_82545GM_FIBER 0x1027
#define E1000_DEV_82545GM_SERDES 0x1028
#define E1000_DEV_82546EB_COPPER 0x1010
#define E1000_DEV_82546EB_FIBER 0x1012
#define E1000_DEV_82546EB_QUAD 0x101D
#define E1000_DEV_82546GB_COPPER 0x1079
#define E1000_DEV_82546GB_FIBER 0x107A
#define E1000_DEV_82546GB_SERDES 0x107B
#define E1000_DEV_82547EI 0x1019
// --- registers, byte offsets into BAR 0 ------------------------------------
#define E1000_CTRL 0x0000 // device control
#define E1000_STATUS 0x0008 // device status
#define E1000_EERD 0x0014 // EEPROM read
#define E1000_ICR 0x00C0 // interrupt cause read
#define E1000_IMS 0x00D0 // interrupt mask set
#define E1000_IMC 0x00D8 // interrupt mask clear
#define E1000_RCTL 0x0100 // receive control
#define E1000_TCTL 0x0400 // transmit control
#define E1000_TIPG 0x0410 // transmit inter-packet gap
#define E1000_RDBAL 0x2800 // receive descriptor base, low
#define E1000_RDBAH 0x2804 // receive descriptor base, high
#define E1000_RDLEN 0x2808 // receive descriptor length, in bytes
#define E1000_RDH 0x2810 // receive descriptor head
#define E1000_RDT 0x2818 // receive descriptor tail
#define E1000_TDBAL 0x3800
#define E1000_TDBAH 0x3804
#define E1000_TDLEN 0x3808
#define E1000_TDH 0x3810
#define E1000_TDT 0x3818
#define E1000_MTA 0x5200 // multicast table array, 128 entries
#define E1000_RAL 0x5400 // receive address low (the MAC filter)
#define E1000_RAH 0x5404 // receive address high
// CTRL
#define E1000_CTRL_RST (1 << 26)
#define E1000_CTRL_ASDE (1 << 5) // auto-speed detection
#define E1000_CTRL_SLU (1 << 6) // set link up
// STATUS
#define E1000_STATUS_LU (1 << 1) // link up
// EERD
#define E1000_EERD_START (1 << 0)
#define E1000_EERD_DONE (1 << 4)
#define E1000_EERD_ADDR_SHIFT 8
#define E1000_EERD_DATA_SHIFT 16
// RCTL
#define E1000_RCTL_EN (1 << 1) // receiver enable
#define E1000_RCTL_SBP (1 << 2) // store bad packets
#define E1000_RCTL_UPE (1 << 3) // unicast promiscuous
#define E1000_RCTL_MPE (1 << 4) // multicast promiscuous
#define E1000_RCTL_LBM_NONE (0 << 6)
#define E1000_RCTL_BAM (1 << 15) // accept broadcast
#define E1000_RCTL_SZ_2048 (0 << 16) // buffer size, with BSEX clear
#define E1000_RCTL_SECRC (1 << 26) // strip the Ethernet CRC
// TCTL
#define E1000_TCTL_EN (1 << 1)
#define E1000_TCTL_PSP (1 << 3) // pad short packets
#define E1000_TCTL_CT_SHIFT 4 // collision threshold
#define E1000_TCTL_COLD_SHIFT 12 // collision distance
// Transmit descriptor command bits
#define E1000_TXD_CMD_EOP (1 << 0) // end of packet
#define E1000_TXD_CMD_IFCS (1 << 1) // insert FCS/CRC
#define E1000_TXD_CMD_RS (1 << 3) // report status
#define E1000_TXD_STAT_DD (1 << 0) // descriptor done
// Receive descriptor status bits
#define E1000_RXD_STAT_DD (1 << 0)
#define E1000_RXD_STAT_EOP (1 << 1)
// Interrupt causes worth unmasking.
#define E1000_ICR_TXDW (1 << 0) // transmit descriptor written back
#define E1000_ICR_LSC (1 << 2) // link status change
#define E1000_ICR_RXDMT0 (1 << 4) // receive descriptor minimum threshold
#define E1000_ICR_RXT0 (1 << 7) // receiver timer
// --- descriptors -----------------------------------------------------------
//
// Both are 16 bytes and the hardware reads them by physical address, so the
// rings must be physically contiguous and 16-byte aligned.
struct e1000_tx_desc {
uint64 addr;
uint16 length;
uint8 cso; // checksum offset
uint8 cmd;
uint8 status;
uint8 css; // checksum start
uint16 special;
} __attribute__((packed));
struct e1000_rx_desc {
uint64 addr;
uint16 length;
uint16 checksum;
uint8 status;
uint8 errors;
uint16 special;
} __attribute__((packed));
// Ring sizes. The manual requires the descriptor ring length to be a multiple
// of 128 bytes, i.e. a multiple of 8 descriptors.
#define E1000_NTX 16
#define E1000_NRX 16
#define E1000_BUFSZ 2048

35
include/elf.h Normal file
View file

@ -0,0 +1,35 @@
#define ELF_MAGIC 0x464C457FU
struct elfhdr {
uint32 magic;
uchar elf[12];
uint16 type;
uint16 machine;
uint32 version;
uint64 entry;
uint64 phoff;
uint64 shoff;
uint32 flags;
uint16 ehsize;
uint16 phentsize;
uint16 phnum;
uint16 shentsize;
uint16 shnum;
uint16 shstrndx;
};
struct proghdr {
uint32 type;
uint32 flags;
uint64 off;
uint64 vaddr;
uint64 paddr;
uint64 filesz;
uint64 memsz;
uint64 align;
};
#define ELF_PROG_LOAD 1
#define ELF_PROG_FLAG_EXEC 1
#define ELF_PROG_FLAG_WRITE 2
#define ELF_PROG_FLAG_READ 4

60
include/errno.h Normal file
View file

@ -0,0 +1,60 @@
// Error numbers, matching the Linux x86_64 ABI values so that musl-linked
// programs interpret syscall failures correctly. Kernel code returns these
// negated (e.g. `return -ENOSYS;`), exactly like Linux does internally.
#ifndef SCHUNIX_ERRNO_H
#define SCHUNIX_ERRNO_H
#define EPERM 1 // Operation not permitted
#define ENOENT 2 // No such file or directory
#define ESRCH 3 // No such process
#define EINTR 4 // Interrupted system call
#define EIO 5 // I/O error
#define ENXIO 6 // No such device or address
#define E2BIG 7 // Argument list too long
#define ENOEXEC 8 // Exec format error
#define EBADF 9 // Bad file descriptor
#define ECHILD 10 // No child processes
#define EAGAIN 11 // Try again
#define ENOMEM 12 // Out of memory
#define EACCES 13 // Permission denied
#define EFAULT 14 // Bad address
#define EBUSY 16 // Device or resource busy
#define EEXIST 17 // File exists
#define EXDEV 18 // Cross-device link
#define ENODEV 19 // No such device
#define ENOTDIR 20 // Not a directory
#define EISDIR 21 // Is a directory
#define EINVAL 22 // Invalid argument
#define ENFILE 23 // File table overflow
#define EMFILE 24 // Too many open files
#define ENOTTY 25 // Not a typewriter
#define EFBIG 27 // File too large
#define ENOSPC 28 // No space left on device
#define ESPIPE 29 // Illegal seek
#define EROFS 30 // Read-only file system
#define EMLINK 31 // Too many links
#define EPIPE 32 // Broken pipe
#define ERANGE 34 // Math result not representable
#define ENAMETOOLONG 36 // File name too long
#define ENOSYS 38 // Function not implemented
#define ENOTEMPTY 39 // Directory not empty
#define ELOOP 40 // Too many symbolic links encountered
// Sockets. Same Linux x86_64 values, so strerror() in a musl-linked program
// prints the message the programmer expected rather than a neighbouring one.
#define ENOTSOCK 88 // Socket operation on non-socket
#define EDESTADDRREQ 89 // Destination address required
#define EMSGSIZE 90 // Message too long
#define EPROTOTYPE 91 // Protocol wrong type for socket
#define ENOPROTOOPT 92 // Protocol not available
#define EPROTONOSUPPORT 93 // Protocol not supported
#define EOPNOTSUPP 95 // Operation not supported on transport endpoint
#define EAFNOSUPPORT 97 // Address family not supported by protocol
#define EADDRINUSE 98 // Address already in use
#define EADDRNOTAVAIL 99 // Cannot assign requested address
#define ECONNRESET 104 // Connection reset by peer
#define EISCONN 106 // Transport endpoint is already connected
#define ENOTCONN 107 // Transport endpoint is not connected
#define ECONNREFUSED 111 // Connection refused
#endif // SCHUNIX_ERRNO_H

95
include/fb.h Normal file
View file

@ -0,0 +1,95 @@
#pragma once
// Framebuffer device ABI -- /dev/fb0.
//
// These are Linux's fbdev request numbers and structure layouts, not ours.
// Schunix invented this device, so nothing forced the choice; matching Linux
// was still the right one. A framebuffer is the first thing a graphics
// program looks for, and every such program already knows how to ask
// FBIOGET_VSCREENINFO. Inventing a private struct would have meant patching
// each one we ever port, and -- worse -- a Linux-ABI binary calling
// FBIOGET_VSCREENINFO would have gotten a *differently shaped* answer to a
// request it thought it understood, which is the failure mode that made
// `>>` truncate back when include/fcntl.h held xv6's open flags instead of
// Linux's. Same lesson, applied before it bites rather than after.
//
// Plain C types throughout (no types.h) so userspace can include this
// directly. Both sides are LP64.
#define FBIOGET_VSCREENINFO 0x4600
#define FBIOPUT_VSCREENINFO 0x4601
#define FBIOGET_FSCREENINFO 0x4602
#define FBIOBLANK 0x4611
// fb_fix_screeninfo.type
#define FB_TYPE_PACKED_PIXELS 0
// fb_fix_screeninfo.visual
#define FB_VISUAL_TRUECOLOR 2
// fb_var_screeninfo.activate
#define FB_ACTIVATE_NOW 0
// One colour channel's position within a pixel. `offset` is the bit position
// of the channel's least significant bit; `length` is how many bits it gets.
// A length of 0 means the channel does not exist -- which is how an opaque
// framebuffer reports `transp`.
struct fb_bitfield {
unsigned int offset;
unsigned int length;
unsigned int msb_right; // != 0 means bit 0 is the MSB; never here
};
struct fb_var_screeninfo {
unsigned int xres; // visible resolution
unsigned int yres;
unsigned int xres_virtual; // virtual resolution; == visible, no panning
unsigned int yres_virtual;
unsigned int xoffset; // offset of visible area within virtual
unsigned int yoffset;
unsigned int bits_per_pixel;
unsigned int grayscale; // 0 == colour
struct fb_bitfield red;
struct fb_bitfield green;
struct fb_bitfield blue;
struct fb_bitfield transp;
unsigned int nonstd; // 0 == standard pixel format
unsigned int activate;
unsigned int height; // physical size in mm; 0 == unknown, and
unsigned int width; // VBE does not tell us, so it stays 0
unsigned int accel_flags;
// Timings. The mode is whatever the bootloader's VBE call established and
// we cannot change it, so these are all reported as zero rather than
// invented.
unsigned int pixclock;
unsigned int left_margin;
unsigned int right_margin;
unsigned int upper_margin;
unsigned int lower_margin;
unsigned int hsync_len;
unsigned int vsync_len;
unsigned int sync;
unsigned int vmode;
unsigned int rotate;
unsigned int colorspace;
unsigned int reserved[4];
};
struct fb_fix_screeninfo {
char id[16]; // "schunixfb"
unsigned long smem_start; // physical address of the framebuffer
unsigned int smem_len; // its length in bytes
unsigned int type;
unsigned int type_aux;
unsigned int visual;
unsigned short xpanstep; // 0 == panning unsupported
unsigned short ypanstep;
unsigned short ywrapstep;
unsigned int line_length; // bytes per scanline (the VBE stride, which
// is NOT always xres * bytes_per_pixel)
unsigned long mmio_start; // no separate register aperture
unsigned int mmio_len;
unsigned int accel; // no acceleration
unsigned short capabilities;
unsigned short reserved[2];
};

43
include/fcntl.h Normal file
View file

@ -0,0 +1,43 @@
#pragma once
// open(2) flags.
//
// These are the *Linux x86-64* values, and they have to be: every program in
// the userland is built against a libc that sends Linux flag values, and the
// kernel reads them with these constants. They disagreed for a long time, with
// results that looked like filesystem corruption rather than like a mistake --
// Linux O_APPEND (0x400) landed on Schunix's O_TRUNC, so `cmd >> file`
// truncated the file it was meant to extend, and Linux O_TRUNC (0x200) landed
// on O_CREATE, so `cmd > file` left whatever was past the new end in place.
// Neither failure pointed anywhere near a header.
//
// Do not tidy these into a neat sequence. They are an external interface.
#define O_RDONLY 0x000000
#define O_WRONLY 0x000001
#define O_RDWR 0x000002
#define O_ACCMODE 0x000003
#define O_CREATE 0x000040 /* Linux O_CREAT (0100) */
#define O_CREAT O_CREATE /* the spelling every program uses */
#define O_EXCL 0x000080 /* Linux O_EXCL (0200) */
#define O_NOCTTY 0x000100 /* Linux O_NOCTTY (0400) */
#define O_TRUNC 0x000200 /* Linux O_TRUNC (01000) */
#define O_APPEND 0x000400 /* Linux O_APPEND (02000) */
#define O_NONBLOCK 0x000800 /* Linux O_NONBLOCK (04000); no-op here */
#define O_DIRECTORY 0x010000 /* Linux O_DIRECTORY (0200000) */
#define O_NOFOLLOW 0x020000 /* Linux O_NOFOLLOW (0400000) */
#define O_CLOEXEC 0x080000 /* Linux O_CLOEXEC (02000000) */
// Schunix-only, placed above every flag Linux defines so it can never be
// mistaken for one. 0x40000 was used before and collides with Linux O_NOATIME.
#define O_EXTENT 0x8000000 /* sparse-extent hint */
#define F_DUPFD 0
#define F_GETFD 1
#define F_SETFD 2
#define F_GETFL 3
#define F_SETFL 4
#define F_DUPFD_CLOEXEC 1030 // Linux value
#define FD_CLOEXEC 1

132
include/file.h Normal file
View file

@ -0,0 +1,132 @@
struct file {
enum { FD_NONE, FD_PIPE, FD_INODE, FD_SOCKET } type;
int ref; // reference count
char readable;
char writable;
// O_NONBLOCK. A property of the open file description, not of the
// descriptor, which is why it lives here and not in myproc()->ofile_flags --
// dup() shares it and F_SETFL on either fd changes it for both, exactly as
// POSIX says.
char nonblock;
struct pipe *pipe;
struct inode *ip;
struct socket *sock;
uint64 off;
};
// ---------------------------------------------------------------------------
// Filesystem operations
//
// One table per filesystem, chosen by iget() from the device number and hung
// off the inode. Everything above this line -- the syscall layer, exec, the
// page cache -- calls the wrappers in fs.c and never learns which filesystem it
// is talking to.
//
// A vtable rather than a chain of `if (dev == SCHFS_DEV)` because there are two
// filesystems today and there will be more: the whole point of the exercise is
// that adding one is a new table, not another branch in fifteen functions.
//
// Every hook takes an inode that is already locked, except ialloc (which has no
// inode yet) and iload (which is what makes one valid in the first place).
// ---------------------------------------------------------------------------
struct stat;
struct fs_ops {
const char *name;
// Fill in the type/size/link fields of a freshly iget()'d inode.
void (*iload)(struct inode *);
// Write those fields back to disk.
void (*istore)(struct inode *);
// The last link is gone and nobody has it open: release the object.
void (*ifree)(struct inode *);
int (*read)(struct inode *, int user_dst, uint64 dst, uint64 off, uint n);
int (*write)(struct inode *, int user_src, uint64 src, uint64 off, uint n);
// Set the length. Growing is allowed only where the filesystem can represent
// the gap; v1 cannot and ignores it.
void (*truncate)(struct inode *, uint64 newsize);
// Directory operations. `poff` is an opaque cookie identifying where the
// entry lives, meaningful only to the same filesystem's dirunlink.
struct inode *(*dirlookup)(struct inode *dp, char *name, uint *poff);
int (*dirlink)(struct inode *dp, char *name, uint64 inum);
int (*dirunlink)(struct inode *dp, char *name, uint off);
int (*dirempty)(struct inode *dp);
// Create an object with no name yet. The caller sets nlink and calls
// dirlink; until it does, the object is unreachable.
struct inode *(*ialloc)(uint dev, short type);
// Read directory entries into a getdents64-shaped stream. `off` is an opaque
// position that starts at 0 and is echoed back; returns bytes written, 0 at
// the end of the directory, or negative on error.
int (*getdents)(struct inode *dp, char *out, int cap, uint64 *off);
};
// In-memory inode.
//
// `inum` and `size` are 64-bit because the filesystem underneath may be: SchFS
// object ids and file sizes are both uint64 on disk, and a 32-bit copy here
// would silently truncate them into a different file. The v1 filesystem uses a
// small fraction of the range and is unaffected.
struct inode {
uint dev;
uint64 inum;
int ref;
struct sleeplock lock;
int valid;
const struct fs_ops *ops; // chosen by iget from dev; never null once held
short type;
short major;
short minor;
short nlink;
uint64 size;
uint rwmode;
uint supermode;
uint showmode;
uint atime;
uint mtime;
uint ctime;
uint addrs[NDIRECT+3];
};
#define I_VALID 0x2
// Device number that means "the mounted SchFS volume". Real disks are 0 and 1,
// and this is deliberately far from them so a stray value never looks like a
// SchFS inode.
#define SCHFS_DEV 64
// Device number that means "the synthetic /proc". Like SCHFS_DEV, it is
// deliberately nowhere near a real disk's 0 or 1.
#define PROCFS_DEV 65
// table mapping major device number to
// device functions
struct devsw {
int (*read)(struct inode*, uint, char*, int);
int (*write)(struct inode*, uint, char*, int);
// Optional. Returns 0 when a read would block, which is the only thing
// fileread needs to know to honour O_NONBLOCK without every device driver
// growing a flags argument. A device that omits this is treated as always
// ready, which is the right answer for a disk and for /dev/zero.
int (*ready)(struct inode*);
// Optional. The last descriptor for this open file is going away. A device
// that hands a program exclusive-feeling control of the hardware needs this
// to put the hardware back -- /dev/fb0 uses it to give the text console its
// screen back when whatever was drawing on it exits.
void (*close)(struct inode*);
// Optional. A descriptor has just been opened on this device. /dev/input
// uses it to discard events that arrived while nobody was listening -- see
// inputopen().
void (*open)(struct inode*);
};
extern struct devsw devsw[];
#define CONSOLE 1
// Major number of /dev/input/eventN. The minor is the device index.
#define INPUT_MAJOR 7

4627
include/font.h Normal file

File diff suppressed because it is too large Load diff

203
include/fs.h Normal file
View file

@ -0,0 +1,203 @@
// SCHFS - On-disk file system format.
// Both the kernel and user programs use this header file.
//
// Changes from original:
// - struct dinode gains atime, mtime, ctime (timestamps) and checksum
// (CRC32c). Padding reduced from 44 to 28 bytes; struct stays 128 bytes.
// - struct superblock gains checksum field.
// - struct fsv1_extent added for T_EXTENT inode block mapping.
// - OVERFLOW_DIR_START / OVERFLOW_DIR_END replace the bare "113 * BSIZE"
// magic numbers used in fs.c and mkfs.c.
#ifndef FS_H
#define FS_H
#define ROOTINO 1 // root i-number
#define BSIZE 1024 // block size
// Permission mode bits (rwmode field)
#define RW 3 // 11 read+write
#define W_ 1 // 01 write-only
#define R_ 2 // 10 read-only
#define NONE 0 // 00 no access
// ---------------------------------------------------------------------------
// Superblock
// ---------------------------------------------------------------------------
// Disk layout:
// [ boot | super | log | inode-bitmap | inode-blocks | block-bitmap | data ]
struct superblock {
uint magic; // Must be FSMAGIC
uint size; // Size of file system image (blocks)
uint nblocks; // Number of data blocks
uint ninodes; // Number of inodes
uint nlog; // Number of log blocks
uint logstart; // Block number of first log block
uint inodestart; // Block number of first inode block
uint bmapstart; // Block number of first free-block bitmap block
uint ibmapstart; // Block number of first inode-bitmap block
uint freeinodes; // Count of free inodes
uint freeblocks; // Count of free blocks
uint checksum; // CRC32c of this struct (field zeroed during computation)
};
extern struct superblock sb;
#define FSMAGIC 0x10203040
// ---------------------------------------------------------------------------
// Block / inode geometry
// ---------------------------------------------------------------------------
#define NDIRECT 12
#define NINDIRECT (BSIZE / sizeof(uint))
// Maximum file size in blocks: direct + 1x + 2x + 3x indirect
#define MAXFILE (NDIRECT \
+ NINDIRECT \
+ (NINDIRECT * NINDIRECT) \
+ (NINDIRECT * NINDIRECT * NINDIRECT))
// ---------------------------------------------------------------------------
// Extent descriptor (T_EXTENT inodes only)
//
// Up to MAX_INLINE_EXTENTS are packed into ip->addrs[0..NDIRECT-1].
// addrs[] = NDIRECT uints = 12*4 = 48 bytes
// each fsv1_extent = 12 bytes → 48/12 = 4 inline extents
// (addrs[NDIRECT], [NDIRECT+1], [NDIRECT+2] remain as indirect pointers)
//
// For files needing more extents, addrs[NDIRECT] points to an indirect block
// of BSIZE/sizeof(struct fsv1_extent) = 85 additional extents.
// ---------------------------------------------------------------------------
// Renamed from "schfs_extent". The new format in include/schfs.h has its own,
// completely different, struct of that name -- 64-bit fields and a refcount --
// and any file including both headers hit a redefinition error. Two structs
// with one name and two layouts is a trap worth removing rather than working
// around; this one belongs to the v1 format and dies with it.
struct fsv1_extent {
uint start_block; // logical block number in the file (first of run)
uint start_blkaddr; // physical disk block address
uint len; // number of contiguous blocks in this run
};
// Inline extents packed into addrs[0 .. NDIRECT-1] only.
#define MAX_INLINE_EXTENTS (NDIRECT * sizeof(uint) / sizeof(struct fsv1_extent))
// ---------------------------------------------------------------------------
// On-disk inode (exactly 128 bytes; IPB = 8 inodes per 1024-byte block)
//
// Byte layout:
// 0 short type 2
// 2 short major 2
// 4 short minor 2
// 6 short nlink 2
// 8 uint size 4
// 12 uint rwmode 4
// 16 uint supermode 4
// 20 uint addrs[15] 60 T_EXTENT: packed fsv1_extent[4] in [0..11], rest normal
// 80 uint showmode 4
// 84 uint atime 4 ← last access time (Unix seconds)
// 88 uint mtime 4 ← last modification time
// 92 uint ctime 4 ← last metadata-change time
// 96 uint checksum 4 ← CRC32c (zeroed during computation)
// 100 uchar pad[28] 28 ← was 44; reduced by 16 for the 4 new fields
// 128 bytes total
// ---------------------------------------------------------------------------
struct dinode {
short type; // file type
short major; // major device number (T_DEVICE only)
short minor; // minor device number (T_DEVICE only)
short nlink; // hard-link count
uint size; // file size in bytes
uint rwmode; // read/write permission flags
uint supermode; // superuser-only flag
uint addrs[NDIRECT + 3]; // block addresses / packed extent entries
uint showmode; // visibility flag
uint atime; // last access time (seconds since epoch)
uint mtime; // last modification time
uint ctime; // last metadata-change time
uint checksum; // CRC32c of this dinode (field = 0 when hashing)
uchar pad[28]; // reserved padding (struct = 128 bytes)
};
// Inodes per block
#define IPB (BSIZE / sizeof(struct dinode))
// Block containing inode i
#define IBLOCK(i, sb) ((i) / IPB + (sb).inodestart)
// Bitmap bits per block
#define BPB (BSIZE * 8)
// Block of free-block bitmap containing bit for block b
#define BBLOCK(b, sb) ((b) / BPB + (sb).bmapstart)
// Block of inode bitmap containing bit for inode i
#define IBBLOCK(i, sb) ((i) / BPB + (sb).ibmapstart)
// ---------------------------------------------------------------------------
// Directory entry
// ---------------------------------------------------------------------------
// 30, not 14.
//
// 14 was xv6's, and the v1 filesystem truncated to it *silently*: a file called
// JetBrainsMono-Regular.ttf was stored as "JetBrainsMono-", could not be opened
// by its real name, and would have collided outright with
// JetBrainsMono-Bold.ttf. Any two files sharing a 14-character prefix mapped to
// one entry. That is data loss, not a display limit.
//
// The value is chosen so that `struct dirent` is exactly 32 bytes, because the
// directory HTree below is laid out in *bytes* and a bucket must stay 256 bytes
// (see DIRENT_BUCKET_BYTES). Going from 16-byte to 32-byte entries therefore
// halves the slots per bucket from 16 to 8 and changes no offset anywhere else
// -- HASHRANGE, the overflow region and MAXFSIZE all keep their values. The
// cost is more overflow use in heavily collided directories, which is a far
// better trade than silently mangling names.
//
// It is still not POSIX's 255. Getting there means reshaping the directory
// format, which wants the on-disk version policy SchFS is getting first.
#define DIRSIZ 30
struct dirent {
ushort inum;
char name[DIRSIZ];
};
// ---------------------------------------------------------------------------
// Directory HTree constants
//
// BKDRHash(name) returns a value in [16, 16 + HASHRANGE).
// Each bucket is 256 bytes: 8 dirent slots of 32 bytes. It was 16 slots of 16
// until DIRSIZ grew; the byte size is what the layout depends on, so it is the
// thing held constant.
//
// With HASHRANGE=443:
// max primary end byte = (16 + 443) * 256 = 117 504 (~114.75 blocks)
// OVERFLOW_DIR_START = 113 * BSIZE = 115 712
// OVERFLOW_DIR_END = 115 * BSIZE = 117 760
// MAXFSIZE = 119 * BSIZE = 121 856
// ---------------------------------------------------------------------------
#define DIRENT_NUM 7168
#define FIRST_LAYER_NODE_NUM 112
#define OVERFLOW_BLOCK (FIRST_LAYER_NODE_NUM + 1)
#define NUM_DIRENT_PER_BLOCK (BSIZE / sizeof(struct dirent))
#define SECOND_LAYER_NODE_NUM NUM_DIRENT_PER_BLOCK
#define HASHRANGE 443
// One hash bucket, in bytes. Every offset in the HTree is derived from this, so
// it must not change when DIRSIZ does -- see the note on DIRSIZ.
#define DIRENT_BUCKET_BYTES 256
#define DIRENT_PER_BUCKET (DIRENT_BUCKET_BYTES / sizeof(struct dirent))
#define MAXFSIZE (119 * BSIZE)
// Overflow bucket: shared between fs.c and mkfs.c.
// These replace the bare "113 * BSIZE" / "115 * BSIZE" literals.
#define OVERFLOW_DIR_START (113 * BSIZE)
#define OVERFLOW_DIR_END (115 * BSIZE)
#endif // FS_H

93
include/input.h Normal file
View file

@ -0,0 +1,93 @@
#pragma once
#include "types.h"
// Raw input events -- Linux's evdev interface.
//
// The console gives characters. That is the right thing for a shell and the
// wrong thing for everything else: a character stream has no key *releases*,
// no way to tell left shift from right, no notion of a key being held, and no
// mouse at all. A game holding W to walk forward, or a compositor deciding
// which window a click landed in, needs the events underneath the characters.
//
// The layout is Linux's, deliberately. It is what every program that reads input
// already speaks -- SDL, X, libinput, every game engine -- so a program that
// runs on Linux reads input here without a porting layer. It costs nothing to
// match: the struct is four fields.
//
// Nodes are /dev/input/event0 (keyboard) and /dev/input/event1 (mouse).
struct input_timeval {
int64 tv_sec;
int64 tv_usec;
};
struct input_event {
struct input_timeval time;
uint16 type;
uint16 code;
int32 value;
};
// Event types.
#define EV_SYN 0x00
#define EV_KEY 0x01
#define EV_REL 0x02
#define EV_ABS 0x03
#define EV_MSC 0x04
#define SYN_REPORT 0
// Relative axes.
#define REL_X 0x00
#define REL_Y 0x01
#define REL_WHEEL 0x08
// Buttons live in the EV_KEY code space alongside keys, which is why the
// keyboard's codes stop well below 0x100.
#define BTN_LEFT 0x110
#define BTN_RIGHT 0x111
#define BTN_MIDDLE 0x112
// Key codes worth naming. The rest are the AT scancode-set-1 numbers, which
// Linux's keycodes were derived from and still match for everything below
// 0x54 -- that is not a coincidence and it is why the PS/2 path needs no
// translation table for unprefixed bytes.
#define KEY_RESERVED 0
#define KEY_ESC 1
#define KEY_ENTER 28
#define KEY_LEFTCTRL 29
#define KEY_LEFTSHIFT 42
#define KEY_RIGHTSHIFT 54
#define KEY_LEFTALT 56
#define KEY_SPACE 57
#define KEY_RIGHTCTRL 97
#define KEY_RIGHTALT 100
#define KEY_HOME 102
#define KEY_UP 103
#define KEY_PAGEUP 104
#define KEY_LEFT 105
#define KEY_RIGHT 106
#define KEY_END 107
#define KEY_DOWN 108
#define KEY_PAGEDOWN 109
#define KEY_INSERT 110
#define KEY_DELETE 111
#define KEY_LEFTMETA 125
#define KEY_RIGHTMETA 126
#define KEY_MAX 255
// EVIOCGRAB -- take/release exclusive access to a device.
//
// Linux's _IOW('E', 0x90, int). Spelled as the resulting constant rather than
// built from an _IOW macro because Schunix has no ioctl-encoding macros and
// inventing a set just for this would be a bigger change than the feature.
// A non-zero argument grabs, zero releases; the argument is passed by value.
#define EVIOCGRAB 0x40044590
// Which device an event came from. Both are minor numbers under the input
// major, and both are the index into the driver's array.
#define INPUT_KBD 0
#define INPUT_MOUSE 1
#define NINPUTDEV 2

43
include/irq.h Normal file
View file

@ -0,0 +1,43 @@
#pragma once
// Hardware interrupt registration.
//
// Until this existed, trap() was a switch statement listing every interrupt
// the kernel knew about, and adding a device meant editing the trap handler.
// That is fine while the devices are the four the PC has always had at fixed
// pins; it stops being fine the moment a device's IRQ is whatever the BIOS
// decided to put in its PCI config space this boot. A driver cannot write
// `case T_IRQ0 + IRQ_XHCI:` because there is no such constant -- it only
// learns its line at probe time.
//
// So: a line has a chain of handlers, a driver adds itself to one at probe
// time, and enabling the line is a consequence of registering rather than a
// separate call somebody can forget.
//
// Chains matter more than they look. PCI interrupt pins are *shared*: four
// INTx lines are routed to a handful of IOAPIC inputs, so two unrelated
// devices routinely land on the same one. A handler must therefore check
// whether its own device actually raised the interrupt and do nothing if it
// did not.
#define NIRQ 24 // IOAPIC redirection entries on a PC
#define NCHAIN 4 // handlers that may share one line
typedef void (*irq_handler_t)(void *arg);
// Returns 0, or -1 if the line is out of range, reserved, or full.
// Registering enables the line; the last unregister masks it again.
//
// `level_low` selects PCI's signalling (level-triggered, active low) rather
// than ISA's (edge-triggered, active high). Getting this wrong does not fail
// cleanly: an edge-configured level interrupt fires once and then wedges,
// because the device keeps the line asserted and no further edge ever comes.
int irq_register(int irq, irq_handler_t fn, void *arg, const char *name,
int level_low);
void irq_unregister(int irq, irq_handler_t fn, void *arg);
// Called from trap() with the IOAPIC pin number, not the vector.
void irq_dispatch(int irq);
void irq_init(void);
int irq_info(char *buf, int cap); // /proc/interrupts

112
include/kbd.h Normal file
View file

@ -0,0 +1,112 @@
// PC keyboard interface constants
#define KBSTATP 0x64 // kbd controller status port(I)
#define KBS_DIB 0x01 // kbd data in buffer
#define KBDATAP 0x60 // kbd data port(I)
#define NO 0
#define SHIFT (1<<0)
#define CTL (1<<1)
#define ALT (1<<2)
#define CAPSLOCK (1<<3)
#define NUMLOCK (1<<4)
#define SCROLLLOCK (1<<5)
#define E0ESC (1<<6)
// Special keycodes
#define KEY_HOME 0xE0
#define KEY_END 0xE1
#define KEY_UP 0xE2
#define KEY_DN 0xE3
#define KEY_LF 0xE4
#define KEY_RT 0xE5
#define KEY_PGUP 0xE6
#define KEY_PGDN 0xE7
#define KEY_INS 0xE8
#define KEY_DEL 0xE9
// C('A') == Control-A
#define C(x) (x - '@')
static uchar shiftcode[256] =
{
[0x1D] CTL,
[0x2A] SHIFT,
[0x36] SHIFT,
[0x38] ALT,
[0x9D] CTL,
[0xB8] ALT
};
static uchar togglecode[256] =
{
[0x3A] CAPSLOCK,
[0x45] NUMLOCK,
[0x46] SCROLLLOCK
};
static uchar normalmap[256] =
{
NO, 0x1B, '1', '2', '3', '4', '5', '6', // 0x00
'7', '8', '9', '0', '-', '=', '\b', '\t',
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', // 0x10
'o', 'p', '[', ']', '\n', NO, 'a', 's',
'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', // 0x20
'\'', '`', NO, '\\', 'z', 'x', 'c', 'v',
'b', 'n', 'm', ',', '.', '/', NO, '*', // 0x30
NO, ' ', NO, NO, NO, NO, NO, NO,
NO, NO, NO, NO, NO, NO, NO, '7', // 0x40
'8', '9', '-', '4', '5', '6', '+', '1',
'2', '3', '0', '.', NO, NO, NO, NO, // 0x50
[0x9C] '\n', // KP_Enter
[0xB5] '/', // KP_Div
[0xC8] KEY_UP, [0xD0] KEY_DN,
[0xC9] KEY_PGUP, [0xD1] KEY_PGDN,
[0xCB] KEY_LF, [0xCD] KEY_RT,
[0x97] KEY_HOME, [0xCF] KEY_END,
[0xD2] KEY_INS, [0xD3] KEY_DEL
};
static uchar shiftmap[256] =
{
NO, 033, '!', '@', '#', '$', '%', '^', // 0x00
'&', '*', '(', ')', '_', '+', '\b', '\t',
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', // 0x10
'O', 'P', '{', '}', '\n', NO, 'A', 'S',
'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', // 0x20
'"', '~', NO, '|', 'Z', 'X', 'C', 'V',
'B', 'N', 'M', '<', '>', '?', NO, '*', // 0x30
NO, ' ', NO, NO, NO, NO, NO, NO,
NO, NO, NO, NO, NO, NO, NO, '7', // 0x40
'8', '9', '-', '4', '5', '6', '+', '1',
'2', '3', '0', '.', NO, NO, NO, NO, // 0x50
[0x9C] '\n', // KP_Enter
[0xB5] '/', // KP_Div
[0xC8] KEY_UP, [0xD0] KEY_DN,
[0xC9] KEY_PGUP, [0xD1] KEY_PGDN,
[0xCB] KEY_LF, [0xCD] KEY_RT,
[0x97] KEY_HOME, [0xCF] KEY_END,
[0xD2] KEY_INS, [0xD3] KEY_DEL
};
static uchar ctlmap[256] =
{
NO, NO, NO, NO, NO, NO, NO, NO,
NO, NO, NO, NO, NO, NO, NO, NO,
C('Q'), C('W'), C('E'), C('R'), C('T'), C('Y'), C('U'), C('I'),
C('O'), C('P'), NO, NO, '\r', NO, C('A'), C('S'),
C('D'), C('F'), C('G'), C('H'), C('J'), C('K'), C('L'), NO,
NO, NO, NO, C('\\'), C('Z'), C('X'), C('C'), C('V'),
C('B'), C('N'), C('M'), NO, NO, C('/'), NO, NO,
[0x9C] '\r', // KP_Enter
[0xB5] C('/'), // KP_Div
[0xC8] KEY_UP, [0xD0] KEY_DN,
[0xC9] KEY_PGUP, [0xD1] KEY_PGDN,
[0xCB] KEY_LF, [0xCD] KEY_RT,
[0x97] KEY_HOME, [0xCF] KEY_END,
[0xD2] KEY_INS, [0xD3] KEY_DEL
};

534
include/logo.h Normal file
View file

@ -0,0 +1,534 @@
#pragma once
// GENERATED by tools/mklogo.py -- do not edit. Run `make logo`.
// source: Assets/Schunix Small Logo.png
//
// An ink-coverage mask, not colour: 0 is background and full scale is
// solid logo. Whoever draws it picks the colour, so the palette stays in
// include/theme.h and can change without regenerating anything.
//
// Two pixels per byte, high nibble first. Included by boot/stage2main.c
// as well as kernel/dev/vga.c, and stage2 must fit below the 0x10000
// kernel-search buffer -- hence 4 bits rather than 8.
#define LOGO_W 128
#define LOGO_H 128
// Ink at linear pixel index i, 0..255.
#define LOGO_INK(i) ((unsigned char)((((i) & 1) ? (logo_mask[(i) >> 1] & 0xF) \
: (logo_mask[(i) >> 1] >> 4)) * 17))
static const unsigned char logo_mask[LOGO_W * LOGO_H / 2] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x23,0x56,0x79,0xaa,0xbb,
0xbb,0xaa,0x98,0x75,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x47,0x9b,0xbb,0xbb,0xbb,0xcc,0xcc,
0xcc,0xcc,0xcc,0xcb,0xbb,0xb9,0x74,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x47,0x9a,0xaa,0xbb,0xbb,0xbb,0xbb,0xcc,0xcc,
0xcc,0xcc,0xcc,0xcb,0xbb,0xbb,0xbb,0xba,0x75,0x20,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x15,0x8a,0xaa,0xaa,0xaa,0xbb,0xbb,0xbb,0xbb,0xcc,0xcc,
0xcc,0xcc,0xcc,0xcb,0xbb,0xbb,0xbb,0xbb,0xbb,0xb9,0x51,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x37,0x99,0xaa,0xaa,0xaa,0xaa,0xbb,0xbb,0xbb,0xbb,0xcc,0xcc,
0xcc,0xcc,0xcc,0xcb,0xbb,0xbb,0xbb,0xbb,0xbb,0xba,0xaa,0x84,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x01,0x58,0x99,0x99,0xaa,0xaa,0xaa,0xaa,0xbb,0xbb,0xbb,0xbb,0xcc,0xcc,
0xcc,0xcc,0xcc,0xcb,0xbb,0xbb,0xbb,0xbb,0xbb,0xba,0xaa,0xaa,0x96,0x10,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x01,0x69,0x99,0x99,0x99,0xaa,0xaa,0xaa,0xaa,0xbb,0xbb,0xbb,0xbb,0xcc,0xcc,
0xcc,0xcc,0xcc,0xcb,0xbb,0xbb,0xbb,0xbb,0xbb,0xba,0xaa,0xaa,0xaa,0xa7,0x10,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x58,0x99,0x99,0x99,0x99,0xaa,0xaa,0xaa,0xaa,0xbb,0xbb,0xba,0x87,0x76,0x66,
0x66,0x67,0x89,0xab,0xbb,0xbb,0xbb,0xbb,0xbb,0xba,0xaa,0xaa,0xaa,0xaa,0xa6,0x10,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x48,0x88,0x99,0x99,0x99,0x99,0xaa,0xaa,0xaa,0xa9,0x65,0x31,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x13,0x57,0x9b,0xbb,0xbb,0xba,0xaa,0xaa,0xaa,0xaa,0xaa,0x95,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,
0x88,0x88,0x99,0x99,0x99,0x99,0xaa,0xa9,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0xab,0xba,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0x93,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x16,0x88,
0x88,0x88,0x99,0x99,0x99,0x99,0x95,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x6a,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0x99,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x78,0x88,
0x88,0x88,0x99,0x99,0x99,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0xaa,0xaa,0xaa,0xaa,0xaa,
0x99,0x99,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x57,0x78,0x88,
0x88,0x88,0x99,0x98,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0xaa,0xaa,0xaa,0xaa,
0x99,0x99,0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x16,0x77,0x78,0x88,
0x88,0x88,0x98,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xaa,0xaa,0xaa,
0x99,0x99,0x99,0x81,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x77,0x77,0x78,0x88,
0x88,0x88,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xaa,0xaa,
0x99,0x99,0x99,0x99,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x77,0x77,0x78,0x88,
0x88,0x61,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0xaa,
0x99,0x99,0x99,0x99,0x95,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x77,0x77,0x77,0x78,0x88,
0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x49,
0x99,0x99,0x99,0x99,0x99,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x57,0x77,0x77,0x77,0x78,0x86,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x79,0x99,0x99,0x99,0x99,0x96,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x67,0x77,0x77,0x77,0x77,0x30,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x04,0x99,0x99,0x99,0x99,0x99,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x67,0x77,0x77,0x77,0x61,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x28,0x99,0x99,0x99,0x99,0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x66,0x67,0x77,0x77,0x76,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x79,0x99,0x99,0x99,0x98,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x66,0x67,0x77,0x77,0x50,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x06,0x99,0x99,0x99,0x98,0x85,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x66,0x66,0x67,0x77,0x74,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x59,0x99,0x99,0x98,0x88,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x26,0x66,0x66,0x67,0x77,0x30,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x04,0x99,0x99,0x98,0x88,0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x56,0x66,0x66,0x67,0x73,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x49,0x99,0x98,0x88,0x88,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x66,0x66,0x66,0x67,0x30,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x05,0x99,0x98,0x88,0x88,0x70,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x66,0x66,0x66,0x64,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x59,0x98,0x88,0x88,0x86,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x02,0x56,0x66,0x66,0x66,0x50,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x06,0x98,0x88,0x88,0x88,0x30,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x05,0x56,0x66,0x66,0x65,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x88,0x88,0x88,0x71,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x45,0x56,0x66,0x66,0x61,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x88,0x88,0x88,0x86,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x02,0x55,0x56,0x66,0x66,0x20,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x88,0x88,0x88,0x88,0x30,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x05,0x55,0x56,0x66,0x64,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x68,0x88,0x88,0x88,0x70,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x35,0x55,0x56,0x66,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x88,0x88,0x88,0x84,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x55,0x55,0x56,0x66,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x88,0x88,0x88,0x87,0x10,0x00,0x00,0x00,
0x00,0x00,0x00,0x03,0x55,0x55,0x56,0x64,0x00,0x00,0x00,0x00,0x05,0xaa,0xaa,0xa9,
0x99,0x98,0x88,0x88,0x77,0x77,0x66,0x66,0x65,0x55,0x55,0x30,0x00,0x00,0x00,0x00,
0x00,0x00,0x35,0x54,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x29,0x98,0x10,0x00,0x00,0x68,0x88,0x88,0x88,0x50,0x00,0x00,0x00,
0x00,0x00,0x00,0x15,0x55,0x55,0x56,0x50,0x00,0x00,0x00,0x00,0x5e,0xee,0xdd,0xdc,
0xcc,0xcb,0xbb,0xaa,0xaa,0x99,0x98,0x88,0x77,0x77,0x66,0x63,0x00,0x00,0x00,0x00,
0x00,0x03,0x77,0x77,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x02,0xbc,0xcc,0xb1,0x00,0x00,0x18,0x88,0x88,0x88,0x81,0x00,0x00,0x00,
0x00,0x00,0x00,0x35,0x55,0x55,0x56,0x30,0x00,0x00,0x00,0x06,0xee,0xed,0xdd,0xdc,
0xcc,0xbb,0xba,0xaa,0xa9,0x99,0x88,0x88,0x77,0x76,0x66,0x66,0x10,0x00,0x00,0x00,
0x00,0x07,0x77,0x77,0x75,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x3b,0xcc,0xcc,0xd8,0x00,0x00,0x04,0x88,0x88,0x88,0x85,0x00,0x00,0x00,
0x00,0x00,0x01,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x6e,0xee,0xdd,0xdd,0xcc,
0xcb,0xbb,0xba,0xaa,0x99,0x98,0x88,0x87,0x77,0x66,0x66,0x66,0x10,0x00,0x00,0x00,
0x00,0x07,0x77,0x77,0x78,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x03,0xbc,0xcc,0xcc,0xd8,0x00,0x00,0x00,0x88,0x88,0x88,0x87,0x10,0x00,0x00,
0x00,0x00,0x03,0x55,0x55,0x55,0x53,0x00,0x00,0x00,0x05,0xee,0xee,0xdd,0xdc,0xcc,
0xbb,0xbb,0xaa,0xa9,0x99,0x98,0x88,0x77,0x76,0x66,0x66,0x66,0x10,0x00,0x00,0x00,
0x00,0x07,0x77,0x77,0x78,0x85,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x2b,0xcc,0xcc,0xcd,0xd8,0x00,0x00,0x00,0x48,0x88,0x88,0x87,0x40,0x00,0x00,
0x00,0x00,0x04,0x55,0x55,0x55,0x50,0x00,0x00,0x00,0x6e,0xee,0xed,0xdd,0xcc,0xcc,
0xbb,0xba,0xaa,0x99,0x99,0x88,0x87,0x77,0x76,0x66,0x66,0x62,0x00,0x00,0x00,0x00,
0x00,0x02,0x77,0x77,0x88,0x88,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x03,0xbc,0xcc,0xcc,0xdd,0xa1,0x00,0x00,0x00,0x07,0x88,0x88,0x87,0x70,0x00,0x00,
0x00,0x00,0x25,0x55,0x55,0x55,0x20,0x00,0x00,0x06,0xfe,0xee,0xdd,0xdc,0xa7,0x77,
0x77,0x66,0x66,0x65,0x55,0x55,0x54,0x44,0x44,0x33,0x44,0x20,0x00,0x00,0x00,0x00,
0x00,0x00,0x27,0x78,0x88,0x88,0x86,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x3b,0xcc,0xcc,0xcd,0xda,0x00,0x00,0x00,0x00,0x04,0x88,0x88,0x87,0x73,0x00,0x00,
0x00,0x00,0x45,0x55,0x55,0x55,0x00,0x00,0x00,0x5e,0xee,0xed,0xdd,0xc9,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x03,0x78,0x88,0x88,0x88,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,
0xbc,0xcc,0xcc,0xdd,0xb1,0x00,0x00,0x00,0x00,0x00,0x88,0x88,0x87,0x76,0x00,0x00,
0x00,0x01,0x45,0x55,0x55,0x53,0x00,0x00,0x05,0xee,0xee,0xdd,0xdd,0x80,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x28,0x88,0x88,0x88,0x86,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3b,
0xcc,0xcc,0xcd,0xda,0x10,0x00,0x00,0x00,0x00,0x00,0x58,0x88,0x87,0x77,0x10,0x00,
0x00,0x02,0x45,0x55,0x55,0x51,0x00,0x00,0x5e,0xee,0xed,0xdd,0xd8,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x02,0x88,0x88,0x88,0x99,0x60,0x00,0x00,0x00,0x00,0x00,0x03,0xbc,
0xcc,0xcc,0xcd,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x88,0x87,0x77,0x40,0x00,
0x00,0x04,0x45,0x55,0x55,0x50,0x00,0x04,0xee,0xee,0xed,0xdd,0x90,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x38,0x88,0x88,0x99,0x96,0x00,0x00,0x00,0x00,0x00,0x2b,0xcc,
0xcc,0xcc,0xdb,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x88,0x87,0x77,0x70,0x00,
0x00,0x14,0x45,0x55,0x55,0x20,0x00,0x08,0xee,0xee,0xdd,0xd8,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x03,0x88,0x89,0x99,0x99,0x60,0x00,0x00,0x00,0x02,0xbc,0xcc,
0xcc,0xcd,0xa1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x88,0x87,0x77,0x71,0x00,
0x00,0x24,0x45,0x55,0x55,0x00,0x00,0x08,0xee,0xed,0xdd,0xc8,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x38,0x99,0x99,0x9a,0xa7,0x00,0x00,0x00,0x2b,0xcc,0xcc,
0xcc,0xda,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x88,0x87,0x77,0x73,0x00,
0x00,0x34,0x45,0x55,0x54,0x00,0x00,0x05,0xee,0xdd,0xdc,0xcc,0x80,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x03,0x99,0x99,0xaa,0xaa,0x70,0x00,0x02,0xbb,0xcc,0xcc,
0xcd,0xb1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x87,0x77,0x75,0x00,
0x00,0x44,0x45,0x55,0x52,0x00,0x00,0x00,0x5d,0xdd,0xdc,0xcc,0xb7,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x39,0x99,0xaa,0xaa,0xa7,0x00,0x2b,0xbc,0xcc,0xcc,
0xda,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x87,0x77,0x77,0x00,
0x01,0x44,0x45,0x55,0x51,0x00,0x00,0x00,0x05,0xdd,0xcc,0xcb,0xbb,0x70,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x9a,0xaa,0xaa,0xab,0x82,0xbb,0xcc,0xcc,0xcc,
0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x87,0x77,0x77,0x10,
0x02,0x44,0x45,0x55,0x50,0x00,0x00,0x00,0x00,0x5c,0xcc,0xbb,0xbb,0xa7,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3a,0xaa,0xaa,0xbb,0xbb,0xbc,0xcc,0xcc,0xcb,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x87,0x77,0x77,0x30,
0x03,0x44,0x45,0x55,0x40,0x00,0x00,0x00,0x00,0x05,0xcc,0xbb,0xba,0xaa,0x75,0x55,
0x55,0x44,0x44,0x43,0x33,0x33,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0xaa,0xab,0xbb,0xbb,0xcc,0xcc,0xcc,0xa1,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x87,0x77,0x77,0x50,
0x04,0x44,0x45,0x55,0x30,0x00,0x00,0x00,0x00,0x00,0x5b,0xbb,0xaa,0xaa,0x99,0x98,
0x88,0x77,0x77,0x66,0x66,0x66,0x66,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4a,0xbb,0xbb,0xbc,0xcc,0xcc,0xca,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x87,0x77,0x77,0x60,
0x04,0x44,0x45,0x55,0x20,0x00,0x00,0x00,0x00,0x00,0x04,0xba,0xaa,0xa9,0x99,0x88,
0x87,0x77,0x76,0x66,0x66,0x66,0x66,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0xbb,0xbb,0xcc,0xcc,0xcc,0xb1,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x87,0x77,0x77,0x70,
0x14,0x44,0x45,0x55,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x4a,0xaa,0x99,0x98,0x88,
0x77,0x77,0x66,0x66,0x66,0x66,0x66,0x66,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6b,0xbb,0xcc,0xcc,0xcc,0x10,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x87,0x77,0x77,0x71,
0x14,0x44,0x45,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0xa9,0x99,0x88,0x88,
0x77,0x76,0x66,0x66,0x66,0x66,0x66,0x67,0x75,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xab,0xbc,0xcc,0xcc,0xcd,0x90,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x87,0x77,0x77,0x72,
0x24,0x44,0x45,0x54,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x39,0x98,0x88,0x87,
0x77,0x66,0x66,0x66,0x66,0x66,0x66,0x77,0x77,0x60,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3a,0xbb,0xcc,0xcc,0xcc,0xdd,0xd9,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x77,0x77,0x77,0x73,
0x24,0x44,0x45,0x54,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x76,0x66,0x65,
0x55,0x55,0x44,0x55,0x55,0x56,0x67,0x77,0x77,0x76,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xbb,0xbc,0xcc,0xcc,0xcd,0xdd,0xdd,0xa0,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x67,0x77,0x77,0x74,
0x34,0x44,0x45,0x53,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x02,0x67,0x77,0x77,0x77,0x60,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2a,0xbb,0xcc,0xcc,0xcc,0xdd,0xdd,0xde,0xea,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x57,0x77,0x77,0x74,
0x34,0x44,0x45,0x53,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x16,0x77,0x77,0x77,0x76,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xab,0xbc,0xcc,0xcc,0xa5,0xcd,0xdd,0xee,0xee,
0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x77,0x77,0x75,
0x34,0x44,0x45,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x77,0x77,0x77,0x77,0x60,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x3b,0xbb,0xbc,0xcc,0xca,0x00,0x4d,0xdd,0xee,0xee,
0xe9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x77,0x77,0x75,
0x44,0x44,0x45,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0x77,0x77,0x78,0x86,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x02,0xab,0xbb,0xcc,0xcc,0xb1,0x00,0x05,0xde,0xee,0xee,
0xdd,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x77,0x77,0x76,
0x44,0x44,0x45,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x77,0x77,0x88,0x88,0x10,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x3a,0xbb,0xbc,0xcc,0xca,0x10,0x00,0x00,0x4d,0xee,0xed,
0xdd,0xd9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x77,0x77,0x76,
0x44,0x44,0x45,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0x77,0x88,0x88,0x10,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x03,0xbb,0xbb,0xcc,0xcc,0xa0,0x00,0x00,0x00,0x05,0xee,0xdd,
0xdd,0xdd,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x77,0x77,0x76,
0x44,0x44,0x45,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x78,0x88,0x88,0x10,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x2a,0xbb,0xbc,0xcc,0xca,0x10,0x00,0x00,0x00,0x00,0x5d,0xdd,
0xdd,0xdd,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x77,0x77,0x76,
0x44,0x44,0x45,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x88,0x88,0x88,0x10,0x00,0x00,0x00,
0x00,0x00,0x00,0x02,0xab,0xbb,0xcc,0xcc,0xa1,0x00,0x00,0x00,0x00,0x00,0x05,0xdd,
0xdd,0xdd,0xcc,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x77,0x77,0x76,
0x44,0x44,0x45,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x88,0x88,0x88,0x10,0x00,0x00,0x00,
0x00,0x00,0x00,0x2a,0xbb,0xbb,0xcc,0xca,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5d,
0xdd,0xdc,0xcc,0xc8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0x77,0x77,0x76,
0x34,0x44,0x45,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x88,0x88,0x88,0x10,0x00,0x00,0x00,
0x00,0x00,0x02,0xab,0xbb,0xbc,0xcc,0xa1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,
0xdd,0xcc,0xcc,0xcc,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x77,0x77,0x76,
0x34,0x44,0x45,0x53,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x88,0x88,0x88,0x10,0x00,0x00,0x00,
0x00,0x00,0x2a,0xbb,0xbb,0xcc,0xca,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x5c,0xcc,0xcc,0xcc,0xc8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x77,0x77,0x75,
0x34,0x44,0x45,0x53,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x88,0x88,0x88,0x10,0x00,0x00,0x00,
0x00,0x02,0xab,0xbb,0xbc,0xcc,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x05,0xcc,0xcc,0xcc,0xbb,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x57,0x77,0x77,0x75,
0x24,0x44,0x45,0x54,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x88,0x88,0x88,0x10,0x00,0x00,0x00,
0x00,0x0a,0xbb,0xbb,0xcc,0xca,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x5c,0xcc,0xcb,0xbb,0xb6,0x00,0x00,0x00,0x00,0x00,0x00,0x67,0x77,0x77,0x74,
0x24,0x44,0x45,0x54,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x88,0x88,0x89,0x10,0x00,0x00,0x00,
0x00,0x0b,0xbb,0xbc,0xcc,0xa1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x05,0xcc,0xbb,0xbb,0xb7,0x00,0x00,0x00,0x00,0x00,0x00,0x77,0x77,0x77,0x73,
0x14,0x44,0x45,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x88,0x88,0x99,0x10,0x00,0x00,0x00,
0x00,0x1b,0xbb,0xbc,0xca,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x4b,0xbb,0xbb,0xb7,0x00,0x00,0x00,0x00,0x00,0x00,0x87,0x77,0x77,0x72,
0x14,0x44,0x45,0x55,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x88,0x89,0x99,0x10,0x00,0x00,0x00,
0x00,0x1b,0xbb,0xcc,0xc4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x09,0xbb,0xbb,0xb7,0x00,0x00,0x00,0x00,0x00,0x01,0x87,0x77,0x77,0x71,
0x04,0x44,0x45,0x55,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x88,0x99,0x99,0x10,0x00,0x00,0x00,
0x00,0x1b,0xbc,0xcc,0xc4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x09,0xbb,0xbb,0xa7,0x00,0x00,0x00,0x00,0x00,0x02,0x87,0x77,0x77,0x70,
0x04,0x44,0x45,0x55,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x88,0x99,0x99,0x10,0x00,0x00,0x00,
0x00,0x1b,0xcc,0xcc,0xc4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x09,0xbb,0xbb,0xa7,0x00,0x00,0x00,0x00,0x00,0x04,0x87,0x77,0x77,0x70,
0x03,0x44,0x45,0x55,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x89,0x99,0x99,0x10,0x00,0x00,0x00,
0x00,0x1c,0xcc,0xcc,0xc4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x09,0xbb,0xba,0xa7,0x00,0x00,0x00,0x00,0x00,0x06,0x87,0x77,0x77,0x50,
0x02,0x44,0x45,0x55,0x50,0x00,0x00,0x00,0x05,0x65,0x20,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x99,0x99,0x9a,0x10,0x00,0x00,0x00,
0x00,0x1c,0xcc,0xcc,0xd4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x08,0xbb,0xaa,0xa7,0x00,0x00,0x00,0x00,0x00,0x07,0x87,0x77,0x77,0x30,
0x01,0x44,0x45,0x55,0x51,0x00,0x00,0x00,0x66,0x66,0x62,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x99,0x99,0xaa,0x10,0x00,0x00,0x00,
0x00,0x1c,0xcc,0xcd,0xd4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x08,0xba,0xaa,0xa7,0x00,0x00,0x00,0x00,0x00,0x18,0x87,0x77,0x77,0x20,
0x00,0x44,0x45,0x55,0x52,0x00,0x00,0x03,0x66,0x66,0x66,0x20,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x99,0x99,0xaa,0x10,0x00,0x00,0x00,
0x00,0x1c,0xcc,0xdd,0xd4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x08,0xaa,0xaa,0xa6,0x00,0x00,0x00,0x00,0x00,0x48,0x87,0x77,0x77,0x00,
0x00,0x34,0x45,0x55,0x54,0x00,0x00,0x03,0x66,0x66,0x66,0x62,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x69,0x99,0x9a,0xaa,0x20,0x00,0x00,0x00,
0x00,0x1c,0xcc,0xdd,0xd4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x08,0xaa,0xaa,0xa6,0x00,0x00,0x00,0x00,0x00,0x68,0x87,0x77,0x76,0x00,
0x00,0x24,0x45,0x55,0x55,0x00,0x00,0x03,0x66,0x66,0x66,0x66,0x20,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x99,0x99,0xaa,0xaa,0x10,0x00,0x00,0x00,
0x00,0x1c,0xcd,0xdd,0xd4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x08,0xaa,0xaa,0xa6,0x00,0x00,0x00,0x00,0x01,0x88,0x87,0x77,0x74,0x00,
0x00,0x14,0x45,0x55,0x55,0x20,0x00,0x00,0x46,0x66,0x66,0x66,0x72,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x69,0x99,0x9a,0xaa,0xa3,0x00,0x00,0x00,0x00,
0x00,0x1c,0xdd,0xdd,0xd4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x08,0xaa,0xaa,0xa6,0x00,0x00,0x00,0x00,0x04,0x88,0x87,0x77,0x72,0x00,
0x00,0x04,0x45,0x55,0x55,0x40,0x00,0x00,0x04,0x66,0x66,0x67,0x77,0x20,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x99,0x99,0xaa,0xaa,0x30,0x00,0x00,0x00,0x00,
0x00,0x1d,0xdd,0xdd,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x08,0xaa,0xaa,0xa6,0x00,0x00,0x00,0x00,0x07,0x88,0x87,0x77,0x70,0x00,
0x00,0x03,0x45,0x55,0x55,0x51,0x00,0x00,0x00,0x46,0x66,0x77,0x77,0x73,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x69,0x99,0x9a,0xaa,0xa4,0x00,0x00,0x00,0x00,0x00,
0x00,0x1d,0xdd,0xdd,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x08,0xaa,0xaa,0xa6,0x00,0x00,0x00,0x00,0x18,0x88,0x87,0x77,0x50,0x00,
0x00,0x01,0x45,0x55,0x55,0x53,0x00,0x00,0x00,0x04,0x66,0x77,0x77,0x77,0x32,0x22,
0x22,0x22,0x22,0x22,0x22,0x26,0x99,0x99,0x9a,0xaa,0x30,0x00,0x00,0x00,0x00,0x00,
0x00,0x1d,0xdd,0xde,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x08,0xaa,0xaa,0xa6,0x00,0x00,0x00,0x00,0x48,0x88,0x87,0x77,0x20,0x00,
0x00,0x00,0x45,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x47,0x77,0x77,0x77,0x77,0x77,
0x88,0x88,0x88,0x88,0x88,0x99,0x99,0x99,0xaa,0xa3,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x1d,0xdd,0xee,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x08,0xaa,0xaa,0xa6,0x00,0x00,0x00,0x00,0x78,0x88,0x87,0x76,0x00,0x00,
0x00,0x00,0x25,0x55,0x55,0x55,0x20,0x00,0x00,0x00,0x05,0x77,0x77,0x77,0x77,0x78,
0x88,0x88,0x88,0x88,0x88,0x99,0x99,0x9a,0xaa,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x1d,0xde,0xee,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x08,0xaa,0xaa,0xa6,0x00,0x00,0x00,0x03,0x88,0x88,0x87,0x73,0x00,0x00,
0x00,0x00,0x04,0x55,0x55,0x55,0x50,0x00,0x00,0x00,0x00,0x47,0x77,0x77,0x77,0x78,
0x88,0x88,0x88,0x88,0x89,0x99,0x99,0xaa,0xa3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x1d,0xee,0xee,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x08,0xaa,0xaa,0xa6,0x00,0x00,0x00,0x07,0x88,0x88,0x87,0x70,0x00,0x00,
0x00,0x00,0x03,0x55,0x55,0x55,0x52,0x00,0x00,0x00,0x00,0x05,0x77,0x77,0x77,0x88,
0x88,0x88,0x88,0x88,0x99,0x99,0x9a,0xaa,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x1e,0xee,0xee,0xd4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x08,0xaa,0xaa,0xa6,0x00,0x00,0x00,0x38,0x88,0x88,0x87,0x50,0x00,0x00,
0x00,0x00,0x01,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x00,0x57,0x77,0x78,0x88,
0x88,0x88,0x88,0x89,0x99,0x99,0xaa,0xa4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x0b,0xee,0xee,0xc2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x05,0xaa,0xaa,0xa4,0x00,0x00,0x00,0x78,0x88,0x88,0x87,0x20,0x00,0x00,
0x00,0x00,0x00,0x45,0x55,0x55,0x56,0x20,0x00,0x00,0x00,0x00,0x05,0x77,0x88,0x88,
0x88,0x88,0x88,0x99,0x99,0x99,0xaa,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0xae,0xec,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x5a,0xaa,0x30,0x00,0x00,0x04,0x88,0x88,0x88,0x86,0x00,0x00,0x00,
0x00,0x00,0x00,0x15,0x55,0x55,0x56,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x01,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x88,0x88,0x88,0x82,0x00,0x00,0x00,
0x00,0x00,0x00,0x04,0x55,0x55,0x56,0x64,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x88,0x88,0x88,0x60,0x00,0x00,0x00,
0x00,0x00,0x00,0x01,0x55,0x55,0x56,0x66,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x88,0x88,0x88,0x88,0x10,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x35,0x55,0x56,0x66,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x88,0x88,0x88,0x85,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x05,0x55,0x56,0x66,0x64,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x88,0x88,0x88,0x71,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x02,0x55,0x56,0x66,0x66,0x20,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x88,0x88,0x88,0x88,0x40,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x45,0x56,0x66,0x66,0x60,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x88,0x88,0x88,0x87,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x15,0x56,0x66,0x66,0x65,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x88,0x88,0x88,0x81,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x03,0x56,0x66,0x66,0x66,0x40,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x05,0x98,0x88,0x88,0x88,0x40,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x66,0x66,0x66,0x63,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x49,0x98,0x88,0x88,0x87,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x66,0x66,0x66,0x67,0x30,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x03,0x99,0x98,0x88,0x88,0x71,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x66,0x66,0x66,0x67,0x72,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x39,0x99,0x98,0x88,0x88,0x20,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x36,0x66,0x66,0x67,0x77,0x20,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x03,0x99,0x99,0x98,0x88,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x66,0x66,0x67,0x77,0x73,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x49,0x99,0x99,0x98,0x88,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x66,0x67,0x77,0x77,0x40,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x04,0x99,0x99,0x99,0x98,0x86,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x66,0x67,0x77,0x77,0x75,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x69,0x99,0x99,0x99,0x98,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x56,0x67,0x77,0x77,0x77,0x60,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x17,0x99,0x99,0x99,0x99,0x97,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x67,0x77,0x77,0x77,0x77,0x20,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x03,0x99,0x99,0x99,0x99,0x99,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x57,0x77,0x77,0x77,0x78,0x85,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x59,0x99,0x99,0x99,0x99,0x97,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x77,0x77,0x77,0x78,0x88,
0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,
0x99,0x99,0x99,0x99,0x99,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x57,0x77,0x77,0x78,0x88,
0x88,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0xaa,
0x99,0x99,0x99,0x99,0x96,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x77,0x77,0x78,0x88,
0x88,0x88,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x9a,0xaa,
0x99,0x99,0x99,0x99,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0x77,0x78,0x88,
0x88,0x88,0x98,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x9a,0xaa,0xaa,
0x99,0x99,0x99,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x67,0x78,0x88,
0x88,0x88,0x99,0x98,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x9a,0xaa,0xaa,0xaa,
0x99,0x99,0x98,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x78,0x88,
0x88,0x88,0x99,0x99,0x98,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x9a,0xaa,0xaa,0xaa,0xaa,
0x99,0x99,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0x88,
0x88,0x88,0x99,0x99,0x99,0x99,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0x99,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,
0x88,0x88,0x99,0x99,0x99,0x99,0xaa,0xa7,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x8b,0xba,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0x95,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x58,0x88,0x99,0x99,0x99,0x99,0xaa,0xaa,0xaa,0x97,0x53,0x10,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x01,0x35,0x8a,0xbb,0xbb,0xba,0xaa,0xaa,0xaa,0xaa,0xaa,0xa7,
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x01,0x68,0x99,0x99,0x99,0x99,0xaa,0xaa,0xaa,0xaa,0xbb,0xbb,0x98,0x76,0x54,0x44,
0x44,0x45,0x67,0x8a,0xbb,0xbb,0xbb,0xbb,0xbb,0xba,0xaa,0xaa,0xaa,0xaa,0xa8,0x20,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x02,0x79,0x99,0x99,0x99,0xaa,0xaa,0xaa,0xaa,0xbb,0xbb,0xbb,0xbb,0xcc,0xcc,
0xcc,0xcc,0xcc,0xcb,0xbb,0xbb,0xbb,0xbb,0xbb,0xba,0xaa,0xaa,0xaa,0xa8,0x30,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x02,0x69,0x99,0x99,0xaa,0xaa,0xaa,0xaa,0xbb,0xbb,0xbb,0xbb,0xcc,0xcc,
0xcc,0xcc,0xcc,0xcb,0xbb,0xbb,0xbb,0xbb,0xbb,0xba,0xaa,0xaa,0xa7,0x30,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x01,0x58,0x99,0xaa,0xaa,0xaa,0xaa,0xbb,0xbb,0xbb,0xbb,0xcc,0xcc,
0xcc,0xcc,0xcc,0xcb,0xbb,0xbb,0xbb,0xbb,0xbb,0xba,0xaa,0x95,0x10,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x36,0x9a,0xaa,0xaa,0xaa,0xbb,0xbb,0xbb,0xbb,0xcc,0xcc,
0xcc,0xcc,0xcc,0xcb,0xbb,0xbb,0xbb,0xbb,0xbb,0xba,0x73,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x68,0xaa,0xaa,0xbb,0xbb,0xbb,0xbb,0xcc,0xcc,
0xcc,0xcc,0xcc,0xcb,0xbb,0xbb,0xbb,0xbb,0x96,0x30,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x68,0xab,0xbb,0xbb,0xbb,0xcc,0xcc,
0xcc,0xcc,0xcc,0xcb,0xbb,0xbb,0x96,0x31,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x34,0x67,0x89,0xab,0xbb,
0xbb,0xba,0x98,0x76,0x53,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};

49
include/memlayout.h Normal file
View file

@ -0,0 +1,49 @@
#pragma once
// Memory layout
#define EXTMEM 0x100000 // Start of extended memory
// Top of usable physical memory. A *variable*, read from the firmware's E820
// map at boot -- see kernel/arch/x86_64/e820.c. It used to be the constant
// below, which was not a limit on what the kernel used but an assertion that
// exactly 224 MB existed: less and the allocator walked off the end of RAM,
// more and it was invisible.
//
// The macro spelling is kept so that the twenty-odd call sites read the same as
// they always did. It must not be used before e820_init(), which runs first
// thing in main() for that reason.
#ifndef __ASSEMBLER__
extern uint64 phystop;
#define PHYSTOP phystop
#endif
// What to assume when the firmware gives us nothing usable: the old constant,
// so that path behaves exactly as the kernel always did.
#define PHYSTOP_FALLBACK 0xE000000ULL
// kvmalloc() maps physical 0-4 GB as four 1 GB pages and marks the top one
// uncached, because that is where PCI BARs and the framebuffer sit. 3 GB is
// therefore the most that can be treated as RAM.
#define PHYSTOP_MAX 0xC0000000ULL
// Below this the kernel image, its page tables and the DMA arena do not fit.
#define PHYSTOP_MIN (24ULL * 1024 * 1024)
// Key addresses for address space layout
#define KERNBASE 0xFFFF800000000000 // First kernel virtual address
#define KERNLINK (KERNBASE+EXTMEM) // Address where kernel is linked
#ifndef __ASSEMBLER__
static inline addr_t v2p(void *a) {
return ((addr_t)(a)) - ((addr_t)KERNBASE);
}
static inline void *p2v(addr_t a) {
return (void *)((a) + ((addr_t)KERNBASE));
}
#endif
#define V2P(a) (((addr_t) (a)) - KERNBASE)
#define P2V(a) (((void *) (a)) + KERNBASE)
#define V2P_WO(x) ((x) - KERNBASE) // same as V2P, but without casts
#define P2V_WO(x) ((x) + KERNBASE) // same as P2V, but without casts

130
include/mmu.h Normal file
View file

@ -0,0 +1,130 @@
#pragma once
// Eflags register
#define FL_CF 0x00000001 // Carry Flag
#define FL_PF 0x00000004 // Parity Flag
#define FL_AF 0x00000010 // Auxiliary carry Flag
#define FL_ZF 0x00000040 // Zero Flag
#define FL_SF 0x00000080 // Sign Flag
#define FL_TF 0x00000100 // Trap Flag
#define FL_IF 0x00000200 // Interrupt Enable
#define FL_DF 0x00000400 // Direction Flag
#define FL_OF 0x00000800 // Overflow Flag
#define FL_IOPL_MASK 0x00003000 // I/O Privilege Level bitmask
#define FL_NT 0x00004000 // Nested Task
#define FL_RF 0x00010000 // Resume Flag
#define FL_VM 0x00020000 // Virtual 8086 mode
#define FL_AC 0x00040000 // Alignment Check
#define FL_VIF 0x00080000 // Virtual Interrupt Flag
#define FL_VIP 0x00100000 // Virtual Interrupt Pending
#define FL_ID 0x00200000 // ID flag
// Control Register flags
#define CR0_PE 0x00000001 // Protection Enable
#define CR0_MP 0x00000002 // Monitor coProcessor
#define CR0_EM 0x00000004 // Emulation
#define CR0_TS 0x00000008 // Task Switched
#define CR0_ET 0x00000010 // Extension Type
#define CR0_NE 0x00000020 // Numeric Errror
#define CR0_WP 0x00010000 // Write Protect
#define CR0_AM 0x00040000 // Alignment Mask
#define CR0_NW 0x20000000 // Not Writethrough
#define CR0_CD 0x40000000 // Cache Disable
#define CR0_PG 0x80000000 // Paging
#define CR4_PSE 0x00000010 // Page size extension
#define CR4_PAE 0x00000020 // Physical address extensions
#define CR4_OSXFSR 0x00000200 // OS supports FXSAVE and FXRSTOR
#define CR4_OSXMMEXCPT 0x00000400 // OS supports SSE exceptions
// Model specific registers
#define MSR_EFER 0xC0000080 // Extended Feature Enable Register
#define MSR_STAR 0xC0000081 // Legacy Mode SYSCALL Target
#define MSR_LSTAR 0xC0000082 // Long Mode SYSCALL Target
#define MSR_CSTAR 0xC0000083 // Compatibility Mode SYSCALL Target
#define MSR_SFMASK 0xC0000084 // SYSCALL Flag Mask
// Segment selectors
#define SEG_KCODE 1
#define SEG_KDATA 2
#define SEG_UCODE32 3
#define SEG_UDATA 4
#define SEG_UCODE 5
#define SEG_KCPU 6
#define SEG_TSS 7 // TSS takes 2 slots in 64-bit GDT
#define NSEGS 9
#define DPL_USER 0x3
#define USER_CS ((SEG_UCODE<<3)|DPL_USER)
#define USER_DS ((SEG_UDATA<<3)|DPL_USER)
#define KERNEL_CS (SEG_KCODE<<3)
#ifndef __ASSEMBLER__
// Segment Descriptor
struct segdesc {
uint32 lim_15_0 : 16; // Low bits of segment limit
uint32 base_15_0 : 16; // Low bits of segment base address
uint32 base_23_16 : 8; // Middle bits of segment base address
uint32 type : 4; // Segment type
uint32 s : 1; // 0 = system, 1 = application
uint32 dpl : 2; // Descriptor Privilege Level
uint32 p : 1; // Present
uint32 lim_19_16 : 4; // High bits of segment limit
uint32 avl : 1; // Available for software use
uint32 l : 1; // 1 = 64-bit segment (Long mode)
uint32 db : 1; // 0 = 16-bit, 1 = 32-bit
uint32 g : 1; // Granularity
uint32 base_31_24 : 8; // High bits of segment base address
};
// 64-bit System Segment Descriptor (e.g., TSS)
struct desclong {
struct segdesc sd;
uint32 base_63_32; // High bits of 64-bit base address
uint32 res; // Reserved
};
#define SEG(type, base, lim, dpl) (struct segdesc) \
{ ((lim) >> 12) & 0xffff, (uint32)(base) & 0xffff, \
((uint32)(base) >> 16) & 0xff, type, 1, dpl, 1, \
(uint32)(lim) >> 28, 0, 1, 0, 1, (uint32)(base) >> 24 }
#endif
// Application segment type bits
#define STA_X 0x8 // Executable segment
#define STA_W 0x2 // Writeable (non-executable)
#define STA_R 0x2 // Readable (executable)
// System segment type bits
#define STS_T64A 0x9 // Available 64-bit TSS
#define STS_T64B 0xB // Busy 64-bit TSS
#define STS_IG64 0xE // 64-bit Interrupt Gate
#define STS_TG64 0xF // 64-bit Trap Gate
// Page table structure: 4 levels
#define PMX(va) (((addr_t)(va) >> 39) & 0x1FF)
#define PDPX(va) (((addr_t)(va) >> 30) & 0x1FF)
#define PDX(va) (((addr_t)(va) >> 21) & 0x1FF)
#define PTX(va) (((addr_t)(va) >> 12) & 0x1FF)
#define PGSIZE 4096
#define PXMASK 0x1FF
#define PGROUNDUP(sz) (((sz)+((addr_t)PGSIZE-1)) & ~((addr_t)(PGSIZE-1)))
#define PGROUNDDOWN(a) (((a)) & ~((addr_t)(PGSIZE-1)))
// Page table/directory entry flags
#define PTE_P 0x001 // Present
#define PTE_W 0x002 // Writeable
#define PTE_U 0x004 // User
#define PTE_PWT 0x008 // Write-Through
#define PTE_PCD 0x010 // Cache-Disable
#define PTE_A 0x020 // Accessed
#define PTE_D 0x040 // Dirty
#define PTE_PS 0x080 // Page Size (Huge Page)
#define PTE_ADDR(pte) ((addr_t)(pte) & 0x000FFFFFFFFFF000ull)
#define PTE_FLAGS(pte) ((addr_t)(pte) & 0xFFF)

54
include/mp.h Normal file
View file

@ -0,0 +1,54 @@
// See MultiProcessor Specification Version 1.[14]
struct mp { // floating pointer
uchar signature[4]; // "_MP_"
uint32 physaddr; // 32-bit phys addr of MP config table
uchar length; // 1
uchar specrev; // [14]
uchar checksum; // all bytes must add up to 0
uchar type; // MP system config type
uchar imcrp;
uchar reserved[3];
};
struct mpconf { // configuration table header
uchar signature[4]; // "PCMP"
ushort length; // total table length
uchar version; // [14]
uchar checksum; // all bytes must add up to 0
uchar product[20]; // product id
uint32 oemtable_p; // OEM table pointer
ushort oemlength; // OEM table length
ushort entry; // entry count
uint32 lapicaddr_p; // address of local APIC
ushort xlength; // extended table length
uchar xchecksum; // extended table checksum
uchar reserved;
};
struct mpproc { // processor table entry
uchar type; // entry type (0)
uchar apicid; // local APIC id
uchar version; // local APIC verison
uchar flags; // CPU flags
#define MPBOOT 0x02 // This proc is the bootstrap processor.
uchar signature[4]; // CPU signature
uint feature; // feature flags from CPUID instruction
uchar reserved[8];
};
struct mpioapic { // I/O APIC table entry
uchar type; // entry type (2)
uchar apicno; // I/O APIC id
uchar version; // I/O APIC version
uchar flags; // I/O APIC flags
uint32 addr_p; // I/O APIC address
};
// Table entry types
#define MPPROC 0x00 // One per processor
#define MPBUS 0x01 // One per bus
#define MPIOAPIC 0x02 // One per I/O APIC
#define MPIOINTR 0x03 // One per bus interrupt source
#define MPLINTR 0x04 // One per system interrupt source

28
include/param.h Normal file
View file

@ -0,0 +1,28 @@
#pragma once
#define NPROC 128 // maximum number of processes
#define KSTACKSIZE 4096 // size of per-process kernel stack (increased for x64)
#define KSTACK_CANARY 0xDEADC0DEDEADC0DEULL // sentinel at kstack[0], see kstack_check_canary()
#define NCPU 16 // maximum number of CPUs
#define NOFILE 128 // open files per process
#define NFILE 512 // open files per system
#define NINODE 200 // maximum number of active i-nodes
#define NDEV 10 // maximum major device number
#define RAMDISK_DEV 2 // memory-backed block device (kernel/dev/ramdisk.c)
#define USBDISK_DEV 3 // USB mass storage (kernel/drivers/usb_storage.c)
// Device the root filesystem is mounted from. Building with RAMROOT=1 defines
// RAMDISK_ROOT and boots from the SCHFS image linked into the kernel instead
// of the IDE disk, leaving the physical disk free to be reformatted from a
// running system. See kernel/dev/ramdisk.c.
#ifdef RAMDISK_ROOT
#define ROOTDEV RAMDISK_DEV
#else
#define ROOTDEV 1 // device number of file system root disk
#endif
#define MAXARG 32 // max exec arguments
#define MAXPATH 128 // max path
#define MAXOPBLOCKS 30 // max # of blocks any FS op writes
#define LOGSIZE (MAXOPBLOCKS*3) // max data blocks in on-disk log
#define NBUF (MAXOPBLOCKS*3) // size of disk block cache
#define FSSIZE 150000 // size of file system in blocks

110
include/pci.h Normal file
View file

@ -0,0 +1,110 @@
#pragma once
// PCI bus enumeration and driver binding.
//
// Until this existed, every driver in Schunix found its hardware by knowing
// where it was: IDE at 0x1F0 because IDE has always been at 0x1F0, the
// framebuffer wherever the BIOS's VBE call said. That works for exactly the
// devices that predate PCI and for nothing else. A NIC, an AHCI controller,
// a virtio device or a real GPU has no fixed address at all -- you find it by
// asking the bus what is plugged into it, which is what this does.
// ---------------------------------------------------------------------------
// Config space
// ---------------------------------------------------------------------------
#define PCI_CONFIG_ADDR 0xCF8
#define PCI_CONFIG_DATA 0xCFC
#define PCI_VENDOR_ID 0x00
#define PCI_DEVICE_ID 0x02
#define PCI_COMMAND 0x04
#define PCI_STATUS 0x06
#define PCI_REVISION 0x08
#define PCI_PROG_IF 0x09
#define PCI_SUBCLASS 0x0A
#define PCI_CLASS 0x0B
#define PCI_HEADER_TYPE 0x0E
#define PCI_BAR0 0x10
#define PCI_SECONDARY_BUS 0x19
#define PCI_INTERRUPT_LINE 0x3C
#define PCI_INTERRUPT_PIN 0x3D
// PCI_COMMAND bits a driver usually wants set before touching its device.
#define PCI_CMD_IO 0x0001
#define PCI_CMD_MEMORY 0x0002
#define PCI_CMD_BUS_MASTER 0x0004
// Base classes worth naming. The full list is long and mostly irrelevant here.
#define PCI_CLASS_STORAGE 0x01
#define PCI_CLASS_NETWORK 0x02
#define PCI_CLASS_DISPLAY 0x03
#define PCI_CLASS_MULTIMEDIA 0x04
#define PCI_CLASS_BRIDGE 0x06
#define PCI_CLASS_SERIAL_BUS 0x0C
#define PCI_STATUS_CAPLIST 0x0010 // device has a capability list
#define PCI_CAP_PTR 0x34 // offset of the first capability
#define PCI_CAP_MSI 0x05
#define PCI_CAP_MSIX 0x11
#define PCI_CAP_VENDOR 0x09 // virtio's configuration lives here
#define PCI_CAP_PCIE 0x10
#define PCI_ANY 0xFFFF // wildcard in a match table
#define NPCI 64 // devices we will remember
struct pci_bar {
uint64 base; // already masked; 0 means "no BAR here"
uint64 size; // determined by write-ones-and-read-back
int is_io; // I/O port range rather than memory
int is_64; // consumed the following BAR slot too
int prefetch;
};
struct pci_dev {
uint8 bus, slot, func;
uint16 vendor, device;
uint8 class, subclass, prog_if, revision;
uint8 irq; // interrupt line, 0xFF when unrouted
uint8 header_type;
struct pci_bar bar[6];
const char *driver; // name of whatever claimed it, or 0
};
// One row of a driver's match table. Terminate the table with a row whose
// vendor is 0.
struct pci_match {
uint16 vendor, device; // PCI_ANY to ignore
uint8 class, subclass; // used only when vendor is PCI_ANY
};
// Declared here rather than defs.h because both take a struct pci_dev, which
// only this header defines. See kernel/dev/device.c for the model they feed.
// device.h is included rather than forward-declaring `enum dev_class`, which
// is a compiler extension and warns.
#include "device.h"
enum dev_class pci_class_of(const struct pci_dev *);
void pci_describe(const struct pci_dev *, char *out, int cap);
struct pci_driver {
const char *name;
// Base for the device's name in /proc/devices, if the driver's own name
// makes a bad one. `e1000` plus an index reads as "e10000"; a NIC wants to
// be `eth0`. Optional -- null means use `name`.
const char *devname;
const struct pci_match *match;
// Class-specific vtable, published on the device when this driver claims
// it -- struct display_ops for a display, and so on. Optional; a driver
// with nothing to offer a consumer leaves it null.
//
// It lives on the driver rather than being set inside probe() because
// pci_bind() registers the device *after* probe returns, so a driver has
// nothing to attach it to at the point it would want to.
const void *ops;
// Return 0 to claim the device. A driver that returns non-zero leaves it
// unclaimed for anything else that matches.
int (*probe)(struct pci_dev *);
};

289
include/posix.h Normal file
View file

@ -0,0 +1,289 @@
// SPDX-License-Identifier: Apache-2.0
// Schunix — POSIX-compatibility types used by kernel syscall handlers.
#pragma once
#include "types.h"
#include "date.h"
struct iovec {
void *iov_base;
uint64 iov_len;
};
// 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 TIOCGPGRP 0x540F
#define TIOCSPGRP 0x5410
#define TIOCGWINSZ 0x5413
#define TIOCSWINSZ 0x5414
#define TIOCSCTTY 0x540E
#define TIOCGSERIAL 0x541E
#define FIONREAD 0x541B
#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];
};
struct statfs {
int64 f_type;
int64 f_bsize;
int64 f_blocks;
int64 f_bfree;
int64 f_bavail;
int64 f_files;
int64 f_ffree;
int64 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
#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)
#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;
};

240
include/proc.h Normal file
View file

@ -0,0 +1,240 @@
#pragma once
#include "types.h"
#include "traps.h"
#define NVMA 64
struct vma {
uint64 addr;
uint64 length;
int used;
// The pages under this mapping are not ours to free on unmap: either they
// are device memory (the framebuffer) or they belong to something with a
// longer life than this process (a shared memory segment). This was
// `is_fb`, which was the only such case until shared memory existed --
// and freeing another process's shared pages on exit is exactly the kind
// of bug that shows up somewhere else entirely, hours later.
int no_free;
int shmid; // shared segment this came from, or -1
};
// Per-CPU state
struct cpu {
uchar id;
uchar apicid; // Local APIC ID
struct context *scheduler; // swtch() here to enter scheduler
volatile uint64 started; // Has the CPU started?
int ncli; // Depth of pushcli nesting.
int intena; // Were interrupts enabled before pushcli?
void *local; // CPU-local storage (GS base)
};
extern struct cpu cpus[NCPU];
extern int ncpu; // processors present
extern int ncpu_online; // processors actually running
// --- per-CPU variables ------------------------------------------------------
//
// These were `__thread struct cpu *cpu` and `__thread struct proc *proc`, and
// that was wrong in a way that only appears once a second processor runs.
//
// `__thread` means *per thread*, and the compiler is entitled to assume a
// thread's pointer never changes: it reads %fs:0 once and keeps the value in a
// register or spilled on the stack across calls. clang did exactly that in
// sleep():
//
// movq %fs:0x0, %rax # read the thread pointer
// movq %rax, -0x18(%rbp) # spill it
// callq sched # <-- the CPU can change here
// movq -0x18(%rbp), %rax # reload the OLD pointer
// movq (%rax,%rcx), %rax # proc, from the previous CPU's block
// movq $0x0, 0x40(%rax) # NULL, because that CPU set proc = 0
//
// But %fs here is *per CPU*, not per thread, and a kernel thread changes CPU at
// every sched(). So the assumption is false for exactly the variables that
// most need to be right, and the failure is a null dereference deep in the
// scheduler on a machine with more than one core.
//
// The fix is to read the value at each use, with no cached base: an explicit
// %gs-relative access that the compiler cannot hoist across a call. `volatile`
// is what forbids that, and the memory clobber on the setters keeps stores in
// order with the rest of the scheduler's bookkeeping.
//
// Layout of the per-CPU block, whose base is in both FS_BASE and GS_BASE, set
// by seginit() in kernel/arch/x86_64/vm.c:
//
// +0 self-pointer required by the x86-64 TLS ABI (%fs:0)
// +8 syscall scratch trapasm.S parks %rsp here across the stack switch
// +16 struct cpu *
// +24 struct proc *
//
// Offset 8 is NOT free. syscall_entry uses %fs:(8) as its scratch slot, and
// because seginit() sets GS base and FS base to the same address, %fs:8 and
// %gs:8 are the same memory. Putting `cpu` there made every syscall overwrite
// it with %rsp -- a #GP in syscall_entry itself, several layers below anything
// that could report it.
//
// trapasm.S reads %gs:24 for proc on the way out to user mode, so these three
// offsets are shared with assembly and must not be reordered.
#define PERCPU_SELF 0
#define PERCPU_SCRATCH 8
#define PERCPU_CPU 16
#define PERCPU_PROC 24
static inline struct cpu *
cpu_get(void)
{
struct cpu *c;
asm volatile("movq %%gs:16, %0" : "=r" (c));
return c;
}
static inline void
cpu_set(struct cpu *c)
{
asm volatile("movq %0, %%gs:16" :: "r" (c) : "memory");
}
static inline struct proc *
proc_get(void)
{
struct proc *p;
asm volatile("movq %%gs:24, %0" : "=r" (p));
return p;
}
static inline void
proc_set(struct proc *p)
{
asm volatile("movq %0, %%gs:24" :: "r" (p) : "memory");
}
// Named mycpu()/myproc(), as xv6-riscv does, and *not* spelled `cpu`/`proc`.
// A macro by those names would also rewrite every `struct cpu` and
// `struct proc`, because macros have no namespace and tags do -- which is
// exactly why the variables could carry those names in the first place.
#define mycpu() cpu_get()
#define myproc() proc_get()
// Saved registers for kernel context switches (x86_64 ABI)
struct context {
uint64 r15;
uint64 r14;
uint64 r13;
uint64 r12;
uint64 rbx;
uint64 rbp;
uint64 rip;
};
enum procstate { UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE };
// Per-process state
// A copy of the interesting fields of one process, taken under ptable.lock.
// procfs reads these rather than struct proc, so nothing outside proc.c needs
// the lock or the layout.
struct procinfo {
int pid, ppid, pgid, sid;
uint uid;
int state; // enum procstate
uint64 sz;
int killed;
char name[16];
char exe[64]; // full path, for /proc/<pid>/exe
};
struct proc {
uint64 sz; // Size of process memory (bytes) [+0x00]
pml4e_t* pgdir; // Page table (PML4 on x86_64) [+0x08]
char *kstack; // Bottom of kernel stack [+0x10]
uint64 fs_base; // User TLS base (IA32_FS_BASE MSR) [+0x18] ← trapasm.S depends on this offset
enum procstate state; // Process state [+0x20]
int pid; // [+0x24]
struct proc *parent; // [+0x28]
struct trapframe *tf; // [+0x30]
struct context *context; // [+0x38]
void *chan; // [+0x40]
int killed; // [+0x48]
int _pad; // [+0x4c]
struct file *ofile[NOFILE]; // Open files [+0x50]
struct inode *cwd; // follows
char name[16]; //
// The path exec() was given. `name` is only the last component and only 15
// characters of it, which is what /proc/<pid>/stat wants; this is the whole
// path, reported by /proc/<pid>/exe.
//
// Note it is exposed as a regular *file*, not the symlink Linux uses, so
// `cat /proc/1/exe` works but readlink() does not. That is why `ps -o comm`
// still prints "[init]": toybox readlink()s exe and brackets the name when
// that fails. Default ps and top output is unaffected. Fixing it properly
// means symlink support in procfs, which is worth doing with the rest of the
// VFS work rather than on its own.
char exe[64];
uint64 signal_mask;
uint64 pending_signals;
int alarm_ticks;
char ofile_flags[NOFILE];
// Real signal delivery (added for SIGCHLD — see kernel/sys/syscall.c's
// deliver_signals() and kernel/proc/proc.c's exit()). sig_handler[sig]/
// sig_restorer[sig] come straight from the user's struct sigaction
// (sys_rt_sigaction); 0 means no handler installed. saved_sigtf stashes
// the pre-signal trapframe so sys_rt_sigreturn() can restore it; in_signal
// prevents re-entering a handler while one is already running (we don't
// support nested signal delivery).
uint64 sig_handler[32];
uint64 sig_restorer[32];
struct trapframe saved_sigtf;
int in_signal;
// rt_sigsuspend() support: the pre-suspend mask to restore once the
// handler that woke us finishes (sigsuspend swaps the mask atomically
// for the duration of the wait -- POSIX). sigsusp_active is set while a
// restore is owed; sys_rt_sigreturn() performs it.
uint64 sigsusp_oldmask;
int sigsusp_active;
struct vma vma[NVMA]; // VMA tracking for mmap
uint64 mmap_next; // next free mmap VA (bump allocator, see sys_mmap)
// ABI translation (Linux compat syscall number map)
int *syscall_map;
int map_size;
// Current working directory path; maintained by sys_chdir / sys_fchdir.
char cwd_path[256];
// --- POSIX process identity -------------------------------------------
// Appended at the end of the struct deliberately: trapasm.S hard-codes the
// offsets of the fields at the top (see the _Static_assert on fs_base in
// kernel/proc/proc.c), so nothing may be inserted above them.
// Exit status, already encoded the way wait(2) reports it -- see
// W_EXITCODE() below. Read by waitpid() before the slot is recycled.
int xstate;
// Signal that killed us, if any. Set by sigsend() alongside ->killed so the
// eventual exit() can report *which* signal, instead of a blanket SIGKILL.
int killsig;
// Process group and session. Job control is defined entirely in terms of
// these: a shell puts each pipeline in its own process group and signals the
// group, not individual pids. Without them a shell's wait loop cannot work,
// which is why mksh's job control never made progress.
int pgid;
int sid;
// Real/effective/saved user and group ids. Nothing enforces permissions with
// them yet (the on-disk format has no owner field until SchFS), but they
// are tracked honestly so getuid()/setuid() stop lying to userland.
uint uid, euid, suid;
uint gid, egid, sgid;
};
#define FD_CLOEXEC 1
// wait(2) status encoding, as understood by musl's WIFEXITED/WEXITSTATUS/
// WIFSIGNALED/WTERMSIG macros:
// normal exit -> (code & 0xff) << 8
// killed by signal -> sig & 0x7f
#define W_EXITCODE(code, sig) ((((code) & 0xff) << 8) | ((sig) & 0x7f))

42
include/qr.h Normal file
View file

@ -0,0 +1,42 @@
#pragma once
// A QR encoder, for getting a crash report off a machine whose network stack is
// dead.
//
// A panic report is worth nothing if it cannot leave the machine, and at panic
// time there is no network, no filesystem write that can be trusted, and often
// no second machine on the desk. A phone camera is a working out-of-band
// channel that needs no drivers on our side at all. See docs/roadmap.md Phase 8.
//
// Deliberately small, in three ways:
//
// - Byte mode only. The report is arbitrary bytes; alphanumeric mode would
// pack tighter but only for a restricted character set.
// - Error correction level L only. The screen is a clean, evenly lit,
// high-contrast source -- the failure mode QR's stronger levels protect
// against (dirt, print damage, curved packaging) does not apply.
// - Versions 1 to 6 only. Version 7 is where QR starts requiring an extra
// 18-bit version-information block in two more places on the symbol, and
// version 10 is where the character count field grows and the alignment
// pattern grid becomes 2-dimensional. Stopping at 6 avoids both, and
// 134 bytes is a large crash report.
//
// If a payload ever needs more than 134 bytes, the honest fix is to shorten the
// report -- not to reach for version 10 and its two extra tables.
#define QR_MAX_VERSION 6
#define QR_MAX_SIZE (17 + 4 * QR_MAX_VERSION) // 41 modules per side
#define QR_MAX_BYTES 134
struct qr {
int size; // modules per side; 0 if unencoded
unsigned char mod[QR_MAX_SIZE][QR_MAX_SIZE]; // 1 = dark
unsigned char fn[QR_MAX_SIZE][QR_MAX_SIZE]; // 1 = function pattern
};
// Encode len bytes into q. Picks the smallest version that fits.
// Returns 0, or -1 if len > QR_MAX_BYTES.
int qr_encode(struct qr *q, const unsigned char *data, int len);
// Largest payload, in bytes, for a given version (1..QR_MAX_VERSION).
int qr_capacity(int version);

246
include/schfs.h Normal file
View file

@ -0,0 +1,246 @@
// SchFS — on-disk format.
//
// Design rationale lives in docs/architecture/schfs.md. In short: copy-on-write
// with the checksum of a block stored in the pointer that leads to it (ZFS),
// one B-tree reused for every kind of record (btrfs), and attribute indexes as
// just another record type (BeFS).
//
// This header is shared by the kernel and by host tools (tools/mkfs,
// tools/schfs_test), so it must stay free of kernel-only types.
#ifndef SCHFS_H
#define SCHFS_H
#include <stdint.h>
#define SCHFS_MAGIC 0x53636846u // "SchF"
#define SCHFS_NODE_MAGIC 0x536e6f64u // "Snod"
// 4096 to match modern media and make extents worth having. The old format
// used 1024, which is also why its directories were so wasteful.
#define SCHFS_BLKSIZE 4096
// Deepest tree we will walk without recursing. 8 levels of a ~84-way internal
// node is far more than any plausible volume needs.
#define SCHFS_MAX_LEVEL 8
// ---------------------------------------------------------------------------
// Keys
//
// Every record in the filesystem is addressed by one 24-byte key, sorted by
// (objectid, type, offset). This is the whole reason there is only one tree:
// inodes, directory entries, extent maps and indexes are just different `type`
// values in the same keyspace.
// ---------------------------------------------------------------------------
#define SCHFS_KEY_INODE 1 // (ino, INODE, 0) -> struct schfs_inode
#define SCHFS_KEY_DIRENT 2 // (dirino,DIRENT, namehash) -> packed dirent list
#define SCHFS_KEY_EXTENT 3 // (ino, EXTENT, fileblk) -> struct schfs_extent
#define SCHFS_KEY_ATTR 4 // (ino, ATTR, namehash) -> attribute value
#define SCHFS_KEY_INDEX 5 // (idxid, INDEX, valuehash) -> objectid
#define SCHFS_KEY_CSUM 6 // (CSUM, CSUM, diskblk) -> uint32 CRC32c
// Data-block checksums live under one reserved object id, exactly as btrfs
// keeps a checksum tree. Tree nodes carry their checksum in their parent
// pointer, but file *data* blocks have no parent to hold it — without these
// records "end-to-end checksums" would only cover metadata, which is the part
// least likely to rot.
#define SCHFS_CSUM_OBJECTID 1ULL
// Object ids below this are reserved; the root directory is the first real one.
#define SCHFS_FIRST_OBJECTID 16ULL
#define SCHFS_ROOT_OBJECTID 16ULL
struct schfs_key {
uint64_t objectid;
uint64_t offset;
uint8_t type;
uint8_t pad[7];
}; /* 24 bytes */
// ---------------------------------------------------------------------------
// Node header — identical for internal nodes and leaves.
//
// `blocknr` is a self-pointer: a block that was written to the wrong place
// still checksums correctly, so the only way to catch a misdirected write is
// for the block to say where it thinks it lives.
// ---------------------------------------------------------------------------
struct schfs_node_hdr {
uint32_t magic; // SCHFS_NODE_MAGIC
uint32_t crc; // CRC32c of the whole block, this field zeroed
uint64_t blocknr; // where this block believes it lives
uint64_t generation; // transaction that wrote it
uint16_t level; // 0 = leaf, >0 = internal
uint16_t nritems;
uint32_t pad;
}; /* 32 bytes */
// Internal node entry: a key and the child it leads to, plus that child's
// checksum and generation. Storing the checksum *here* rather than in the
// child is what makes the tree self-validating.
struct schfs_kptr {
struct schfs_key key;
uint64_t blocknr;
uint64_t generation;
uint32_t crc;
uint32_t pad;
}; /* 48 bytes */
// Leaf entry. Items grow forward from the end of the header; their data grows
// backward from the end of the block, exactly like btrfs. `offset` is measured
// from the start of the block.
struct schfs_item {
struct schfs_key key;
uint32_t offset;
uint32_t size;
}; /* 32 bytes */
#define SCHFS_NODE_SPACE (SCHFS_BLKSIZE - (int)sizeof(struct schfs_node_hdr))
#define SCHFS_MAX_KPTR (SCHFS_NODE_SPACE / (int)sizeof(struct schfs_kptr))
#define SCHFS_MAX_ITEMS (SCHFS_NODE_SPACE / (int)sizeof(struct schfs_item))
// Largest value that can live inline in a leaf. Anything bigger becomes an
// extent record pointing at data blocks.
#define SCHFS_MAX_INLINE (SCHFS_NODE_SPACE / 4)
// ---------------------------------------------------------------------------
// Uberblock
//
// A ring of these is written round-robin. Mounting means reading them all and
// taking the highest generation that checksums — that is the entire crash
// recovery story, in place of a journal replay.
// ---------------------------------------------------------------------------
#define SCHFS_UBER_COUNT 128
#define SCHFS_UBER_START 1 // block 0 stays free for a boot sector
// First block available for the tree and for file data: everything below is
// the boot block and the uberblock ring.
#define SCHFS_FIRST_BLOCK (SCHFS_UBER_START + SCHFS_UBER_COUNT)
#define SCHFS_VERSION 1
#define SCHFS_LABEL_MAX 32
struct schfs_uberblock {
uint32_t magic; // SCHFS_MAGIC
uint32_t crc; // CRC32c of this struct, this field zeroed
uint32_t version; // SCHFS_VERSION
uint32_t blocksize; // SCHFS_BLKSIZE; a reader must refuse a mismatch
uint64_t generation; // transaction number; highest valid one wins
uint64_t root; // block number of the tree root
uint32_t root_crc; // checksum of that root block
uint32_t pad0;
uint64_t root_generation;
uint64_t total_blocks;
// Informational only. Which blocks are actually free is derived from the
// tree at mount rather than stored, so this is what the volume believed at
// commit time — useful for df before anything is mounted, never trusted.
uint64_t free_blocks;
uint64_t reserved0;
uint64_t next_objectid;
uint64_t root_objectid; // normally SCHFS_ROOT_OBJECTID
uint8_t uuid[16];
char label[SCHFS_LABEL_MAX];
uint8_t pad[SCHFS_BLKSIZE - 136];
};
// ---------------------------------------------------------------------------
// Records
// ---------------------------------------------------------------------------
#define SCHFS_T_FILE 1
#define SCHFS_T_DIR 2
#define SCHFS_T_DEV 3
#define SCHFS_T_SYMLINK 4
struct schfs_inode {
uint64_t size;
uint64_t blocks;
uint64_t atime, mtime, ctime;
// Containing directory. Meaningful for directories only, where it is what
// ".." resolves to — neither "." nor ".." is stored on disk, so a directory
// costs nothing until it has real entries. For files with several hard
// links "parent" is simply the first directory that linked them and must
// not be trusted.
uint64_t parent;
uint32_t mode; // real POSIX mode bits, at last
uint32_t uid, gid;
uint32_t nlink;
uint16_t type; // SCHFS_T_*
uint16_t rdev_major, rdev_minor;
uint16_t pad;
uint32_t flags; // SCHFS_I_* — none defined yet
uint32_t gen; // transaction that last changed this inode;
// what an incremental send/snapshot diff needs
};
// An extent maps a run of file blocks onto a run of disk blocks. refs is what
// makes snapshots and reflink copies nearly free: sharing a range is a refcount
// bump rather than a data copy.
struct schfs_extent {
uint64_t disk_block;
uint64_t nblocks;
// Transaction group that allocated this run. A run stamped with the group
// currently being built cannot be reached from any committed root, so its
// blocks may be overwritten in place — which is what stops a program that
// writes a hundred bytes at a time from copying a whole 4 KB block, and
// then a whole tree path, on every call.
//
// A full 64 bits, matching the tree's generation counter, because a 32-bit
// one would wrap after four billion commits and a wrapped comparison says
// "same group" about a block belonging to a committed tree — the one
// mistake this field exists to prevent. Only ever trusted together with
// refs == 1; a shared run belongs to somebody else as well.
uint64_t gen;
uint32_t refs;
uint32_t pad;
};
// Directory entry payload. The key's offset field holds the name hash, so a
// lookup is one tree descent rather than a directory scan.
//
// Two names in one directory can hash the same, and the key would then be
// identical — the second insert would silently replace the first. So the value
// is a *packed list*: one schfs_dirent_rec plus its name bytes, repeated. A
// 64-bit hash makes lists longer than one vanishingly rare, but "vanishingly
// rare" is not "impossible", and a filesystem that loses a file under a hash
// collision is not one to build on.
struct schfs_dirent_rec {
uint64_t objectid;
uint16_t type;
uint16_t namelen;
uint32_t pad;
/* name bytes follow, namelen of them, not NUL-terminated */
};
#define SCHFS_NAME_MAX 255
// Step from one packed dirent to the next. Records are 8-byte aligned so the
// uint64 objectid of the next one is naturally aligned.
#define SCHFS_DIRENT_LEN(namelen) \
((unsigned)((sizeof(struct schfs_dirent_rec) + (namelen) + 7) & ~7u))
// ---------------------------------------------------------------------------
// Compile-time layout checks.
//
// Every one of these is a number that ends up baked into images on disk. A
// silent change to any of them — adding a field, changing a type, a compiler
// padding a struct differently — makes every existing image unreadable in a way
// that looks like corruption rather than like a mistake. Failing the build is
// enormously cheaper than debugging that.
// ---------------------------------------------------------------------------
#define SCHFS_ASSERT_SIZE(t, n) \
typedef char schfs_sizecheck_##t[(sizeof(struct t) == (n)) ? 1 : -1]
SCHFS_ASSERT_SIZE(schfs_key, 24);
SCHFS_ASSERT_SIZE(schfs_node_hdr, 32);
SCHFS_ASSERT_SIZE(schfs_kptr, 48);
SCHFS_ASSERT_SIZE(schfs_item, 32);
SCHFS_ASSERT_SIZE(schfs_uberblock, SCHFS_BLKSIZE);
SCHFS_ASSERT_SIZE(schfs_inode, 80);
SCHFS_ASSERT_SIZE(schfs_extent, 32);
SCHFS_ASSERT_SIZE(schfs_dirent_rec, 16);
#endif /* SCHFS_H */

9
include/sleeplock.h Normal file
View file

@ -0,0 +1,9 @@
// Long-term locks for processes
struct sleeplock {
uint locked; // Is the lock held?
struct spinlock lk; // spinlock protecting this sleep lock
// For debugging:
char *name; // Name of lock.
int pid; // Process holding lock
};

81
include/socket.h Normal file
View file

@ -0,0 +1,81 @@
#pragma once
#include "types.h"
// Unix domain sockets.
//
// These exist for Schcom. A compositor and its clients have to exchange
// messages, and a pipe cannot do it: a pipe is one-directional, has no
// notion of a connection, and gives no way for a server to be *found* by a
// client that starts later. A socket with a name in the filesystem is
// exactly the missing piece.
//
// AF_INET is deliberately absent. The socket layer is being built around the
// local case first because that is the one the GUI needs and the one whose
// semantics are simplest; a network stack plugs in underneath the same
// syscalls later rather than reshaping them.
#define AF_UNIX 1
#define AF_LOCAL 1
#define AF_INET 2 // recognised so it can be refused honestly
#define SOCK_STREAM 1
#define SOCK_DGRAM 2
#define UNIX_PATH_MAX 108
#define SHUT_RD 0
#define SHUT_WR 1
#define SHUT_RDWR 2
struct sockaddr_un {
uint16 sun_family;
char sun_path[UNIX_PATH_MAX];
};
// The generic form syscalls take. Same shape as Linux's, so a musl-linked
// program's struct lines up byte for byte.
struct sockaddr {
uint16 sa_family;
char sa_data[UNIX_PATH_MAX];
};
#ifdef _KERNEL_SOCKET_INTERNALS
#define NSOCK 32 // sockets in the system
#define SOCKBUF 4096 // receive buffer per connected socket
#define NBACKLOG 8
enum sockstate {
SS_FREE = 0,
SS_UNBOUND,
SS_BOUND,
SS_LISTENING,
SS_CONNECTED,
};
// Every field here is protected by the socket table's single lock in
// kernel/net/unix.c -- there is deliberately no per-socket lock; see the
// comment at the top of that file for why.
struct socket {
int ref;
int type;
int state;
char name[UNIX_PATH_MAX]; // the bound path, for a listener
// A connected socket's peer. Writing to a socket appends to the *peer's*
// buffer, which is what makes one buffer per socket enough for a
// bidirectional connection.
struct socket *peer;
int peer_closed;
char data[SOCKBUF];
uint nread, nwrite;
// Connections waiting to be accepted, on a listener.
struct socket *queue[NBACKLOG];
int nqueue;
};
#endif

9
include/spinlock.h Normal file
View file

@ -0,0 +1,9 @@
// Mutual exclusion lock.
struct spinlock {
uint64 locked; // Is the lock held?
// For debugging:
char *name; // Name of lock.
struct cpu *cpu; // The cpu holding the lock.
addr_t pcs[10]; // The call stack (an array of program counters)
// that locked the lock.
};

24
include/stat.h Normal file
View file

@ -0,0 +1,24 @@
#pragma once
#include "types.h"
#define T_DIR 1 // Directory
#define T_FILE 2 // File
#define T_DEV 3 // Device
#define T_SYMLINK 4 // Divesymlink
#define T_EXTENT 5 // bmap & itrunc
struct stat {
int32 type; // File type (T_DIR, T_FILE, or T_DEV)
int32 dev; // File system's disk device ID
uint64 ino; // Inode number
int32 nlink; // Number of hard links to file
uint32 pad; // Padding for 64-bit alignment
uint64 size; // Size of file in bytes
uint rwmode; // Permissions
uint supermode; // Mode
uint showmode; // Visiblity
uint atime; // Last access time
uint mtime; // Last modification time
uint ctime; // Last metadata-change time
uint addrs[12+3]; // Block Addresses
};

49
include/syscall.h Normal file
View file

@ -0,0 +1,49 @@
#pragma once
// Syscall numbers and definition macros — all derived from
// kernel/sys/table.inc, which is the single source of truth.
//
// Do NOT add SYS_* constants by hand, and do NOT add anything to
// kernel/sys/linux_abi.c: add one SYSCALL() line to table.inc and write the
// body with SYSCALL_DEFINE(). The constant, the dispatch slot and the Linux
// ABI mapping are all generated from that one line.
#define NSYSCALLS 512
// Scratch slot for syscalls with no Linux equivalent. Every such entry lands
// on this one index of the translation map, which is never dispatched (Linux
// x86_64 numbers currently top out around 450). Using a real index rather
// than a negative sentinel keeps the generated map a plain designated
// initialiser instead of needing a second macro.
#define NO_LINUX 511
#ifdef __ASSEMBLER__
// In .S files GCC passes through the C preprocessor but the assembler
// sees the output, so emit .set directives instead of an enum.
#define SYSCALL(nr, lnr, name) .set SYS_##name, nr
#define SYSCALL_ALIAS(lnr, name)
#include "../kernel/sys/table.inc"
#undef SYSCALL
#undef SYSCALL_ALIAS
#else
// In C files generate a proper enum so constants work in switch/designators.
enum syscall_nr {
_SYS_RESERVED = 0,
#define SYSCALL(nr, lnr, name) SYS_##name = (nr),
#define SYSCALL_ALIAS(lnr, name)
#include "../kernel/sys/table.inc"
#undef SYSCALL
#undef SYSCALL_ALIAS
};
// Every syscall body is written as:
//
// SYSCALL_DEFINE(getpid)
// {
// return myproc()->pid;
// }
//
// so the signature lives in exactly one place and every implementation is
// findable with a single grep.
#define SYSCALL_DEFINE(name) addr_t sys_##name(void)
#endif

86
include/text.h Normal file
View file

@ -0,0 +1,86 @@
#pragma once
// Text rendering.
//
// The console draws text by indexing `font_data[256][16]` and stepping the
// cursor eight pixels. That is a *character cell grid*, and it is the thing in
// the way -- not the font. A grid cannot do variable-width glyphs, cannot
// position text anywhere except on a multiple of eight, cannot anti-alias, and
// cannot represent a codepoint above 255. Swapping the bitmap for a nicer
// bitmap changes none of that.
//
// So this is a layer, not a font. Three things it fixes:
//
// *Glyphs have metrics.* A glyph knows its own size, its bearing and how far
// to advance afterwards. That is what variable-width text is; everything else
// follows from it.
//
// *It draws into a surface, not into the screen.* A compositor draws into an
// off-screen buffer and presents it. Rendering that writes straight to the
// VGA aperture is unusable to it, which is why this takes a target.
//
// *The font is behind an interface.* The bitmap font is one implementation.
// A TrueType rasteriser is another, and arrives without any caller changing:
// glyphs carry 8-bit coverage, so an anti-aliased outline renderer already
// has somewhere to put its output.
struct font;
// Somewhere to draw. Deliberately not a `struct device` or a framebuffer: the
// same code has to work on the virtio-gpu back buffer, on a window's own
// buffer, and on the VGA aperture, and none of those know about each other.
struct surface {
void *pixels; // 32-bit 0x00RRGGBB, the format everything here uses
uint32 stride; // bytes per row, not pixels -- they differ on real hardware
int width, height;
};
// One rendered glyph. `cov` is 8-bit coverage, not a bitmap: 0 is background,
// 255 is solid, and everything between is an anti-aliased edge. A bitmap font
// fills it with 0 and 255 only, and costs nothing for the generality.
struct glyph {
const unsigned char *cov; // w*h bytes, row-major
int w, h; // size of the coverage bitmap
int bearing_x, bearing_y; // offset from the pen to the top-left of `cov`
int advance; // how far the pen moves afterwards
};
struct font_ops {
// Fill `out` for `cp`. Returns 0, or -1 if the font has no such glyph --
// callers substitute rather than failing, because a missing glyph must not
// stop a line of text.
int (*glyph)(struct font *, uint32 cp, struct glyph *out);
int (*height)(struct font *); // line height
int (*baseline)(struct font *); // pen offset from the top of the line
};
struct font {
const struct font_ops *ops;
void *priv;
};
// The built-in bitmap font, as a font provider. Always available, needs no
// allocation, and is what the console falls back to before any filesystem
// exists to load a real typeface from.
struct font *font_builtin(void);
// Draw one UTF-8 string. Returns the x advance.
//
// `x, y` is the pen position on the *baseline*, which is how every text API
// that is not a terminal works -- glyphs of different heights then sit on a
// common line instead of being top-aligned.
int text_draw(struct surface *, struct font *, int x, int y,
const char *utf8, uint32 color);
// Width the same string would occupy, without drawing it. Needed before you
// draw, for centring and for laying out anything at all.
int text_measure(struct font *, const char *utf8);
// One glyph, for callers doing their own layout.
int text_draw_glyph(struct surface *, struct font *, int x, int y,
uint32 cp, uint32 color);
// Decode one UTF-8 sequence. Returns the codepoint and advances *p.
// Malformed input yields U+FFFD and consumes one byte, so a decoder loop
// always terminates.
uint32 utf8_next(const char **p);

57
include/theme.h Normal file
View file

@ -0,0 +1,57 @@
#pragma once
// Schunix visual identity — one palette, shared by everything that draws.
//
// This header exists because there were three unrelated designs and the seams
// showed. The bootloader splash was deep purple with gold text, deliberately
// matching the *panic* screen; the kernel console was cream with near-black
// text; the panic screen was the purple both were copying. So a normal boot
// looked like a crash, then abruptly became an amber terminal, and none of the
// three looked like the same product.
//
// The rule now: **normal states are calm and dark; only failure is loud.**
// Boot, console and shell share SCH_BG/SCH_FG. The panic screen keeps the
// full-bleed purple entirely to itself, which is what makes it mean something.
//
// Included by boot/stage2main.c (freestanding, pre-kernel), kernel/dev/vga.c,
// kernel/core/console.c and kernel/core/panic.c. Plain #defines only — no
// types, no code — because stage2 is compiled 32-bit against a different
// world than the kernel.
//
// Colours are 0xRRGGBB. vga_draw_pixel packs them for whatever depth the
// framebuffer actually is.
// --- the product ---------------------------------------------------------
// Near-black with a slight blue cast rather than pure #000: pure black on an
// LCD reads as "the machine is off", and every serious platform sits a few
// points above it.
#define SCH_BG 0x0C0E13
#define SCH_FG 0xE6E8EC // primary text
#define SCH_DIM 0x707784 // secondary text, hints, version strings
#define SCH_ACCENT 0x7C5CFF // the one accent: violet, keeping the
// project's purple lineage without the
// eye-searing chroma of the old splash
#define SCH_ACCENT_DIM 0x2A2440 // unused track behind a progress bar
#define SCH_OK 0x4ADE80 // reserved: success states
#define SCH_WARN 0xFBBF24 // reserved: warnings that are not panics
// --- failure -------------------------------------------------------------
// PSOGM. Deliberately unlike anything above, because its whole job is to be
// unmistakable. See kernel/core/panic.c.
//
// These are the values panic.c actually renders. It used to carry a second,
// different set of PSOGM_* defines of its own, so the two disagreed about what
// the crash screen looked like and this header was quietly fiction. There was
// also a PSOGM_TITLE in gold here, left over from a splash design that no
// longer exists -- the screen is one background and two weights of text, on
// purpose, because a crash screen with an accent colour is a crash screen
// someone was enjoying designing.
#define PSOGM_BG 0x4B1D9A // the purple
#define PSOGM_FG 0xFFFFFF // the face, the headline, the values
#define PSOGM_DIM 0xC3AEEC // labels and the closing lines
// The one exception to "two weights of text": the QR card has to be a light
// panel with dark modules, because that is what a scanner needs. It reads as a
// label stuck onto the screen, which is roughly what it is.
#define PSOGM_CARD 0xFFFFFF
#define PSOGM_INK 0x000000

69
include/traps.h Normal file
View file

@ -0,0 +1,69 @@
#pragma once
// x86 trap and interrupt constants.
// Processor-defined exceptions:
#define T_DIVIDE 0 // divide error
#define T_DEBUG 1 // debug exception
#define T_NMI 2 // non-maskable interrupt
#define T_BRKPT 3 // breakpoint
#define T_OFLOW 4 // overflow
#define T_BOUND 5 // bounds check
#define T_ILLOP 6 // illegal opcode
#define T_DEVICE 7 // device not available
#define T_DBLFLT 8 // double fault
#define T_TSS 10 // invalid task switch segment
#define T_SEGNP 11 // segment not present
#define T_STACK 12 // stack exception
#define T_GPFLT 13 // general protection fault
#define T_PGFLT 14 // page fault
#define T_FPERR 16 // floating point error
#define T_ALIGN 17 // aligment check
#define T_MCHK 18 // machine check
#define T_SIMDERR 19 // SIMD floating point error
// IRQ offsets
#define T_IRQ0 32 // IRQ 0 corresponds to int T_IRQ
#define IRQ_TIMER 0
#define IRQ_KBD 1
#define IRQ_COM1 4
#define IRQ_MOUSE 12
#define IRQ_IDE 14
#define IRQ_ERROR 19
#define IRQ_SPURIOUS 31
// System call interrupt number for legacy int 0x40 or 0x80 if used
// although syscall/sysret is preferred for x64
#define T_SYSCALL 0x40
#ifndef __ASSEMBLER__
struct trapframe {
// Registers saved by trapasm.S
uint64 rax;
uint64 rbx;
uint64 rcx;
uint64 rdx;
uint64 rbp;
uint64 rsi;
uint64 rdi;
uint64 r8;
uint64 r9;
uint64 r10;
uint64 r11;
uint64 r12;
uint64 r13;
uint64 r14;
uint64 r15;
uint64 trapno;
// Error code and info saved by hardware
uint64 err;
uint64 rip;
uint64 cs;
uint64 rflags;
uint64 rsp;
uint64 ss;
};
#endif

49
include/ttf.h Normal file
View file

@ -0,0 +1,49 @@
#pragma once
// TrueType outlines, as a font provider for include/text.h.
//
// Scope, and why it is this and not "TTF and OTF":
//
// .ttf and .otf are both sfnt containers -- the same table directory, the same
// cmap, the same hmtx. What differs is how outlines are stored. TrueType puts
// quadratic B-spline contours in a `glyf` table; OpenType/PostScript puts cubic
// béziers in a `CFF ` table encoded as Type 2 charstrings, which is a
// stack-based interpreted format and a separate project.
//
// Checked before writing any of it: JetBrains Mono and Roboto -- the two fonts
// this system is going to use -- both ship `glyf` and neither ships `CFF `. So
// CFF support would buy nothing today, and the honest thing is to implement the
// format the fonts actually use and say so, rather than half-implement two.
//
// Everything here is from Apple's TrueType Reference Manual and the OpenType
// specification, both public documents.
struct ttf {
const unsigned char *data;
uint32 len;
uint32 glyf, glyf_len;
uint32 loca, loca_len;
uint32 cmap4; // offset of the format 4 subtable, 0 if none
uint32 hmtx;
int num_glyphs;
int num_hmetrics;
int units_per_em;
int long_loca; // indexToLocFormat: 0 = 16-bit offsets, 1 = 32
int ascent, descent;
// Rasterisation target size, in pixels per em. Set by ttf_open.
int px;
};
// Parse a font already in memory. Returns 0, or -1 if it is not a TrueType
// font this can read. `data` must outlive the struct -- nothing is copied.
int ttf_open(struct ttf *, const void *data, uint32 len, int pixels_per_em);
// Rasterise one codepoint into `cov`. Returns 0, or -1 if the font has no such
// glyph or it will not fit. Exposed because the host harness uses it directly.
int ttf_render(struct ttf *, uint32 cp, struct glyph *out, unsigned char *cov,
int covcap, int *ox, int *oy);
// A font provider over it, for text.h. The struct must outlive the font.
struct font *ttf_font(struct ttf *);

79
include/types.h Normal file
View file

@ -0,0 +1,79 @@
#pragma once
typedef unsigned int uint;
typedef unsigned short ushort;
typedef unsigned char uchar;
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef signed char int8;
typedef signed short int16;
typedef signed int int32;
// uint64 has to be 64 bits everywhere this header is used, and `unsigned long`
// is not that everywhere. Linux and the x86_64-elf kernel target are LP64, so
// long is 64-bit; Windows is LLP64, where long is 32-bit and only long long is
// 64-bit.
//
// This matters far more than a portability nicety. The host tools -- mkfs,
// mkschfs, the SchFS suites -- include this header *and* the on-disk structure
// definitions in fs.h and schfs.h. Building them on Windows with a 32-bit
// uint64 does not fail: it quietly produces images whose inode numbers, sizes
// and block pointers are half the width the kernel reads back, which shows up
// as a corrupt filesystem long after the tool that wrote it has exited.
//
// Spelled as long/long long rather than <stdint.h>'s uint64_t so the `%l`
// format specifiers used throughout the kernel stay correct and untouched.
// Conditioned on the actual width of `long` rather than on the platform,
// because there are three cases and only one of them is about Windows:
// x86_64-elf / Linux LP64 -> long is 64-bit
// Windows LLP64 -> long is 32-bit, long long is 64
// i386-elf (boot/) ILP32 -> long is 32-bit, and stage2main.c includes
// this header too
#if defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 8
typedef unsigned long uint64;
typedef signed long int64;
#else
typedef unsigned long long uint64;
typedef signed long long int64;
#endif
// Belt and braces: if the above is ever wrong on some new host, say so at
// compile time rather than in a filesystem image.
_Static_assert(sizeof(uint64) == 8, "uint64 must be 64 bits");
_Static_assert(sizeof(int64) == 8, "int64 must be 64 bits");
typedef uint64 uintptr_t;
typedef int64 intptr_t;
typedef int64 ptrdiff_t;
typedef uint64 addr_t;
typedef uint64 size_t;
typedef int64 ssize_t;
#ifndef MKFS
#ifndef _SIGSET_T
#define _SIGSET_T
typedef uint64 sigset_t;
#endif
#endif
typedef addr_t pte_t;
typedef addr_t pde_t;
typedef addr_t pdpe_t;
typedef addr_t pml4e_t;
struct mouse_data {
int x;
int y;
uint8 buttons;
};
#ifndef NULL
#define NULL ((void*)0)
#endif
#define TRUE 1
#define FALSE 0

49
include/uaccess.h Normal file
View file

@ -0,0 +1,49 @@
// User-memory access API, modeled on Linux's <linux/uaccess.h>.
//
// Rules for kernel code touching user pointers:
//
// 1. Never dereference a user-supplied address without validating it
// first. A syscall argument can point anywhere, including at kernel
// memory or at nothing at all.
//
// 2. Never assume a user buffer is physically contiguous. uva2ka() only
// translates ONE page; the direct-map alias it returns runs into an
// unrelated physical page at the next 4K boundary. Any multi-byte
// access through it must stay within a single page.
//
// These helpers encapsulate both rules. Because Schunix (like old x86
// without SMAP) keeps the user page table active in kernel mode, a raw
// user virtual address is directly dereferenceable once the whole range
// has been validated — that is what user_ptr() hands back, and why the
// result is safe across page boundaries where a uva2ka() pointer is not.
#ifndef SCHUNIX_UACCESS_H
#define SCHUNIX_UACCESS_H
#include "types.h"
// Nonzero if [uaddr, uaddr+size) is entirely mapped, user-accessible
// memory in the current process. size == 0 is always ok.
int access_ok(addr_t uaddr, uint64 size);
// Validate the whole range and return it as a directly usable pointer
// (the raw user VA). 0 on bad/NULL address.
void *user_ptr(addr_t uaddr, uint64 size);
// Copy between kernel and user memory, page by page.
// Return 0 on success, -EFAULT on any unmapped page.
int copy_from_user(void *dst, addr_t uaddr, uint64 n);
int copy_to_user(addr_t uaddr, const void *src, uint64 n);
// Fixed-size scalar variants, in the spirit of Linux's get_user/put_user.
#define get_user(x, uaddr) copy_from_user(&(x), (addr_t)(uaddr), sizeof(x))
#define put_user(x, uaddr) copy_to_user((addr_t)(uaddr), &(x), sizeof(x))
// Longest string fetchstr()/strlen_user() will scan before giving up.
#define USER_STR_MAX 32768
// Length of the NUL-terminated string at uaddr (excluding the NUL),
// validating every page it spans. -EFAULT if it runs off mapped memory
// or exceeds USER_STR_MAX.
long strlen_user(addr_t uaddr);
#endif // SCHUNIX_UACCESS_H

270
include/usb.h Normal file
View file

@ -0,0 +1,270 @@
#pragma once
#include "device.h"
// USB, the parts that are the same whatever host controller you have.
//
// Everything here comes from the USB 2.0 specification chapter 9, which every
// USB device implements regardless of speed, class or vendor. That is what
// makes enumeration possible at all: before you know anything about a device
// you can still ask it what it is, because the question is standardised.
// bmRequestType
#define USB_DIR_OUT 0x00
#define USB_DIR_IN 0x80
#define USB_TYPE_STANDARD 0x00
#define USB_TYPE_CLASS 0x20
#define USB_RECIP_DEVICE 0x00
#define USB_RECIP_INTERFACE 0x01
#define USB_RECIP_ENDPOINT 0x02
#define USB_RECIP_OTHER 0x03 // a hub's downstream port
// bRequest, standard requests
#define USB_REQ_GET_STATUS 0
#define USB_REQ_CLEAR_FEATURE 1
#define USB_REQ_SET_FEATURE 3
#define USB_REQ_SET_ADDRESS 5
#define USB_REQ_GET_DESCRIPTOR 6
#define USB_REQ_SET_DESCRIPTOR 7
#define USB_REQ_GET_CONFIG 8
#define USB_REQ_SET_CONFIG 9
#define USB_REQ_GET_INTERFACE 10
#define USB_REQ_SET_INTERFACE 11
// Descriptor types (the high byte of wValue in a GET_DESCRIPTOR)
#define USB_DT_DEVICE 1
#define USB_DT_CONFIG 2
#define USB_DT_STRING 3
#define USB_DT_INTERFACE 4
#define USB_DT_ENDPOINT 5
// Class codes we care about
#define USB_CLASS_HID 0x03
#define USB_CLASS_MASS_STORAGE 0x08
#define USB_CLASS_HUB 0x09
// HID subclass/protocol. Boot protocol is the one a BIOS uses, and the reason
// a USB keyboard works before any operating system has loaded: the report
// layout is fixed, so it can be read without parsing a report descriptor.
#define USB_HID_SUBCLASS_BOOT 0x01
#define USB_HID_PROTO_KEYBOARD 0x01
#define USB_HID_PROTO_MOUSE 0x02
// Bus speeds.
//
// These are xHCI's numbering, used as the common currency rather than
// translated at the boundary. That is a deliberate choice: there is one host
// controller, the values have to reach a slot context eventually, and a
// second enum whose only job is to be converted into this one would be
// ceremony. If a second controller ever appears, this is the thing to
// revisit -- but a class driver still has no business including xhci.h.
#define USB_SPEED_FULL 1 // 12 Mb/s
#define USB_SPEED_LOW 2 // 1.5 Mb/s
#define USB_SPEED_HIGH 3 // 480 Mb/s
#define USB_SPEED_SUPER 4 // 5 Gb/s
// An eight-byte SETUP packet, the header of every control transfer.
struct usb_setup {
uint8 bmRequestType;
uint8 bRequest;
uint16 wValue;
uint16 wIndex;
uint16 wLength;
} __attribute__((packed));
struct usb_device_desc {
uint8 bLength;
uint8 bDescriptorType;
uint16 bcdUSB;
uint8 bDeviceClass;
uint8 bDeviceSubClass;
uint8 bDeviceProtocol;
uint8 bMaxPacketSize0;
uint16 idVendor;
uint16 idProduct;
uint16 bcdDevice;
uint8 iManufacturer;
uint8 iProduct;
uint8 iSerialNumber;
uint8 bNumConfigurations;
} __attribute__((packed));
struct usb_config_desc {
uint8 bLength;
uint8 bDescriptorType;
uint16 wTotalLength;
uint8 bNumInterfaces;
uint8 bConfigurationValue;
uint8 iConfiguration;
uint8 bmAttributes;
uint8 bMaxPower;
} __attribute__((packed));
struct usb_interface_desc {
uint8 bLength;
uint8 bDescriptorType;
uint8 bInterfaceNumber;
uint8 bAlternateSetting;
uint8 bNumEndpoints;
uint8 bInterfaceClass;
uint8 bInterfaceSubClass;
uint8 bInterfaceProtocol;
uint8 iInterface;
} __attribute__((packed));
struct usb_endpoint_desc {
uint8 bLength;
uint8 bDescriptorType;
uint8 bEndpointAddress; // bit 7: 1 = IN
uint8 bmAttributes; // bits 1:0: 0 ctrl, 1 iso, 2 bulk, 3 interrupt
uint16 wMaxPacketSize;
uint8 bInterval;
} __attribute__((packed));
#define USB_EP_XFERTYPE(a) ((a) & 0x03)
#define USB_EP_BULK 2
#define USB_EP_INTERRUPT 3
#define USB_EP_IS_IN(a) (((a) & 0x80) != 0)
#define USB_EP_NUM(a) ((a) & 0x0F)
// Mass storage: SCSI transparent command set over bulk-only transport.
#define USB_MSC_SUBCLASS_SCSI 0x06
#define USB_MSC_PROTO_BOT 0x50
// ---------------------------------------------------------------------------
// Hubs
//
// A hub is a USB device like any other, and everything it does is done by
// sending it ordinary control requests. There is no separate bus protocol:
// "reset port 3" is a SET_FEATURE addressed to the hub.
// ---------------------------------------------------------------------------
#define USB_DT_HUB 0x29
// Port features, the wValue of SET_FEATURE / CLEAR_FEATURE on a port.
#define PORT_FEAT_ENABLE 1
#define PORT_FEAT_RESET 4
#define PORT_FEAT_POWER 8
#define PORT_FEAT_C_CONNECTION 16
#define PORT_FEAT_C_ENABLE 17
#define PORT_FEAT_C_RESET 20
// wPortStatus, the first half of a port's GET_STATUS reply.
#define PORTSTAT_CONNECTION (1 << 0)
#define PORTSTAT_ENABLE (1 << 1)
#define PORTSTAT_RESET (1 << 4)
#define PORTSTAT_POWER (1 << 8)
#define PORTSTAT_LOWSPEED (1 << 9)
#define PORTSTAT_HIGHSPEED (1 << 10)
struct usb_hub_desc {
uint8 bDescLength;
uint8 bDescriptorType;
uint8 bNbrPorts;
uint16 wHubCharacteristics;
uint8 bPwrOn2PwrGood; // in 2 ms units
uint8 bHubContrCurrent;
} __attribute__((packed));
// Bits 1:0 of wHubCharacteristics: 00 ganged power, 01 per-port.
#define HUB_CHAR_TT_MASK 0x0060
// HID class requests, on the interface rather than the device.
#define USB_HID_SET_IDLE 0x0A
#define USB_HID_SET_PROTOCOL 0x0B
#define USB_HID_PROTOCOL_BOOT 0
// ---------------------------------------------------------------------------
// The interface between the USB core and a host controller
//
// One host controller exists (xHCI) and one probably always will, but the
// core has no business knowing about TRBs and slot IDs, and the controller
// has no business knowing what a HID report is. This is where the line goes.
// ---------------------------------------------------------------------------
struct usb_dev;
struct usb_hc_ops {
// A control transfer on endpoint 0. `buf`, if any, must be DMA memory.
int (*control)(struct usb_dev *, struct usb_setup *, void *buf, int len);
// Make an endpoint usable. Returns 0, or -1 if the controller refused.
int (*open_ep)(struct usb_dev *, const struct usb_endpoint_desc *);
// Queue one IN transfer. Completion arrives via dev->complete.
int (*queue_in)(struct usb_dev *, int ep_addr, void *buf, int len);
// One bulk transfer, synchronously. Sleeps, so process context only.
// Returns bytes transferred, or -1.
int (*bulk)(struct usb_dev *, int ep_addr, void *buf, int len);
// Bring up a device found on a downstream port of `hub`. The controller
// works out the route string from the hub's own position.
void (*attach)(struct usb_dev *hub, int hub_port, int speed);
// Tell the controller this device is a hub with `nports` ports. It has to
// know: a hub is scheduled differently from anything else, and devices
// behind it are addressed relative to it.
int (*set_hub)(struct usb_dev *, int nports, int mtt);
};
#define USB_MAXCONF 256 // bytes of configuration descriptor we keep
struct usb_dev {
const struct usb_hc_ops *ops;
void *hc; // the controller's own handle for this device
int slot;
int speed;
int port; // ROOT hub port this whole branch hangs off
// Where the device sits in the tree.
//
// A USB device has no address of its own that describes its position -- the
// controller finds it by being told the path. `route` is xHCI's route
// string: five nibbles, one per tier, each holding the downstream port
// number taken at that tier. Tier 0 is a device on a root port, and its
// route is 0.
uint32 route;
int tier;
// Transaction translator, for a full or low speed device behind a
// high-speed hub. The controller has to know which hub is doing the
// speed conversion on its behalf, because it is the hub, not the device,
// that it actually schedules against.
int tt_slot, tt_port;
int in_use;
struct usb_device_desc desc;
uchar conf[USB_MAXCONF]; // the configuration descriptor and everything
int conflen; // that follows it, exactly as the device sent
// The first interface, which is all a boot-protocol or bulk-only device
// needs, and the endpoints belonging to it.
struct usb_interface_desc iface;
struct usb_endpoint_desc intr_in;
struct usb_endpoint_desc bulk_in;
struct usb_endpoint_desc bulk_out;
int has_intr_in, has_bulk_in, has_bulk_out;
// Filled in by whichever class driver claimed the device.
const char *driver;
void *drvdata;
void (*complete)(struct usb_dev *, void *buf, int len);
};
// One row per class driver. Matching is on the *interface* descriptor,
// because bDeviceClass is very often 0 ("look at the interfaces").
struct usb_driver {
const char *name;
uint8 class, subclass, protocol; // 0xFF matches anything
// What the rest of the kernel should consider this device to be, once this
// driver has claimed it. Distinct from `class` above, which is the USB
// interface class the descriptor advertises: the driver knows what it made
// of the device, the descriptor only says what the device claims to be.
enum dev_class devclass;
int (*probe)(struct usb_dev *);
};
// Called by a host controller once a device is addressed and its device
// descriptor has been read. The core reads the configuration, selects it, and
// offers the device to the class drivers.
void usb_attach(struct usb_dev *dev);

117
include/user.h Normal file
View file

@ -0,0 +1,117 @@
#pragma once
#ifndef USER_H
#define USER_H
#include "types.h"
#include "date.h"
struct stat;
struct rtcdate;
struct mouse_data;
// --- system calls ---
int fork(void);
void exit(void) __attribute__((noreturn));
int wait(void);
int pipe(int*);
int write(int, void*, int);
int read(int, void*, int);
int close(int);
int kill(int);
int exec(char*, char**);
int open(char*, int);
int mknod(char*, short, short);
int unlink(char*);
int fstat(int fd, struct stat*);
int link(char*, char*);
int mkdir(char*);
int chdir(char*);
int dup(int);
int dup2(int, int);
int fcntl(int, int, int);
long lseek(int, long, int);
int getpid(void);
char* sbrk(uint64);
int sleep(int);
int uptime(void);
int vga_sync(void*);
int getmouse(struct mouse_data*);
int reboot(void);
int shutdown(void);
int sigfillset(sigset_t *set);
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
int sigwait(const sigset_t *set, int *sig);
int alarm(int seconds);
int waitpid(int pid, int *status, int options);
int setsid(void);
void* mmap(void*, uint64, int, int, int, uint64);
// Shared memory. shmat returns the attach address, or a small negative value
// on failure — there is no errno in this runtime, so check for < 0.
int shmget(int key, uint64 size, int flags);
void* shmat(int id, void *addr, int flags);
int shmdt(void *addr);
int munmap(void*, uint64);
int delete(char*);
int show(char*);
int showstat(char*, struct stat*);
int ftruncate(int, int);
int truncate(char*, int);
int rename(const char*, const char*);
int symlink(char*, char*);
int readlink(char*, char*, int);
int getuid(void);
int geteuid(void);
int nanosleep(void*);
int mprotect(void*, uint64, int);
int ioctl(int, uint64, void*);
char* getcwd(char*, int);
int arch_prctl(int, uint64);
int set_tid_address(int*);
int set_robust_list(void*, int);
int futex(int*, int, int, void*, int*, int);
int clone(uint64, void*, void*, void*, void*);
void exit_group(int) __attribute__((noreturn));
int wait4(int, int*, int, void*);
int getgid(void);
int getegid(void);
int umask(int);
int writev(int, void*, int);
int readv(int, void*, int);
void* brk(void*);
int prlimit(int, int, void*, void*);
int lstat(const char*, struct stat*);
int access(const char*, int);
int openat(int, const char*, int, ...);
int fchdir(int);
int enable_linux_abi(void);
int getrlimit(int, void*);
int setuid(int);
int setgid(int);
int getsid(int);
int dup3(int, int, int);
int pipe2(int*, int);
int clock_gettime(int, void*);
int getppid(void);
int rt_sigaction(int, void*, void*, uint64);
int mount(const char *src, const char *tgt, const char *fstype, uint64 flags, void *data);
// Sockets. `struct sockaddr` and the AF_*/SOCK_* constants are in socket.h;
// include it as well as this header to use them.
struct sockaddr;
int socket(int domain, int type, int protocol);
int bind(int fd, const struct sockaddr *addr, int addrlen);
int listen(int fd, int backlog);
int accept(int fd, struct sockaddr *addr, int *addrlen);
int connect(int fd, const struct sockaddr *addr, int addrlen);
int socketpair(int domain, int type, int protocol, int sv[2]);
int sendto(int fd, const void *buf, int len, int flags, const struct sockaddr*, int);
int recvfrom(int fd, void *buf, int len, int flags, struct sockaddr*, int*);
int sockshutdown(int fd, int how);
int setsockopt(int fd, int level, int opt, const void *val, int len);
int getsockopt(int fd, int level, int opt, void *val, int *len);
// --- ulib.c ---
int stat(const char*, struct stat*);
char* gets(char*, int max);
#endif // USER_H

174
include/virtio.h Normal file
View file

@ -0,0 +1,174 @@
#pragma once
// virtio 1.0 over PCI — the transport, and virtio-gpu's 2D protocol.
//
// Written from the OASIS specification (virtio 1.1, chapters 2, 4.1 and 5.7),
// which is a public document with no licence on what you write from it. Same
// reasoning as kernel/drivers/xhci.c.
//
// Why virtio-gpu at all, when there is already a framebuffer: the VBE
// framebuffer is a flat block of memory the loader happened to be told about.
// It has no mode setting, no notion of a frame being complete, and no way to
// ask the host to present anything -- so a compositor drawing into it is
// racing the scanout with no way to synchronise. virtio-gpu has resources,
// explicit transfer and an explicit flush, which is the model every real GPU
// driver has. It is the smallest device that teaches the right shape.
// --- PCI transport ---------------------------------------------------------
#define VIRTIO_VENDOR 0x1AF4
// Modern (1.0) device IDs are 0x1040 + the virtio device type. GPU is type 16.
#define VIRTIO_DEV_GPU 0x1050
// Vendor-specific PCI capability, which is how a virtio device says where in
// its BARs each configuration structure lives.
#define PCI_CAP_ID_VNDR 0x09
#define VIRTIO_PCI_CAP_COMMON_CFG 1
#define VIRTIO_PCI_CAP_NOTIFY_CFG 2
#define VIRTIO_PCI_CAP_ISR_CFG 3
#define VIRTIO_PCI_CAP_DEVICE_CFG 4
// Offsets within the common configuration structure. Written out rather than
// declared as a struct: the fields are little-endian by specification and of
// mixed width, and a struct invites the compiler to pad or a caller to forget
// that these are MMIO and must be accessed at exactly the stated width.
#define VCOMMON_DFEAT_SEL 0x00 // le32
#define VCOMMON_DFEAT 0x04 // le32
#define VCOMMON_GFEAT_SEL 0x08 // le32
#define VCOMMON_GFEAT 0x0C // le32
#define VCOMMON_MSIX_CFG 0x10 // le16
#define VCOMMON_NUM_QUEUES 0x12 // le16
#define VCOMMON_STATUS 0x14 // u8
#define VCOMMON_CFG_GEN 0x15 // u8
#define VCOMMON_Q_SELECT 0x16 // le16
#define VCOMMON_Q_SIZE 0x18 // le16
#define VCOMMON_Q_MSIX 0x1A // le16
#define VCOMMON_Q_ENABLE 0x1C // le16
#define VCOMMON_Q_NOTIFY_OFF 0x1E // le16
#define VCOMMON_Q_DESC 0x20 // le64
#define VCOMMON_Q_DRIVER 0x28 // le64
#define VCOMMON_Q_DEVICE 0x30 // le64
// device_status bits, set in this order during bring-up.
#define VSTATUS_ACK 1
#define VSTATUS_DRIVER 2
#define VSTATUS_DRIVER_OK 4
#define VSTATUS_FEATURES_OK 8
#define VSTATUS_FAILED 0x80
#define VIRTIO_F_VERSION_1 32 // feature bit: this is a 1.0 device
// --- split virtqueue -------------------------------------------------------
#define VRING_DESC_F_NEXT 1
#define VRING_DESC_F_WRITE 2 // device writes it; i.e. this is our buffer
struct vring_desc {
uint64 addr;
uint32 len;
uint16 flags;
uint16 next;
} __attribute__((packed));
struct vring_avail {
uint16 flags;
uint16 idx;
uint16 ring[];
} __attribute__((packed));
struct vring_used_elem {
uint32 id;
uint32 len;
} __attribute__((packed));
struct vring_used {
uint16 flags;
uint16 idx;
struct vring_used_elem ring[];
} __attribute__((packed));
// --- virtio-gpu, 2D --------------------------------------------------------
#define VIRTIO_GPU_CMD_GET_DISPLAY_INFO 0x0100
#define VIRTIO_GPU_CMD_RESOURCE_CREATE_2D 0x0101
#define VIRTIO_GPU_CMD_RESOURCE_UNREF 0x0102
#define VIRTIO_GPU_CMD_SET_SCANOUT 0x0103
#define VIRTIO_GPU_CMD_RESOURCE_FLUSH 0x0104
#define VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D 0x0105
#define VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING 0x0106
#define VIRTIO_GPU_RESP_OK_NODATA 0x1100
#define VIRTIO_GPU_RESP_OK_DISPLAY_INFO 0x1101
#define VIRTIO_GPU_MAX_SCANOUTS 16
// B8G8R8X8, which is what a 32-bit little-endian 0x00RRGGBB word looks like in
// memory -- the same layout vga.c already draws into, so a framebuffer can be
// handed over without a conversion pass.
#define VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM 2
struct virtio_gpu_ctrl_hdr {
uint32 type;
uint32 flags;
uint64 fence_id;
uint32 ctx_id;
uint32 padding;
} __attribute__((packed));
struct virtio_gpu_rect {
uint32 x, y, width, height;
} __attribute__((packed));
struct virtio_gpu_display_one {
struct virtio_gpu_rect r;
uint32 enabled;
uint32 flags;
} __attribute__((packed));
struct virtio_gpu_resp_display_info {
struct virtio_gpu_ctrl_hdr hdr;
struct virtio_gpu_display_one pmodes[VIRTIO_GPU_MAX_SCANOUTS];
} __attribute__((packed));
struct virtio_gpu_resource_create_2d {
struct virtio_gpu_ctrl_hdr hdr;
uint32 resource_id;
uint32 format;
uint32 width;
uint32 height;
} __attribute__((packed));
struct virtio_gpu_mem_entry {
uint64 addr;
uint32 length;
uint32 padding;
} __attribute__((packed));
struct virtio_gpu_resource_attach_backing {
struct virtio_gpu_ctrl_hdr hdr;
uint32 resource_id;
uint32 nr_entries;
} __attribute__((packed));
struct virtio_gpu_set_scanout {
struct virtio_gpu_ctrl_hdr hdr;
struct virtio_gpu_rect r;
uint32 scanout_id;
uint32 resource_id;
} __attribute__((packed));
struct virtio_gpu_transfer_to_host_2d {
struct virtio_gpu_ctrl_hdr hdr;
struct virtio_gpu_rect r;
uint64 offset;
uint32 resource_id;
uint32 padding;
} __attribute__((packed));
struct virtio_gpu_resource_flush {
struct virtio_gpu_ctrl_hdr hdr;
struct virtio_gpu_rect r;
uint32 resource_id;
uint32 padding;
} __attribute__((packed));

219
include/x86.h Normal file
View file

@ -0,0 +1,219 @@
#pragma once
struct dtr {
ushort limit;
uint64 base;
} __attribute__((packed));
static inline uchar
inb(ushort port)
{
uchar data;
asm volatile("in %1,%0" : "=a" (data) : "d" (port));
return data;
}
static inline void
insl(int port, void *addr, int cnt)
{
asm volatile("cld; rep insl" :
"=D" (addr), "=c" (cnt) :
"d" (port), "0" (addr), "1" (cnt) :
"memory", "cc");
}
static inline void
outb(ushort port, uchar data)
{
asm volatile("out %0,%1" : : "a" (data), "d" (port));
}
static inline uint
inl(ushort port)
{
uint data;
asm volatile("inl %1,%0" : "=a" (data) : "d" (port));
return data;
}
static inline void
outw(ushort port, ushort data)
{
asm volatile("out %0,%1" : : "a" (data), "d" (port));
}
// PCI configuration space is reached through a pair of 32-bit ports, so this
// is not optional decoration -- see kernel/dev/pci.c.
static inline void
outl(ushort port, uint data)
{
asm volatile("outl %0,%1" : : "a" (data), "d" (port));
}
static inline void
outsl(int port, const void *addr, int cnt)
{
asm volatile("cld; rep outsl" :
"=S" (addr), "=c" (cnt) :
"d" (port), "0" (addr), "1" (cnt) :
"cc");
}
static inline void
stosb(void *addr, int data, int cnt)
{
asm volatile("cld; rep stosb" :
"=D" (addr), "=c" (cnt) :
"0" (addr), "1" (cnt), "a" (data) :
"memory", "cc");
}
// 64-bit-only helpers. `rep stosq` and `xchgq` do not exist in 32-bit mode, so
// these must not even be parsed by the -m32 bootloader build -- they compiled
// there before only because uint64 was accidentally 32 bits wide, which is the
// bug include/types.h now asserts against.
#ifdef __x86_64__
static inline void
stosq(void *addr, uint64 data, int cnt)
{
asm volatile("cld; rep stosq" :
"=D" (addr), "=c" (cnt) :
"0" (addr), "1" (cnt), "a" (data) :
"memory", "cc");
}
struct segdesc;
static inline void
lgdt(struct segdesc *p, int size)
{
struct dtr d;
d.limit = size - 1;
d.base = (uint64)p;
asm volatile("lgdt (%0)" : : "r" (&d));
}
struct gatedesc;
static inline void
lidt(struct gatedesc *p, int size)
{
struct dtr d;
d.limit = size - 1;
d.base = (uint64)p;
asm volatile("lidt (%0)" : : "r" (&d));
}
static inline void
ltr(ushort sel)
{
asm volatile("ltr %0" : : "r" (sel));
}
static inline uint64
readeflags(void)
{
uint64 flags;
asm volatile("pushfq; pop %0" : "=r" (flags));
return flags;
}
static inline void
cli(void)
{
asm volatile("cli");
}
static inline void
sti(void)
{
asm volatile("sti");
}
static inline void
hlt(void)
{
asm volatile("hlt");
}
static inline uint64
xchg(volatile uint64 *addr, uint64 newval)
{
uint64 result;
asm volatile("lock; xchgq %0, %1" :
"+m" (*addr), "=a" (result) :
"1" (newval) :
"cc");
return result;
}
#endif /* __x86_64__ */
static inline uint64
rcr2(void)
{
uint64 val;
asm volatile("mov %%cr2,%0" : "=r" (val));
return val;
}
static inline void
lcr3(uint64 val)
{
asm volatile("mov %0,%%cr3" : : "r" (val));
}
// Invalidate the TLB entry for one page. Needed any time a PTE is changed
// or cleared for an address space that may still be the active CR3 —
// otherwise the CPU can keep translating through the stale entry until the
// next full CR3 reload (context switch), silently reading/writing the
// wrong physical page.
static inline void
invlpg(void *va)
{
asm volatile("invlpg (%0)" : : "r" (va) : "memory");
}
static inline void
wrmsr(uint32 msr, uint64 val)
{
uint32 low = (uint32)val;
uint32 high = (uint32)(val >> 32);
asm volatile("wrmsr" : : "c" (msr), "a" (low), "d" (high));
}
static inline uint64
rdmsr(uint32 msr)
{
uint32 low, high;
asm volatile("rdmsr" : "=a" (low), "=d" (high) : "c" (msr));
return ((uint64)high << 32) | low;
}
static inline uint64
readcs(void)
{
uint64 val;
asm volatile("mov %%cs, %0" : "=r" (val));
return val;
}
// CPUID. `leaf` in EAX, results in EAX/EBX/ECX/EDX.
//
// %rbx is callee-saved *and* the PIC base register on some builds, so it is
// exchanged out rather than named as an operand -- naming it directly is the
// classic way to get "inline asm clobbers reserved register" or, worse, silent
// corruption in the caller.
static inline void
cpuid_leaf(uint32 leaf, uint32 *a, uint32 *b, uint32 *c, uint32 *d)
{
uint32 ra, rb, rc, rd;
asm volatile("xchgq %%rbx, %q1\n\t"
"cpuid\n\t"
"xchgq %%rbx, %q1"
: "=a"(ra), "=&r"(rb), "=c"(rc), "=d"(rd)
: "0"(leaf), "2"(0));
if (a) *a = ra;
if (b) *b = rb;
if (c) *c = rc;
if (d) *d = rd;
}

161
include/xhci.h Normal file
View file

@ -0,0 +1,161 @@
#pragma once
// eXtensible Host Controller Interface -- the register and data-structure
// definitions from the xHCI 1.2 specification.
//
// Why xHCI and not UHCI/OHCI/EHCI: xHCI is the only host controller interface
// that speaks every USB speed, so one driver covers USB 1.1 through 3.x. The
// older controllers would each need their own, and a machine with all of them
// needs the companion-controller handover dance on top. There is no hardware
// worth supporting that has no xHCI.
// ---------------------------------------------------------------------------
// Capability registers -- at the start of BAR0, read-only
// ---------------------------------------------------------------------------
#define XHCI_CAPLENGTH 0x00 // byte: where the operational regs begin
#define XHCI_HCIVERSION 0x02 // word
#define XHCI_HCSPARAMS1 0x04
#define XHCI_HCSPARAMS2 0x08
#define XHCI_HCSPARAMS3 0x0C
#define XHCI_HCCPARAMS1 0x10
#define XHCI_DBOFF 0x14 // doorbell array offset from BAR0
#define XHCI_RTSOFF 0x18 // runtime register offset from BAR0
#define HCS1_MAXSLOTS(x) ((x) & 0xFF)
#define HCS1_MAXINTRS(x) (((x) >> 8) & 0x7FF)
#define HCS1_MAXPORTS(x) (((x) >> 24) & 0xFF)
// Scratchpad buffer count is split across two fields, high part first.
#define HCS2_SPB_HI(x) (((x) >> 21) & 0x1F)
#define HCS2_SPB_LO(x) (((x) >> 27) & 0x1F)
#define HCC1_AC64 (1 << 0) // 64-bit addressing
#define HCC1_CSZ (1 << 2) // contexts are 64 bytes, not 32
#define HCC1_XECP(x) (((x) >> 16) & 0xFFFF) // extended caps, in dwords
// ---------------------------------------------------------------------------
// Operational registers -- at BAR0 + CAPLENGTH
// ---------------------------------------------------------------------------
#define XHCI_USBCMD 0x00
#define XHCI_USBSTS 0x04
#define XHCI_PAGESIZE 0x08
#define XHCI_DNCTRL 0x14
#define XHCI_CRCR 0x18 // 64-bit
#define XHCI_DCBAAP 0x30 // 64-bit
#define XHCI_CONFIG 0x38
#define XHCI_PORTSC(p) (0x400 + 0x10 * ((p) - 1)) // ports are 1-based
#define CMD_RS (1 << 0) // run/stop
#define CMD_HCRST (1 << 1) // host controller reset
#define CMD_INTE (1 << 2) // interrupter enable
#define CMD_HSEE (1 << 3)
#define STS_HCH (1 << 0) // halted
#define STS_HSE (1 << 2) // host system error
#define STS_EINT (1 << 3) // event interrupt (write 1 to clear)
#define STS_PCD (1 << 4) // port change detect (write 1 to clear)
#define STS_CNR (1 << 11) // controller not ready
#define CRCR_RCS (1 << 0) // ring cycle state
// PORTSC. The change bits are write-1-to-clear, and so is PED -- writing back
// a value read from this register clears whatever happened to be set. Every
// write has to mask them off first.
#define PORT_CCS (1 << 0) // current connect status
#define PORT_PED (1 << 1) // port enabled (RW1C!)
#define PORT_OCA (1 << 3)
#define PORT_PR (1 << 4) // port reset
#define PORT_PLS(x) (((x) >> 5) & 0xF)
#define PORT_PP (1 << 9) // port power
#define PORT_SPEED(x) (((x) >> 10) & 0xF)
#define PORT_CSC (1 << 17)
#define PORT_PEC (1 << 18)
#define PORT_PRC (1 << 21)
#define PORT_RW1C 0x00FE0002u // change bits 17..23, plus PED
// PORTSC speed encoding. These are the same numbers as USB_SPEED_* in usb.h,
// which is not a coincidence -- the core uses this encoding directly so that
// nothing has to be translated on its way to a slot context.
#define XSPEED_FULL USB_SPEED_FULL
#define XSPEED_LOW USB_SPEED_LOW
#define XSPEED_HIGH USB_SPEED_HIGH
#define XSPEED_SUPER USB_SPEED_SUPER
// ---------------------------------------------------------------------------
// Runtime registers -- at BAR0 + RTSOFF. Interrupter n is at 0x20 + 32*n.
// ---------------------------------------------------------------------------
#define XHCI_MFINDEX 0x00
#define XHCI_IR0 0x20
#define IR_IMAN 0x00
#define IR_IMOD 0x04
#define IR_ERSTSZ 0x08
#define IR_ERSTBA 0x10 // 64-bit
#define IR_ERDP 0x18 // 64-bit
#define IMAN_IP (1 << 0) // interrupt pending (RW1C)
#define IMAN_IE (1 << 1) // interrupt enable
#define ERDP_EHB (1 << 3) // event handler busy (RW1C)
// ---------------------------------------------------------------------------
// Transfer Request Blocks
// ---------------------------------------------------------------------------
struct trb {
uint64 param;
uint32 status;
uint32 control;
} __attribute__((packed));
#define TRB_TYPE(t) (((t) & 0x3F) << 10)
#define TRB_GET_TYPE(c) (((c) >> 10) & 0x3F)
#define TRB_C (1 << 0) // cycle bit
#define TRB_TC (1 << 1) // toggle cycle (link TRBs)
#define TRB_ISP (1 << 2)
#define TRB_CH (1 << 4) // chain
#define TRB_IOC (1 << 5) // interrupt on completion
#define TRB_IDT (1 << 6) // immediate data
#define TRB_SLOT(s) ((uint32)(s) << 24)
#define TRB_GET_SLOT(c) (((c) >> 24) & 0xFF)
#define TRB_GET_EPID(c) (((c) >> 16) & 0x1F) // transfer events
// Transfer TRBs
#define TRB_NORMAL 1
#define TRB_SETUP 2
#define TRB_DATA 3
#define TRB_STATUS 4
#define TRB_LINK 6
// Command TRBs
#define TRB_ENABLE_SLOT 9
#define TRB_DISABLE_SLOT 10
#define TRB_ADDRESS_DEV 11
#define TRB_CONFIG_EP 12
#define TRB_EVAL_CTX 13
#define TRB_RESET_EP 14
#define TRB_NOOP_CMD 23
// Event TRBs
#define TRB_XFER_EVENT 32
#define TRB_CMD_COMPLETE 33
#define TRB_PORT_STATUS 34
#define TRB_CC(status) (((status) >> 24) & 0xFF)
#define CC_SUCCESS 1
#define CC_SHORT_PACKET 13
// Setup Stage transfer type, and Data Stage direction.
#define TRT_NONE 0
#define TRT_OUT 2
#define TRT_IN 3
#define DIR_IN (1 << 16)
// Endpoint types in an endpoint context. Direction is part of the type, and
// the numbering is not arbitrary: OUT types are 1-3, control is 4, and the IN
// types are the OUT ones plus four.
#define EPTYPE_ISOCH_OUT 1
#define EPTYPE_BULK_OUT 2
#define EPTYPE_INT_OUT 3
#define EPTYPE_CONTROL 4
#define EPTYPE_ISOCH_IN 5
#define EPTYPE_BULK_IN 6
#define EPTYPE_INT_IN 7
// Doorbell targets: 0 is the command ring; for a device slot, DCI 1 is EP0.
#define DCI_EP0 1