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:
commit
d0f7acf9eb
275 changed files with 51417 additions and 0 deletions
21
include/asm.h
Normal file
21
include/asm.h
Normal 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
14
include/buf.h
Normal 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
3
include/config_sinit.h
Normal 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
15
include/date.h
Normal 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
466
include/defs.h
Normal 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
89
include/device.h
Normal 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
56
include/display.h
Normal 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
43
include/dma.h
Normal 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
165
include/e1000.h
Normal 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
35
include/elf.h
Normal 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
60
include/errno.h
Normal 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
95
include/fb.h
Normal 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
43
include/fcntl.h
Normal 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
132
include/file.h
Normal 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
4627
include/font.h
Normal file
File diff suppressed because it is too large
Load diff
203
include/fs.h
Normal file
203
include/fs.h
Normal 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
93
include/input.h
Normal 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
43
include/irq.h
Normal 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
112
include/kbd.h
Normal 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
534
include/logo.h
Normal 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
49
include/memlayout.h
Normal 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
130
include/mmu.h
Normal 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
54
include/mp.h
Normal 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
28
include/param.h
Normal 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
110
include/pci.h
Normal 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
289
include/posix.h
Normal 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
240
include/proc.h
Normal 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
42
include/qr.h
Normal 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
246
include/schfs.h
Normal 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
9
include/sleeplock.h
Normal 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
81
include/socket.h
Normal 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
9
include/spinlock.h
Normal 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
24
include/stat.h
Normal 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
49
include/syscall.h
Normal 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
86
include/text.h
Normal 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
57
include/theme.h
Normal 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
69
include/traps.h
Normal 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
49
include/ttf.h
Normal 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
79
include/types.h
Normal 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
49
include/uaccess.h
Normal 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
270
include/usb.h
Normal 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
117
include/user.h
Normal 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
174
include/virtio.h
Normal 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
219
include/x86.h
Normal 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
161
include/xhci.h
Normal 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
|
||||
Loading…
Reference in a new issue