├── logo.ppm ├── bootstrap.sh ├── images ├── logo.ppm └── screenshot.png ├── include ├── sched.h ├── font.h ├── ppm.h ├── dirent.h ├── timer.h ├── sys │ ├── times.h │ ├── utsname.h │ ├── wait.h │ └── stat.h ├── sos │ ├── limits.h │ └── signal.h ├── spinlock.h ├── sprintf.h ├── stdarg.h ├── devfs.h ├── string.h ├── blkio.h ├── list.h ├── ramfs.h ├── common.h ├── devices.h ├── tty.h ├── ctype.h ├── disk.h ├── types.h ├── memlayout.h ├── isr.h ├── syscall.h ├── elf.h ├── fcntl.h ├── errno.h ├── vector.h ├── mm.h ├── task.h ├── stat.h ├── sys.h ├── lru.h ├── ringbuf.h ├── x86.h ├── graphics.h ├── vm.h ├── display.h ├── ata.h ├── unistd.h ├── boot.h ├── map.h ├── gdt.h ├── mmu.h ├── vfs.h ├── termios.h └── fat32.h ├── kern ├── runtime │ ├── crtn.s │ ├── crti.s │ └── cxx_rt.cc ├── kernel.ld ├── drv │ ├── disk.cc │ ├── devfs.cc │ ├── ata.cc │ └── ramfs.cc ├── core │ ├── spinlock.cc │ ├── context.s │ ├── devices.cc │ ├── common.cc │ ├── irq_stubs.s │ ├── blkio.cc │ ├── timer.cc │ ├── isr.cc │ ├── syscall.cc │ ├── gdt.cc │ ├── graphics.cc │ └── mm.cc ├── utils │ └── ppm.cc └── boot.s ├── user ├── libc │ ├── stdio.h │ ├── stdlib.h │ ├── printf.c │ ├── libc.c │ └── malloc.c ├── echo.c ├── user.ld ├── testsig.c ├── cat.c ├── wc.c ├── grep.c └── ls.c ├── .gitignore ├── grub.cfg ├── lib ├── ctype.cc ├── string.cc └── sprintf.cc ├── LICENSE.md ├── tools └── ramfs_gen.c ├── README.md ├── .ycm_extra_conf.py └── Makefile /logo.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sonald/sos/HEAD/logo.ppm -------------------------------------------------------------------------------- /bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | make && qemu-system-i386 -kernel kernel 4 | -------------------------------------------------------------------------------- /images/logo.ppm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sonald/sos/HEAD/images/logo.ppm -------------------------------------------------------------------------------- /images/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sonald/sos/HEAD/images/screenshot.png -------------------------------------------------------------------------------- /include/sched.h: -------------------------------------------------------------------------------- 1 | #ifndef _SOS_SCHED_H 2 | #define _SOS_SCHED_H 3 | #include "isr.h" 4 | 5 | extern void scheduler(); 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /kern/runtime/crtn.s: -------------------------------------------------------------------------------- 1 | ; crtn 2 | 3 | [section .init] 4 | pop ebp 5 | ret 6 | 7 | [section .fini] 8 | pop ebp 9 | ret 10 | 11 | -------------------------------------------------------------------------------- /kern/runtime/crti.s: -------------------------------------------------------------------------------- 1 | ; crti 2 | [section .init] 3 | global _init 4 | _init: 5 | push ebp 6 | mov ebp, esp 7 | 8 | [section .fini] 9 | global _fini 10 | _fini: 11 | push ebp 12 | mov ebp, esp 13 | 14 | 15 | -------------------------------------------------------------------------------- /user/libc/stdio.h: -------------------------------------------------------------------------------- 1 | #ifndef _SOS_STDIO_H 2 | #define _SOS_STDIO_H 3 | 4 | #include 5 | #include 6 | 7 | int vprintf(const char* fmt, va_list args); 8 | int printf(const char* fmt, ...); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *~ 3 | .*~ 4 | mnt 5 | *.swp 6 | *.pyc 7 | .zcache 8 | objs 9 | kernel 10 | echo 11 | init 12 | initramfs.img 13 | ramfs_gen 14 | *.img 15 | sos.sublime-project 16 | sos.sublime-workspace 17 | tags 18 | TAGS 19 | bin 20 | -------------------------------------------------------------------------------- /include/font.h: -------------------------------------------------------------------------------- 1 | #ifndef _SOS_FONT_H 2 | #define _SOS_FONT_H 3 | 4 | typedef struct font_info_s { 5 | int xadvance, yadvance; 6 | } font_info_t; 7 | 8 | 9 | extern font_info_t builtin_fontinfo; 10 | extern const char* builtin_font[]; 11 | #endif 12 | -------------------------------------------------------------------------------- /include/ppm.h: -------------------------------------------------------------------------------- 1 | #ifndef _SOS_PPM_H 2 | #define _SOS_PPM_H 3 | 4 | typedef struct ppm_s { 5 | char magic[2]; 6 | int width, height; 7 | int max_color; 8 | char data[0]; 9 | } ppm_t; 10 | 11 | ppm_t* ppm_load(const char* path); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /include/dirent.h: -------------------------------------------------------------------------------- 1 | #ifndef _SOS_DIRENT_H 2 | #define _SOS_DIRENT_H 3 | 4 | #include 5 | #include 6 | 7 | struct dirent { 8 | long d_ino; 9 | off_t d_off; 10 | unsigned short d_reclen; 11 | char d_name[NAMELEN+1]; 12 | }; 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /include/timer.h: -------------------------------------------------------------------------------- 1 | #ifndef _TIMER_H 2 | #define _TIMER_H 3 | 4 | #include "common.h" 5 | 6 | #define HZ 100 7 | 8 | void init_timer(); 9 | void busy_wait(int millisecs); 10 | 11 | typedef struct timeout_s timeout_t; 12 | timeout_t* add_timeout(int millisecs); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /include/sys/times.h: -------------------------------------------------------------------------------- 1 | #ifndef _TIMES_H 2 | #define _TIMES_H 3 | 4 | #include 5 | 6 | struct tms { 7 | time_t tms_utime; 8 | time_t tms_stime; 9 | time_t tms_cutime; 10 | time_t tms_cstime; 11 | }; 12 | 13 | extern time_t times(struct tms * tp); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /include/sys/utsname.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYS_UTSNAME_H 2 | #define _SYS_UTSNAME_H 3 | 4 | #include 5 | 6 | struct utsname { 7 | char sysname[9]; 8 | char nodename[9]; 9 | char release[9]; 10 | char version[9]; 11 | char machine[9]; 12 | }; 13 | 14 | extern int uname(struct utsname * utsbuf); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /user/echo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define BUF_SZ 128 5 | char echobuf[128]; 6 | 7 | int main(int argc, char* argv[]) 8 | { 9 | argc--; 10 | argv++; 11 | while (argc-- > 0) { 12 | printf("%s ", *argv++); 13 | } 14 | printf("\n"); 15 | return 0; 16 | } 17 | 18 | 19 | -------------------------------------------------------------------------------- /user/libc/stdlib.h: -------------------------------------------------------------------------------- 1 | #ifndef _SOS_STDLIB_H 2 | #define _SOS_STDLIB_H 3 | 4 | #include 5 | #include 6 | 7 | BEGIN_CDECL 8 | void* calloc(size_t count, size_t size); 9 | void free(void *ptr); 10 | void* malloc(size_t size); 11 | void* realloc(void *ptr, size_t size); 12 | 13 | END_CDECL 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /include/sos/limits.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _SOS_LIMITS_H 3 | #define _SOS_LIMITS_H 4 | 5 | #define NAMELEN 255 6 | #define PATHLEN 1024 7 | #define MAX_NR_FILE 128 // max files to open system-wide 8 | #define FILES_PER_PROC 32 // max filer per task 9 | #define MAX_NR_INODE 1024 10 | #define MAX_NR_DENTRY 1024 11 | #define MAXPROCS 32 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /grub.cfg: -------------------------------------------------------------------------------- 1 | #load_env 2 | insmod part_msdos 3 | set default="0" 4 | 5 | loadfont unicode 6 | set gfxmode=auto 7 | insmod vbe 8 | insmod vga 9 | insmod video_bochs 10 | 11 | insmod gfxterm 12 | terminal_input console 13 | terminal_output gfxterm 14 | set timeout=0 15 | 16 | 17 | menuentry 'SOS' { 18 | insmod part_msdos 19 | set root='hd0,msdos1' 20 | multiboot /kernel 21 | module /initramfs.img 22 | } 23 | -------------------------------------------------------------------------------- /include/spinlock.h: -------------------------------------------------------------------------------- 1 | #ifndef _SOS_SPINLOCK_H 2 | #define _SOS_SPINLOCK_H 3 | 4 | #include "types.h" 5 | 6 | // uniprocess spinlock 7 | class Spinlock { 8 | public: 9 | Spinlock(const char* name): _name(name) {} 10 | uint32_t lock(); 11 | void release(uint32_t oldflags = 0); 12 | bool locked() const; 13 | 14 | private: 15 | uint32_t _locked; 16 | const char* _name; // for debug 17 | }; 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /include/sprintf.h: -------------------------------------------------------------------------------- 1 | #ifndef _SPRINTF_H 2 | #define _SPRINTF_H 3 | 4 | #include "types.h" 5 | #include "stdarg.h" 6 | 7 | char* itoa(int d, char* buf, int base); 8 | char* utoa(u32 u, char* buf, int base); 9 | 10 | int vsprintf(char* sbuf, const char* fmt, va_list args); 11 | int vsnprintf(char* sbuf, size_t len, const char* fmt, va_list args); 12 | 13 | int sprintf(char* buf, const char* fmt, ...); 14 | int snprintf(char* buf, size_t len, const char* fmt, ...); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /user/user.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | OUTPUT_FORMAT(elf32-i386) 3 | 4 | SECTIONS 5 | { 6 | . = 0x08000000; 7 | 8 | .text : 9 | { 10 | *(.text) 11 | *(.rodata) 12 | } 13 | 14 | _etext = .; 15 | 16 | . = ALIGN(0x1000); 17 | 18 | _data = .; 19 | 20 | .data : 21 | { 22 | *(.data) 23 | } 24 | 25 | .bss : 26 | { 27 | *(COMMON) 28 | *(.bss) 29 | } 30 | 31 | _end = .; 32 | } 33 | -------------------------------------------------------------------------------- /include/stdarg.h: -------------------------------------------------------------------------------- 1 | #ifndef _STD_ARG_H 2 | #define _STD_ARG_H 3 | 4 | #define __va_rounded_size(TYPE) \ 5 | (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int)) 6 | 7 | typedef char* va_list; 8 | #define va_start(ap, last) (ap = (((char*)&last) + __va_rounded_size(last))) 9 | #define va_arg(ap, type) ({ \ 10 | type r = *(type*)ap; \ 11 | ap = ap + __va_rounded_size(type); \ 12 | r; \ 13 | }) 14 | 15 | #define va_end(ap) (ap = NULL) 16 | 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /kern/kernel.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | OUTPUT_FORMAT(elf32-i386) 3 | 4 | SECTIONS 5 | { 6 | . = 0xC0100000; 7 | 8 | .text 0xC0100000: AT(ADDR(.text) - 0xC0000000) 9 | { 10 | *(.mboot) 11 | *(.text) 12 | *(.rodata) 13 | } 14 | 15 | . = ALIGN(0x1000); 16 | 17 | _data = .; 18 | 19 | .data : 20 | { 21 | *(.data) 22 | } 23 | 24 | .bss : 25 | { 26 | *(COMMON) 27 | *(.bss) 28 | *(.bootstrap_stack) 29 | } 30 | 31 | _end = .; 32 | } 33 | -------------------------------------------------------------------------------- /include/devfs.h: -------------------------------------------------------------------------------- 1 | #ifndef _SOS_DEVFS_H 2 | #define _SOS_DEVFS_H 3 | 4 | #include 5 | 6 | // should mount at '/dev' now 7 | class DevFs: public FileSystem { 8 | public: 9 | DevFs(): FileSystem() {} 10 | void init(); 11 | dentry_t * lookup(inode_t * dir, dentry_t *) override; 12 | 13 | ssize_t read(File *, char * buf, size_t count, off_t * offset) override; 14 | ssize_t write(File *, const char * buf, size_t, off_t *offset) override; 15 | 16 | private: 17 | int _nodes; 18 | }; 19 | 20 | FileSystem* create_devfs(const void*); 21 | 22 | #endif 23 | 24 | -------------------------------------------------------------------------------- /kern/drv/disk.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void Disk::init(dev_t dev) 6 | { 7 | Buffer* mbr = bio.read(dev, 0); 8 | kassert(mbr); 9 | kassert(mbr->data[0x1fe] == 0x55 && mbr->data[0x1ff] == 0xaa); 10 | memcpy(_parts, &mbr->data[PART_TABLE_OFFSET], sizeof _parts); 11 | bio.release(mbr); 12 | 13 | //kprintf("PARTs: \n"); 14 | //auto* p = &_parts[0]; 15 | //while (p->nr_sects) { 16 | //kprintf("\tstart: 0x%x, sz: 0x%x, b: %d, ty: %s\n", p->lba_start, 17 | //p->nr_sects, p->boot, 18 | //p->part_type == PartType::Fat32L ? "fat32l" 19 | //: (p->part_type == PartType::Linux ? "ext2" : "(X")); 20 | //p++; 21 | //} 22 | } 23 | 24 | -------------------------------------------------------------------------------- /include/string.h: -------------------------------------------------------------------------------- 1 | #ifndef _STRING_H 2 | #define _STRING_H 3 | 4 | #include "types.h" 5 | 6 | void * memcpy(void * dst, const void * src, size_t n); 7 | void* memset(void* dst, int c, size_t count); 8 | void* memmove(void* dst, const void * src, size_t n); 9 | int memcmp(const void *s1, const void * s2, size_t count); 10 | 11 | size_t strlen(const char* s); 12 | char* strcpy(char* dst, const char* src); 13 | char* strncpy(char* dst, const char* src, size_t count); 14 | int strcmp(const char *s1, const char *s2); 15 | int strncmp(const char *s1, const char *s2, size_t n); 16 | char* strncat(char * dst, const char *src, size_t count); 17 | char* strcat(char * dst, const char *src); 18 | 19 | char* strchr(const char *s, int c); 20 | char* strrchr(const char *s, int c); 21 | #endif 22 | -------------------------------------------------------------------------------- /include/sys/wait.h: -------------------------------------------------------------------------------- 1 | #ifndef _SOS_SYS_WAIT_H 2 | #define _SOS_SYS_WAIT_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | 10 | #define WNOHANG 1 11 | #define WUNTRACED 2 12 | 13 | /* A status looks like: 14 | == 0, child has exited, info is the exit value 15 | == 1..7e, child has exited, info is the signal number. 16 | == 7f, child has stopped, info was the signal number. 17 | == 80, there was a core dump. 18 | */ 19 | 20 | #define WIFEXITED(w) (((w) & 0xff) == 0) 21 | #define WIFSIGNALED(w) (((w) & 0x7f) > 0 && (((w) & 0x7f) < 0x7f)) 22 | #define WIFSTOPPED(w) (((w) & 0xff) == 0x7f) 23 | #define WEXITSTATUS(w) (((w) >> 8) & 0xff) 24 | #define WTERMSIG(w) ((w) & 0x7f) 25 | #define WSTOPSIG WEXITSTATUS 26 | 27 | #ifdef __cplusplus 28 | }; 29 | #endif 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /include/blkio.h: -------------------------------------------------------------------------------- 1 | #ifndef _BLKIO_H 2 | #define _BLKIO_H 3 | 4 | #include 5 | 6 | #define NR_BUFFERS 2048 7 | #define BYTES_PER_SECT 512 8 | 9 | typedef uint32_t sector_t; 10 | 11 | enum BufferFlags { 12 | BUF_FULL = 0x01, // loaded from disk 13 | BUF_DIRTY = 0x02, // need to write to disk 14 | BUF_BUSY = 0x04 // hold by a task 15 | }; 16 | 17 | struct Buffer { 18 | sector_t sector; 19 | dev_t dev; 20 | uint8_t flags; 21 | Buffer* next; 22 | Buffer* prev; 23 | Buffer* waitq; 24 | uint8_t data[BYTES_PER_SECT]; 25 | }; 26 | 27 | class BlockIOManager { 28 | public: 29 | void init(); 30 | Buffer* read(dev_t dev, sector_t sect); 31 | bool write(Buffer* bufp); 32 | void release(Buffer* bufp); 33 | 34 | private: 35 | Buffer* _cache; 36 | Buffer* allocBuffer(dev_t dev, sector_t sect); 37 | }; 38 | 39 | extern BlockIOManager bio; 40 | #endif 41 | -------------------------------------------------------------------------------- /include/list.h: -------------------------------------------------------------------------------- 1 | #ifndef _SOS_LIST_H 2 | #define _SOS_LIST_H 3 | 4 | #include "types.h" 5 | 6 | struct list_head 7 | { 8 | struct list_head* prev; 9 | struct list_head* next; 10 | }; 11 | 12 | #define LIST_INIT(lh) \ 13 | struct list_head lh = { &(lh), &(lh) } 14 | 15 | static inline bool list_empty(struct list_head* lh) 16 | { 17 | return lh->next == lh; 18 | } 19 | 20 | static inline void list_add(struct list_head* lh, struct list_head* elem) 21 | { 22 | lh->next->prev = elem; 23 | elem->prev = lh; 24 | elem->next = lh->next; 25 | lh->next = elem; 26 | } 27 | 28 | static inline void list_del(struct list_head* lh) 29 | { 30 | if (!lh || list_empty(lh)) return; 31 | auto* next = lh->next; 32 | auto* prev = lh->prev; 33 | prev->next = next; 34 | next->prev = prev; 35 | lh->next = nullptr; 36 | lh->prev = nullptr; 37 | } 38 | 39 | #define list_entry(ptr, type, member) \ 40 | (type*)((char*)(ptr)-(char*)&((type*)0)->member) 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /include/ramfs.h: -------------------------------------------------------------------------------- 1 | #ifndef _RAMFS_H 2 | #define _RAMFS_H 3 | 4 | #include "types.h" 5 | #include "vfs.h" 6 | 7 | typedef struct initrd_header initrd_header_t; 8 | typedef struct ramfs_mod_info_s { 9 | char* addr; 10 | size_t size; 11 | char* cmdline; 12 | } ramfs_mod_info_t; 13 | 14 | class Ramfs: public FileSystem { 15 | public: 16 | Ramfs(): FileSystem() {} 17 | void init(char* addr, size_t size, const char* cmdline); 18 | dentry_t * lookup(inode_t * dir, dentry_t *) override; 19 | 20 | ssize_t read(File *, char * buf, size_t count, off_t * offset) override; 21 | ssize_t write(File *, const char * buf, size_t, off_t *offset) override; 22 | int readdir(File *, dentry_t *, filldir_t) override; 23 | 24 | private: 25 | inode_t* _nodes; 26 | int _nr_nodes; 27 | initrd_header_t* _sb; 28 | char* _cmdline; 29 | 30 | void read_inode(inode_t *); 31 | }; 32 | 33 | FileSystem* create_ramfs(const void*); 34 | #endif 35 | -------------------------------------------------------------------------------- /include/common.h: -------------------------------------------------------------------------------- 1 | #ifndef _COMMON_H 2 | #define _COMMON_H 3 | 4 | #include 5 | #include 6 | 7 | #if !defined __i386__ 8 | #error "target error, need a cross-compiler with ix86-elf as target" 9 | #endif 10 | 11 | void panic(const char* fmt, ...); 12 | #define kassert(cond) do { \ 13 | if (!(cond)) { \ 14 | kprintf("[%s:%d]: ", __func__, __LINE__); \ 15 | panic("assert " #cond " failed"); \ 16 | } \ 17 | } while(0) 18 | 19 | #define ARRAYLEN(arr) (sizeof(arr)/sizeof(arr[0])) 20 | 21 | static inline int max(int a, int b) 22 | { 23 | return ((a>b)?a:b); 24 | } 25 | 26 | static inline int min(int a, int b) 27 | { 28 | return ((a>b)?b:a); 29 | } 30 | 31 | 32 | 33 | #define SOS_UNUSED __attribute__((unused)) 34 | 35 | void operator delete(void *ptr); 36 | void* operator new(size_t len); 37 | void operator delete[](void *ptr); 38 | void* operator new[](size_t len); 39 | 40 | void kprintf(const char* fmt, ...); 41 | void kvprintf(const char* fmt, va_list args); 42 | 43 | void kputs(const char* msg); 44 | void kputchar(char c); 45 | 46 | #endif 47 | 48 | -------------------------------------------------------------------------------- /kern/core/spinlock.cc: -------------------------------------------------------------------------------- 1 | #include "spinlock.h" 2 | #include "x86.h" 3 | #include "task.h" 4 | 5 | //#define DEBUG_SPINLOCK 6 | 7 | uint32_t Spinlock::lock() 8 | { 9 | auto oldflags = readflags(); 10 | cli(); 11 | #if CONFIG_SMP 12 | while (bts(&_locked) == 1) { 13 | while (_locked) { 14 | asm volatile ("nop; pause"); 15 | } 16 | } 17 | #else 18 | bts(&_locked); 19 | #endif 20 | 21 | #ifdef DEBUG_SPINLOCK 22 | auto old = get_text_color(); 23 | set_text_color(BROWN); 24 | kprintf("[%s:L %s (IF %d)] ", _name, current?current->name:"", 25 | (oldflags&FL_IF)?1:0); 26 | set_text_color(old); 27 | #endif 28 | 29 | return oldflags; 30 | } 31 | 32 | void Spinlock::release(uint32_t oldflags) 33 | { 34 | #ifdef DEBUG_SPINLOCK 35 | auto old = get_text_color(); 36 | set_text_color(BROWN); 37 | kprintf("[%s:R %s (IF %d)] ", _name, current?current->name:"", 38 | (oldflags&FL_IF)?1:0); 39 | set_text_color(old); 40 | #endif 41 | asm volatile ("lock btr $0, %0":"+m"(_locked)); 42 | if (oldflags) writeflags(oldflags); 43 | } 44 | 45 | bool Spinlock::locked() const 46 | { 47 | return _locked > 0; 48 | } 49 | 50 | -------------------------------------------------------------------------------- /include/devices.h: -------------------------------------------------------------------------------- 1 | #ifndef _DEVICES_H 2 | #define _DEVICES_H 3 | 4 | #include "types.h" 5 | #include "blkio.h" 6 | 7 | #define MAJOR(a) (((u32)(a))>>16) 8 | #define MINOR(a) ((a) & 0xFFFF) 9 | #define DEVNO(ma, mi) ((((u32)(ma))<<16) | (((u32)(mi)) & 0xFFFF)) 10 | 11 | enum DeviceType { 12 | TTY_MAJOR = 1, 13 | DEVFS_MAJOR, 14 | RAMFS_MAJOR, 15 | IDE_MAJOR, 16 | FLOPPY_MAJOR, 17 | SCSI_MAJOR, 18 | NULL_MAJOR, 19 | ZERO_MAJOR, 20 | NDEV 21 | }; 22 | 23 | struct BlockDevice 24 | { 25 | dev_t dev; 26 | BlockDevice* prev; 27 | BlockDevice* next; 28 | virtual bool read(Buffer* bufp) = 0; 29 | virtual bool write(Buffer* bufp) = 0; 30 | }; 31 | 32 | struct CharDevice 33 | { 34 | dev_t dev; 35 | CharDevice* prev; 36 | CharDevice* next; 37 | virtual char read() = 0; 38 | virtual bool write(char ch) = 0; 39 | }; 40 | 41 | extern struct BlockDevice* block_devices; 42 | extern struct CharDevice* char_devices; 43 | 44 | void chr_device_register(dev_t dev, CharDevice* chrdev); 45 | void blk_device_register(dev_t dev, BlockDevice* blkdev); 46 | 47 | BlockDevice* blk_device_get(dev_t dev); 48 | CharDevice* chr_device_get(dev_t dev); 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /include/tty.h: -------------------------------------------------------------------------------- 1 | #ifndef _SOS_TTY_H 2 | #define _SOS_TTY_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using TtyBuffer = RingBuffer; 10 | 11 | #define INTR_CHAR(tty) ((tty)->termios.c_cc[VINTR]) 12 | #define QUIT_CHAR(tty) ((tty)->termios.c_cc[VQUIT]) 13 | #define ERASE_CHAR(tty) ((tty)->termios.c_cc[VERASE]) 14 | #define KILL_CHAR(tty) ((tty)->termios.c_cc[VKILL]) 15 | #define WERASE_CHAR(tty) ((tty)->termios.c_cc[VWERASE]) 16 | #define EOF_CHAR(tty) ((tty)->termios.c_cc[VEOF]) 17 | #define START_CHAR(tty) ((tty)->termios.c_cc[VSTART]) 18 | #define STOP_CHAR(tty) ((tty)->termios.c_cc[VSTOP]) 19 | #define SUSPEND_CHAR(tty) ((tty)->termios.c_cc[VSUSP]) 20 | 21 | class TtyDevice: public CharDevice 22 | { 23 | public: 24 | char read() override; 25 | bool write(char ch) override; 26 | 27 | void flush(); 28 | 29 | struct termios termios; 30 | int signaled: 1; 31 | int full_line: 1; 32 | 33 | pid_t pgrp; // foreground process group 34 | TtyBuffer readq; 35 | TtyBuffer writeq; 36 | TtyBuffer secondaryq; 37 | }; 38 | 39 | extern void tty_init(); 40 | extern void tty_thread(); 41 | 42 | #endif // _SOS_TTY_H 43 | -------------------------------------------------------------------------------- /include/ctype.h: -------------------------------------------------------------------------------- 1 | #ifndef _SOS_CTYPE_H 2 | #define _SOS_CTYPE_H 3 | 4 | #define _U 0x01 /* upper */ 5 | #define _L 0x02 /* lower */ 6 | #define _D 0x04 /* digit */ 7 | #define _C 0x08 /* cntrl */ 8 | #define _P 0x10 /* punct */ 9 | #define _S 0x20 /* white space (space/lf/tab) */ 10 | #define _X 0x40 /* hex digit */ 11 | #define _SP 0x80 /* hard space (0x20) */ 12 | 13 | extern unsigned char _ctype[]; 14 | extern char _ctmp; 15 | 16 | #define isalnum(c) ((_ctype+1)[(int)c]&(_U|_L|_D)) 17 | #define isalpha(c) ((_ctype+1)[(int)c]&(_U|_L)) 18 | #define iscntrl(c) ((_ctype+1)[(int)c]&(_C)) 19 | #define isdigit(c) ((_ctype+1)[(int)c]&(_D)) 20 | #define isgraph(c) ((_ctype+1)[(int)c]&(_P|_U|_L|_D)) 21 | #define islower(c) ((_ctype+1)[(int)c]&(_L)) 22 | #define isprint(c) ((_ctype+1)[(int)c]&(_P|_U|_L|_D|_SP)) 23 | #define ispunct(c) ((_ctype+1)[(int)c]&(_P)) 24 | #define isspace(c) ((_ctype+1)[(int)c]&(_S)) 25 | #define isupper(c) ((_ctype+1)[(int)c]&(_U)) 26 | #define isxdigit(c) ((_ctype+1)[(int)c]&(_D|_X)) 27 | 28 | #define isascii(c) (((unsigned) c)<=0x7f) 29 | #define toascii(c) (((unsigned) c)&0x7f) 30 | 31 | #define tolower(c) (_ctmp=c,isupper(_ctmp)?_ctmp-('A'-'a'):_ctmp) 32 | #define toupper(c) (_ctmp=c,islower(_ctmp)?_ctmp-('a'-'A'):_ctmp) 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /lib/ctype.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * linux/lib/ctype.c 3 | * 4 | * Copyright (C) 1991, 1992 Linus Torvalds 5 | */ 6 | 7 | #include 8 | 9 | char _ctmp; 10 | unsigned char _ctype[] = {0x00, /* EOF */ 11 | _C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */ 12 | _C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */ 13 | _C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */ 14 | _C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */ 15 | _S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */ 16 | _P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */ 17 | _D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */ 18 | _D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */ 19 | _P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */ 20 | _U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */ 21 | _U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */ 22 | _U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */ 23 | _P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */ 24 | _L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */ 25 | _L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */ 26 | _L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */ 27 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */ 28 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */ 29 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 160-175 */ 30 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 176-191 */ 31 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 192-207 */ 32 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 208-223 */ 33 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 224-239 */ 34 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* 240-255 */ 35 | 36 | -------------------------------------------------------------------------------- /include/disk.h: -------------------------------------------------------------------------------- 1 | #ifndef _SOS_DISK_H 2 | #define _SOS_DISK_H 3 | 4 | // generic hard disk information 5 | 6 | #include "types.h" 7 | #include "blkio.h" 8 | 9 | #define EXTENDED_PARTITION 5 10 | enum class PartType : uint8_t { 11 | Fat32 = 0x0B, 12 | Fat32L = 0x0C, // WIN95 OSR2 FAT32, LBA-mapped 13 | LinuxSwap = 0x82, 14 | Linux = 0x83 15 | }; 16 | 17 | typedef struct partition_s { 18 | uint8_t boot; /* 0x80 - active */ 19 | uint8_t head; /* starting head */ 20 | uint8_t sector; /* starting sector 21 | * & holds bits 8 and 9 of the cyl */ 22 | uint8_t cyl; /* starting cylinder */ 23 | PartType part_type; /* What partition type */ 24 | uint8_t end_head; /* end head */ 25 | uint8_t end_sector; /* end sector */ 26 | uint8_t end_cyl; /* end cylinder */ 27 | uint32_t lba_start; /* starting sector counting from 0 */ 28 | uint32_t nr_sects; /* nr of sectors in partition */ 29 | } partition_t; 30 | 31 | #define PART_TABLE_OFFSET 446 32 | 33 | // msdos disk 34 | class Disk { 35 | public: 36 | void init(dev_t dev); 37 | int num() const { return _nr_parts; } 38 | const partition_t* part(int idx) const { return &_parts[idx]; } 39 | 40 | private: 41 | partition_t _parts[4]; 42 | int _nr_parts {0}; 43 | }; 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /include/types.h: -------------------------------------------------------------------------------- 1 | #ifndef _TYPES_H 2 | #define _TYPES_H 3 | 4 | #include 5 | #if !defined __cplusplus 6 | #include 7 | #endif 8 | #include 9 | 10 | #if defined __cplusplus 11 | 12 | #define BEGIN_CDECL extern "C" { 13 | #define END_CDECL } 14 | 15 | #else 16 | 17 | #define BEGIN_CDECL 18 | #define END_CDECL 19 | 20 | #endif 21 | 22 | #if !defined uint32_t 23 | typedef unsigned int u32; 24 | typedef int s32; 25 | typedef unsigned short u16; 26 | typedef short s16; 27 | typedef unsigned char u8; 28 | typedef char s8; 29 | #else 30 | typedef uint32_t u32; 31 | typedef int32_t s32; 32 | typedef uint16_t u16; 33 | typedef int16_t s16; 34 | typedef uint8_t u8; 35 | typedef int8_t s8; 36 | #endif 37 | 38 | #ifndef NULL 39 | #define NULL ((void*)0) 40 | #endif 41 | 42 | typedef int pid_t; 43 | typedef unsigned short uid_t; 44 | typedef unsigned short gid_t; 45 | typedef uint32_t dev_t; 46 | typedef unsigned short ino_t; 47 | typedef unsigned short mode_t; 48 | typedef unsigned short umode_t; 49 | typedef unsigned short nlink_t; 50 | typedef int daddr_t; 51 | typedef long off_t; 52 | typedef int64_t loff_t; 53 | typedef unsigned char u_char; 54 | typedef unsigned short ushort; 55 | typedef int ssize_t; 56 | typedef long time_t; 57 | 58 | typedef struct { int quot,rem; } div_t; 59 | typedef struct { long quot,rem; } ldiv_t; 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /include/memlayout.h: -------------------------------------------------------------------------------- 1 | #ifndef _MEM_LAYOUT_H 2 | #define _MEM_LAYOUT_H 3 | 4 | #include "types.h" 5 | // Memory layout 6 | 7 | // Key addresses for address space layout (see kmap in vm.c for layout) 8 | #define KERNEL_VIRTUAL_BASE 0xC0000000 // First kernel virtual address 9 | #define EXTMEM 0x100000 // Start of extended memory 10 | #define PHYSTOP 0x4000000 // physical memory kernel can use at most 11 | 12 | #define KERNTOP (KERNEL_VIRTUAL_BASE+PHYSTOP) 13 | 14 | #define KERNLINK (KERNEL_VIRTUAL_BASE+EXTMEM) // Address where kernel is linked 15 | #define DEVSPACE 0xFE000000 // Other devices are at high addresses 16 | 17 | #define USTACK 0xB0000000 18 | #define USTACK_TOP (USTACK+PGSIZE) 19 | #define UCODE 0x08000000 20 | 21 | /* p2v /v2p is only possible in kernel space, 22 | * since I know the rule of mapping */ 23 | #ifndef __ASSEMBLER__ 24 | // wont used by nasm 25 | static inline u32 v2p(void *a) { return ((u32)a) - KERNEL_VIRTUAL_BASE; } 26 | static inline void *p2v(u32 a) { return (void*)(a + KERNEL_VIRTUAL_BASE); } 27 | #endif 28 | 29 | #define V2P(a) (((u32)(a)) - KERNEL_VIRTUAL_BASE) 30 | #define P2V(a) (((void*)(a)) + KERNEL_VIRTUAL_BASE) 31 | 32 | #define V2P_WO(x) ((x) - KERNEL_VIRTUAL_BASE) // same as V2P, but without casts 33 | #define P2V_WO(x) ((x) + KERNEL_VIRTUAL_BASE) // same as V2P, but without casts 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /kern/core/context.s: -------------------------------------------------------------------------------- 1 | [section .text] 2 | [BITS 32] 3 | 4 | global switch_to_usermode 5 | global flush_tss 6 | global switch_to 7 | 8 | ; parameters: esp, eip 9 | switch_to_usermode: 10 | push ebp 11 | mov ebp, esp 12 | 13 | cli 14 | 15 | mov ax, 0x23 ; GDT entry 4, RPL = 3 16 | mov ds, ax 17 | mov gs, ax 18 | mov es, ax 19 | mov fs, ax 20 | 21 | push 0x23 ;; ss 22 | mov eax, [ebp + 8] 23 | push eax ;; ring3 esp 24 | 25 | pushfd 26 | pop eax 27 | xor eax, 0x200 ;; enable IF 28 | push eax 29 | 30 | push 0x1b ; GDT entry 3, RPL = 3 31 | push dword [ebp + 12] ;; eip 32 | iretd 33 | 34 | cli 35 | hlt ;; never return here 36 | 37 | mov esp, ebp 38 | pop ebp 39 | ret 40 | 41 | 42 | flush_tss: 43 | mov ax, 0x28 44 | ltr ax 45 | ret 46 | 47 | ;; [esp] old ret eip 48 | ;; [esp+4] old addr of kctx 49 | ;; [esp+8] next kctx 50 | switch_to: 51 | mov eax, [esp+4] 52 | mov edx, [esp+8] 53 | 54 | ;; eip is right at esp, no need to push 55 | push ebp 56 | push edi 57 | push esi 58 | push ebx 59 | 60 | mov [eax], esp ;; save kctx at old 61 | mov esp, edx 62 | 63 | pop ebx 64 | pop esi 65 | pop edi 66 | pop ebp 67 | ;; this will return to trap_return if new task is not run before. 68 | ;; else, return to break point in isr 69 | ret 70 | -------------------------------------------------------------------------------- /user/testsig.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | static volatile int quit = 0; 13 | static void signal_handler(int sig) 14 | { 15 | pid_t pid = getpid(); 16 | printf("%s: pid %d, sig %d\n", __func__, pid, sig); 17 | if (sig == SIGUSR1) { 18 | /*kill(pid, SIGUSR2);*/ 19 | } 20 | if (sig == SIGUSR2) 21 | quit = 1; 22 | } 23 | 24 | int main(int argc, char *argv[]) 25 | { 26 | signal(SIGUSR1, (uint32_t)signal_handler); 27 | signal(SIGUSR2, (uint32_t)signal_handler); 28 | 29 | pid_t pid = fork(); 30 | if (pid == 0) { 31 | printf("child(%d): busy loop\n", getpid()); 32 | int count = 0; 33 | while (!quit) { 34 | sleep(1000); 35 | printf("loop %d\n", count++); 36 | sleep(1000); 37 | kill(getppid(), SIGUSR1); 38 | } 39 | 40 | } else if (pid > 0) { 41 | sleep(100); 42 | kill(pid, SIGUSR1); 43 | sigset_t mask = 0; 44 | sigsuspend(&mask); 45 | printf("wake up from suspend\n"); 46 | kill(pid, SIGUSR2); 47 | wait(NULL); 48 | printf("parent(%d) quit\n", getpid()); 49 | } 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /include/isr.h: -------------------------------------------------------------------------------- 1 | #ifndef _ISR_H 2 | #define _ISR_H 3 | 4 | #include "common.h" 5 | #include "gdt.h" 6 | 7 | #define PAGE_FAULT 14 8 | 9 | #define IRQ_OFFSET 32 // offset off ISRs 10 | 11 | #define IRQ0 32 // PIT 12 | #define IRQ_TIMER 32 // PIT 13 | #define IRQ_KBD 33 14 | #define IRQ1 IRQ_KBD 15 | #define IRQ2 34 // slave 16 | #define IRQ3 35 // serial2 17 | #define IRQ4 36 // serial1 18 | #define IRQ5 37 // LPT2 19 | #define IRQ6 38 // floppy 20 | #define IRQ7 39 // LPT1 21 | 22 | #define IRQ8 40 // RTC 23 | #define IRQ9 41 // IRQ2 24 | #define IRQ10 42 // reserve 25 | #define IRQ11 43 // reserve 26 | #define IRQ_MOUSE 44 // PS/2 mouse 27 | #define IRQ12 IRQ_MOUSE 28 | #define IRQ13 45 // FPU 29 | #define IRQ_ATA1 46 // ATA HD1 30 | #define IRQ_ATA2 47 // ATA HD2 31 | 32 | #define ISR_SYSCALL 0x80 33 | 34 | typedef struct trapframe_s { 35 | u32 fs, gs, es, ds; 36 | u32 edi, esi, ebp, esp, ebx, edx, ecx, eax; 37 | u32 isrno, errcode; 38 | // Pushed by the processor automatically. 39 | u32 eip, cs, eflags; 40 | u32 useresp, ss; // exists only when PL switched 41 | } __attribute__((packed)) trapframe_t; 42 | 43 | typedef struct kcontext_s { 44 | u32 ebx, esi, edi, ebp, eip; 45 | } __attribute__((packed)) kcontext_t; 46 | 47 | BEGIN_CDECL 48 | 49 | void isr_handler(trapframe_t* regs); 50 | void irq_handler(trapframe_t* regs); 51 | 52 | END_CDECL 53 | 54 | void picenable(int irq); 55 | 56 | typedef void (*interrupt_handler)(trapframe_t* regs); 57 | void register_isr_handler(int isr, interrupt_handler cb); 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /include/sys/stat.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYS_STAT_H 2 | #define _SYS_STAT_H 3 | 4 | #include 5 | 6 | struct stat { 7 | dev_t st_dev; 8 | ino_t st_ino; 9 | umode_t st_mode; 10 | nlink_t st_nlink; 11 | uid_t st_uid; 12 | gid_t st_gid; 13 | dev_t st_rdev; 14 | off_t st_size; 15 | time_t st_atime; 16 | time_t st_mtime; 17 | time_t st_ctime; 18 | }; 19 | 20 | #define S_IFMT 00170000 21 | #define S_IFREG 0100000 22 | #define S_IFBLK 0060000 23 | #define S_IFDIR 0040000 24 | #define S_IFCHR 0020000 25 | #define S_IFIFO 0010000 26 | #define S_ISUID 0004000 27 | #define S_ISGID 0002000 28 | #define S_ISVTX 0001000 29 | 30 | #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) 31 | #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) 32 | #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) 33 | #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) 34 | #define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) 35 | 36 | #define S_IRWXU 00700 37 | #define S_IRUSR 00400 38 | #define S_IWUSR 00200 39 | #define S_IXUSR 00100 40 | 41 | #define S_IRWXG 00070 42 | #define S_IRGRP 00040 43 | #define S_IWGRP 00020 44 | #define S_IXGRP 00010 45 | 46 | #define S_IRWXO 00007 47 | #define S_IROTH 00004 48 | #define S_IWOTH 00002 49 | #define S_IXOTH 00001 50 | 51 | extern int chmod(const char *_path, mode_t mode); 52 | extern int fstat(int fildes, struct stat *stat_buf); 53 | extern int mkdir(const char *_path, mode_t mode); 54 | extern int mkfifo(const char *_path, mode_t mode); 55 | extern int stat(const char *filename, struct stat *stat_buf); 56 | extern mode_t umask(mode_t mask); 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /include/syscall.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYSCALL_H 2 | #define _SYSCALL_H 3 | 4 | #include 5 | 6 | #define SYS_none 0 7 | #define SYS_fork 1 8 | #define SYS_exit 2 9 | #define SYS_wait 3 10 | #define SYS_pipe 4 11 | #define SYS_read 5 12 | #define SYS_kill 6 13 | #define SYS_exec 7 14 | #define SYS_fstat 8 15 | #define SYS_chdir 9 16 | #define SYS_dup 10 17 | #define SYS_getpid 11 18 | #define SYS_sbrk 12 19 | #define SYS_sleep 13 20 | #define SYS_uptime 14 21 | #define SYS_open 15 22 | #define SYS_write 16 23 | #define SYS_mknod 17 24 | #define SYS_unlink 18 25 | #define SYS_link 19 26 | #define SYS_mkdir 20 27 | #define SYS_close 21 28 | #define SYS_mount 22 29 | #define SYS_umount 23 30 | #define SYS_getppid 24 31 | #define SYS_mmap 25 32 | #define SYS_readdir 26 33 | #define SYS_dup2 27 34 | #define SYS_kdump 28 35 | #define SYS_lseek 29 36 | #define SYS_stat 30 37 | #define SYS_lstat 31 38 | #define SYS_signal 32 39 | #define SYS_sigaction 33 40 | #define SYS_sigpending 34 41 | #define SYS_sigprocmask 35 42 | #define SYS_sigsuspend 36 43 | #define SYS_sigreturn 37 44 | #define SYS_waitpid 38 45 | #define SYS_fchdir 39 46 | #define SYS_getcwd 40 47 | 48 | #define NR_SYSCALL 41 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /include/elf.h: -------------------------------------------------------------------------------- 1 | #ifndef _ELF_H 2 | #define _ELF_H 3 | 4 | #include "types.h" 5 | 6 | #define ELF_MAGIC 0x464C457FU /* "\x7FELF" in little endian */ 7 | 8 | typedef struct elf_header_s { 9 | u32 e_magic; // must equal ELF_MAGIC 10 | u8 e_elf[12]; 11 | u16 e_type; 12 | u16 e_machine; 13 | u32 e_version; 14 | u32 e_entry; 15 | u32 e_phoff; 16 | u32 e_shoff; 17 | u32 e_flags; 18 | u16 e_ehsize; 19 | u16 e_phentsize; 20 | u16 e_phnum; 21 | u16 e_shentsize; 22 | u16 e_shnum; 23 | u16 e_shstrndx; 24 | } elf_header_t; 25 | 26 | typedef struct elf_prog_header_s { 27 | u32 p_type; 28 | u32 p_offset; 29 | u32 p_va; 30 | u32 p_pa; 31 | u32 p_filesz; 32 | u32 p_memsz; 33 | u32 p_flags; 34 | u32 p_align; 35 | } elf_prog_header_t; 36 | 37 | typedef struct elf_section_header_s { 38 | u32 sh_name; 39 | u32 sh_type; 40 | u32 sh_flags; 41 | u32 sh_addr; 42 | u32 sh_offset; 43 | u32 sh_size; 44 | u32 sh_link; 45 | u32 sh_info; 46 | u32 sh_addralign; 47 | u32 sh_entsize; 48 | } elf_section_header_t; 49 | 50 | // Values for Proghdr::p_type 51 | #define ELF_PROG_LOAD 1 52 | 53 | // Flag bits for Proghdr::p_flags 54 | #define ELF_PROG_FLAG_EXEC 1 55 | #define ELF_PROG_FLAG_WRITE 2 56 | #define ELF_PROG_FLAG_READ 4 57 | 58 | // Values for Secthdr::sh_type 59 | #define ELF_SHT_NULL 0 60 | #define ELF_SHT_PROGBITS 1 61 | #define ELF_SHT_SYMTAB 2 62 | #define ELF_SHT_STRTAB 3 63 | 64 | // Values for Secthdr::sh_name 65 | #define ELF_SHN_UNDEF 0 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /kern/core/devices.cc: -------------------------------------------------------------------------------- 1 | #include "devices.h" 2 | #include 3 | 4 | struct BlockDevice* block_devices = nullptr; 5 | struct CharDevice* char_devices = nullptr; 6 | 7 | void chr_device_register(dev_t dev, CharDevice* chrdev) 8 | { 9 | chrdev->dev = dev; 10 | if (!char_devices) { 11 | char_devices = chrdev; 12 | chrdev->next = chrdev; 13 | chrdev->prev = chrdev; 14 | } else { 15 | char_devices->next->prev = chrdev; 16 | chrdev->prev = char_devices; 17 | chrdev->next = char_devices->next; 18 | char_devices->next = chrdev; 19 | } 20 | } 21 | 22 | void blk_device_register(dev_t dev, BlockDevice* blkdev) 23 | { 24 | blkdev->dev = dev; 25 | if (!block_devices) { 26 | block_devices = blkdev; 27 | blkdev->next = blkdev; 28 | blkdev->prev = blkdev; 29 | } else { 30 | block_devices->next->prev = blkdev; 31 | blkdev->prev = block_devices; 32 | blkdev->next = block_devices->next; 33 | block_devices->next = blkdev; 34 | } 35 | } 36 | 37 | BlockDevice* blk_device_get(dev_t dev) 38 | { 39 | if (!block_devices) return nullptr; 40 | auto* p = block_devices; 41 | do { 42 | if (p->dev == dev) return p; 43 | p = p->next; 44 | } while (p != block_devices); 45 | return nullptr; 46 | } 47 | 48 | CharDevice* chr_device_get(dev_t dev) 49 | { 50 | if (!char_devices) return nullptr; 51 | auto* p = char_devices; 52 | do { 53 | if (p->dev == dev) return p; 54 | p = p->next; 55 | } while (p != char_devices); 56 | return nullptr; 57 | } 58 | 59 | -------------------------------------------------------------------------------- /kern/utils/ppm.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | static int atoi(const char* s) 10 | { 11 | int i = 0; 12 | while (*s && isdigit(*s)) { 13 | i = (i * 10) + (*s - '0'); 14 | s++; 15 | } 16 | return i; 17 | } 18 | 19 | ppm_t* ppm_load(const char* path) 20 | { 21 | inode_t* ip = vfs.namei(path); 22 | if (!ip) return NULL; 23 | auto sz = ip->size; 24 | vfs.dealloc_inode(ip); 25 | 26 | char* buf = new char[sz]; 27 | int fd = sys_open(path, O_RDONLY, 0); 28 | if (fd < 0) { 29 | kprintf("open logo failed\n"); 30 | delete buf; 31 | return NULL; 32 | } 33 | 34 | int len = sys_read(fd, buf, sz); 35 | sys_close(fd); 36 | 37 | if (len < 0) { 38 | kprintf("load %s failed\n", path); 39 | delete buf; 40 | return NULL; 41 | } 42 | 43 | ppm_t* ppm = (ppm_t*) vmm.kmalloc(len, 1); 44 | ppm->magic[0] = buf[0]; 45 | ppm->magic[1] = buf[1]; 46 | if (ppm->magic[0] != 'P' && ppm->magic[1] != '6') { 47 | kprintf("wrong magic\n"); 48 | delete buf; 49 | delete ppm; 50 | return NULL; 51 | } 52 | 53 | char* p = buf+3; 54 | ppm->width = atoi(p); 55 | 56 | while (isdigit(*p)) p++; 57 | ppm->height = atoi(++p); 58 | 59 | while (isdigit(*p)) p++; 60 | ppm->max_color = atoi(++p); 61 | while (*p != '\n') p++; 62 | p++; 63 | 64 | len = buf + len - p; 65 | memcpy(ppm->data, p, len); 66 | delete buf; 67 | 68 | return ppm; 69 | } 70 | 71 | -------------------------------------------------------------------------------- /include/fcntl.h: -------------------------------------------------------------------------------- 1 | #ifndef _FCNTL_H 2 | #define _FCNTL_H 3 | 4 | #include "types.h" 5 | 6 | /* open/fcntl - NOCTTY, NDELAY isn't implemented yet */ 7 | #define O_ACCMODE 00003 8 | #define O_RDONLY 00 9 | #define O_WRONLY 01 10 | #define O_RDWR 02 11 | #define O_CREAT 00100 /* not fcntl */ 12 | #define O_EXCL 00200 /* not fcntl */ 13 | #define O_NOCTTY 00400 /* not fcntl */ 14 | #define O_TRUNC 01000 /* not fcntl */ 15 | #define O_APPEND 02000 16 | #define O_NONBLOCK 04000 /* not fcntl */ 17 | #define O_NDELAY O_NONBLOCK 18 | 19 | /* Defines for fcntl-commands. Note that currently 20 | * locking isn't supported, and other things aren't really 21 | * tested. 22 | */ 23 | #define F_DUPFD 0 /* dup */ 24 | #define F_GETFD 1 /* get f_flags */ 25 | #define F_SETFD 2 /* set f_flags */ 26 | #define F_GETFL 3 /* more flags (cloexec) */ 27 | #define F_SETFL 4 28 | #define F_GETLK 5 /* not implemented */ 29 | #define F_SETLK 6 30 | #define F_SETLKW 7 31 | 32 | /* for F_[GET|SET]FL */ 33 | #define FD_CLOEXEC 1 /* actually anything with low bit set goes */ 34 | 35 | /* Ok, these are locking features, and aren't implemented at any 36 | * level. POSIX wants them. 37 | */ 38 | #define F_RDLCK 0 39 | #define F_WRLCK 1 40 | #define F_UNLCK 2 41 | 42 | /* Once again - not implemented, but ... */ 43 | struct flock { 44 | short l_type; 45 | short l_whence; 46 | off_t l_start; 47 | off_t l_len; 48 | pid_t l_pid; 49 | }; 50 | 51 | #ifdef __cplusplus 52 | extern "C" { 53 | #endif 54 | int creat(const char * filename,mode_t mode); 55 | int fcntl(int fildes,int cmd, ...); 56 | int open (const char *path, int flags, int mode); 57 | 58 | #ifdef __cplusplus 59 | } 60 | #endif 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /include/errno.h: -------------------------------------------------------------------------------- 1 | #ifndef _ERRNO_H 2 | #define _ERRNO_H 3 | 4 | /* 5 | * ok, as I hadn't got any other source of information about 6 | * possible error numbers, I was forced to use the same numbers 7 | * as minix. 8 | * Hopefully these are posix or something. I wouldn't know (and posix 9 | * isn't telling me - they want $$$ for their f***ing standard). 10 | * 11 | * We don't use the _SIGN cludge of minix, so kernel returns must 12 | * see to the sign by themselves. 13 | * 14 | * NOTE! Remember to change strerror() if you change this file! 15 | */ 16 | 17 | extern int errno; 18 | 19 | #define ERROR 99 20 | #define EPERM 1 21 | #define ENOENT 2 22 | #define ESRCH 3 23 | #define EINTR 4 24 | #define EIO 5 25 | #define ENXIO 6 26 | #define E2BIG 7 27 | #define ENOEXEC 8 28 | #define EBADF 9 29 | #define ECHILD 10 30 | #define EAGAIN 11 31 | #define ENOMEM 12 32 | #define EACCES 13 33 | #define EFAULT 14 34 | #define ENOTBLK 15 35 | #define EBUSY 16 36 | #define EEXIST 17 37 | #define EXDEV 18 38 | #define ENODEV 19 39 | #define ENOTDIR 20 40 | #define EISDIR 21 41 | #define EINVAL 22 42 | #define ENFILE 23 43 | #define EMFILE 24 44 | #define ENOTTY 25 45 | #define ETXTBSY 26 46 | #define EFBIG 27 47 | #define ENOSPC 28 48 | #define ESPIPE 29 49 | #define EROFS 30 50 | #define EMLINK 31 51 | #define EPIPE 32 52 | #define EDOM 33 53 | #define ERANGE 34 54 | #define EDEADLK 35 55 | #define ENAMETOOLONG 36 56 | #define ENOLCK 37 57 | #define ENOSYS 38 58 | #define ENOTEMPTY 39 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Software License Agreement (BSD License) 2 | ======================================== 3 | 4 | Copyright (c) 2014-2015, Sian Cao . 5 | ---------------------------------------------------- 6 | 7 | Redistribution and use of this software in source and binary forms, with or 8 | without modification, are permitted provided that the following conditions are 9 | met: 10 | 11 | * Redistributions of source code must retain the above copyright notice, this 12 | list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | * Neither the name of Yahoo! Inc. nor the names of YUI's contributors may be 17 | used to endorse or promote products derived from this software without 18 | specific prior written permission of Yahoo! Inc. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 24 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 27 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | -------------------------------------------------------------------------------- /user/cat.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define BUF_LEN 512 8 | #define LINE_LEN 1024 9 | static char buf[BUF_LEN], buf2[20]; 10 | static char line[LINE_LEN]; 11 | static int lp = 0; 12 | 13 | static void print_lino(int no) 14 | { 15 | int len = snprintf(buf2, 19, "%d\t", no); 16 | write(STDOUT_FILENO, buf2, len); 17 | } 18 | 19 | int main(int argc, char* argv[]) 20 | { 21 | int f_lineno = 0; 22 | 23 | const char* filepath = NULL; 24 | if (argc > 1) { 25 | argc--; 26 | argv++; 27 | 28 | for (int i = 0; i < argc; i++) { 29 | auto& av = argv[i]; 30 | if (av[0] && av[0] == '-') { 31 | switch(av[1]) { 32 | case 'n': f_lineno = 1; break; 33 | } 34 | } else filepath = av; 35 | } 36 | } 37 | 38 | int fd = STDIN_FILENO; 39 | if (filepath) fd = open(filepath, O_RDONLY, 0); 40 | if (fd >= 0) { 41 | int len = 0; 42 | int no = 1; 43 | while ((len = read(fd, buf, BUF_LEN)) > 0) { 44 | if (f_lineno) { 45 | int i = 0; 46 | while (i < len) { 47 | line[lp++] = buf[i]; 48 | if (buf[i] == '\n') { 49 | line[lp] = 0; 50 | print_lino(no++); 51 | write(STDOUT_FILENO, line, lp); 52 | lp = 0; 53 | } 54 | i++; 55 | } 56 | 57 | } else write(STDOUT_FILENO, buf, len); 58 | } 59 | 60 | if (f_lineno && lp) { 61 | line[lp] = 0; 62 | print_lino(no++); 63 | write(STDOUT_FILENO, line, lp); 64 | } 65 | if (fd != STDIN_FILENO) close(fd); 66 | } 67 | return 0; 68 | } 69 | 70 | 71 | -------------------------------------------------------------------------------- /user/wc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | struct flags_ { 9 | int word: 1; 10 | int line: 1; 11 | int chr: 1; 12 | } flgs = {0, 0, 0}; 13 | 14 | void wc(int fd, const char* name) 15 | { 16 | int w = 0, c = 0, l = 0; 17 | char* buf = (char*)malloc(128); 18 | int len = 0, inword = 0; 19 | 20 | while ((len = read(fd, buf, 128)) > 0) { 21 | c += len; 22 | for (int i = 0; i < len; i++) { 23 | if (isspace(buf[i])) { 24 | if (buf[i] == '\n') l++; 25 | inword = 0; 26 | } else if (!inword) { 27 | inword = 1; 28 | w++; 29 | } 30 | } 31 | } 32 | 33 | free(buf); 34 | if (flgs.line) printf("%d\t", l); 35 | if (flgs.word) printf("%d\t", w); 36 | if (flgs.chr) printf("%d\t", c); 37 | printf("%s\n", name); 38 | } 39 | 40 | int main(int argc, char *argv[]) 41 | { 42 | int nofile = 1; 43 | for (int i = 1; i < argc; i++) { 44 | if (argv[i][0] == '-') { 45 | char* av = argv[i]; 46 | switch(av[1]) { 47 | case 'l': flgs.line = 1; break; 48 | case 'w': flgs.word = 1; break; 49 | case 'c': flgs.chr = 1; break; 50 | } 51 | } else { 52 | nofile = 0; 53 | if (!flgs.line && !flgs.word && !flgs.chr) { 54 | flgs = {1, 1, 1}; 55 | } 56 | int fd = open(argv[i], O_RDONLY, 0); 57 | if (fd > 0) { 58 | wc(fd, argv[i]); 59 | close(fd); 60 | } 61 | } 62 | } 63 | 64 | if (nofile) { 65 | if (!flgs.line && !flgs.word && !flgs.chr) { 66 | flgs = {1, 1, 1}; 67 | } 68 | wc(0, ""); 69 | } 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /include/vector.h: -------------------------------------------------------------------------------- 1 | #ifndef _SOS_VECTOR_H 2 | #define _SOS_VECTOR_H 3 | 4 | #ifdef _SOS_KERNEL_ 5 | #include 6 | #endif 7 | 8 | #include 9 | 10 | template 11 | class Vector 12 | { 13 | public: 14 | Vector() { 15 | _cap = 16; 16 | _sz = 0; 17 | _buf = new T[_cap]; 18 | } 19 | 20 | ~Vector() { 21 | delete _buf; 22 | } 23 | 24 | void push_back(const T& t) { 25 | if (_sz + 1 == _cap) { 26 | realloc(_cap*2); 27 | } 28 | 29 | _buf[_sz++] = t; 30 | } 31 | 32 | T& operator[](int pos) { 33 | return _buf[pos]; 34 | } 35 | 36 | const T& operator[](int pos) const { 37 | return _buf[pos]; 38 | } 39 | 40 | int size() const { return _sz; } 41 | 42 | T remove(int pos) { 43 | T t; 44 | if (pos >= 0 && pos < _sz) { 45 | t = _buf[pos]; 46 | memmove(_buf+pos, _buf+pos+1, sizeof(T)*(_sz-pos-1)); 47 | _sz--; 48 | } 49 | return t; 50 | } 51 | 52 | void insert(int pos, const T& t) { 53 | if (_sz + 1 >= _cap) realloc(_cap*2); 54 | if (pos >= 0 && pos < _sz) { 55 | memmove(_buf+pos+1, _buf+pos, sizeof(T)*(_sz-pos)); 56 | _sz++; 57 | _buf[pos] = t; 58 | } 59 | } 60 | 61 | void pop_back() { 62 | if (_sz > 0) --_sz; 63 | } 64 | 65 | void clear() { 66 | _sz = 0; 67 | } 68 | 69 | private: 70 | int _cap; 71 | int _sz; 72 | 73 | T* _buf; 74 | 75 | void realloc(int sz) { 76 | auto* newp = new T[sz]; 77 | memcpy(newp, _buf, sizeof(T)*_cap); 78 | delete _buf; 79 | _buf = newp; 80 | _cap = sz; 81 | } 82 | }; 83 | 84 | #endif 85 | 86 | -------------------------------------------------------------------------------- /include/mm.h: -------------------------------------------------------------------------------- 1 | #ifndef _MM_H 2 | #define _MM_H 3 | 4 | #include "mmu.h" 5 | #include "memlayout.h" 6 | 7 | //TODO: no lock for pmm now 8 | //kernel is preemptive, but since no mem allocation occurs in ISRs, 9 | //there is no risk now. need spinlock after support SMP. 10 | class PhysicalMemoryManager { 11 | public: 12 | friend class VirtualMemoryManager; 13 | 14 | static constexpr int frame_size = PGSIZE; //4k 15 | static constexpr u32 invalid = (u32)-1; // invalid frame number 16 | 17 | PhysicalMemoryManager(); 18 | 19 | // if mods loaded, last_used will right after them. else it is NULL, 20 | // which indicated using _end as default 21 | void init(u32 mem_size, void* last_used); 22 | 23 | u32 mem_size() const { return _memSize; } 24 | 25 | /** 26 | * alloc first free frame and return physical address 27 | */ 28 | u32 alloc_frame(); 29 | // alloc first free frame from the end of memory 30 | u32 alloc_frame_tail(); 31 | void free_frame(u32 paddr); 32 | 33 | /** 34 | * alloc first consective size/frame_size of free frames and 35 | * return physical address 36 | */ 37 | u32 alloc_region(u32 size); 38 | void free_region(u32 paddr, u32 size); 39 | 40 | private: 41 | void set_frame(u32 frame_addr); 42 | void clear_frame(u32 frame_addr); 43 | void set_region(u32 frame_addr, u32 size); 44 | void clear_region(u32 frame_addr, u32 size); 45 | int test_frame(u32 frame_addr); 46 | 47 | u32 get_first_free_frame(); 48 | u32 get_last_free_frame(); 49 | u32 get_first_free_region(u32 size); 50 | 51 | private: 52 | u32* _frames; 53 | u32* _framesEnd; 54 | u32 _frameCount; 55 | u32 _frameUsed; 56 | u32 _memSize; // in KB 57 | 58 | u32* _freeStart; 59 | u32* _freeEnd; 60 | }; 61 | 62 | extern PhysicalMemoryManager pmm; 63 | 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /include/task.h: -------------------------------------------------------------------------------- 1 | #ifndef _TASK_H 2 | #define _TASK_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define PROC_NAME_LEN 31 12 | 13 | typedef s32 pid_t; 14 | 15 | enum proc_state { 16 | TASK_UNUSED = 0, 17 | TASK_CREATE, 18 | TASK_READY, 19 | TASK_RUNNING, 20 | TASK_SLEEP, 21 | TASK_ZOMBIE, 22 | }; 23 | 24 | typedef struct address_mapping_s { 25 | void* start; 26 | uint32_t size; 27 | } address_mapping_t; 28 | 29 | typedef struct proc_s { 30 | trapframe_t* regs; 31 | kcontext_t* kctx; 32 | 33 | pid_t pid; 34 | pid_t ppid; 35 | pid_t pgrp; 36 | char name[32]; 37 | 38 | u32 kern_esp; 39 | u32 user_esp; 40 | address_mapping_t mmap[3]; // for code(text), data, stack 41 | u32 data_end; 42 | 43 | u32 heap_end; // current heap brk, intially = end of data 44 | u32 stack_end; // stack end, expanding on-demand 45 | 46 | void* entry; 47 | enum proc_state state; 48 | bool need_resched; 49 | 50 | page_directory_t* pgdir; 51 | 52 | File* files[FILES_PER_PROC]; 53 | inode_t* pwd; 54 | char wdname[PATHLEN+1]; // traced string for current working dir 55 | 56 | void* channel; // sleep on 57 | struct proc_s* next; 58 | struct proc_s* parent; 59 | 60 | struct { 61 | u32 blocked; // block mask 62 | u32 signal; // pending mask 63 | struct sigaction action[32]; 64 | } sig; 65 | 66 | int exit_status, exit_signal; 67 | } proc_t; 68 | 69 | extern proc_t* current; 70 | extern proc_t* task_init; 71 | extern proc_t tasks[MAXPROCS]; 72 | void tasks_init(); 73 | 74 | void sleep(Spinlock* lk, void* chan); 75 | void wakeup(void* chan); 76 | void do_exit(int sig); 77 | 78 | proc_t* prepare_userinit(void* prog); 79 | proc_t* create_proc(void* entry, void* proc, size_t size, const char* name); 80 | 81 | using kthread_t = void (*)(); 82 | proc_t* create_kthread(const char* name, kthread_t prog); 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /include/stat.h: -------------------------------------------------------------------------------- 1 | #ifndef _SOS_STAT_H 2 | #define _SOS_STAT_H 3 | 4 | #include 5 | 6 | struct stat { 7 | dev_t st_dev; /* ID of device containing file */ 8 | ino_t st_ino; /* inode number */ 9 | mode_t st_mode; /* protection */ 10 | nlink_t st_nlink; /* number of hard links */ 11 | uid_t st_uid; /* user ID of owner */ 12 | gid_t st_gid; /* group ID of owner */ 13 | dev_t st_rdev; /* device ID (if special file) */ 14 | off_t st_size; /* total size, in bytes */ 15 | 16 | uint32_t st_atime; 17 | uint32_t st_mtime; 18 | uint32_t st_ctime; 19 | }; 20 | 21 | // this is identical with ext2 mode 22 | // 23 | #define S_IFMT 00170000 24 | #define S_IFSOCK 0140000 25 | #define S_IFLNK 0120000 26 | #define S_IFREG 0100000 27 | #define S_IFBLK 0060000 28 | #define S_IFDIR 0040000 29 | #define S_IFCHR 0020000 30 | #define S_IFIFO 0010000 31 | #define S_ISUID 0004000 32 | #define S_ISGID 0002000 33 | #define S_ISVTX 0001000 34 | 35 | #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) 36 | #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) 37 | #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) 38 | #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) 39 | #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) 40 | #define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) 41 | #define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) 42 | 43 | #define S_IRWXU 00700 44 | #define S_IRUSR 00400 45 | #define S_IWUSR 00200 46 | #define S_IXUSR 00100 47 | 48 | #define S_IRWXG 00070 49 | #define S_IRGRP 00040 50 | #define S_IWGRP 00020 51 | #define S_IXGRP 00010 52 | 53 | #define S_IRWXO 00007 54 | #define S_IROTH 00004 55 | #define S_IWOTH 00002 56 | #define S_IXOTH 00001 57 | 58 | #ifdef _SOS_KERNEL_ 59 | #define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO) 60 | #define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO) 61 | #define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH) 62 | #define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH) 63 | #define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH) 64 | #endif 65 | 66 | #endif 67 | 68 | -------------------------------------------------------------------------------- /include/sys.h: -------------------------------------------------------------------------------- 1 | #ifndef _SOS_SYS_H 2 | #define _SOS_SYS_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | extern int sys_getppid(); 9 | extern int sys_fork(); 10 | extern int sys_sleep(int); 11 | extern int sys_getpid(); 12 | extern int sys_wait(int*); 13 | extern int sys_waitpid(pid_t pid, int *status, int options); 14 | extern int sys_exit(int); 15 | extern int sys_execve(const char *path, char *const argv[], char *const envp[]); 16 | extern int sys_open(const char *path, int flags, int mode); 17 | extern int sys_close(int); 18 | extern int sys_mmap(struct file *, struct vm_area_struct *); 19 | extern int sys_write(int fd, const void *buf, size_t nbyte); 20 | extern int sys_read(int fd, void *buf, size_t nbyte); 21 | extern int sys_readdir(unsigned int fd, struct dirent *dirp, unsigned int count); 22 | extern int sys_mount(const char *, const char *, const char *, unsigned long, const void *); 23 | extern int sys_unmount(const char *target); 24 | extern int sys_dup(int); 25 | extern int sys_dup2(int fd, int fd2); 26 | extern int sys_pipe(int fd[2]); 27 | extern int sys_kdump(); // for debug 28 | extern uint32_t sys_sbrk(int inc); 29 | extern off_t sys_lseek(int fd, off_t offset, int whence); 30 | extern int sys_stat(const char *pathname, struct stat *buf); 31 | extern int sys_fstat(int fd, struct stat *buf); 32 | extern int sys_lstat(const char *pathname, struct stat *buf); 33 | extern int sys_kill(pid_t pid, int sig); 34 | extern int sys_signal(int signum, unsigned long handler); 35 | extern int sys_sigaction(int signum, const struct sigaction * act, 36 | struct sigaction * oldact); 37 | extern int sys_sigpending(sigset_t *set); 38 | extern int sys_sigprocmask(int how, sigset_t *set, sigset_t *oldset); 39 | extern int sys_sigsuspend(sigset_t *sigmask); 40 | //right now, I should take care of it specially cause there is 41 | //no way I can pass a trap frame to a syscall easily. 42 | extern int sys_sigreturn(uint32_t); 43 | extern int sys_chdir(const char *path); 44 | extern int sys_fchdir(int fd); 45 | extern char* sys_getcwd(char *buf, size_t size); 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /user/libc/printf.c: -------------------------------------------------------------------------------- 1 | #include "sprintf.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | static int puts(const char* buf) 8 | { 9 | return write(STDOUT_FILENO, buf, strlen(buf)); 10 | } 11 | 12 | int vprintf(const char* fmt, va_list args) 13 | { 14 | int d = 0; 15 | u32 u = 0; 16 | char* s = NULL; 17 | char c = ' '; 18 | char buf[32]; 19 | int ret = 0; 20 | 21 | while (*fmt) { 22 | char ch = *fmt; 23 | if (ch == '%') { 24 | switch(*++fmt) { 25 | case 'b': case 'B': 26 | d = va_arg(args, int); 27 | ret += puts(itoa(d, buf, 2)); 28 | break; 29 | 30 | case 'x': case 'X': 31 | u = va_arg(args, u32); 32 | ret += puts(utoa(u, buf, 16)); 33 | break; 34 | 35 | case 'd': 36 | d = va_arg(args, int); 37 | ret += puts(itoa(d, buf, 10)); 38 | break; 39 | 40 | case 'u': 41 | u = va_arg(args, u32); 42 | ret += puts(utoa(u, buf, 10)); 43 | break; 44 | 45 | case '%': 46 | ret += puts("%"); 47 | break; 48 | 49 | case 'c': 50 | c = va_arg(args, int); 51 | buf[0] = c; 52 | buf[1] = 0; 53 | ret += puts(buf); 54 | break; 55 | 56 | case 's': 57 | s = va_arg(args, char*); 58 | ret += puts(s?s:"(NULL)"); 59 | break; 60 | 61 | default: 62 | break; 63 | } 64 | } else { 65 | buf[0] = ch; 66 | buf[1] = 0; 67 | ret += puts(buf); 68 | } 69 | fmt++; 70 | } 71 | 72 | return ret; 73 | } 74 | 75 | int printf(const char* fmt, ...) 76 | { 77 | va_list args; 78 | va_start(args, fmt); 79 | int nwrite = vprintf(fmt, args); 80 | va_end(args); 81 | return nwrite; 82 | } 83 | 84 | -------------------------------------------------------------------------------- /kern/core/common.cc: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "sprintf.h" 3 | #include "display.h" 4 | 5 | void kprintf(const char* fmt, ...) 6 | { 7 | va_list args; 8 | va_start(args, fmt); 9 | kvprintf(fmt, args); 10 | va_end(args); 11 | } 12 | 13 | void kvprintf(const char* fmt, va_list args) 14 | { 15 | int d = 0; 16 | u32 u = 0; 17 | char* s = NULL; 18 | char c = ' '; 19 | char buf[32]; 20 | 21 | while (*fmt) { 22 | char ch = *fmt; 23 | if (ch == '%') { 24 | switch(*++fmt) { 25 | case 'b': case 'B': 26 | d = va_arg(args, int); 27 | kputs(itoa(d, buf, 2)); 28 | break; 29 | 30 | case 'x': case 'X': 31 | u = va_arg(args, u32); 32 | kputs(utoa(u, buf, 16)); 33 | break; 34 | 35 | case 'd': 36 | d = va_arg(args, int); 37 | kputs(itoa(d, buf, 10)); 38 | break; 39 | 40 | case 'u': 41 | u = va_arg(args, u32); 42 | kputs(utoa(u, buf, 10)); 43 | break; 44 | 45 | case '%': 46 | kputchar('%'); 47 | break; 48 | 49 | case 'c': 50 | c = va_arg(args, char); 51 | kputchar(c); 52 | break; 53 | 54 | case 's': 55 | s = va_arg(args, char*); 56 | kputs(s?s:"(NULL)"); 57 | break; 58 | 59 | default: 60 | break; 61 | } 62 | } else { 63 | kputchar(ch); 64 | } 65 | fmt++; 66 | } 67 | } 68 | 69 | void kputs(const char* msg) 70 | { 71 | const char* p = msg; 72 | while (*p) { 73 | kputchar(*p); 74 | p++; 75 | } 76 | } 77 | void kputchar(char c) 78 | { 79 | current_display->putchar(c); 80 | } 81 | 82 | void panic(const char* fmt, ...) 83 | { 84 | asm ("cli"); 85 | va_list args; 86 | va_start(args, fmt); 87 | kvprintf(fmt, args); 88 | va_end(args); 89 | for(;;) { 90 | asm volatile ("hlt"); 91 | } 92 | } 93 | 94 | 95 | -------------------------------------------------------------------------------- /user/libc/libc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | _syscall0(pid_t, getpid); 9 | _syscall0(pid_t, getppid); 10 | _syscall0(pid_t, fork); 11 | _syscall3(int, write, int, fd, const void*, buf, size_t, nbyte); 12 | /*_syscall2(int, creat, const char*, filename, mode_t, mode)*/ 13 | /*_syscall2(int, fcntl, int, fildes, int, cmd);*/ 14 | _syscall1(int, chdir, const char *, path); 15 | _syscall1(int, fchdir, int, fd); 16 | 17 | _syscall3(int, open, const char*, path, int, flags, int, mode); 18 | _syscall1(int, close, int, fd); 19 | _syscall3(int, read, int, fildes, void*, buf, size_t, nbyte); 20 | _syscall3(int, exec, const char*, path, char *const*, argv, char *const*, envp); 21 | _syscall1(int, sleep, int, millisecs); 22 | _syscall1(int, exit, int, status); 23 | _syscall1(pid_t, wait, int *, status); 24 | _syscall3(pid_t, waitpid, pid_t, pid, int *, status, int, options); 25 | _syscall3(int, readdir, unsigned int, fd, struct dirent *, dirp, unsigned int, count); 26 | _syscall1(int, dup, int, fd); 27 | _syscall2(int, dup2, int, fd, int, fd2); 28 | _syscall1(int, pipe, int*, fds); // int fd[2] 29 | _syscall0(int, kdump); 30 | _syscall1(void*, sbrk, int, inc); 31 | _syscall3(off_t, lseek, int, fd, off_t, offset, int, whence); 32 | _syscall2(int, stat, const char *, pathname, struct stat *, buf); 33 | _syscall2(int, fstat, int, fd, struct stat *, buf); 34 | _syscall2(int, lstat, const char *, pathname, struct stat *, buf); 35 | _syscall2(int, kill, pid_t, pid, int, sig); 36 | _syscall2(int, signal, int, signum, unsigned long, handler); 37 | _syscall1(int, sigpending, sigset_t *, set); 38 | _syscall3(int, sigprocmask, int, how, sigset_t*, set, sigset_t*, oldset); 39 | _syscall1(int, sigsuspend, sigset_t*, sigmask); 40 | _syscall2(char*, getcwd, char *, buf, size_t, size); 41 | 42 | int execve(const char *path, char *const argv[], char *const envp[]) 43 | { 44 | return exec(path, argv, envp); 45 | } 46 | 47 | extern int main(int argc, char* argv[]); 48 | 49 | extern void _init(); 50 | extern void _fini(); 51 | extern void __cxa_finalize(void * d); 52 | 53 | void _start(int argc, char* argv[]) 54 | { 55 | _init(); 56 | int ret = main(argc, argv); 57 | _fini(); 58 | __cxa_finalize(NULL); 59 | exit(ret); 60 | } 61 | 62 | #ifdef __cplusplus 63 | } 64 | #endif 65 | 66 | -------------------------------------------------------------------------------- /include/lru.h: -------------------------------------------------------------------------------- 1 | #ifndef _SOS_LRU_H 2 | #define _SOS_LRU_H 3 | 4 | #include 5 | 6 | // generic LRU cache 7 | 8 | template , class Eq = KeyEqual> 9 | class LRUCache { 10 | public: 11 | LRUCache(int cap = 16): _cap{cap} { 12 | _l.prev = &_l; 13 | _l.next = &_l; 14 | } 15 | 16 | ~LRUCache() { 17 | Node* p = _l.next; 18 | while (p != &_l) { 19 | auto* d = p; 20 | p = p->next; 21 | delete d; 22 | } 23 | } 24 | 25 | V first() { 26 | if (_h.size() > 0) return _l.next->v; 27 | return V(); 28 | } 29 | 30 | size_t size() const { return _h.size(); } 31 | 32 | bool has(const K& k) const { return _h.contains(k); } 33 | 34 | V get(const K& k) { 35 | if (!_h.contains(k)) return V(); 36 | 37 | promote(k); 38 | return _h.find(k)->v; 39 | } 40 | 41 | void set(const K& k, const V& v) { 42 | Node* n = NULL; 43 | if (_h.contains(k)) { 44 | promote(k); 45 | Node* p = _h.find(k); 46 | p->v = v; 47 | return; 48 | } 49 | 50 | if (_h.size() == _cap) { 51 | Node* last = _l.prev; 52 | _h.erase(last->k); 53 | last->next->prev = last->prev; 54 | last->prev->next = last->next; 55 | n = last; 56 | } else n = new Node; 57 | 58 | n->k = k; 59 | n->v = v; 60 | 61 | _h.insert(k, n); 62 | n->next = _l.next; 63 | n->prev = &_l; 64 | _l.next->prev = n; 65 | _l.next = n; 66 | } 67 | 68 | private: 69 | struct Node { 70 | K k; 71 | V v; 72 | struct Node* next, *prev; 73 | }; 74 | 75 | int _cap; // capacity 76 | HashMap _h; 77 | Node _l {K(), V(), NULL, NULL}; 78 | 79 | void promote(const K& k) { 80 | Node* p = _h.find(k); 81 | p->prev->next = p->next; 82 | p->next->prev = p->prev; 83 | 84 | p->next = _l.next; 85 | p->prev = &_l; 86 | _l.next->prev = p; 87 | _l.next = p; 88 | } 89 | }; 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /include/ringbuf.h: -------------------------------------------------------------------------------- 1 | #ifndef _SOS_LIB_RINGBUF_H 2 | #define _SOS_LIB_RINGBUF_H 3 | 4 | #include "types.h" 5 | #include "common.h" 6 | #include "spinlock.h" 7 | 8 | template 9 | class RingBuffer 10 | { 11 | public: 12 | T read(); 13 | void write(const T& v); 14 | 15 | bool full() const { return _used == _sz; } 16 | bool empty() const { return _used == 0; } 17 | int sz() const { return _sz; } 18 | int remain() const { return _sz - _used; } 19 | 20 | void clear(); 21 | T peek(); 22 | T last(); 23 | T drop(); // remove last input if any 24 | 25 | private: 26 | T _buf[N]; 27 | size_t _h {0}, _t {0}; 28 | size_t _used {0}, _sz {N}; 29 | Spinlock _lock {"ringbuf"}; 30 | }; 31 | 32 | template 33 | T RingBuffer::read() 34 | { 35 | auto eflags = _lock.lock(); 36 | if (empty()) return T(); 37 | 38 | T& v = _buf[_t]; 39 | _t = (_t + 1) % N; 40 | _used--; 41 | _lock.release(eflags); 42 | return v; 43 | } 44 | 45 | template 46 | T RingBuffer::last() 47 | { 48 | auto eflags = _lock.lock(); 49 | if (empty()) return T(); 50 | 51 | T& v = _buf[_h]; 52 | _lock.release(eflags); 53 | return v; 54 | } 55 | 56 | template 57 | T RingBuffer::peek() 58 | { 59 | auto eflags = _lock.lock(); 60 | if (empty()) return T(); 61 | T& v = _buf[_t]; 62 | _lock.release(eflags); 63 | return v; 64 | } 65 | 66 | template 67 | void RingBuffer::write(const T& v) 68 | { 69 | auto eflags = _lock.lock(); 70 | if (full()) { read(); } // eat oldest 71 | 72 | _buf[_h] = v; 73 | _h = (_h + 1) % N; 74 | _used++; 75 | _lock.release(eflags); 76 | } 77 | 78 | template 79 | T RingBuffer::drop() 80 | { 81 | auto eflags = _lock.lock(); 82 | if (empty()) return T(); 83 | 84 | _h--; 85 | if (_h < 0) _h = N-1; 86 | T& v = _buf[_h]; 87 | _used--; 88 | _lock.release(eflags); 89 | return v; 90 | } 91 | 92 | template 93 | void RingBuffer::clear() 94 | { 95 | auto eflags = _lock.lock(); 96 | _h = _t = 0; 97 | _sz = N; 98 | _used = 0; 99 | _lock.release(eflags); 100 | } 101 | #endif 102 | 103 | -------------------------------------------------------------------------------- /include/x86.h: -------------------------------------------------------------------------------- 1 | #ifndef _X86_H 2 | #define _X86_H 3 | 4 | #include "types.h" 5 | 6 | static inline void sti() { asm volatile ("sti":::"cc"); } 7 | static inline void cli() { asm volatile ("cli":::"cc"); } 8 | 9 | // port io 10 | static inline void outb(u16 port, u8 val) 11 | { 12 | __asm__ __volatile__ ( "outb %1, %0" : : "dN"(port), "a"(val)); 13 | } 14 | 15 | static inline u8 inb(u16 port) 16 | { 17 | u8 val; 18 | __asm__ __volatile__ ( "inb %1, %0" : "=a"(val) : "dN"(port)); 19 | return val; 20 | } 21 | 22 | static inline u16 inw(u16 port) 23 | { 24 | u16 val; 25 | __asm__ __volatile__ ( "inw %1, %0" : "=a"(val) : "dN"(port)); 26 | return val; 27 | } 28 | 29 | // Eflags register 30 | #define FL_CF 0x00000001 // Carry Flag 31 | #define FL_PF 0x00000004 // Parity Flag 32 | #define FL_AF 0x00000010 // Auxiliary carry Flag 33 | #define FL_ZF 0x00000040 // Zero Flag 34 | #define FL_SF 0x00000080 // Sign Flag 35 | #define FL_TF 0x00000100 // Trap Flag 36 | #define FL_IF 0x00000200 // Interrupt Enable 37 | #define FL_DF 0x00000400 // Direction Flag 38 | #define FL_OF 0x00000800 // Overflow Flag 39 | #define FL_IOPL_MASK 0x00003000 // I/O Privilege Level bitmask 40 | #define FL_IOPL_0 0x00000000 // IOPL == 0 41 | #define FL_IOPL_1 0x00001000 // IOPL == 1 42 | #define FL_IOPL_2 0x00002000 // IOPL == 2 43 | #define FL_IOPL_3 0x00003000 // IOPL == 3 44 | #define FL_NT 0x00004000 // Nested Task 45 | #define FL_RF 0x00010000 // Resume Flag 46 | #define FL_VM 0x00020000 // Virtual 8086 mode 47 | #define FL_AC 0x00040000 // Alignment Check 48 | #define FL_VIF 0x00080000 // Virtual Interrupt Flag 49 | #define FL_VIP 0x00100000 // Virtual Interrupt Pending 50 | #define FL_ID 0x00200000 // ID flag 51 | 52 | static inline uint32_t readflags() { 53 | uint32_t old; 54 | asm volatile ("pushfl; popl %0":"=r"(old)::"memory"); 55 | return old; 56 | } 57 | 58 | static inline void writeflags(uint32_t flags) { 59 | asm volatile ("pushl %0; popfl"::"r"(flags):"memory", "cc"); 60 | } 61 | 62 | static inline int bts(uint32_t* val) { 63 | int ret = 0; 64 | asm volatile ("lock bts $0, %1 \n" 65 | "jnc 1f \n" 66 | "movl $1, %0 \n" 67 | "1: " 68 | :"=m"(ret):"m"(*val) :"memory", "cc"); 69 | return ret; 70 | } 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /tools/ramfs_gen.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define MAXFILES 64 8 | #define NAMELEN 255 9 | struct initrd_entry_header 10 | { 11 | unsigned char magic; // The magic number is there to check for consistency. 12 | char name[NAMELEN+1]; 13 | int32_t offset; // Offset in the initrd the file starts. 14 | int32_t length; // Length of the file. 15 | }__attribute__((packed)); 16 | 17 | // ramfs don't support subdir, so change '/' into '_' 18 | static char* sanitize_name(const char* name) 19 | { 20 | int n = strlen(name); 21 | char* s = malloc(n+1); 22 | for (int i = 0; i < n; i++) { 23 | s[i] = name[i] == '/' ? '_': name[i]; 24 | } 25 | s[n] = 0; 26 | return s; 27 | } 28 | 29 | int main(int argc, char **argv) 30 | { 31 | int nheaders = (argc-1); 32 | struct initrd_entry_header headers[MAXFILES]; 33 | memset(headers, 0, sizeof(headers)); 34 | if (nheaders > MAXFILES) nheaders = MAXFILES; 35 | 36 | printf("size of header: %lu\n", sizeof(struct initrd_entry_header)); 37 | unsigned int off = sizeof(struct initrd_entry_header) * MAXFILES + sizeof(int); 38 | int i; 39 | for(i = 1; i <= nheaders; i++) { 40 | printf("writing file %s at 0x%x\n", argv[i], off); 41 | char* filename = sanitize_name(argv[i]); 42 | strncpy(headers[i-1].name, filename, NAMELEN+1); 43 | free(filename); 44 | 45 | headers[i-1].offset = off; 46 | FILE *stream = fopen(argv[i], "r"); 47 | if(stream == 0) { 48 | printf("Error: file not found: %s\n", argv[i]); 49 | return 1; 50 | } 51 | 52 | fseek(stream, 0, SEEK_END); 53 | headers[i-1].length = ftell(stream); 54 | off += headers[i-1].length; 55 | fclose(stream); 56 | headers[i-1].magic = 0xBF; 57 | } 58 | 59 | FILE *wstream = fopen("./initramfs.img", "w"); 60 | unsigned char *data = (unsigned char *)malloc(off); 61 | fwrite(&nheaders, sizeof(int), 1, wstream); 62 | fwrite(headers, sizeof(struct initrd_entry_header), MAXFILES, wstream); 63 | 64 | for(i = 0; i < nheaders; i++) { 65 | FILE *stream = fopen(argv[i+1], "r"); 66 | unsigned char *buf = (unsigned char *)malloc(headers[i].length); 67 | fread(buf, 1, headers[i].length, stream); 68 | fwrite(buf, 1, headers[i].length, wstream); 69 | fclose(stream); 70 | free(buf); 71 | } 72 | 73 | fclose(wstream); 74 | free(data); 75 | 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /kern/core/irq_stubs.s: -------------------------------------------------------------------------------- 1 | [BITS 32] 2 | global gdt_flush 3 | global idt_flush 4 | global trap_return 5 | 6 | extern isr_handler 7 | extern irq_handler 8 | 9 | gdt_flush: 10 | mov eax, [esp+4] 11 | lgdt [eax] 12 | 13 | mov ax, 0x10 14 | mov ds, ax 15 | mov gs, ax 16 | mov fs, ax 17 | mov es, ax 18 | jmp 0x08:.flush ; jump to new code selector 19 | .flush: 20 | ret 21 | 22 | idt_flush: 23 | mov eax, [esp+4] 24 | lidt [eax] 25 | ret 26 | 27 | %macro isr_noerrcode 1 28 | global isr%1 29 | isr%1: 30 | push 0 31 | push %1 32 | jmp isr_stub 33 | %endmacro 34 | 35 | %macro isr_errcode 1 36 | global isr%1 37 | isr%1: 38 | push %1 39 | jmp isr_stub 40 | %endmacro 41 | 42 | %macro def_irq 2 43 | global irq%1 44 | irq%1: 45 | push 0 46 | push %2 47 | jmp irq_stub 48 | %endmacro 49 | 50 | %macro handler_stub 2 51 | %1: 52 | pusha ; this will do pushad 53 | push ds 54 | push es 55 | push gs 56 | push fs 57 | 58 | mov ax, 0x10 59 | mov ds, ax 60 | mov es, ax 61 | mov gs, ax 62 | mov fs, ax 63 | 64 | push esp 65 | call %2 66 | add esp, 4 67 | 68 | jmp trap_return 69 | %endmacro 70 | 71 | trap_return: 72 | pop fs 73 | pop gs 74 | pop es 75 | pop ds 76 | popa 77 | add esp, 8 78 | iret 79 | 80 | isr_noerrcode 0 81 | isr_noerrcode 1 82 | isr_noerrcode 2 83 | isr_noerrcode 3 84 | isr_noerrcode 4 85 | isr_noerrcode 5 86 | isr_noerrcode 6 87 | isr_noerrcode 7 88 | isr_errcode 8 89 | isr_noerrcode 9 90 | isr_errcode 10 91 | isr_errcode 11 92 | isr_errcode 12 93 | isr_errcode 13 94 | isr_errcode 14 95 | isr_noerrcode 15 96 | isr_noerrcode 16 97 | isr_noerrcode 17 98 | isr_noerrcode 18 99 | isr_noerrcode 19 100 | isr_noerrcode 20 101 | isr_noerrcode 21 102 | isr_noerrcode 22 103 | isr_noerrcode 23 104 | isr_noerrcode 24 105 | isr_noerrcode 25 106 | isr_noerrcode 26 107 | isr_noerrcode 27 108 | isr_noerrcode 28 109 | isr_noerrcode 29 110 | isr_noerrcode 30 111 | isr_noerrcode 31 112 | 113 | isr_noerrcode 128 114 | 115 | handler_stub isr_stub, isr_handler 116 | 117 | ; master PIC 118 | def_irq 0, 32 119 | def_irq 1, 33 120 | def_irq 2, 34 121 | def_irq 3, 35 122 | def_irq 4, 36 123 | def_irq 5, 37 124 | def_irq 6, 38 125 | def_irq 7, 39 126 | ; slave PIC 127 | def_irq 8, 40 128 | def_irq 9, 41 129 | def_irq 10, 42 130 | def_irq 11, 43 131 | def_irq 12, 44 132 | def_irq 13, 45 133 | def_irq 14, 46 134 | def_irq 15, 47 135 | 136 | handler_stub irq_stub, irq_handler 137 | -------------------------------------------------------------------------------- /kern/core/blkio.cc: -------------------------------------------------------------------------------- 1 | #include "x86.h" 2 | #include "blkio.h" 3 | #include "string.h" 4 | #include "devices.h" 5 | #include "task.h" 6 | #include "sched.h" 7 | #include "spinlock.h" 8 | 9 | BlockIOManager bio; 10 | Buffer* waitq = nullptr; 11 | Spinlock biolock("bio"); 12 | 13 | void BlockIOManager::init() 14 | { 15 | _cache = (Buffer*)vmm.kmalloc(sizeof(Buffer) * NR_BUFFERS, 1); 16 | memset(_cache, 0, sizeof(Buffer) * NR_BUFFERS); 17 | Buffer& p = _cache[0]; 18 | p.next = &p; 19 | p.prev = &p; 20 | for (int i = 1; i prev = &q; 26 | q.prev = &p; 27 | } 28 | } 29 | 30 | Buffer* BlockIOManager::allocBuffer(dev_t dev, sector_t sect) 31 | { 32 | auto oldflags = biolock.lock(); 33 | recheck: 34 | for (int i = 0; i < NR_BUFFERS; i++) { 35 | if (_cache[i].dev == dev && _cache[i].sector == sect) { 36 | if (!(_cache[i].flags & BUF_BUSY)) { 37 | _cache[i].flags |= BUF_BUSY; 38 | //kprintf(" (BIO:reget) "); 39 | biolock.release(oldflags); 40 | if (oldflags & FL_IF) sti(); 41 | return &_cache[i]; 42 | } 43 | 44 | sleep(&biolock, &_cache[i]); 45 | goto recheck; 46 | } 47 | } 48 | 49 | for (int i = 0; i < NR_BUFFERS; i++) { 50 | Buffer* bp = &_cache[i]; 51 | if ((bp->flags & BUF_BUSY) == 0 && (bp->flags & BUF_DIRTY) == 0) { 52 | bp->dev = dev; 53 | bp->sector = sect; 54 | bp->flags = BUF_BUSY | ~BUF_FULL; 55 | biolock.release(oldflags); 56 | return bp; 57 | } 58 | } 59 | 60 | panic("no buffer avail\n"); 61 | return nullptr; 62 | } 63 | 64 | Buffer* BlockIOManager::read(dev_t dev, sector_t sect) 65 | { 66 | dev_t rdev = DEVNO(MAJOR(dev), 0); 67 | Buffer* bp = allocBuffer(rdev, sect); 68 | if (bp->flags & BUF_FULL) { 69 | return bp; 70 | } 71 | auto* device = blk_device_get(rdev); 72 | kassert(device != nullptr); 73 | device->read(bp); 74 | bp->flags |= BUF_FULL; 75 | return bp; 76 | } 77 | 78 | bool BlockIOManager::write(Buffer* bufp) 79 | { 80 | (void)bufp; 81 | return false; 82 | } 83 | 84 | void BlockIOManager::release(Buffer* bufp) 85 | { 86 | auto oldflags = biolock.lock(); 87 | //kprintf("[BIO: %s release] ", current->name); 88 | kassert(bufp && (bufp->flags & BUF_BUSY)); 89 | bufp->flags &= ~BUF_BUSY; 90 | wakeup(bufp); 91 | biolock.release(oldflags); 92 | } 93 | 94 | -------------------------------------------------------------------------------- /user/grep.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define BUF_LEN 128 9 | #define LINE_LEN 1024 10 | static int lp = 0; 11 | 12 | static int match_here(const char* re, const char* s); 13 | 14 | static int match_star(const char* re, const char* s) 15 | { 16 | int c = re[0]; 17 | do { 18 | if (match_here(re+2, s)) return 1; 19 | } while (*s && (c == *s++ || c == '.')); 20 | return 0; 21 | } 22 | 23 | static int match_here(const char* re, const char* s) 24 | { 25 | if (!*re) return 1; 26 | else if (!*s) return 0; 27 | 28 | if (re[1] == '*') { 29 | return match_star(re, s); 30 | } else if (*re == '$' && re[1] == 0) { 31 | return *s == 0; 32 | } else { 33 | if (*re == '.' || *s == *re) { 34 | return match_here(re+1, s+1); 35 | } 36 | } 37 | 38 | return 0; 39 | } 40 | 41 | // re is regex: only . and * supported 42 | static int match(const char* re, const char* s) 43 | { 44 | if (*re == '^') return match_here(re+1, s); 45 | 46 | while (*s) { 47 | if (match_here(re, s)) return 1; 48 | s++; 49 | } 50 | return 0; 51 | } 52 | 53 | //grep re [file] 54 | int main(int argc, char* argv[]) 55 | { 56 | char* line = (char*)malloc(LINE_LEN); 57 | char* buf = (char*)malloc(BUF_LEN); 58 | 59 | int no = 1; 60 | 61 | const char* filepath = NULL, *re = NULL; 62 | if (argc > 1) { 63 | re = argv[1]; 64 | if (argc > 2) filepath = argv[2]; 65 | } else { 66 | printf("usage: grep re file ...\n"); 67 | } 68 | 69 | int fd = STDIN_FILENO; 70 | if (filepath) fd = open(filepath, O_RDONLY, 0); 71 | if (fd >= 0) { 72 | int len = 0; 73 | while ((len = read(fd, buf, sizeof buf - 1)) > 0) { 74 | buf[len] = 0; 75 | int i = 0; 76 | while (i < len) { 77 | line[lp++] = buf[i]; 78 | if (buf[i] == '\n') { 79 | line[lp] = 0; 80 | if (match(re, line)) { 81 | printf("%d: %s", no, line); 82 | } 83 | no++; 84 | lp = 0; 85 | } 86 | i++; 87 | } 88 | } 89 | 90 | if (lp) { 91 | line[lp] = 0; 92 | if (match(re, line)) 93 | write(STDOUT_FILENO, line, lp); 94 | } 95 | if (fd != STDIN_FILENO) close(fd); 96 | } 97 | 98 | free(line); 99 | free(buf); 100 | return 0; 101 | } 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /kern/runtime/cxx_rt.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * c++ runtime 3 | * http://wiki.osdev.org/C%2B%2B 4 | */ 5 | 6 | #ifdef _SOS_KERNEL_ 7 | #include "common.h" 8 | #include "vm.h" 9 | #else 10 | #include 11 | #include 12 | #endif 13 | 14 | #define MAX_ATEXIT_ENTRIES 128 15 | 16 | //TODO: in user-space this should throw error 17 | extern "C" void __cxa_pure_virtual() 18 | { 19 | // do nothing 20 | } 21 | 22 | struct cxa_ref_s 23 | { 24 | void (*f)(void*); 25 | void* arg; 26 | void* dso; 27 | }; 28 | 29 | cxa_ref_s refs[MAX_ATEXIT_ENTRIES]; 30 | int refs_len = 0; 31 | 32 | extern "C" int __cxa_atexit(void (*func) (void *), void * arg, void * dso_handle) 33 | { 34 | if (refs_len >= MAX_ATEXIT_ENTRIES) return -1; 35 | refs[refs_len].f = func; 36 | refs[refs_len].arg = arg; 37 | refs[refs_len++].dso = dso_handle; 38 | 39 | return 0; 40 | } 41 | 42 | extern "C" void __cxa_finalize(void * d) 43 | { 44 | if (!d) { 45 | for (int i = refs_len-1; i >= 0; --i) { 46 | if (refs[i].f) 47 | refs[i].f(refs[i].arg); 48 | } 49 | return; 50 | } 51 | 52 | // else 53 | for (int i = refs_len-1; i >= 0; --i) { 54 | if (refs[i].f == d) { 55 | refs[i].f(refs[i].arg); 56 | refs[i].f = NULL; 57 | } 58 | } 59 | } 60 | 61 | // not thread safe 62 | // should add a mutex-like guard with a test-and-set primitive. 63 | namespace __cxxabiv1 64 | { 65 | /* guard variables */ 66 | 67 | /* The ABI requires a 64-bit type. */ 68 | __extension__ typedef int __guard __attribute__((mode(__DI__))); 69 | 70 | extern "C" int __cxa_guard_acquire (__guard *g) 71 | { 72 | return !*(char *)(g); 73 | } 74 | 75 | extern "C" void __cxa_guard_release (__guard *g) 76 | { 77 | *(char *)g = 1; 78 | } 79 | 80 | extern "C" void __cxa_guard_abort (__guard *) 81 | { 82 | 83 | } 84 | } 85 | 86 | 87 | #ifdef _SOS_KERNEL_ 88 | void operator delete(void *ptr) 89 | { 90 | vmm.kfree(ptr); 91 | } 92 | 93 | void* operator new(size_t len) 94 | { 95 | return vmm.kmalloc(len, 1); 96 | } 97 | 98 | void operator delete[](void *ptr) 99 | { 100 | ::operator delete(ptr); 101 | } 102 | 103 | void* operator new[](size_t len) 104 | { 105 | return ::operator new(len); 106 | } 107 | 108 | #else 109 | void operator delete(void *ptr) 110 | { 111 | free(ptr); 112 | } 113 | 114 | void* operator new(size_t len) 115 | { 116 | return malloc(len); 117 | } 118 | 119 | void operator delete[](void *ptr) 120 | { 121 | ::operator delete(ptr); 122 | } 123 | 124 | void* operator new[](size_t len) 125 | { 126 | return ::operator new(len); 127 | } 128 | #endif 129 | 130 | -------------------------------------------------------------------------------- /include/graphics.h: -------------------------------------------------------------------------------- 1 | #ifndef _SOS_GRAPHICS_H 2 | #define _SOS_GRAPHICS_H 3 | 4 | #include "types.h" 5 | 6 | typedef struct VbeInfoBlock_s { 7 | char VbeSignature[4]; // == "VESA" 8 | uint16_t VbeVersion; // == 0x0300 for VBE 3.0 9 | uint16_t OemStringPtr[2]; // isa vbeFarPtr 10 | uint8_t Capabilities[4]; 11 | uint16_t VideoModePtr[2]; // isa vbeFarPtr 12 | uint16_t TotalMemory; // as # of 64KB blocks 13 | } __attribute__((packed)) VbeInfoBlock_t; 14 | 15 | typedef struct ModeInfoBlock_s { 16 | uint16_t attributes; 17 | uint8_t winA,winB; 18 | uint16_t granularity; 19 | uint16_t winsize; 20 | uint16_t segmentA, segmentB; 21 | uint32_t realFctPtr; 22 | uint16_t pitch; // bytes per scanline 23 | 24 | uint16_t Xres, Yres; 25 | uint8_t Wchar, Ychar, planes, bpp, banks; 26 | uint8_t memory_model, bank_size, image_pages; 27 | uint8_t reserved0; 28 | 29 | uint8_t red_mask, red_position; 30 | uint8_t green_mask, green_position; 31 | uint8_t blue_mask, blue_position; 32 | uint8_t rsv_mask, rsv_position; 33 | uint8_t directcolor_attributes; 34 | 35 | uint32_t physbase; // your LFB (Linear Framebuffer) address ;) 36 | uint32_t reserved1; 37 | uint16_t reserved2; 38 | } __attribute__((packed)) ModeInfoBlock_t; 39 | 40 | struct Rgb 41 | { 42 | uint8_t b, g, r; // match memory layout of pixel 43 | Rgb(): b{0}, g{0}, r{0} {} 44 | Rgb(uint8_t r, uint8_t g, uint8_t b): b{b}, g{g}, r{r} {} 45 | Rgb(uint32_t rgb) 46 | :b{(uint8_t)(rgb & 0xff)}, 47 | g{(uint8_t)((rgb>>8) & 0xff)}, r{(uint8_t)(rgb>>16)} {} 48 | }; 49 | 50 | typedef struct position_s 51 | { 52 | int x, y; 53 | } position_t; 54 | 55 | class VideoMode 56 | { 57 | public: 58 | void init(ModeInfoBlock_t* modeinfo); 59 | void drawLine(int x0, int y0, int x1, int y1, Rgb rgb); 60 | void drawLine(position_t p1, position_t p2, Rgb rgb); 61 | void drawPixel(int x, int y, Rgb rgb); 62 | void drawRect(position_t p, int width, int height, Rgb rgb); 63 | void fillRect(position_t p, int width, int height, Rgb rgb); 64 | void drawString(position_t p, const char* s, Rgb rgb); 65 | void drawChar(position_t p, char c, Rgb rgb); 66 | void drawImage(position_t p, char* data, int width, int height); 67 | 68 | void blitCopy(position_t dst, position_t src, int width, int height); 69 | 70 | int width() const { return _width; } 71 | int height() const { return _height; } 72 | 73 | private: 74 | char* _base; 75 | uint32_t _pitch; 76 | uint32_t _width, _height; 77 | 78 | void octant0(position_t p1, position_t p2, Rgb rgb); 79 | void octant1(position_t p1, position_t p2, Rgb rgb); 80 | }; 81 | 82 | extern VideoMode videoMode; 83 | extern Rgb colormap[]; 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /include/vm.h: -------------------------------------------------------------------------------- 1 | #ifndef _VM_H 2 | #define _VM_H 3 | 4 | #include "mm.h" 5 | #include "memlayout.h" 6 | #include "mmu.h" 7 | #include 8 | 9 | typedef struct proc_s proc_t; 10 | class VirtualMemoryManager 11 | { 12 | public: 13 | VirtualMemoryManager(); 14 | 15 | bool init(PhysicalMemoryManager* pmm); 16 | 17 | void map_pages(page_directory_t* pgdir, void *vaddr, u32 size, 18 | u32 paddr, u32 flags); 19 | void unmap_pages(page_directory_t* pgdir, void *vaddr, u32 size, bool free_mem); 20 | 21 | bool mapped(page_directory_t* pgdir, void* vaddr); 22 | page_t* walk(page_directory_t* pgdir, void* vaddr, bool create = false); 23 | /** 24 | * Causes the specified page directory to be loaded into the 25 | * CR3 register. 26 | **/ 27 | void switch_page_directory(page_directory_t *pgdir); 28 | page_directory_t* current_directory() const { return _current_pdir; } 29 | 30 | void dump_page_directory(page_directory_t* pgdir); 31 | page_directory_t* create_address_space(); 32 | void release_address_space(proc_t* proc, page_directory_t* pgdir); 33 | 34 | void release_task_heap(proc_t* proc, char* vaddr, uint32_t size); 35 | void alloc_task_heap(proc_t* proc, char* vaddr, uint32_t size); 36 | void copy_task_heap(proc_t* dst, proc_t* src); 37 | 38 | page_directory_t* copy_page_directory(page_directory_t* pgdir); 39 | page_directory_t* kernel_page_directory(); 40 | 41 | // alloc one kernel page and return vaddr 42 | void* alloc_page(); 43 | void free_page(void* vaddr); 44 | 45 | // kernel heap allocation 46 | void* kmalloc(size_t size, int align = 1); 47 | void kfree(void* ptr); 48 | //for debug 49 | void dump_heap(int limit = -1); 50 | 51 | private: 52 | struct kheap_block_head 53 | { 54 | u32 size; 55 | struct kheap_block_head* prev; 56 | struct kheap_block_head* next; 57 | void* ptr; 58 | u32 used; 59 | char data[1]; 60 | }; 61 | 62 | PhysicalMemoryManager* _pmm; 63 | page_directory_t* _current_pdir; 64 | 65 | kheap_block_head* _kheap_ptr; 66 | u32* _kern_heap_start; 67 | u32* _kern_heap_limit; 68 | Spinlock _lock {"vmm"}; 69 | 70 | kheap_block_head* find_block(kheap_block_head** last, size_t size, int align); 71 | void split_block(kheap_block_head* h, size_t size); 72 | kheap_block_head* merge_block(kheap_block_head* h); 73 | kheap_block_head* align_block(kheap_block_head* h, int align); 74 | bool aligned(void* ptr, int align); 75 | void* ksbrk(size_t size); 76 | 77 | void flush_tlb_entry(u32 vaddr); 78 | void test_malloc(); 79 | 80 | }; 81 | 82 | extern VirtualMemoryManager vmm; 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /include/display.h: -------------------------------------------------------------------------------- 1 | #ifndef _SOS_DISPLAY_H 2 | #define _SOS_DISPLAY_H 3 | 4 | #include "types.h" 5 | #include "graphics.h" 6 | #include "spinlock.h" 7 | 8 | // http://www.rapidtables.com/web/color/RGB_Color.htm 9 | enum Color { 10 | BLACK = 0, // BLACK 11 | BLUE = 1, // BLUE 12 | GREEN = 2, // GREEN 13 | CYAN = 3, // CYAN 0x00ffff 14 | RED = 4, // RED 15 | MAGENTA = 5, // MAGENTA 0xff00ff 16 | BROWN = 6, // BROWN 0xa52a2a 17 | LIGHT_GRAY = 7, // LIGHT GRAY 0xd3d3d3 18 | DARK_GRAY = 8, // DARK GRAY 0xbebebe 19 | LIGHT_BLUE = 9, // LIGHT BLUE 0xadd8e6 20 | LIGHT_GREEN = 10, // LIGHT GREEN 0x90ee90 21 | LIGHT_CYAN = 11, // LIGHT CYAN 0xe0ffff 22 | LIGHT_RED = 12, // LIGHT RED 0xcd5c5c? 23 | LIGHT_MAGENTA = 13, // LIGHT MAGENTA 0xee00ee 24 | LIGHT_BROWN = 14, // LIGHT BROWN 0xff4040 25 | WHITE = 15, // WHITE , 26 | 27 | // below is not supported in text mode 28 | YELLOW = 16, // 0xffff00 29 | LIGHT_YELLOW = 17, // 0xfafad2 30 | PURPLE = 18, //0x800080 31 | 32 | MAXCOLOR=PURPLE 33 | }; 34 | 35 | class Display 36 | { 37 | public: 38 | virtual Color get_text_color() = 0; 39 | virtual void set_text_color(Color) = 0; 40 | virtual void set_cursor(position_t cur) = 0; 41 | virtual position_t get_cursor() = 0; 42 | virtual void clear() = 0; 43 | 44 | virtual void scroll(int lines) = 0; 45 | virtual void putchar(char c) = 0; 46 | 47 | virtual void del() = 0; 48 | }; 49 | 50 | class Console: public Display 51 | { 52 | public: 53 | Color get_text_color() override; 54 | void set_text_color(Color) override; 55 | void set_cursor(position_t cur) override; 56 | position_t get_cursor() override; 57 | void clear() override; 58 | 59 | void putchar(char c) override; 60 | void scroll(int lines) override; 61 | void del() override; 62 | 63 | private: 64 | void set_phy_cursor(int x, int y); 65 | int _cx {0}, _cy {0}; 66 | u8 _attrib {0x0F}; 67 | Spinlock _lock {"console"}; 68 | }; 69 | 70 | class GraphicDisplay: public Display 71 | { 72 | public: 73 | Color get_text_color() override; 74 | void set_text_color(Color) override; 75 | void set_cursor(position_t cur) override; 76 | position_t get_cursor() override; 77 | void clear() override; 78 | void putchar(char c) override; 79 | void scroll(int lines) override; 80 | void del() override; 81 | 82 | private: 83 | position_t _cursor {0, 0}; 84 | int _rows {34}, _cols {88}; 85 | Rgb _clr {colormap[RED]}; 86 | Color _clridx {RED}; 87 | Spinlock _lock {"graphdisplay"}; 88 | }; 89 | 90 | extern Console console; 91 | extern GraphicDisplay graph_console; 92 | extern Display* current_display; 93 | extern void video_mode_test(); 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /include/ata.h: -------------------------------------------------------------------------------- 1 | #ifndef _ATA_H 2 | #define _ATA_H 3 | 4 | #include "types.h" 5 | #include "blkio.h" 6 | #include "devices.h" 7 | 8 | #define NR_ATA 4 9 | 10 | /* 11 | * BSY (busy) 12 | * DRDY (device ready) 13 | * DF (Device Fault) 14 | * DSC (seek complete) 15 | * DRQ (Data Transfer Requested) 16 | * CORR (data corrected) 17 | * IDX (index mark) 18 | * ERR (error) 19 | */ 20 | enum ATA_STATUS { 21 | ATA_BSY = 0x80, 22 | ATA_DRDY = 0x40, 23 | ATA_DF = 0x20, 24 | ATA_DSC = 0x10, 25 | ATA_DRQ = 0x08, 26 | ATA_CORR = 0x04, 27 | ATA_IDX = 0x02, 28 | ATA_ERR = 0x01 29 | }; 30 | 31 | /* 32 | * BBK (Bad Block) 33 | * UNC (Uncorrectable data error) 34 | * MC (Media Changed) 35 | * IDNF (ID mark Not Found) 36 | * MCR (Media Change Requested) 37 | * ABRT (command aborted) 38 | * TK0NF (Track 0 Not Found) 39 | * AMNF (Address Mark Not Found) 40 | */ 41 | 42 | enum ATA_ERROR { 43 | ATA_ERR_BBK = 0x80, 44 | ATA_ERR_UNC = 0x40, 45 | ATA_ERR_MC = 0x20, 46 | ATA_ERR_IDNF = 0x10, 47 | ATA_ERR_MCR = 0x08, 48 | ATA_ERR_ABRT = 0x04, 49 | ATA_ERR_TK0NF = 0x02, 50 | ATA_ERR_AMNF = 0x01, 51 | }; 52 | 53 | enum ATAFlags { 54 | LBA28 = 0x01, 55 | LBA48 = 0x02, 56 | }; 57 | 58 | /* Primary Master Controller Registers 59 | * 1F0 (Read and Write): Data Register 60 | * 1F1 (Read): Error Register 61 | * 1F1 (Write): Features Register 62 | * 1F2 (Read and Write): Sector Count Register 63 | * 1F3 (Read and Write): LBA Low Register 64 | * 1F4 (Read and Write): LBA Mid Register 65 | * 1F5 (Read and Write): LBA High Register 66 | * 1F6 (Read and Write): Drive/Head Register 67 | * 1F7 (Read): Status Register 68 | * 1F7 (Write): Command Register 69 | * 3F6 (Read): Alternate Status Register 70 | * 3F6 (Write): Device Control Register 71 | */ 72 | 73 | #define ATA_DATA_REG 0x0 74 | #define ATA_SECTOR_COUNT_REG 0x2 75 | #define ATA_LBA_LO_REG 0x3 76 | #define ATA_LBA_MI_REG 0x4 77 | #define ATA_LBA_HI_REG 0x5 78 | #define ATA_DRIVE_REG 0x6 79 | #define ATA_STATUS_REG 0x7 80 | #define ATA_CMD_REG 0x7 81 | 82 | #define ATA_CMD_IDENTIFY 0xEC 83 | #define ATA_CMD_READ 0x20 84 | #define ATA_CMD_WRITE 0x30 85 | 86 | 87 | class PATADevice: public BlockDevice { 88 | public: 89 | PATADevice(); 90 | 91 | bool valid() const { return _valid; } 92 | void init(int bus, bool master); 93 | 94 | bool read(Buffer* bufp) override; 95 | bool write(Buffer* bufp) override; 96 | 97 | private: 98 | bool _valid {false}; 99 | int _bus; // 0 or 1 100 | int _master; // or slave 101 | int _iobase; 102 | int _ioctl; // device control reg 103 | ATAFlags _flags; 104 | 105 | uint32_t _sectors; // lba28 sectors total 106 | 107 | 108 | void _outb(u16 port, u8 val); 109 | u8 _inb(u16 port); 110 | u16 _inw(u16 port); 111 | }; 112 | 113 | extern void ata_init(); 114 | 115 | #endif /* ATA_H */ 116 | 117 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![logo](images/logo.ppm?raw=true) 2 | 3 | sos 4 | === 5 | Sian's experimenting Operating System written in C++. it's a 32bit os kernel and runs on uniprocessor. 6 | 7 | ![screenshot](images/screenshot.png?raw=true) 8 | 9 | BUILD 10 | ==== 11 | Like `makefile` indicated, this is a x86 kernel, and you need a i686 gcc cross compiler for building and running it. see [here](http://wiki.osdev.org/GCC_Cross-Compiler) for the information. I think it also works under a 32bit GNU/Linux distribution. you may need to specify `-Wl,--build-id=none` for successful compiling. The kernel follows multiboot protocol and need a hd img with grub2 preinstalled. [Here](http://pan.baidu.com/s/1o6uZ1s2) is a premade image for testing. 12 | 13 | Refs 14 | === 15 | [xv6][] is a great reference implementation of a unix style kernel. [linux 0.11][linux] is also worth reading, and I learned a lot from these projects. You can find a lot of info about writing an small os kernel [here](http://wiki.osdev.org). 16 | 17 | Notes 18 | === 19 | One of the hardest as far as I can tell is memory management. I do implement my own kmalloc/kfree based on a simple algorithm. The way I choose to manage memory (both physical and virtual) makes some thing hard to implement, i.e shared memory region. 20 | 21 | Another thing is task switch. There are many ways to do this, 22 | [xv6][]'s way or old linux way or your own method. 23 | 24 | When design other parts of the kernel, you can stick to the unix tradition or just go bold and invent your own. 25 | 26 | How to make a hd.img 27 | === 28 | This works under modern GNU/Linux (tested on Deepin 15). 29 | make disk image, then use parted (or fdisk to format as msdos) 30 | ``` 31 | dd if=/dev/zero of=hd.img bs=1M count=500 32 | sudo parted hd.img mklabel msdos 33 | sudo parted hd.img mkpart primary fat32 0% 100% 34 | ``` 35 | 36 | bind loop device (fat32 partition will be /dev/loop0p1) and mkfs 37 | ``` 38 | sudo losetup -f -P -v hd.img 39 | sudo mkfs.vfat -F 32 /dev/loop0p1 40 | ``` 41 | 42 | then mount fat32 partition and install grub2: 43 | ``` 44 | sudo mount /dev/loop0p1 /mnt 45 | sudo grub-install --modules="fat biosdisk normal part_msdos ext2 multiboot" --root-directory=/mnt /dev/loop0 46 | ``` 47 | 48 | TODOs 49 | ==== 50 | + tty and io partially works 51 | + enough syscalls for sh 52 | + write support of vfs & block io layers 53 | + signal handling (partially) 54 | + simple GUI and software renderer (may port mesa if possible) 55 | + port newlib as userland libc 56 | 57 | ISSUSE 58 | ==== 59 | + physical mm is not good enough, and it's impossible to do va->pa & pa->va convertion. 60 | + userspace alloc will make some virtual address in kernel space can not be mapped (by adding KERNEL_VIRTUAL_BASE). which in turn may cause kernel has no mem to alloc. 61 | + sos use trap gate for syscalls, which leaves IF as it was(not cleared). must be very careful. 62 | + spinlock can not used in irq context in uniprocess system. 63 | + take care of the IF state, sleep can only happen with IF enabled context 64 | and wakeup from irq context leave IF disabled. 65 | + about spinlock: busy-waiting isn't enough when access syscall is a trap gate (IF enabled). 66 | we need to make sure cli'ed so fork / exec will not be preempted before finished. 67 | 68 | 69 | [xv6]: http://pdos.csail.mit.edu/6.828/2014/xv6.html 70 | [linux]: http://oldlinux.org 71 | -------------------------------------------------------------------------------- /include/sos/signal.h: -------------------------------------------------------------------------------- 1 | #ifndef _SOS_SIGNAL_H 2 | #define _SOS_SIGNAL_H 3 | #include 4 | 5 | #define SIGHUP 1 /* Hangup */ 6 | #define SIGINT 2 /* Interupt */ 7 | #define SIGQUIT 3 /* Quit */ 8 | #define SIGILL 4 /* Illegal instruction */ 9 | #define SIGTRAP 5 /* A breakpoint or trace instruction has been reached */ 10 | #define SIGABRT 6 /* Another process has requested that you abort */ 11 | #define SIGEMT 7 /* Emulation trap XXX */ 12 | #define SIGFPE 8 /* Floating-point arithmetic exception */ 13 | #define SIGKILL 9 /* You have been stabbed repeated with a large knife */ 14 | #define SIGBUS 10 /* Bus error (device error) */ 15 | #define SIGSEGV 11 /* Segmentation fault */ 16 | #define SIGSYS 12 /* Bad system call */ 17 | #define SIGPIPE 13 /* Attempted to read or write from a broken pipe */ 18 | #define SIGALRM 14 /* This is your wakeup call. */ 19 | #define SIGTERM 15 /* You have been Schwarzenegger'd */ 20 | #define SIGUSR1 16 /* User Defined Signal #1 */ 21 | #define SIGUSR2 17 /* User Defined Signal #2 */ 22 | #define SIGCHLD 18 /* Child status report */ 23 | #define SIGPWR 19 /* We need more power! */ 24 | #define SIGWINCH 20 /* Your containing terminal has changed size */ 25 | #define SIGURG 21 /* An URGENT! event (On a socket) */ 26 | #define SIGPOLL 22 /* XXX OBSOLETE; socket i/o possible */ 27 | #define SIGSTOP 23 /* Stopped (signal) */ 28 | #define SIGTSTP 24 /* ^Z (suspend) */ 29 | #define SIGCONT 25 /* Unsuspended (please, continue) */ 30 | #define SIGTTIN 26 /* TTY input has stopped */ 31 | #define SIGTTOU 27 /* TTY output has stopped */ 32 | 33 | #define NUMSIGNALS 28 34 | #define NSIG NUMSIGNALS 35 | 36 | typedef unsigned long sigset_t; 37 | 38 | #define S_MASK(sig) (1<<((sig)-1)) 39 | /* 40 | *sa_flags values: SA_STACK is not currently supported, but will allow the 41 | * usage of signal stacks by using the (now obsolete) sa_restorer field in 42 | * the sigaction structure as a stack pointer. This is now possible due to 43 | * the changes in signal handling. LBT 010493. 44 | * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the 45 | * SA_RESTART flag to get restarting signals (which were the default long ago) 46 | */ 47 | #define SA_NOCLDSTOP 1 48 | #define SA_STACK 0x08000000 49 | #define SA_RESTART 0x10000000 50 | #define SA_INTERRUPT 0x20000000 51 | #define SA_NOMASK 0x40000000 52 | #define SA_ONESHOT 0x80000000 53 | 54 | #define SIG_BLOCK 0 /* for blocking signals */ 55 | #define SIG_UNBLOCK 1 /* for unblocking signals */ 56 | #define SIG_SETMASK 2 /* for setting the signal mask */ 57 | 58 | typedef void (*_signal_handler_t)(); 59 | struct sigaction { 60 | int sa_flags; /* Special flags to affect behavior of signal */ 61 | sigset_t sa_mask; /* Additional set of signals to be blocked during execution of signal-catching function. */ 62 | _signal_handler_t sa_handler; 63 | }; 64 | 65 | typedef struct sigcontext_s { 66 | int32_t edi, esi, ebp, ebx, edx, ecx, eax; 67 | int32_t eip, uesp; 68 | int32_t signo, sig_mask; // old mask 69 | } sigcontext_t; 70 | 71 | #define SIG_DFL ((_signal_handler_t)0) /* Default action */ 72 | #define SIG_IGN ((_signal_handler_t)1) /* Ignore action */ 73 | #define SIG_ERR ((_signal_handler_t)-1) /* Error return */ 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /include/unistd.h: -------------------------------------------------------------------------------- 1 | #ifndef _UNISTD_H 2 | #define _UNISTD_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define _syscall0(ret_t, fn) \ 9 | ret_t fn() \ 10 | { \ 11 | ret_t ret; \ 12 | asm volatile ( "int $0x80 \n" \ 13 | :"=a"(ret) \ 14 | :"a"(SYS_##fn) \ 15 | :"cc", "memory"); \ 16 | return ret; \ 17 | } 18 | 19 | #define _syscall1(ret_t, fn, t1, arg1) \ 20 | ret_t fn(t1 arg1) \ 21 | { \ 22 | ret_t ret; \ 23 | asm volatile ( "int $0x80 \n" \ 24 | :"=a"(ret) \ 25 | :"a"(SYS_##fn), "b"(arg1) \ 26 | :"cc", "memory"); \ 27 | return ret; \ 28 | } 29 | 30 | #define _syscall2(ret_t, fn, t1, arg1, t2, arg2) \ 31 | ret_t fn(t1 arg1, t2 arg2) \ 32 | { \ 33 | ret_t ret; \ 34 | asm volatile ( "int $0x80 \n" \ 35 | :"=a"(ret) \ 36 | :"a"(SYS_##fn), "b"(arg1), "c"(arg2) \ 37 | :"cc", "memory"); \ 38 | return ret; \ 39 | } 40 | 41 | #define _syscall3(ret_t, fn, t1, arg1, t2, arg2, t3, arg3) \ 42 | ret_t fn(t1 arg1, t2 arg2, t3 arg3) \ 43 | { \ 44 | ret_t ret; \ 45 | asm volatile ( "int $0x80 \n" \ 46 | :"=a"(ret) \ 47 | :"a"(SYS_##fn), "b"(arg1), "c"(arg2), "d"(arg3) \ 48 | :"cc", "memory"); \ 49 | return ret; \ 50 | } 51 | 52 | #define _syscall4(ret_t, fn, t1, arg1, t2, arg2, t3, arg3, t4, arg4) \ 53 | ret_t fn(t1 arg1, t2 arg2, t3 arg3, t4 arg4) \ 54 | { \ 55 | ret_t ret; \ 56 | asm volatile ( "int $0x80 \n" \ 57 | :"=a"(ret) \ 58 | :"a"(SYS_##fn), "b"(arg1), "c"(arg2), "d"(arg3), "S"(arg4) \ 59 | :"cc", "memory"); \ 60 | return ret; \ 61 | } 62 | 63 | #define STDIN_FILENO 0 64 | #define STDOUT_FILENO 1 65 | #define STDERR_FILENO 2 66 | 67 | #ifndef NULL 68 | #define NULL ((void*)0) 69 | #endif 70 | 71 | #define SEEK_SET 0 72 | #define SEEK_CUR 1 73 | #define SEEK_END 2 74 | 75 | extern int errno; 76 | 77 | #ifdef __cplusplus 78 | extern "C" { 79 | #endif 80 | 81 | int write(int fildes, const void *buf, size_t nbyte); 82 | int close(int fd); 83 | int read(int fildes, void *buf, size_t nbyte); 84 | int fork(); 85 | int exec(const char *path, char *const argv[], char *const envp[]); 86 | int execve(const char *path, char *const argv[], char *const envp[]); 87 | int getpid(); 88 | int getppid(); 89 | int sleep(int); 90 | int exit(int); 91 | int readdir(unsigned int fd, struct dirent *dirp, unsigned int count); 92 | int dup(int fd); 93 | int dup2(int fd, int fd2); 94 | int pipe(int fd[2]); 95 | int kdump(); 96 | void* sbrk(int inc); 97 | off_t lseek(int, off_t, int); 98 | int stat(const char *pathname, struct stat *buf); 99 | int fstat(int fd, struct stat *buf); 100 | int lstat(const char *pathname, struct stat *buf); 101 | int kill(pid_t pid, int sig); 102 | int signal(int signum, unsigned long handler); 103 | int sigpending(sigset_t *set); 104 | int sigprocmask(int how, sigset_t *set, sigset_t *oldset); 105 | int sigsuspend(sigset_t *sigmask); 106 | int chdir(const char *path); 107 | int fchdir(int fd); 108 | char* getcwd(char *buf, size_t size); 109 | 110 | // return -1 if no child, or pid of any of children exited 111 | pid_t wait(int *status); 112 | pid_t waitpid(pid_t pid, int *status, int options); 113 | 114 | #ifdef __cplusplus 115 | } 116 | #endif 117 | #endif 118 | -------------------------------------------------------------------------------- /include/boot.h: -------------------------------------------------------------------------------- 1 | #ifndef _BOOT_H 2 | #define _BOOT_H 3 | 4 | #include "common.h" 5 | 6 | 7 | /* Flags to be set in the 'flags' member of the multiboot info structure. */ 8 | 9 | /* is there basic lower/upper memory information? */ 10 | #define MULTIBOOT_INFO_MEMORY 0x00000001 11 | /* is there a boot device set? */ 12 | #define MULTIBOOT_INFO_BOOTDEV 0x00000002 13 | /* is the command-line defined? */ 14 | #define MULTIBOOT_INFO_CMDLINE 0x00000004 15 | /* are there modules to do something with? */ 16 | #define MULTIBOOT_INFO_MODS 0x00000008 17 | 18 | /* These next two are mutually exclusive */ 19 | 20 | /* is there a symbol table loaded? */ 21 | #define MULTIBOOT_INFO_AOUT_SYMS 0x00000010 22 | /* is there an ELF section header table? */ 23 | #define MULTIBOOT_INFO_ELF_SHDR 0X00000020 24 | 25 | /* is there a full memory map? */ 26 | #define MULTIBOOT_INFO_MEM_MAP 0x00000040 27 | 28 | /* Is there drive info? */ 29 | #define MULTIBOOT_INFO_DRIVE_INFO 0x00000080 30 | 31 | /* Is there a config table? */ 32 | #define MULTIBOOT_INFO_CONFIG_TABLE 0x00000100 33 | 34 | /* Is there a boot loader name? */ 35 | #define MULTIBOOT_INFO_BOOT_LOADER_NAME 0x00000200 36 | 37 | /* Is there a APM table? */ 38 | #define MULTIBOOT_INFO_APM_TABLE 0x00000400 39 | 40 | /* Is there video information? */ 41 | #define MULTIBOOT_INFO_VBE_INFO 0x00000800 42 | #define MULTIBOOT_INFO_FRAMEBUFFER_INFO 0x00001000 43 | 44 | 45 | 46 | /* The Multiboot header. */ 47 | typedef struct multiboot_header 48 | { 49 | unsigned long magic; 50 | unsigned long flags; 51 | unsigned long checksum; 52 | unsigned long header_addr; 53 | unsigned long load_addr; 54 | unsigned long load_end_addr; 55 | unsigned long bss_end_addr; 56 | unsigned long entry_addr; 57 | } multiboot_header_t; 58 | 59 | typedef struct multiboot_info { 60 | u32 flags; 61 | u32 low_mem; 62 | u32 high_mem; 63 | u32 boot_device; 64 | u32 cmdline; 65 | u32 mods_count; 66 | u32 mods_addr; 67 | struct { 68 | u32 num; 69 | u32 size; 70 | u32 addr; 71 | u32 shndx; 72 | } elf_sec; 73 | unsigned long mmap_length; 74 | unsigned long mmap_addr; 75 | unsigned long drives_length; 76 | unsigned long drives_addr; 77 | unsigned long config_table; 78 | unsigned long boot_loader_name; 79 | unsigned long apm_table; 80 | unsigned long vbe_control_info; 81 | unsigned long vbe_mode_info; 82 | unsigned long vbe_mode; 83 | unsigned long vbe_interface_seg; 84 | unsigned long vbe_interface_off; 85 | unsigned long vbe_interface_len; 86 | 87 | uint64_t fb_addr; 88 | uint32_t fb_pitch; 89 | uint32_t fb_width; 90 | uint32_t fb_height; 91 | uint8_t fb_bpp; 92 | } multiboot_info_t; 93 | 94 | /* The module structure. */ 95 | typedef struct module 96 | { 97 | unsigned long mod_start; 98 | unsigned long mod_end; 99 | unsigned long string; 100 | unsigned long reserved; 101 | } module_t; 102 | 103 | /* The memory map. Be careful that the offset 0 is base_addr_low 104 | * but no size. */ 105 | typedef struct memory_map_s { 106 | unsigned long size; 107 | unsigned long base_addr_low; 108 | unsigned long base_addr_high; 109 | unsigned long length_low; 110 | unsigned long length_high; 111 | unsigned long type; 112 | } memory_map_t; 113 | 114 | #endif 115 | -------------------------------------------------------------------------------- /include/map.h: -------------------------------------------------------------------------------- 1 | #ifndef _SOS_MAP_H 2 | #define _SOS_MAP_H 3 | 4 | #include 5 | #include 6 | 7 | using hash_t = uint32_t; 8 | constexpr int DEFAULT_TABLE_SIZE = 127; // prime 9 | 10 | template 11 | struct KeyHash { 12 | hash_t operator()(const K& key) const { 13 | return static_cast(key) % DEFAULT_TABLE_SIZE; 14 | } 15 | }; 16 | 17 | template 18 | struct KeyEqual { 19 | bool operator()(const K& k1, const K& k2) const { 20 | return k1 == k2; 21 | } 22 | }; 23 | 24 | //BKDR hash 25 | struct CStringHash { 26 | hash_t operator()(const char* key) const { 27 | unsigned int seed = 131; // 31 131 13131 1313131 ... 28 | hash_t h = 0; 29 | while (*key) { 30 | h = h * seed + *key++; 31 | } 32 | return (h & 0x7fffffff); 33 | } 34 | }; 35 | 36 | struct CStringEqual { 37 | bool operator()(const char* s1, const char* s2) const { 38 | return strcmp(s1, s2) == 0; 39 | } 40 | }; 41 | 42 | template , class Eq = KeyEqual> 43 | class HashMap 44 | { 45 | public: 46 | HashMap() { 47 | memset(_buckets, 0, sizeof _buckets); 48 | } 49 | 50 | ~HashMap() { 51 | for (int i = 0; i < DEFAULT_TABLE_SIZE; i++) { 52 | node_t* p = _buckets[i]; 53 | while (p) { 54 | auto* d = p; 55 | p = p->next; 56 | delete d; 57 | } 58 | } 59 | _sz = 0; 60 | } 61 | 62 | int size() const { return _sz; } 63 | bool contains(const K& key) const { 64 | auto h = _hfn(key) % DEFAULT_TABLE_SIZE; 65 | auto* p = _buckets[h]; 66 | while (p) { 67 | if (_heq(p->k, key)) return true; 68 | p = p->next; 69 | } 70 | return false; 71 | } 72 | 73 | V find(const K& key) const { 74 | auto h = _hfn(key) % DEFAULT_TABLE_SIZE; 75 | auto* p = _buckets[h]; 76 | while (p) { 77 | if (_heq(p->k, key)) return p->v; 78 | p = p->next; 79 | } 80 | 81 | return V(); 82 | } 83 | 84 | V erase(const K& key) { 85 | auto h = _hfn(key) % DEFAULT_TABLE_SIZE; 86 | auto** p = &_buckets[h]; 87 | 88 | V ret; 89 | while (*p) { 90 | if (_heq((*p)->k, key)) { 91 | auto* d = *p; 92 | ret = d->v; 93 | *p = d->next; 94 | delete d; 95 | --_sz; 96 | } else 97 | p = &(*p)->next; 98 | } 99 | 100 | return ret; 101 | } 102 | 103 | void insert(const K& key, const V& val) { 104 | auto h = _hfn(key) % DEFAULT_TABLE_SIZE; 105 | auto* q = new node_t; 106 | q->k = key; 107 | q->v = val; 108 | q->next = _buckets[h]; 109 | _buckets[h] = q; 110 | _sz++; 111 | } 112 | 113 | private: 114 | typedef struct node_ { 115 | K k; 116 | V v; 117 | struct node_* next; 118 | } node_t; 119 | 120 | int _sz {0}; 121 | node_t* _buckets[DEFAULT_TABLE_SIZE]; 122 | F _hfn; 123 | Eq _heq; 124 | }; 125 | 126 | #endif 127 | -------------------------------------------------------------------------------- /kern/core/timer.cc: -------------------------------------------------------------------------------- 1 | #include "timer.h" 2 | #include "x86.h" 3 | #include "isr.h" 4 | #include "task.h" 5 | #include "spinlock.h" 6 | #include "display.h" 7 | 8 | static const u32 FREQ = 1193180; 9 | volatile u32 timer_ticks = 0; 10 | 11 | extern tss_entry_t shared_tss; 12 | extern "C" void switch_to(kcontext_t** old, kcontext_t* next); 13 | extern void setup_tss(u32 stack); 14 | extern "C" void flush_tss(); 15 | 16 | Spinlock schedlock("sched"); 17 | 18 | void scheduler() 19 | { 20 | //NOTE: should never spin in interrupt context! so check IF flag 21 | //to determine if in irq context. this is not a good way. 22 | auto oldflags = schedlock.lock(); 23 | if (current) { 24 | if (current->need_resched) current->need_resched = false; 25 | 26 | auto* old = current; 27 | bool rewind = true; 28 | proc_t* tsk = old->next ? old->next: task_init; 29 | while (tsk) { 30 | if (old != tsk && tsk->state == TASK_READY) { 31 | current = tsk; 32 | break; 33 | } 34 | tsk = tsk->next; 35 | if (!tsk && rewind) { 36 | rewind = false; 37 | tsk = &tasks[0]; 38 | } 39 | } 40 | 41 | kassert(current->state == TASK_READY); 42 | kassert( old != current ); 43 | 44 | // kprintf("(sched: %s(%d) -> %s(%d)) ", old->name, old->pid, 45 | // current->name, current->pid); 46 | //very tricky! 47 | setup_tss(current->kern_esp); 48 | flush_tss(); 49 | vmm.switch_page_directory(current->pgdir); 50 | 51 | switch_to(&old->kctx, current->kctx); 52 | } 53 | 54 | schedlock.release(oldflags); 55 | } 56 | 57 | struct timeout_s { 58 | uint32_t end_tick; 59 | struct timeout_s* next; 60 | }; 61 | 62 | static timeout_t* tm_head = NULL; 63 | 64 | timeout_t* add_timeout(int millisecs) 65 | { 66 | timeout_t* tm = new timeout_t; 67 | tm->end_tick = timer_ticks + millisecs * HZ / 1000; 68 | tm->next = tm_head; 69 | tm_head = tm; 70 | return tm; 71 | } 72 | 73 | static void timer_interrupt(trapframe_t* regs) 74 | { 75 | (void)regs; 76 | timer_ticks++; 77 | auto old = current_display->get_text_color(); 78 | current_display->set_text_color(RED); 79 | auto cur = current_display->get_cursor(); 80 | current_display->set_cursor({70, 0}); 81 | 82 | timeout_t** tm = &tm_head; 83 | while (*tm) { 84 | if ((*tm)->end_tick <= timer_ticks) { 85 | wakeup((void*)tm); 86 | auto* p = *tm; 87 | wakeup(p); 88 | *tm = (*tm)->next; 89 | delete p; 90 | } else tm = &(*tm)->next; 91 | } 92 | kprintf("T: %d", timer_ticks/HZ); 93 | 94 | current_display->set_cursor(cur); 95 | current_display->set_text_color(old); 96 | } 97 | 98 | void init_timer() 99 | { 100 | register_isr_handler(IRQ0, timer_interrupt); 101 | 102 | u32 div = FREQ / HZ; 103 | outb(0x43, 0x36); 104 | 105 | /*Divisor has to be sent byte-wise, so split here into upper/lower bytes.*/ 106 | u8 l = (u8)(div & 0xff); 107 | u8 h = (u8)((div>>8) & 0xff); 108 | 109 | // Send the frequency divisor. 110 | outb(0x40, l); 111 | outb(0x40, h); 112 | } 113 | 114 | void busy_wait(int millisecs) 115 | { 116 | u32 end = timer_ticks + millisecs * HZ / 1000; 117 | while (timer_ticks < end) { 118 | asm volatile ("hlt"); 119 | asm volatile ("nop"); 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /kern/drv/devfs.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | Spinlock devfslock {"devfs"}; 8 | 9 | struct known_dev_ { 10 | const char* name; 11 | FsNodeType type; 12 | dev_t dev; 13 | } known_devs[] = { 14 | {"tty1", FsNodeType::CharDev, DEVNO(TTY_MAJOR, 1)}, 15 | {"tty2", FsNodeType::CharDev, DEVNO(TTY_MAJOR, 2)}, 16 | {"hda", FsNodeType::BlockDev, DEVNO(IDE_MAJOR, 0)}, 17 | {"zero", FsNodeType::CharDev, DEVNO(ZERO_MAJOR, 0)}, 18 | {"null", FsNodeType::CharDev, DEVNO(NULL_MAJOR, 0)}, 19 | }; 20 | 21 | void DevFs::init() 22 | { 23 | dev_t dev = DEVNO(DEVFS_MAJOR, 0); 24 | _iroot = vfs.alloc_inode(dev, 1); 25 | kassert(_iroot->ref == 0); 26 | _iroot->ref++; 27 | _iroot->dev = dev; 28 | _iroot->type = FsNodeType::Dir; 29 | _iroot->ino = 1; 30 | _iroot->size = 0; 31 | _iroot->blksize = 1; 32 | _iroot->blocks = _iroot->size; 33 | _iroot->fs = this; 34 | } 35 | 36 | dentry_t * DevFs::lookup(inode_t * dir, dentry_t *de) 37 | { 38 | if (dir->type != FsNodeType::Dir && dir->ino != 1) return NULL; 39 | 40 | size_t i = 0; 41 | for (i = 0; i < ARRAYLEN(known_devs); i++) { 42 | if (strcmp(de->name, known_devs[i].name) == 0) { 43 | break; 44 | } 45 | } 46 | if (i >= ARRAYLEN(known_devs)) return NULL; 47 | de->ip = vfs.alloc_inode(known_devs[i].dev, i+2); 48 | if (de->ip->ref == 0) { 49 | de->ip->ino = i+2; 50 | de->ip->dev = known_devs[i].dev; 51 | de->ip->type = known_devs[i].type; 52 | de->ip->size = 0; 53 | de->ip->blksize = 1; 54 | de->ip->blocks = de->ip->size; 55 | de->ip->fs = this; 56 | de->ip->ref++; 57 | } 58 | return de; 59 | } 60 | 61 | // blocking 62 | ssize_t DevFs::read(File *filp, char * buf, size_t count, off_t * offset) 63 | { 64 | inode_t* ip = filp->inode(); 65 | if (ip->type != FsNodeType::CharDev && ip->type != FsNodeType::BlockDev) return -EBADF; 66 | off_t off = filp->off(); 67 | 68 | if (ip->type == FsNodeType::CharDev) { 69 | auto* rdev = chr_device_get(ip->dev); 70 | if (!rdev) return -ENOENT; 71 | auto* sp = buf; 72 | 73 | while (count > 0 && (*sp = rdev->read()) >= 0) { 74 | count--; 75 | if (*sp == '\n') break; 76 | sp++; 77 | } 78 | *sp = 0; 79 | 80 | count = sp - buf; 81 | } else if (ip->type == FsNodeType::BlockDev) { 82 | panic("not implemented"); 83 | } 84 | 85 | filp->set_off(off + count); 86 | if (offset) *offset = filp->off(); 87 | return count; 88 | } 89 | 90 | ssize_t DevFs::write(File *filp, const char * buf, size_t count, off_t *offset) 91 | { 92 | // write to terminal 93 | inode_t* ip = filp->inode(); 94 | if (ip->type != FsNodeType::CharDev && ip->type != FsNodeType::BlockDev) return -EBADF; 95 | (void)offset; 96 | 97 | auto* sp = buf; 98 | if (ip->type == FsNodeType::CharDev) { 99 | auto* rdev = chr_device_get(ip->dev); 100 | if (!rdev) return -ENOENT; 101 | 102 | auto oflags = devfslock.lock(); 103 | while (count > 0 && *sp) { 104 | rdev->write(*sp); 105 | sp++; 106 | count--; 107 | } 108 | devfslock.release(oflags); 109 | } 110 | 111 | return sp - buf; 112 | } 113 | 114 | FileSystem* create_devfs(const void* data) 115 | { 116 | (void)data; 117 | auto* fs = new DevFs; 118 | fs->init(); 119 | return fs; 120 | } 121 | -------------------------------------------------------------------------------- /kern/drv/ata.cc: -------------------------------------------------------------------------------- 1 | #include "ata.h" 2 | #include "x86.h" 3 | #include "common.h" 4 | #include "isr.h" 5 | #include "string.h" 6 | 7 | static void ata_wait(int iobase) 8 | { 9 | while ((inb(ATA_STATUS_REG+iobase) & (ATA_BSY|ATA_DRDY)) != ATA_DRDY) 10 | ; 11 | } 12 | 13 | static inline bool ata_ready(int iobase) 14 | { 15 | uint8_t r = 0; 16 | while (!((r = inb(iobase+ATA_STATUS_REG)) & (ATA_DRQ|ATA_ERR))) 17 | ; 18 | 19 | return !(r & ATA_ERR); 20 | } 21 | 22 | PATADevice::PATADevice() 23 | { 24 | } 25 | 26 | void PATADevice::_outb(u16 port, u8 val) 27 | { 28 | outb(port+_iobase, val); 29 | } 30 | 31 | u8 PATADevice::_inb(u16 port) 32 | { 33 | return inb(port+_iobase); 34 | } 35 | 36 | u16 PATADevice::_inw(u16 port) 37 | { 38 | return inw(port+_iobase); 39 | } 40 | 41 | void PATADevice::init(int bus, bool master) 42 | { 43 | this->_bus = bus; 44 | this->_master = master; 45 | this->_iobase = bus == 0 ? 0x1f0 : 0x170; 46 | this->_ioctl = bus == 0 ? 0x3f6 : 0x376; 47 | 48 | //ata_wait(); 49 | _outb(ATA_DRIVE_REG, (master?0:1)<<4); 50 | _outb(ATA_CMD_REG, ATA_CMD_IDENTIFY); 51 | 52 | for (int i = 0; i < 1000; i++) { 53 | if (_inb(ATA_STATUS_REG) != 0) { 54 | this->_valid = true; 55 | break; 56 | } 57 | } 58 | 59 | char model[41]; 60 | char serial[21]; 61 | 62 | if (!ata_ready(_iobase)) { 63 | this->_valid = false; 64 | } else { 65 | uint16_t data[256]; 66 | for (size_t i = 0; i < ARRAYLEN(data); i++) { 67 | data[i] = _inw(ATA_DATA_REG); 68 | } 69 | 70 | auto fn = [](uint16_t* src, char* dst, size_t sz) { 71 | for (size_t i = 0; i < sz; i++, src++) { 72 | dst[i*2] = *src >> 8; 73 | dst[i*2+1] = *src & 0xff; 74 | } 75 | 76 | for (size_t i = sz*2; i > 0; i--) { 77 | if (dst[i] <= 0x20) 78 | dst[i] = 0; 79 | else break; 80 | } 81 | }; 82 | 83 | fn(&data[10], (char*)&serial, 10); 84 | fn(&data[27], (char*)&model, 20); 85 | _sectors = data[60] | (data[61] << 16); 86 | } 87 | kprintf("IDE %d %s %sdetected, sectors %d, model (%s) serial (%s)\n", 88 | bus, master?"master":"slave", 89 | _valid?"":"not ", _sectors, model, serial); 90 | } 91 | 92 | bool PATADevice::read(Buffer* bufp) 93 | { 94 | sector_t sect = bufp->sector; 95 | _outb(ATA_SECTOR_COUNT_REG, 1); 96 | _outb(ATA_LBA_LO_REG, sect & 0xff); 97 | _outb(ATA_LBA_MI_REG, (sect >> 8) & 0xff); 98 | _outb(ATA_LBA_HI_REG, (sect >> 16) & 0xff); 99 | _outb(ATA_DRIVE_REG, 0xE0 | ((_master?0:1)<<4) | ((sect>>24) & 0x0f)); 100 | 101 | _outb(ATA_CMD_REG, ATA_CMD_READ); 102 | //TODO: wait for interrupt, so sleep .... ,now just polling 103 | 104 | if (!ata_ready(_iobase)) return false; 105 | for (size_t i = 0; i < 256; i++) { 106 | uint16_t d = _inw(ATA_DATA_REG); 107 | bufp->data[i*2] = d; 108 | bufp->data[i*2+1] = d >> 8; 109 | } 110 | return true; 111 | } 112 | 113 | bool PATADevice::write(Buffer* bufp) 114 | { 115 | (void)bufp; 116 | return true; 117 | } 118 | 119 | void ata_init() 120 | { 121 | kprintf("Probing IDE hard drives\n"); 122 | auto* pata0 = new PATADevice; 123 | pata0->init(0, true); 124 | pata0->dev = DEVNO(IDE_MAJOR, 0); 125 | blk_device_register(pata0->dev, pata0); 126 | 127 | //patas[1].init(0, false); 128 | picenable(IRQ_ATA1); 129 | //picenable(IRQ_ATA2); 130 | //blk_device_register(DEVNO(IDE_MAJOR, 64), pata1); 131 | } 132 | 133 | -------------------------------------------------------------------------------- /user/ls.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define BUF_SIZE 1024 11 | static const char* base = NULL; 12 | 13 | static inline int min(int a, int b) 14 | { 15 | return a < b ? a : b; 16 | } 17 | 18 | static inline int max(int a, int b) 19 | { 20 | return a > b ? a : b; 21 | } 22 | 23 | static int f_long = 0, f_single = 0, f_stream = 0; 24 | 25 | static char* mode_to_str(mode_t m, char* buf) 26 | { 27 | if (S_ISDIR(m)) buf[0] = 'd'; 28 | if (m & S_IRUSR) buf[1] = 'r'; 29 | if (m & S_IWUSR) buf[2] = 'w'; 30 | if (m & S_IXUSR) buf[3] = 'x'; 31 | if (m & S_IRGRP) buf[4] = 'r'; 32 | if (m & S_IWGRP) buf[5] = 'w'; 33 | if (m & S_IXGRP) buf[6] = 'x'; 34 | if (m & S_IROTH) buf[7] = 'r'; 35 | if (m & S_IWOTH) buf[8] = 'w'; 36 | if (m & S_IXOTH) buf[9] = 'x'; 37 | return buf; 38 | } 39 | 40 | static void do_stream(int fd) 41 | { 42 | struct dirent de; 43 | if (readdir(fd, &de, 1) > 0) { 44 | printf("%s", de.d_name); 45 | } 46 | while (readdir(fd, &de, 1) > 0) { 47 | printf(", %s", de.d_name); 48 | } 49 | printf("\n"); 50 | } 51 | 52 | static void do_single(int fd) 53 | { 54 | struct dirent de; 55 | while (readdir(fd, &de, 1) > 0) { 56 | printf("%s\n", de.d_name); 57 | } 58 | } 59 | 60 | static void do_normal(int fd) 61 | { 62 | int count = 0; 63 | int maxcol = 0; 64 | struct dirent de; 65 | while (readdir(fd, &de, 1) > 0) { 66 | maxcol = max(maxcol, strlen(de.d_name)); 67 | } 68 | maxcol = min(maxcol, 80); 69 | if (maxcol == 0) return; 70 | 71 | int ln_max = 80 / maxcol; 72 | char* buf = (char*)malloc(maxcol+1); 73 | buf[maxcol] = 0; 74 | 75 | lseek(fd, 0, SEEK_SET); 76 | while (readdir(fd, &de, 1) > 0) { 77 | memset(buf, ' ', maxcol); 78 | sprintf(buf, "%s", de.d_name); 79 | printf("%s", buf); 80 | if (++count % ln_max == 0) printf("\n"); 81 | } 82 | printf("\n"); 83 | free(buf); 84 | } 85 | 86 | static void do_long_mode(int fd) 87 | { 88 | struct dirent de; 89 | while (readdir(fd, &de, 1) > 0) { 90 | char modes[] = "----------"; 91 | struct stat stbuf; 92 | char name[NAMELEN+1]; 93 | snprintf(name, NAMELEN, "%s/%s", base, de.d_name); 94 | if (lstat(name, &stbuf) == 0) { 95 | printf("%s\t%d\t%d\t%d\t%d\t%s\n", 96 | mode_to_str(stbuf.st_mode, modes), 97 | stbuf.st_uid, stbuf.st_gid, 98 | stbuf.st_size, stbuf.st_mtime, de.d_name); 99 | } 100 | } 101 | } 102 | 103 | int main(int argc, char* const argv[]) 104 | { 105 | char* nm = (char*)malloc(PATHLEN); 106 | base = getcwd(nm, PATHLEN); 107 | if (argc > 1) { 108 | argc--; 109 | argv++; 110 | 111 | for (int i = 0; i < argc; i++) { 112 | auto& av = argv[i]; 113 | if (av[0] && av[0] == '-') { 114 | switch(av[1]) { 115 | case 'l': f_long = 1; break; 116 | case '1': f_single = 1; break; 117 | case 'm': f_stream = 1; break; 118 | } 119 | } else base = av; 120 | } 121 | } 122 | 123 | int fd = open(base, O_RDONLY, 0); 124 | if (fd >= 0) { 125 | if (f_stream) do_stream(fd); 126 | else if (f_long) do_long_mode(fd); 127 | else if (f_single) do_single(fd); 128 | else do_normal(fd); 129 | close(fd); 130 | } 131 | free(nm); 132 | return 0; 133 | } 134 | 135 | -------------------------------------------------------------------------------- /kern/boot.s: -------------------------------------------------------------------------------- 1 | ; This is the kernel's entry point. We could either call main here, 2 | ; or we can use this to setup the stack or other nice stuff, like 3 | ; perhaps setting up the GDT and segments. Please note that interrupts 4 | ; are disabled at this point: More on interrupts later! 5 | [BITS 32] 6 | global start 7 | global _start 8 | global is_cpuid_capable 9 | 10 | extern kernel_main 11 | extern kernel_init 12 | extern __cxa_finalize 13 | extern _init 14 | extern _fini 15 | 16 | ; setup higher-half kernel 17 | KERNEL_VIRTUAL_BASE equ 0xC0000000 18 | KERNEL_PDE_INDEX equ (KERNEL_VIRTUAL_BASE >> 22) 19 | 20 | ; temporary Page Dir (4MB pages) 21 | [section .data] 22 | ALIGN 0x1000 23 | KERNEL_4M_PAGE_ATTR equ 0x83 ; P, RW, PSE(4M Page) 24 | _boot_page_directory_4m: 25 | dd (0 | KERNEL_4M_PAGE_ATTR) 26 | times (KERNEL_PDE_INDEX - 1) dd 0 27 | dd (0 | KERNEL_4M_PAGE_ATTR) 28 | times (1024 - KERNEL_PDE_INDEX - 1) dd 0 29 | 30 | [section .mboot] 31 | ; This part MUST be 4byte aligned, so we solve that issue using 'ALIGN 4' 32 | ALIGN 4 33 | mboot: 34 | ; Multiboot macros to make a few lines later more readable 35 | MULTIBOOT_PAGE_ALIGN equ 1<<0 36 | MULTIBOOT_MEMORY_INFO equ 1<<1 37 | MULTIBOOT_VIDEO_INFO equ 1<<2 38 | MULTIBOOT_HEADER_MAGIC equ 0x1BADB002 39 | MULTIBOOT_HEADER_FLAGS equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO | MULTIBOOT_VIDEO_INFO 40 | MULTIBOOT_CHECKSUM equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) 41 | 42 | ; This is the GRUB Multiboot header. A boot signature 43 | dd MULTIBOOT_HEADER_MAGIC 44 | dd MULTIBOOT_HEADER_FLAGS 45 | dd MULTIBOOT_CHECKSUM 46 | 47 | dd 0, 0, 0, 0, 0 48 | dd 0 ; 0 = set graphics mode 49 | dd 800, 600, 24 ; Width, height, depth 50 | 51 | [section .text] 52 | ; physical address for _start, need it before paing enabled. 53 | start equ (_start - KERNEL_VIRTUAL_BASE) 54 | 55 | _start: 56 | push ebx ; save mbinfo 57 | 58 | call is_cpuid_capable 59 | test eax, eax 60 | jz _no_pse 61 | 62 | mov eax, 01 63 | cpuid 64 | and edx, 0x00000010 ; check PSE 65 | jz _no_pse 66 | 67 | ; enable PSE 68 | mov ecx, cr4 69 | or ecx, 0x00000010 70 | mov cr4, ecx 71 | 72 | mov ecx, (_boot_page_directory_4m - KERNEL_VIRTUAL_BASE) 73 | jmp _pse 74 | 75 | _no_pse: 76 | hlt 77 | 78 | _pse: 79 | mov cr3, ecx 80 | 81 | mov ecx, cr0 82 | or ecx, 0x80000000 ; PG=1 83 | mov cr0, ecx 84 | 85 | ; an absolute jump into virtual address of next instruction 86 | lea ecx, [higher_half_entry] 87 | jmp ecx 88 | 89 | higher_half_entry: 90 | pop ebx ; restore mbinfo, must before invalidating first PDE, 91 | ; cause after invalidation, esp point to invalid low-end mem vaddr 92 | 93 | ; invalidate all PTEs for PDE 0 94 | mov ecx, 1024 95 | mov eax, 0x0 ; Not Present 96 | .flush: 97 | ;; invalidate PDE 0 98 | mov dword [_boot_page_directory_4m], 0 99 | 100 | invlpg [eax] 101 | add eax, 0x1000 102 | loop .flush 103 | 104 | 105 | mov esp, kern_stack_top 106 | 107 | call kernel_init 108 | call _init 109 | 110 | ; cdecl, ebx will keep as it was 111 | add ebx, KERNEL_VIRTUAL_BASE 112 | push ebx 113 | 114 | call kernel_main 115 | call _fini 116 | 117 | sub esp, 4 118 | push 0 119 | call __cxa_finalize 120 | 121 | cli 122 | hlt 123 | jmp $ 124 | 125 | is_cpuid_capable: 126 | ; try to modify ID flag 127 | pushfd 128 | pop eax 129 | mov ecx, eax 130 | xor eax, 0x200000 ; flip ID 131 | push eax 132 | popfd 133 | 134 | ; test if modify success 135 | pushfd 136 | pop eax 137 | xor eax, ecx 138 | shr eax, 21 139 | and eax, 1 140 | push ecx 141 | popfd 142 | ret 143 | 144 | 145 | [section .bootstrap_stack nobits] 146 | _kern_stack: 147 | resb 4096 148 | kern_stack_top: 149 | 150 | -------------------------------------------------------------------------------- /kern/core/isr.cc: -------------------------------------------------------------------------------- 1 | #include "isr.h" 2 | #include "types.h" 3 | #include "task.h" 4 | #include "x86.h" 5 | #include "sched.h" 6 | #include 7 | 8 | /* This is a simple string array. It contains the message that 9 | * * corresponds to each and every exception. We get the correct 10 | * * message by accessing like: 11 | * * exception_message[interrupt_number] */ 12 | const char* exception_messages[] = 13 | { 14 | "Division By Zero", 15 | "Debug", 16 | "Non Maskable Interrupt", 17 | "Breakpoint", 18 | "Into Detected Overflow", 19 | "Out of Bounds", 20 | "Invalid Opcode", 21 | "No Coprocessor", 22 | 23 | "Double Fault", 24 | "Coprocessor Segment Overrun", 25 | "Bad TSS", 26 | "Segment Not Present", 27 | "Stack Fault", 28 | "General Protection Fault", 29 | "Page Fault", 30 | "Unknown Interrupt", 31 | 32 | "Coprocessor Fault", 33 | "Alignment Check", 34 | "Machine Check", 35 | "Reserved", 36 | "Reserved", 37 | "Reserved", 38 | "Reserved", 39 | "Reserved", 40 | 41 | "Reserved", 42 | "Reserved", 43 | "Reserved", 44 | "Reserved", 45 | "Reserved", 46 | "Reserved", 47 | "Reserved", 48 | "Reserved" 49 | }; 50 | 51 | static interrupt_handler isr_handlers[256]; 52 | extern void busy_wait(int millisecs); 53 | 54 | #define IO_PIC1 0x20 // Master (IRQs 0-7) 55 | #define IO_PIC2 0xA0 // Slave (IRQs 8-15) 56 | #define IRQ_SLAVE 2 // IRQ at which slave connects to master 57 | 58 | // Initial IRQ mask has interrupt 2 enabled (for slave 8259A). 59 | static u16 irqmask = 0xFFFF & ~(1<> 8); 66 | } 67 | 68 | void picenable(int irq) 69 | { 70 | if (irq > IRQ_OFFSET) irq -= IRQ_OFFSET; 71 | picsetmask(irqmask & ~(1<isrno < 32) kputs(exception_messages[regs->isrno]); 77 | if (isr_handlers[regs->isrno]) { 78 | interrupt_handler cb = isr_handlers[regs->isrno]; 79 | cb(regs); 80 | return; 81 | } 82 | 83 | kprintf(" regs: ds: 0x%x, edi: 0x%x, esi: 0x%x, ebp: 0x%x, esp: 0x%x\n" 84 | "ebx: 0x%x, edx: 0x%x, ecx: 0x%x, eax: 0x%x, isr: %d, errno: %d\n" 85 | "eip: 0x%x, cs: 0x%x, eflags: 0b%b, useresp: 0x%x, ss: 0x%x\n", 86 | regs->ds, regs->edi, regs->esi, regs->ebp, regs->esp, 87 | regs->ebx, regs->edx, regs->ecx, regs->eax, regs->isrno, regs->errcode, 88 | regs->eip, regs->cs, regs->eflags, regs->useresp, regs->ss); 89 | for(;;) { 90 | asm("cli; hlt"); 91 | } 92 | } 93 | 94 | extern void check_pending_signal(trapframe_t* regs); 95 | void irq_handler(trapframe_t* regs) 96 | { 97 | if (regs->isrno >= 32 && regs->isrno <= 47) { 98 | // Send an EOI (end of interrupt) signal to the PICs. 99 | // If this interrupt involved the slave. 100 | if (regs->isrno >= 40) { 101 | // Send reset signal to slave. 102 | outb(IO_PIC2, 0x20); 103 | } 104 | // Send reset signal to master. (As well as slave, if necessary). 105 | outb(IO_PIC1, 0x20); 106 | } 107 | 108 | if (isr_handlers[regs->isrno]) { 109 | interrupt_handler cb = isr_handlers[regs->isrno]; 110 | cb(regs); 111 | } 112 | 113 | //NOTE: dirty hack, I can not handle situation when preempting happens 114 | //in kernel space. only check signal during returning to the userspace. 115 | if (regs->cs == 0x1b) { 116 | check_pending_signal(regs); 117 | } 118 | 119 | if (regs->isrno == IRQ_TIMER || current->need_resched) { 120 | scheduler(); 121 | } 122 | } 123 | 124 | void register_isr_handler(int isr, interrupt_handler cb) 125 | { 126 | //TODO: check old handler 127 | isr_handlers[isr] = cb; 128 | } 129 | -------------------------------------------------------------------------------- /.ycm_extra_conf.py: -------------------------------------------------------------------------------- 1 | import os 2 | import ycm_core 3 | 4 | flags = [ 5 | '-Wall', 6 | '-std=c++11', 7 | '-m32', 8 | '-x', 9 | 'c++', 10 | '-ffreestanding', 11 | '-O2', 12 | '-Wall', 13 | '-Wextra', 14 | '-fno-exceptions', 15 | '-fno-rtti', 16 | '-I', 17 | '.', 18 | '-I', 19 | './include' 20 | ] 21 | 22 | 23 | # Set this to the absolute path to the folder (NOT the file!) containing the 24 | # compile_commands.json file to use that instead of 'flags'. See here for 25 | # more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html 26 | # 27 | # Most projects will NOT need to set this to anything; you can just change the 28 | # 'flags' list of compilation flags. Notice that YCM itself uses that approach. 29 | compilation_database_folder = '' 30 | 31 | if os.path.exists( compilation_database_folder ): 32 | database = ycm_core.CompilationDatabase( compilation_database_folder ) 33 | else: 34 | database = None 35 | 36 | SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ] 37 | 38 | def DirectoryOfThisScript(): 39 | return os.path.dirname( os.path.abspath( __file__ ) ) 40 | 41 | 42 | def MakeRelativePathsInFlagsAbsolute( flags, working_directory ): 43 | if not working_directory: 44 | return list( flags ) 45 | new_flags = [] 46 | make_next_absolute = False 47 | path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ] 48 | for flag in flags: 49 | new_flag = flag 50 | 51 | if make_next_absolute: 52 | make_next_absolute = False 53 | if not flag.startswith( '/' ): 54 | new_flag = os.path.join( working_directory, flag ) 55 | 56 | for path_flag in path_flags: 57 | if flag == path_flag: 58 | make_next_absolute = True 59 | break 60 | 61 | if flag.startswith( path_flag ): 62 | path = flag[ len( path_flag ): ] 63 | new_flag = path_flag + os.path.join( working_directory, path ) 64 | break 65 | 66 | if new_flag: 67 | new_flags.append( new_flag ) 68 | return new_flags 69 | 70 | 71 | def IsHeaderFile( filename ): 72 | extension = os.path.splitext( filename )[ 1 ] 73 | return extension in [ '.h', '.hxx', '.hpp', '.hh' ] 74 | 75 | 76 | def GetCompilationInfoForFile( filename ): 77 | # The compilation_commands.json file generated by CMake does not have entries 78 | # for header files. So we do our best by asking the db for flags for a 79 | # corresponding source file, if any. If one exists, the flags for that file 80 | # should be good enough. 81 | if IsHeaderFile( filename ): 82 | basename = os.path.splitext( filename )[ 0 ] 83 | for extension in SOURCE_EXTENSIONS: 84 | replacement_file = basename + extension 85 | if os.path.exists( replacement_file ): 86 | compilation_info = database.GetCompilationInfoForFile( 87 | replacement_file ) 88 | if compilation_info.compiler_flags_: 89 | return compilation_info 90 | return None 91 | return database.GetCompilationInfoForFile( filename ) 92 | 93 | 94 | def FlagsForFile( filename, **kwargs ): 95 | if database: 96 | # Bear in mind that compilation_info.compiler_flags_ does NOT return a 97 | # python list, but a "list-like" StringVec object 98 | compilation_info = GetCompilationInfoForFile( filename ) 99 | if not compilation_info: 100 | return None 101 | 102 | final_flags = MakeRelativePathsInFlagsAbsolute( 103 | compilation_info.compiler_flags_, 104 | compilation_info.compiler_working_dir_ ) 105 | 106 | # NOTE: This is just for YouCompleteMe; it's highly likely that your project 107 | # does NOT need to remove the stdlib flag. DO NOT USE THIS IN YOUR 108 | # ycm_extra_conf IF YOU'RE NOT 100% SURE YOU NEED IT. 109 | try: 110 | final_flags.remove( '-stdlib=libc++' ) 111 | except ValueError: 112 | pass 113 | else: 114 | relative_to = DirectoryOfThisScript() 115 | final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to ) 116 | 117 | return { 118 | 'flags': final_flags, 119 | 'do_cache': True 120 | } 121 | -------------------------------------------------------------------------------- /include/gdt.h: -------------------------------------------------------------------------------- 1 | #ifndef _GDT_H 2 | #define _GDT_H 3 | 4 | #include "types.h" 5 | 6 | // This structure contains the value of one GDT entry. 7 | // We use the attribute 'packed' to tell GCC not to change 8 | // any of the alignment in the structure. 9 | struct gdt_entry_ { 10 | u16 limit_low; // The lower 16 bits of the limit. 11 | u16 base_low; // The lower 16 bits of the base. 12 | u8 base_middle; // The next 8 bits of the base. 13 | u8 access; // Access flags, determine what ring this segment can be used in. 14 | u8 granularity; 15 | u8 base_high; // The last 8 bits of the base. 16 | } __attribute__((packed)); 17 | typedef struct gdt_entry_ gdt_entry_t; 18 | 19 | struct gdt_ptr_ 20 | { 21 | u16 limit; // The upper 16 bits of all selector limits. 22 | u32 base; // The address of the first gdt_entry_t struct. 23 | } __attribute__((packed)); 24 | typedef struct gdt_ptr_ gdt_ptr_t; 25 | 26 | //access 27 | #define GDTE_DT_CD (1 << 4) // code or data seg type 28 | #define GDTE_DT_GATE (0 << 4) // system or gate type 29 | #define GDTE_PRESENT(x) ((x) << 7) // present 30 | #define GDTE_DPL(x) ((x & 0x03) << 5) // DPL 31 | 32 | // granularity 33 | #define GDTE_G(x) ((x) << 0xf) // 0 for byte, 1 for 4KB 34 | #define GDTE_SIZE(x) ((x) << 0xe) // 1 for 32bit addr or 4GB bound 35 | 36 | // segment type 37 | #define SEG_DATA_R 0x00 // Read-Only 38 | #define SEG_DATA_RA 0x01 // Read-Only, accessed 39 | #define SEG_DATA_RW 0x02 // Read/Write 40 | #define SEG_DATA_RWA 0x03 // Read/Write, accessed 41 | #define SEG_DATA_REXPD 0x04 // Read-Only, expand-down 42 | #define SEG_DATA_REXPDA 0x05 // Read-Only, expand-down, accessed 43 | #define SEG_DATA_RWEXPD 0x06 // Read/Write, expand-down 44 | #define SEG_DATA_RWEXPDA 0x07 // Read/Write, expand-down, accessed 45 | #define SEG_CODE_E 0x08 // Execute-Only 46 | #define SEG_CODE_EA 0x09 // Execute-Only, accessed 47 | #define SEG_CODE_ER 0x0A // Execute/Read 48 | #define SEG_CODE_ERA 0x0B // Execute/Read, accessed 49 | #define SEG_CODE_EC 0x0C // Execute-Only, conforming 50 | #define SEG_CODE_ECA 0x0D // Execute-Only, conforming, accessed 51 | #define SEG_CODE_ERC 0x0E // Execute/Read, conforming 52 | #define SEG_CODE_ERCA 0x0F // Execute/Read, conforming, accessed 53 | 54 | #define SEG_386TSS 0x09 //386 TSS 55 | 56 | #define GDT_CODE_PL0 GDTE_DT_CD | GDTE_PRESENT(1) | GDTE_SIZE(1) | GDTE_G(1) | \ 57 | SEG_CODE_ER | GDTE_DPL(0) 58 | 59 | #define GDT_DATA_PL0 GDTE_DT_CD | GDTE_PRESENT(1) | GDTE_SIZE(1) | GDTE_G(1) | \ 60 | SEG_DATA_RW | GDTE_DPL(0) 61 | 62 | #define GDT_CODE_PL3 GDTE_DT_CD | GDTE_PRESENT(1) | GDTE_SIZE(1) | GDTE_G(1) | \ 63 | SEG_CODE_ER | GDTE_DPL(3) 64 | 65 | #define GDT_DATA_PL3 GDTE_DT_CD | GDTE_PRESENT(1) | GDTE_SIZE(1) | GDTE_G(1) | \ 66 | SEG_DATA_RW | GDTE_DPL(3) 67 | 68 | #define GDT_TSS_PL3 GDTE_DT_GATE | GDTE_PRESENT(1) | GDTE_SIZE(0) | GDTE_G(0) | \ 69 | SEG_386TSS | GDTE_DPL(3) 70 | 71 | // A struct describing an interrupt gate. 72 | struct idt_entry_s 73 | { 74 | u16 base_lo; // The lower 16 bits of the address to jump to when this interrupt fires. 75 | u16 sel; // Kernel segment selector. 76 | u8 always0; // This must always be zero. 77 | u8 flags; // More flags. See documentation. 78 | u16 base_hi; // The upper 16 bits of the address to jump to. 79 | } __attribute__((packed)); 80 | typedef struct idt_entry_s idt_entry_t; 81 | 82 | // A struct describing a pointer to an array of interrupt handlers. 83 | // This is in a format suitable for giving to 'lidt'. 84 | struct idt_ptr_s 85 | { 86 | u16 limit; 87 | u32 base; // The address of the first element in our idt_entry_t array. 88 | } __attribute__((packed)); 89 | typedef struct idt_ptr_s idt_ptr_t; 90 | 91 | //int gate will reset IF flag, trap gate will not 92 | #define IDTE_INT_GATE 0x0E 93 | #define IDTE_TRAP_GATE 0x0F 94 | 95 | void setup_gdt_entry(int idx, u32 base, u32 limit, u16 mode); 96 | void setup_idt_entry(int idx, u32 base, u16 selector, u8 flags); 97 | 98 | void init_gdt(); 99 | void init_idt(); 100 | 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /kern/drv/ramfs.cc: -------------------------------------------------------------------------------- 1 | #include "vfs.h" 2 | #include "string.h" 3 | #include "ramfs.h" 4 | #include "vm.h" 5 | #include "common.h" 6 | #include "errno.h" 7 | #include 8 | 9 | #define NR_INITRD_FILES 64 10 | #define RAMFS_ENTRY_MAGIC 0xBF 11 | 12 | typedef struct initrd_entry_header 13 | { 14 | unsigned char magic; // The magic number is there to check for consistency. 15 | char name[NAMELEN+1]; 16 | unsigned int offset; // Offset in the initrd the file starts. 17 | unsigned int length; // Length of the file. 18 | } __attribute__((packed)) initrd_entry_header_t; 19 | 20 | typedef struct initrd_header 21 | { 22 | u32 nfiles; 23 | initrd_entry_header_t files[NR_INITRD_FILES]; 24 | } initrd_header_t; 25 | 26 | void Ramfs::init(char* addr, size_t size, const char* cmdline) 27 | { 28 | (void)size; 29 | 30 | int cmd_len = strlen(cmdline); 31 | _cmdline = (char*)vmm.kmalloc(cmd_len+1, 1); 32 | strcpy(_cmdline, cmdline); 33 | 34 | _sb = (initrd_header_t*)addr; 35 | //kprintf("files: %d\n", _sb->nfiles); 36 | 37 | u32 dev = DEVNO(RAMFS_MAJOR, 0); 38 | _iroot = vfs.alloc_inode(dev, 1); 39 | _iroot->ref = 1; 40 | _iroot->dev = dev; 41 | _iroot->type = FsNodeType::Dir; 42 | _iroot->ino = 1; 43 | _iroot->size = 0; 44 | _iroot->blksize = 1; 45 | _iroot->blocks = _iroot->size; 46 | _iroot->fs = this; 47 | 48 | _nr_nodes = _sb->nfiles; 49 | } 50 | 51 | ssize_t Ramfs::read(File * filp, char * buf, size_t count, off_t * offset) 52 | { 53 | inode_t* ip = filp->inode(); 54 | off_t off = filp->off(); 55 | initrd_entry_header* ieh = &_sb->files[ip->ino-2]; 56 | 57 | if (off >= ip->size) return 0; 58 | if (count + off >= ip->size) count = ip->size - off; 59 | 60 | char* data = (char*)_sb + ieh->offset + off; 61 | memcpy(buf, data, count); 62 | 63 | filp->set_off(off + count); 64 | if (offset) *offset = filp->off(); 65 | return count; 66 | } 67 | 68 | ssize_t Ramfs::write(File* filp, const char * buf, size_t count, off_t *offset) 69 | { 70 | inode_t* ip = filp->inode(); 71 | kassert(ip->type == FsNodeType::File); 72 | (void)buf; 73 | (void)count; 74 | (void)offset; 75 | return -EINVAL; 76 | 77 | } 78 | int Ramfs::readdir(File* filp, dentry_t * de, filldir_t) 79 | { 80 | inode_t* ip = filp->inode(); 81 | int id = filp->off() / sizeof(initrd_entry_header_t); 82 | 83 | if (ip->type != FsNodeType::Dir) return -EINVAL; 84 | if (id >= _nr_nodes) return 0; 85 | 86 | initrd_entry_header_t* ieh = &_sb->files[id]; 87 | strcpy(de->name, ieh->name); 88 | 89 | de->ip = vfs.alloc_inode(_iroot->dev, id+2); 90 | if (de->ip->ref == 0) { 91 | de->ip->ref++; 92 | de->ip->ino = id+2; 93 | read_inode(de->ip); 94 | } 95 | 96 | filp->set_off((id+1)*sizeof(initrd_entry_header_t)); 97 | return 1; 98 | } 99 | 100 | dentry_t * Ramfs::lookup(inode_t * dir, dentry_t *de) 101 | { 102 | if (dir->type != FsNodeType::Dir) return NULL; 103 | 104 | int i = -1; 105 | for (i = 0; i < _nr_nodes; ++i) { 106 | initrd_entry_header* dp = &_sb->files[i]; 107 | if (strncmp(de->name, dp->name, NAMELEN) == 0) { 108 | break; 109 | } 110 | } 111 | 112 | if (i >= _nr_nodes) return NULL; 113 | de->ip = vfs.alloc_inode(_iroot->dev, i+2); 114 | if (de->ip->ref == 0) { 115 | de->ip->ref++; 116 | de->ip->ino = i+2; 117 | read_inode(de->ip); 118 | } 119 | 120 | return de; 121 | } 122 | 123 | void Ramfs::read_inode(inode_t *ip) 124 | { 125 | int i = ip->ino; 126 | if (i == 1) { 127 | memcpy(ip, _iroot, sizeof *ip); 128 | } else if (i > 1 && i <= _nr_nodes+1) { 129 | initrd_entry_header* de = &_sb->files[i-2]; 130 | kassert(de->magic == RAMFS_ENTRY_MAGIC); 131 | ip->size = de->length; 132 | ip->blksize = 1; 133 | ip->blocks = ip->size; 134 | ip->dev = DEVNO(RAMFS_MAJOR, 0); 135 | ip->type = FsNodeType::File; 136 | ip->data = 0; 137 | ip->fs = this; 138 | } 139 | } 140 | 141 | FileSystem* create_ramfs(const void* data) 142 | { 143 | auto* info = (ramfs_mod_info_t*)data; 144 | auto* ramfs = new Ramfs; 145 | ramfs->init(info->addr, info->size, info->cmdline); 146 | return ramfs; 147 | } 148 | 149 | -------------------------------------------------------------------------------- /kern/core/syscall.cc: -------------------------------------------------------------------------------- 1 | #include "syscall.h" 2 | #include "string.h" 3 | #include "isr.h" 4 | #include "task.h" 5 | #include "spinlock.h" 6 | #include "sys.h" 7 | 8 | typedef int (*syscall0_t)(); 9 | typedef int (*syscall1_t)(u32); 10 | typedef int (*syscall2_t)(u32, u32); 11 | typedef int (*syscall3_t)(u32, u32, u32); 12 | typedef int (*syscall4_t)(u32, u32, u32, u32); 13 | 14 | #define do_syscall0(fn) fn() 15 | #define do_syscall1(fn, arg0) fn(arg0) 16 | #define do_syscall2(fn, arg0, arg1) fn(arg0, arg1) 17 | #define do_syscall3(fn, arg0, arg1, arg2) fn(arg0, arg1, arg2) 18 | #define do_syscall4(fn, arg0, arg1, arg2, arg3) fn(arg0, arg1, arg2, arg3) 19 | 20 | static struct syscall_info_s { 21 | void* call; 22 | int nr_args; 23 | 24 | } syscalls[NR_SYSCALL]; 25 | 26 | Spinlock syscallock {"syscall"}; 27 | 28 | 29 | extern void check_pending_signal(trapframe_t* regs); 30 | static void syscall_handler(trapframe_t* regs) 31 | { 32 | auto oflags = syscallock.lock(); 33 | current->regs = regs; 34 | syscallock.release(oflags); 35 | 36 | if (regs->eax >= NR_SYSCALL) { 37 | kprintf("invalid syscall number: %d\n", regs->eax); 38 | regs->eax = -1; 39 | return; 40 | } 41 | 42 | struct syscall_info_s info = syscalls[regs->eax]; 43 | if (!info.call) { 44 | return; 45 | } 46 | 47 | switch(info.nr_args) { 48 | case 0: 49 | { 50 | syscall0_t fn = (syscall0_t)info.call; 51 | regs->eax = do_syscall0(fn); 52 | break; 53 | } 54 | 55 | case 1: 56 | { 57 | syscall1_t fn = (syscall1_t)info.call; 58 | if (regs->eax == SYS_sigreturn) { 59 | regs->eax = do_syscall1(fn, (uint32_t)regs); 60 | } else 61 | regs->eax = do_syscall1(fn, regs->ebx); 62 | break; 63 | } 64 | 65 | case 2: 66 | { 67 | syscall2_t fn = (syscall2_t)info.call; 68 | regs->eax = do_syscall2(fn, regs->ebx, regs->ecx); 69 | break; 70 | } 71 | 72 | case 3: 73 | { 74 | syscall3_t fn = (syscall3_t)info.call; 75 | regs->eax = do_syscall3(fn, regs->ebx, regs->ecx, 76 | regs->edx); 77 | break; 78 | } 79 | 80 | case 4: 81 | { 82 | syscall4_t fn = (syscall4_t)info.call; 83 | regs->eax = do_syscall4(fn, regs->ebx, regs->ecx, 84 | regs->edx, regs->esi); 85 | break; 86 | } 87 | 88 | default: panic("SYSCALL crash\n"); 89 | } 90 | 91 | if (regs->cs == 0x1b) check_pending_signal(regs); 92 | } 93 | 94 | void init_syscall() 95 | { 96 | memset(syscalls, 0, sizeof(syscalls)); 97 | 98 | syscalls[SYS_open] = { (void*)sys_open, 3 }; 99 | syscalls[SYS_close] = { (void*)sys_close, 1 }; 100 | syscalls[SYS_write] = { (void*)sys_write, 3 }; 101 | syscalls[SYS_read] = { (void*)sys_read, 3 }; 102 | syscalls[SYS_readdir] = { (void*)sys_readdir, 3 }; 103 | syscalls[SYS_fork] = { (void*)sys_fork, 0 }; 104 | syscalls[SYS_sleep] = { (void*)sys_sleep, 1 }; 105 | syscalls[SYS_getpid] = { (void*)sys_getpid, 0 }; 106 | syscalls[SYS_getppid] = { (void*)sys_getppid, 0 }; 107 | syscalls[SYS_exec] = { (void*)sys_execve, 3 }; 108 | syscalls[SYS_wait] = { (void*)sys_wait, 1 }; 109 | syscalls[SYS_waitpid] = { (void*)sys_waitpid, 3 }; 110 | syscalls[SYS_exit] = { (void*)sys_exit, 1 }; 111 | syscalls[SYS_mount] = { (void*)sys_mount, 5 }; 112 | syscalls[SYS_umount] = { (void*)sys_unmount, 1 }; 113 | syscalls[SYS_dup] = { (void*)sys_dup, 1 }; 114 | syscalls[SYS_dup2] = { (void*)sys_dup2, 2 }; 115 | syscalls[SYS_pipe] = { (void*)sys_pipe, 1 }; 116 | syscalls[SYS_kdump] = { (void*)sys_kdump, 0 }; 117 | syscalls[SYS_sbrk] = { (void*)sys_sbrk, 1 }; 118 | syscalls[SYS_lseek] = { (void*)sys_lseek, 3 }; 119 | syscalls[SYS_fstat] = { (void*)sys_fstat, 2 }; 120 | syscalls[SYS_stat] = { (void*)sys_stat, 2 }; 121 | syscalls[SYS_lstat] = { (void*)sys_lstat, 2 }; 122 | syscalls[SYS_kill] = { (void*)sys_kill, 2 }; 123 | syscalls[SYS_signal] = { (void*)sys_signal, 2 }; 124 | syscalls[SYS_sigaction] = { (void*)sys_sigaction, 3 }; 125 | syscalls[SYS_sigpending] = { (void*)sys_sigpending, 1 }; 126 | syscalls[SYS_sigprocmask] = { (void*)sys_sigprocmask, 3 }; 127 | syscalls[SYS_sigsuspend] = { (void*)sys_sigsuspend, 1 }; 128 | syscalls[SYS_sigreturn] = { (void*)sys_sigreturn, 1 }; 129 | syscalls[SYS_chdir] = { (void*)sys_chdir, 1 }; 130 | syscalls[SYS_fchdir] = { (void*)sys_fchdir, 1 }; 131 | syscalls[SYS_getcwd] = { (void*)sys_getcwd, 2 }; 132 | 133 | register_isr_handler(ISR_SYSCALL, syscall_handler); 134 | } 135 | 136 | -------------------------------------------------------------------------------- /kern/core/gdt.cc: -------------------------------------------------------------------------------- 1 | #include "gdt.h" 2 | #include "x86.h" 3 | #include "string.h" 4 | #include "task.h" 5 | 6 | BEGIN_CDECL 7 | 8 | // Lets us access our ASM functions from our C code. 9 | void gdt_flush(u32); 10 | void idt_flush(u32); 11 | 12 | void isr0(); 13 | void isr1(); 14 | void isr2(); 15 | void isr3(); 16 | void isr4(); 17 | void isr5(); 18 | void isr6(); 19 | void isr7(); 20 | void isr8(); 21 | void isr9(); 22 | void isr10(); 23 | void isr11(); 24 | void isr12(); 25 | void isr13(); 26 | void isr14(); 27 | void isr15(); 28 | void isr16(); 29 | void isr17(); 30 | void isr18(); 31 | void isr19(); 32 | void isr20(); 33 | void isr21(); 34 | void isr22(); 35 | void isr23(); 36 | void isr24(); 37 | void isr25(); 38 | void isr26(); 39 | void isr27(); 40 | void isr28(); 41 | void isr29(); 42 | void isr30(); 43 | void isr31(); 44 | 45 | void isr128(); 46 | 47 | void irq0(); 48 | void irq1(); 49 | void irq2(); 50 | void irq3(); 51 | void irq4(); 52 | void irq5(); 53 | void irq6(); 54 | void irq7(); 55 | void irq8(); 56 | void irq9(); 57 | void irq10(); 58 | void irq11(); 59 | void irq12(); 60 | void irq13(); 61 | void irq14(); 62 | void irq15(); 63 | 64 | END_CDECL 65 | 66 | // may need TSS entry later 67 | gdt_entry_t gdt_entries[6]; 68 | tss_entry_t shared_tss; 69 | 70 | gdt_ptr_t gdt_ptr; 71 | idt_entry_t idt_entries[256]; 72 | idt_ptr_t idt_ptr; 73 | 74 | void init_gdt() 75 | { 76 | gdt_ptr.limit = sizeof(gdt_entries) - 1; 77 | gdt_ptr.base = (u32)&gdt_entries; // linear base of GDT 78 | 79 | setup_gdt_entry(SEG_NULL, 0, 0, 0); 80 | setup_gdt_entry(SEG_KCODE, 0, 0xffffffff, GDT_CODE_PL0); 81 | setup_gdt_entry(SEG_KDATA, 0, 0xffffffff, GDT_DATA_PL0); 82 | setup_gdt_entry(SEG_UCODE, 0, 0xffffffff, GDT_CODE_PL3); 83 | setup_gdt_entry(SEG_UDATA, 0, 0xffffffff, GDT_DATA_PL3); 84 | 85 | gdt_flush((u32)&gdt_ptr); 86 | } 87 | 88 | #define SETUP_GATE(i) \ 89 | setup_idt_entry(i, (u32)isr##i, 0x08, GDTE_PRESENT(1) | GDTE_DPL(0) | IDTE_INT_GATE) 90 | 91 | #define SETUP_IRQ(i, j) \ 92 | setup_idt_entry(j, (u32)irq##i, 0x08, GDTE_PRESENT(1) | GDTE_DPL(0) | IDTE_INT_GATE) 93 | 94 | void init_idt() 95 | { 96 | // reprogram PICs 97 | // Remap the irq table. 98 | outb(0x20, 0x11); 99 | outb(0xA0, 0x11); 100 | outb(0x21, 0x20); 101 | outb(0xA1, 0x28); 102 | outb(0x21, 0x04); 103 | outb(0xA1, 0x02); 104 | outb(0x21, 0x01); 105 | outb(0xA1, 0x01); 106 | outb(0x21, 0x0); 107 | outb(0xA1, 0x0); 108 | 109 | idt_ptr.limit = sizeof(idt_entries) - 1; 110 | idt_ptr.base = (u32)&idt_entries; 111 | 112 | memset(&idt_entries, 0, sizeof(idt_entries)); 113 | 114 | SETUP_GATE(0); 115 | SETUP_GATE(1); 116 | SETUP_GATE(2); 117 | SETUP_GATE(3); 118 | SETUP_GATE(4); 119 | SETUP_GATE(5); 120 | SETUP_GATE(6); 121 | SETUP_GATE(7); 122 | SETUP_GATE(8); 123 | SETUP_GATE(9); 124 | SETUP_GATE(10); 125 | SETUP_GATE(11); 126 | SETUP_GATE(12); 127 | SETUP_GATE(13); 128 | SETUP_GATE(14); 129 | SETUP_GATE(15); 130 | SETUP_GATE(16); 131 | SETUP_GATE(17); 132 | SETUP_GATE(18); 133 | SETUP_GATE(19); 134 | SETUP_GATE(20); 135 | SETUP_GATE(21); 136 | SETUP_GATE(22); 137 | SETUP_GATE(23); 138 | SETUP_GATE(24); 139 | SETUP_GATE(26); 140 | SETUP_GATE(27); 141 | SETUP_GATE(28); 142 | SETUP_GATE(29); 143 | SETUP_GATE(30); 144 | SETUP_GATE(31); 145 | 146 | // 0x80 for syscall 147 | setup_idt_entry(0x80, (u32)isr128, 0x08, 148 | GDTE_PRESENT(1) | GDTE_DPL(3) | IDTE_TRAP_GATE); 149 | 150 | SETUP_IRQ(0, 32); 151 | SETUP_IRQ(1, 33); 152 | SETUP_IRQ(2, 34); 153 | SETUP_IRQ(3, 35); 154 | SETUP_IRQ(4, 36); 155 | SETUP_IRQ(5, 37); 156 | SETUP_IRQ(6, 38); 157 | SETUP_IRQ(7, 39); 158 | 159 | SETUP_IRQ(8, 40); 160 | SETUP_IRQ(9, 41); 161 | SETUP_IRQ(10, 42); 162 | SETUP_IRQ(11, 43); 163 | SETUP_IRQ(12, 44); 164 | SETUP_IRQ(13, 45); 165 | SETUP_IRQ(14, 46); 166 | SETUP_IRQ(15, 47); 167 | 168 | idt_flush((u32)&idt_ptr); 169 | } 170 | 171 | #undef SETUP_GATE 172 | 173 | void setup_gdt_entry(int idx, u32 base, u32 limit, u16 mode) 174 | { 175 | gdt_entry_t* p = &gdt_entries[idx]; 176 | p->limit_low = (limit & 0xffff); 177 | p->base_low = (base & 0xffff); 178 | p->base_middle = (base >>16) & 0xff; 179 | p->access = mode & 0xff; 180 | p->granularity = ((mode >> 8) & 0xf0) | ((limit >> 16) & 0x0f); 181 | p->base_high = (base >> 24) & 0xff; 182 | } 183 | 184 | void setup_idt_entry(int idx, u32 base, u16 selector, u8 flags) 185 | { 186 | idt_entry_t *p = &idt_entries[idx]; 187 | p->base_lo = (base & 0xffff); 188 | p->always0 = 0; 189 | p->flags = flags; 190 | p->sel = selector; 191 | p->base_hi = (base >> 16) & 0xffff; 192 | } 193 | 194 | void setup_tss(u32 stack) 195 | { 196 | memset(&shared_tss, 0, sizeof(shared_tss)); 197 | shared_tss.ss0 = SEG_KDATA<<3; 198 | shared_tss.esp0 = (u32)stack; 199 | 200 | setup_gdt_entry(SEG_TSS, (u32)&shared_tss, sizeof(shared_tss), GDT_TSS_PL3); 201 | } 202 | 203 | -------------------------------------------------------------------------------- /lib/string.cc: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | void * memcpy(void * dst, const void * src, size_t n) 4 | { 5 | asm ( 6 | "cld \n" 7 | "rep movsb \n" 8 | ::"D"(dst), "S"(src), "c"(n): "cc", "memory"); 9 | return dst; 10 | } 11 | 12 | void* memmove(void* dst, const void * src, size_t n) 13 | { 14 | if (dst < src) { 15 | asm ( 16 | "cld \n" 17 | "rep movsb \n" 18 | ::"D"(dst), "S"(src), "c"(n): "cc", "memory"); 19 | } else { 20 | asm ( 21 | "std \n" 22 | "rep movsb \n" 23 | ::"D"((char*)dst+n-1), "S"((char*)src+n-1), "c"(n): "cc", "memory"); 24 | } 25 | return dst; 26 | } 27 | 28 | void* memset(void* dst, int c, size_t count) 29 | { 30 | asm ( 31 | "cld \n" 32 | "rep stosb \n" 33 | ::"D"(dst), "a"(c), "c"(count): "cc", "memory"); 34 | return dst; 35 | } 36 | 37 | int memcmp(const void *s1, const void * s2, size_t count) 38 | { 39 | register int ret asm ("eax"); 40 | asm ( 41 | "cld \n" 42 | "repe cmpsb \n" 43 | "je 1f \n" 44 | "movl $1, %0 \n" 45 | "jl 1f \n" 46 | "negl %0 \n" 47 | "1: " 48 | :"=a"(ret):"0"(0), "D"(s1), "S"(s2), "c"(count)); 49 | return ret; 50 | } 51 | 52 | 53 | size_t strlen(const char* s) 54 | { 55 | register size_t ret asm ("ecx"); 56 | asm ( 57 | "cld \n" 58 | "repne scasb \n" 59 | "notl %0 \n" 60 | "decl %0 " 61 | :"=c"(ret):"a"(0), "D"(s), "0"(-1)); 62 | return ret; 63 | } 64 | 65 | char* strcpy(char* dst, const char* src) 66 | { 67 | asm ( 68 | "cld \n" 69 | "1:lodsb \n" 70 | "stosb \n" 71 | "testb %%al, %%al \n" 72 | "jnz 1b " 73 | ::"D"(dst), "S"(src) 74 | :"eax"); 75 | return dst; 76 | } 77 | 78 | char* strncpy(char* dst, const char* src, size_t count) 79 | { 80 | asm ( 81 | "cld \n" 82 | "1: decl %2 \n" 83 | "js 2f \n" 84 | "lodsb \n" 85 | "stosb \n" 86 | "testb %%al, %%al \n" 87 | "jne 1b \n" 88 | "rep stosb \n" 89 | "2: " 90 | ::"D"(dst), "S"(src), "c"(count) 91 | :"eax"); 92 | return dst; 93 | } 94 | 95 | char * strcat(char * dst, const char *src) 96 | { 97 | asm ( 98 | "cld \n" 99 | "repne scasb \n" // reach end of dst 100 | "decl %0 \n" 101 | "1: lodsb \n" 102 | "stosb \n" 103 | "test %%al, %%al \n" 104 | "jnz 1b \n" 105 | ::"D"(dst), "S"(src), "a"(0), "c"(0xffffffff)); 106 | return dst; 107 | } 108 | 109 | char * strncat(char * dst, const char *src, size_t count) 110 | { 111 | asm ( 112 | "cld \n" 113 | "repne scasb \n" // reach end of dst 114 | "decl %0 \n" 115 | "mov %4, %3 \n" 116 | "1: decl %3 \n" 117 | "js 2f \n" 118 | "lodsb \n" 119 | "stosb \n" 120 | "test %%al, %%al \n" 121 | "jnz 1b \n" 122 | "2: xor %2, %2 \n" 123 | "stosb " 124 | ::"D"(dst), "S"(src), "a"(0), "c"(0xffffffff), "g"(count)); 125 | return dst; 126 | } 127 | 128 | int strcmp(const char *s1, const char *s2) 129 | { 130 | register int ret asm("eax"); 131 | asm ( 132 | "cld \n" 133 | "1: lodsb \n" 134 | "scasb \n" 135 | "jne 2f \n" 136 | "testb %%al, %%al \n" 137 | "jnz 1b \n" 138 | "xorl %%eax, %%eax \n" 139 | "jmp 3f \n" 140 | "2: movl $1, %0 \n" 141 | "jg 3f \n" 142 | "negl %0 \n" 143 | "3: " 144 | :"=a"(ret) :"S"(s1), "D"(s2)); 145 | return ret; 146 | } 147 | 148 | int strncmp(const char *s1, const char *s2, size_t count) 149 | { 150 | register int ret asm("eax"); 151 | asm ( 152 | "cld \n" 153 | "1: decl %3 \n" 154 | "js 2f \n" 155 | "lodsb \n" 156 | "scasb \n" 157 | "jne 3f \n" 158 | "testb %%al, %%al \n" 159 | "jne 1b \n" 160 | "2: xorl %%eax, %%eax \n" 161 | "jmp 4f \n" 162 | "3: movl $1, %0 \n" 163 | "jg 4f \n" 164 | "negl %0 \n" 165 | "4: " 166 | :"=a"(ret) :"S"(s1), "D"(s2), "c"(count)); 167 | return ret; 168 | } 169 | 170 | char* strchr(const char *s, int c) 171 | { 172 | char* ret = 0; 173 | asm ( 174 | "cld \n" 175 | "1: lodsb \n" 176 | "cmpb %%al, %%dl \n" 177 | "je 2f \n" 178 | "testb %%al, %%al \n" 179 | "jne 1b \n" 180 | "movl $1, %0 \n" 181 | "2: decl %0 \n" 182 | :"=S"(ret):"d"(c), "S"(s) 183 | :"al" 184 | ); 185 | return ret; 186 | } 187 | 188 | char* strrchr(const char *s, int c) 189 | { 190 | char* ret = 0; 191 | asm ( 192 | "cld \n" 193 | "movb %%al, %%ah \n" 194 | "1: lodsb \n" 195 | "cmpb %%al, %%ah \n" 196 | "jne 2f \n" 197 | "movl %2, %0 \n" 198 | "decl %0 \n" 199 | "2: testb %%al, %%al \n" 200 | "jne 1b \n" 201 | :"=d"(ret):"0"(0), "S"(s), "a"(c) 202 | ); 203 | return ret; 204 | } 205 | 206 | 207 | -------------------------------------------------------------------------------- /include/mmu.h: -------------------------------------------------------------------------------- 1 | #ifndef _MMU_H 2 | #define _MMU_H 3 | 4 | #include "types.h" 5 | 6 | // This file contains definitions for the 7 | // x86 memory management unit (MMU). 8 | 9 | // Control Register flags 10 | #define CR0_PE 0x00000001 // Protection Enable 11 | #define CR0_MP 0x00000002 // Monitor coProcessor 12 | #define CR0_EM 0x00000004 // Emulation 13 | #define CR0_TS 0x00000008 // Task Switched 14 | #define CR0_ET 0x00000010 // Extension Type 15 | #define CR0_NE 0x00000020 // Numeric Errror 16 | #define CR0_WP 0x00010000 // Write Protect 17 | #define CR0_AM 0x00040000 // Alignment Mask 18 | #define CR0_NW 0x20000000 // Not Writethrough 19 | #define CR0_CD 0x40000000 // Cache Disable 20 | #define CR0_PG 0x80000000 // Paging 21 | 22 | #define CR4_PSE 0x00000010 // Page size extension 23 | 24 | // GDT Segment index 25 | #define SEG_NULL 0 // NULL 26 | #define SEG_KCODE 1 // kernel code 27 | #define SEG_KDATA 2 // kernel data+stack 28 | #define SEG_UCODE 3 // user code 29 | #define SEG_UDATA 4 // user data+stack 30 | #define SEG_TSS 5 // this process's task state 31 | 32 | 33 | // A virtual address 'la' has a three-part structure as follows: 34 | // 35 | // +--------10------+-------10-------+---------12----------+ 36 | // | Page Directory | Page Table | Offset within Page | 37 | // | Index | Index | | 38 | // +----------------+----------------+---------------------+ 39 | // \--- PDX(va) --/ \--- PTX(va) --/ 40 | 41 | 42 | typedef struct page_s { 43 | u32 present : 1; // Page present in memory 44 | u32 rw : 1; // Read-only if clear, readwrite if set 45 | u32 user : 1; // Supervisor level only if clear 46 | u32 accessed : 1; // Has the page been accessed since last refresh? 47 | u32 dirty : 1; // Has the page been written to since last refresh? 48 | u32 unused : 7; // Amalgamation of unused and reserved bits 49 | u32 frame : 20; // Frame address (shifted right 12 bits) 50 | } page_t; 51 | 52 | typedef struct page_table_s { 53 | page_t pages[1024]; 54 | } page_table_t; 55 | 56 | // for PDE and PTE 57 | enum PAGE_PDE_FLAGS { 58 | PDE_PRESENT = 0x01, 59 | PDE_WRITABLE = 0x02, 60 | PDE_USER = 0x04, 61 | PDE_PWT = 0x08, 62 | PDE_PCD = 0x10, 63 | PDE_ACCESSED = 0x20, 64 | PDE_DIRTY = 0x40, 65 | PDE_4MB = 0x80, 66 | PDE_FRAME = 0xFFFFF000 67 | }; 68 | 69 | #define pde_set_flag(pde, flag) ((pde) |= (flag)) 70 | #define pde_get_flags(pde) (((u32)pde) & ~PDE_FRAME) 71 | #define pde_set_frame(pde, frame) (pde = ((pde) & ~PDE_FRAME) | (u32)frame) 72 | 73 | typedef u32 pde_t; 74 | 75 | typedef struct page_directory_s { 76 | pde_t tables[1024]; 77 | } page_directory_t; 78 | 79 | 80 | #define PGSHIFT 12 // log2(PGSIZE) 81 | #define PTXSHIFT 12 // offset of PTX in a linear address 82 | #define PDXSHIFT 22 // offset of PDX in a linear address 83 | #define PGSIZE 4096 // bytes mapped by a page 84 | 85 | #define PAGE_DIR_IDX(vaddr) ((((u32)vaddr) >> PDXSHIFT) & 0x3ff) 86 | #define PAGE_TABLE_IDX(vaddr) ((((u32)vaddr) >> PTXSHIFT) & 0x3ff) 87 | #define PAGE_ENTRY_OFFSET(vaddr) (((u32)vaddr) & 0x00000fff) 88 | 89 | #define PGROUNDUP(sz) ((((u32)sz)+PGSIZE-1) & ~(PGSIZE-1)) 90 | #define PGROUNDDOWN(a) (((u32)a) & ~(PGSIZE-1)) 91 | 92 | #define PDE_GET_TABLE_PHYSICAL(pde) (((pde_t)pde) & 0xfffff000) 93 | 94 | // construct virtual address from indexes and offset 95 | #define PGADDR(d, t, o) ((uint)((d) << PDXSHIFT | (t) << PTXSHIFT | (o))) 96 | 97 | #define A2I(addr) ((u32)(unsigned long)(addr)) 98 | #define I2A(paddr) ((void*)(unsigned long)(paddr)) 99 | 100 | struct tss_entry_ 101 | { 102 | u32 prev_tss; // The previous TSS - if we used hardware task switching this would form a linked list. 103 | u32 esp0; // The stack pointer to load when we change to kernel mode. 104 | u16 ss0; // The stack segment to load when we change to kernel mode. 105 | u16 pad1; 106 | u32 esp1; // Unused... 107 | u16 ss1; 108 | u16 pad3; 109 | u32 esp2; 110 | u16 ss2; 111 | u16 pad5; 112 | 113 | u32 cr3; 114 | u32 eip; 115 | u32 eflags; 116 | u32 eax; 117 | u32 ecx; 118 | u32 edx; 119 | u32 ebx; 120 | u32 esp; 121 | u32 ebp; 122 | u32 esi; 123 | u32 edi; 124 | 125 | u16 es; // The value to load into ES when we change to kernel mode. 126 | u16 pad6; 127 | u16 cs; // The value to load into CS when we change to kernel mode. 128 | u16 pad7; 129 | u16 ss; // The value to load into SS when we change to kernel mode. 130 | u16 pad8; 131 | u16 ds; // The value to load into DS when we change to kernel mode. 132 | u16 pad9; 133 | u16 fs; // The value to load into FS when we change to kernel mode. 134 | u16 pad10; 135 | u16 gs; // The value to load into GS when we change to kernel mode. 136 | u16 pad11; 137 | u16 ldt; // Unused... 138 | u16 pad12; 139 | u16 trap; 140 | u16 iomap_base; 141 | }; 142 | 143 | typedef struct tss_entry_ tss_entry_t; 144 | 145 | #endif 146 | -------------------------------------------------------------------------------- /user/libc/malloc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | BEGIN_CDECL 7 | 8 | #define PGSIZE 4096 9 | 10 | // very first brk 11 | static void* __data_end = NULL; 12 | static void* __kheap_ptr = NULL; 13 | 14 | #define KHEAD_SIZE 20 // ignore data field 15 | #define ALIGN(sz, align) ((((u32)(sz)-1)/(align))*(align)+(align)) 16 | 17 | struct kheap_block_head 18 | { 19 | u32 size; 20 | struct kheap_block_head* prev; 21 | struct kheap_block_head* next; 22 | void* ptr; 23 | u32 used; 24 | char data[1]; 25 | }; 26 | 27 | static void* ksbrk(size_t size) 28 | { 29 | if (!__data_end) { 30 | __data_end = sbrk(0); 31 | } 32 | void* ptr = sbrk(size); 33 | if ((int)ptr == -1) { 34 | printf("ksbrk failed\n"); 35 | return NULL; 36 | } 37 | 38 | kheap_block_head* newh = (kheap_block_head*)ptr; 39 | newh->used = 0; 40 | newh->next = newh->prev = NULL; 41 | newh->size = size - KHEAD_SIZE; 42 | newh->ptr = newh->data; 43 | 44 | return ptr; 45 | } 46 | 47 | static void split_block(kheap_block_head* h, size_t size) 48 | { 49 | kheap_block_head *b = (kheap_block_head*)(h->data + size); 50 | b->used = 0; 51 | b->size = h->size - size - KHEAD_SIZE; 52 | b->ptr = b->data; 53 | 54 | b->next = h->next; 55 | h->next = b; 56 | b->prev = h; 57 | 58 | if (b->next) b->next->prev = b; 59 | h->size = size; 60 | } 61 | 62 | 63 | static kheap_block_head* align_block(kheap_block_head* h, int align) 64 | { 65 | auto newh = (kheap_block_head*)(ALIGN(&h->data, align)-KHEAD_SIZE); 66 | int gap = (char*)newh - (char*)h; 67 | // kprintf("aligned %x to 0x%x, gap = %d\n", h, newh, gap); 68 | if (gap >= KHEAD_SIZE+4) { 69 | split_block(h, gap-KHEAD_SIZE); 70 | h = h->next; 71 | 72 | } else { 73 | //drop little memory, which cause frag that never can be regain 74 | if (h == __kheap_ptr) __kheap_ptr = newh; 75 | else if (h->prev) { 76 | auto prev = h->prev; 77 | prev->size += gap; 78 | prev->next = newh; 79 | } 80 | if (h->next) h->next->prev = newh; 81 | // h and newh may overlay, so copy aside 82 | kheap_block_head tmp = *h; 83 | *newh = tmp; 84 | newh->size -= gap; 85 | newh->ptr = newh->data; 86 | } 87 | return newh; 88 | } 89 | 90 | // merge h with next 91 | static kheap_block_head* merge_block(kheap_block_head* h) 92 | { 93 | if (h->next->used) return h; 94 | 95 | auto next = h->next; 96 | h->size += KHEAD_SIZE + next->size; 97 | h->next = next->next; 98 | if (h->next) h->next->prev = h; 99 | return h; 100 | } 101 | 102 | static kheap_block_head* find_block(kheap_block_head** last, size_t size, int align) 103 | { 104 | kheap_block_head* p = (kheap_block_head*)__kheap_ptr; 105 | while (p && !(p->used == 0 && p->size >= size + (ALIGN(p->data, align) - (u32)p->data))) { 106 | *last = p; 107 | p = p->next; 108 | } 109 | 110 | return p; 111 | } 112 | 113 | static bool aligned(void* ptr, int align) 114 | { 115 | return ((u32)ptr & (align-1)) == 0; 116 | } 117 | 118 | void* calloc(size_t count, size_t size) 119 | { 120 | size_t sz = count * size; 121 | if (sz == 0 || count == 0) return NULL; 122 | void* ptr = malloc(sz); 123 | memset(ptr, 0, sz); 124 | return ptr; 125 | } 126 | 127 | void free(void *ptr) 128 | { 129 | if (!ptr) return; 130 | kheap_block_head* h = (kheap_block_head*)((char*)ptr - KHEAD_SIZE); 131 | 132 | h->used = 0; 133 | if (h->prev && h->prev->used == 0) { 134 | h = merge_block(h->prev); 135 | } 136 | 137 | if (h->next) { 138 | h = merge_block(h); 139 | } 140 | } 141 | 142 | #define PGROUNDUP(sz) ((((u32)sz)+PGSIZE-1) & ~(PGSIZE-1)) 143 | 144 | void* malloc(size_t size) 145 | { 146 | if (!__kheap_ptr) __kheap_ptr = ksbrk(PGSIZE); 147 | 148 | size_t realsize = size; 149 | int align = 4; 150 | 151 | kheap_block_head* last = NULL; 152 | kheap_block_head* h = find_block(&last, realsize, align); 153 | if (!h) { 154 | char* end = (char*)last->data + last->size; 155 | realsize += ALIGN(end + KHEAD_SIZE, align) - (u32)end; 156 | h = (kheap_block_head*)ksbrk(PGROUNDUP(realsize)); 157 | if (!h) { 158 | return NULL; 159 | } 160 | 161 | last->next = h; 162 | h->prev = last; 163 | 164 | if (h->prev && h->prev->used == 0) { 165 | h = merge_block(h->prev); 166 | } 167 | } 168 | 169 | if (!aligned(h->data, align)) { 170 | h = align_block(h, align); 171 | } 172 | 173 | if (h->size - realsize >= KHEAD_SIZE + 4) { 174 | split_block(h, realsize); 175 | } 176 | 177 | h->used = 1; 178 | return h->data; 179 | } 180 | 181 | void* realloc(void *ptr, size_t size) 182 | { 183 | if (!ptr) return malloc(size); 184 | kheap_block_head* h = (kheap_block_head*)((char*)ptr - KHEAD_SIZE); 185 | //sanity check 186 | if (h->used == 0 || h->ptr != h->data) { 187 | return NULL; 188 | } 189 | 190 | if (h->size >= size) return ptr; 191 | size = size ? size : 1; 192 | void* newptr = malloc(size); 193 | if (!newptr) return NULL; 194 | memcpy(newptr, ptr, h->size); 195 | free(ptr); 196 | return newptr; 197 | } 198 | 199 | END_CDECL 200 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CROSS_PATH = /Users/sonald/crossgcc/bin 2 | CXX = $(CROSS_PATH)/i686-elf-g++ 3 | CPP = $(CROSS_PATH)/i686-elf-cpp 4 | CC = $(CROSS_PATH)/i686-elf-gcc 5 | CXXFLAGS = -std=c++11 -g -I./include -ffreestanding \ 6 | -O2 -Wall -Wextra -fno-exceptions -fno-rtti -DDEBUG -fno-strict-aliasing -D__sos__ -D_SOS_KERNEL_ 7 | DISKIMG=hd.img 8 | 9 | USER_FLAGS = -std=c++11 -I./include -I./user/libc -ffreestanding \ 10 | -O2 -Wall -Wextra -fno-exceptions -fno-rtti -DDEBUG 11 | 12 | OBJS_DIR = objs 13 | 14 | crtbegin_o=$(shell $(CXX) $(CXXFLAGS) -print-file-name=crtbegin.o) 15 | crtend_o=$(shell $(CXX) $(CXXFLAGS) -print-file-name=crtend.o) 16 | 17 | kernel_srcs = kern/boot.s kern/core/irq_stubs.s kern/core/context.s \ 18 | $(wildcard kern/*.cc) \ 19 | $(wildcard kern/runtime/*.cc) \ 20 | $(wildcard kern/core/*.cc) \ 21 | $(wildcard kern/drv/*.cc) \ 22 | $(wildcard kern/utils/*.cc) \ 23 | $(wildcard lib/*.cc) 24 | 25 | kernel_objs := $(patsubst %.cc, $(OBJS_DIR)/%.o, $(kernel_srcs)) 26 | kernel_objs := $(patsubst %.s, $(OBJS_DIR)/%.o, $(kernel_objs)) 27 | 28 | kern_objs := $(OBJS_DIR)/kern/runtime/crti.o $(crtbegin_o) \ 29 | $(kernel_objs) \ 30 | $(crtend_o) $(OBJS_DIR)/kern/runtime/crtn.o 31 | 32 | DEPFILES := $(patsubst %.cc, $(OBJS_DIR)/%.d, $(kernel_srcs)) 33 | DEPFILES := $(patsubst %.s, $(OBJS_DIR)/%.d, $(DEPFILES)) 34 | 35 | ulib_src = $(wildcard lib/*.cc) $(wildcard user/libc/*.c) 36 | ulib_obj := $(patsubst lib/%.cc, $(OBJS_DIR)/user/lib/%.o, $(ulib_src)) $(OBJS_DIR)/user/lib/cxx_rt.o 37 | ulib_obj := $(patsubst user/libc/%.c, $(OBJS_DIR)/user/lib/%.o, $(ulib_obj)) 38 | 39 | DEPFILES := $(DEPFILES) $(patsubst %.o, %.d, $(ulib_obj)) 40 | 41 | ulib_pre_objs := $(OBJS_DIR)/user/lib/crti.o $(crtbegin_o) 42 | ulib_post_objs := $(ulib_obj) $(crtend_o) $(OBJS_DIR)/user/lib/crtn.o 43 | 44 | uprogs_objs = $(patsubst user/%.c, $(OBJS_DIR)/user/bin/%.o, \ 45 | $(wildcard user/*.c)) 46 | uprogs = $(patsubst $(OBJS_DIR)/user/bin/%.o, bin/%, $(uprogs_objs)) 47 | 48 | all: run ramfs_gen 49 | 50 | # for debugging 51 | print-%: ; @echo $* = $($*) 52 | 53 | -include $(DEPFILES) 54 | 55 | $(OBJS_DIR)/kern/%.d: kern/%.cc 56 | @mkdir -p $(@D) 57 | $(CPP) $(CXXFLAGS) $< -MM -MT $(@:.d=.o) >$@ 58 | 59 | $(OBJS_DIR)/lib/%.d: lib/%.cc 60 | @mkdir -p $(@D) 61 | $(CPP) $(CXXFLAGS) $< -MM -MT $(@:.d=.o) >$@ 62 | 63 | # for userspace 64 | $(OBJS_DIR)/user/lib/cxx_rt.d: kern/runtime/cxx_rt.cc 65 | @mkdir -p $(@D) 66 | $(CPP) $(USER_FLAGS) $< -MM -MT $(@:.d=.o) >$@ 67 | 68 | $(OBJS_DIR)/user/lib/%.d: user/libc/%.c 69 | @mkdir -p $(@D) 70 | $(CPP) $(USER_FLAGS) $< -MM -MT $(@:.d=.o) >$@ 71 | 72 | $(OBJS_DIR)/user/bin/%.d: user/%.c 73 | @mkdir -p $(@D) 74 | $(CPP) $(USER_FLAGS) $< -MM -MT $(@:.d=.o) >$@ 75 | 76 | # print makefile variable (for debug purpose) 77 | print-%: ; @echo $* = $($*) 78 | 79 | debug: kernel 80 | qemu-system-i386 -kernel kernel -initrd initramfs.img -m 64 -s -monitor stdio \ 81 | -drive file=$(DISKIMG),format=raw -vga vmware 82 | 83 | run: kernel $(DISKIMG) initramfs.img 84 | qemu-system-i386 -m 64 -s -monitor stdio -drive file=$(DISKIMG),format=raw -vga vmware 85 | 86 | $(DISKIMG): kernel $(uprogs) initramfs.img logo.ppm 87 | hdiutil attach $(DISKIMG) 88 | cp grub.cfg /Volumes/SOS/boot/grub/ 89 | cp kernel /Volumes/SOS 90 | cp logo.ppm /Volumes/SOS 91 | cp bin/init /Volumes/SOS 92 | @mkdir -p /Volumes/SOS/bin 93 | cp bin/* /Volumes/SOS/bin 94 | cp initramfs.img /Volumes/SOS 95 | #hdiutil detach disk2 96 | 97 | kernel: $(kern_objs) kern/kernel.ld 98 | $(CXX) -T kern/kernel.ld -O2 -nostdlib -o $@ $^ -lgcc 99 | 100 | $(OBJS_DIR)/kern/%.o: kern/%.cc 101 | @mkdir -p $(@D) 102 | $(CXX) $(CXXFLAGS) -c -o $@ $< 103 | 104 | $(OBJS_DIR)/kern/%.o: kern/%.s 105 | @mkdir -p $(@D) 106 | nasm -f elf32 -o $@ $< 107 | 108 | $(OBJS_DIR)/lib/%.o: lib/%.cc 109 | @mkdir -p $(@D) 110 | $(CXX) $(CXXFLAGS) -c -o $@ $< 111 | 112 | # tools 113 | ramfs_gen: tools/ramfs_gen.c 114 | gcc -o $@ $^ 115 | 116 | 117 | ################################################################# 118 | # user space 119 | ################################################################# 120 | 121 | $(OBJS_DIR)/user/lib/cxx_rt.o: kern/runtime/cxx_rt.cc 122 | @mkdir -p $(@D) 123 | $(CXX) $(USER_FLAGS) -c -o $@ $< 124 | 125 | $(OBJS_DIR)/user/lib/%.o: kern/runtime/%.s 126 | @mkdir -p $(@D) 127 | nasm -f elf32 -o $@ $< 128 | 129 | $(OBJS_DIR)/user/lib/%.o: lib/%.cc 130 | @mkdir -p $(@D) 131 | $(CXX) $(USER_FLAGS) -c -o $@ $< 132 | 133 | $(OBJS_DIR)/user/lib/%.o: user/libc/%.c 134 | @mkdir -p $(@D) 135 | $(CXX) $(USER_FLAGS) -c -o $@ $< 136 | 137 | $(OBJS_DIR)/user/bin/%.o: user/%.c 138 | @mkdir -p $(@D) 139 | $(CXX) $(USER_FLAGS) -c -o $@ $< 140 | 141 | bin/%: $(ulib_pre_objs) $(OBJS_DIR)/user/bin/%.o $(ulib_post_objs) user/user.ld 142 | @mkdir -p $(@D) 143 | $(CXX) $(USER_FLAGS) -T user/user.ld -nostdlib -o $@ $^ 144 | 145 | 146 | initramfs.img: bin/echo ramfs_gen 147 | ./ramfs_gen README.md user/echo.c bin/echo 148 | 149 | .PHONY: clean 150 | 151 | clean: 152 | -rm $(OBJS_DIR)/kern/*.o 153 | -rm $(OBJS_DIR)/lib/*.o 154 | -rm $(OBJS_DIR)/kern/core/*.o 155 | -rm $(OBJS_DIR)/kern/runtime/*.o 156 | -rm $(OBJS_DIR)/kern/utils/*.o 157 | -rm $(OBJS_DIR)/kern/drv/*.o 158 | -rm $(OBJS_DIR)/user/lib/*.o 159 | -rm $(OBJS_DIR)/user/bin/*.o 160 | -rm $(OBJS_DIR)/kern/*.d 161 | -rm $(OBJS_DIR)/lib/*.d 162 | -rm $(OBJS_DIR)/kern/core/*.d 163 | -rm $(OBJS_DIR)/kern/runtime/*.d 164 | -rm $(OBJS_DIR)/kern/utils/*.d 165 | -rm $(OBJS_DIR)/kern/drv/*.d 166 | -rm $(OBJS_DIR)/user/lib/*.d 167 | -rm $(OBJS_DIR)/user/bin/*.d 168 | -rm bin/* 169 | -rm kernel 170 | -------------------------------------------------------------------------------- /lib/sprintf.cc: -------------------------------------------------------------------------------- 1 | #include "sprintf.h" 2 | #include "types.h" 3 | #include "stdarg.h" 4 | 5 | char* itoa(int d, char* buf, int base) 6 | { 7 | if (base < 2 || base > 36) { 8 | *buf = '\0'; 9 | return buf; 10 | } 11 | 12 | const char map[] = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"; 13 | char* p = buf, *dp = buf; 14 | if (d < 0 && base == 10) { 15 | *buf++ = '-'; 16 | dp = buf; 17 | } 18 | 19 | do { 20 | *buf++ = map[35 + d % base]; 21 | d /= base; 22 | } while (d); 23 | *buf-- = '\0'; 24 | 25 | while (dp < buf) { 26 | char c = *dp; 27 | *dp++ = *buf; 28 | *buf-- = c; 29 | } 30 | 31 | return p; 32 | } 33 | 34 | char* utoa(u32 u, char* buf, int base) 35 | { 36 | if (base < 2 || base > 36) { 37 | *buf = '\0'; 38 | return buf; 39 | } 40 | 41 | const char map[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 42 | char* p = buf, *dp = buf; 43 | 44 | do { 45 | *buf++ = map[u % base]; 46 | u /= base; 47 | } while (u); 48 | *buf-- = '\0'; 49 | 50 | while (dp < buf) { 51 | char c = *dp; 52 | *dp++ = *buf; 53 | *buf-- = c; 54 | } 55 | 56 | return p; 57 | } 58 | 59 | static char* ksnputs(char* buf, size_t* len, const char* p) 60 | { 61 | while (*p && (*len)--) { 62 | *buf++ = *p++; 63 | } 64 | return buf; 65 | } 66 | 67 | static char* ksputs(char* buf, const char* p) 68 | { 69 | while (*p) { 70 | *buf++ = *p++; 71 | } 72 | return buf; 73 | } 74 | 75 | int vsnprintf(char* sbuf, size_t len, const char* fmt, va_list args) 76 | { 77 | char* old = sbuf; 78 | 79 | int d = 0; 80 | u32 u = 0; 81 | char* s = NULL; 82 | char c = ' '; 83 | char buf[32]; 84 | 85 | while (*fmt && len) { 86 | char ch = *fmt; 87 | if (ch == '%') { 88 | switch(*++fmt) { 89 | case 'b': case 'B': 90 | d = va_arg(args, int); 91 | sbuf = ksnputs(sbuf, &len, itoa(d, buf, 2)); 92 | break; 93 | 94 | case 'x': case 'X': 95 | u = va_arg(args, u32); 96 | sbuf = ksnputs(sbuf, &len, utoa(u, buf, 16)); 97 | break; 98 | 99 | case 'd': 100 | d = va_arg(args, int); 101 | sbuf = ksnputs(sbuf, &len, itoa(d, buf, 10)); 102 | break; 103 | 104 | case 'u': 105 | u = va_arg(args, u32); 106 | sbuf = ksnputs(sbuf, &len, utoa(u, buf, 10)); 107 | len--; 108 | break; 109 | 110 | case '%': 111 | *sbuf++ = '%'; 112 | len--; 113 | break; 114 | 115 | case 'c': 116 | c = va_arg(args, int); 117 | *sbuf++ = c; 118 | len--; 119 | break; 120 | 121 | case 's': 122 | s = va_arg(args, char*); 123 | sbuf = ksnputs(sbuf, &len, s?s:"(NULL)"); 124 | break; 125 | 126 | default: 127 | break; 128 | } 129 | } else { 130 | *sbuf++ = ch; 131 | } 132 | fmt++; 133 | } 134 | 135 | return sbuf - old; 136 | } 137 | 138 | int vsprintf(char* sbuf, const char* fmt, va_list args) 139 | { 140 | char* old = sbuf; 141 | 142 | int d = 0; 143 | u32 u = 0; 144 | char* s = NULL; 145 | char c = ' '; 146 | char buf[32]; 147 | 148 | while (*fmt) { 149 | char ch = *fmt; 150 | if (ch == '%') { 151 | switch(*++fmt) { 152 | case 'b': case 'B': 153 | d = va_arg(args, int); 154 | sbuf = ksputs(sbuf, itoa(d, buf, 2)); 155 | break; 156 | 157 | case 'x': case 'X': 158 | u = va_arg(args, u32); 159 | sbuf = ksputs(sbuf, utoa(u, buf, 16)); 160 | break; 161 | 162 | case 'd': 163 | d = va_arg(args, int); 164 | sbuf = ksputs(sbuf, itoa(d, buf, 10)); 165 | break; 166 | 167 | case 'u': 168 | u = va_arg(args, u32); 169 | sbuf = ksputs(sbuf, utoa(u, buf, 10)); 170 | break; 171 | 172 | case '%': 173 | *sbuf++ = '%'; 174 | break; 175 | 176 | case 'c': 177 | c = va_arg(args, int); 178 | *sbuf++ = c; 179 | break; 180 | 181 | case 's': 182 | s = va_arg(args, char*); 183 | sbuf = ksputs(sbuf, s?s:"(NULL)"); 184 | break; 185 | 186 | default: 187 | break; 188 | } 189 | } else { 190 | *sbuf++ = ch; 191 | } 192 | fmt++; 193 | } 194 | 195 | return sbuf - old; 196 | } 197 | 198 | int snprintf(char* buf, size_t len, const char* fmt, ...) 199 | { 200 | va_list args; 201 | va_start(args, fmt); 202 | int nwrite = vsnprintf(buf, len, fmt, args); 203 | buf[nwrite] = 0; 204 | va_end(args); 205 | return nwrite; 206 | } 207 | 208 | int sprintf(char* buf, const char* fmt, ...) 209 | { 210 | va_list args; 211 | va_start(args, fmt); 212 | int nwrite = vsprintf(buf, fmt, args); 213 | va_end(args); 214 | return nwrite; 215 | } 216 | 217 | -------------------------------------------------------------------------------- /kern/core/graphics.cc: -------------------------------------------------------------------------------- 1 | #include "graphics.h" 2 | #include "common.h" 3 | #include "vm.h" 4 | #include "string.h" 5 | #include "font.h" 6 | #include "spinlock.h" 7 | 8 | Spinlock videolock("video"); 9 | 10 | VideoMode videoMode; 11 | Rgb colormap[] = { 12 | 0x000000, 13 | 0x0000ff, 14 | 0x00ff00, 15 | 0x00ffff, 16 | 0xff0000, 17 | 0xff00ff, 18 | 0xa52a2a, 19 | 0xd3d3d3, 20 | 0xbebebe, 21 | 0xadd8e6, 22 | 0x90ee90, 23 | 0xe0ffff, 24 | 0xcd5c5c, 25 | 0xee00ee, 26 | 0xff4040, 27 | 0xffffff, 28 | 0xffff00, 29 | 0xfafad2, 30 | 0x800080 31 | }; 32 | 33 | void VideoMode::init(ModeInfoBlock_t* modeinfo) 34 | { 35 | _base = (char*)0xE0000000; 36 | uint32_t video_phys = modeinfo->physbase; 37 | uint32_t vramsize = modeinfo->Yres * modeinfo->pitch; 38 | vmm.map_pages(vmm.kernel_page_directory(), (void*)_base, 39 | vramsize, video_phys, PDE_WRITABLE); 40 | _pitch = modeinfo->pitch; 41 | _width = modeinfo->Xres; 42 | _height = modeinfo->Yres; 43 | } 44 | 45 | void VideoMode::drawLine(int x0, int y0, int x1, int y1, Rgb rgb) 46 | { 47 | drawLine({x0, y0}, {x1, y1}, rgb); 48 | } 49 | 50 | void VideoMode::octant0(position_t p1, position_t p2, Rgb rgb) 51 | { 52 | int dx = p2.x - p1.x; 53 | int dy = p2.y - p1.y; 54 | int dir = dy >= 0 ? 1 : -1; 55 | dy = dir * dy; 56 | int dx2 = dx * 2, dy2 = dy * 2; 57 | int f = dy2 - dir * dx, y = p1.y; 58 | 59 | for (int x = p1.x; x <= p2.x; x++) { 60 | if (f >= 0) { 61 | y += dir; 62 | drawPixel(x, y, rgb); 63 | f += dy2 - dx2; 64 | } else { 65 | drawPixel(x, y, rgb); 66 | f += dy2; 67 | } 68 | } 69 | } 70 | 71 | void VideoMode::octant1(position_t p1, position_t p2, Rgb rgb) 72 | { 73 | int dx = p2.x - p1.x; 74 | int dy = p2.y - p1.y; 75 | int dx2 = dx * 2, dy2 = dy * 2; 76 | int dir = dy >= 0 ? 1 : -1; 77 | dy = dir * dy; 78 | int f = dx2 - dy, x = p1.x; 79 | 80 | for (int y = p1.y; y != p2.y; y += dir) { 81 | if (f >= 0) { 82 | drawPixel(++x, y, rgb); 83 | f += dx2 - dy2; 84 | } else { 85 | drawPixel(x, y, rgb); 86 | f += dx2; 87 | } 88 | } 89 | drawPixel(p2.x, p2.y, rgb); 90 | } 91 | 92 | // FIXME: bounds check 93 | void VideoMode::drawLine(position_t p1, position_t p2, Rgb rgb) 94 | { 95 | if (p1.x > p2.x) { 96 | auto tmp = p1; 97 | p1 = p2; 98 | p2 = tmp; 99 | } 100 | int dx = p2.x - p1.x; 101 | int dy = p2.y > p1.y ? p2.y - p1.y : p1.y - p2.y; 102 | if (dx >= dy) octant0(p1, p2, rgb); 103 | else octant1(p1, p2, rgb); 104 | } 105 | 106 | void VideoMode::drawPixel(int x, int y, Rgb rgb) 107 | { 108 | char* loc = (_base + y * _pitch + x*3); 109 | *(loc) = rgb.b; 110 | *(loc + 1) = rgb.g; 111 | *(loc + 2) = rgb.r; 112 | } 113 | 114 | void VideoMode::drawRect(position_t p, int width, int height, Rgb rgb) 115 | { 116 | width = min(_width - p.x, width); 117 | height = min(_height - p.y, height); 118 | 119 | auto l = p.x, r = p.x+width-1, t = p.y, b = p.y+height-1; 120 | drawLine(l, t, r, t, rgb); 121 | drawLine(l, t, l, b, rgb); 122 | drawLine(r, t, r, b, rgb); 123 | drawLine(l, b, r, b, rgb); 124 | } 125 | 126 | void VideoMode::drawImage(position_t p, char* data, int width, int height) 127 | { 128 | width = min(_width - p.x, width); 129 | height = min(_height - p.y, height); 130 | 131 | char* start = _base + p.y * _pitch + p.x * 3; 132 | for (int j = 0; j < height; j++) { 133 | memcpy(start + _pitch*j, data + j*width*3, width*3); 134 | } 135 | } 136 | 137 | void VideoMode::fillRect(position_t p, int width, int height, Rgb rgb) 138 | { 139 | width = min(_width - p.x, width); 140 | height = min(_height - p.y, height); 141 | 142 | if (height == 0 || width == 0) return; 143 | char* start = _base + p.y * _pitch + p.x * 3; 144 | for (int i = 0; i < width; i++) { 145 | *(start + i*3) = rgb.b; 146 | *(start + i*3 + 1) = rgb.g; 147 | *(start + i*3 + 2) = rgb.r; 148 | } 149 | 150 | for (int j = 0; j < height-1; j++) { 151 | memcpy(start+_pitch, start, width*3); 152 | start += _pitch; 153 | } 154 | } 155 | 156 | void VideoMode::drawString(position_t p, const char* s, Rgb rgb) 157 | { 158 | int step = builtin_fontinfo.xadvance; 159 | int len = strlen(s); 160 | for (int i = 0; i < len; i++) { 161 | drawChar(p, s[i], rgb); 162 | p.x += step; 163 | } 164 | } 165 | 166 | void VideoMode::drawChar(position_t p, char c, Rgb rgb) 167 | { 168 | if (c <= 0) return; 169 | char* start = _base + p.y * _pitch + p.x * 3; 170 | const char* f = builtin_font[(int)c-1]; 171 | 172 | auto oflags = videolock.lock(); 173 | for (int i = 0; i < 16; i++) { 174 | char* ln = (start + i*_pitch); 175 | for (int j = 0; j < 8; j++) { 176 | auto v = f[i*8+j]; 177 | Rgb* p = (Rgb*)(ln + j*3); 178 | if (v == '*') { 179 | *p = rgb; 180 | } else { 181 | *p = {0, 0, 0}; //bg color 182 | } 183 | } 184 | } 185 | videolock.release(oflags); 186 | } 187 | 188 | // FIXME: bounds check 189 | void VideoMode::blitCopy(position_t dst, position_t src, int width, int height) 190 | { 191 | char* start = _base + dst.y * _pitch + dst.x * 3; 192 | char* old = _base + src.y * _pitch + src.x * 3; 193 | uint32_t expand = min(width*3, _pitch); 194 | if (expand == _pitch && dst.x == 0 && src.x == 0) { 195 | expand *= height; 196 | memmove(start, old, expand); 197 | return; 198 | } 199 | // slow version 200 | for (int j = 0; j < height; j++) { 201 | memcpy(start, old, expand); 202 | start += _pitch; 203 | old += _pitch; 204 | } 205 | } 206 | 207 | -------------------------------------------------------------------------------- /include/vfs.h: -------------------------------------------------------------------------------- 1 | #ifndef _VFS_H 2 | #define _VFS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class Disk; 12 | 13 | enum class FsNodeType: uint8_t { 14 | Inval, 15 | Dir, 16 | File, 17 | BlockDev, 18 | CharDev 19 | }; 20 | 21 | class FileSystem; 22 | // in-memory inode 23 | typedef struct inode_s { 24 | dev_t dev; // major and minor 25 | u32 ino; 26 | loff_t size; // size in bytes 27 | nlink_t links; // hard links 28 | loff_t blocks; 29 | uint16_t uid; 30 | uint16_t gid; 31 | 32 | size_t blksize; 33 | time_t mtime; 34 | time_t atime; 35 | time_t ctime; 36 | umode_t mode; 37 | FsNodeType type; 38 | int ref; // in-memory copies 39 | void* data; // fs specific 40 | FileSystem* fs; 41 | } inode_t; 42 | 43 | typedef struct dentry_s { 44 | char name[NAMELEN+1]; 45 | inode_t *ip; 46 | } dentry_t; 47 | 48 | using PipeBuffer = RingBuffer; 49 | class File; 50 | struct Pipe { 51 | public: 52 | File* readf; 53 | File* writef; 54 | PipeBuffer pbuf; 55 | 56 | int write(const void *buf, size_t nbyte); 57 | int read(void *buf, size_t nbyte); 58 | }; 59 | 60 | class File { 61 | public: 62 | enum class Type { 63 | None, Pipe, Inode 64 | }; 65 | enum Mode { 66 | Readable = 0x01, 67 | Writable = 0x02, 68 | }; 69 | 70 | 71 | File(Type ty = Type::None); 72 | ~File(); 73 | 74 | void dup() { _ref++; } 75 | void put(); 76 | 77 | Type type() const { return _type; } 78 | int ref() const { return _ref; } 79 | off_t off() const { return _off; } 80 | void set_off(off_t off) { _off = off; } 81 | inode_t* inode() { return _ip; } 82 | void set_inode(inode_t* ip); 83 | void set_pipe(Pipe* p); 84 | Pipe* pipe() { return _pipe; } 85 | 86 | void set_readable() { _mode |= Readable; } 87 | void set_writable() { _mode |= Writable; } 88 | bool readable() const { return _mode & Readable; } 89 | bool writable() const { return _mode & Writable; } 90 | 91 | protected: 92 | inode_t *_ip; 93 | off_t _off; 94 | int _ref; 95 | Type _type; 96 | Pipe *_pipe; 97 | int _mode; 98 | }; 99 | 100 | typedef void* filldir_t; 101 | class FileSystem { 102 | public: 103 | friend class VFSManager; 104 | 105 | FileSystem(): _iroot(NULL) {} 106 | 107 | // virtual void dirty_inode(inode_t *) {} 108 | // virtual void write_inode(inode_t *, int) {} 109 | // virtual void put_inode(inode_t *) {} 110 | // virtual void drop_inode(inode_t *) {} 111 | // virtual void delete_inode(inode_t *) {} 112 | 113 | // virtual int create(inode_t * dir, struct dentry *, int mode) {} 114 | // virtual int link(struct dentry * old, inode_t * dir, struct dentry *new_de) {} 115 | // virtual int unlink(inode_t * dir, dentry_t *) {} 116 | // virtual int mkdir(inode_t *, dentry_t *, int) {} 117 | // virtual int rmdir(inode_t *, dentry_t *) {} 118 | // virtual int mknod(inode_t *, dentry_t *, int, dev_t) {} 119 | // virtual int rename(inode_t *, dentry_t *, inode_t *, dentry_t *) {} 120 | // virtual int readlink(dentry_t *, char * buf,int len) {} 121 | // virtual int open(inode_t *, struct file *) {} 122 | // virtual int release(inode_t *, struct file *) {} 123 | 124 | virtual dentry_t * lookup(inode_t*, dentry_t*) { return NULL; } 125 | 126 | virtual off_t llseek(File *, off_t , int ) { return -EINVAL; } 127 | virtual ssize_t read(File *, char * , size_t , off_t* ) { return -EINVAL; } 128 | virtual ssize_t write(File *, const char * , size_t, off_t* ) { return -EINVAL; } 129 | virtual int readdir(File *, dentry_t *, filldir_t) { return -EINVAL; } 130 | 131 | inode_t* root() const { return _iroot; } 132 | 133 | protected: 134 | inode_t* _iroot; 135 | 136 | FileSystem* _prev, *_next; 137 | }; 138 | 139 | /** 140 | * NOTE: mount point handling is extremely complex, I have observed 141 | * linux 1.0 and linux 0.11 and modern linux, the schema evolves 142 | * a lot! so I'll take a simple wrong way to do it first. 143 | * mnts ordered in stack 144 | */ 145 | typedef struct mount_info_s { 146 | char* mnt_point; 147 | FileSystem* fs; 148 | inode_t* mnt_over; // inode on which this fs mounted. 149 | struct mount_info_s *next; 150 | } mount_info_t; 151 | 152 | using CreateFsFunction = FileSystem* (*)(const void*); 153 | typedef struct file_system_type_s { 154 | const char* fsname; 155 | CreateFsFunction spawn; 156 | struct file_system_type_s *next; 157 | } file_system_type_t; 158 | 159 | class VFSManager { 160 | public: 161 | void init(); 162 | void init_root(dev_t rootdev); //bootstrap root dev 163 | void register_fs(const char* fsname, CreateFsFunction func); 164 | file_system_type_t* find_fs(const char* fsname); 165 | 166 | int mount(const char *src, const char *target, const char *fstype, 167 | unsigned long mountflags, const void *data); 168 | int unmount(const char *target); 169 | mount_info_t* get_mount(const char* target); 170 | // find mount point for path, and return new_path by stripping mount prefix 171 | mount_info_t* find_mount(const char* path, char**new_path); 172 | // find if there is a fs mount on ip 173 | mount_info_t* find_mount_over(inode_t* ip); 174 | 175 | inode_t* namei(const char* path); 176 | 177 | // wrapper for fs::lookup 178 | inode_t* dir_lookup(inode_t* ip, const char* name); 179 | 180 | dentry_t* alloc_entry(); 181 | void dealloc_entry(dentry_t*); 182 | inode_t* alloc_inode(dev_t dev, uint32_t ino); 183 | void dealloc_inode(inode_t*); 184 | 185 | private: 186 | FileSystem* _fs_list {nullptr}; 187 | file_system_type_t* _fs_types {nullptr}; 188 | FileSystem* _rootfs {nullptr}; // fs for root mountpoint 189 | mount_info_t* _mounts {nullptr}; 190 | }; 191 | 192 | extern dev_t rootdev; 193 | extern VFSManager vfs; 194 | 195 | #endif 196 | -------------------------------------------------------------------------------- /kern/core/mm.cc: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "string.h" 3 | #include "mm.h" 4 | #include "mmu.h" 5 | 6 | #ifdef DEBUG 7 | #define debug_mm(fmt, ...) kprintf("[%s]: " fmt, __func__, ##__VA_ARGS__) 8 | #else 9 | #define debug_mm(fmt, ...) 10 | #endif 11 | 12 | extern u32* _end; 13 | PhysicalMemoryManager pmm; 14 | 15 | #define BITS_PER_INT (sizeof(u32)*8) 16 | 17 | static inline u32 aligned(u32 size, u32 frame_size) 18 | { 19 | return size / frame_size + ((size % frame_size) ? 1 : 0); 20 | } 21 | 22 | // PMM 23 | void PhysicalMemoryManager::set_frame(u32 frame_addr) 24 | { 25 | u32 fid = frame_addr >> 12; 26 | _frames[fid/BITS_PER_INT] |= (1<<(fid%BITS_PER_INT)); 27 | } 28 | 29 | void PhysicalMemoryManager::clear_frame(u32 frame_addr) 30 | { 31 | u32 fid = frame_addr >> 12; 32 | _frames[fid/BITS_PER_INT] &= ~(1<<(fid%BITS_PER_INT)); 33 | } 34 | 35 | int PhysicalMemoryManager::test_frame(u32 frame_addr) 36 | { 37 | u32 fid = frame_addr >> 12; 38 | return _frames[fid/BITS_PER_INT] & (1<<(fid%BITS_PER_INT)); 39 | } 40 | 41 | u32 PhysicalMemoryManager::get_last_free_frame() 42 | { 43 | for (int i = _frameCount/BITS_PER_INT-1; i >= 0; --i) { 44 | if (_frames[i] != 0xffffffff) { 45 | for (int j = BITS_PER_INT-1; j >= 0; --j) { 46 | if (!(_frames[i] & (1<invalid; 74 | 75 | u32 count = aligned(size, this->frame_size); 76 | if (count == 1) return get_first_free_frame(); 77 | //debug_mm("find %d frame\n", count); 78 | 79 | for (u32 i = 0; i < _frameCount / BITS_PER_INT; ++i) { 80 | if (_frames[i] != 0xffffffff) { 81 | for (u8 j = 0; j < BITS_PER_INT; ++j) { 82 | if (!(_frames[i] & (1<frame_size)) { 86 | break; 87 | } 88 | } 89 | if (k == count) return start; 90 | 91 | } 92 | } 93 | } 94 | } 95 | 96 | debug_mm("failed\n"); 97 | return this->invalid; 98 | } 99 | 100 | void PhysicalMemoryManager::set_region(u32 frame_addr, u32 size) 101 | { 102 | u32 p = frame_addr, e = p + size; 103 | while (p < e) { 104 | set_frame(p); 105 | p += this->frame_size; 106 | } 107 | } 108 | 109 | void PhysicalMemoryManager::clear_region(u32 frame_addr, u32 size) 110 | { 111 | u32 p = frame_addr, e = p + size; 112 | while (p < e) { 113 | clear_frame(p); 114 | p += this->frame_size; 115 | } 116 | } 117 | 118 | PhysicalMemoryManager::PhysicalMemoryManager() 119 | :_frames((u32*)&_end), _frameCount(0), _frameUsed(0) 120 | { 121 | } 122 | 123 | void PhysicalMemoryManager::init(u32 mem_size, void* last_used) 124 | { 125 | _memSize = mem_size; 126 | if (last_used) { 127 | _frames = (u32*)last_used; 128 | } 129 | _frameCount = aligned(_memSize * 1024, PGSIZE); 130 | memset(_frames, 0, _frameCount/8); 131 | 132 | // from there, we can alloc memory for kernel 133 | _freeStart = (u32*)PGROUNDUP(_frames + _frameCount/BITS_PER_INT); 134 | 135 | u32 used_mem = PGROUNDUP(v2p(_freeStart)), // in Bytes 136 | free_mem = _memSize * 1024 - used_mem; // in Bytes 137 | 138 | if (free_mem > PHYSTOP) free_mem = PHYSTOP; 139 | _freeEnd = _freeStart + free_mem/4; 140 | 141 | alloc_region(used_mem); 142 | 143 | debug_mm("mem_size: %dKB, used: %dKB, pmap addr: 0x%x, frames: %d," 144 | " used: %d, freestart: 0x%x, freeend: 0x%x\n", 145 | mem_size, used_mem/1024, _frames, _frameCount, 146 | _frameUsed, _freeStart, _freeEnd); 147 | } 148 | 149 | // there is a caveat: NULL is actually ambiguous, it may means the very first 150 | // frame or alloc failure. to keep it safe, we asure that first frame is always 151 | // occupied by kernel, so NULL always means failure. 152 | u32 PhysicalMemoryManager::alloc_frame() 153 | { 154 | //debug_mm("_frameUsed: %d\n", _frameUsed); 155 | if (_frameUsed >= _frameCount) return 0; 156 | u32 id = get_first_free_frame(); 157 | if (id == this->invalid) return 0; 158 | 159 | u32 paddr = id * this->frame_size; 160 | set_frame(paddr); 161 | _frameUsed++; 162 | return paddr; 163 | } 164 | 165 | u32 PhysicalMemoryManager::alloc_frame_tail() 166 | { 167 | //debug_mm("_frameUsed: %d\n", _frameUsed); 168 | if (_frameUsed >= _frameCount) return 0; 169 | u32 id = get_last_free_frame(); 170 | if (id == this->invalid) return 0; 171 | 172 | u32 paddr = id * this->frame_size; 173 | set_frame(paddr); 174 | _frameUsed++; 175 | return paddr; 176 | } 177 | 178 | u32 PhysicalMemoryManager::alloc_region(u32 size) 179 | { 180 | if (size == 0) return 0; 181 | 182 | int nframes = aligned(size, frame_size); 183 | if (_frameUsed + nframes > _frameCount) { 184 | debug_mm("nframes %d is too large\n", nframes); 185 | return 0; 186 | } 187 | 188 | u32 id = get_first_free_region(size); 189 | if (id == this->invalid) { 190 | debug_mm("get_first_free_region failed\n"); 191 | return 0; 192 | } 193 | 194 | u32 paddr = id * this->frame_size; 195 | set_region(paddr, size); 196 | _frameUsed += nframes; 197 | 198 | return paddr; 199 | } 200 | 201 | void PhysicalMemoryManager::free_frame(u32 paddr) 202 | { 203 | clear_frame(paddr); 204 | _frameUsed--; 205 | } 206 | 207 | void PhysicalMemoryManager::free_region(u32 paddr, u32 size) 208 | { 209 | clear_region(paddr, size); 210 | _frameUsed -= aligned(size, frame_size); 211 | } 212 | 213 | -------------------------------------------------------------------------------- /include/termios.h: -------------------------------------------------------------------------------- 1 | /* 2 | * borrowed from linux 0.11 3 | */ 4 | 5 | #ifndef _TERMIOS_H 6 | #define _TERMIOS_H 7 | 8 | #define TTY_BUF_SIZE 1024 9 | 10 | /* 0x54 is just a magic number to make these relatively uniqe ('T') */ 11 | 12 | #define TCGETS 0x5401 13 | #define TCSETS 0x5402 14 | #define TCSETSW 0x5403 15 | #define TCSETSF 0x5404 16 | #define TCGETA 0x5405 17 | #define TCSETA 0x5406 18 | #define TCSETAW 0x5407 19 | #define TCSETAF 0x5408 20 | #define TCSBRK 0x5409 21 | #define TCXONC 0x540A 22 | #define TCFLSH 0x540B 23 | #define TIOCEXCL 0x540C 24 | #define TIOCNXCL 0x540D 25 | #define TIOCSCTTY 0x540E 26 | #define TIOCGPGRP 0x540F 27 | #define TIOCSPGRP 0x5410 28 | #define TIOCOUTQ 0x5411 29 | #define TIOCSTI 0x5412 30 | #define TIOCGWINSZ 0x5413 31 | #define TIOCSWINSZ 0x5414 32 | #define TIOCMGET 0x5415 33 | #define TIOCMBIS 0x5416 34 | #define TIOCMBIC 0x5417 35 | #define TIOCMSET 0x5418 36 | #define TIOCGSOFTCAR 0x5419 37 | #define TIOCSSOFTCAR 0x541A 38 | #define TIOCINQ 0x541B 39 | 40 | struct winsize { 41 | unsigned short ws_row; 42 | unsigned short ws_col; 43 | unsigned short ws_xpixel; 44 | unsigned short ws_ypixel; 45 | }; 46 | 47 | #define NCC 8 48 | struct termio { 49 | unsigned short c_iflag; /* input mode flags */ 50 | unsigned short c_oflag; /* output mode flags */ 51 | unsigned short c_cflag; /* control mode flags */ 52 | unsigned short c_lflag; /* local mode flags */ 53 | unsigned char c_line; /* line discipline */ 54 | unsigned char c_cc[NCC]; /* control characters */ 55 | }; 56 | 57 | #define NCCS 17 58 | struct termios { 59 | unsigned int c_iflag; /* input mode flags */ 60 | unsigned int c_oflag; /* output mode flags */ 61 | unsigned int c_cflag; /* control mode flags */ 62 | unsigned int c_lflag; /* local mode flags */ 63 | unsigned char c_line; /* line discipline */ 64 | unsigned char c_cc[NCCS]; /* control characters */ 65 | }; 66 | 67 | /* c_cc characters */ 68 | #define VINTR 0 69 | #define VQUIT 1 70 | #define VERASE 2 71 | #define VKILL 3 72 | #define VEOF 4 73 | #define VTIME 5 74 | #define VMIN 6 75 | #define VSWTC 7 76 | #define VSTART 8 77 | #define VSTOP 9 78 | #define VSUSP 10 79 | #define VEOL 11 80 | #define VREPRINT 12 81 | #define VDISCARD 13 82 | #define VWERASE 14 83 | #define VLNEXT 15 84 | #define VEOL2 16 85 | 86 | /* c_iflag bits */ 87 | #define IGNBRK 0000001 88 | #define BRKINT 0000002 89 | #define IGNPAR 0000004 90 | #define PARMRK 0000010 91 | #define INPCK 0000020 92 | #define ISTRIP 0000040 93 | #define INLCR 0000100 94 | #define IGNCR 0000200 95 | #define ICRNL 0000400 96 | #define IUCLC 0001000 97 | #define IXON 0002000 98 | #define IXANY 0004000 99 | #define IXOFF 0010000 100 | #define IMAXBEL 0020000 101 | 102 | /* c_oflag bits */ 103 | #define OPOST 0000001 104 | #define OLCUC 0000002 105 | #define ONLCR 0000004 106 | #define OCRNL 0000010 107 | #define ONOCR 0000020 108 | #define ONLRET 0000040 109 | #define OFILL 0000100 110 | #define OFDEL 0000200 111 | #define NLDLY 0000400 112 | #define NL0 0000000 113 | #define NL1 0000400 114 | #define CRDLY 0003000 115 | #define CR0 0000000 116 | #define CR1 0001000 117 | #define CR2 0002000 118 | #define CR3 0003000 119 | #define TABDLY 0014000 120 | #define TAB0 0000000 121 | #define TAB1 0004000 122 | #define TAB2 0010000 123 | #define TAB3 0014000 124 | #define XTABS 0014000 125 | #define BSDLY 0020000 126 | #define BS0 0000000 127 | #define BS1 0020000 128 | #define VTDLY 0040000 129 | #define VT0 0000000 130 | #define VT1 0040000 131 | #define FFDLY 0040000 132 | #define FF0 0000000 133 | #define FF1 0040000 134 | 135 | /* c_cflag bit meaning */ 136 | #define CBAUD 0000017 137 | #define B0 0000000 /* hang up */ 138 | #define B50 0000001 139 | #define B75 0000002 140 | #define B110 0000003 141 | #define B134 0000004 142 | #define B150 0000005 143 | #define B200 0000006 144 | #define B300 0000007 145 | #define B600 0000010 146 | #define B1200 0000011 147 | #define B1800 0000012 148 | #define B2400 0000013 149 | #define B4800 0000014 150 | #define B9600 0000015 151 | #define B19200 0000016 152 | #define B38400 0000017 153 | #define EXTA B19200 154 | #define EXTB B38400 155 | #define CSIZE 0000060 156 | #define CS5 0000000 157 | #define CS6 0000020 158 | #define CS7 0000040 159 | #define CS8 0000060 160 | #define CSTOPB 0000100 161 | #define CREAD 0000200 162 | #define CPARENB 0000400 163 | #define CPARODD 0001000 164 | #define HUPCL 0002000 165 | #define CLOCAL 0004000 166 | #define CIBAUD 03600000 /* input baud rate (not used) */ 167 | #define CRTSCTS 020000000000 /* flow control */ 168 | 169 | #define PARENB CPARENB 170 | #define PARODD CPARODD 171 | 172 | /* c_lflag bits */ 173 | #define ISIG 0000001 174 | #define ICANON 0000002 175 | #define XCASE 0000004 176 | #define ECHO 0000010 177 | #define ECHOE 0000020 178 | #define ECHOK 0000040 179 | #define ECHONL 0000100 180 | #define NOFLSH 0000200 181 | #define TOSTOP 0000400 182 | #define ECHOCTL 0001000 183 | #define ECHOPRT 0002000 184 | #define ECHOKE 0004000 185 | #define FLUSHO 0010000 186 | #define PENDIN 0040000 187 | #define IEXTEN 0100000 188 | 189 | /* modem lines */ 190 | #define TIOCM_LE 0x001 191 | #define TIOCM_DTR 0x002 192 | #define TIOCM_RTS 0x004 193 | #define TIOCM_ST 0x008 194 | #define TIOCM_SR 0x010 195 | #define TIOCM_CTS 0x020 196 | #define TIOCM_CAR 0x040 197 | #define TIOCM_RNG 0x080 198 | #define TIOCM_DSR 0x100 199 | #define TIOCM_CD TIOCM_CAR 200 | #define TIOCM_RI TIOCM_RNG 201 | 202 | /* tcflow() and TCXONC use these */ 203 | #define TCOOFF 0 204 | #define TCOON 1 205 | #define TCIOFF 2 206 | #define TCION 3 207 | 208 | /* tcflush() and TCFLSH use these */ 209 | #define TCIFLUSH 0 210 | #define TCOFLUSH 1 211 | #define TCIOFLUSH 2 212 | 213 | /* tcsetattr uses these */ 214 | #define TCSANOW 0 215 | #define TCSADRAIN 1 216 | #define TCSAFLUSH 2 217 | 218 | // implemented and used in userspace 219 | 220 | typedef int speed_t; 221 | 222 | extern speed_t cfgetispeed(struct termios *termios_p); 223 | extern speed_t cfgetospeed(struct termios *termios_p); 224 | extern int cfsetispeed(struct termios *termios_p, speed_t speed); 225 | extern int cfsetospeed(struct termios *termios_p, speed_t speed); 226 | extern int tcdrain(int fildes); 227 | extern int tcflow(int fildes, int action); 228 | extern int tcflush(int fildes, int queue_selector); 229 | extern int tcgetattr(int fildes, struct termios *termios_p); 230 | extern int tcsendbreak(int fildes, int duration); 231 | extern int tcsetattr(int fildes, int optional_actions, 232 | struct termios *termios_p); 233 | 234 | #endif 235 | -------------------------------------------------------------------------------- /include/fat32.h: -------------------------------------------------------------------------------- 1 | #ifndef _SOS_FAT32_H 2 | #define _SOS_FAT32_H 3 | 4 | #include 5 | 6 | // Spec: 7 | // http://en.wikipedia.org/wiki/Design_of_the_FAT_file_system 8 | 9 | typedef struct fat_extBS_32 10 | { 11 | //extended fat32 stuff 12 | unsigned int table_size_32; 13 | unsigned short extended_flags; 14 | unsigned short fat_version; 15 | unsigned int root_cluster; 16 | unsigned short fat_info; 17 | unsigned short backup_BS_sector; 18 | unsigned char reserved_0[12]; 19 | unsigned char drive_number; 20 | unsigned char reserved_1; 21 | unsigned char boot_signature; 22 | unsigned int volume_id; 23 | unsigned char volume_label[11]; 24 | unsigned char fat_type_label[8]; 25 | 26 | }__attribute__((packed)) fat_extBS_32_t; 27 | 28 | typedef struct fat_extBS_16 29 | { 30 | //extended fat12 and fat16 stuff 31 | unsigned char bios_drive_num; 32 | unsigned char reserved1; 33 | unsigned char boot_signature; 34 | unsigned int volume_id; 35 | unsigned char volume_label[11]; 36 | unsigned char fat_type_label[8]; 37 | 38 | }__attribute__((packed)) fat_extBS_16_t; 39 | 40 | //Bios Parameter Block 41 | typedef struct fat_bs 42 | { 43 | unsigned char bootjmp[3]; 44 | unsigned char oem_name[8]; 45 | unsigned short bytes_per_sector; 46 | unsigned char sectors_per_cluster; 47 | unsigned short reserved_sector_count; 48 | unsigned char table_count; 49 | unsigned short root_entry_count; 50 | unsigned short total_sectors_16; 51 | unsigned char media_type; 52 | unsigned short table_size_16; 53 | unsigned short sectors_per_track; 54 | unsigned short head_side_count; 55 | unsigned int hidden_sector_count; 56 | unsigned int total_sectors_32; 57 | 58 | //this will be cast to it's specific type once the driver actually knows what type of FAT this is. 59 | //unsigned char extended_section[54]; 60 | union { 61 | fat_extBS_16_t ebs16; 62 | fat_extBS_32_t ebs32; 63 | }; 64 | 65 | }__attribute__((packed)) fat_bs_t; 66 | 67 | // fat_dirent.lfn.lfn_seq 68 | #define LFN_SEQ_NUM(n) ((n) & 0x3f) 69 | #define LFN_LAST(n) ((n) & 0x40) 70 | #define LFN_ERASED(n) ((n) & 0x80) 71 | 72 | enum FatAttr { 73 | READ_ONLY=0x01, 74 | HIDDEN=0x02, 75 | SYSTEM=0x04, 76 | VOLUME_ID=0x08, 77 | DIRECTORY=0x10, 78 | ARCHIVE=0x20, 79 | LFN=READ_ONLY|HIDDEN|SYSTEM|VOLUME_ID 80 | }; 81 | 82 | union fat_dirent { 83 | struct { 84 | char name[8]; // 8.3 name and ext 85 | char ext[3]; 86 | uint8_t attr; 87 | uint8_t reserved; 88 | uint8_t create_tenth; 89 | uint16_t create_time; 90 | uint16_t create_date; 91 | uint16_t access_date; 92 | uint16_t start_cluster_hi; // for fat16/12 is 0 93 | uint16_t mod_time; 94 | uint16_t mod_date; 95 | uint16_t start_cluster_lo; 96 | uint32_t size; // in bytes, only for file, not dir 97 | } __attribute__((packed)) std; // standard 8.3 format 98 | 99 | struct { 100 | uint8_t lfn_seq; 101 | uint16_t name1[5]; 102 | uint8_t attr; 103 | uint8_t type; // 0 104 | uint8_t checksum; 105 | uint16_t name2[6]; 106 | uint16_t zeroed; // 0 107 | uint16_t name3[2]; 108 | } __attribute__((packed)) lfn; // long file names 109 | }; 110 | 111 | #define FAT_ROOT_INO 1 112 | 113 | // fat has no inode, so I come up with a simple idea by mapping 114 | // inode_t.ino to start_cluster of itself. 115 | // root inode is special 1 116 | // inode_t.data part 117 | // dir_id and dir_start are for cache purpose, dir_id locates node at dir position 118 | // dir_start is used to identify dir 119 | #define LFN_MAX_LEN (64*13) 120 | typedef struct fat_inode_s { 121 | uint32_t start_cluster; 122 | uint32_t size; 123 | int dir_id; 124 | uint32_t dir_start; 125 | char long_name[LFN_MAX_LEN]; 126 | uint8_t attr; 127 | int lfn_len; 128 | char std_name[13]; 129 | } fat_inode_t; 130 | 131 | /* 132 | * FAT12 FAT16 FAT32 133 | * Available 000 0000 00000000 134 | * Reserved 001 0001 00000001 135 | * User Data 002-FF6 0002-FFF6 00000002-0FFFFFF6 136 | * Bad Cluster FF7 FFF7 0FFFFFF7 137 | * End Marker FF8-FFF FFF8-FFFF 0FFFFFF8-0FFFFFFF 138 | **/ 139 | enum ClusterStatus { 140 | CLUSTER_AVAIL = 0x0, 141 | CLUSTER_RESERVED = 0x01, 142 | CLUSTER_DATA_BEGIN = 0x02, 143 | CLUSTER_DATA_END_12 = 0x0ff7, 144 | CLUSTER_DATA_END_16 = 0x0fff7, 145 | CLUSTER_DATA_END_32 = 0x0ffffff7, 146 | }; 147 | 148 | typedef struct scan_dir_option_s { 149 | const char* name; 150 | int target_id; 151 | } scan_dir_option_t; 152 | 153 | class Fat32Fs: public FileSystem { 154 | public: 155 | enum class FatType { 156 | Fat32, 157 | Fat16, 158 | Fat12 159 | }; 160 | 161 | void init(dev_t dev); 162 | dentry_t * lookup(inode_t * dir, dentry_t *) override; 163 | 164 | ssize_t read(File *, char * buf, size_t count, off_t * offset) override; 165 | ssize_t write(File *, const char * buf, size_t, off_t *offset) override; 166 | int readdir(File *, dentry_t *, filldir_t) override; 167 | 168 | private: 169 | dev_t _dev; // disk device, no partition info included 170 | dev_t _pdev; // partiton dev 171 | fat_bs_t _fat_bs; 172 | FatType _type; 173 | 174 | uint32_t _total_sects; 175 | uint32_t _fat_sects; 176 | uint32_t _root_sects; // fat12/16 177 | uint32_t _root_start_sect; 178 | uint32_t _data_start_sect; 179 | uint32_t _clusters; 180 | uint32_t _blksize; 181 | uint32_t _lba_start; // start phy sector of filesystem in disk 182 | 183 | fat_inode_t _icaches[256]; 184 | int _icache_size; 185 | 186 | uint32_t sector2cluster(uint32_t); 187 | uint32_t cluster2sector(uint32_t); 188 | void read_inode(inode_t* ip, fat_inode_t* fat_ip = NULL); 189 | int scan_dir(inode_t* dir, scan_dir_option_t* opt, inode_t** ip); 190 | ssize_t read_file_cluster(char * buf, size_t count, uint32_t off, uint32_t cluster); 191 | fat_inode_t* build_fat_inode(union fat_dirent* dp, int dp_len); 192 | uint32_t find_next_cluster(uint32_t cluster); 193 | 194 | fat_inode_t* find_in_cache(inode_t* dir, int id); 195 | void push_cache(fat_inode_t* fat_ip); 196 | }; 197 | 198 | FileSystem* create_fat32fs(const void*); 199 | #endif 200 | 201 | 202 | --------------------------------------------------------------------------------