├── .gitignore ├── LICENSE ├── README.md └── code ├── Makefile ├── boot ├── asm.h ├── bootasm.S └── bootmain.c ├── disk0 ├── script │ ├── test1.sh │ ├── test2.sh │ └── test3.sh ├── test │ └── testfile └── testman │ ├── awk │ ├── coreutils │ ├── cat │ ├── cp │ ├── ls │ ├── mv │ └── rm │ ├── cpp │ ├── gcc │ ├── gdb │ ├── ld │ ├── sed │ └── zsh ├── kern ├── debug │ ├── assert.h │ ├── kdebug.c │ ├── kdebug.h │ ├── monitor.c │ ├── monitor.h │ ├── panic.c │ └── stab.h ├── driver │ ├── clock.c │ ├── clock.h │ ├── console.c │ ├── console.h │ ├── ide.c │ ├── ide.h │ ├── intr.c │ ├── intr.h │ ├── kbdreg.h │ ├── picirq.c │ └── picirq.h ├── fs │ ├── devs │ │ ├── dev.c │ │ ├── dev.h │ │ ├── dev_disk0.c │ │ ├── dev_null.c │ │ ├── dev_stdin.c │ │ └── dev_stdout.c │ ├── file.c │ ├── file.h │ ├── fs.c │ ├── fs.h │ ├── iobuf.c │ ├── iobuf.h │ ├── pipe │ │ ├── pipe.c │ │ ├── pipe.h │ │ ├── pipe_inode.c │ │ ├── pipe_root.c │ │ ├── pipe_state.c │ │ └── pipe_state.h │ ├── sfs │ │ ├── bitmap.c │ │ ├── bitmap.h │ │ ├── sfs.c │ │ ├── sfs.h │ │ ├── sfs_fs.c │ │ ├── sfs_inode.c │ │ ├── sfs_io.c │ │ └── sfs_lock.c │ ├── swap │ │ ├── swapfs.c │ │ └── swapfs.h │ ├── sysfile.c │ ├── sysfile.h │ └── vfs │ │ ├── inode.c │ │ ├── inode.h │ │ ├── vfs.c │ │ ├── vfs.h │ │ ├── vfsdev.c │ │ ├── vfsfile.c │ │ ├── vfslookup.c │ │ └── vfspath.c ├── init │ ├── entry.S │ └── init.c ├── libs │ ├── rb_tree.c │ ├── rb_tree.h │ ├── readline.c │ ├── stdio.c │ └── string.c ├── mm │ ├── buddy_pmm.c │ ├── buddy_pmm.h │ ├── memlayout.h │ ├── mmu.h │ ├── pmm.c │ ├── pmm.h │ ├── shmem.c │ ├── shmem.h │ ├── slab.c │ ├── slab.h │ ├── swap.c │ ├── swap.h │ ├── vmm.c │ └── vmm.h ├── process │ ├── entry.S │ ├── proc.c │ ├── proc.h │ └── switch.S ├── schedule │ ├── sched.c │ ├── sched.h │ ├── sched_MLFQ.c │ ├── sched_MLFQ.h │ ├── sched_RR.c │ └── sched_RR.h ├── sync │ ├── event.c │ ├── event.h │ ├── ipc.h │ ├── mbox.c │ ├── mbox.h │ ├── sem.c │ ├── sem.h │ ├── sync.c │ ├── sync.h │ ├── wait.c │ └── wait.h ├── syscall │ ├── syscall.c │ └── syscall.h └── trap │ ├── trap.c │ ├── trap.h │ ├── trapentry.S │ └── vectors.S ├── libs ├── atomic.h ├── dirent.h ├── elf.h ├── error.h ├── hash.c ├── list.h ├── mboxbuf.h ├── printfmt.c ├── rand.c ├── stat.h ├── stdarg.h ├── stdio.h ├── stdlib.h ├── string.c ├── string.h ├── types.h ├── unistd.h └── x86.h ├── tools ├── function.mk ├── gdbinit ├── grade.sh ├── kernel.ld ├── mksfs.c ├── sign.c ├── user.ld └── vector.c └── user ├── badarg.c ├── badbrktest.c ├── badsegment.c ├── brkfreetest.c ├── brktest.c ├── buggy_event.c ├── buggy_wait.c ├── buggy_wait2.c ├── cat.c ├── cowtest.c ├── divzero.c ├── echo.c ├── eventtest.c ├── exit.c ├── faultread.c ├── faultreadkernel.c ├── forktest.c ├── forktree.c ├── fread_test.c ├── fread_test2.c ├── fwrite_test.c ├── hello.c ├── hello2.c ├── libs ├── clone.S ├── dir.c ├── dir.h ├── file.c ├── file.h ├── initcode.S ├── lock.h ├── malloc.c ├── malloc.h ├── panic.c ├── spipe.c ├── spipe.h ├── stdio.c ├── string.c ├── syscall.c ├── syscall.h ├── thread.c ├── thread.h ├── ulib.c ├── ulib.h └── umain.c ├── link.c ├── ls.c ├── matrix.c ├── mboxmap.c ├── mboxtest.c ├── mkdir.c ├── mmaptest.c ├── nulldevfs_test.c ├── pgdir.c ├── pipetest.c ├── pipetest2.c ├── primer.c ├── primer2.c ├── primer3.c ├── pwd.c ├── rename.c ├── robot.c ├── sem_rf.c ├── sem_wf.c ├── semtest.c ├── semtest2.c ├── semtest3.c ├── semtest4.c ├── sfs_dirtest1.c ├── sfs_dirtest2.c ├── sfs_dirtest3.c ├── sfs_exectest1.c ├── sfs_exectest2.c ├── sfs_filetest1.c ├── sfs_filetest2.c ├── sfs_filetest3.c ├── sh.c ├── shmemtest.c ├── sleep.c ├── sleepkill.c ├── softint.c ├── spin.c ├── spipetest.c ├── spipetest2.c ├── swaptest.c ├── testbss.c ├── threadfork.c ├── threadgroup1.c ├── threadgroup2.c ├── threadtest.c ├── threadwork.c ├── unlink.c ├── waitkill.c └── yield.c /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ 3 | *~ 4 | *.bak 5 | *.d 6 | *.o 7 | *.org 8 | .gdb.in 9 | .qemu.out 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 一步一步构建ucore OS(配套代码) 2 | ====================== 3 | "操作系统简单实现与基本原理 — 基于ucore" (持续更新) http://chyyuu.gitbooks.io/ucorebook/ 4 | 5 | 介绍 6 | ====================== 7 | ucore OS是用于清华大学计算机系本科操作系统课程的OS教学试验内容。 8 | ucore OS起源于MIT CSAIL PDOS课题组开发的xv6&jos、哈佛大学开发的 9 | OS161教学操作系统、以及Linux-2.4内核。 10 | 11 | ucore OS中包含的xv6&jos代码版权属于Frans Kaashoek, Robert Morris, 12 | and Russ Cox,使用MIT License。ucore OS中包含的OS/161代码版权属于 13 | David A. Holland。其他代码版权属于陈渝、王乃铮、向勇,并采用GPL License. 14 | ucore OS相关的文档版权属于陈渝、向勇,并采用 Creative Commons 15 | Attribution/Share-Alike (CC-BY-SA) License. 16 | 17 | 开发维护人员 18 | ====================== 19 | * 陈渝 http://soft.cs.tsinghua.edu.cn/~chen 20 | * 茅俊杰 eternal.n08 AT gmail.com 21 | 22 | 相关资料 23 | ====================== 24 | * https://github.com/chyyuu/mooc_os 25 | -------------------------------------------------------------------------------- /code/boot/asm.h: -------------------------------------------------------------------------------- 1 | #ifndef __BOOT_ASM_H__ 2 | #define __BOOT_ASM_H__ 3 | 4 | /* Assembler macros to create x86 segments */ 5 | 6 | /* Normal segment */ 7 | #define SEG_NULLASM \ 8 | .word 0, 0; \ 9 | .byte 0, 0, 0, 0 10 | 11 | #define SEG_ASM(type,base,lim) \ 12 | .word (((lim) >> 12) & 0xffff), ((base) & 0xffff); \ 13 | .byte (((base) >> 16) & 0xff), (0x90 | (type)), \ 14 | (0xC0 | (((lim) >> 28) & 0xf)), (((base) >> 24) & 0xff) 15 | 16 | 17 | /* Application segment type bits */ 18 | #define STA_X 0x8 // Executable segment 19 | #define STA_E 0x4 // Expand down (non-executable segments) 20 | #define STA_C 0x4 // Conforming code segment (executable only) 21 | #define STA_W 0x2 // Writeable (non-executable segments) 22 | #define STA_R 0x2 // Readable (executable segments) 23 | #define STA_A 0x1 // Accessed 24 | 25 | #endif /* !__BOOT_ASM_H__ */ 26 | 27 | -------------------------------------------------------------------------------- /code/disk0/script/test1.sh: -------------------------------------------------------------------------------- 1 | ls 2 | cd test 3 | pwd 4 | ls /testman > xx 5 | cat xx 6 | unlink xx 7 | echo test1.sh end. 8 | 9 | -------------------------------------------------------------------------------- /code/disk0/script/test2.sh: -------------------------------------------------------------------------------- 1 | cd test 2 | mkdir pp 3 | cd pp 4 | ls /bin | cat > qq 5 | link qq pp 6 | ls 7 | cd .. 8 | link pp/pp orz 9 | unlink pp/pp pp/qq 10 | rename pp qq 11 | unlink qq 12 | unlink orz 13 | echo test2.sh end. 14 | 15 | -------------------------------------------------------------------------------- /code/disk0/script/test3.sh: -------------------------------------------------------------------------------- 1 | cat script/test2.sh > test/tmp.sh 2 | ls test 3 | sh < test/tmp.sh 4 | unlink test/tmp.sh 5 | echo test3.sh end. 6 | 7 | -------------------------------------------------------------------------------- /code/disk0/test/testfile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chyyuu/ucorebook_code/18da356a2f3ef90680aca9cc50ef328d1e84585e/code/disk0/test/testfile -------------------------------------------------------------------------------- /code/disk0/testman/coreutils/cat: -------------------------------------------------------------------------------- 1 | CAT(1) User Commands CAT(1) 2 | 3 | 4 | 5 | NAME 6 | cat - concatenate files and print on the standard output 7 | 8 | SYNOPSIS 9 | cat [OPTION]... [FILE]... 10 | 11 | DESCRIPTION 12 | Concatenate FILE(s), or standard input, to standard output. 13 | 14 | -A, --show-all 15 | equivalent to -vET 16 | 17 | -b, --number-nonblank 18 | number nonempty output lines 19 | 20 | -e equivalent to -vE 21 | 22 | -E, --show-ends 23 | display $ at end of each line 24 | 25 | -n, --number 26 | number all output lines 27 | 28 | -s, --squeeze-blank 29 | suppress repeated empty output lines 30 | 31 | -t equivalent to -vT 32 | 33 | -T, --show-tabs 34 | display TAB characters as ^I 35 | 36 | -u (ignored) 37 | 38 | -v, --show-nonprinting 39 | use ^ and M- notation, except for LFD and TAB 40 | 41 | --help display this help and exit 42 | 43 | --version 44 | output version information and exit 45 | 46 | With no FILE, or when FILE is -, read standard input. 47 | 48 | EXAMPLES 49 | cat f - g 50 | Output f's contents, then standard input, then g's contents. 51 | 52 | cat Copy standard input to standard output. 53 | 54 | AUTHOR 55 | Written by Torbjorn Granlund and Richard M. Stallman. 56 | 57 | REPORTING BUGS 58 | Report cat bugs to bug-coreutils@gnu.org 59 | GNU coreutils home page: 60 | General help using GNU software: 61 | Report cat translation bugs to 62 | 63 | COPYRIGHT 64 | Copyright (C) 2010 Free Software Foundation, Inc. License GPLv3+: GNU 65 | GPL version 3 or later . 66 | This is free software: you are free to change and redistribute it. 67 | There is NO WARRANTY, to the extent permitted by law. 68 | 69 | SEE ALSO 70 | The full documentation for cat is maintained as a Texinfo manual. If 71 | the info and cat programs are properly installed at your site, the com- 72 | mand 73 | 74 | info coreutils 'cat invocation' 75 | 76 | should give you access to the complete manual. 77 | 78 | 79 | 80 | GNU coreutils 8.5 April 2010 CAT(1) 81 | -------------------------------------------------------------------------------- /code/disk0/testman/coreutils/mv: -------------------------------------------------------------------------------- 1 | MV(1) User Commands MV(1) 2 | 3 | 4 | 5 | NAME 6 | mv - move (rename) files 7 | 8 | SYNOPSIS 9 | mv [OPTION]... [-T] SOURCE DEST 10 | mv [OPTION]... SOURCE... DIRECTORY 11 | mv [OPTION]... -t DIRECTORY SOURCE... 12 | 13 | DESCRIPTION 14 | Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY. 15 | 16 | Mandatory arguments to long options are mandatory for short options 17 | too. 18 | 19 | --backup[=CONTROL] 20 | make a backup of each existing destination file 21 | 22 | -b like --backup but does not accept an argument 23 | 24 | -f, --force 25 | do not prompt before overwriting 26 | 27 | -i, --interactive 28 | prompt before overwrite 29 | 30 | -n, --no-clobber 31 | do not overwrite an existing file 32 | 33 | If you specify more than one of -i, -f, -n, only the final one takes 34 | effect. 35 | 36 | --strip-trailing-slashes 37 | remove any trailing slashes from each SOURCE argument 38 | 39 | -S, --suffix=SUFFIX 40 | override the usual backup suffix 41 | 42 | -t, --target-directory=DIRECTORY 43 | move all SOURCE arguments into DIRECTORY 44 | 45 | -T, --no-target-directory 46 | treat DEST as a normal file 47 | 48 | -u, --update 49 | move only when the SOURCE file is newer than the destination 50 | file or when the destination file is missing 51 | 52 | -v, --verbose 53 | explain what is being done 54 | 55 | --help display this help and exit 56 | 57 | --version 58 | output version information and exit 59 | 60 | The backup suffix is `~', unless set with --suffix or SIM- 61 | PLE_BACKUP_SUFFIX. The version control method may be selected via the 62 | --backup option or through the VERSION_CONTROL environment variable. 63 | Here are the values: 64 | 65 | none, off 66 | never make backups (even if --backup is given) 67 | 68 | numbered, t 69 | make numbered backups 70 | 71 | existing, nil 72 | numbered if numbered backups exist, simple otherwise 73 | 74 | simple, never 75 | always make simple backups 76 | 77 | AUTHOR 78 | Written by Mike Parker, David MacKenzie, and Jim Meyering. 79 | 80 | REPORTING BUGS 81 | Report mv bugs to bug-coreutils@gnu.org 82 | GNU coreutils home page: 83 | General help using GNU software: 84 | Report mv translation bugs to 85 | 86 | COPYRIGHT 87 | Copyright (C) 2010 Free Software Foundation, Inc. License GPLv3+: GNU 88 | GPL version 3 or later . 89 | This is free software: you are free to change and redistribute it. 90 | There is NO WARRANTY, to the extent permitted by law. 91 | 92 | SEE ALSO 93 | rename(2) 94 | 95 | The full documentation for mv is maintained as a Texinfo manual. If 96 | the info and mv programs are properly installed at your site, the com- 97 | mand 98 | 99 | info coreutils 'mv invocation' 100 | 101 | should give you access to the complete manual. 102 | 103 | 104 | 105 | GNU coreutils 8.5 April 2010 MV(1) 106 | -------------------------------------------------------------------------------- /code/kern/debug/assert.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_DEBUG_ASSERT_H__ 2 | #define __KERN_DEBUG_ASSERT_H__ 3 | 4 | void __warn(const char *file, int line, const char *fmt, ...); 5 | void __panic(const char *file, int line, const char *fmt, ...) __attribute__((noreturn)); 6 | 7 | #define warn(...) \ 8 | __warn(__FILE__, __LINE__, __VA_ARGS__) 9 | 10 | #define panic(...) \ 11 | __panic(__FILE__, __LINE__, __VA_ARGS__) 12 | 13 | #define assert(x) \ 14 | do { \ 15 | if (!(x)) { \ 16 | panic("assertion failed: %s", #x); \ 17 | } \ 18 | } while (0) 19 | 20 | // static_assert(x) will generate a compile-time error if 'x' is false. 21 | #define static_assert(x) \ 22 | switch (x) { case 0: case (x): ; } 23 | 24 | #endif /* !__KERN_DEBUG_ASSERT_H__ */ 25 | 26 | -------------------------------------------------------------------------------- /code/kern/debug/kdebug.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_DEBUG_KDEBUG_H__ 2 | #define __KERN_DEBUG_KDEBUG_H__ 3 | 4 | #include 5 | #include 6 | 7 | void print_kerninfo(void); 8 | void print_stackframe(void); 9 | void print_debuginfo(uintptr_t eip); 10 | 11 | // number of debug registers 12 | #define MAX_DR_NUM 4 13 | 14 | // index of DR6-Debug status and DR7-Debug control 15 | #define DR_STATUS 6 16 | #define DR_CONTROL 7 17 | 18 | /* DR6 Register */ 19 | #define DR6_B0_BIT 0x00000001 20 | #define DR6_B1_BIT 0x00000002 21 | #define DR6_B2_BIT 0x00000004 22 | #define DR6_B3_BIT 0x00000008 23 | 24 | /* DR7 Register */ 25 | #define DR7_L0_BIT 0x00000001 26 | #define DR7_G0_BIT 0x00000002 27 | #define DR7_L1_BIT 0x00000004 28 | #define DR7_G1_BIT 0x00000008 29 | #define DR7_L2_BIT 0x00000010 30 | #define DR7_G2_BIT 0x00000020 31 | #define DR7_L3_BIT 0x00000040 32 | #define DR7_G3_BIT 0x00000080 33 | #define DR7_LEXACT 0x00000100 34 | #define DR7_GEXACT 0x00000200 35 | #define DR7_GDETECT 0x00002000 36 | #define DR7_MASK 0xFFFF0000 37 | 38 | void debug_init(void); 39 | void debug_monitor(struct trapframe *tf); 40 | void debug_list_dr(void); 41 | int debug_enable_dr(unsigned regnum, uintptr_t addr, unsigned type, unsigned len); 42 | int debug_disable_dr(unsigned regnum); 43 | 44 | #endif /* !__KERN_DEBUG_KDEBUG_H__ */ 45 | 46 | -------------------------------------------------------------------------------- /code/kern/debug/monitor.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_DEBUG_MONITOR_H__ 2 | #define __KERN_DEBUG_MONITOR_H__ 3 | 4 | #include 5 | 6 | void monitor(struct trapframe *tf); 7 | 8 | int mon_help(int argc, char **argv, struct trapframe *tf); 9 | int mon_kerninfo(int argc, char **argv, struct trapframe *tf); 10 | int mon_backtrace(int argc, char **argv, struct trapframe *tf); 11 | int mon_continue(int argc, char **argv, struct trapframe *tf); 12 | int mon_step(int argc, char **argv, struct trapframe *tf); 13 | int mon_breakpoint(int argc, char **argv, struct trapframe *tf); 14 | int mon_watchpoint(int argc, char **argv, struct trapframe *tf); 15 | int mon_delete_dr(int argc, char **argv, struct trapframe *tf); 16 | int mon_list_dr(int argc, char **argv, struct trapframe *tf); 17 | 18 | #endif /* !__KERN_DEBUG_MONITOR_H__ */ 19 | 20 | -------------------------------------------------------------------------------- /code/kern/debug/panic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | static bool is_panic = 0; 7 | 8 | /* * 9 | * __panic - __panic is called on unresolvable fatal errors. it prints 10 | * "panic: 'message'", and then enters the kernel monitor. 11 | * */ 12 | void 13 | __panic(const char *file, int line, const char *fmt, ...) { 14 | if (is_panic) { 15 | goto panic_dead; 16 | } 17 | is_panic = 1; 18 | 19 | // print the 'message' 20 | va_list ap; 21 | va_start(ap, fmt); 22 | cprintf("kernel panic at %s:%d:\n ", file, line); 23 | vcprintf(fmt, ap); 24 | cprintf("\n"); 25 | va_end(ap); 26 | 27 | panic_dead: 28 | intr_disable(); 29 | while (1) { 30 | monitor(NULL); 31 | } 32 | } 33 | 34 | /* __warn - like panic, but don't */ 35 | void 36 | __warn(const char *file, int line, const char *fmt, ...) { 37 | va_list ap; 38 | va_start(ap, fmt); 39 | cprintf("kernel warning at %s:%d:\n ", file, line); 40 | vcprintf(fmt, ap); 41 | cprintf("\n"); 42 | va_end(ap); 43 | } 44 | 45 | bool 46 | is_kernel_panic(void) { 47 | return is_panic; 48 | } 49 | 50 | -------------------------------------------------------------------------------- /code/kern/debug/stab.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_DEBUG_STAB_H__ 2 | #define __KERN_DEBUG_STAB_H__ 3 | 4 | #include 5 | 6 | /* * 7 | * STABS debugging info 8 | * 9 | * The kernel debugger can understand some debugging information in 10 | * the STABS format. For more information on this format, see 11 | * http://sources.redhat.com/gdb/onlinedocs/stabs_toc.html 12 | * 13 | * The constants below define some symbol types used by various debuggers 14 | * and compilers. Kernel uses the N_SO, N_SOL, N_FUN, and N_SLINE types. 15 | * */ 16 | 17 | #define N_GSYM 0x20 // global symbol 18 | #define N_FNAME 0x22 // F77 function name 19 | #define N_FUN 0x24 // procedure name 20 | #define N_STSYM 0x26 // data segment variable 21 | #define N_LCSYM 0x28 // bss segment variable 22 | #define N_MAIN 0x2a // main function name 23 | #define N_PC 0x30 // global Pascal symbol 24 | #define N_RSYM 0x40 // register variable 25 | #define N_SLINE 0x44 // text segment line number 26 | #define N_DSLINE 0x46 // data segment line number 27 | #define N_BSLINE 0x48 // bss segment line number 28 | #define N_SSYM 0x60 // structure/union element 29 | #define N_SO 0x64 // main source file name 30 | #define N_LSYM 0x80 // stack variable 31 | #define N_BINCL 0x82 // include file beginning 32 | #define N_SOL 0x84 // included source file name 33 | #define N_PSYM 0xa0 // parameter variable 34 | #define N_EINCL 0xa2 // include file end 35 | #define N_ENTRY 0xa4 // alternate entry point 36 | #define N_LBRAC 0xc0 // left bracket 37 | #define N_EXCL 0xc2 // deleted include file 38 | #define N_RBRAC 0xe0 // right bracket 39 | #define N_BCOMM 0xe2 // begin common 40 | #define N_ECOMM 0xe4 // end common 41 | #define N_ECOML 0xe8 // end common (local name) 42 | #define N_LENG 0xfe // length of preceding entry 43 | 44 | /* Entries in the STABS table are formatted as follows. */ 45 | struct stab { 46 | uint32_t n_strx; // index into string table of name 47 | uint8_t n_type; // type of symbol 48 | uint8_t n_other; // misc info (usually empty) 49 | uint16_t n_desc; // description field 50 | uintptr_t n_value; // value of symbol 51 | }; 52 | 53 | #endif /* !__KERN_DEBUG_STAB_H__ */ 54 | 55 | -------------------------------------------------------------------------------- /code/kern/driver/clock.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | /* * 7 | * Support for time-related hardware gadgets - the 8253 timer, 8 | * which generates interruptes on IRQ-0. 9 | * */ 10 | 11 | #define IO_TIMER1 0x040 // 8253 Timer #1 12 | 13 | /* * 14 | * Frequency of all three count-down timers; (TIMER_FREQ/freq) 15 | * is the appropriate count to generate a frequency of freq Hz. 16 | * */ 17 | 18 | #define TIMER_FREQ 1193182 19 | #define TIMER_DIV(x) ((TIMER_FREQ + (x) / 2) / (x)) 20 | 21 | #define TIMER_MODE (IO_TIMER1 + 3) // timer mode port 22 | #define TIMER_SEL0 0x00 // select counter 0 23 | #define TIMER_RATEGEN 0x04 // mode 2, rate generator 24 | #define TIMER_16BIT 0x30 // r/w counter 16 bits, LSB first 25 | 26 | volatile size_t ticks; 27 | 28 | /* * 29 | * clock_init - initialize 8253 clock to interrupt 100 times per second, 30 | * and then enable IRQ_TIMER. 31 | * */ 32 | void 33 | clock_init(void) { 34 | // set 8253 timer-chip 35 | outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); 36 | outb(IO_TIMER1, TIMER_DIV(100) % 256); 37 | outb(IO_TIMER1, TIMER_DIV(100) / 256); 38 | 39 | // initialize time counter 'ticks' to zero 40 | ticks = 0; 41 | 42 | cprintf("++ setup timer interrupts\n"); 43 | pic_enable(IRQ_TIMER); 44 | } 45 | 46 | -------------------------------------------------------------------------------- /code/kern/driver/clock.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_DRIVER_CLOCK_H__ 2 | #define __KERN_DRIVER_CLOCK_H__ 3 | 4 | #include 5 | 6 | extern volatile size_t ticks; 7 | 8 | void clock_init(void); 9 | 10 | #endif /* !__KERN_DRIVER_CLOCK_H__ */ 11 | 12 | -------------------------------------------------------------------------------- /code/kern/driver/console.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_DRIVER_CONSOLE_H__ 2 | #define __KERN_DRIVER_CONSOLE_H__ 3 | 4 | void cons_init(void); 5 | void cons_putc(int c); 6 | int cons_getc(void); 7 | void serial_intr(void); 8 | void kbd_intr(void); 9 | 10 | #endif /* !__KERN_DRIVER_CONSOLE_H__ */ 11 | 12 | -------------------------------------------------------------------------------- /code/kern/driver/ide.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_DRIVER_IDE_H__ 2 | #define __KERN_DRIVER_IDE_H__ 3 | 4 | #include 5 | 6 | void ide_init(void); 7 | bool ide_device_valid(unsigned short ideno); 8 | size_t ide_device_size(unsigned short ideno); 9 | 10 | int ide_read_secs(unsigned short ideno, uint32_t secno, void *dst, size_t nsecs); 11 | int ide_write_secs(unsigned short ideno, uint32_t secno, const void *src, size_t nsecs); 12 | 13 | #endif /* !__KERN_DRIVER_IDE_H__ */ 14 | 15 | -------------------------------------------------------------------------------- /code/kern/driver/intr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* intr_enable - enable irq interrupt */ 5 | void 6 | intr_enable(void) { 7 | sti(); 8 | } 9 | 10 | /* intr_disable - disable irq interrupt */ 11 | void 12 | intr_disable(void) { 13 | cli(); 14 | } 15 | 16 | -------------------------------------------------------------------------------- /code/kern/driver/intr.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_DRIVER_INTR_H__ 2 | #define __KERN_DRIVER_INTR_H__ 3 | 4 | void intr_enable(void); 5 | void intr_disable(void); 6 | 7 | #endif /* !__KERN_DRIVER_INTR_H__ */ 8 | 9 | -------------------------------------------------------------------------------- /code/kern/driver/picirq.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // I/O Addresses of the two programmable interrupt controllers 6 | #define IO_PIC1 0x20 // Master (IRQs 0-7) 7 | #define IO_PIC2 0xA0 // Slave (IRQs 8-15) 8 | 9 | #define IRQ_SLAVE 2 // IRQ at which slave connects to master 10 | 11 | // Current IRQ mask. 12 | // Initial IRQ mask has interrupt 2 enabled (for slave 8259A). 13 | static uint16_t irq_mask = 0xFFFF & ~(1 << IRQ_SLAVE); 14 | static bool did_init = 0; 15 | 16 | static void 17 | pic_setmask(uint16_t mask) { 18 | irq_mask = mask; 19 | if (did_init) { 20 | outb(IO_PIC1 + 1, mask); 21 | outb(IO_PIC2 + 1, mask >> 8); 22 | } 23 | } 24 | 25 | void 26 | pic_enable(unsigned int irq) { 27 | pic_setmask(irq_mask & ~(1 << irq)); 28 | } 29 | 30 | /* pic_init - initialize the 8259A interrupt controllers */ 31 | void 32 | pic_init(void) { 33 | did_init = 1; 34 | 35 | // mask all interrupts 36 | outb(IO_PIC1 + 1, 0xFF); 37 | outb(IO_PIC2 + 1, 0xFF); 38 | 39 | // Set up master (8259A-1) 40 | 41 | // ICW1: 0001g0hi 42 | // g: 0 = edge triggering, 1 = level triggering 43 | // h: 0 = cascaded PICs, 1 = master only 44 | // i: 0 = no ICW4, 1 = ICW4 required 45 | outb(IO_PIC1, 0x11); 46 | 47 | // ICW2: Vector offset 48 | outb(IO_PIC1 + 1, IRQ_OFFSET); 49 | 50 | // ICW3: (master PIC) bit mask of IR lines connected to slaves 51 | // (slave PIC) 3-bit # of slave's connection to master 52 | outb(IO_PIC1 + 1, 1 << IRQ_SLAVE); 53 | 54 | // ICW4: 000nbmap 55 | // n: 1 = special fully nested mode 56 | // b: 1 = buffered mode 57 | // m: 0 = slave PIC, 1 = master PIC 58 | // (ignored when b is 0, as the master/slave role 59 | // can be hardwired). 60 | // a: 1 = Automatic EOI mode 61 | // p: 0 = MCS-80/85 mode, 1 = intel x86 mode 62 | outb(IO_PIC1 + 1, 0x3); 63 | 64 | // Set up slave (8259A-2) 65 | outb(IO_PIC2, 0x11); // ICW1 66 | outb(IO_PIC2 + 1, IRQ_OFFSET + 8); // ICW2 67 | outb(IO_PIC2 + 1, IRQ_SLAVE); // ICW3 68 | // NB Automatic EOI mode doesn't tend to work on the slave. 69 | // Linux source code says it's "to be investigated". 70 | outb(IO_PIC2 + 1, 0x3); // ICW4 71 | 72 | // OCW3: 0ef01prs 73 | // ef: 0x = NOP, 10 = clear specific mask, 11 = set specific mask 74 | // p: 0 = no polling, 1 = polling mode 75 | // rs: 0x = NOP, 10 = read IRR, 11 = read ISR 76 | outb(IO_PIC1, 0x68); // clear specific mask 77 | outb(IO_PIC1, 0x0a); // read IRR by default 78 | 79 | outb(IO_PIC2, 0x68); // OCW3 80 | outb(IO_PIC2, 0x0a); // OCW3 81 | 82 | if (irq_mask != 0xFFFF) { 83 | pic_setmask(irq_mask); 84 | } 85 | } 86 | 87 | -------------------------------------------------------------------------------- /code/kern/driver/picirq.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_DRIVER_PICIRQ_H__ 2 | #define __KERN_DRIVER_PICIRQ_H__ 3 | 4 | void pic_init(void); 5 | void pic_enable(unsigned int irq); 6 | 7 | #define IRQ_OFFSET 32 8 | 9 | #endif /* !__KERN_DRIVER_PICIRQ_H__ */ 10 | 11 | -------------------------------------------------------------------------------- /code/kern/fs/devs/dev.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_FS_DEVS_DEV_H__ 2 | #define __KERN_FS_DEVS_DEV_H__ 3 | 4 | #include 5 | 6 | struct inode; 7 | struct iobuf; 8 | 9 | /* 10 | * Filesystem-namespace-accessible device. 11 | * d_io is for both reads and writes; the iob indicates the io buffer, write indicates direction. 12 | */ 13 | struct device { 14 | size_t d_blocks; 15 | size_t d_blocksize; 16 | int (*d_open)(struct device *dev, uint32_t open_flags); 17 | int (*d_close)(struct device *dev); 18 | int (*d_io)(struct device *dev, struct iobuf *iob, bool write); 19 | int (*d_ioctl)(struct device *dev, int op, void *data); 20 | }; 21 | 22 | #define dop_open(dev, open_flags) ((dev)->d_open(dev, open_flags)) 23 | #define dop_close(dev) ((dev)->d_close(dev)) 24 | #define dop_io(dev, iob, write) ((dev)->d_io(dev, iob, write)) 25 | #define dop_ioctl(dev, op, data) ((dev)->d_ioctl(dev, op, data)) 26 | 27 | void dev_init(void); 28 | /* Create inode for a vfs-level device. */ 29 | struct inode *dev_create_inode(void); 30 | 31 | #endif /* !__KERN_FS_DEVS_DEV_H__ */ 32 | 33 | -------------------------------------------------------------------------------- /code/kern/fs/devs/dev_null.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Implementation of the null device, "null:", which generates an 3 | * immediate EOF on read and throws away anything written to it. 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | /* For open() */ 14 | static int 15 | null_open(struct device *dev, uint32_t open_flags) { 16 | return 0; 17 | } 18 | 19 | /* For close() */ 20 | static int 21 | null_close(struct device *dev) { 22 | return 0; 23 | } 24 | 25 | /* For dop_io() */ 26 | static int 27 | null_io(struct device *dev, struct iobuf *iob, bool write) { 28 | /* 29 | * On write, discard everything without looking at it. 30 | * On read, do nothing, generating an immediate EOF. 31 | */ 32 | if (write) { 33 | iob->io_resid = 0; 34 | } 35 | return 0; 36 | } 37 | 38 | /* For ioctl() */ 39 | static int 40 | null_ioctl(struct device *dev, int op, void *data) { 41 | return -E_INVAL; 42 | } 43 | 44 | static void 45 | null_device_init(struct device *dev) { 46 | dev->d_blocks = 0; 47 | dev->d_blocksize = 1; 48 | dev->d_open = null_open; 49 | dev->d_close = null_close; 50 | dev->d_io = null_io; 51 | dev->d_ioctl = null_ioctl; 52 | } 53 | 54 | /* 55 | * Function to create and attach null: 56 | */ 57 | void 58 | dev_init_null(void) { 59 | struct inode *node; 60 | if ((node = dev_create_inode()) == NULL) { 61 | panic("null: dev_create_node.\n"); 62 | } 63 | null_device_init(vop_info(node, device)); 64 | 65 | int ret; 66 | if ((ret = vfs_add_dev("null", node, 0)) != 0) { 67 | panic("null: vfs_add_dev: %e.\n", ret); 68 | } 69 | } 70 | 71 | -------------------------------------------------------------------------------- /code/kern/fs/devs/dev_stdin.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define STDIN_BUFSIZE 4096 16 | 17 | static char stdin_buffer[STDIN_BUFSIZE]; 18 | static off_t p_rpos, p_wpos; 19 | static wait_queue_t __wait_queue, *wait_queue = &__wait_queue; 20 | 21 | void 22 | dev_stdin_write(char c) { 23 | bool intr_flag; 24 | if (c != '\0') { 25 | local_intr_save(intr_flag); 26 | { 27 | stdin_buffer[p_wpos % STDIN_BUFSIZE] = c; 28 | if (p_wpos - p_rpos < STDIN_BUFSIZE) { 29 | p_wpos ++; 30 | } 31 | if (!wait_queue_empty(wait_queue)) { 32 | wakeup_queue(wait_queue, WT_KBD, 1); 33 | } 34 | } 35 | local_intr_restore(intr_flag); 36 | } 37 | } 38 | 39 | static int 40 | dev_stdin_read(char *buf, size_t len) { 41 | int ret = 0; 42 | bool intr_flag; 43 | local_intr_save(intr_flag); 44 | { 45 | for (; ret < len; ret ++, p_rpos ++) { 46 | try_again: 47 | if (p_rpos < p_wpos) { 48 | *buf ++ = stdin_buffer[p_rpos % STDIN_BUFSIZE]; 49 | } 50 | else { 51 | wait_t __wait, *wait = &__wait; 52 | wait_current_set(wait_queue, wait, WT_KBD); 53 | local_intr_restore(intr_flag); 54 | 55 | schedule(); 56 | 57 | local_intr_save(intr_flag); 58 | wait_current_del(wait_queue, wait); 59 | if (wait->wakeup_flags == WT_KBD) { 60 | goto try_again; 61 | } 62 | break; 63 | } 64 | } 65 | } 66 | local_intr_restore(intr_flag); 67 | return ret; 68 | } 69 | 70 | static int 71 | stdin_open(struct device *dev, uint32_t open_flags) { 72 | if (open_flags != O_RDONLY) { 73 | return -E_INVAL; 74 | } 75 | return 0; 76 | } 77 | 78 | static int 79 | stdin_close(struct device *dev) { 80 | return 0; 81 | } 82 | 83 | static int 84 | stdin_io(struct device *dev, struct iobuf *iob, bool write) { 85 | if (!write) { 86 | int ret; 87 | if ((ret = dev_stdin_read(iob->io_base, iob->io_resid)) > 0) { 88 | iob->io_resid -= ret; 89 | } 90 | return ret; 91 | } 92 | return -E_INVAL; 93 | } 94 | 95 | static int 96 | stdin_ioctl(struct device *dev, int op, void *data) { 97 | return -E_INVAL; 98 | } 99 | 100 | static void 101 | stdin_device_init(struct device *dev) { 102 | dev->d_blocks = 0; 103 | dev->d_blocksize = 1; 104 | dev->d_open = stdin_open; 105 | dev->d_close = stdin_close; 106 | dev->d_io = stdin_io; 107 | dev->d_ioctl = stdin_ioctl; 108 | 109 | p_rpos = p_wpos = 0; 110 | wait_queue_init(wait_queue); 111 | } 112 | 113 | void 114 | dev_init_stdin(void) { 115 | struct inode *node; 116 | if ((node = dev_create_inode()) == NULL) { 117 | panic("stdin: dev_create_node.\n"); 118 | } 119 | stdin_device_init(vop_info(node, device)); 120 | 121 | int ret; 122 | if ((ret = vfs_add_dev("stdin", node, 0)) != 0) { 123 | panic("stdin: vfs_add_dev: %e.\n", ret); 124 | } 125 | } 126 | 127 | -------------------------------------------------------------------------------- /code/kern/fs/devs/dev_stdout.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | static int 12 | stdout_open(struct device *dev, uint32_t open_flags) { 13 | if (open_flags != O_WRONLY) { 14 | return -E_INVAL; 15 | } 16 | return 0; 17 | } 18 | 19 | static int 20 | stdout_close(struct device *dev) { 21 | return 0; 22 | } 23 | 24 | static int 25 | stdout_io(struct device *dev, struct iobuf *iob, bool write) { 26 | if (write) { 27 | char *data = iob->io_base; 28 | for (; iob->io_resid != 0; iob->io_resid --) { 29 | cputchar(*data ++); 30 | } 31 | return 0; 32 | } 33 | return -E_INVAL; 34 | } 35 | 36 | static int 37 | stdout_ioctl(struct device *dev, int op, void *data) { 38 | return -E_INVAL; 39 | } 40 | 41 | static void 42 | stdout_device_init(struct device *dev) { 43 | dev->d_blocks = 0; 44 | dev->d_blocksize = 1; 45 | dev->d_open = stdout_open; 46 | dev->d_close = stdout_close; 47 | dev->d_io = stdout_io; 48 | dev->d_ioctl = stdout_ioctl; 49 | } 50 | 51 | void 52 | dev_init_stdout(void) { 53 | struct inode *node; 54 | if ((node = dev_create_inode()) == NULL) { 55 | panic("stdout: dev_create_node.\n"); 56 | } 57 | stdout_device_init(vop_info(node, device)); 58 | 59 | int ret; 60 | if ((ret = vfs_add_dev("stdout", node, 0)) != 0) { 61 | panic("stdout: vfs_add_dev: %e.\n", ret); 62 | } 63 | } 64 | 65 | -------------------------------------------------------------------------------- /code/kern/fs/file.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_FS_FILE_H__ 2 | #define __KERN_FS_FILE_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | struct inode; 11 | struct stat; 12 | struct dirent; 13 | 14 | struct file { 15 | enum { 16 | FD_NONE, FD_INIT, FD_OPENED, FD_CLOSED, 17 | } status; 18 | bool readable; 19 | bool writable; 20 | int fd; 21 | off_t pos; 22 | struct inode *node; 23 | atomic_t open_count; 24 | }; 25 | 26 | void filemap_init(struct file *filemap); 27 | void filemap_open(struct file *file); 28 | void filemap_close(struct file *file); 29 | void filemap_dup(struct file *to, struct file *from); 30 | bool file_testfd(int fd, bool readable, bool writable); 31 | 32 | int file_open(char *path, uint32_t open_flags); 33 | int file_close(int fd); 34 | int file_read(int fd, void *base, size_t len, size_t *copied_store); 35 | int file_write(int fd, void *base, size_t len, size_t *copied_store); 36 | int file_seek(int fd, off_t pos, int whence); 37 | int file_fstat(int fd, struct stat *stat); 38 | int file_fsync(int fd); 39 | int file_getdirentry(int fd, struct dirent *dirent); 40 | int file_dup(int fd1, int fd2); 41 | int file_pipe(int fd[]); 42 | int file_mkfifo(const char *name, uint32_t open_flags); 43 | 44 | static inline int 45 | fopen_count(struct file *file) { 46 | return atomic_read(&(file->open_count)); 47 | } 48 | 49 | static inline int 50 | fopen_count_inc(struct file *file) { 51 | return atomic_add_return(&(file->open_count), 1); 52 | } 53 | 54 | static inline int 55 | fopen_count_dec(struct file *file) { 56 | return atomic_sub_return(&(file->open_count), 1); 57 | } 58 | 59 | #endif /* !__KERN_FS_FILE_H__ */ 60 | 61 | -------------------------------------------------------------------------------- /code/kern/fs/fs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | void 13 | fs_init(void) { 14 | vfs_init(); 15 | dev_init(); 16 | pipe_init(); 17 | sfs_init(); 18 | } 19 | 20 | void 21 | fs_cleanup(void) { 22 | vfs_cleanup(); 23 | } 24 | 25 | void 26 | lock_fs(struct fs_struct *fs_struct) { 27 | down(&(fs_struct->fs_sem)); 28 | } 29 | 30 | void 31 | unlock_fs(struct fs_struct *fs_struct) { 32 | up(&(fs_struct->fs_sem)); 33 | } 34 | 35 | struct fs_struct * 36 | fs_create(void) { 37 | static_assert((int)FS_STRUCT_NENTRY > 128); 38 | struct fs_struct *fs_struct; 39 | if ((fs_struct = kmalloc(sizeof(struct fs_struct) + FS_STRUCT_BUFSIZE)) != NULL) { 40 | fs_struct->pwd = NULL; 41 | fs_struct->filemap = (void *)(fs_struct + 1); 42 | atomic_set(&(fs_struct->fs_count), 0); 43 | sem_init(&(fs_struct->fs_sem), 1); 44 | filemap_init(fs_struct->filemap); 45 | } 46 | return fs_struct; 47 | } 48 | 49 | void 50 | fs_destroy(struct fs_struct *fs_struct) { 51 | assert(fs_struct != NULL && fs_count(fs_struct) == 0); 52 | if (fs_struct->pwd != NULL) { 53 | vop_ref_dec(fs_struct->pwd); 54 | } 55 | int i; 56 | struct file *file = fs_struct->filemap; 57 | for (i = 0; i < FS_STRUCT_NENTRY; i ++, file ++) { 58 | if (file->status == FD_OPENED) { 59 | filemap_close(file); 60 | } 61 | assert(file->status == FD_NONE); 62 | } 63 | kfree(fs_struct); 64 | } 65 | 66 | void 67 | fs_closeall(struct fs_struct *fs_struct) { 68 | assert(fs_struct != NULL && fs_count(fs_struct) > 0); 69 | int i; 70 | struct file *file = fs_struct->filemap; 71 | for (i = 2, file += 2; i < FS_STRUCT_NENTRY; i ++, file ++) { 72 | if (file->status == FD_OPENED) { 73 | filemap_close(file); 74 | } 75 | } 76 | } 77 | 78 | int 79 | dup_fs(struct fs_struct *to, struct fs_struct *from) { 80 | assert(to != NULL && from != NULL); 81 | assert(fs_count(to) == 0 && fs_count(from) > 0); 82 | if ((to->pwd = from->pwd) != NULL) { 83 | vop_ref_inc(to->pwd); 84 | } 85 | int i; 86 | struct file *to_file = to->filemap, *from_file = from->filemap; 87 | for (i = 0; i < FS_STRUCT_NENTRY; i ++, to_file ++, from_file ++) { 88 | if (from_file->status == FD_OPENED) { 89 | /* alloc_fd first */ 90 | to_file->status = FD_INIT; 91 | filemap_dup(to_file, from_file); 92 | } 93 | } 94 | return 0; 95 | } 96 | 97 | -------------------------------------------------------------------------------- /code/kern/fs/fs.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_FS_FS_H__ 2 | #define __KERN_FS_FS_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define SECTSIZE 512 10 | #define PAGE_NSECT (PGSIZE / SECTSIZE) 11 | 12 | #define SWAP_DEV_NO 1 13 | #define DISK0_DEV_NO 2 14 | 15 | void fs_init(void); 16 | void fs_cleanup(void); 17 | 18 | struct inode; 19 | struct file; 20 | 21 | struct fs_struct { 22 | struct inode *pwd; 23 | struct file *filemap; 24 | atomic_t fs_count; 25 | semaphore_t fs_sem; 26 | }; 27 | 28 | #define FS_STRUCT_BUFSIZE (PGSIZE - sizeof(struct fs_struct)) 29 | #define FS_STRUCT_NENTRY (FS_STRUCT_BUFSIZE / sizeof(struct file)) 30 | 31 | void lock_fs(struct fs_struct *fs_struct); 32 | void unlock_fs(struct fs_struct *fs_struct); 33 | 34 | struct fs_struct *fs_create(void); 35 | void fs_destroy(struct fs_struct *fs_struct); 36 | void fs_closeall(struct fs_struct *fs_struct); 37 | int dup_fs(struct fs_struct *to, struct fs_struct *from); 38 | 39 | static inline int 40 | fs_count(struct fs_struct *fs_struct) { 41 | return atomic_read(&(fs_struct->fs_count)); 42 | } 43 | 44 | static inline int 45 | fs_count_inc(struct fs_struct *fs_struct) { 46 | return atomic_add_return(&(fs_struct->fs_count), 1); 47 | } 48 | 49 | static inline int 50 | fs_count_dec(struct fs_struct *fs_struct) { 51 | return atomic_sub_return(&(fs_struct->fs_count), 1); 52 | } 53 | 54 | #endif /* !__KERN_FS_FS_H__ */ 55 | 56 | -------------------------------------------------------------------------------- /code/kern/fs/iobuf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | struct iobuf * 8 | iobuf_init(struct iobuf *iob, void *base, size_t len, off_t offset) { 9 | iob->io_base = base; 10 | iob->io_offset = offset; 11 | iob->io_len = iob->io_resid = len; 12 | return iob; 13 | } 14 | 15 | int 16 | iobuf_move(struct iobuf *iob, void *data, size_t len, bool m2b, size_t *copiedp) { 17 | size_t alen; 18 | if ((alen = iob->io_resid) > len) { 19 | alen = len; 20 | } 21 | if (alen > 0) { 22 | void *src = iob->io_base, *dst = data; 23 | if (m2b) { 24 | void *tmp = src; 25 | src = dst, dst = tmp; 26 | } 27 | memmove(dst, src, alen); 28 | iobuf_skip(iob, alen), len -= alen; 29 | } 30 | if (copiedp != NULL) { 31 | *copiedp = alen; 32 | } 33 | return (len == 0) ? 0 : -E_NO_MEM; 34 | } 35 | 36 | int 37 | iobuf_move_zeros(struct iobuf *iob, size_t len, size_t *copiedp) { 38 | size_t alen; 39 | if ((alen = iob->io_resid) > len) { 40 | alen = len; 41 | } 42 | if (alen > 0) { 43 | memset(iob->io_base, 0, alen); 44 | iobuf_skip(iob, alen), len -= alen; 45 | } 46 | if (copiedp != NULL) { 47 | *copiedp = alen; 48 | } 49 | return (len == 0) ? 0 : -E_NO_MEM; 50 | } 51 | 52 | void 53 | iobuf_skip(struct iobuf *iob, size_t n) { 54 | assert(iob->io_resid >= n); 55 | iob->io_base += n, iob->io_offset += n, iob->io_resid -= n; 56 | } 57 | 58 | -------------------------------------------------------------------------------- /code/kern/fs/iobuf.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_FS_IOBUF_H__ 2 | #define __KERN_FS_IOBUF_H__ 3 | 4 | #include 5 | 6 | /* 7 | * Like BSD uio, but simplified a lot. (In BSD, there can be one or more 8 | * iovec in a uio.) 9 | * 10 | */ 11 | 12 | struct iobuf { 13 | void *io_base; /* The base addr of object */ 14 | off_t io_offset; /* Desired offset into object */ 15 | size_t io_len; /* The lenght of Data */ 16 | size_t io_resid; /* Remaining amt of data to xfer */ 17 | }; 18 | 19 | /* 20 | * Copy data from a kernel buffer to a data region defined by a iobuf struct, 21 | * updating the iobuf struct's offset and resid fields. 22 | * 23 | * Before calling this, you should 24 | * (1) set up iobuf to point to the buffer you want to transfer 25 | * to; 26 | * (2) initialize iobuf's offset as desired; 27 | * (3) initialize iobuf's resid to the total amount of data that can be 28 | * transferred through this iobuf; 29 | * 30 | * After calling, 31 | * (1) the contents of iobuf may be altered and should not be interpreted; 32 | * (2) iobuf's offset will have been incremented by the amount transferred; 33 | * (3) iobuf's resid will have been decremented by the amount transferred; 34 | * 35 | * iobuf_move() may be called repeatedly on the same iobuf to transfer 36 | * additional data until the available buffer space the iobuf refers to 37 | * is exhausted. 38 | * 39 | * Note that the actual value of iobuf's offset is not interpreted. It is 40 | * provided to allow for easier file seek pointer management. 41 | * 42 | */ 43 | 44 | #define iobuf_used(iob) ((size_t)((iob)->io_len - (iob)->io_resid)) 45 | 46 | struct iobuf *iobuf_init(struct iobuf *iob, void *base, size_t len, off_t offset); 47 | int iobuf_move(struct iobuf *iob, void *data, size_t len, bool m2b, size_t *copiedp); 48 | /* 49 | * Like uiomove, but sends zeros. 50 | */ 51 | int iobuf_move_zeros(struct iobuf *iob, size_t len, size_t *copiedp); 52 | void iobuf_skip(struct iobuf *iob, size_t n); 53 | 54 | #endif /* !__KERN_FS_IOBUF_H__ */ 55 | 56 | -------------------------------------------------------------------------------- /code/kern/fs/pipe/pipe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | void 12 | lock_pipe(struct pipe_fs *pipe) { 13 | down(&(pipe->pipe_sem)); 14 | } 15 | 16 | void 17 | unlock_pipe(struct pipe_fs *pipe) { 18 | up(&(pipe->pipe_sem)); 19 | } 20 | 21 | static int 22 | pipe_sync(struct fs *fs) { 23 | return 0; 24 | } 25 | 26 | static struct inode * 27 | pipe_get_root(struct fs *fs) { 28 | struct pipe_fs *pipe = fsop_info(fs, pipe); 29 | vop_ref_inc(pipe->root); 30 | return pipe->root; 31 | } 32 | 33 | static int 34 | pipe_unmount(struct fs *fs) { 35 | return -E_INVAL; 36 | } 37 | 38 | static void 39 | pipe_cleanup(struct fs *fs) { 40 | /* do nothing */ 41 | } 42 | 43 | static void 44 | pipe_fs_init(struct fs *fs) { 45 | struct pipe_fs *pipe = fsop_info(fs, pipe); 46 | if ((pipe->root = pipe_create_root(fs)) == NULL) { 47 | panic("pipe: create root inode failed.\n"); 48 | } 49 | sem_init(&(pipe->pipe_sem), 1); 50 | list_init(&(pipe->pipe_list)); 51 | 52 | fs->fs_sync = pipe_sync; 53 | fs->fs_get_root = pipe_get_root; 54 | fs->fs_unmount = pipe_unmount; 55 | fs->fs_cleanup = pipe_cleanup; 56 | } 57 | 58 | void 59 | pipe_init(void) { 60 | struct fs *fs; 61 | if ((fs = alloc_fs(pipe)) == NULL) { 62 | panic("pipe: create pipe_fs failed.\n"); 63 | } 64 | pipe_fs_init(fs); 65 | 66 | int ret; 67 | if ((ret = vfs_add_fs("pipe", fs)) != 0) { 68 | panic("pipe: vfs_add_fs: %e.\n", ret); 69 | } 70 | } 71 | 72 | -------------------------------------------------------------------------------- /code/kern/fs/pipe/pipe.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_FS_PIPE_PIPE_H__ 2 | #define __KERN_FS_PIPE_PIPE_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct fs; 9 | struct inode; 10 | struct pipe_state; 11 | 12 | struct pipe_fs { 13 | struct inode *root; 14 | semaphore_t pipe_sem; 15 | list_entry_t pipe_list; 16 | }; 17 | 18 | void pipe_init(void); 19 | void lock_pipe(struct pipe_fs *pipe); 20 | void unlock_pipe(struct pipe_fs *pipe); 21 | 22 | struct pipe_root { 23 | /* empty */ 24 | }; 25 | 26 | struct pipe_inode { 27 | enum { 28 | PIN_RDONLY, PIN_WRONLY, 29 | } pin_type; 30 | char *name; 31 | int reclaim_count; 32 | struct pipe_state *state; 33 | list_entry_t pipe_link; 34 | }; 35 | 36 | #define le2pin(le, member) \ 37 | to_struct((le), struct pipe_inode, member) 38 | 39 | struct inode *pipe_create_root(struct fs *fs); 40 | struct inode *pipe_create_inode(struct fs *fs, const char *name, struct pipe_state *state, bool readonly); 41 | int pipe_open(struct inode **rnode_store, struct inode **wnode_store); 42 | 43 | #endif /* !__KERN_FS_PIPE_PIPE_H__ */ 44 | 45 | -------------------------------------------------------------------------------- /code/kern/fs/pipe/pipe_state.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_FS_PIPE_PIPE_STATE_H__ 2 | #define __KERN_FS_PIPE_PIPE_STATE_H__ 3 | 4 | struct pipe_state; 5 | 6 | struct pipe_state *pipe_state_create(void); 7 | void pipe_state_acquire(struct pipe_state *state); 8 | void pipe_state_release(struct pipe_state *state); 9 | void pipe_state_close(struct pipe_state *state); 10 | 11 | size_t pipe_state_size(struct pipe_state *state, bool write); 12 | size_t pipe_state_read(struct pipe_state *state, void *buf, size_t n); 13 | size_t pipe_state_write(struct pipe_state *state, void *buf, size_t n); 14 | 15 | #endif /* !__KERN_FS_PIPE_PIPE_STATE_H__ */ 16 | 17 | -------------------------------------------------------------------------------- /code/kern/fs/sfs/bitmap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define WORD_TYPE uint32_t 9 | #define WORD_BITS (sizeof(WORD_TYPE) * CHAR_BIT) 10 | 11 | struct bitmap { 12 | uint32_t nbits; 13 | uint32_t nwords; 14 | WORD_TYPE *map; 15 | }; 16 | 17 | struct bitmap * 18 | bitmap_create(uint32_t nbits) { 19 | static_assert(WORD_BITS != 0); 20 | assert(nbits != 0 && nbits + WORD_BITS > nbits); 21 | 22 | struct bitmap *bitmap; 23 | if ((bitmap = kmalloc(sizeof(struct bitmap))) == NULL) { 24 | return NULL; 25 | } 26 | 27 | uint32_t nwords = ROUNDUP_DIV(nbits, WORD_BITS); 28 | WORD_TYPE *map; 29 | if ((map = kmalloc(sizeof(WORD_TYPE) * nwords)) == NULL) { 30 | kfree(bitmap); 31 | return NULL; 32 | } 33 | 34 | bitmap->nbits = nbits, bitmap->nwords = nwords; 35 | bitmap->map = memset(map, 0xFF, sizeof(WORD_TYPE) * nwords); 36 | 37 | /* mark any leftover bits at the end in use(0) */ 38 | if (nbits != nwords * WORD_BITS) { 39 | uint32_t ix = nwords - 1, overbits = nbits - ix * WORD_BITS; 40 | 41 | assert(nbits / WORD_BITS == ix); 42 | assert(overbits > 0 && overbits < WORD_BITS); 43 | 44 | for (; overbits < WORD_BITS; overbits ++) { 45 | bitmap->map[ix] ^= (1 << overbits); 46 | } 47 | } 48 | return bitmap; 49 | } 50 | 51 | int 52 | bitmap_alloc(struct bitmap *bitmap, uint32_t *index_store) { 53 | WORD_TYPE *map = bitmap->map; 54 | uint32_t ix, offset, nwords = bitmap->nwords; 55 | for (ix = 0; ix < nwords; ix ++) { 56 | if (map[ix] != 0) { 57 | for (offset = 0; offset < WORD_BITS; offset ++) { 58 | WORD_TYPE mask = (1 << offset); 59 | if (map[ix] & mask) { 60 | map[ix] ^= mask; 61 | *index_store = ix * WORD_BITS + offset; 62 | return 0; 63 | } 64 | } 65 | assert(0); 66 | } 67 | } 68 | return -E_NO_MEM; 69 | } 70 | 71 | static void 72 | bitmap_translate(struct bitmap *bitmap, uint32_t index, WORD_TYPE **word, WORD_TYPE *mask) { 73 | assert(index < bitmap->nbits); 74 | uint32_t ix = index / WORD_BITS, offset = index % WORD_BITS; 75 | *word = bitmap->map + ix; 76 | *mask = (1 << offset); 77 | } 78 | 79 | bool 80 | bitmap_test(struct bitmap *bitmap, uint32_t index) { 81 | WORD_TYPE *word, mask; 82 | bitmap_translate(bitmap, index, &word, &mask); 83 | return (*word & mask); 84 | } 85 | 86 | void 87 | bitmap_free(struct bitmap *bitmap, uint32_t index) { 88 | WORD_TYPE *word, mask; 89 | bitmap_translate(bitmap, index, &word, &mask); 90 | assert(!(*word & mask)); 91 | *word |= mask; 92 | } 93 | 94 | void 95 | bitmap_destroy(struct bitmap *bitmap) { 96 | kfree(bitmap->map); 97 | kfree(bitmap); 98 | } 99 | 100 | void * 101 | bitmap_getdata(struct bitmap *bitmap, size_t *len_store) { 102 | if (len_store != NULL) { 103 | *len_store = sizeof(WORD_TYPE) * bitmap->nwords; 104 | } 105 | return bitmap->map; 106 | } 107 | 108 | -------------------------------------------------------------------------------- /code/kern/fs/sfs/bitmap.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_FS_SFS_BITMAP_H__ 2 | #define __KERN_FS_SFS_BITMAP_H__ 3 | 4 | #include 5 | 6 | struct bitmap; 7 | 8 | struct bitmap *bitmap_create(uint32_t nbits); 9 | int bitmap_alloc(struct bitmap *bitmap, uint32_t *index_store); 10 | bool bitmap_test(struct bitmap *bitmap, uint32_t index); 11 | void bitmap_free(struct bitmap *bitmap, uint32_t index); 12 | void bitmap_destroy(struct bitmap *bitmap); 13 | void *bitmap_getdata(struct bitmap *bitmap, size_t *len_store); 14 | 15 | #endif /* !__KERN_FS_SFS_BITMAP_H__ */ 16 | 17 | -------------------------------------------------------------------------------- /code/kern/fs/sfs/sfs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void 7 | sfs_init(void) { 8 | int ret; 9 | if ((ret = sfs_mount("disk0")) != 0) { 10 | panic("failed: sfs: sfs_mount: %e.\n", ret); 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /code/kern/fs/sfs/sfs_io.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | static int 10 | sfs_rwblock_nolock(struct sfs_fs *sfs, void *buf, uint32_t blkno, bool write, bool check) { 11 | assert((blkno != 0 || !check) && blkno < sfs->super.blocks); 12 | struct iobuf __iob, *iob = iobuf_init(&__iob, buf, SFS_BLKSIZE, blkno * SFS_BLKSIZE); 13 | return dop_io(sfs->dev, iob, write); 14 | } 15 | 16 | static int 17 | sfs_rwblock(struct sfs_fs *sfs, void *buf, uint32_t blkno, uint32_t nblks, bool write) { 18 | int ret = 0; 19 | lock_sfs_io(sfs); 20 | { 21 | while (nblks != 0) { 22 | if ((ret = sfs_rwblock_nolock(sfs, buf, blkno, write, 1)) != 0) { 23 | break; 24 | } 25 | blkno ++, nblks --; 26 | buf += SFS_BLKSIZE; 27 | } 28 | } 29 | unlock_sfs_io(sfs); 30 | return ret; 31 | } 32 | 33 | int 34 | sfs_rblock(struct sfs_fs *sfs, void *buf, uint32_t blkno, uint32_t nblks) { 35 | return sfs_rwblock(sfs, buf, blkno, nblks, 0); 36 | } 37 | 38 | int 39 | sfs_wblock(struct sfs_fs *sfs, void *buf, uint32_t blkno, uint32_t nblks) { 40 | return sfs_rwblock(sfs, buf, blkno, nblks, 1); 41 | } 42 | 43 | int 44 | sfs_rbuf(struct sfs_fs *sfs, void *buf, size_t len, uint32_t blkno, off_t offset) { 45 | assert(offset >= 0 && offset < SFS_BLKSIZE && offset + len <= SFS_BLKSIZE); 46 | int ret; 47 | lock_sfs_io(sfs); 48 | { 49 | if ((ret = sfs_rwblock_nolock(sfs, sfs->sfs_buffer, blkno, 0, 1)) == 0) { 50 | memcpy(buf, sfs->sfs_buffer + offset, len); 51 | } 52 | } 53 | unlock_sfs_io(sfs); 54 | return ret; 55 | } 56 | 57 | int 58 | sfs_wbuf(struct sfs_fs *sfs, void *buf, size_t len, uint32_t blkno, off_t offset) { 59 | assert(offset >= 0 && offset < SFS_BLKSIZE && offset + len <= SFS_BLKSIZE); 60 | int ret; 61 | lock_sfs_io(sfs); 62 | { 63 | if ((ret = sfs_rwblock_nolock(sfs, sfs->sfs_buffer, blkno, 0, 1)) == 0) { 64 | memcpy(sfs->sfs_buffer + offset, buf, len); 65 | ret = sfs_rwblock_nolock(sfs, sfs->sfs_buffer, blkno, 1, 1); 66 | } 67 | } 68 | unlock_sfs_io(sfs); 69 | return ret; 70 | } 71 | 72 | int 73 | sfs_sync_super(struct sfs_fs *sfs) { 74 | int ret; 75 | lock_sfs_io(sfs); 76 | { 77 | memset(sfs->sfs_buffer, 0, SFS_BLKSIZE); 78 | memcpy(sfs->sfs_buffer, &(sfs->super), sizeof(sfs->super)); 79 | ret = sfs_rwblock_nolock(sfs, sfs->sfs_buffer, SFS_BLKN_SUPER, 1, 0); 80 | } 81 | unlock_sfs_io(sfs); 82 | return ret; 83 | } 84 | 85 | int 86 | sfs_sync_freemap(struct sfs_fs *sfs) { 87 | uint32_t nblks = sfs_freemap_blocks(&(sfs->super)); 88 | return sfs_wblock(sfs, bitmap_getdata(sfs->freemap, NULL), SFS_BLKN_FREEMAP, nblks); 89 | } 90 | 91 | int 92 | sfs_clear_block(struct sfs_fs *sfs, uint32_t blkno, uint32_t nblks) { 93 | int ret; 94 | lock_sfs_io(sfs); 95 | { 96 | memset(sfs->sfs_buffer, 0, SFS_BLKSIZE); 97 | while (nblks != 0) { 98 | if ((ret = sfs_rwblock_nolock(sfs, sfs->sfs_buffer, blkno, 1, 1)) != 0) { 99 | break; 100 | } 101 | blkno ++, nblks --; 102 | } 103 | } 104 | unlock_sfs_io(sfs); 105 | return ret; 106 | } 107 | 108 | -------------------------------------------------------------------------------- /code/kern/fs/sfs/sfs_lock.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void 6 | lock_sfs_fs(struct sfs_fs *sfs) { 7 | down(&(sfs->fs_sem)); 8 | } 9 | 10 | void 11 | lock_sfs_io(struct sfs_fs *sfs) { 12 | down(&(sfs->io_sem)); 13 | } 14 | 15 | void 16 | lock_sfs_mutex(struct sfs_fs *sfs) { 17 | down(&(sfs->mutex_sem)); 18 | } 19 | 20 | void 21 | unlock_sfs_fs(struct sfs_fs *sfs) { 22 | up(&(sfs->fs_sem)); 23 | } 24 | 25 | void 26 | unlock_sfs_io(struct sfs_fs *sfs) { 27 | up(&(sfs->io_sem)); 28 | } 29 | 30 | void 31 | unlock_sfs_mutex(struct sfs_fs *sfs) { 32 | up(&(sfs->mutex_sem)); 33 | } 34 | 35 | -------------------------------------------------------------------------------- /code/kern/fs/swap/swapfs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | void 10 | swapfs_init(void) { 11 | static_assert((PGSIZE % SECTSIZE) == 0); 12 | if (!ide_device_valid(SWAP_DEV_NO)) { 13 | panic("swap fs isn't available.\n"); 14 | } 15 | max_swap_offset = ide_device_size(SWAP_DEV_NO) / (PGSIZE / SECTSIZE); 16 | } 17 | 18 | int 19 | swapfs_read(swap_entry_t entry, struct Page *page) { 20 | return ide_read_secs(SWAP_DEV_NO, swap_offset(entry) * PAGE_NSECT, page2kva(page), PAGE_NSECT); 21 | } 22 | 23 | int 24 | swapfs_write(swap_entry_t entry, struct Page *page) { 25 | return ide_write_secs(SWAP_DEV_NO, swap_offset(entry) * PAGE_NSECT, page2kva(page), PAGE_NSECT); 26 | } 27 | 28 | -------------------------------------------------------------------------------- /code/kern/fs/swap/swapfs.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_FS_SWAP_SWAPFS_H__ 2 | #define __KERN_FS_SWAP_SWAPFS_H__ 3 | 4 | #include 5 | #include 6 | 7 | void swapfs_init(void); 8 | int swapfs_read(swap_entry_t entry, struct Page *page); 9 | int swapfs_write(swap_entry_t entry, struct Page *page); 10 | 11 | #endif /* !__KERN_FS_SWAP_SWAPFS_H__ */ 12 | 13 | -------------------------------------------------------------------------------- /code/kern/fs/sysfile.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_FS_SYSFILE_H__ 2 | #define __KERN_FS_SYSFILE_H__ 3 | 4 | #include 5 | 6 | struct stat; 7 | struct dirent; 8 | 9 | int sysfile_open(const char *path, uint32_t open_flags); 10 | int sysfile_close(int fd); 11 | int sysfile_read(int fd, void *base, size_t len); 12 | int sysfile_write(int fd, void *base, size_t len); 13 | int sysfile_seek(int fd, off_t pos, int whence); 14 | int sysfile_fstat(int fd, struct stat *stat); 15 | int sysfile_fsync(int fd); 16 | int sysfile_chdir(const char *path); 17 | int sysfile_mkdir(const char *path); 18 | int sysfile_link(const char *path1, const char *path2); 19 | int sysfile_rename(const char *path1, const char *path2); 20 | int sysfile_unlink(const char *path); 21 | int sysfile_getcwd(char *buf, size_t len); 22 | int sysfile_getdirentry(int fd, struct dirent *direntp); 23 | int sysfile_dup(int fd1, int fd2); 24 | int sysfile_pipe(int *fd_store); 25 | int sysfile_mkfifo(const char *name, uint32_t open_flags); 26 | 27 | #endif /* !__KERN_FS_SYSFILE_H__ */ 28 | 29 | -------------------------------------------------------------------------------- /code/kern/fs/vfs/vfs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | static semaphore_t bootfs_sem; 11 | static struct inode *bootfs_node = NULL; 12 | 13 | extern void vfs_devlist_init(void); 14 | 15 | struct fs * 16 | __alloc_fs(int type) { 17 | struct fs *fs; 18 | if ((fs = kmalloc(sizeof(struct fs))) != NULL) { 19 | fs->fs_type = type; 20 | } 21 | return fs; 22 | } 23 | 24 | void 25 | vfs_init(void) { 26 | sem_init(&bootfs_sem, 1); 27 | vfs_devlist_init(); 28 | } 29 | 30 | static void 31 | lock_bootfs(void) { 32 | down(&bootfs_sem); 33 | } 34 | 35 | static void 36 | unlock_bootfs(void) { 37 | up(&bootfs_sem); 38 | } 39 | 40 | /* 41 | * Helper function for actually changing bootfs_inode. 42 | */ 43 | static void 44 | change_bootfs(struct inode *node) { 45 | struct inode *old; 46 | lock_bootfs(); 47 | { 48 | old = bootfs_node, bootfs_node = node; 49 | } 50 | unlock_bootfs(); 51 | if (old != NULL) { 52 | vop_ref_dec(old); 53 | } 54 | } 55 | 56 | /* 57 | * Set bootfs_node. 58 | * 59 | * Bootfs_node is the inode used for beginning path translation of 60 | * pathnames starting with /. 61 | * 62 | * It is also incidentally the system's first current directory. 63 | */ 64 | int 65 | vfs_set_bootfs(char *fsname) { 66 | struct inode *node = NULL; 67 | if (fsname != NULL) { 68 | char *s; 69 | if ((s = strchr(fsname, ':')) == NULL || s[1] != '\0') { 70 | return -E_INVAL; 71 | } 72 | int ret; 73 | if ((ret = vfs_chdir(fsname)) != 0) { 74 | return ret; 75 | } 76 | if ((ret = vfs_get_curdir(&node)) != 0) { 77 | return ret; 78 | } 79 | } 80 | change_bootfs(node); 81 | return 0; 82 | } 83 | 84 | /* 85 | * Get bootfs_inode. 86 | */ 87 | int 88 | vfs_get_bootfs(struct inode **node_store) { 89 | struct inode *node = NULL; 90 | if (bootfs_node != NULL) { 91 | lock_bootfs(); 92 | { 93 | if ((node = bootfs_node) != NULL) { 94 | vop_ref_inc(bootfs_node); 95 | } 96 | } 97 | unlock_bootfs(); 98 | } 99 | if (node == NULL) { 100 | return -E_NOENT; 101 | } 102 | *node_store = node; 103 | return 0; 104 | } 105 | 106 | -------------------------------------------------------------------------------- /code/kern/fs/vfs/vfslookup.c: -------------------------------------------------------------------------------- 1 | /* 2 | * VFS operations relating to pathname translation 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | /* 13 | * Common code to pull the device name, if any, off the front of a 14 | * path and choose the inode to begin the name lookup relative to. 15 | */ 16 | static int 17 | get_device(char *path, char **subpath, struct inode **node_store) { 18 | int i, slash = -1, colon = -1; 19 | /* 20 | * Locate the first colon or slash. 21 | */ 22 | for (i = 0; path[i] != '\0'; i ++) { 23 | if (path[i] == ':') { colon = i; break; } 24 | if (path[i] == '/') { slash = i; break; } 25 | } 26 | if (colon < 0 && slash != 0) { 27 | /* * 28 | * No colon before a slash, so no device name specified, and the slash isn't leading 29 | * or is also absent, so this is a relative path or just a bare filename. Start from 30 | * the current directory, and use the whole thing as the subpath. 31 | * */ 32 | *subpath = path; 33 | return vfs_get_curdir(node_store); 34 | } 35 | if (colon > 0) { 36 | /* device:path - get root of device's filesystem */ 37 | path[colon] = '\0'; 38 | 39 | /* device:/path - skip slash, treat as device:path */ 40 | while (path[++ colon] == '/'); 41 | *subpath = path + colon; 42 | return vfs_get_root(path, node_store); 43 | } 44 | 45 | /* * 46 | * we have either /path or :path 47 | * /path is a path relative to the root of the "boot filesystem" 48 | * :path is a path relative to the root of the current filesystem 49 | * */ 50 | int ret; 51 | if (*path == '/') { 52 | if ((ret = vfs_get_bootfs(node_store)) != 0) { 53 | return ret; 54 | } 55 | } 56 | else { 57 | assert(*path == ':'); 58 | struct inode *node; 59 | if ((ret = vfs_get_curdir(&node)) != 0) { 60 | return ret; 61 | } 62 | /* The current directory may not be a device, so it must have a fs. */ 63 | assert(node->in_fs != NULL); 64 | *node_store = fsop_get_root(node->in_fs); 65 | vop_ref_dec(node); 66 | } 67 | 68 | /* ///... or :/... */ 69 | while (*(++ path) == '/'); 70 | *subpath = path; 71 | return 0; 72 | } 73 | 74 | /* 75 | * Name-to-inode translation. 76 | * (In BSD, both of these are subsumed by namei().) 77 | */ 78 | 79 | int 80 | vfs_lookup(char *path, struct inode **node_store) { 81 | int ret; 82 | struct inode *node; 83 | if ((ret = get_device(path, &path, &node)) != 0) { 84 | return ret; 85 | } 86 | if (*path != '\0') { 87 | ret = vop_lookup(node, path, node_store); 88 | vop_ref_dec(node); 89 | return ret; 90 | } 91 | *node_store = node; 92 | return 0; 93 | } 94 | 95 | int 96 | vfs_lookup_parent(char *path, struct inode **node_store, char **endp) { 97 | int ret; 98 | struct inode *node; 99 | if ((ret = get_device(path, &path, &node)) != 0) { 100 | return ret; 101 | } 102 | ret = (*path != '\0') ? vop_lookup_parent(node, path, node_store, endp) : -E_INVAL; 103 | vop_ref_dec(node); 104 | return ret; 105 | } 106 | 107 | -------------------------------------------------------------------------------- /code/kern/fs/vfs/vfspath.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | static struct inode * 12 | get_cwd_nolock(void) { 13 | return current->fs_struct->pwd; 14 | } 15 | 16 | static void 17 | set_cwd_nolock(struct inode *pwd) { 18 | current->fs_struct->pwd = pwd; 19 | } 20 | 21 | static void 22 | lock_cfs(void) { 23 | lock_fs(current->fs_struct); 24 | } 25 | 26 | static void 27 | unlock_cfs(void) { 28 | unlock_fs(current->fs_struct); 29 | } 30 | 31 | /* 32 | * Get current directory as a inode. 33 | * 34 | * We do not synchronize current->fs_struct->pwd, because it belongs exclusively 35 | * to its own process(or threads) with the holding lock. 36 | */ 37 | int 38 | vfs_get_curdir(struct inode **dir_store) { 39 | struct inode *node; 40 | if ((node = get_cwd_nolock()) != NULL) { 41 | vop_ref_inc(node); 42 | *dir_store = node; 43 | return 0; 44 | } 45 | return -E_NOENT; 46 | } 47 | 48 | /* 49 | * Set current directory as a vnode. 50 | * The passed inode must in fact be a directory. 51 | */ 52 | int 53 | vfs_set_curdir(struct inode *dir) { 54 | int ret = 0; 55 | lock_cfs(); 56 | struct inode *old_dir; 57 | if ((old_dir = get_cwd_nolock()) != dir) { 58 | if (dir != NULL) { 59 | uint32_t type; 60 | if ((ret = vop_gettype(dir, &type)) != 0) { 61 | goto out; 62 | } 63 | if (!S_ISDIR(type)) { 64 | ret = -E_NOTDIR; 65 | goto out; 66 | } 67 | vop_ref_inc(dir); 68 | } 69 | set_cwd_nolock(dir); 70 | if (old_dir != NULL) { 71 | vop_ref_dec(old_dir); 72 | } 73 | } 74 | out: 75 | unlock_cfs(); 76 | return ret; 77 | } 78 | 79 | /* 80 | * Set current directory, as a pathname. Use vfs_lookup to translate 81 | * it to a inode. 82 | */ 83 | int 84 | vfs_chdir(char *path) { 85 | int ret; 86 | struct inode *node; 87 | if ((ret = vfs_lookup(path, &node)) == 0) { 88 | ret = vfs_set_curdir(node); 89 | vop_ref_dec(node); 90 | } 91 | return ret; 92 | } 93 | 94 | /* 95 | * Get current directory, as a pathname. 96 | * Use vop_namefile to get the pathname. 97 | */ 98 | int 99 | vfs_getcwd(struct iobuf *iob) { 100 | int ret; 101 | struct inode *node; 102 | if ((ret = vfs_get_curdir(&node)) != 0) { 103 | return ret; 104 | } 105 | /* The current dir must be a directory, and thus it is not a device. */ 106 | assert(node->in_fs != NULL); 107 | 108 | const char *devname = vfs_get_devname(node->in_fs); 109 | if ((ret = iobuf_move(iob, (char *)devname, strlen(devname), 1, NULL)) != 0) { 110 | goto out; 111 | } 112 | char colon = ':'; 113 | if ((ret = iobuf_move(iob, &colon, sizeof(colon), 1, NULL)) != 0) { 114 | goto out; 115 | } 116 | ret = vop_namefile(node, iob); 117 | 118 | out: 119 | vop_ref_dec(node); 120 | return ret; 121 | } 122 | 123 | -------------------------------------------------------------------------------- /code/kern/init/entry.S: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define REALLOC(x) (x - KERNBASE) 5 | 6 | .text 7 | .globl kern_entry 8 | kern_entry: 9 | # reload temperate gdt (second time) to remap all physical memory 10 | # virtual_addr 0~4G=linear_addr&physical_addr -KERNBASE~4G-KERNBASE 11 | lgdt REALLOC(__gdtdesc) 12 | movl $KERNEL_DS, %eax 13 | movw %ax, %ds 14 | movw %ax, %es 15 | movw %ax, %ss 16 | 17 | ljmp $KERNEL_CS, $relocated 18 | 19 | relocated: 20 | 21 | # set ebp, esp 22 | movl $0x0, %ebp 23 | # the kernel stack region is from bootstack -- bootstacktop, 24 | # the kernel stack size is KSTACKSIZE (8KB)defined in memlayout.h 25 | movl $bootstacktop, %esp 26 | # now kernel stack is ready , call the first C function 27 | call kern_init 28 | 29 | # should never get here 30 | spin: 31 | jmp spin 32 | 33 | .data 34 | .align PGSIZE 35 | .globl bootstack 36 | bootstack: 37 | .space KSTACKSIZE 38 | .globl bootstacktop 39 | bootstacktop: 40 | 41 | .align 4 42 | __gdt: 43 | SEG_NULL 44 | SEG_ASM(STA_X | STA_R, - KERNBASE, 0xFFFFFFFF) # code segment 45 | SEG_ASM(STA_W, - KERNBASE, 0xFFFFFFFF) # data segment 46 | __gdtdesc: 47 | .word 0x17 # sizeof(__gdt) - 1 48 | .long REALLOC(__gdt) 49 | 50 | -------------------------------------------------------------------------------- /code/kern/init/init.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | int kern_init(void) __attribute__((noreturn)); 19 | 20 | int 21 | kern_init(void) { 22 | extern char edata[], end[]; 23 | memset(edata, 0, end - edata); 24 | 25 | cons_init(); // init the console 26 | 27 | const char *message = "(THU.CST) os is loading ..."; 28 | cprintf("%s\n\n", message); 29 | 30 | print_kerninfo(); 31 | 32 | debug_init(); // init debug registers 33 | pmm_init(); // init physical memory management 34 | 35 | pic_init(); // init interrupt controller 36 | idt_init(); // init interrupt descriptor table 37 | 38 | vmm_init(); // init virtual memory management 39 | sched_init(); // init scheduler 40 | proc_init(); // init process table 41 | sync_init(); // init sync struct 42 | 43 | ide_init(); // init ide devices 44 | swap_init(); // init swap 45 | fs_init(); // init fs 46 | 47 | clock_init(); // init clock interrupt 48 | intr_enable(); // enable irq interrupt 49 | 50 | cpu_idle(); // run idle process 51 | } 52 | 53 | -------------------------------------------------------------------------------- /code/kern/libs/rb_tree.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_LIBS_RB_TREE_H__ 2 | #define __KERN_LIBS_RB_TREE_H__ 3 | 4 | #include 5 | 6 | typedef struct rb_node { 7 | bool red; // if red = 0, it's a black node 8 | struct rb_node *parent; 9 | struct rb_node *left, *right; 10 | } rb_node; 11 | 12 | typedef struct rb_tree { 13 | // compare function should return -1 if *node1 < *node2, 1 if *node1 > *node2, and 0 otherwise 14 | int (*compare)(rb_node *node1, rb_node *node2); 15 | struct rb_node *nil, *root; 16 | } rb_tree; 17 | 18 | rb_tree *rb_tree_create(int (*compare)(rb_node *node1, rb_node *node2)); 19 | void rb_tree_destroy(rb_tree *tree); 20 | void rb_insert(rb_tree *tree, rb_node *node); 21 | void rb_delete(rb_tree *tree, rb_node *node); 22 | rb_node *rb_search(rb_tree *tree, int (*compare)(rb_node *node, void *key), void *key); 23 | rb_node *rb_node_prev(rb_tree *tree, rb_node *node); 24 | rb_node *rb_node_next(rb_tree *tree, rb_node *node); 25 | rb_node *rb_node_root(rb_tree *tree); 26 | rb_node *rb_node_left(rb_tree *tree, rb_node *node); 27 | rb_node *rb_node_right(rb_tree *tree, rb_node *node); 28 | 29 | void check_rb_tree(void); 30 | 31 | #endif /* !__KERN_LIBS_RBTREE_H__ */ 32 | 33 | -------------------------------------------------------------------------------- /code/kern/libs/readline.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define BUFSIZE 1024 4 | static char buf[BUFSIZE]; 5 | 6 | /* * 7 | * readline - get a line from stdin 8 | * @prompt: the string to be written to stdout 9 | * 10 | * The readline() function will write the input string @prompt to 11 | * stdout first. If the @prompt is NULL or the empty string, 12 | * no prompt is issued. 13 | * 14 | * This function will keep on reading characters and saving them to buffer 15 | * 'buf' until '\n' or '\r' is encountered. 16 | * 17 | * Note that, if the length of string that will be read is longer than 18 | * buffer size, the end of string will be discarded. 19 | * 20 | * The readline() function returns the text of the line read. If some errors 21 | * are happened, NULL is returned. The return value is a global variable, 22 | * thus it should be copied before it is used. 23 | * */ 24 | char * 25 | readline(const char *prompt) { 26 | if (prompt != NULL) { 27 | cprintf("%s", prompt); 28 | } 29 | int i = 0, c; 30 | while (1) { 31 | c = getchar(); 32 | if (c < 0) { 33 | return NULL; 34 | } 35 | else if (c >= ' ' && i < BUFSIZE - 1) { 36 | cputchar(c); 37 | buf[i ++] = c; 38 | } 39 | else if (c == '\b' && i > 0) { 40 | cputchar(c); 41 | i --; 42 | } 43 | else if (c == '\n' || c == '\r') { 44 | cputchar(c); 45 | buf[i] = '\0'; 46 | return buf; 47 | } 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /code/kern/libs/stdio.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | /* HIGH level console I/O */ 7 | 8 | /* * 9 | * cputch - writes a single character @c to stdout, and it will 10 | * increace the value of counter pointed by @cnt. 11 | * */ 12 | static void 13 | cputch(int c, int *cnt) { 14 | cons_putc(c); 15 | (*cnt) ++; 16 | } 17 | 18 | /* * 19 | * vcprintf - format a string and writes it to stdout 20 | * 21 | * The return value is the number of characters which would be 22 | * written to stdout. 23 | * 24 | * Call this function if you are already dealing with a va_list. 25 | * Or you probably want cprintf() instead. 26 | * */ 27 | int 28 | vcprintf(const char *fmt, va_list ap) { 29 | int cnt = 0; 30 | vprintfmt((void*)cputch, NO_FD, &cnt, fmt, ap); 31 | return cnt; 32 | } 33 | 34 | /* * 35 | * cprintf - formats a string and writes it to stdout 36 | * 37 | * The return value is the number of characters which would be 38 | * written to stdout. 39 | * */ 40 | int 41 | cprintf(const char *fmt, ...) { 42 | va_list ap; 43 | int cnt; 44 | va_start(ap, fmt); 45 | cnt = vcprintf(fmt, ap); 46 | va_end(ap); 47 | return cnt; 48 | } 49 | 50 | /* cputchar - writes a single character to stdout */ 51 | void 52 | cputchar(int c) { 53 | cons_putc(c); 54 | } 55 | 56 | /* * 57 | * cputs- writes the string pointed by @str to stdout and 58 | * appends a newline character. 59 | * */ 60 | int 61 | cputs(const char *str) { 62 | int cnt = 0; 63 | char c; 64 | while ((c = *str ++) != '\0') { 65 | cputch(c, &cnt); 66 | } 67 | cputch('\n', &cnt); 68 | return cnt; 69 | } 70 | 71 | /* getchar - reads a single non-zero character from stdin */ 72 | int 73 | getchar(void) { 74 | int c; 75 | while ((c = cons_getc()) == 0) 76 | /* do nothing */; 77 | return c; 78 | } 79 | 80 | -------------------------------------------------------------------------------- /code/kern/libs/string.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | char * 5 | strdup(const char *src) { 6 | char *dst; 7 | size_t len = strlen(src); 8 | if ((dst = kmalloc(len + 1)) != NULL) { 9 | memcpy(dst, src, len); 10 | dst[len] = '\0'; 11 | } 12 | return dst; 13 | } 14 | 15 | char * 16 | stradd(const char *src1, const char *src2) { 17 | char *ret, *dst; 18 | size_t len1 = strlen(src1), len2 = strlen(src2); 19 | if ((ret = dst = kmalloc(len1 + len2 + 1)) != NULL) { 20 | memcpy(dst, src1, len1), dst += len1; 21 | memcpy(dst, src2, len2), dst += len2; 22 | *dst = '\0'; 23 | } 24 | return ret; 25 | } 26 | 27 | -------------------------------------------------------------------------------- /code/kern/mm/buddy_pmm.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_MM_BUDDY_PMM_H__ 2 | #define __KERN_MM_BUDDY_PMM_H__ 3 | 4 | #include 5 | 6 | extern const struct pmm_manager buddy_pmm_manager; 7 | 8 | #endif /* !__KERN_MM_BUDDY_PMM_H__ */ 9 | 10 | -------------------------------------------------------------------------------- /code/kern/mm/shmem.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_MM_SHMEM_H__ 2 | #define __KERN_MM_SHMEM_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | typedef struct shmn_s { 12 | uintptr_t start; 13 | uintptr_t end; 14 | pte_t *entry; 15 | list_entry_t list_link; 16 | } shmn_t; 17 | 18 | #define SHMN_NENTRY (PGSIZE / sizeof(pte_t)) 19 | 20 | #define le2shmn(le, member) \ 21 | to_struct((le), shmn_t, member) 22 | 23 | struct shmem_struct { 24 | list_entry_t shmn_list; 25 | shmn_t *shmn_cache; 26 | size_t len; 27 | atomic_t shmem_ref; 28 | semaphore_t shmem_sem; 29 | }; 30 | 31 | struct shmem_struct *shmem_create(size_t len); 32 | void shmem_destroy(struct shmem_struct *shmem); 33 | pte_t *shmem_get_entry(struct shmem_struct *shmem, uintptr_t addr, bool create); 34 | int shmem_insert_entry(struct shmem_struct *shmem, uintptr_t addr, pte_t entry); 35 | int shmem_remove_entry(struct shmem_struct *shmem, uintptr_t addr); 36 | 37 | static inline int 38 | shmem_ref(struct shmem_struct *shmem) { 39 | return atomic_read(&(shmem->shmem_ref)); 40 | } 41 | 42 | static inline void 43 | set_shmem_ref(struct shmem_struct *shmem, int val) { 44 | atomic_set(&(shmem->shmem_ref), val); 45 | } 46 | 47 | static inline int 48 | shmem_ref_inc(struct shmem_struct *shmem) { 49 | return atomic_add_return(&(shmem->shmem_ref), 1); 50 | } 51 | 52 | static inline int 53 | shmem_ref_dec(struct shmem_struct *shmem) { 54 | return atomic_sub_return(&(shmem->shmem_ref), 1); 55 | } 56 | 57 | static inline void 58 | lock_shmem(struct shmem_struct *shmem) { 59 | down(&(shmem->shmem_sem)); 60 | } 61 | 62 | static inline void 63 | unlock_shmem(struct shmem_struct *shmem) { 64 | up(&(shmem->shmem_sem)); 65 | } 66 | 67 | #endif /* !__KERN_MM_SHMEM_H__ */ 68 | 69 | -------------------------------------------------------------------------------- /code/kern/mm/slab.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_MM_SLAB_H__ 2 | #define __KERN_MM_SLAB_H__ 3 | 4 | #include 5 | 6 | #define KMALLOC_MAX_ORDER 10 7 | 8 | void slab_init(void); 9 | 10 | void *kmalloc(size_t n); 11 | void kfree(void *objp); 12 | 13 | size_t slab_allocated(void); 14 | 15 | #endif /* !__KERN_MM_SLAB_H__ */ 16 | 17 | -------------------------------------------------------------------------------- /code/kern/mm/swap.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_MM_SWAP_H__ 2 | #define __KERN_MM_SWAP_H__ 3 | 4 | #include 5 | #include 6 | 7 | /* * 8 | * swap_entry_t 9 | * -------------------------------------------- 10 | * | offset | reserved | 0 | 11 | * -------------------------------------------- 12 | * 24 bits 7 bits 1 bit 13 | * */ 14 | 15 | #define MAX_SWAP_OFFSET_LIMIT (1 << 24) 16 | 17 | extern size_t max_swap_offset; 18 | 19 | /* * 20 | * swap_offset - takes a swap_entry (saved in pte), and returns 21 | * the corresponding offset in swap mem_map. 22 | * */ 23 | #define swap_offset(entry) ({ \ 24 | size_t __offset = (entry >> 8); \ 25 | if (!(__offset > 0 && __offset < max_swap_offset)) { \ 26 | panic("invalid swap_entry_t = %08x.\n", entry); \ 27 | } \ 28 | __offset; \ 29 | }) 30 | 31 | void swap_init(void); 32 | bool try_free_pages(size_t n); 33 | 34 | void swap_remove_entry(swap_entry_t entry); 35 | int swap_page_count(struct Page *page); 36 | void swap_duplicate(swap_entry_t entry); 37 | int swap_in_page(swap_entry_t entry, struct Page **pagep); 38 | int swap_copy_entry(swap_entry_t entry, swap_entry_t *store); 39 | 40 | int kswapd_main(void *arg) __attribute__((noreturn)); 41 | 42 | #endif /* !__KERN_MM_SWAP_H__ */ 43 | 44 | -------------------------------------------------------------------------------- /code/kern/process/entry.S: -------------------------------------------------------------------------------- 1 | .text 2 | .globl kernel_thread_entry 3 | kernel_thread_entry: # void kernel_thread(void) 4 | 5 | pushl %edx # push arg 6 | call *%ebx # call fn 7 | 8 | pushl %eax # save the return value of fn(arg) 9 | call do_exit # call do_exit to terminate current thread 10 | 11 | -------------------------------------------------------------------------------- /code/kern/process/switch.S: -------------------------------------------------------------------------------- 1 | .text 2 | .globl switch_to 3 | switch_to: # switch_to(from, to) 4 | 5 | # save from's registers 6 | movl 4(%esp), %eax # eax points to from 7 | popl 0(%eax) # save eip !popl 8 | movl %esp, 4(%eax) 9 | movl %ebx, 8(%eax) 10 | movl %ecx, 12(%eax) 11 | movl %edx, 16(%eax) 12 | movl %esi, 20(%eax) 13 | movl %edi, 24(%eax) 14 | movl %ebp, 28(%eax) 15 | 16 | # restore to's registers 17 | movl 4(%esp), %eax # not 8(%esp): popped return address already 18 | # eax now points to to 19 | movl 28(%eax), %ebp 20 | movl 24(%eax), %edi 21 | movl 20(%eax), %esi 22 | movl 16(%eax), %edx 23 | movl 12(%eax), %ecx 24 | movl 8(%eax), %ebx 25 | movl 4(%eax), %esp 26 | 27 | pushl 0(%eax) # push eip 28 | 29 | ret 30 | 31 | -------------------------------------------------------------------------------- /code/kern/schedule/sched.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_SCHEDULE_SCHED_H__ 2 | #define __KERN_SCHEDULE_SCHED_H__ 3 | 4 | #include 5 | #include 6 | 7 | struct proc_struct; 8 | 9 | typedef struct { 10 | unsigned int expires; 11 | struct proc_struct *proc; 12 | list_entry_t timer_link; 13 | } timer_t; 14 | 15 | #define le2timer(le, member) \ 16 | to_struct((le), timer_t, member) 17 | 18 | static inline timer_t * 19 | timer_init(timer_t *timer, struct proc_struct *proc, int expires) { 20 | timer->expires = expires; 21 | timer->proc = proc; 22 | list_init(&(timer->timer_link)); 23 | return timer; 24 | } 25 | 26 | struct run_queue; 27 | 28 | // The introduction of scheduling classes is borrrowed from Linux, and makes the 29 | // core scheduler quite extensible. These classes (the scheduler modules) encapsulate 30 | // the scheduling policies. 31 | struct sched_class { 32 | // the name of sched_class 33 | const char *name; 34 | // Init the run queue 35 | void (*init)(struct run_queue *rq); 36 | // put the proc into runqueue, and this function must be called with rq_lock 37 | void (*enqueue)(struct run_queue *rq, struct proc_struct *proc); 38 | // get the proc out runqueue, and this function must be called with rq_lock 39 | void (*dequeue)(struct run_queue *rq, struct proc_struct *proc); 40 | // choose the next runnable task 41 | struct proc_struct *(*pick_next)(struct run_queue *rq); 42 | // dealer of the time-tick 43 | void (*proc_tick)(struct run_queue *rq, struct proc_struct *proc); 44 | /* for SMP support in the future 45 | * load_balance 46 | * void (*load_balance)(struct rq* rq); 47 | * get some proc from this rq, used in load_balance, 48 | * return value is the num of gotten proc 49 | * int (*get_proc)(struct rq* rq, struct proc* procs_moved[]); 50 | */ 51 | }; 52 | 53 | struct run_queue { 54 | list_entry_t run_list; 55 | unsigned int proc_num; 56 | int max_time_slice; 57 | list_entry_t rq_link; 58 | }; 59 | 60 | #define le2rq(le, member) \ 61 | to_struct((le), struct run_queue, member) 62 | 63 | void sched_init(void); 64 | void wakeup_proc(struct proc_struct *proc); 65 | void schedule(void); 66 | void add_timer(timer_t *timer); 67 | void del_timer(timer_t *timer); 68 | void run_timer_list(void); 69 | 70 | #endif /* !__KERN_SCHEDULE_SCHED_H__ */ 71 | 72 | -------------------------------------------------------------------------------- /code/kern/schedule/sched_MLFQ.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | static struct sched_class *sched_class; 10 | 11 | static void 12 | MLFQ_init(struct run_queue *rq) { 13 | sched_class = &RR_sched_class; 14 | list_entry_t *list = &(rq->rq_link), *le = list; 15 | do { 16 | sched_class->init(le2rq(le, rq_link)); 17 | le = list_next(le); 18 | } while (le != list); 19 | } 20 | 21 | static void 22 | MLFQ_enqueue(struct run_queue *rq, struct proc_struct *proc) { 23 | assert(list_empty(&(proc->run_link))); 24 | struct run_queue *nrq = rq; 25 | if (proc->rq != NULL && proc->time_slice == 0) { 26 | nrq = le2rq(list_next(&(proc->rq->rq_link)), rq_link); 27 | if (nrq == rq) { 28 | nrq = proc->rq; 29 | } 30 | } 31 | sched_class->enqueue(nrq, proc); 32 | } 33 | 34 | static void 35 | MLFQ_dequeue(struct run_queue *rq, struct proc_struct *proc) { 36 | assert(!list_empty(&(proc->run_link))); 37 | sched_class->dequeue(proc->rq, proc); 38 | } 39 | 40 | static struct proc_struct * 41 | MLFQ_pick_next(struct run_queue *rq) { 42 | struct proc_struct *next; 43 | list_entry_t *list = &(rq->rq_link), *le = list; 44 | do { 45 | if ((next = sched_class->pick_next(le2rq(le, rq_link))) != NULL) { 46 | break; 47 | } 48 | le = list_next(le); 49 | } while (le != list); 50 | return next; 51 | } 52 | 53 | static void 54 | MLFQ_proc_tick(struct run_queue *rq, struct proc_struct *proc) { 55 | sched_class->proc_tick(proc->rq, proc); 56 | } 57 | 58 | struct sched_class MLFQ_sched_class = { 59 | .name = "MLFQ_scheduler", 60 | .init = MLFQ_init, 61 | .enqueue = MLFQ_enqueue, 62 | .dequeue = MLFQ_dequeue, 63 | .pick_next = MLFQ_pick_next, 64 | .proc_tick = MLFQ_proc_tick, 65 | }; 66 | 67 | -------------------------------------------------------------------------------- /code/kern/schedule/sched_MLFQ.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_SCHEDULE_SCHED_MLFQ_H__ 2 | #define __KERN_SCHEDULE_SCHED_MLFQ_H__ 3 | 4 | #include 5 | 6 | extern struct sched_class MLFQ_sched_class; 7 | 8 | #endif /* !__KERN_SCHEDULE_SCHED_MLFQ_H__ */ 9 | 10 | -------------------------------------------------------------------------------- /code/kern/schedule/sched_RR.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | static void 8 | RR_init(struct run_queue *rq) { 9 | list_init(&(rq->run_list)); 10 | rq->proc_num = 0; 11 | } 12 | 13 | static void 14 | RR_enqueue(struct run_queue *rq, struct proc_struct *proc) { 15 | assert(list_empty(&(proc->run_link))); 16 | list_add_before(&(rq->run_list), &(proc->run_link)); 17 | if (proc->time_slice == 0 || proc->time_slice > rq->max_time_slice) { 18 | proc->time_slice = rq->max_time_slice; 19 | } 20 | proc->rq = rq; 21 | rq->proc_num ++; 22 | } 23 | 24 | static void 25 | RR_dequeue(struct run_queue *rq, struct proc_struct *proc) { 26 | assert(!list_empty(&(proc->run_link)) && proc->rq == rq); 27 | list_del_init(&(proc->run_link)); 28 | rq->proc_num --; 29 | } 30 | 31 | static struct proc_struct * 32 | RR_pick_next(struct run_queue *rq) { 33 | list_entry_t *le = list_next(&(rq->run_list)); 34 | if (le != &(rq->run_list)) { 35 | return le2proc(le, run_link); 36 | } 37 | return NULL; 38 | } 39 | 40 | static void 41 | RR_proc_tick(struct run_queue *rq, struct proc_struct *proc) { 42 | if (proc->time_slice > 0) { 43 | proc->time_slice --; 44 | } 45 | if (proc->time_slice == 0) { 46 | proc->need_resched = 1; 47 | } 48 | } 49 | 50 | struct sched_class RR_sched_class = { 51 | .name = "RR_scheduler", 52 | .init = RR_init, 53 | .enqueue = RR_enqueue, 54 | .dequeue = RR_dequeue, 55 | .pick_next = RR_pick_next, 56 | .proc_tick = RR_proc_tick, 57 | }; 58 | 59 | -------------------------------------------------------------------------------- /code/kern/schedule/sched_RR.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_SCHEDULE_SCHED_RR_H__ 2 | #define __KERN_SCHEDULE_SCHED_RR_H__ 3 | 4 | #include 5 | 6 | extern struct sched_class RR_sched_class; 7 | 8 | #endif /* !__KERN_SCHEDULE_SCHED_RR_H__ */ 9 | 10 | -------------------------------------------------------------------------------- /code/kern/sync/event.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_SYNC_EVENT_H__ 2 | #define __KERN_SYNC_EVENT_H__ 3 | 4 | #include 5 | #include 6 | 7 | typedef struct { 8 | int event; 9 | wait_queue_t wait_queue; 10 | } event_t; 11 | 12 | void event_box_init(event_t *event_box); 13 | 14 | int ipc_event_send(int pid, int event, unsigned int timeout); 15 | int ipc_event_recv(int *pid_store, int *event_store, unsigned int timeout); 16 | 17 | #endif /* !__KERN_SYNC_EVENT_H__ */ 18 | 19 | -------------------------------------------------------------------------------- /code/kern/sync/ipc.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_SYNC_IPC_H__ 2 | #define __KERN_SYNC_IPC_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | static inline void 11 | ipc_add_timer(timer_t *timer) { 12 | if (timer != NULL) { 13 | add_timer(timer); 14 | } 15 | } 16 | 17 | static inline void 18 | ipc_del_timer(timer_t *timer) { 19 | if (timer != NULL) { 20 | del_timer(timer); 21 | } 22 | } 23 | 24 | static inline timer_t * 25 | ipc_timer_init(unsigned int timeout, unsigned long *saved_ticks, timer_t *timer) { 26 | if (timeout != 0) { 27 | *saved_ticks = ticks; 28 | return timer_init(timer, current, timeout); 29 | } 30 | return NULL; 31 | } 32 | 33 | static inline int 34 | ipc_check_timeout(unsigned int timeout, unsigned long saved_ticks) { 35 | if (timeout != 0) { 36 | unsigned long delt = (unsigned long)(ticks - saved_ticks); 37 | if (delt >= timeout) { 38 | return -E_TIMEOUT; 39 | } 40 | } 41 | return -1; 42 | } 43 | 44 | #endif /* !__KERN_SYNC_IPC_H__ */ 45 | 46 | -------------------------------------------------------------------------------- /code/kern/sync/mbox.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_SYNC_MBOX_H__ 2 | #define __KERN_SYNC_MBOX_H__ 3 | 4 | #include 5 | 6 | void mbox_init(void); 7 | 8 | struct mboxbuf; 9 | struct mboxinfo; 10 | 11 | int ipc_mbox_init(unsigned int max_slots); 12 | int ipc_mbox_send(int id, struct mboxbuf *buf, unsigned int timeout); 13 | int ipc_mbox_recv(int id, struct mboxbuf *buf, unsigned int timeout); 14 | int ipc_mbox_free(int id); 15 | int ipc_mbox_info(int id, struct mboxinfo *info); 16 | 17 | void mbox_cleanup(void); 18 | 19 | #endif /* !__KERN_SYNC_MBOX_H__ */ 20 | 21 | -------------------------------------------------------------------------------- /code/kern/sync/sem.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_SYNC_SEM_H__ 2 | #define __KERN_SYNC_SEM_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | typedef struct { 9 | int value; 10 | bool valid; 11 | atomic_t count; 12 | wait_queue_t wait_queue; 13 | } semaphore_t; 14 | 15 | // The sem_undo_t is used to permit semaphore manipulations that can be undone. If a process 16 | // crashes after modifying a semaphore, the information held in the list is used to return the semaphore 17 | // to its state prior to modification. The mechanism is useful when the crashed process has made changes 18 | // after which processes waiting on the semaphore can no longer be woken. By undoing these actions (using 19 | // the information in the sem_undo list), the semaphore can be returned to a consistent state, thus preventing 20 | // deadlocks. 21 | typedef struct sem_undo { 22 | semaphore_t *sem; 23 | list_entry_t semu_link; 24 | } sem_undo_t; 25 | 26 | #define le2semu(le, member) \ 27 | to_struct((le), sem_undo_t, member) 28 | 29 | typedef struct sem_queue { 30 | semaphore_t sem; 31 | atomic_t count; 32 | list_entry_t semu_list; 33 | } sem_queue_t; 34 | 35 | void sem_init(semaphore_t *sem, int value); 36 | void up(semaphore_t *sem); 37 | void down(semaphore_t *sem); 38 | bool try_down(semaphore_t *sem); 39 | 40 | sem_undo_t *semu_create(semaphore_t *sem, int value); 41 | void semu_destroy(sem_undo_t *semu); 42 | 43 | sem_queue_t *sem_queue_create(void); 44 | void sem_queue_destroy(sem_queue_t *sem_queue); 45 | int dup_sem_queue(sem_queue_t *to, sem_queue_t *from); 46 | void exit_sem_queue(sem_queue_t *sem_queue); 47 | 48 | int ipc_sem_init(int value); 49 | int ipc_sem_post(sem_t sem_id); 50 | int ipc_sem_wait(sem_t sem_id, unsigned int timeout); 51 | int ipc_sem_free(sem_t sem_id); 52 | int ipc_sem_get_value(sem_t sem_id, int *value_store); 53 | 54 | static inline int 55 | sem_count(semaphore_t *sem) { 56 | return atomic_read(&(sem->count)); 57 | } 58 | 59 | static inline void 60 | set_sem_count(semaphore_t *sem, int val) { 61 | atomic_set(&(sem->count), val); 62 | } 63 | 64 | static inline int 65 | sem_count_inc(semaphore_t *sem) { 66 | return atomic_add_return(&(sem->count), 1); 67 | } 68 | 69 | static inline int 70 | sem_count_dec(semaphore_t *sem) { 71 | return atomic_sub_return(&(sem->count), 1); 72 | } 73 | 74 | static inline int 75 | sem_queue_count(sem_queue_t *sq) { 76 | return atomic_read(&(sq->count)); 77 | } 78 | 79 | static inline void 80 | set_sem_queue_count(sem_queue_t *sq, int val) { 81 | atomic_set(&(sq->count), val); 82 | } 83 | 84 | static inline int 85 | sem_queue_count_inc(sem_queue_t *sq) { 86 | return atomic_add_return(&(sq->count), 1); 87 | } 88 | 89 | static inline int 90 | sem_queue_count_dec(sem_queue_t *sq) { 91 | return atomic_sub_return(&(sq->count), 1); 92 | } 93 | 94 | #endif /* !__KERN_SYNC_SEM_H__ */ 95 | 96 | -------------------------------------------------------------------------------- /code/kern/sync/sync.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void 5 | sync_init(void) { 6 | mbox_init(); 7 | } 8 | 9 | -------------------------------------------------------------------------------- /code/kern/sync/sync.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_SYNC_SYNC_H__ 2 | #define __KERN_SYNC_SYNC_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | static inline bool 12 | __intr_save(void) { 13 | if (read_eflags() & FL_IF) { 14 | intr_disable(); 15 | return 1; 16 | } 17 | return 0; 18 | } 19 | 20 | static inline void 21 | __intr_restore(bool flag) { 22 | if (flag) { 23 | intr_enable(); 24 | } 25 | } 26 | 27 | #define local_intr_save(x) do { x = __intr_save(); } while (0) 28 | #define local_intr_restore(x) __intr_restore(x); 29 | 30 | void sync_init(void); 31 | 32 | #endif /* !__KERN_SYNC_SYNC_H__ */ 33 | 34 | -------------------------------------------------------------------------------- /code/kern/sync/wait.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_SYNC_WAIT_H__ 2 | #define __KERN_SYNC_WAIT_H__ 3 | 4 | #include 5 | 6 | typedef struct { 7 | list_entry_t wait_head; 8 | } wait_queue_t; 9 | 10 | struct proc_struct; 11 | 12 | typedef struct { 13 | struct proc_struct *proc; 14 | uint32_t wakeup_flags; 15 | wait_queue_t *wait_queue; 16 | list_entry_t wait_link; 17 | } wait_t; 18 | 19 | #define le2wait(le, member) \ 20 | to_struct((le), wait_t, member) 21 | 22 | void wait_init(wait_t *wait, struct proc_struct *proc); 23 | void wait_queue_init(wait_queue_t *queue); 24 | void wait_queue_add(wait_queue_t *queue, wait_t *wait); 25 | void wait_queue_del(wait_queue_t *queue, wait_t *wait); 26 | 27 | wait_t *wait_queue_next(wait_queue_t *queue, wait_t *wait); 28 | wait_t *wait_queue_prev(wait_queue_t *queue, wait_t *wait); 29 | wait_t *wait_queue_first(wait_queue_t *queue); 30 | wait_t *wait_queue_last(wait_queue_t *queue); 31 | 32 | bool wait_queue_empty(wait_queue_t *queue); 33 | bool wait_in_queue(wait_t *wait); 34 | void wakeup_wait(wait_queue_t *queue, wait_t *wait, uint32_t wakeup_flags, bool del); 35 | void wakeup_first(wait_queue_t *queue, uint32_t wakeup_flags, bool del); 36 | void wakeup_queue(wait_queue_t *queue, uint32_t wakeup_flags, bool del); 37 | 38 | void wait_current_set(wait_queue_t *queue, wait_t *wait, uint32_t wait_state); 39 | 40 | #define wait_current_del(queue, wait) \ 41 | do { \ 42 | if (wait_in_queue(wait)) { \ 43 | wait_queue_del(queue, wait); \ 44 | } \ 45 | } while (0) 46 | 47 | #endif /* !__KERN_SYNC_WAIT_H__ */ 48 | 49 | -------------------------------------------------------------------------------- /code/kern/syscall/syscall.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_SYSCALL_SYSCALL_H__ 2 | #define __KERN_SYSCALL_SYSCALL_H__ 3 | 4 | void syscall(void); 5 | 6 | #endif /* !__KERN_SYSCALL_SYSCALL_H__ */ 7 | 8 | -------------------------------------------------------------------------------- /code/kern/trap/trap.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_TRAP_TRAP_H__ 2 | #define __KERN_TRAP_TRAP_H__ 3 | 4 | #include 5 | 6 | /* Trap Numbers */ 7 | 8 | /* Processor-defined: */ 9 | #define T_DIVIDE 0 // divide error 10 | #define T_DEBUG 1 // debug exception 11 | #define T_NMI 2 // non-maskable interrupt 12 | #define T_BRKPT 3 // breakpoint 13 | #define T_OFLOW 4 // overflow 14 | #define T_BOUND 5 // bounds check 15 | #define T_ILLOP 6 // illegal opcode 16 | #define T_DEVICE 7 // device not available 17 | #define T_DBLFLT 8 // double fault 18 | // #define T_COPROC 9 // reserved (not used since 486) 19 | #define T_TSS 10 // invalid task switch segment 20 | #define T_SEGNP 11 // segment not present 21 | #define T_STACK 12 // stack exception 22 | #define T_GPFLT 13 // general protection fault 23 | #define T_PGFLT 14 // page fault 24 | // #define T_RES 15 // reserved 25 | #define T_FPERR 16 // floating point error 26 | #define T_ALIGN 17 // aligment check 27 | #define T_MCHK 18 // machine check 28 | #define T_SIMDERR 19 // SIMD floating point error 29 | 30 | /* Hardware IRQ numbers. We receive these as (IRQ_OFFSET + IRQ_xx) */ 31 | #define IRQ_OFFSET 32 // IRQ 0 corresponds to int IRQ_OFFSET 32 | 33 | #define IRQ_TIMER 0 34 | #define IRQ_KBD 1 35 | #define IRQ_COM1 4 36 | #define IRQ_IDE1 14 37 | #define IRQ_IDE2 15 38 | #define IRQ_ERROR 19 39 | #define IRQ_SPURIOUS 31 40 | 41 | /* registers as pushed by pushal */ 42 | struct pushregs { 43 | uint32_t reg_edi; 44 | uint32_t reg_esi; 45 | uint32_t reg_ebp; 46 | uint32_t reg_oesp; /* Useless */ 47 | uint32_t reg_ebx; 48 | uint32_t reg_edx; 49 | uint32_t reg_ecx; 50 | uint32_t reg_eax; 51 | }; 52 | 53 | struct trapframe { 54 | struct pushregs tf_regs; 55 | uint16_t tf_es; 56 | uint16_t tf_padding1; 57 | uint16_t tf_ds; 58 | uint16_t tf_padding2; 59 | uint32_t tf_trapno; 60 | /* below here defined by x86 hardware */ 61 | uint32_t tf_err; 62 | uintptr_t tf_eip; 63 | uint16_t tf_cs; 64 | uint16_t tf_padding3; 65 | uint32_t tf_eflags; 66 | /* below here only when crossing rings, such as from user to kernel */ 67 | uintptr_t tf_esp; 68 | uint16_t tf_ss; 69 | uint16_t tf_padding4; 70 | } __attribute__((packed)); 71 | 72 | void idt_init(void); 73 | void print_trapframe(struct trapframe *tf); 74 | void print_regs(struct pushregs *regs); 75 | bool trap_in_kernel(struct trapframe *tf); 76 | 77 | #endif /* !__KERN_TRAP_TRAP_H__ */ 78 | 79 | -------------------------------------------------------------------------------- /code/kern/trap/trapentry.S: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | # vectors.S sends all traps here. 4 | .text 5 | .globl __alltraps 6 | __alltraps: 7 | # push registers to build a trap frame 8 | # therefore make the stack look like a struct trapframe 9 | pushl %ds 10 | pushl %es 11 | pushal 12 | 13 | # load GD_KDATA into %ds and %es to set up data segments for kernel 14 | movl $GD_KDATA, %eax 15 | movw %ax, %ds 16 | movw %ax, %es 17 | 18 | # push %esp to pass a pointer to the trapframe as an argument to trap() 19 | pushl %esp 20 | 21 | # call trap(tf), where tf=%esp 22 | call trap 23 | 24 | # pop the pushed stack pointer 25 | popl %esp 26 | 27 | # return falls through to trapret... 28 | .globl __trapret 29 | __trapret: 30 | # restore registers from stack 31 | popal 32 | 33 | # restore %ds and %es 34 | popl %es 35 | popl %ds 36 | 37 | # get rid of the trap number and error code 38 | addl $0x8, %esp 39 | iret 40 | 41 | .globl forkrets 42 | forkrets: 43 | # set stack to this new process's trapframe 44 | movl 4(%esp), %esp 45 | jmp __trapret 46 | 47 | -------------------------------------------------------------------------------- /code/libs/dirent.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIBS_DIRENT_H__ 2 | #define __LIBS_DIRENT_H__ 3 | 4 | #include 5 | #include 6 | 7 | struct dirent { 8 | off_t offset; 9 | char name[FS_MAX_FNAME_LEN + 1]; 10 | }; 11 | 12 | #endif /* !__LIBS_DIRENT_H__ */ 13 | 14 | -------------------------------------------------------------------------------- /code/libs/elf.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIBS_ELF_H__ 2 | #define __LIBS_ELF_H__ 3 | 4 | #include 5 | 6 | #define ELF_MAGIC 0x464C457FU // "\x7FELF" in little endian 7 | 8 | /* file header */ 9 | struct elfhdr { 10 | uint32_t e_magic; // must equal ELF_MAGIC 11 | uint8_t e_elf[12]; 12 | uint16_t e_type; // 1=relocatable, 2=executable, 3=shared object, 4=core image 13 | uint16_t e_machine; // 3=x86, 4=68K, etc. 14 | uint32_t e_version; // file version, always 1 15 | uint32_t e_entry; // entry point if executable 16 | uint32_t e_phoff; // file position of program header or 0 17 | uint32_t e_shoff; // file position of section header or 0 18 | uint32_t e_flags; // architecture-specific flags, usually 0 19 | uint16_t e_ehsize; // size of this elf header 20 | uint16_t e_phentsize; // size of an entry in program header 21 | uint16_t e_phnum; // number of entries in program header or 0 22 | uint16_t e_shentsize; // size of an entry in section header 23 | uint16_t e_shnum; // number of entries in section header or 0 24 | uint16_t e_shstrndx; // section number that contains section name strings 25 | }; 26 | 27 | /* program section header */ 28 | struct proghdr { 29 | uint32_t p_type; // loadable code or data, dynamic linking info,etc. 30 | uint32_t p_offset; // file offset of segment 31 | uint32_t p_va; // virtual address to map segment 32 | uint32_t p_pa; // physical address, not used 33 | uint32_t p_filesz; // size of segment in file 34 | uint32_t p_memsz; // size of segment in memory (bigger if contains bss) 35 | uint32_t p_flags; // read/write/execute bits 36 | uint32_t p_align; // required alignment, invariably hardware page size 37 | }; 38 | 39 | /* values for Proghdr::p_type */ 40 | #define ELF_PT_LOAD 1 41 | 42 | /* flag bits for Proghdr::p_flags */ 43 | #define ELF_PF_X 1 44 | #define ELF_PF_W 2 45 | #define ELF_PF_R 4 46 | 47 | #endif /* !__LIBS_ELF_H__ */ 48 | 49 | -------------------------------------------------------------------------------- /code/libs/error.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIBS_ERROR_H__ 2 | #define __LIBS_ERROR_H__ 3 | 4 | /* kernel error codes -- keep in sync with list in lib/printfmt.c */ 5 | #define E_UNSPECIFIED 1 // Unspecified or unknown problem 6 | #define E_BAD_PROC 2 // Process doesn't exist or otherwise 7 | #define E_INVAL 3 // Invalid parameter 8 | #define E_NO_MEM 4 // Request failed due to memory shortage 9 | #define E_NO_FREE_PROC 5 // Attempt to create a new process beyond 10 | #define E_FAULT 6 // Memory fault 11 | #define E_SWAP_FAULT 7 // SWAP READ/WRITE fault 12 | #define E_INVAL_ELF 8 // Invalid elf file 13 | #define E_KILLED 9 // Process is killed 14 | #define E_PANIC 10 // Panic Failure 15 | #define E_TIMEOUT 11 // Timeout 16 | #define E_TOO_BIG 12 // Argument is Too Big 17 | #define E_NO_DEV 13 // No such Device 18 | #define E_NA_DEV 14 // Device Not Available 19 | #define E_BUSY 15 // Device/File is Busy 20 | #define E_NOENT 16 // No Such File or Directory 21 | #define E_ISDIR 17 // Is a Directory 22 | #define E_NOTDIR 18 // Not a Directory 23 | #define E_XDEV 19 // Cross Device-Link 24 | #define E_UNIMP 20 // Unimplemented Feature 25 | #define E_SEEK 21 // Illegal Seek 26 | #define E_MAX_OPEN 22 // Too Many Files are Open 27 | #define E_EXISTS 23 // File/Directory Already Exists 28 | #define E_NOTEMPTY 24 // Directory is Not Empty 29 | /* the maximum allowed */ 30 | #define MAXERROR 24 31 | 32 | #endif /* !__LIBS_ERROR_H__ */ 33 | 34 | -------------------------------------------------------------------------------- /code/libs/hash.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */ 4 | #define GOLDEN_RATIO_PRIME_32 0x9e370001UL 5 | 6 | /* * 7 | * hash32 - generate a hash value in the range [0, 2^@bits - 1] 8 | * @val: the input value 9 | * @bits: the number of bits in a return value 10 | * 11 | * High bits are more random, so we use them. 12 | * */ 13 | uint32_t 14 | hash32(uint32_t val, unsigned int bits) { 15 | uint32_t hash = val * GOLDEN_RATIO_PRIME_32; 16 | return (hash >> (32 - bits)); 17 | } 18 | 19 | -------------------------------------------------------------------------------- /code/libs/mboxbuf.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIBS_MBOXBUF_H__ 2 | #define __LIBS_MBOXBUF_H__ 3 | 4 | #include 5 | 6 | #define MAX_MSG_SLOTS 0x1000 7 | #define MAX_MSG_BYTES 0x10000 8 | 9 | struct mboxbuf { 10 | int from; 11 | size_t len; 12 | size_t size; 13 | void *data; 14 | }; 15 | 16 | struct mboxinfo { 17 | size_t slots; 18 | size_t max_slots; 19 | bool inuse; 20 | bool has_sender; 21 | bool has_receiver; 22 | }; 23 | 24 | #endif /* !__LIBS_MBOXBUF_H__ */ 25 | 26 | 27 | -------------------------------------------------------------------------------- /code/libs/rand.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static unsigned long long next = 1; 5 | 6 | /* * 7 | * rand - returns a pseudo-random integer 8 | * 9 | * The rand() function return a value in the range [0, RAND_MAX]. 10 | * */ 11 | int 12 | rand(void) { 13 | next = (next * 0x5DEECE66DLL + 0xBLL) & ((1LL << 48) - 1); 14 | unsigned long long result = (next >> 12); 15 | return (int)do_div(result, RAND_MAX + 1); 16 | } 17 | 18 | /* * 19 | * srand - seed the random number generator with the given number 20 | * @seed: the required seed number 21 | * */ 22 | void 23 | srand(unsigned int seed) { 24 | next = seed; 25 | } 26 | 27 | -------------------------------------------------------------------------------- /code/libs/stat.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIBS_STAT_H__ 2 | #define __LIBS_STAT_H__ 3 | 4 | #include 5 | 6 | struct stat { 7 | uint32_t st_mode; // protection mode and file type 8 | size_t st_nlinks; // number of hard links 9 | size_t st_blocks; // number of blocks file is using 10 | size_t st_size; // file size (bytes) 11 | }; 12 | 13 | #define S_IFMT 070000 // mask for type of file 14 | #define S_IFREG 010000 // ordinary regular file 15 | #define S_IFDIR 020000 // directory 16 | #define S_IFLNK 030000 // symbolic link 17 | #define S_IFCHR 040000 // character device 18 | #define S_IFBLK 050000 // block device 19 | 20 | #define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) // regular file 21 | #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) // directory 22 | #define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) // symlink 23 | #define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) // char device 24 | #define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) // block device 25 | 26 | #endif /* !__LIBS_STAT_H__ */ 27 | 28 | -------------------------------------------------------------------------------- /code/libs/stdarg.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIBS_STDARG_H__ 2 | #define __LIBS_STDARG_H__ 3 | 4 | /* compiler provides size of save area */ 5 | typedef __builtin_va_list va_list; 6 | 7 | #define va_start(ap, last) (__builtin_va_start(ap, last)) 8 | #define va_arg(ap, type) (__builtin_va_arg(ap, type)) 9 | #define va_end(ap) /*nothing*/ 10 | 11 | #endif /* !__LIBS_STDARG_H__ */ 12 | 13 | -------------------------------------------------------------------------------- /code/libs/stdio.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIBS_STDIO_H__ 2 | #define __LIBS_STDIO_H__ 3 | 4 | #include 5 | #include 6 | 7 | /* kern/libs/stdio.c */ 8 | int cprintf(const char *fmt, ...); 9 | int vcprintf(const char *fmt, va_list ap); 10 | void cputchar(int c); 11 | int cputs(const char *str); 12 | int getchar(void); 13 | 14 | /* kern/libs/readline.c */ 15 | char *readline(const char *prompt); 16 | 17 | /* libs/printfmt.c */ 18 | void printfmt(void (*putch)(int, void *, int), int fd, void *putdat, const char *fmt, ...); 19 | void vprintfmt(void (*putch)(int, void *, int), int fd, void *putdat, const char *fmt, va_list ap); 20 | int snprintf(char *str, size_t size, const char *fmt, ...); 21 | int vsnprintf(char *str, size_t size, const char *fmt, va_list ap); 22 | 23 | #endif /* !__LIBS_STDIO_H__ */ 24 | 25 | -------------------------------------------------------------------------------- /code/libs/stdlib.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIBS_STDLIB_H__ 2 | #define __LIBS_STDLIB_H__ 3 | 4 | #include 5 | 6 | /* the largest number rand will return */ 7 | #define RAND_MAX 2147483647UL 8 | 9 | /* libs/rand.c */ 10 | int rand(void); 11 | void srand(unsigned int seed); 12 | 13 | /* libs/hash.c */ 14 | uint32_t hash32(uint32_t val, unsigned int bits); 15 | 16 | #endif /* !__LIBS_RAND_H__ */ 17 | 18 | -------------------------------------------------------------------------------- /code/libs/string.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIBS_STRING_H__ 2 | #define __LIBS_STRING_H__ 3 | 4 | #include 5 | 6 | size_t strlen(const char *s); 7 | size_t strnlen(const char *s, size_t len); 8 | 9 | char *strcpy(char *dst, const char *src); 10 | char *strncpy(char *dst, const char *src, size_t len); 11 | char *strcat(char *dst, const char *src); 12 | char *strdup(const char *src); 13 | char *stradd(const char *src1, const char *src2); 14 | 15 | int strcmp(const char *s1, const char *s2); 16 | int strncmp(const char *s1, const char *s2, size_t n); 17 | 18 | char *strchr(const char *s, char c); 19 | char *strfind(const char *s, char c); 20 | long strtol(const char *s, char **endptr, int base); 21 | 22 | void *memset(void *s, char c, size_t n); 23 | void *memmove(void *dst, const void *src, size_t n); 24 | void *memcpy(void *dst, const void *src, size_t n); 25 | int memcmp(const void *v1, const void *v2, size_t n); 26 | 27 | #endif /* !__LIBS_STRING_H__ */ 28 | 29 | -------------------------------------------------------------------------------- /code/libs/types.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIBS_TYPES_H__ 2 | #define __LIBS_TYPES_H__ 3 | 4 | #ifndef NULL 5 | #define NULL ((void *)0) 6 | #endif 7 | 8 | #define CHAR_BIT 8 9 | 10 | /* Represents true-or-false values */ 11 | typedef int bool; 12 | 13 | /* Explicitly-sized versions of integer types */ 14 | typedef char int8_t; 15 | typedef unsigned char uint8_t; 16 | typedef short int16_t; 17 | typedef unsigned short uint16_t; 18 | typedef int int32_t; 19 | typedef unsigned int uint32_t; 20 | typedef long long int64_t; 21 | typedef unsigned long long uint64_t; 22 | 23 | /* * 24 | * Pointers and addresses are 32 bits long. 25 | * We use pointer types to represent addresses, 26 | * uintptr_t to represent the numerical values of addresses. 27 | * */ 28 | typedef int32_t intptr_t; 29 | typedef uint32_t uintptr_t; 30 | 31 | /* size_t is used for memory object sizes */ 32 | typedef uintptr_t size_t; 33 | 34 | /* off_t is used for file offsets and lengths */ 35 | typedef intptr_t off_t; 36 | 37 | /* used for page numbers */ 38 | typedef size_t ppn_t; 39 | 40 | /* sem_t is used for semaphore id */ 41 | typedef uintptr_t sem_t; 42 | 43 | /* * 44 | * Rounding operations (efficient when n is a power of 2) 45 | * Round down to the nearest multiple of n 46 | * */ 47 | #define ROUNDDOWN(a, n) ({ \ 48 | size_t __a = (size_t)(a); \ 49 | (typeof(a))(__a - __a % (n)); \ 50 | }) 51 | 52 | /* Round up to the nearest multiple of n */ 53 | #define ROUNDUP(a, n) ({ \ 54 | size_t __n = (size_t)(n); \ 55 | (typeof(a))(ROUNDDOWN((size_t)(a) + __n - 1, __n)); \ 56 | }) 57 | 58 | /* Round up the result of dividing of n */ 59 | #define ROUNDUP_DIV(a, n) ({ \ 60 | uint32_t __n = (uint32_t)(n); \ 61 | (typeof(a))(((a) + __n - 1) / __n); \ 62 | }) 63 | 64 | /* Return the offset of 'member' relative to the beginning of a struct type */ 65 | #define offsetof(type, member) \ 66 | ((size_t)(&((type *)0)->member)) 67 | 68 | /* * 69 | * to_struct - get the struct from a ptr 70 | * @ptr: a struct pointer of member 71 | * @type: the type of the struct this is embedded in 72 | * @member: the name of the member within the struct 73 | * */ 74 | #define to_struct(ptr, type, member) \ 75 | ((type *)((char *)(ptr) - offsetof(type, member))) 76 | 77 | #endif /* !__LIBS_TYPES_H__ */ 78 | 79 | -------------------------------------------------------------------------------- /code/libs/unistd.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIBS_UNISTD_H__ 2 | #define __LIBS_UNISTD_H__ 3 | 4 | #define T_SYSCALL 0x80 5 | 6 | /* syscall number */ 7 | #define SYS_exit 1 8 | #define SYS_fork 2 9 | #define SYS_wait 3 10 | #define SYS_exec 4 11 | #define SYS_clone 5 12 | #define SYS_exit_thread 9 13 | #define SYS_yield 10 14 | #define SYS_sleep 11 15 | #define SYS_kill 12 16 | #define SYS_gettime 17 17 | #define SYS_getpid 18 18 | #define SYS_brk 19 19 | #define SYS_mmap 20 20 | #define SYS_munmap 21 21 | #define SYS_shmem 22 22 | #define SYS_putc 30 23 | #define SYS_pgdir 31 24 | #define SYS_sem_init 40 25 | #define SYS_sem_post 41 26 | #define SYS_sem_wait 42 27 | #define SYS_sem_free 43 28 | #define SYS_sem_get_value 44 29 | #define SYS_event_send 48 30 | #define SYS_event_recv 49 31 | #define SYS_mbox_init 50 32 | #define SYS_mbox_send 51 33 | #define SYS_mbox_recv 52 34 | #define SYS_mbox_free 53 35 | #define SYS_mbox_info 54 36 | #define SYS_open 100 37 | #define SYS_close 101 38 | #define SYS_read 102 39 | #define SYS_write 103 40 | #define SYS_seek 104 41 | #define SYS_fstat 110 42 | #define SYS_fsync 111 43 | #define SYS_chdir 120 44 | #define SYS_getcwd 121 45 | #define SYS_mkdir 122 46 | #define SYS_link 123 47 | #define SYS_rename 124 48 | #define SYS_readlink 125 49 | #define SYS_symlink 126 50 | #define SYS_unlink 127 51 | #define SYS_getdirentry 128 52 | #define SYS_dup 130 53 | #define SYS_pipe 140 54 | #define SYS_mkfifo 141 55 | 56 | /* SYS_fork flags */ 57 | #define CLONE_VM 0x00000100 // set if VM shared between processes 58 | #define CLONE_THREAD 0x00000200 // thread group 59 | #define CLONE_SEM 0x00000400 // set if shared between processes 60 | #define CLONE_FS 0x00000800 // set if shared between processes 61 | 62 | /* SYS_mmap flags */ 63 | #define MMAP_WRITE 0x00000100 64 | #define MMAP_STACK 0x00000200 65 | 66 | /* VFS flags */ 67 | // flags for open: choose one of these 68 | #define O_RDONLY 0 // open for reading only 69 | #define O_WRONLY 1 // open for writing only 70 | #define O_RDWR 2 // open for reading and writing 71 | // then or in any of these: 72 | #define O_CREAT 0x00000004 // create file if it does not exist 73 | #define O_EXCL 0x00000008 // error if O_CREAT and the file exists 74 | #define O_TRUNC 0x00000010 // truncate file upon open 75 | #define O_APPEND 0x00000020 // append on each write 76 | // additonal related definition 77 | #define O_ACCMODE 3 // mask for O_RDONLY / O_WRONLY / O_RDWR 78 | 79 | #define NO_FD -0x9527 // invalid fd 80 | 81 | /* lseek codes */ 82 | #define LSEEK_SET 0 // seek relative to beginning of file 83 | #define LSEEK_CUR 1 // seek relative to current position in file 84 | #define LSEEK_END 2 // seek relative to end of file 85 | 86 | #define FS_MAX_DNAME_LEN 31 87 | #define FS_MAX_FNAME_LEN 255 88 | #define FS_MAX_FPATH_LEN 4095 89 | 90 | #define EXEC_MAX_ARG_NUM 32 91 | #define EXEC_MAX_ARG_LEN 4095 92 | 93 | #endif /* !__LIBS_UNISTD_H__ */ 94 | 95 | -------------------------------------------------------------------------------- /code/tools/function.mk: -------------------------------------------------------------------------------- 1 | OBJPREFIX := __objs_ 2 | 3 | .SECONDEXPANSION: 4 | # -------------------- function begin -------------------- 5 | 6 | # list all files in some directories: (#directories, #types) 7 | listf = $(filter $(if $(2),$(addprefix %.,$(2)),%),\ 8 | $(wildcard $(addsuffix $(SLASH)*,$(1)))) 9 | 10 | # get .o obj files: (#files[, packet]) 11 | toobj = $(addprefix $(OBJDIR)$(SLASH)$(if $(2),$(2)$(SLASH)),\ 12 | $(addsuffix .o,$(basename $(1)))) 13 | 14 | # get .d dependency files: (#files[, packet]) 15 | todep = $(patsubst %.o,%.d,$(call toobj,$(1),$(2))) 16 | 17 | totarget = $(addprefix $(BINDIR)$(SLASH),$(1)) 18 | 19 | # change $(name) to $(OBJPREFIX)$(name): (#names) 20 | packetname = $(if $(1),$(addprefix $(OBJPREFIX),$(1)),$(OBJPREFIX)) 21 | 22 | # cc compile template, generate rule for dep, obj: (file, cc[, flags, dir]) 23 | define cc_template 24 | $$(call todep,$(1),$(4)): $(1) | $$$$(dir $$$$@) 25 | @$(2) -I$$(dir $(1)) $(3) -MM $$< -MT "$$(patsubst %.d,%.o,$$@) $$@"> $$@ 26 | $$(call toobj,$(1),$(4)): $(1) | $$$$(dir $$$$@) 27 | @echo + cc $$< 28 | $(V)$(2) -I$$(dir $(1)) $(3) -c $$< -o $$@ 29 | ALLOBJS += $$(call toobj,$(1),$(4)) 30 | endef 31 | 32 | # compile file: (#files, cc[, flags, dir]) 33 | define do_cc_compile 34 | $$(foreach f,$(1),$$(eval $$(call cc_template,$$(f),$(2),$(3),$(4)))) 35 | endef 36 | 37 | # add files to packet: (#files, cc[, flags, packet, dir]) 38 | define do_add_files_to_packet 39 | __temp_packet__ := $(call packetname,$(4)) 40 | ifeq ($$(origin $$(__temp_packet__)),undefined) 41 | $$(__temp_packet__) := 42 | endif 43 | __temp_objs__ := $(call toobj,$(1),$(5)) 44 | $$(foreach f,$(1),$$(eval $$(call cc_template,$$(f),$(2),$(3),$(5)))) 45 | $$(__temp_packet__) += $$(__temp_objs__) 46 | endef 47 | 48 | # add objs to packet: (#objs, packet) 49 | define do_add_objs_to_packet 50 | __temp_packet__ := $(call packetname,$(2)) 51 | ifeq ($$(origin $$(__temp_packet__)),undefined) 52 | $$(__temp_packet__) := 53 | endif 54 | $$(__temp_packet__) += $(1) 55 | endef 56 | 57 | # add packets and objs to target (target, #packes, #objs[, cc, flags]) 58 | define do_create_target 59 | __temp_target__ = $(call totarget,$(1)) 60 | __temp_objs__ = $$(foreach p,$(call packetname,$(2)),$$($$(p))) $(3) 61 | TARGETS += $$(__temp_target__) 62 | ifneq ($(4),) 63 | $$(__temp_target__): $$(__temp_objs__) | $$$$(dir $$$$@) 64 | $(V)$(4) $(5) $$^ -o $$@ 65 | else 66 | $$(__temp_target__): $$(__temp_objs__) | $$$$(dir $$$$@) 67 | endif 68 | endef 69 | 70 | # finish all 71 | define do_finish_all 72 | ALLDEPS = $$(ALLOBJS:.o=.d) 73 | $$(sort $$(dir $$(ALLOBJS)) $(BINDIR)$(SLASH) $(OBJDIR)$(SLASH)): 74 | @$(MKDIR) $$@ 75 | endef 76 | 77 | # -------------------- function end -------------------- 78 | # compile file: (#files, cc[, flags, dir]) 79 | cc_compile = $(eval $(call do_cc_compile,$(1),$(2),$(3),$(4))) 80 | 81 | # add files to packet: (#files, cc[, flags, packet, dir]) 82 | add_files = $(eval $(call do_add_files_to_packet,$(1),$(2),$(3),$(4),$(5))) 83 | 84 | # add objs to packet: (#objs, packet) 85 | add_objs = $(eval $(call do_add_objs_to_packet,$(1),$(2))) 86 | 87 | # add packets and objs to target (target, #packes, #objs, cc, [, flags]) 88 | create_target = $(eval $(call do_create_target,$(1),$(2),$(3),$(4),$(5))) 89 | 90 | read_packet = $(foreach p,$(call packetname,$(1)),$($(p))) 91 | 92 | add_dependency = $(eval $(1): $(2)) 93 | 94 | finish_all = $(eval $(call do_finish_all)) 95 | 96 | -------------------------------------------------------------------------------- /code/tools/gdbinit: -------------------------------------------------------------------------------- 1 | file bin/kernel 2 | target remote :1234 3 | break kern_init 4 | -------------------------------------------------------------------------------- /code/tools/kernel.ld: -------------------------------------------------------------------------------- 1 | /* Simple linker script for the ucore kernel. 2 | See the GNU ld 'info' manual ("info ld") to learn the syntax. */ 3 | 4 | OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") 5 | OUTPUT_ARCH(i386) 6 | ENTRY(kern_entry) 7 | 8 | SECTIONS { 9 | /* Load the kernel at this address: "." means the current address */ 10 | . = 0xC0100000; 11 | 12 | .text : { 13 | *(.text .stub .text.* .gnu.linkonce.t.*) 14 | } 15 | 16 | PROVIDE(etext = .); /* Define the 'etext' symbol to this value */ 17 | 18 | .rodata : { 19 | *(.rodata .rodata.* .gnu.linkonce.r.*) 20 | } 21 | 22 | /* Include debugging information in kernel memory */ 23 | .stab : { 24 | PROVIDE(__STAB_BEGIN__ = .); 25 | *(.stab); 26 | PROVIDE(__STAB_END__ = .); 27 | BYTE(0) /* Force the linker to allocate space 28 | for this section */ 29 | } 30 | 31 | .stabstr : { 32 | PROVIDE(__STABSTR_BEGIN__ = .); 33 | *(.stabstr); 34 | PROVIDE(__STABSTR_END__ = .); 35 | BYTE(0) /* Force the linker to allocate space 36 | for this section */ 37 | } 38 | 39 | /* Adjust the address for the data segment to the next page */ 40 | . = ALIGN(0x1000); 41 | 42 | /* The data segment */ 43 | .data : { 44 | *(.data) 45 | } 46 | 47 | PROVIDE(edata = .); 48 | 49 | .bss : { 50 | *(.bss) 51 | } 52 | 53 | PROVIDE(end = .); 54 | 55 | /DISCARD/ : { 56 | *(.eh_frame .note.GNU-stack) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /code/tools/sign.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int 7 | main(int argc, char *argv[]) { 8 | struct stat st; 9 | if (argc != 3) { 10 | fprintf(stderr, "Usage: \n"); 11 | return -1; 12 | } 13 | if (stat(argv[1], &st) != 0) { 14 | fprintf(stderr, "Error opening file '%s': %s\n", argv[1], strerror(errno)); 15 | return -1; 16 | } 17 | printf("'%s' size: %lld bytes\n", argv[1], (long long)st.st_size); 18 | if (st.st_size > 510) { 19 | fprintf(stderr, "%lld >> 510!!\n", (long long)st.st_size); 20 | return -1; 21 | } 22 | char buf[512]; 23 | memset(buf, 0, sizeof(buf)); 24 | FILE *ifp = fopen(argv[1], "rb"); 25 | int size = fread(buf, 1, st.st_size, ifp); 26 | if (size != st.st_size) { 27 | fprintf(stderr, "read '%s' error, size is %d.\n", argv[1], size); 28 | return -1; 29 | } 30 | fclose(ifp); 31 | buf[510] = 0x55; 32 | buf[511] = 0xAA; 33 | FILE *ofp = fopen(argv[2], "wb+"); 34 | size = fwrite(buf, 1, 512, ofp); 35 | if (size != 512) { 36 | fprintf(stderr, "write '%s' error, size is %d.\n", argv[2], size); 37 | return -1; 38 | } 39 | fclose(ofp); 40 | printf("build 512 bytes boot sector: '%s' success!\n", argv[2]); 41 | return 0; 42 | } 43 | 44 | -------------------------------------------------------------------------------- /code/tools/user.ld: -------------------------------------------------------------------------------- 1 | /* Simple linker script for ucore user-level programs. 2 | See the GNU ld 'info' manual ("info ld") to learn the syntax. */ 3 | 4 | OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") 5 | OUTPUT_ARCH(i386) 6 | ENTRY(_start) 7 | 8 | SECTIONS { 9 | /* Load programs at this address: "." means the current address */ 10 | . = 0x800020; 11 | 12 | .text : { 13 | *(.text .stub .text.* .gnu.linkonce.t.*) 14 | } 15 | 16 | PROVIDE(etext = .); /* Define the 'etext' symbol to this value */ 17 | 18 | .rodata : { 19 | *(.rodata .rodata.* .gnu.linkonce.r.*) 20 | } 21 | 22 | /* Adjust the address for the data segment to the next page */ 23 | . = ALIGN(0x1000); 24 | 25 | .data : { 26 | *(.data) 27 | } 28 | 29 | PROVIDE(edata = .); 30 | 31 | .bss : { 32 | *(.bss) 33 | } 34 | 35 | PROVIDE(end = .); 36 | 37 | 38 | /* Place debugging symbols so that they can be found by 39 | * the kernel debugger. 40 | * Specifically, the four words at 0x200000 mark the beginning of 41 | * the stabs, the end of the stabs, the beginning of the stabs 42 | * string table, and the end of the stabs string table, respectively. 43 | */ 44 | 45 | .stab_info 0x200000 : { 46 | LONG(__STAB_BEGIN__); 47 | LONG(__STAB_END__); 48 | LONG(__STABSTR_BEGIN__); 49 | LONG(__STABSTR_END__); 50 | } 51 | 52 | .stab : { 53 | __STAB_BEGIN__ = DEFINED(__STAB_BEGIN__) ? __STAB_BEGIN__ : .; 54 | *(.stab); 55 | __STAB_END__ = DEFINED(__STAB_END__) ? __STAB_END__ : .; 56 | BYTE(0) /* Force the linker to allocate space 57 | for this section */ 58 | } 59 | 60 | .stabstr : { 61 | __STABSTR_BEGIN__ = DEFINED(__STABSTR_BEGIN__) ? __STABSTR_BEGIN__ : .; 62 | *(.stabstr); 63 | __STABSTR_END__ = DEFINED(__STABSTR_END__) ? __STABSTR_END__ : .; 64 | BYTE(0) /* Force the linker to allocate space 65 | for this section */ 66 | } 67 | 68 | /DISCARD/ : { 69 | *(.eh_frame .note.GNU-stack .comment) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /code/tools/vector.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int 4 | main(void) { 5 | printf("# handler\n"); 6 | printf(".text\n"); 7 | printf(".globl __alltraps\n"); 8 | 9 | int i; 10 | for (i = 0; i < 256; i ++) { 11 | printf(".globl vector%d\n", i); 12 | printf("vector%d:\n", i); 13 | if ((i < 8 || i > 14) && i != 17) { 14 | printf(" pushl $0\n"); 15 | } 16 | printf(" pushl $%d\n", i); 17 | printf(" jmp __alltraps\n"); 18 | } 19 | printf("\n"); 20 | printf("# vector table\n"); 21 | printf(".data\n"); 22 | printf(".globl __vectors\n"); 23 | printf("__vectors:\n"); 24 | for (i = 0; i < 256; i ++) { 25 | printf(" .long vector%d\n", i); 26 | } 27 | return 0; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /code/user/badarg.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int 5 | main(void) { 6 | int pid, exit_code; 7 | if ((pid = fork()) == 0) { 8 | cprintf("fork ok.\n"); 9 | int i; 10 | for (i = 0; i < 10; i ++) { 11 | yield(); 12 | } 13 | exit(0xbeaf); 14 | } 15 | assert(pid > 0); 16 | assert(waitpid(-1, NULL) != 0); 17 | assert(waitpid(pid, (void *)0xC0000000) != 0); 18 | assert(waitpid(pid, &exit_code) == 0 && exit_code == 0xbeaf); 19 | cprintf("badarg pass.\n"); 20 | return 0; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /code/user/badbrktest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct slot { 6 | char data[4096]; 7 | struct slot *next; 8 | }; 9 | 10 | int 11 | main(void) { 12 | int pid, exit_code; 13 | if ((pid = fork()) == 0) { 14 | struct slot *tmp, *head = NULL; 15 | int n = 0, m = 0; 16 | cprintf("I am child.\n"); 17 | cprintf("I am going to eat out all the mem, MU HA HA!!.\n"); 18 | while ((tmp = (struct slot *)malloc(sizeof(struct slot))) != NULL) { 19 | n ++, m ++; 20 | if (m == 1000) { 21 | cprintf("I ate %d slots.\n", m); 22 | m = 0; 23 | } 24 | tmp->next = head; 25 | head = tmp; 26 | } 27 | exit(0xdead); 28 | } 29 | assert(pid > 0); 30 | assert(waitpid(pid, &exit_code) == 0 && exit_code != 0xdead); 31 | cprintf("child is killed by kernel, en.\n"); 32 | 33 | assert(wait() != 0); 34 | cprintf("badbrktest pass.\n"); 35 | return 0; 36 | } 37 | 38 | -------------------------------------------------------------------------------- /code/user/badsegment.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* try to load the kernel's TSS selector into the DS register */ 5 | 6 | int 7 | main(void) { 8 | asm volatile("movw $0x28,%ax; movw %ax,%ds"); 9 | panic("FAIL: T.T\n"); 10 | } 11 | 12 | -------------------------------------------------------------------------------- /code/user/brkfreetest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void 7 | brkfreetest(void) { 8 | uintptr_t oldbrk = 0; 9 | assert(sys_brk(&oldbrk) == 0); 10 | 11 | uintptr_t newbrk = oldbrk + 4096; 12 | assert(sys_brk(&newbrk) == 0 && newbrk >= oldbrk + 4096); 13 | 14 | char *p = (void *)oldbrk; 15 | int i; 16 | for (i = 0; i < 4096; i ++) { 17 | p[i] = (char)(i * 31 + (i & 0xF)); 18 | } 19 | for (i = 0; i < 4096; i ++) { 20 | assert(p[i] == (char)(i * 31 + (i & 0xF))); 21 | } 22 | newbrk = oldbrk; 23 | assert(sys_brk(&newbrk) == 0 && newbrk == oldbrk); 24 | 25 | cprintf("page fault!!\n"); 26 | p[0] = 0; 27 | } 28 | 29 | int 30 | main(void) { 31 | int pid, exit_code; 32 | if ((pid = fork()) == 0) { 33 | brkfreetest(); 34 | exit(0xdead); 35 | } 36 | assert(pid > 0); 37 | assert(waitpid(pid, &exit_code) == 0 && exit_code != 0xdead); 38 | assert(exit_code != -E_PANIC); 39 | 40 | cprintf("brkfreetest pass.\n"); 41 | return 0; 42 | } 43 | 44 | -------------------------------------------------------------------------------- /code/user/brktest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct slot { 6 | char data[4096]; 7 | struct slot *next; 8 | }; 9 | 10 | int 11 | main(void) { 12 | struct slot *tmp, *head = NULL; 13 | int n = 0, rounds = 10; 14 | cprintf("I am going to eat out all the mem, MU HA HA!!.\n"); 15 | while (rounds > 0 && (tmp = (struct slot *)malloc(sizeof(struct slot))) != NULL) { 16 | if ((++ n) % 1000 == 0) { 17 | cprintf("I ate %d slots.\n", n); 18 | rounds --; 19 | } 20 | tmp->next = head; 21 | head = tmp; 22 | head->data[0] = (char)n; 23 | } 24 | cprintf("I ate (at least) %d byte memory.\n", n * sizeof(struct slot)); 25 | print_pgdir(); 26 | 27 | int error = 0; 28 | while (head != NULL) { 29 | if (head->data[0] != (char)(n --)) { 30 | error ++; 31 | } 32 | tmp = head->next; 33 | free(head); 34 | head = tmp; 35 | } 36 | cprintf("I free all the memory.(%d)\n", error); 37 | cprintf("brktest pass.\n"); 38 | return 0; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /code/user/buggy_event.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | uintptr_t addr = 0; 7 | const size_t size = 4096 * 2; 8 | 9 | int pid; 10 | 11 | int 12 | test(void *arg) { 13 | assert(addr != 0 && munmap(addr, size) == 0); 14 | send_event(pid, 1481); 15 | cprintf("child munmap ok.\n"); 16 | return 0; 17 | } 18 | 19 | int 20 | main(void) { 21 | assert(mmap(&addr, size, MMAP_WRITE) == 0); 22 | 23 | pid = getpid(); 24 | 25 | int *pidp = (int *)addr, *eventp = (int *)(addr + 4096); 26 | 27 | thread_t tid; 28 | assert(thread(test, NULL, &tid) == 0); 29 | assert(recv_event(pidp, eventp) != 0); 30 | 31 | thread_wait(&tid, NULL); 32 | cprintf("buggy_event pass.\n"); 33 | return 0; 34 | } 35 | 36 | -------------------------------------------------------------------------------- /code/user/buggy_wait.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | uintptr_t addr = 0; 7 | const size_t size = 4096; 8 | 9 | int 10 | test(void *arg) { 11 | assert(addr != 0 && munmap(addr, size) == 0); 12 | cprintf("child munmap ok.\n"); 13 | return 0; 14 | } 15 | 16 | int 17 | main(void) { 18 | assert(mmap(&addr, size, MMAP_WRITE) == 0); 19 | 20 | int *exit_codep = (int *)addr; 21 | 22 | thread_t tid; 23 | assert(thread(test, NULL, &tid) == 0); 24 | assert(thread_wait(&tid, exit_codep) != 0); 25 | 26 | thread_wait(&tid, NULL); 27 | cprintf("buggy_wait pass.\n"); 28 | return 0; 29 | } 30 | 31 | -------------------------------------------------------------------------------- /code/user/buggy_wait2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | uintptr_t addr = 0; 6 | const size_t size = 4096; 7 | 8 | int 9 | main(void) { 10 | assert(mmap(&addr, size, MMAP_WRITE) == 0); 11 | 12 | int *exit_codep = (int *)addr, pid; 13 | 14 | if ((pid = fork()) == 0) { 15 | cprintf("child fork ok.\n"); 16 | exit(0); 17 | } 18 | 19 | assert(waitpid(pid, exit_codep) == 0 && *exit_codep == 0); 20 | cprintf("buggy_wait2 pass.\n"); 21 | return 0; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /code/user/cat.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define BUFSIZE 4096 7 | 8 | int 9 | cat(int fd) { 10 | static char buffer[BUFSIZE]; 11 | int ret1, ret2; 12 | while ((ret1 = read(fd, buffer, sizeof(buffer))) > 0) { 13 | if ((ret2 = write(1, buffer, ret1)) != ret1) { 14 | return ret2; 15 | } 16 | } 17 | return ret1; 18 | } 19 | 20 | int 21 | main(int argc, char **argv) { 22 | if (argc == 1) { 23 | return cat(0); 24 | } 25 | else { 26 | int i, ret; 27 | for (i = 1; i < argc; i ++) { 28 | if ((ret = open(argv[i], O_RDONLY)) < 0) { 29 | return ret; 30 | } 31 | if ((ret = cat(ret)) != 0) { 32 | return ret; 33 | } 34 | } 35 | } 36 | return 0; 37 | } 38 | 39 | -------------------------------------------------------------------------------- /code/user/cowtest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | struct slot { 7 | char data[4096]; 8 | struct slot *next; 9 | }; 10 | 11 | struct slot * 12 | expand(int num) { 13 | struct slot *tmp, *head = NULL; 14 | while (num > 0) { 15 | tmp = (struct slot *)malloc(sizeof(struct slot)); 16 | tmp->next = head; 17 | head = tmp; 18 | num --; 19 | } 20 | return head; 21 | } 22 | 23 | struct slot *head; 24 | 25 | void 26 | sweeper(void) { 27 | struct slot *p = head; 28 | while (p != NULL) { 29 | p->data[0] = (char)0xEF; 30 | p = p->next; 31 | } 32 | p = head; 33 | while (p != NULL) { 34 | assert(p->data[0] == (char)0xEF); 35 | p = p->next; 36 | } 37 | exit(0xbeaf); 38 | } 39 | 40 | int 41 | main(void) { 42 | head = expand(6000); 43 | 44 | int pid, exit_code; 45 | if ((pid = fork()) == 0) { 46 | sweeper(); 47 | } 48 | assert(pid > 0); 49 | cprintf("fork ok.\n"); 50 | 51 | assert(waitpid(pid, &exit_code) == 0 && exit_code == 0xbeaf); 52 | cprintf("cowtest pass.\n"); 53 | return 0; 54 | } 55 | 56 | -------------------------------------------------------------------------------- /code/user/divzero.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int zero; 5 | 6 | int 7 | main(void) { 8 | cprintf("value is %d.\n", 1 / zero); 9 | panic("FAIL: T.T\n"); 10 | } 11 | 12 | -------------------------------------------------------------------------------- /code/user/echo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int 7 | main(int argc, char **argv) { 8 | int i, nflag = 0; 9 | if (argc > 1 && strcmp(argv[1], "-n") == 0) { 10 | nflag = 1, argc --, argv ++; 11 | } 12 | for (i = 1; i < argc; i ++) { 13 | if (i > 1) { 14 | write(1, " ", 1); 15 | } 16 | write(1, argv[i], strlen(argv[i])); 17 | } 18 | if (!nflag) { 19 | write(1, "\n", 1); 20 | } 21 | return 0; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /code/user/eventtest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void 6 | test1(void) { 7 | int pid, parent = getpid(); 8 | if ((pid = fork()) == 0) { 9 | int event, sum = 0; 10 | while (recv_event(&pid, &event) == 0 && parent == pid) { 11 | if (event == -1) { 12 | cprintf("child1 Hmmm!\n"); 13 | sleep(100); 14 | cprintf("child1 quit\n"); 15 | exit(-1); 16 | } 17 | cprintf("child1 receive %08x from %d\n", event, pid); 18 | sum += event; 19 | } 20 | panic("FAIL: T.T\n"); 21 | } 22 | assert(pid > 0); 23 | int i = 10; 24 | while (send_event(pid, i) == 0) { 25 | i --; 26 | sleep(50); 27 | } 28 | cprintf("test1 pass.\n"); 29 | } 30 | 31 | void 32 | test2(void) { 33 | int pid; 34 | if ((pid = fork()) == 0) { 35 | cprintf("child2 is spinning...\n"); 36 | while (1); 37 | } 38 | assert(pid > 0); 39 | if (send_event_timeout(pid, 0xbee, 100) == -E_TIMEOUT) { 40 | cprintf("test2 pass.\n"); 41 | } 42 | kill(pid); 43 | } 44 | 45 | void 46 | test3(void) { 47 | int pid; 48 | if ((pid = fork()) == 0) { 49 | int event; 50 | if (recv_event_timeout(NULL, &event, 100) == -E_TIMEOUT) { 51 | cprintf("test3 pass.\n"); 52 | } 53 | exit(0); 54 | } 55 | assert(pid > 0); 56 | assert(waitpid(pid, NULL) == 0); 57 | } 58 | 59 | int 60 | main(void) { 61 | test1(); 62 | test2(); 63 | test3(); 64 | cprintf("eventtest pass.\n"); 65 | return 0; 66 | } 67 | 68 | -------------------------------------------------------------------------------- /code/user/exit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int magic = -0x10384; 5 | 6 | int 7 | main(void) { 8 | int pid, code; 9 | cprintf("I am the parent. Forking the child...\n"); 10 | if ((pid = fork()) == 0) { 11 | cprintf("I am the child.\n"); 12 | yield(); 13 | yield(); 14 | yield(); 15 | yield(); 16 | yield(); 17 | yield(); 18 | yield(); 19 | exit(magic); 20 | } 21 | assert(pid > 0); 22 | cprintf("I am the parent, waiting now..\n"); 23 | 24 | assert(waitpid(pid, &code) == 0 && code == magic); 25 | assert(waitpid(pid, &code) != 0 && wait() != 0); 26 | cprintf("waitpid %d ok.\n", pid); 27 | 28 | cprintf("exit pass.\n"); 29 | return 0; 30 | } 31 | 32 | -------------------------------------------------------------------------------- /code/user/faultread.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int 5 | main(void) { 6 | cprintf("I read %8x from 0.\n", *(unsigned int *)0); 7 | panic("FAIL: T.T\n"); 8 | } 9 | 10 | -------------------------------------------------------------------------------- /code/user/faultreadkernel.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int 5 | main(void) { 6 | cprintf("I read %08x from 0xfac00000!\n", *(unsigned *)0xfac00000); 7 | panic("FAIL: T.T\n"); 8 | } 9 | 10 | -------------------------------------------------------------------------------- /code/user/forktest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | const int max_child = 32; 5 | 6 | int 7 | main(void) { 8 | int n, pid; 9 | for (n = 0; n < max_child; n ++) { 10 | if ((pid = fork()) == 0) { 11 | cprintf("I am child %d\n", n); 12 | exit(0); 13 | } 14 | assert(pid > 0); 15 | } 16 | 17 | if (n > max_child) { 18 | panic("fork claimed to work %d times!\n", n); 19 | } 20 | 21 | for (; n > 0; n --) { 22 | if (wait() != 0) { 23 | panic("wait stopped early\n"); 24 | } 25 | } 26 | 27 | if (wait() == 0) { 28 | panic("wait got too many\n"); 29 | } 30 | 31 | cprintf("forktest pass.\n"); 32 | return 0; 33 | } 34 | 35 | -------------------------------------------------------------------------------- /code/user/forktree.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define DEPTH 4 6 | 7 | void forktree(const char *cur); 8 | 9 | void 10 | forkchild(const char *cur, char branch) { 11 | char nxt[DEPTH + 1]; 12 | 13 | if (strlen(cur) >= DEPTH) 14 | return; 15 | 16 | snprintf(nxt, DEPTH + 1, "%s%c", cur, branch); 17 | if (fork() == 0) { 18 | forktree(nxt); 19 | yield(); 20 | exit(0); 21 | } 22 | } 23 | 24 | void 25 | forktree(const char *cur) { 26 | cprintf("%04x: I am '%s'\n", getpid(), cur); 27 | 28 | forkchild(cur, '0'); 29 | forkchild(cur, '1'); 30 | } 31 | 32 | int 33 | main(void) { 34 | forktree(""); 35 | return 0; 36 | } 37 | 38 | -------------------------------------------------------------------------------- /code/user/fread_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int 7 | main(void) { 8 | /* type '^C' to stop reading */ 9 | char c; 10 | cprintf("now reading...\n"); 11 | do { 12 | int ret = read(0, &c, sizeof(c)); 13 | assert(ret == 1); 14 | cprintf("type [%03d] %c.\n", c, c); 15 | } while (c != 3); 16 | return 0; 17 | } 18 | 19 | -------------------------------------------------------------------------------- /code/user/fread_test2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int 7 | main(void) { 8 | int pid, ret; 9 | if ((pid = fork()) == 0) { 10 | do { 11 | char c; 12 | ret = read(0, &c, sizeof(c)); 13 | assert(ret == 1); 14 | } while (1); 15 | } 16 | assert(pid > 0); 17 | 18 | sleep(100); 19 | kill(pid); 20 | 21 | assert(waitpid(pid, &ret) == 0 && ret != 0); 22 | cprintf("fread_test2 pass.\n"); 23 | return 0; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /code/user/fwrite_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | static void 8 | testfd(const char *name, int fd) { 9 | struct stat __stat, *stat = &__stat; 10 | int ret = fstat(fd, stat); 11 | assert(ret == 0); 12 | print_stat(name, fd, stat); 13 | } 14 | 15 | int 16 | main(void) { 17 | int fd = dup(1); 18 | assert(fd >= 0); 19 | 20 | testfd("stdin", 0); 21 | testfd("stdout", 1); 22 | testfd("dup: stdout", fd); 23 | 24 | int size = 1024, len = 0; 25 | char buf[size]; 26 | len += snprintf(buf + len, size - len, "Hello world!!.\n"); 27 | len += snprintf(buf + len, size - len, "I am process %d.\n", getpid()); 28 | write(fd, buf, len); 29 | 30 | int ret; 31 | while ((ret = dup(fd)) >= 0) 32 | /* do nothing */; 33 | 34 | close(fd); 35 | len = snprintf(buf, size, "FAIL: T.T\n"); 36 | write(fd, buf, len); 37 | cprintf("dup fd ok.\n"); 38 | 39 | int pid; 40 | if ((pid = fork()) == 0) { 41 | sleep(10); 42 | len = snprintf(buf, size, "fork fd ok.\n"); 43 | ret = write(1, buf, len); 44 | assert(ret == len); 45 | exit(0); 46 | } 47 | assert(pid > 0); 48 | assert(waitpid(pid, &ret) == 0 && ret == 0); 49 | cprintf("fwrite_test pass.\n"); 50 | return 0; 51 | } 52 | 53 | -------------------------------------------------------------------------------- /code/user/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int 5 | main(void) { 6 | cprintf("Hello world!!.\n"); 7 | cprintf("I am process %d.\n", getpid()); 8 | cprintf("hello pass.\n"); 9 | return 0; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /code/user/hello2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int 5 | main(void) { 6 | fprintf(1, "Hello world!!.\n"); 7 | fprintf(1, "I am process %d.\n", getpid()); 8 | fprintf(1, "hello2 pass.\n"); 9 | return 0; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /code/user/libs/clone.S: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | .text 4 | .globl __clone 5 | __clone: # __clone(clone_flags, stack, fn, arg) 6 | pushl %ebp # maintain ebp chain 7 | movl %esp, %ebp 8 | 9 | pushl %edx # save old registers 10 | pushl %ecx 11 | pushl %ebx 12 | pushl %edi 13 | 14 | movl 0x8(%ebp), %edx # load clone_flags 15 | movl 0xc(%ebp), %ecx # load stack 16 | movl 0x10(%ebp), %ebx # load fn 17 | movl 0x14(%ebp), %edi # load arg 18 | 19 | movl $SYS_clone, %eax # load SYS_clone 20 | int $T_SYSCALL # syscall 21 | 22 | cmpl $0x0, %eax # pid ? child or parent ? 23 | je 1f # eax == 0, goto 1; 24 | 25 | # parent 26 | popl %edi # restore registers 27 | popl %ebx 28 | popl %ecx 29 | popl %edx 30 | 31 | leave # restore ebp 32 | ret 33 | 34 | # child 35 | 1: 36 | pushl %edi 37 | call *%ebx # call fn(arg) 38 | 39 | movl %eax, %edx # save exit_code 40 | movl $SYS_exit_thread, %eax # load SYS_exit_thread 41 | int $T_SYSCALL # int SYS_exit_thread 42 | 43 | spin: # error ? 44 | jmp spin 45 | 46 | -------------------------------------------------------------------------------- /code/user/libs/dir.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | DIR * 13 | opendir(const char *path) { 14 | DIR *dirp; 15 | if ((dirp = malloc(sizeof(DIR))) == NULL) { 16 | return NULL; 17 | } 18 | if ((dirp->fd = open(path, O_RDONLY)) < 0) { 19 | goto failed; 20 | } 21 | struct stat __stat, *stat = &__stat; 22 | if (fstat(dirp->fd, stat) != 0 || !S_ISDIR(stat->st_mode)) { 23 | goto failed; 24 | } 25 | dirp->dirent.offset = 0; 26 | return dirp; 27 | 28 | failed: 29 | free(dirp); 30 | return NULL; 31 | } 32 | 33 | struct dirent * 34 | readdir(DIR *dirp) { 35 | if (sys_getdirentry(dirp->fd, &(dirp->dirent)) == 0) { 36 | return &(dirp->dirent); 37 | } 38 | return NULL; 39 | } 40 | 41 | void 42 | closedir(DIR *dirp) { 43 | close(dirp->fd); 44 | free(dirp); 45 | } 46 | 47 | int 48 | chdir(const char *path) { 49 | return sys_chdir(path); 50 | } 51 | 52 | int 53 | getcwd(char *buffer, size_t len) { 54 | return sys_getcwd(buffer, len); 55 | } 56 | 57 | int 58 | mkdir(const char *path) { 59 | return sys_mkdir(path); 60 | } 61 | 62 | int 63 | link(const char *old_path, const char *new_path) { 64 | return sys_link(old_path, new_path); 65 | } 66 | 67 | int 68 | rename(const char *old_path, const char *new_path) { 69 | return sys_rename(old_path, new_path); 70 | } 71 | 72 | int 73 | unlink(const char *path) { 74 | return sys_unlink(path); 75 | } 76 | 77 | -------------------------------------------------------------------------------- /code/user/libs/dir.h: -------------------------------------------------------------------------------- 1 | #ifndef __USER_LIBS_DIR_H__ 2 | #define __USER_LIBS_DIR_H__ 3 | 4 | #include 5 | #include 6 | 7 | typedef struct { 8 | int fd; 9 | struct dirent dirent; 10 | } DIR; 11 | 12 | DIR *opendir(const char *path); 13 | struct dirent *readdir(DIR *dirp); 14 | void closedir(DIR *dirp); 15 | int chdir(const char *path); 16 | int getcwd(char *buffer, size_t len); 17 | int mkdir(const char *path); 18 | int link(const char *old_path, const char *new_path); 19 | int rename(const char *old_path, const char *new_path); 20 | int unlink(const char *path); 21 | 22 | #endif /* !__USER_LIBS_DIR_H__ */ 23 | 24 | -------------------------------------------------------------------------------- /code/user/libs/file.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int 11 | open(const char *path, uint32_t open_flags) { 12 | return sys_open(path, open_flags); 13 | } 14 | 15 | int 16 | close(int fd) { 17 | return sys_close(fd); 18 | } 19 | 20 | int 21 | read(int fd, void *base, size_t len) { 22 | return sys_read(fd, base, len); 23 | } 24 | 25 | int 26 | write(int fd, void *base, size_t len) { 27 | return sys_write(fd, base, len); 28 | } 29 | 30 | int 31 | seek(int fd, off_t pos, int whence) { 32 | return sys_seek(fd, pos, whence); 33 | } 34 | 35 | int 36 | fstat(int fd, struct stat *stat) { 37 | return sys_fstat(fd, stat); 38 | } 39 | 40 | int 41 | fsync(int fd) { 42 | return sys_fsync(fd); 43 | } 44 | 45 | int 46 | dup(int fd) { 47 | return sys_dup(fd, NO_FD); 48 | } 49 | 50 | int 51 | dup2(int fd1, int fd2) { 52 | return sys_dup(fd1, fd2); 53 | } 54 | 55 | int 56 | pipe(int *fd_store) { 57 | return sys_pipe(fd_store); 58 | } 59 | 60 | int 61 | mkfifo(const char *name, uint32_t open_flags) { 62 | return sys_mkfifo(name, open_flags); 63 | } 64 | 65 | static char 66 | transmode(struct stat *stat) { 67 | uint32_t mode = stat->st_mode; 68 | if (S_ISREG(mode)) return 'r'; 69 | if (S_ISDIR(mode)) return 'd'; 70 | if (S_ISLNK(mode)) return 'l'; 71 | if (S_ISCHR(mode)) return 'c'; 72 | if (S_ISBLK(mode)) return 'b'; 73 | return '-'; 74 | } 75 | 76 | void 77 | print_stat(const char *name, int fd, struct stat *stat) { 78 | cprintf("[%03d] %s\n", fd, name); 79 | cprintf(" mode : %c\n", transmode(stat)); 80 | cprintf(" links : %lu\n", stat->st_nlinks); 81 | cprintf(" blocks : %lu\n", stat->st_blocks); 82 | cprintf(" size : %lu\n", stat->st_size); 83 | } 84 | 85 | -------------------------------------------------------------------------------- /code/user/libs/file.h: -------------------------------------------------------------------------------- 1 | #ifndef __USER_LIBS_FILE_H__ 2 | #define __USER_LIBS_FILE_H__ 3 | 4 | #include 5 | 6 | struct stat; 7 | 8 | int open(const char *path, uint32_t open_flags); 9 | int close(int fd); 10 | int read(int fd, void *base, size_t len); 11 | int write(int fd, void *base, size_t len); 12 | int seek(int fd, off_t pos, int whence); 13 | int fstat(int fd, struct stat *stat); 14 | int fsync(int fd); 15 | int dup(int fd); 16 | int dup2(int fd1, int fd2); 17 | int pipe(int *fd_store); 18 | int mkfifo(const char *name, uint32_t open_flags); 19 | 20 | void print_stat(const char *name, int fd, struct stat *stat); 21 | 22 | #endif /* !__USER_LIBS_FILE_H__ */ 23 | 24 | -------------------------------------------------------------------------------- /code/user/libs/initcode.S: -------------------------------------------------------------------------------- 1 | .text 2 | .globl _start 3 | _start: 4 | # set ebp for backtrace 5 | movl $0x0, %ebp 6 | 7 | # load argc and argv 8 | movl (%esp), %ebx 9 | lea 0x4(%esp), %ecx 10 | 11 | # move down the esp register 12 | # since it may cause page fault in backtrace 13 | subl $0x20, %esp 14 | 15 | # save argc and argv on stack 16 | pushl %ecx 17 | pushl %ebx 18 | 19 | # call user-program function 20 | call umain 21 | 1: jmp 1b 22 | 23 | -------------------------------------------------------------------------------- /code/user/libs/lock.h: -------------------------------------------------------------------------------- 1 | #ifndef __USER_LIBS_LOCK_H__ 2 | #define __USER_LIBS_LOCK_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define INIT_LOCK {0} 9 | 10 | typedef volatile bool lock_t; 11 | 12 | static inline void 13 | lock_init(lock_t *l) { 14 | *l = 0; 15 | } 16 | 17 | static inline bool 18 | try_lock(lock_t *l) { 19 | return test_and_set_bit(0, l); 20 | } 21 | 22 | static inline void 23 | lock(lock_t *l) { 24 | if (try_lock(l)) { 25 | int step = 0; 26 | do { 27 | yield(); 28 | if (++ step == 100) { 29 | step = 0; 30 | sleep(10); 31 | } 32 | } while (try_lock(l)); 33 | } 34 | } 35 | 36 | static inline void 37 | unlock(lock_t *l) { 38 | test_and_clear_bit(0, l); 39 | } 40 | 41 | #endif /* !__USER_LIBS_LOCK_H__ */ 42 | 43 | -------------------------------------------------------------------------------- /code/user/libs/malloc.h: -------------------------------------------------------------------------------- 1 | #ifndef __USER_LIBS_MALLOC_H__ 2 | #define __USER_LIBS_MALLOC_H__ 3 | 4 | #include 5 | 6 | void *malloc(size_t size); 7 | void *shmem_malloc(size_t size); 8 | void free(void *ap); 9 | 10 | #endif /* !__USER_LIBS_MALLOC_H__ */ 11 | 12 | -------------------------------------------------------------------------------- /code/user/libs/panic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void 8 | __panic(const char *file, int line, const char *fmt, ...) { 9 | // print the 'message' 10 | va_list ap; 11 | va_start(ap, fmt); 12 | cprintf("user panic at %s:%d:\n ", file, line); 13 | vcprintf(fmt, ap); 14 | cprintf("\n"); 15 | va_end(ap); 16 | exit(-E_PANIC); 17 | } 18 | 19 | void 20 | __warn(const char *file, int line, const char *fmt, ...) { 21 | va_list ap; 22 | va_start(ap, fmt); 23 | cprintf("user warning at %s:%d:\n ", file, line); 24 | vcprintf(fmt, ap); 25 | cprintf("\n"); 26 | va_end(ap); 27 | } 28 | 29 | -------------------------------------------------------------------------------- /code/user/libs/spipe.h: -------------------------------------------------------------------------------- 1 | #ifndef __USER_LIBS_SPIPE_H__ 2 | #define __USER_LIBS_SPIPE_H__ 3 | 4 | #include 5 | 6 | typedef struct { 7 | off_t p_rpos; 8 | off_t p_wpos; 9 | bool isclosed; 10 | } __spipe_state_t; 11 | 12 | typedef struct { 13 | volatile bool isclosed; 14 | sem_t spipe_sem; 15 | uintptr_t addr; 16 | __spipe_state_t *state; 17 | uint8_t *buf; 18 | } spipe_t; 19 | 20 | int spipe(spipe_t *p); 21 | size_t spiperead(spipe_t *p, void *buf, size_t n); 22 | size_t spipewrite(spipe_t *p, void *buf, size_t n); 23 | int spipeclose(spipe_t *p); 24 | bool spipeisclosed(spipe_t *p); 25 | 26 | #endif /* !__USER_LIBS_SPIPE_H__ */ 27 | 28 | -------------------------------------------------------------------------------- /code/user/libs/stdio.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /* * 9 | * cputch - writes a single character @c to stdout, and it will 10 | * increace the value of counter pointed by @cnt. 11 | * */ 12 | static void 13 | cputch(int c, int *cnt) { 14 | sys_putc(c); 15 | (*cnt) ++; 16 | } 17 | 18 | /* * 19 | * vcprintf - format a string and writes it to stdout 20 | * 21 | * The return value is the number of characters which would be 22 | * written to stdout. 23 | * 24 | * Call this function if you are already dealing with a va_list. 25 | * Or you probably want cprintf() instead. 26 | * */ 27 | int 28 | vcprintf(const char *fmt, va_list ap) { 29 | int cnt = 0; 30 | vprintfmt((void*)cputch, NO_FD, &cnt, fmt, ap); 31 | return cnt; 32 | } 33 | 34 | /* * 35 | * cprintf - formats a string and writes it to stdout 36 | * 37 | * The return value is the number of characters which would be 38 | * written to stdout. 39 | * */ 40 | int 41 | cprintf(const char *fmt, ...) { 42 | va_list ap; 43 | 44 | va_start(ap, fmt); 45 | int cnt = vcprintf(fmt, ap); 46 | va_end(ap); 47 | 48 | return cnt; 49 | } 50 | 51 | /* * 52 | * cputs- writes the string pointed by @str to stdout and 53 | * appends a newline character. 54 | * */ 55 | int 56 | cputs(const char *str) { 57 | int cnt = 0; 58 | char c; 59 | while ((c = *str ++) != '\0') { 60 | cputch(c, &cnt); 61 | } 62 | cputch('\n', &cnt); 63 | return cnt; 64 | } 65 | 66 | static void 67 | fputch(char c, int *cnt, int fd) { 68 | write(fd, &c, sizeof(char)); 69 | (*cnt) ++; 70 | } 71 | 72 | int 73 | vfprintf(int fd, const char *fmt, va_list ap) { 74 | int cnt = 0; 75 | vprintfmt((void*)fputch, fd, &cnt, fmt, ap); 76 | return cnt; 77 | } 78 | 79 | int 80 | fprintf(int fd, const char *fmt, ...) { 81 | va_list ap; 82 | 83 | va_start(ap, fmt); 84 | int cnt = vfprintf(fd, fmt, ap); 85 | va_end(ap); 86 | 87 | return cnt; 88 | } 89 | 90 | -------------------------------------------------------------------------------- /code/user/libs/string.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | char * 5 | strdup(const char *src) { 6 | char *dst; 7 | size_t len = strlen(src) + 1; 8 | if ((dst = malloc(len)) != NULL) { 9 | memcpy(dst, src, len); 10 | } 11 | return dst; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /code/user/libs/syscall.h: -------------------------------------------------------------------------------- 1 | #ifndef __USER_LIBS_SYSCALL_H__ 2 | #define __USER_LIBS_SYSCALL_H__ 3 | 4 | #include 5 | 6 | int sys_exit(int error_code); 7 | int sys_fork(void); 8 | int sys_wait(int pid, int *store); 9 | int sys_exec(const char *name, int argc, const char **argv); 10 | int sys_yield(void); 11 | int sys_sleep(unsigned int time); 12 | int sys_kill(int pid); 13 | size_t sys_gettime(void); 14 | int sys_getpid(void); 15 | int sys_brk(uintptr_t *brk_store); 16 | int sys_mmap(uintptr_t *addr_store, size_t len, uint32_t mmap_flags); 17 | int sys_munmap(uintptr_t addr, size_t len); 18 | int sys_shmem(uintptr_t *addr_store, size_t len, uint32_t mmap_flags); 19 | int sys_putc(int c); 20 | int sys_pgdir(void); 21 | sem_t sys_sem_init(int value); 22 | int sys_sem_post(sem_t sem_id); 23 | int sys_sem_wait(sem_t sem_id, unsigned int timeout); 24 | int sys_sem_free(sem_t sem_id); 25 | int sys_sem_get_value(sem_t sem_id, int *value_store); 26 | int sys_send_event(int pid, int event, unsigned int timeout); 27 | int sys_recv_event(int *pid_store, int *event_store, unsigned int timeout); 28 | 29 | struct mboxbuf; 30 | struct mboxinfo; 31 | 32 | int sys_mbox_init(unsigned int max_slots); 33 | int sys_mbox_send(int id, struct mboxbuf *buf, unsigned int timeout); 34 | int sys_mbox_recv(int id, struct mboxbuf *buf, unsigned int timeout); 35 | int sys_mbox_free(int id); 36 | int sys_mbox_info(int id, struct mboxinfo *info); 37 | 38 | struct stat; 39 | struct dirent; 40 | 41 | int sys_open(const char *path, uint32_t open_flags); 42 | int sys_close(int fd); 43 | int sys_read(int fd, void *base, size_t len); 44 | int sys_write(int fd, void *base, size_t len); 45 | int sys_seek(int fd, off_t pos, int whence); 46 | int sys_fstat(int fd, struct stat *stat); 47 | int sys_fsync(int fd); 48 | int sys_chdir(const char *path); 49 | int sys_getcwd(char *buffer, size_t len); 50 | int sys_mkdir(const char *path); 51 | int sys_link(const char *path1, const char *path2); 52 | int sys_rename(const char *path1, const char *path2); 53 | int sys_unlink(const char *path); 54 | int sys_getdirentry(int fd, struct dirent *dirent); 55 | int sys_dup(int fd1, int fd2); 56 | int sys_pipe(int *fd_store); 57 | int sys_mkfifo(const char *name, uint32_t open_flags); 58 | 59 | #endif /* !__USER_LIBS_SYSCALL_H__ */ 60 | 61 | -------------------------------------------------------------------------------- /code/user/libs/thread.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int 8 | thread(int (*fn)(void *), void *arg, thread_t *tidp) { 9 | if (fn == NULL || tidp == NULL) { 10 | return -E_INVAL; 11 | } 12 | int ret; 13 | uintptr_t stack = 0; 14 | if ((ret = mmap(&stack, THREAD_STACKSIZE, MMAP_WRITE | MMAP_STACK)) != 0) { 15 | return ret; 16 | } 17 | assert(stack != 0); 18 | 19 | if ((ret = clone(CLONE_VM | CLONE_THREAD | CLONE_SEM | CLONE_FS, stack + THREAD_STACKSIZE, fn, arg)) < 0) { 20 | munmap(stack, THREAD_STACKSIZE); 21 | return ret; 22 | } 23 | 24 | tidp->pid = ret; 25 | tidp->stack = (void *)stack; 26 | return 0; 27 | } 28 | 29 | int 30 | thread_wait(thread_t *tidp, int *exit_code) { 31 | int ret = -E_INVAL; 32 | if (tidp != NULL) { 33 | if ((ret = waitpid(tidp->pid, exit_code)) == 0) { 34 | munmap((uintptr_t)(tidp->stack), THREAD_STACKSIZE); 35 | } 36 | } 37 | return ret; 38 | } 39 | 40 | int 41 | thread_kill(thread_t *tidp) { 42 | if (tidp != NULL) { 43 | return kill(tidp->pid); 44 | } 45 | return -E_INVAL; 46 | } 47 | 48 | -------------------------------------------------------------------------------- /code/user/libs/thread.h: -------------------------------------------------------------------------------- 1 | #ifndef __USER_LIBS_THREAD_H__ 2 | #define __USER_LIBS_THREAD_H__ 3 | 4 | typedef struct { 5 | int pid; 6 | void *stack; 7 | } thread_t; 8 | 9 | #define THREAD_STACKSIZE (4096 * 10) 10 | 11 | int thread(int (*fn)(void *), void *arg, thread_t *tidp); 12 | int thread_wait(thread_t *tidp, int *exit_code); 13 | int thread_kill(thread_t *tidp); 14 | 15 | #endif /* !__USER_LIBS_THREAD_H__ */ 16 | 17 | -------------------------------------------------------------------------------- /code/user/libs/ulib.h: -------------------------------------------------------------------------------- 1 | #ifndef __USER_LIBS_ULIB_H__ 2 | #define __USER_LIBS_ULIB_H__ 3 | 4 | #include 5 | 6 | void __warn(const char *file, int line, const char *fmt, ...); 7 | void __panic(const char *file, int line, const char *fmt, ...) __attribute__((noreturn)); 8 | 9 | #define warn(...) \ 10 | __warn(__FILE__, __LINE__, __VA_ARGS__) 11 | 12 | #define panic(...) \ 13 | __panic(__FILE__, __LINE__, __VA_ARGS__) 14 | 15 | #define assert(x) \ 16 | do { \ 17 | if (!(x)) { \ 18 | panic("assertion failed: %s", #x); \ 19 | } \ 20 | } while (0) 21 | 22 | // static_assert(x) will generate a compile-time error if 'x' is false. 23 | #define static_assert(x) \ 24 | switch (x) { case 0: case (x): ; } 25 | 26 | int fprintf(int fd, const char *fmt, ...); 27 | 28 | void exit(int error_code) __attribute__((noreturn)); 29 | int fork(void); 30 | int forks(void); 31 | int wait(void); 32 | int waitpid(int pid, int *store); 33 | void yield(void); 34 | int sleep(unsigned int time); 35 | int kill(int pid); 36 | unsigned int gettime_msec(void); 37 | int getpid(void); 38 | void print_pgdir(void); 39 | int mmap(uintptr_t *addr_store, size_t len, uint32_t mmap_flags); 40 | int munmap(uintptr_t addr, size_t len); 41 | int shmem(uintptr_t *addr_store, size_t len, uint32_t mmap_flags); 42 | int clone(uint32_t clone_flags, uintptr_t stack, int (*fn)(void *), void *arg); 43 | sem_t sem_init(int value); 44 | int sem_post(sem_t sem_id); 45 | int sem_wait(sem_t sem_id); 46 | int sem_wait_timeout(sem_t sem_id, unsigned int timeout); 47 | int sem_free(sem_t sem_id); 48 | int sem_get_value(sem_t sem_id, int *value_store); 49 | int send_event(int pid, int event); 50 | int send_event_timeout(int pid, int event, unsigned int timeout); 51 | int recv_event(int *pid_store, int *event_store); 52 | int recv_event_timeout(int *pid_store, int *event_store, unsigned int timeout); 53 | 54 | struct mboxbuf; 55 | struct mboxinfo; 56 | 57 | int mbox_init(unsigned int max_slots); 58 | int mbox_send(int id, struct mboxbuf *buf); 59 | int mbox_send_timeout(int id, struct mboxbuf *buf, unsigned int timeout); 60 | int mbox_recv(int id, struct mboxbuf *buf); 61 | int mbox_recv_timeout(int id, struct mboxbuf *buf, unsigned int timeout); 62 | int mbox_free(int id); 63 | int mbox_info(int id, struct mboxinfo *info); 64 | 65 | int __exec(const char *name, const char **argv); 66 | 67 | #define __exec0(name, path, ...) \ 68 | ({ const char *argv[] = {path, ##__VA_ARGS__, NULL}; __exec(name, argv); }) 69 | 70 | #define exec(path, ...) __exec0(NULL, path, ##__VA_ARGS__) 71 | #define nexec(name, path, ...) __exec0(name, path, ##__VA_ARGS__) 72 | 73 | #endif /* !__USER_LIBS_ULIB_H__ */ 74 | 75 | -------------------------------------------------------------------------------- /code/user/libs/umain.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char **argv); 7 | 8 | static int 9 | initfd(int fd2, const char *path, uint32_t open_flags) { 10 | struct stat __stat, *stat = &__stat; 11 | int ret, fd1; 12 | if ((ret = fstat(fd2, stat)) != 0) { 13 | if ((fd1 = open(path, open_flags)) < 0 || fd1 == fd2) { 14 | return fd1; 15 | } 16 | close(fd2); 17 | ret = dup2(fd1, fd2); 18 | close(fd1); 19 | } 20 | return ret; 21 | } 22 | 23 | void 24 | umain(int argc, char **argv) { 25 | int fd; 26 | if ((fd = initfd(0, "stdin:", O_RDONLY)) < 0) { 27 | warn("open failed: %e.\n", fd); 28 | } 29 | if ((fd = initfd(1, "stdout:", O_WRONLY)) < 0) { 30 | warn("open failed: %e.\n", fd); 31 | } 32 | int ret = main(argc, argv); 33 | exit(ret); 34 | } 35 | 36 | -------------------------------------------------------------------------------- /code/user/link.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define printf(...) fprintf(1, __VA_ARGS__) 6 | 7 | void 8 | usage(void) { 9 | printf("usage: link file1 file2\n"); 10 | } 11 | 12 | int 13 | main(int argc, char **argv) { 14 | if (argc != 3) { 15 | usage(); 16 | return -1; 17 | } 18 | return link(argv[1], argv[2]); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /code/user/ls.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define printf(...) fprintf(1, __VA_ARGS__) 11 | #define BUFSIZE 4096 12 | 13 | static char 14 | getmode(uint32_t st_mode) { 15 | char mode = '?'; 16 | if (S_ISREG(st_mode)) mode = '-'; 17 | if (S_ISDIR(st_mode)) mode = 'd'; 18 | if (S_ISLNK(st_mode)) mode = 'l'; 19 | if (S_ISCHR(st_mode)) mode = 'c'; 20 | if (S_ISBLK(st_mode)) mode = 'b'; 21 | return mode; 22 | } 23 | 24 | static int 25 | getstat(const char *name, struct stat *stat) { 26 | int fd, ret; 27 | if ((fd = open(name, O_RDONLY)) < 0) { 28 | return fd; 29 | } 30 | ret = fstat(fd, stat); 31 | close(fd); 32 | return ret; 33 | } 34 | 35 | void 36 | lsstat(struct stat *stat, const char *filename) { 37 | printf(" [%c]", getmode(stat->st_mode)); 38 | printf(" %3d(h)", stat->st_nlinks); 39 | printf(" %8d(b)", stat->st_blocks); 40 | printf(" %8d(s)", stat->st_size); 41 | printf(" %s\n", filename); 42 | } 43 | 44 | int 45 | lsdir(const char *path) { 46 | struct stat __stat, *stat = &__stat; 47 | static char cwdbuf[BUFSIZE]; 48 | int ret; 49 | if ((ret = getcwd(cwdbuf, BUFSIZE)) != 0) { 50 | return ret; 51 | } 52 | if ((ret = chdir(path)) != 0) { 53 | return ret; 54 | } 55 | DIR *dirp = opendir("."); 56 | if (dirp == NULL) { 57 | return -1; 58 | } 59 | struct dirent *direntp; 60 | while ((direntp = readdir(dirp)) != NULL) { 61 | if ((ret = getstat(direntp->name, stat)) != 0) { 62 | goto failed; 63 | } 64 | lsstat(stat, direntp->name); 65 | } 66 | closedir(dirp); 67 | return chdir(cwdbuf); 68 | 69 | failed: 70 | closedir(dirp); 71 | chdir(cwdbuf); 72 | return ret; 73 | } 74 | 75 | int 76 | ls(const char *path) { 77 | struct stat __stat, *stat = &__stat; 78 | int ret, type; 79 | if ((ret = getstat(path, stat)) != 0) { 80 | return ret; 81 | } 82 | 83 | static const char *filetype[] = { 84 | " [ file ]", 85 | " [directory]", 86 | " [ symlink ]", 87 | " [character]", 88 | " [ block ]", 89 | " [ ????? ]", 90 | }; 91 | switch (getmode(stat->st_mode)) { 92 | case '0': type = 0; break; 93 | case 'd': type = 1; break; 94 | case 'l': type = 2; break; 95 | case 'c': type = 3; break; 96 | case 'b': type = 4; break; 97 | default: type = 5; break; 98 | } 99 | 100 | printf(" @ is %s", filetype[type]); 101 | printf(" %d(hlinks)", stat->st_nlinks); 102 | printf(" %d(blocks)", stat->st_blocks); 103 | printf(" %d(bytes) : @'%s'\n", stat->st_size, path); 104 | if (S_ISDIR(stat->st_mode)) { 105 | return lsdir(path); 106 | } 107 | return 0; 108 | } 109 | 110 | int 111 | main(int argc, char **argv) { 112 | if (argc == 1) { 113 | return ls("."); 114 | } 115 | else { 116 | int i, ret; 117 | for (i = 1; i < argc; i ++) { 118 | if ((ret = ls(argv[i])) != 0) { 119 | return ret; 120 | } 121 | } 122 | } 123 | return 0; 124 | } 125 | 126 | -------------------------------------------------------------------------------- /code/user/matrix.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define MATSIZE 10 7 | 8 | static int mata[MATSIZE][MATSIZE]; 9 | static int matb[MATSIZE][MATSIZE]; 10 | static int matc[MATSIZE][MATSIZE]; 11 | 12 | void 13 | work(unsigned int times) { 14 | int i, j, k, size = MATSIZE; 15 | for (i = 0; i < size; i ++) { 16 | for (j = 0; j < size; j ++) { 17 | mata[i][j] = matb[i][j] = 1; 18 | } 19 | } 20 | 21 | yield(); 22 | 23 | cprintf("pid %d is running (%d times)!.\n", getpid(), times); 24 | 25 | while (times -- > 0) { 26 | for (i = 0; i < size; i ++) { 27 | for (j = 0; j < size; j ++) { 28 | matc[i][j] = 0; 29 | for (k = 0; k < size; k ++) { 30 | matc[i][j] += mata[i][k] * matb[k][j]; 31 | } 32 | } 33 | } 34 | for (i = 0; i < size; i ++) { 35 | for (j = 0; j < size; j ++) { 36 | mata[i][j] = matb[i][j] = matc[i][j]; 37 | } 38 | } 39 | } 40 | cprintf("pid %d done!.\n", getpid()); 41 | exit(0); 42 | } 43 | 44 | const int total = 20; 45 | 46 | int 47 | main(void) { 48 | int pids[total]; 49 | memset(pids, 0, sizeof(pids)); 50 | 51 | int i; 52 | for (i = 0; i < total; i ++) { 53 | if ((pids[i] = fork()) == 0) { 54 | srand(i * i); 55 | int times = (((unsigned int)rand()) % total); 56 | times = (times * times + 10) * 100; 57 | work(times); 58 | } 59 | if (pids[i] < 0) { 60 | goto failed; 61 | } 62 | } 63 | 64 | cprintf("fork ok.\n"); 65 | 66 | for (i = 0; i < total; i ++) { 67 | if (wait() != 0) { 68 | cprintf("wait failed.\n"); 69 | goto failed; 70 | } 71 | } 72 | 73 | cprintf("matrix pass.\n"); 74 | return 0; 75 | 76 | failed: 77 | for (i = 0; i < total; i ++) { 78 | if (pids[i] > 0) { 79 | kill(pids[i]); 80 | } 81 | } 82 | panic("FAIL: T.T\n"); 83 | } 84 | 85 | -------------------------------------------------------------------------------- /code/user/mboxtest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | const int mbox_slots = 128; 9 | 10 | void 11 | mbox_test(void) { 12 | int mbox_id = mbox_init(1); 13 | assert(mbox_id >= 0); 14 | 15 | struct mboxbuf __buf, *buf = &__buf; 16 | buf->size = 4096; 17 | buf->len = buf->size; 18 | buf->data = (void *)0xF0000000; 19 | assert(mbox_send(mbox_id, buf) < 0); 20 | 21 | buf->data = malloc(sizeof(char) * buf->size); 22 | assert(buf->data != NULL); 23 | 24 | char *data = (char *)(buf->data); 25 | int i; 26 | for (i = 0; i < buf->size; i ++) { 27 | data[i] = (char)i; 28 | } 29 | buf->len = buf->size; 30 | 31 | unsigned int timeout = 100, saved_msec = gettime_msec(); 32 | 33 | assert(mbox_send(mbox_id, buf) == 0); 34 | assert(mbox_send_timeout(mbox_id, buf, timeout) == -E_TIMEOUT); 35 | assert((unsigned int)(gettime_msec() - saved_msec) >= timeout); 36 | 37 | size_t saved_size = buf->size; 38 | buf->size = 100; 39 | assert(mbox_recv(mbox_id, buf) != 0); 40 | 41 | buf->size = saved_size - 1; 42 | assert(mbox_recv(mbox_id, buf) != 0); 43 | 44 | buf->size = saved_size; 45 | memset(buf->data, 0, sizeof(char) * buf->size); 46 | assert(mbox_recv(mbox_id, buf) == 0); 47 | 48 | assert(buf->size == saved_size && buf->len == saved_size); 49 | data = (char *)(buf->data); 50 | for (i = 0; i < buf->size; i ++) { 51 | assert(data[i] == (char)i); 52 | } 53 | 54 | saved_msec = gettime_msec(); 55 | assert(mbox_recv_timeout(mbox_id, buf, timeout) == -E_TIMEOUT); 56 | assert((unsigned int)(gettime_msec() - saved_msec) >= timeout); 57 | 58 | assert(mbox_free(mbox_id) == 0); 59 | assert(mbox_send(mbox_id, buf) != 0); 60 | 61 | exit(0); 62 | } 63 | 64 | int 65 | main(void) { 66 | int pid, ret; 67 | if ((pid = fork()) == 0) { 68 | mbox_test(); 69 | } 70 | assert(pid > 0 && waitpid(pid, &ret) == 0 && ret == 0); 71 | cprintf("mboxtest pass.\n"); 72 | return 0; 73 | } 74 | 75 | -------------------------------------------------------------------------------- /code/user/mkdir.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define printf(...) fprintf(1, __VA_ARGS__) 6 | 7 | void 8 | usage(void) { 9 | printf("usage: mkdir dir [...]\n"); 10 | } 11 | 12 | int 13 | main(int argc, char **argv) { 14 | if (argc == 1) { 15 | usage(); 16 | return -1; 17 | } 18 | else { 19 | int i, ret; 20 | for (i = 1; i < argc; i ++) { 21 | if ((ret = mkdir(argv[i])) != 0) { 22 | return ret; 23 | } 24 | } 25 | } 26 | return 0; 27 | } 28 | 29 | -------------------------------------------------------------------------------- /code/user/mmaptest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int 6 | main(void) { 7 | const int size = 4096; 8 | void *mapped[10] = {0}; 9 | 10 | uintptr_t addr; 11 | 12 | assert(mmap(NULL, size, 0) != 0 && mmap((void *)0xC0000000, size, 0) != 0); 13 | 14 | int i; 15 | for (i = 0; i < 10; i ++) { 16 | assert(mmap(&addr, size, MMAP_WRITE) == 0 && addr != 0); 17 | mapped[i] = (void *)addr, addr = 0; 18 | } 19 | cprintf("mmap step1 ok.\n"); 20 | 21 | for (i = 0; i < 10; i ++) { 22 | assert(munmap((uintptr_t)mapped[i], size) == 0); 23 | } 24 | 25 | cprintf("munmap step1 ok.\n"); 26 | 27 | addr = 0x80000000; 28 | assert(mmap(&addr, size, MMAP_WRITE) == 0); 29 | mapped[0] = (void *)addr; 30 | 31 | addr = 0x80001000; 32 | assert(mmap(&addr, size, MMAP_WRITE) == 0); 33 | mapped[1] = (void *)addr; 34 | 35 | cprintf("mmap step2 ok.\n"); 36 | 37 | addr = 0x80001800; 38 | assert(mmap(&addr, 100, 0) != 0); 39 | 40 | cprintf("mmap step3 ok.\n"); 41 | 42 | assert(munmap((uintptr_t)mapped[0], size * 2 + 100) == 0); 43 | 44 | cprintf("mumap step2 ok.\n"); 45 | 46 | addr = 0; 47 | assert(mmap(&addr, 128, MMAP_WRITE) == 0 && addr != 0); 48 | mapped[0] = (void *)addr; 49 | 50 | char *buffer = mapped[0]; 51 | for (i = 0; i < 128; i ++) { 52 | buffer[i] = (char)(i * i); 53 | } 54 | 55 | for (i = 0; i < 128; i ++) { 56 | assert(buffer[i] == (char)(i * i)); 57 | } 58 | 59 | cprintf("mmaptest pass.\n"); 60 | return 0; 61 | } 62 | 63 | -------------------------------------------------------------------------------- /code/user/nulldevfs_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | int 9 | main(void) { 10 | int fd=0,ret; 11 | char buf[5]; 12 | buf[0]=buf[1]=buf[2]=buf[3]='a';buf[4]='\n'; 13 | fd=open("null:",O_RDWR); 14 | cprintf("NULL fd is %d\n",fd); 15 | ret=write(fd,"hello",5); 16 | cprintf("write %d to NULL\n",ret); 17 | ret=read(fd,buf,5); 18 | cprintf("read %d from NULL, buf is %s\n",ret,buf); 19 | 20 | fprintf(1, "Hello world!!.\n"); 21 | fprintf(1, "I am process %d.\n", getpid()); 22 | fprintf(1, "hello2 pass.\n"); 23 | return 0; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /code/user/pgdir.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int 5 | main(void) { 6 | cprintf("I am %d, print pgdir.\n", getpid()); 7 | print_pgdir(); 8 | cprintf("pgdir pass.\n"); 9 | return 0; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /code/user/pipetest2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int __fd[2], fd; 11 | 12 | thread_t tids[10]; 13 | int total = sizeof(tids) / sizeof(tids[0]); 14 | 15 | int 16 | thread_main(void *arg) { 17 | int id = (long)arg; 18 | cprintf("this is %d\n", id); 19 | 20 | size_t n = 10000; 21 | char *buf = malloc(sizeof(char) * n); 22 | if (buf == NULL) { 23 | return -1; 24 | } 25 | 26 | memset(buf, (char)id, n); 27 | 28 | int i, rounds = 20, ret; 29 | for (i = 0; i < rounds; i ++) { 30 | if ((ret = write(fd, buf, n)) < 0 || ret != n) { 31 | cprintf("pipe is closed, too early.\n"); 32 | return -1; 33 | } 34 | if (id == 0) { 35 | cprintf("send %d/%d\n", i, rounds); 36 | } 37 | } 38 | return 0; 39 | } 40 | 41 | void 42 | process_main(void) { 43 | int counts[total], i, ret; 44 | for (i = 0; i < total; i ++) { 45 | counts[i] = 0; 46 | } 47 | 48 | char buf[128]; 49 | size_t n = sizeof(buf); 50 | 51 | while (1) { 52 | if ((ret = read(fd, buf, n)) <= 0) { 53 | break; 54 | } 55 | for (i = 0; i < ret; i ++) { 56 | counts[((unsigned int)buf[i]) % total] ++; 57 | } 58 | } 59 | for (i = 0; i < total; i ++) { 60 | cprintf("%d reads %d\n", i, counts[i]); 61 | } 62 | exit(0); 63 | } 64 | 65 | int 66 | main(void) { 67 | int pid, i; 68 | assert(pipe(__fd) == 0); 69 | 70 | if ((pid = fork()) == 0) { 71 | fd = __fd[0], close(__fd[1]); 72 | process_main(); 73 | } 74 | assert(pid > 0); 75 | 76 | fd = __fd[1], close(__fd[0]); 77 | memset(tids, 0, sizeof(thread_t) * total); 78 | for (i = 0; i < total; i ++) { 79 | if (thread(thread_main, (void *)(long)i, tids + i) != 0) { 80 | goto failed; 81 | } 82 | } 83 | 84 | int exit_code; 85 | for (i = 0; i < total; i ++) { 86 | if (thread_wait(tids + i, &exit_code) != 0 || exit_code != 0) { 87 | goto failed; 88 | } 89 | } 90 | 91 | for (i = 0; i < total; i ++) { 92 | yield(); 93 | } 94 | 95 | close(__fd[0]), close(__fd[1]); 96 | assert(waitpid(pid, &exit_code) == 0 && exit_code == 0); 97 | cprintf("pipetest2 pass.\n"); 98 | return 0; 99 | 100 | failed: 101 | for (i = 0; i < total; i ++) { 102 | if (tids[i].pid > 0) { 103 | kill(tids[i].pid); 104 | } 105 | } 106 | kill(pid); 107 | panic("FAIL: T.T\n"); 108 | } 109 | 110 | -------------------------------------------------------------------------------- /code/user/primer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int total = 1000; 8 | 9 | int *note; 10 | lock_t *locks; 11 | 12 | static void * 13 | safe_shmem_malloc(size_t size) { 14 | void *ret; 15 | if ((ret = shmem_malloc(size)) == NULL) { 16 | exit(-0xdead); 17 | } 18 | return ret; 19 | } 20 | 21 | static int 22 | read(int index) { 23 | lock_t *l = locks + index; 24 | int ret; 25 | try_again: 26 | lock(l); 27 | if ((ret = note[index]) > 0) { 28 | note[index] = 0; 29 | } 30 | unlock(l); 31 | if (ret == 0) { 32 | yield(); 33 | goto try_again; 34 | } 35 | return ret; 36 | } 37 | 38 | static int 39 | write(int index, int val, bool force) { 40 | lock_t *l = locks + index; 41 | int ret; 42 | try_again: 43 | lock(l); 44 | if ((ret = note[index]) >= 0) { 45 | if (ret == 0 || force) { 46 | note[index] = val; 47 | } 48 | } 49 | unlock(l); 50 | if (ret > 0 && !force) { 51 | yield(); 52 | goto try_again; 53 | } 54 | return (ret > 0) ? 0 : ret; 55 | } 56 | 57 | void 58 | primeproc(void) { 59 | int index = 0, this, num, pid = 0; 60 | top: 61 | this = read(index); 62 | cprintf("%d is a primer.\n", this); 63 | 64 | while ((num = read(index)) > 0) { 65 | if ((num % this) == 0) { 66 | continue ; 67 | } 68 | if (pid == 0) { 69 | if (index + 1 == total || (pid = fork()) < 0) { 70 | goto out; 71 | } 72 | if (pid == 0) { 73 | index ++; 74 | goto top; 75 | } 76 | } 77 | if (write(index + 1, num, 0) != 0) { 78 | goto out; 79 | } 80 | } 81 | 82 | out: 83 | cprintf("[%04d] %d quit.\n", getpid(), index); 84 | write(index, -1, 1); 85 | } 86 | 87 | int 88 | main(void) { 89 | note = safe_shmem_malloc(total * sizeof(int)); 90 | locks = safe_shmem_malloc(total * sizeof(lock_t)); 91 | 92 | int i, pid; 93 | for (i = 0; i < total; i ++) { 94 | note[i] = 0; 95 | lock_init(locks + i); 96 | } 97 | 98 | cprintf("sharemem init ok.\n"); 99 | 100 | unsigned int time = gettime_msec(); 101 | 102 | if ((pid = fork()) == 0) { 103 | primeproc(); 104 | exit(0); 105 | } 106 | assert(pid > 0); 107 | 108 | for (i = 2; ; i ++) { 109 | if (write(0, i, 0) != 0) { 110 | break; 111 | } 112 | } 113 | 114 | cprintf("use %d msecs.\n", gettime_msec() - time); 115 | cprintf("primer pass.\n"); 116 | return 0; 117 | } 118 | 119 | -------------------------------------------------------------------------------- /code/user/primer2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | const int total = 1000; 8 | int *note; 9 | 10 | void * 11 | safe_shmem_malloc(size_t size) { 12 | void *ret; 13 | if ((ret = shmem_malloc(size)) == NULL) { 14 | exit(-0xdead); 15 | } 16 | return ret; 17 | } 18 | 19 | int 20 | __read(int index, sem_t sem[]) { 21 | int ret; 22 | if (sem_wait(sem[0]) != 0) { 23 | return -1; 24 | } 25 | ret = note[index]; 26 | if (sem_post(sem[1]) != 0) { 27 | return -1; 28 | } 29 | return ret; 30 | } 31 | 32 | int 33 | __write(int index, sem_t sem[], int val) { 34 | int ret; 35 | if (sem_wait(sem[1]) != 0) { 36 | return -1; 37 | } 38 | ret = note[index], note[index] = val; 39 | if (sem_post(sem[0]) != 0) { 40 | return -1; 41 | } 42 | return (ret >= 0) ? 0 : -1; 43 | } 44 | 45 | void 46 | read_and_quit(int index, sem_t sem[]) { 47 | sem_wait(sem[0]); 48 | note[index] = -1; 49 | sem_post(sem[1]); 50 | } 51 | 52 | void 53 | primeproc(sem_t sem[]) { 54 | int index = 0, this, num, pid = 0; 55 | sem_t next_sem[2]; 56 | top: 57 | this = __read(index, sem); 58 | cprintf("%d is a primer.\n", this); 59 | 60 | while ((num = __read(index, sem)) > 0) { 61 | if ((num % this) == 0) { 62 | continue ; 63 | } 64 | if (pid == 0) { 65 | if (index + 1 == total) { 66 | goto out; 67 | } 68 | if ((next_sem[0] = sem_init(0)) < 0 || (next_sem[1] = sem_init(1)) < 0) { 69 | goto out; 70 | } 71 | if ((pid = fork()) == 0) { 72 | sem[0] = next_sem[0]; 73 | sem[1] = next_sem[1]; 74 | index ++; 75 | goto top; 76 | } 77 | if (pid < 0) { 78 | goto out; 79 | } 80 | } 81 | if (__write(index + 1, next_sem, num) != 0) { 82 | goto out; 83 | } 84 | } 85 | 86 | out: 87 | cprintf("[%04d] %d quit.\n", getpid(), index); 88 | read_and_quit(index, sem); 89 | } 90 | 91 | int 92 | main(void) { 93 | note = safe_shmem_malloc(total * sizeof(int)); 94 | memset(note, 0, sizeof(int) * total); 95 | cprintf("sharemem init ok.\n"); 96 | 97 | sem_t sem[2]; 98 | assert((sem[0] = sem_init(0)) > 0 && (sem[1] = sem_init(1)) > 0); 99 | 100 | unsigned int time = gettime_msec(); 101 | 102 | int pid; 103 | if ((pid = fork()) == 0) { 104 | primeproc(sem); 105 | exit(0); 106 | } 107 | assert(pid > 0); 108 | 109 | int i; 110 | for (i = 2; ; i ++) { 111 | if (__write(0, sem, i) != 0) { 112 | break; 113 | } 114 | } 115 | 116 | cprintf("use %d msecs.\n", gettime_msec() - time); 117 | cprintf("primer2 pass.\n"); 118 | return 0; 119 | } 120 | 121 | -------------------------------------------------------------------------------- /code/user/primer3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | const int total = 1000; 7 | 8 | void 9 | primeproc(void) { 10 | int index = 0, this, num, pid = 0; 11 | top: 12 | recv_event(NULL, &this); 13 | cprintf("%d is a primer.\n", this); 14 | 15 | while (recv_event(NULL, &num) == 0) { 16 | if ((num % this) == 0) { 17 | continue ; 18 | } 19 | if (pid == 0) { 20 | if (index + 1 == total) { 21 | goto out; 22 | } 23 | if ((pid = fork()) == 0) { 24 | index ++; 25 | goto top; 26 | } 27 | if (pid < 0) { 28 | goto out; 29 | } 30 | } 31 | if (send_event(pid, num) != 0) { 32 | goto out; 33 | } 34 | } 35 | out: 36 | cprintf("[%04d] %d quit.\n", getpid(), index); 37 | } 38 | 39 | int 40 | main(void) { 41 | int i, pid; 42 | unsigned int time = gettime_msec(); 43 | if ((pid = fork()) == 0) { 44 | primeproc(); 45 | exit(0); 46 | } 47 | assert(pid > 0); 48 | 49 | for (i = 2; ; i ++) { 50 | if (send_event(pid, i) != 0) { 51 | break; 52 | } 53 | } 54 | cprintf("use %d msecs.\n", gettime_msec() - time); 55 | cprintf("primer3 pass.\n"); 56 | return 0; 57 | } 58 | 59 | -------------------------------------------------------------------------------- /code/user/pwd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define printf(...) fprintf(1, __VA_ARGS__) 6 | #define BUFSIZE 4096 7 | 8 | int 9 | main(int argc, char **argv) { 10 | int ret; 11 | static char cwdbuf[BUFSIZE]; 12 | if ((ret = getcwd(cwdbuf, sizeof(cwdbuf))) != 0) { 13 | return ret; 14 | } 15 | printf("%s\n", cwdbuf); 16 | return 0; 17 | } 18 | 19 | -------------------------------------------------------------------------------- /code/user/rename.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define printf(...) fprintf(1, __VA_ARGS__) 6 | 7 | void 8 | usage(void) { 9 | printf("usage: rename from to\n"); 10 | } 11 | 12 | int 13 | main(int argc, char **argv) { 14 | if (argc != 3) { 15 | usage(); 16 | return -1; 17 | } 18 | return rename(argv[1], argv[2]); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /code/user/robot.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int 6 | main(void) { 7 | static char buffer[1024]; 8 | while (1) { 9 | int ret; 10 | if ((ret = read(0, buffer, sizeof(buffer))) <= 0) { 11 | return ret; 12 | } 13 | write(1, buffer, ret); 14 | } 15 | } 16 | 17 | -------------------------------------------------------------------------------- /code/user/semtest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void 5 | sem_test(void) { 6 | sem_t sem_id = sem_init(1); 7 | assert(sem_id > 0); 8 | cprintf("sem_id = 0x%08x\n", sem_id); 9 | 10 | int i, value; 11 | for (i = 0; i < 10; i ++) { 12 | assert(sem_get_value(sem_id, &value) == 0); 13 | assert(value == i + 1 && sem_post(sem_id) == 0); 14 | } 15 | cprintf("post ok.\n"); 16 | 17 | for (; i > 0; i --) { 18 | assert(sem_wait(sem_id) == 0); 19 | assert(sem_get_value(sem_id, &value) == 0 && value == i); 20 | } 21 | cprintf("wait ok.\n"); 22 | 23 | int pid, ret; 24 | if ((pid = fork()) == 0) { 25 | assert(sem_get_value(sem_id, &value) == 0); 26 | assert(value == 1 && sem_wait(sem_id) == 0); 27 | 28 | sleep(10); 29 | for (i = 0; i < 10; i ++) { 30 | cprintf("sleep %d\n", i); 31 | sleep(20); 32 | } 33 | assert(sem_post(sem_id) == 0); 34 | exit(0); 35 | } 36 | assert(pid > 0); 37 | 38 | sleep(10); 39 | for (i = 0; i < 10; i ++) { 40 | yield(); 41 | } 42 | 43 | cprintf("wait semaphore...\n"); 44 | 45 | assert(sem_wait(sem_id) == 0); 46 | assert(sem_get_value(sem_id, &value) == 0 && value == 0); 47 | cprintf("hold semaphore.\n"); 48 | 49 | assert(waitpid(pid, &ret) == 0 && ret == 0); 50 | assert(sem_get_value(sem_id, &value) == 0 && value == 0); 51 | cprintf("fork pass.\n"); 52 | exit(0); 53 | } 54 | 55 | int 56 | main(void) { 57 | int pid, ret; 58 | if ((pid = fork()) == 0) { 59 | sem_test(); 60 | } 61 | assert(pid > 0 && waitpid(pid, &ret) == 0 && ret == 0); 62 | cprintf("semtest pass.\n"); 63 | return 0; 64 | } 65 | 66 | -------------------------------------------------------------------------------- /code/user/semtest2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | sem_t mutex; 5 | 6 | void test1(void) { 7 | cprintf("semtest2 test1:\n"); 8 | int nloop = 3, i, pid; 9 | if ((pid = fork()) == 0) { 10 | for (i = 0; i < nloop; i ++) { 11 | sem_wait(mutex); 12 | cprintf("child start %d.\n", i); 13 | sleep(50); 14 | cprintf("child end.\n"); 15 | sem_post(mutex); 16 | } 17 | cprintf("child exit.\n"); 18 | exit(0xbad); 19 | } 20 | assert(pid > 0); 21 | yield(); 22 | for (i = 0; i < nloop; i ++) { 23 | sem_wait(mutex); 24 | cprintf("parent start %d.\n", i); 25 | sleep(50); 26 | cprintf("parent end.\n"); 27 | sem_post(mutex); 28 | } 29 | assert(wait() == 0); 30 | } 31 | 32 | void test2(void) { 33 | cprintf("semtest2 test2:\n"); 34 | int nloop = 3, i, pid; 35 | if ((pid = fork()) == 0) { 36 | sem_wait(mutex); 37 | for (i = 0; i < nloop; i ++) { 38 | sem_wait(mutex); 39 | cprintf("child %d\n", i); 40 | sleep(50 * (i + 1)); 41 | sem_post(mutex); 42 | } 43 | sem_post(mutex); 44 | exit(0xbad); 45 | } 46 | assert(pid > 0); 47 | sleep(30); 48 | for (i = 0; i < nloop; i ++) { 49 | sem_post(mutex); 50 | yield(); 51 | cprintf("parent %d\n", i); 52 | sem_wait(mutex); 53 | } 54 | assert(wait() == 0); 55 | } 56 | 57 | int 58 | main(void) { 59 | assert((mutex = sem_init(1)) > 0); 60 | test1(); 61 | test2(); 62 | cprintf("semtest2 pass.\n"); 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /code/user/semtest3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | sem_t mutex; 6 | 7 | int 8 | main(void) { 9 | assert((mutex = sem_init(0)) > 0); 10 | 11 | cprintf("wait now...\n"); 12 | 13 | assert(sem_wait_timeout(mutex, 500) == -E_TIMEOUT); 14 | 15 | cprintf("wait timeout\n"); 16 | 17 | int pid; 18 | if ((pid = fork()) == 0) { 19 | cprintf("child now sleep\n"); 20 | sleep(500); 21 | sem_post(mutex); 22 | exit(0); 23 | } 24 | assert(pid > 0); 25 | 26 | yield(); 27 | assert(sem_wait_timeout(mutex, ~0) == 0); 28 | cprintf("semtest3 pass.\n"); 29 | return 0; 30 | } 31 | 32 | -------------------------------------------------------------------------------- /code/user/semtest4.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | sem_t mutex; 5 | 6 | int 7 | main(void) { 8 | assert((mutex = sem_init(1)) > 0); 9 | assert(sem_post(mutex) == 0); 10 | 11 | int value, pid; 12 | assert(sem_get_value(mutex, &value) == 0 && value == 2); 13 | assert(sem_free(mutex) == 0 && sem_get_value(mutex, &value) != 0); 14 | 15 | assert((mutex = sem_init(0)) > 0); 16 | if ((pid = fork()) == 0) { 17 | assert(sem_wait(mutex) != 0); 18 | cprintf("child exit ok.\n"); 19 | exit(0); 20 | } 21 | assert(pid > 0); 22 | assert(sem_free(mutex) == 0 && waitpid(pid, &value) == 0 && value == 0); 23 | cprintf("semtest4 pass.\n"); 24 | return 0; 25 | } 26 | 27 | -------------------------------------------------------------------------------- /code/user/sfs_dirtest1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define printf(...) fprintf(1, __VA_ARGS__) 11 | 12 | static char 13 | getmode(uint32_t st_mode) { 14 | char mode = '?'; 15 | if (S_ISREG(st_mode)) mode = '-'; 16 | if (S_ISDIR(st_mode)) mode = 'd'; 17 | if (S_ISLNK(st_mode)) mode = 'l'; 18 | if (S_ISCHR(st_mode)) mode = 'c'; 19 | if (S_ISBLK(st_mode)) mode = 'b'; 20 | return mode; 21 | } 22 | 23 | static void 24 | safe_stat(const char *name) { 25 | struct stat __stat, *stat = &__stat; 26 | int fd = open(name, O_RDONLY), ret = fstat(fd, stat); 27 | assert(fd >= 0 && ret == 0); 28 | printf("%c %3d %4d %10d ", getmode(stat->st_mode), 29 | stat->st_nlinks, stat->st_blocks, stat->st_size); 30 | } 31 | 32 | static void 33 | safe_chdir(const char *path) { 34 | int ret = chdir(path); 35 | assert(ret == 0); 36 | } 37 | 38 | static void 39 | safe_getcwd(round) { 40 | static char buffer[FS_MAX_FPATH_LEN + 1]; 41 | int ret = getcwd(buffer, sizeof(buffer)); 42 | assert(ret == 0); 43 | printf("%d: current: %s\n", round, buffer); 44 | } 45 | 46 | static void 47 | safe_lsdir(int round) { 48 | DIR *dirp = opendir("."); 49 | assert(dirp != NULL); 50 | struct dirent *direntp; 51 | while ((direntp = readdir(dirp)) != NULL) { 52 | printf("%d: ", round); 53 | safe_stat(direntp->name); 54 | printf("%s\n", direntp->name); 55 | } 56 | closedir(dirp); 57 | } 58 | 59 | void 60 | changedir(const char *path) { 61 | static int round = 0; 62 | printf("------------------------\n"); 63 | safe_chdir(path); 64 | safe_getcwd(round); 65 | safe_lsdir(round); 66 | round ++; 67 | } 68 | 69 | int 70 | main(void) { 71 | changedir("/"); 72 | changedir("/./../././../../././.././../.././../testman/.."); 73 | changedir("home"); 74 | changedir("../testman"); 75 | changedir("coreutils"); 76 | changedir("../././.././../../testman"); 77 | changedir("/"); 78 | printf("sfs_dirtest1 pass.\n"); 79 | return 0; 80 | } 81 | 82 | -------------------------------------------------------------------------------- /code/user/sfs_exectest1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define printf(...) fprintf(1, __VA_ARGS__) 7 | 8 | int 9 | main(void) { 10 | int fd[2], ret = pipe(fd); 11 | assert(ret == 0); 12 | 13 | int pid; 14 | if ((pid = fork()) == 0) { 15 | close(0), close(fd[1]); 16 | if ((ret = dup2(fd[0], 0)) < 0) { 17 | exit(ret); 18 | } 19 | ret = exec("bin/robot"); 20 | panic("child exec failed: %e\n", ret); 21 | } 22 | assert(pid > 0); 23 | 24 | close(fd[0]); 25 | 26 | int i; 27 | for (i = 0; i < 32; i ++) { 28 | fprintf(fd[1], "%02d: Hello world!!.\n", i); 29 | } 30 | close(fd[1]); 31 | 32 | assert(wait() == 0); 33 | cprintf("sfs_exectest1 pass.\n"); 34 | return 0; 35 | } 36 | 37 | -------------------------------------------------------------------------------- /code/user/sfs_exectest2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define printf(...) fprintf(1, __VA_ARGS__) 7 | 8 | const char *cmd = "bin/sfs_exectest2"; 9 | 10 | int 11 | main(int argc, char **argv) { 12 | int i; 13 | for (i = 0; i < argc; i ++) { 14 | printf("%d-%d: %s\n", argc, i, argv[i]); 15 | } 16 | switch (argc) { 17 | case 1: 18 | exec(cmd, "arg0"); 19 | case 2: 20 | exec(cmd, "arg0", "arg1"); 21 | case 3: 22 | exec(cmd, "arg0", "arg1", "arg2"); 23 | case 4: 24 | exec(cmd, "arg0", "arg1", "arg2", "arg3"); 25 | case 5: 26 | exec(cmd, "arg0", "arg1", "arg2", "arg3", "arg4"); 27 | } 28 | cprintf("sfs_exectest2 pass.\n"); 29 | return 0; 30 | } 31 | 32 | -------------------------------------------------------------------------------- /code/user/sfs_filetest1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define printf(...) fprintf(1, __VA_ARGS__) 11 | 12 | static int 13 | safe_open(const char *path, int open_flags) { 14 | int fd = open(path, open_flags); 15 | assert(fd >= 0); 16 | return fd; 17 | } 18 | 19 | static struct stat * 20 | safe_fstat(int fd) { 21 | static struct stat __stat, *stat = &__stat; 22 | int ret = fstat(fd, stat); 23 | assert(ret == 0); 24 | return stat; 25 | } 26 | 27 | static int 28 | safe_dup(int fd1) { 29 | int fd2 = dup(fd1); 30 | assert(fd2 >= 0); 31 | return fd2; 32 | } 33 | 34 | static void 35 | safe_read(int fd, void *data, size_t len) { 36 | int ret = read(fd, data, len); 37 | assert(ret == len); 38 | } 39 | 40 | static void 41 | safe_write(int fd, void *data, size_t len) { 42 | int ret = write(fd, data, len); 43 | assert(ret == len); 44 | } 45 | 46 | static void 47 | safe_seek(int fd, off_t pos, int whence) { 48 | int ret = seek(fd, pos, whence); 49 | assert(ret == 0); 50 | } 51 | 52 | static uint32_t buffer[1024]; 53 | 54 | void 55 | init_data(int fd, int pages) { 56 | int i, j; 57 | uint32_t value = 0; 58 | for (i = 0; i < pages; i ++) { 59 | for (j = 0; j < sizeof(buffer) / sizeof(buffer[0]); j ++) { 60 | buffer[j] = value ++; 61 | } 62 | safe_write(fd, buffer, sizeof(buffer)); 63 | } 64 | } 65 | 66 | void 67 | random_test(int fd, int pages) { 68 | int i, j; 69 | const int size = sizeof(buffer) / sizeof(buffer[0]); 70 | safe_seek(fd, 0, LSEEK_SET); 71 | for (i = 0; i < pages; i ++) { 72 | safe_read(fd, buffer, sizeof(buffer)); 73 | for (j = 0; j < 32; j ++) { 74 | uint32_t value = rand() % size; 75 | assert(buffer[value] == i * size + value); 76 | } 77 | } 78 | } 79 | 80 | int 81 | main(void) { 82 | int fd1 = safe_open("/test/testfile", O_RDWR | O_TRUNC); 83 | struct stat *stat = safe_fstat(fd1); 84 | assert(stat->st_size == 0 && stat->st_blocks == 0); 85 | 86 | const int npages = 128; 87 | init_data(fd1, npages); 88 | printf("init_data ok.\n"); 89 | 90 | int fd2 = safe_dup(fd1); 91 | stat = safe_fstat(fd2); 92 | assert(stat->st_size == npages * sizeof(buffer)); 93 | 94 | random_test(fd2, npages); 95 | printf("random_test ok.\n"); 96 | 97 | int fd3 = safe_open("/test/testfile", O_RDWR | O_TRUNC); 98 | stat = safe_fstat(fd3); 99 | assert(stat->st_size == 0 && stat->st_blocks == 0); 100 | safe_seek(fd3, sizeof(buffer), LSEEK_END); 101 | safe_seek(fd3, 0, LSEEK_SET); 102 | stat = safe_fstat(fd3); 103 | assert(stat->st_size == sizeof(buffer)); 104 | 105 | safe_seek(fd3, sizeof(buffer), LSEEK_END); 106 | stat = safe_fstat(fd3); 107 | assert(stat->st_size == sizeof(buffer) * 2); 108 | 109 | safe_seek(fd3, -sizeof(buffer), LSEEK_CUR); 110 | safe_read(fd3, buffer, sizeof(buffer)); 111 | int i; 112 | for (i = 0; i < sizeof(buffer) / sizeof(buffer[0]); i ++) { 113 | assert(buffer[i] == 0); 114 | } 115 | int fd4 = safe_open("/test/testfile", O_WRONLY | O_TRUNC); 116 | stat = safe_fstat(fd4); 117 | assert(stat->st_size == 0 && stat->st_blocks == 0); 118 | printf("sfs_filetest1 pass.\n"); 119 | return 0; 120 | } 121 | 122 | -------------------------------------------------------------------------------- /code/user/sfs_filetest2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define printf(...) fprintf(1, __VA_ARGS__) 11 | 12 | static int 13 | safe_open(const char *path, int open_flags) { 14 | int fd = open(path, open_flags); 15 | assert(fd >= 0); 16 | return fd; 17 | } 18 | 19 | static struct stat * 20 | safe_fstat(int fd) { 21 | static struct stat __stat, *stat = &__stat; 22 | int ret = fstat(fd, stat); 23 | assert(ret == 0); 24 | return stat; 25 | } 26 | 27 | static void 28 | safe_read(int fd, void *data, size_t len) { 29 | int ret = read(fd, data, len); 30 | assert(ret == len); 31 | } 32 | 33 | static void 34 | safe_write(int fd, void *data, size_t len) { 35 | int ret = write(fd, data, len); 36 | assert(ret == len); 37 | } 38 | 39 | static void 40 | safe_seek(int fd, off_t pos, int whence) { 41 | int ret = seek(fd, pos, whence); 42 | assert(ret == 0); 43 | } 44 | 45 | static unsigned char buffer[4096]; 46 | 47 | int 48 | main(void) { 49 | int fd = safe_open("/test/testfile", O_RDWR | O_TRUNC); 50 | struct stat *stat = safe_fstat(fd); 51 | assert(stat->st_size == 0 && stat->st_blocks == 0); 52 | 53 | safe_seek(fd, sizeof(buffer) * 1024 * 2, LSEEK_SET); 54 | 55 | int i; 56 | for (i = 0; i < sizeof(buffer); i ++) { 57 | buffer[i] = i; 58 | } 59 | safe_write(fd, buffer, sizeof(buffer)); 60 | memset(buffer, 0, sizeof(buffer)); 61 | 62 | safe_seek(fd, -sizeof(buffer), LSEEK_END); 63 | safe_read(fd, buffer, sizeof(buffer)); 64 | 65 | for (i = 0; i < sizeof(buffer); i ++) { 66 | assert(buffer[i] == (unsigned char)i); 67 | } 68 | 69 | fd = safe_open("/test/testfile", O_RDWR | O_TRUNC); 70 | stat = safe_fstat(fd); 71 | assert(stat->st_size == 0 && stat->st_blocks == 0); 72 | printf("sfs_filetest2 pass.\n"); 73 | return 0; 74 | } 75 | 76 | -------------------------------------------------------------------------------- /code/user/shmemtest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void *buf1, *buf2; 8 | 9 | int 10 | main(void) { 11 | assert((buf1 = shmem_malloc(8192)) != NULL); 12 | assert((buf2 = malloc(4096)) != NULL); 13 | 14 | int i; 15 | for (i = 0; i < 4096; i ++) { 16 | *(char *)(buf1 + i) = (char)i; 17 | } 18 | memset(buf2, 0, 4096); 19 | 20 | int pid, exit_code; 21 | if ((pid = fork()) == 0) { 22 | for (i = 0; i < 4096; i ++) { 23 | assert(*(char *)(buf1 + i) == (char)i); 24 | } 25 | memcpy(buf1 + 4096, buf1, 4096); 26 | memset(buf1, 0, 4096); 27 | memset(buf2, 0xFF, 4096); 28 | exit(0); 29 | } 30 | assert(pid > 0 && waitpid(pid, &exit_code) == 0 && exit_code == 0); 31 | 32 | for (i = 0; i < 4096; i ++) { 33 | assert(*(char *)(buf1 + 4096 + i) == (char)i); 34 | assert(*(char *)(buf1 + i) == 0); 35 | assert(*(char *)(buf2 + i) == 0); 36 | } 37 | 38 | free(buf1); 39 | free(buf2); 40 | 41 | cprintf("shmemtest pass.\n"); 42 | return 0; 43 | } 44 | 45 | -------------------------------------------------------------------------------- /code/user/sleep.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct slot { 6 | char data[4096]; 7 | struct slot *next; 8 | }; 9 | 10 | void 11 | glutton(void) { 12 | struct slot *tmp, *head = NULL; 13 | int n = 0; 14 | cprintf("I am child and I will eat out all the memory.\n"); 15 | while ((tmp = (struct slot *)malloc(sizeof(struct slot))) != NULL) { 16 | if ((++ n) % 1000 == 0) { 17 | cprintf("I ate %d slots.\n", n); 18 | sleep(50); 19 | } 20 | tmp->next = head; 21 | head = tmp; 22 | } 23 | exit(0xdead); 24 | } 25 | 26 | void 27 | sleepy(int pid) { 28 | int i, time = 100; 29 | for (i = 0; i < 10; i ++) { 30 | sleep(time); 31 | cprintf("sleep %d x %d slices.\n", i + 1, time); 32 | } 33 | assert(kill(pid) == 0); 34 | exit(0); 35 | } 36 | 37 | int 38 | main(void) { 39 | unsigned int time = gettime_msec(); 40 | int pid1, pid2, exit_code; 41 | if ((pid1 = fork()) == 0) { 42 | glutton(); 43 | } 44 | assert(pid1 > 0); 45 | 46 | if ((pid2 = fork()) == 0) { 47 | sleepy(pid1); 48 | } 49 | if (pid2 < 0) { 50 | kill(pid1); 51 | panic("fork failed.\n"); 52 | } 53 | 54 | assert(waitpid(pid2, &exit_code) == 0 && exit_code == 0); 55 | cprintf("use %04d msecs.\n", gettime_msec() - time); 56 | cprintf("sleep pass.\n"); 57 | return 0; 58 | } 59 | 60 | -------------------------------------------------------------------------------- /code/user/sleepkill.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int 5 | main(void) { 6 | int pid; 7 | if ((pid = fork()) == 0) { 8 | sleep(~0); 9 | exit(0xdead); 10 | } 11 | assert(pid > 0); 12 | 13 | sleep(100); 14 | assert(kill(pid) == 0); 15 | cprintf("sleepkill pass.\n"); 16 | return 0; 17 | } 18 | 19 | -------------------------------------------------------------------------------- /code/user/softint.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int 5 | main(void) { 6 | asm volatile("int $14"); 7 | panic("FAIL: T.T\n"); 8 | } 9 | 10 | -------------------------------------------------------------------------------- /code/user/spin.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int 5 | main(void) { 6 | int pid, ret; 7 | cprintf("I am the parent. Forking the child...\n"); 8 | if ((pid = fork()) == 0) { 9 | cprintf("I am the child. spinning ...\n"); 10 | while (1); 11 | } 12 | cprintf("I am the parent. Running the child...\n"); 13 | 14 | yield(); 15 | yield(); 16 | yield(); 17 | 18 | cprintf("I am the parent. Killing the child...\n"); 19 | 20 | assert((ret = kill(pid)) == 0); 21 | cprintf("kill returns %d\n", ret); 22 | 23 | assert((ret = waitpid(pid, NULL)) == 0); 24 | cprintf("wait returns %d\n", ret); 25 | 26 | cprintf("spin may pass.\n"); 27 | return 0; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /code/user/spipetest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int 8 | main(void) { 9 | spipe_t pipe; 10 | assert(spipe(&pipe) == 0); 11 | 12 | int i, pid; 13 | if ((pid = fork()) == 0) { 14 | for (i = 0; i < 10; i ++) { 15 | yield(); 16 | } 17 | if (spipewrite(&pipe, "A", 1) == 1) { 18 | cprintf("child write ok\n"); 19 | } 20 | spipeclose(&pipe); 21 | exit(0); 22 | } 23 | assert(pid > 0); 24 | 25 | sleep(100); 26 | int len; 27 | char buf[100]; 28 | assert((len = spiperead(&pipe, buf, sizeof(buf))) == 1 && buf[0] == 'A'); 29 | assert(spipeclose(&pipe) == 0); 30 | cprintf("parent read ok\n"); 31 | cprintf("spipetest pass\n"); 32 | return 0; 33 | } 34 | 35 | -------------------------------------------------------------------------------- /code/user/spipetest2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | static spipe_t pipe; 10 | 11 | thread_t tids[10]; 12 | int total = sizeof(tids) / sizeof(tids[0]); 13 | 14 | int 15 | thread_main(void *arg) { 16 | long id = (long)arg; 17 | cprintf("this is %d\n", id); 18 | 19 | size_t n = 10000; 20 | char *buf = malloc(sizeof(char) * n); 21 | if (buf == NULL) { 22 | return -1; 23 | } 24 | 25 | memset(buf, (char)id, n); 26 | 27 | int i, rounds = 20; 28 | for (i = 0; i < rounds; i ++) { 29 | size_t ret = spipewrite(&pipe, buf, n); 30 | if (ret != n) { 31 | cprintf("pipe is closed, too early.\n"); 32 | return -1; 33 | } 34 | if (id == 0) { 35 | cprintf("send %d/%d\n", i, rounds); 36 | } 37 | } 38 | return 0; 39 | } 40 | 41 | void 42 | process_main(void) { 43 | int counts[total], i; 44 | for (i = 0; i < total; i ++) { 45 | counts[i] = 0; 46 | } 47 | 48 | char buf[128]; 49 | size_t n = sizeof(buf); 50 | 51 | while (1) { 52 | size_t ret = spiperead(&pipe, buf, n); 53 | if (ret == 0) { 54 | break; 55 | } 56 | for (i = 0; i < ret; i ++) { 57 | counts[((unsigned int)buf[i]) % total] ++; 58 | } 59 | } 60 | if (spipeisclosed(&pipe)) { 61 | for (i = 0; i < total; i ++) { 62 | cprintf("%d reads %d\n", i, counts[i]); 63 | } 64 | exit(0); 65 | } 66 | exit(0xbad); 67 | } 68 | 69 | int 70 | main(void) { 71 | int pid, i; 72 | assert(spipe(&pipe) == 0); 73 | 74 | if ((pid = fork()) == 0) { 75 | process_main(); 76 | } 77 | assert(pid > 0); 78 | 79 | memset(tids, 0, sizeof(thread_t) * total); 80 | for (i = 0; i < total; i ++) { 81 | if (thread(thread_main, (void *)(long)i, tids + i) != 0) { 82 | goto failed; 83 | } 84 | } 85 | 86 | int exit_code; 87 | for (i = 0; i < total; i ++) { 88 | if (thread_wait(tids + i, &exit_code) != 0 || exit_code != 0) { 89 | goto failed; 90 | } 91 | } 92 | 93 | for (i = 0; i < total; i ++) { 94 | yield(); 95 | } 96 | 97 | assert(spipeclose(&pipe) == 0); 98 | assert(waitpid(pid, &exit_code) == 0 && exit_code == 0); 99 | cprintf("spipetest2 pass.\n"); 100 | return 0; 101 | 102 | failed: 103 | for (i = 0; i < total; i ++) { 104 | if (tids[i].pid > 0) { 105 | kill(tids[i].pid); 106 | } 107 | } 108 | kill(pid); 109 | panic("FAIL: T.T\n"); 110 | } 111 | 112 | -------------------------------------------------------------------------------- /code/user/swaptest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | const int size = 5 * 1024 * 1024; 7 | char *buffer; 8 | 9 | int pid[10] = {0}, pids; 10 | 11 | void 12 | do_yield(void) { 13 | int i; 14 | for (i = 0; i < 5; i ++) { 15 | yield(); 16 | } 17 | } 18 | 19 | void 20 | work(int num, bool print) { 21 | #define printf(...) \ 22 | do { \ 23 | if ((print)) { \ 24 | cprintf(__VA_ARGS__); \ 25 | } \ 26 | } while (0) 27 | 28 | do_yield(); 29 | 30 | int i, j; 31 | for (i = 0; i < size; i ++) { 32 | assert(buffer[i] == (char)(i * i)); 33 | } 34 | 35 | printf("check cow ok.\n"); 36 | 37 | char c = (char)num; 38 | 39 | for (i = 0; i < 5; i ++, c ++) { 40 | printf("round %d\n", i); 41 | memset(buffer, c, size); 42 | for (j = 0; j < size; j ++) { 43 | assert(buffer[i] == c); 44 | } 45 | } 46 | 47 | do_yield(); 48 | 49 | printf("child check ok.\n"); 50 | 51 | #undef printf 52 | } 53 | 54 | int 55 | main(void) { 56 | assert((buffer = malloc(size)) != NULL); 57 | cprintf("buffer size = %08x\n", size); 58 | 59 | pids = sizeof(pid) / sizeof(pid[0]); 60 | 61 | int i; 62 | for (i = 0; i < size; i ++) { 63 | buffer[i] = (char)(i * i); 64 | } 65 | 66 | for (i = 0; i < pids; i ++) { 67 | if ((pid[i] = fork()) == 0) { 68 | sleep((pids - i) * 10); 69 | cprintf("child %d fork ok, pid = %d.\n", i, getpid()); 70 | work(getpid(), i == 0); 71 | exit(0xbee); 72 | } 73 | if (pid[i] < 0) { 74 | goto failed; 75 | } 76 | } 77 | cprintf("parent init ok.\n"); 78 | 79 | for (i = 0; i < pids; i ++) { 80 | int exit_code, ret; 81 | if ((ret = waitpid(pid[i], &exit_code)) == 0) { 82 | if (exit_code == 0xbee) { 83 | continue ; 84 | } 85 | } 86 | cprintf("wait failed: %d, pid = %d, ret = %d, exit = %x.\n", 87 | i, pid[i], ret, exit_code); 88 | goto failed; 89 | } 90 | 91 | cprintf("wait ok.\n"); 92 | for (i = 0; i < size; i ++) { 93 | assert(buffer[i] == (char)(i * i)); 94 | } 95 | 96 | cprintf("check buffer ok.\n"); 97 | cprintf("swaptest pass.\n"); 98 | return 0; 99 | 100 | failed: 101 | for (i = 0; i < pids; i ++) { 102 | if (pid[i] > 0) { 103 | kill(pid[i]); 104 | } 105 | } 106 | panic("FAIL: T.T\n"); 107 | } 108 | 109 | -------------------------------------------------------------------------------- /code/user/testbss.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define ARRAYSIZE (1024*1024) 5 | 6 | uint32_t bigarray[ARRAYSIZE]; 7 | 8 | int 9 | main(void) { 10 | cprintf("Making sure bss works right...\n"); 11 | int i; 12 | for (i = 0; i < ARRAYSIZE; i ++) { 13 | if (bigarray[i] != 0) { 14 | panic("bigarray[%d] isn't cleared!\n", i); 15 | } 16 | } 17 | for (i = 0; i < ARRAYSIZE; i ++) { 18 | bigarray[i] = i; 19 | } 20 | for (i = 0; i < ARRAYSIZE; i ++) { 21 | if (bigarray[i] != i) { 22 | panic("bigarray[%d] didn't hold its value!\n", i); 23 | } 24 | } 25 | 26 | cprintf("Yes, good. Now doing a wild write off the end...\n"); 27 | cprintf("testbss may pass.\n"); 28 | 29 | bigarray[ARRAYSIZE + 1024] = 0; 30 | asm volatile ("int $0x14"); 31 | panic("FAIL: T.T\n"); 32 | } 33 | 34 | -------------------------------------------------------------------------------- /code/user/threadfork.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | const int forknum = 125; 6 | 7 | void 8 | do_yield(void) { 9 | int i; 10 | for (i = 0; i < 30; i ++) { 11 | sleep(10); 12 | yield(); 13 | } 14 | } 15 | 16 | void 17 | process_main(void) { 18 | do_yield(); 19 | } 20 | 21 | int 22 | thread_main(void *arg) { 23 | int i, pid; 24 | for (i = 0; i < forknum; i ++) { 25 | if ((pid = fork()) == 0) { 26 | process_main(); 27 | exit(0); 28 | } 29 | } 30 | do_yield(); 31 | return 0; 32 | } 33 | 34 | int 35 | main(void) { 36 | thread_t tids[10]; 37 | 38 | int i, n = sizeof(tids) / sizeof(tids[0]); 39 | for (i = 0; i < n; i ++) { 40 | if (thread(thread_main, NULL, tids + i) != 0) { 41 | goto failed; 42 | } 43 | } 44 | 45 | int count = 0; 46 | while (wait() == 0) { 47 | count ++; 48 | } 49 | 50 | assert(count == (forknum + 1) * n); 51 | cprintf("threadfork pass.\n"); 52 | return 0; 53 | 54 | failed: 55 | for (i = 0; i < n; i ++) { 56 | if (tids[i].pid > 0) { 57 | kill(tids[i].pid); 58 | } 59 | } 60 | panic("FAIL: T.T\n"); 61 | } 62 | 63 | -------------------------------------------------------------------------------- /code/user/threadgroup1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int 6 | thread_loop(void *arg) { 7 | while (1) 8 | /* do nothing */; 9 | } 10 | 11 | int 12 | main(void) { 13 | thread_t tids[10]; 14 | 15 | int i, n = sizeof(tids) / sizeof(tids[0]); 16 | for (i = 0; i < n; i ++) { 17 | if (thread(thread_loop, NULL, tids + i) != 0) { 18 | goto failed; 19 | } 20 | } 21 | 22 | cprintf("thread ok.\n"); 23 | 24 | for (i = 0; i < 3; i ++) { 25 | cprintf("yield %d.\n", i); 26 | yield(); 27 | } 28 | cprintf("exit thread group now.\n"); 29 | return 0; 30 | 31 | failed: 32 | for (i = 0; i < 10; i ++) { 33 | if (tids[i].pid > 0) { 34 | kill(tids[i].pid); 35 | } 36 | } 37 | panic("FAIL: T.T\n"); 38 | } 39 | 40 | -------------------------------------------------------------------------------- /code/user/threadgroup2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int 6 | thread_loop(void *arg) { 7 | int quit = (long)arg; 8 | while (quit != 0) 9 | /* do nothing */; 10 | 11 | int i; 12 | for (i = 0; i < 3; i ++) { 13 | cprintf("yield %d.\n", i); 14 | yield(); 15 | } 16 | cprintf("exit thread group now.\n"); 17 | exit(0); 18 | } 19 | 20 | int 21 | main(void) { 22 | thread_t tids[10]; 23 | 24 | int i, n = sizeof(tids) / sizeof(tids[0]); 25 | for (i = 0; i < n; i ++) { 26 | if (thread(thread_loop, (void *)(long)i, tids + i) != 0) { 27 | goto failed; 28 | } 29 | } 30 | 31 | cprintf("thread ok.\n"); 32 | 33 | while (1) 34 | /* do nothing */; 35 | 36 | return 0; 37 | 38 | failed: 39 | for (i = 0; i < 10; i ++) { 40 | if (tids[i].pid > 0) { 41 | kill(tids[i].pid); 42 | } 43 | } 44 | panic("FAIL: T.T\n"); 45 | } 46 | 47 | -------------------------------------------------------------------------------- /code/user/threadtest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int 6 | test(void *arg) { 7 | cprintf("child ok.\n"); 8 | return 0xbee; 9 | } 10 | 11 | int 12 | main(void) { 13 | thread_t tid; 14 | assert(thread(test, NULL, &tid) == 0); 15 | cprintf("thread ok.\n"); 16 | 17 | int exit_code; 18 | assert(thread_wait(&tid, &exit_code) == 0 && exit_code == 0xbee); 19 | 20 | cprintf("threadtest pass.\n"); 21 | return 0; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /code/user/threadwork.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | char **buffer; 9 | thread_t *tids; 10 | const int size = 47, rounds = 103; 11 | 12 | int 13 | work(void *arg) { 14 | long n = (long)arg; 15 | int value = hash32(n * n, 8); 16 | cprintf("i am %02d, %02d, i got %08x\n", n, getpid(), value); 17 | yield(); 18 | int i, j; 19 | for (i = 0; i < size; i ++) { 20 | for (j = n; j < size * rounds; j += size) { 21 | buffer[i][j] = (char)value; 22 | } 23 | } 24 | return 0xbee; 25 | } 26 | 27 | int 28 | loop(void *arg) { 29 | cprintf("child: do nothing\n"); 30 | while (1); 31 | } 32 | 33 | int 34 | main(void) { 35 | buffer = (char **)malloc(sizeof(char *) * size); 36 | 37 | int i, j, k, ret; 38 | for (i = 0; i < size; i ++) { 39 | assert((buffer[i] = (char *)malloc(sizeof(char) * size * rounds)) != NULL); 40 | } 41 | 42 | // print current page table 43 | print_pgdir(); 44 | 45 | assert((tids = (thread_t *)malloc(sizeof(thread_t) * size)) != NULL); 46 | memset(tids, 0, sizeof(thread_t) * size); 47 | 48 | // create 'size' threads 49 | for (i = 0; i < size; i ++) { 50 | if ((ret = thread(work, (void *)(long)i, tids + i)) != 0) { 51 | cprintf("thread %d failed, returns %d\n", i, ret); 52 | goto failed; 53 | } 54 | } 55 | 56 | cprintf("thread ok.\n"); 57 | 58 | // yield, make sure that threads have touched their stacks 59 | for (i = 0; i < size * 2; i ++) { 60 | yield(); 61 | } 62 | 63 | // print current page table 64 | print_pgdir(); 65 | 66 | // wait and check exit codes 67 | for (i = 0; i < size; i ++) { 68 | int exit_code = 0; 69 | if (thread_wait(tids + i, &exit_code) != 0) { 70 | goto failed; 71 | } 72 | if (exit_code != 0xbee) { 73 | cprintf("thread %d exit failed, %d\n", i, exit_code); 74 | goto failed; 75 | } 76 | } 77 | 78 | cprintf("thread wait ok.\n"); 79 | 80 | print_pgdir(); 81 | 82 | for (k = 0; k < size; k ++) { 83 | int value = hash32(k * k, 8); 84 | for (i = 0; i < size; i ++) { 85 | for (j = k; j < size * rounds; j += size) { 86 | assert(buffer[i][j] == (char)value); 87 | } 88 | } 89 | } 90 | 91 | // create a 'loop' thread, kill and wait 92 | thread_t loop_tid; 93 | assert(thread(loop, NULL, &loop_tid) == 0); 94 | cprintf("loop init ok.\n"); 95 | 96 | if (thread_kill(&loop_tid) != 0) { 97 | kill(loop_tid.pid); 98 | panic("kill loop_tid failed.\n"); 99 | } 100 | 101 | // wait 'loop' quit, wait() == 0 102 | assert(wait() == 0 && wait() != 0); 103 | 104 | cprintf("threadwork pass.\n"); 105 | return 0; 106 | 107 | failed: 108 | for (i = 0; i < size; i ++) { 109 | if (tids[i].pid > 0) { 110 | kill(tids[i].pid); 111 | } 112 | } 113 | panic("FAIL: T.T\n"); 114 | } 115 | 116 | -------------------------------------------------------------------------------- /code/user/unlink.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define printf(...) fprintf(1, __VA_ARGS__) 6 | 7 | void 8 | usage(void) { 9 | printf("usage: unlink dir [...]\n"); 10 | } 11 | 12 | int 13 | main(int argc, char **argv) { 14 | if (argc == 1) { 15 | usage(); 16 | return -1; 17 | } 18 | else { 19 | int i, ret; 20 | for (i = 1; i < argc; i ++) { 21 | if ((ret = unlink(argv[i])) != 0) { 22 | return ret; 23 | } 24 | } 25 | } 26 | return 0; 27 | } 28 | 29 | -------------------------------------------------------------------------------- /code/user/waitkill.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void 5 | do_yield(void) { 6 | yield(); 7 | yield(); 8 | yield(); 9 | yield(); 10 | yield(); 11 | yield(); 12 | } 13 | 14 | int parent, pid1, pid2; 15 | 16 | void 17 | loop(void) { 18 | cprintf("child 1.\n"); 19 | while (1); 20 | } 21 | 22 | void 23 | work(void) { 24 | cprintf("child 2.\n"); 25 | do_yield(); 26 | if (kill(parent) == 0) { 27 | cprintf("kill parent ok.\n"); 28 | do_yield(); 29 | if (kill(pid1) == 0) { 30 | cprintf("kill child1 ok.\n"); 31 | exit(0); 32 | } 33 | } 34 | exit(-1); 35 | } 36 | 37 | int 38 | main(void) { 39 | parent = getpid(); 40 | if ((pid1 = fork()) == 0) { 41 | loop(); 42 | } 43 | 44 | assert(pid1 > 0); 45 | 46 | if ((pid2 = fork()) == 0) { 47 | work(); 48 | } 49 | if (pid2 > 0) { 50 | cprintf("wait child 1.\n"); 51 | waitpid(pid1, NULL); 52 | panic("waitpid %d returns\n", pid1); 53 | } 54 | else { 55 | kill(pid1); 56 | } 57 | panic("FAIL: T.T\n"); 58 | } 59 | 60 | -------------------------------------------------------------------------------- /code/user/yield.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int 5 | main(void) { 6 | int i; 7 | cprintf("Hello, I am process %d.\n", getpid()); 8 | for (i = 0; i < 5; i ++) { 9 | yield(); 10 | cprintf("Back in process %d, iteration %d.\n", getpid(), i); 11 | } 12 | cprintf("All done in process %d.\n", getpid()); 13 | cprintf("yield pass.\n"); 14 | return 0; 15 | } 16 | 17 | --------------------------------------------------------------------------------