├── .gitignore ├── README.md ├── blogcode └── 文件系统分析 │ ├── fs.h │ ├── inode.h │ ├── iobuf.h │ └── ucoredef.h ├── code-with-comments ├── .gitignore ├── Makefile ├── boot │ ├── asm.h │ ├── bootasm.S │ └── bootmain.c ├── kern │ ├── debug │ │ ├── assert.h │ │ ├── kdebug.c │ │ ├── kdebug.h │ │ ├── kmonitor.c │ │ ├── kmonitor.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_stdin.c │ │ │ └── dev_stdout.c │ │ ├── file.c │ │ ├── file.h │ │ ├── fs.c │ │ ├── fs.h │ │ ├── iobuf.c │ │ ├── iobuf.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 │ │ ├── readline.c │ │ ├── stdio.c │ │ └── string.c │ ├── mm │ │ ├── default_pmm.c │ │ ├── default_pmm.h │ │ ├── kmalloc.c │ │ ├── kmalloc.h │ │ ├── memlayout.h │ │ ├── mmu.h │ │ ├── pmm.c │ │ ├── pmm.h │ │ ├── swap.c │ │ ├── swap.h │ │ ├── swap_fifo.c │ │ ├── swap_fifo.h │ │ ├── vmm.c │ │ └── vmm.h │ ├── process │ │ ├── entry.S │ │ ├── proc.c │ │ ├── proc.h │ │ └── switch.S │ ├── schedule │ │ ├── rr_sched.c │ │ ├── rr_sched.h │ │ ├── sched.c │ │ ├── sched.h │ │ ├── stride_sched.c │ │ └── stride_sched.h │ ├── sync │ │ ├── check_sync.c │ │ ├── monitor.c │ │ ├── monitor.h │ │ ├── sem.c │ │ ├── sem.h │ │ ├── sync.h │ │ ├── wait.c │ │ └── wait.h │ ├── syscall │ │ ├── syscall.c │ │ └── syscall.h │ └── trap │ │ ├── trap.c │ │ ├── trap.h │ │ ├── trapentry.S │ │ └── vectors.S ├── libs │ ├── atomic.h │ ├── defs.h │ ├── dirent.h │ ├── elf.h │ ├── error.h │ ├── hash.c │ ├── list.h │ ├── printfmt.c │ ├── rand.c │ ├── skew_heap.h │ ├── stat.h │ ├── stdarg.h │ ├── stdio.h │ ├── stdlib.h │ ├── string.c │ ├── string.h │ ├── unistd.h │ └── x86.h ├── readme.md ├── tools │ ├── boot.ld │ ├── function.mk │ ├── gdbinit │ ├── grade.sh │ ├── kernel.ld │ ├── mksfs.c │ ├── sign.c │ ├── user.ld │ └── vector.c └── user │ ├── badarg.c │ ├── badsegment.c │ ├── divzero.c │ ├── exit.c │ ├── faultread.c │ ├── faultreadkernel.c │ ├── forktest.c │ ├── forktree.c │ ├── hello.c │ ├── libs │ ├── dir.c │ ├── dir.h │ ├── file.c │ ├── file.h │ ├── initcode.S │ ├── lock.h │ ├── panic.c │ ├── stdio.c │ ├── syscall.c │ ├── syscall.h │ ├── ulib.c │ ├── ulib.h │ └── umain.c │ ├── ls.c │ ├── matrix.c │ ├── pgdir.c │ ├── priority.c │ ├── sfs_filetest1.c │ ├── sh.c │ ├── sleep.c │ ├── sleepkill.c │ ├── softint.c │ ├── spin.c │ ├── testbss.c │ ├── waitkill.c │ └── yield.c ├── images ├── Canonical Device.png ├── PTE.png ├── SFS 磁盘组织.png ├── VFS 与 SFS 的衔接.png ├── fork-文件描述块.png ├── gdb 调试用户程序.jpg ├── gdb调试用户态程序 4.png ├── gdb调试用户态程序 5.png ├── gdb调试用户态程序3.png ├── gdb调试用户程序 2.png ├── io_buffer.png ├── iobuf 与 disk0_buffer.png ├── iobuf含义.png ├── kernel 链接信息.png ├── vdev_list.png ├── 中断寻址.png ├── 中断结构.png ├── 内核数据结构-pages.png ├── 内核虚拟地址.png ├── 双向链表示例.png ├── 哈希表.png ├── 存储管理模块依赖图.png ├── 文件系统分析 1.png ├── 文件系统分析 2.png ├── 文件系统分析 3.png ├── 文件系统架构.png ├── 文件系统类图fs.png ├── 文件系统类图inode.png ├── 文件系统设计图.png ├── 物理内存初始状态.png ├── 物理页示意图.png ├── 目录树的磁盘级表示1.png ├── 目录树的磁盘级表示2.png ├── 磁盘区块.png ├── 线性地址结构.png ├── 虚拟内存管理.png ├── 虚拟内存维护.png ├── 虚拟地址空间和物理地址空间的示意图.png ├── 进程与文件数据结构.png └── 进程数据结构 1.png ├── mindmaps ├── 操作系统机制.xmind ├── 操作系统设计.xmind └── 虚拟化.xmind ├── notes ├── bitmap.md ├── lab 7.md ├── lab0-1.md ├── lab2.md ├── lab3.md ├── lab4.md ├── lab5.md ├── lab6.md ├── lab8.md ├── ucore 中的数据结构与算法.md ├── ucore 分析之——文件系统的面向对象实现: 手写虚函数表.md ├── ucore 拓展之——日志输出及控制,调试逻辑优化.md ├── ucore 拓展之——用 gdb 调试程序从用户态到内核态的整个流程.md ├── ucore 文件系统疑似 bug 记录.md ├── 信号量.md ├── 内存管理概览.md ├── 函数调用与中断.md ├── 基于分页机制的虚拟内存管理实现.md ├── 心得.md ├── 总线相关.md ├── 总结.md ├── 教程.md ├── 网络编程.md ├── 自问自答.md └── 速查表.md ├── others ├── IDE 文档ATA-d1410r3a.pdf └── ucore.xls └── ppts ├── 任务管理.pptx ├── 内存管理.pptx ├── 数据结构.pptx ├── 文件系统.pptx ├── 网络编程.pptx └── 进程.pptx /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode -------------------------------------------------------------------------------- /blogcode/文件系统分析/fs.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/blogcode/文件系统分析/fs.h -------------------------------------------------------------------------------- /blogcode/文件系统分析/inode.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/blogcode/文件系统分析/inode.h -------------------------------------------------------------------------------- /blogcode/文件系统分析/iobuf.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/blogcode/文件系统分析/iobuf.h -------------------------------------------------------------------------------- /blogcode/文件系统分析/ucoredef.h: -------------------------------------------------------------------------------- 1 | #ifndef _UCOREDEF_H_ 2 | #define _UCOREDEF_H_ 3 | 4 | 5 | #define UCORE_NAMESPACE_START \ 6 | namespace ucore\ 7 | { 8 | 9 | #define UCORE_NAMESPACE_END \ 10 | } 11 | 12 | UCORE_NAMESPACE_START 13 | 14 | typedef int int32_t; 15 | 16 | typedef int32_t intptr_t; 17 | 18 | typedef intptr_t off_t; 19 | 20 | UCORE_NAMESPACE_END 21 | 22 | #endif // !_UCOREDEF_H_ 23 | -------------------------------------------------------------------------------- /code-with-comments/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | *.udb 3 | .idea -------------------------------------------------------------------------------- /code-with-comments/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-with-comments/kern/debug/assert.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_DEBUG_ASSERT_H__ 2 | #define __KERN_DEBUG_ASSERT_H__ 3 | 4 | #include 5 | 6 | void __warn(const char *file, int line, const char *fmt, ...); 7 | void __noreturn __panic(const char *file, int line, const char *fmt, ...); 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 | #endif /* !__KERN_DEBUG_ASSERT_H__ */ 27 | 28 | -------------------------------------------------------------------------------- /code-with-comments/kern/debug/kdebug.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_DEBUG_KDEBUG_H__ 2 | #define __KERN_DEBUG_KDEBUG_H__ 3 | 4 | #include 5 | #include 6 | 7 | 8 | 9 | /** 10 | * 日志控制优化: 11 | * 0) 行日志开关 12 | * 1) 模块级日志开关: 视 kern 下一个文件夹为一个模块, 对应宏置零即可关闭 13 | * 2) 区域日志开关: 如果想屏蔽对某个区域的日志, 只需用 _NO_LOG_START 和_NO_LOG_END包裹区域即可. 14 | * 这两个宏已配置为必须成对出现,否则无法编译通过. 15 | */ 16 | #define LOG_LINE_ON 0 // 行打印开关,即"---xxx---"形式的开关 17 | 18 | #define IS_LOG_GLOBAL_ENABLE 1 // 日志总控(不含LOG_LINE) 19 | #define IS_LOG_INIT_ON 0 20 | #define IS_LOG_MEMORY_ON 0 21 | #define IS_LOG_TRAP_ON 1 22 | #define IS_LOG_SYNC_ON 0 23 | #define IS_LOG_PROCESS_ON 0 24 | #define IS_LOG_FS_ON 0 25 | #define IS_LOG_DRIVER_ON 0 26 | #define IS_LOG_SYSCALL_ON 0 27 | #define IS_LOG_SCHEDULE_ON 0 28 | #define IS_LOG_DEBUG_ON 0 29 | 30 | extern int _will_log; 31 | extern int log(const char *fmt, ...); 32 | extern int log_check(const char *filename); 33 | extern int cprintf(const char *fmt, ...); 34 | 35 | #define _NO_LOG_START\ 36 | {\ 37 | do{_will_log = 0;}while(0); 38 | 39 | #define _NO_LOG_END\ 40 | do{_will_log = 1;}while(0);\ 41 | } 42 | 43 | #define LOG(_LOG_STR, ...)\ 44 | do{\ 45 | if(_will_log && log_check(__FILE__)){\ 46 | log(_LOG_STR, ##__VA_ARGS__);\ 47 | }\ 48 | }while(0) 49 | 50 | #define LOG_TAB(_LOG_STR, ...)\ 51 | LOG("\t"_LOG_STR, ##__VA_ARGS__) 52 | 53 | // 行打印, 行如"-------xxx---------" 54 | #define LOG_LINE(_LOG_STR)\ 55 | do{\ 56 | if (LOG_LINE_ON)\ 57 | cprintf("\n\n--------------"_LOG_STR"--------------\n\n");\ 58 | }while(0) 59 | 60 | void print_history(void); 61 | void print_kerninfo(void); 62 | void print_stackframe(void); 63 | void print_debuginfo(uintptr_t eip); 64 | 65 | #endif /* !__KERN_DEBUG_KDEBUG_H__ */ 66 | 67 | -------------------------------------------------------------------------------- /code-with-comments/kern/debug/kmonitor.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /* * 9 | * Simple command-line kernel monitor useful for controlling the 10 | * kernel and exploring the system interactively. 11 | * */ 12 | 13 | struct command { 14 | const char *name; 15 | const char *desc; 16 | // return -1 to force monitor to exit 17 | int(*func)(int argc, char **argv, struct trapframe *tf); 18 | }; 19 | 20 | static struct command commands[] = { 21 | {"help", "Display this list of commands.", mon_help}, 22 | {"kerninfo", "Display information about the kernel.", mon_kerninfo}, 23 | {"backtrace", "Print backtrace of stack frame.", mon_backtrace}, 24 | }; 25 | 26 | /* return if kernel is panic, in kern/debug/panic.c */ 27 | bool is_kernel_panic(void); 28 | 29 | #define NCOMMANDS (sizeof(commands)/sizeof(struct command)) 30 | 31 | /***** Kernel monitor command interpreter *****/ 32 | 33 | #define MAXARGS 16 34 | #define WHITESPACE " \t\n\r" 35 | 36 | /* parse - parse the command buffer into whitespace-separated arguments */ 37 | static int 38 | parse(char *buf, char **argv) { 39 | int argc = 0; 40 | while (1) { 41 | // find global whitespace 42 | while (*buf != '\0' && strchr(WHITESPACE, *buf) != NULL) { 43 | *buf ++ = '\0'; 44 | } 45 | if (*buf == '\0') { 46 | break; 47 | } 48 | 49 | // save and scan past next arg 50 | if (argc == MAXARGS - 1) { 51 | cprintf("Too many arguments (max %d).\n", MAXARGS); 52 | } 53 | argv[argc ++] = buf; 54 | while (*buf != '\0' && strchr(WHITESPACE, *buf) == NULL) { 55 | buf ++; 56 | } 57 | } 58 | return argc; 59 | } 60 | 61 | /* * 62 | * runcmd - parse the input string, split it into separated arguments 63 | * and then lookup and invoke some related commands/ 64 | * */ 65 | static int 66 | runcmd(char *buf, struct trapframe *tf) { 67 | char *argv[MAXARGS]; 68 | int argc = parse(buf, argv); 69 | if (argc == 0) { 70 | return 0; 71 | } 72 | int i; 73 | for (i = 0; i < NCOMMANDS; i ++) { 74 | if (strcmp(commands[i].name, argv[0]) == 0) { 75 | return commands[i].func(argc - 1, argv + 1, tf); 76 | } 77 | } 78 | cprintf("Unknown command '%s'\n", argv[0]); 79 | return 0; 80 | } 81 | 82 | /***** Implementations of basic kernel monitor commands *****/ 83 | 84 | void 85 | kmonitor(struct trapframe *tf) { 86 | cprintf("Welcome to the kernel debug monitor!!\n"); 87 | cprintf("Type 'help' for a list of commands.\n"); 88 | 89 | if (tf != NULL) { 90 | print_trapframe(tf); 91 | } 92 | 93 | char *buf; 94 | while (1) { 95 | if ((buf = readline("K> ")) != NULL) { 96 | if (runcmd(buf, tf) < 0) { 97 | break; 98 | } 99 | } 100 | } 101 | } 102 | 103 | /* mon_help - print the information about mon_* functions */ 104 | int 105 | mon_help(int argc, char **argv, struct trapframe *tf) { 106 | int i; 107 | for (i = 0; i < NCOMMANDS; i ++) { 108 | cprintf("%s - %s\n", commands[i].name, commands[i].desc); 109 | } 110 | return 0; 111 | } 112 | 113 | /* * 114 | * mon_kerninfo - call print_kerninfo in kern/debug/kdebug.c to 115 | * print the memory occupancy in kernel. 116 | * */ 117 | int 118 | mon_kerninfo(int argc, char **argv, struct trapframe *tf) { 119 | print_kerninfo(); 120 | return 0; 121 | } 122 | 123 | /* * 124 | * mon_backtrace - call print_stackframe in kern/debug/kdebug.c to 125 | * print a backtrace of the stack. 126 | * */ 127 | int 128 | mon_backtrace(int argc, char **argv, struct trapframe *tf) { 129 | print_stackframe(); 130 | return 0; 131 | } 132 | 133 | -------------------------------------------------------------------------------- /code-with-comments/kern/debug/kmonitor.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_DEBUG_MONITOR_H__ 2 | #define __KERN_DEBUG_MONITOR_H__ 3 | 4 | #include 5 | 6 | void kmonitor(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-with-comments/kern/debug/panic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | static bool is_panic = 0; 8 | 9 | /* * 10 | * __panic - __panic is called on unresolvable fatal errors. it prints 11 | * "panic: 'message'", and then enters the kernel monitor. 12 | * */ 13 | void 14 | __panic(const char *file, int line, const char *fmt, ...) { 15 | if (is_panic) { 16 | goto panic_dead; 17 | } 18 | is_panic = 1; 19 | 20 | // print the 'message' 21 | va_list ap; 22 | va_start(ap, fmt); 23 | cprintf("kernel panic at %s:%d:\n ", file, line); 24 | vcprintf(fmt, ap); 25 | cprintf("\n"); 26 | 27 | cprintf("stack trackback:\n"); 28 | print_stackframe(); 29 | 30 | va_end(ap); 31 | 32 | panic_dead: 33 | intr_disable(); 34 | while (1) { 35 | kmonitor(NULL); 36 | } 37 | } 38 | 39 | /* __warn - like panic, but don't */ 40 | void 41 | __warn(const char *file, int line, const char *fmt, ...) { 42 | va_list ap; 43 | va_start(ap, fmt); 44 | cprintf("kernel warning at %s:%d:\n ", file, line); 45 | vcprintf(fmt, ap); 46 | cprintf("\n"); 47 | va_end(ap); 48 | } 49 | 50 | bool 51 | is_kernel_panic(void) { 52 | return is_panic; 53 | } 54 | 55 | -------------------------------------------------------------------------------- /code-with-comments/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-with-comments/kern/driver/clock.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | /* * 7 | * 时间相关硬件的函数封装 - 8253 时钟控制器, 8 | * 在 IRQ-0 生成中断. 9 | * 10 | * 注: 8253内部有三个计数器,分别成为计数器0、计数器1和计数器2. 11 | * 我们只用到 timer1. 12 | * 13 | * 参考 linux 的源码 include/linux/jiffies.h 14 | * http://blog.chinaunix.net/uid-23951161-id-206711.html 15 | * */ 16 | 17 | #define IO_TIMER1 0x040 // 8253 Timer #1 18 | 19 | /* * 20 | * Frequency of all three count-down timers; (TIMER_FREQ/freq) 21 | * is the appropriate count to generate a frequency of freq Hz. 22 | * */ 23 | 24 | 25 | /** 26 | * TIMER_FREQ 是8253 每秒的脉冲个数. 27 | * 要想1 秒内发出中断n 次,就需要 TIMER_FREQ 28 | */ 29 | 30 | #define TIMER_FREQ 1193182 // 输入频率固定,每秒的时钟脉冲个数 31 | #define TIMER_DIV(x) ((TIMER_FREQ + (x) / 2) / (x)) // 分频, 32 | 33 | #define TIMER_MODE (IO_TIMER1 + 3) // timer mode port 34 | #define TIMER_SEL0 0x00 // select counter 0 35 | #define TIMER_RATEGEN 0x04 // mode 2, rate generator 36 | #define TIMER_16BIT 0x30 // r/w counter 16 bits, LSB first 37 | 38 | volatile size_t ticks; 39 | 40 | long SYSTEM_READ_TIMER( void ){ 41 | return ticks; 42 | } 43 | 44 | /* * 45 | * clock_init - initialize 8253 clock to interrupt 100 times per second, 46 | * and then enable IRQ_TIMER. 47 | * 设置时钟每秒中断 100 次,即时钟频率为 100Hz,即两次中断间隔 0.01=10 毫秒 并使能时钟中断 48 | * */ 49 | void 50 | clock_init(void) { 51 | LOG_LINE("初始化开始:时钟控制器"); 52 | 53 | // set 8253 timer-chip 54 | outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT); 55 | // 装入计数器初值 56 | int times_per_second = 100;// ms 57 | outb(IO_TIMER1, TIMER_DIV(times_per_second) % 256); 58 | outb(IO_TIMER1, TIMER_DIV(times_per_second) / 256); 59 | 60 | // initialize time counter 'ticks' to zero 61 | ticks = 0; 62 | pic_enable(IRQ_TIMER); 63 | LOG("clock_init:\n"); 64 | LOG_TAB("每秒脉冲次数:%d\n", times_per_second); 65 | LOG_LINE("初始化完毕:时钟控制器"); 66 | } 67 | 68 | -------------------------------------------------------------------------------- /code-with-comments/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 | long SYSTEM_READ_TIMER( void ); 11 | 12 | 13 | #endif /* !__KERN_DRIVER_CLOCK_H__ */ 14 | 15 | -------------------------------------------------------------------------------- /code-with-comments/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-with-comments/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-with-comments/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-with-comments/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-with-comments/kern/driver/kbdreg.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_DRIVER_KBDREG_H__ 2 | #define __KERN_DRIVER_KBDREG_H__ 3 | 4 | // Special keycodes 5 | #define KEY_HOME 0xE0 6 | #define KEY_END 0xE1 7 | #define KEY_UP 0xE2 8 | #define KEY_DN 0xE3 9 | #define KEY_LF 0xE4 10 | #define KEY_RT 0xE5 11 | #define KEY_PGUP 0xE6 12 | #define KEY_PGDN 0xE7 13 | #define KEY_INS 0xE8 14 | #define KEY_DEL 0xE9 15 | 16 | 17 | /* This is i8042reg.h + kbdreg.h from NetBSD. */ 18 | 19 | #define KBSTATP 0x64 // kbd controller status port(I) 20 | #define KBS_DIB 0x01 // kbd data in buffer 21 | #define KBS_IBF 0x02 // kbd input buffer low 22 | #define KBS_WARM 0x04 // kbd input buffer low 23 | #define BS_OCMD 0x08 // kbd output buffer has command 24 | #define KBS_NOSEC 0x10 // kbd security lock not engaged 25 | #define KBS_TERR 0x20 // kbd transmission error 26 | #define KBS_RERR 0x40 // kbd receive error 27 | #define KBS_PERR 0x80 // kbd parity error 28 | 29 | #define KBCMDP 0x64 // kbd controller port(O) 30 | #define KBC_RAMREAD 0x20 // read from RAM 31 | #define KBC_RAMWRITE 0x60 // write to RAM 32 | #define KBC_AUXDISABLE 0xa7 // disable auxiliary port 33 | #define KBC_AUXENABLE 0xa8 // enable auxiliary port 34 | #define KBC_AUXTEST 0xa9 // test auxiliary port 35 | #define KBC_KBDECHO 0xd2 // echo to keyboard port 36 | #define KBC_AUXECHO 0xd3 // echo to auxiliary port 37 | #define KBC_AUXWRITE 0xd4 // write to auxiliary port 38 | #define KBC_SELFTEST 0xaa // start self-test 39 | #define KBC_KBDTEST 0xab // test keyboard port 40 | #define KBC_KBDDISABLE 0xad // disable keyboard port 41 | #define KBC_KBDENABLE 0xae // enable keyboard port 42 | #define KBC_PULSE0 0xfe // pulse output bit 0 43 | #define KBC_PULSE1 0xfd // pulse output bit 1 44 | #define KBC_PULSE2 0xfb // pulse output bit 2 45 | #define KBC_PULSE3 0xf7 // pulse output bit 3 46 | 47 | #define KBDATAP 0x60 // kbd data port(I) 48 | #define KBOUTP 0x60 // kbd data port(O) 49 | 50 | #define K_RDCMDBYTE 0x20 51 | #define K_LDCMDBYTE 0x60 52 | 53 | #define KC8_TRANS 0x40 // convert to old scan codes 54 | #define KC8_MDISABLE 0x20 // disable mouse 55 | #define KC8_KDISABLE 0x10 // disable keyboard 56 | #define KC8_IGNSEC 0x08 // ignore security lock 57 | #define KC8_CPU 0x04 // exit from protected mode reset 58 | #define KC8_MENABLE 0x02 // enable mouse interrupt 59 | #define KC8_KENABLE 0x01 // enable keyboard interrupt 60 | #define CMDBYTE (KC8_TRANS|KC8_CPU|KC8_MENABLE|KC8_KENABLE) 61 | 62 | /* keyboard commands */ 63 | #define KBC_RESET 0xFF // reset the keyboard 64 | #define KBC_RESEND 0xFE // request the keyboard resend the last byte 65 | #define KBC_SETDEFAULT 0xF6 // resets keyboard to its power-on defaults 66 | #define KBC_DISABLE 0xF5 // as per KBC_SETDEFAULT, but also disable key scanning 67 | #define KBC_ENABLE 0xF4 // enable key scanning 68 | #define KBC_TYPEMATIC 0xF3 // set typematic rate and delay 69 | #define KBC_SETTABLE 0xF0 // set scancode translation table 70 | #define KBC_MODEIND 0xED // set mode indicators(i.e. LEDs) 71 | #define KBC_ECHO 0xEE // request an echo from the keyboard 72 | 73 | /* keyboard responses */ 74 | #define KBR_EXTENDED 0xE0 // extended key sequence 75 | #define KBR_RESEND 0xFE // needs resend of command 76 | #define KBR_ACK 0xFA // received a valid command 77 | #define KBR_OVERRUN 0x00 // flooded 78 | #define KBR_FAILURE 0xFD // diagnosic failure 79 | #define KBR_BREAK 0xF0 // break code prefix - sent on key release 80 | #define KBR_RSTDONE 0xAA // reset complete 81 | #define KBR_ECHO 0xEE // echo response 82 | 83 | #endif /* !__KERN_DRIVER_KBDREG_H__ */ 84 | 85 | -------------------------------------------------------------------------------- /code-with-comments/kern/driver/picirq.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // I/O Addresses of the two programmable interrupt controllers 7 | #define IO_PIC1 0x20 // Master (IRQs 0-7) 8 | #define IO_PIC2 0xA0 // Slave (IRQs 8-15) 9 | 10 | #define IRQ_SLAVE 2 // IRQ at which slave connects to master 11 | 12 | // Current IRQ mask. 13 | // Initial IRQ mask has interrupt 2 enabled (for slave 8259A). 14 | static uint16_t irq_mask = 0xFFFF & ~(1 << IRQ_SLAVE); 15 | static bool did_init = 0; 16 | 17 | static void 18 | pic_setmask(uint16_t mask) { 19 | irq_mask = mask; 20 | if (did_init) { 21 | outb(IO_PIC1 + 1, mask); 22 | outb(IO_PIC2 + 1, mask >> 8); 23 | } 24 | } 25 | 26 | void 27 | pic_enable(unsigned int irq) { 28 | pic_setmask(irq_mask & ~(1 << irq)); 29 | } 30 | 31 | /* pic_init - initialize the 8259A interrupt controllers */ 32 | void 33 | pic_init(void) { 34 | did_init = 1; 35 | 36 | // mask all interrupts 37 | outb(IO_PIC1 + 1, 0xFF); 38 | outb(IO_PIC2 + 1, 0xFF); 39 | 40 | // Set up master (8259A-1) 41 | 42 | // ICW1: 0001g0hi 43 | // g: 0 = edge triggering, 1 = level triggering 44 | // h: 0 = cascaded PICs, 1 = master only 45 | // i: 0 = no ICW4, 1 = ICW4 required 46 | outb(IO_PIC1, 0x11); 47 | 48 | // ICW2: Vector offset 49 | outb(IO_PIC1 + 1, IRQ_OFFSET); 50 | 51 | // ICW3: (master PIC) bit mask of IR lines connected to slaves 52 | // (slave PIC) 3-bit # of slave's connection to master 53 | outb(IO_PIC1 + 1, 1 << IRQ_SLAVE); 54 | 55 | // ICW4: 000nbmap 56 | // n: 1 = special fully nested mode 57 | // b: 1 = buffered mode 58 | // m: 0 = slave PIC, 1 = master PIC 59 | // (ignored when b is 0, as the master/slave role 60 | // can be hardwired). 61 | // a: 1 = Automatic EOI mode 62 | // p: 0 = MCS-80/85 mode, 1 = intel x86 mode 63 | outb(IO_PIC1 + 1, 0x3); 64 | 65 | // Set up slave (8259A-2) 66 | outb(IO_PIC2, 0x11); // ICW1 67 | outb(IO_PIC2 + 1, IRQ_OFFSET + 8); // ICW2 68 | outb(IO_PIC2 + 1, IRQ_SLAVE); // ICW3 69 | // NB Automatic EOI mode doesn't tend to work on the slave. 70 | // Linux source code says it's "to be investigated". 71 | outb(IO_PIC2 + 1, 0x3); // ICW4 72 | 73 | // OCW3: 0ef01prs 74 | // ef: 0x = NOP, 10 = clear specific mask, 11 = set specific mask 75 | // p: 0 = no polling, 1 = polling mode 76 | // rs: 0x = NOP, 10 = read IRR, 11 = read ISR 77 | outb(IO_PIC1, 0x68); // clear specific mask 78 | outb(IO_PIC1, 0x0a); // read IRR by default 79 | 80 | outb(IO_PIC2, 0x68); // OCW3 81 | outb(IO_PIC2, 0x0a); // OCW3 82 | 83 | if (irq_mask != 0xFFFF) { 84 | pic_setmask(irq_mask); 85 | } 86 | LOG_LINE("初始化完毕:中断控制器"); 87 | } 88 | 89 | -------------------------------------------------------------------------------- /code-with-comments/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-with-comments/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 | * device 代表一个设备文件. Filesystem-namespace-accessible device. 11 | * 区别于普通文件 sfs_inode 12 | * 13 | * 此支持对块设备(比如磁盘)、字符设备(比如键盘、串口)的表示. 14 | * d_io 可以用于读和写. 其中的参数iobuf 指明读写方向. 15 | */ 16 | struct device { 17 | size_t d_blocks; // 设备占用的数据块的个数 18 | size_t d_blocksize; // 每个数据块的大小 19 | // 以下是函数指针 20 | int (*d_open)(struct device *dev, uint32_t open_flags); // 打开设备 21 | int (*d_close)(struct device *dev); // 关闭设备 22 | int (*d_io)(struct device *dev, struct iobuf *iob, bool write); // 读写设备 23 | int (*d_ioctl)(struct device *dev, int op, void *data); // 用ioctl方式控制设备 24 | }; 25 | 26 | #define dop_open(dev, open_flags) ((dev)->d_open(dev, open_flags)) 27 | #define dop_close(dev) ((dev)->d_close(dev)) 28 | // 设备操作 IO 接口 29 | #define dop_io(dev, iob, write) ((dev)->d_io(dev, iob, write)) 30 | #define dop_ioctl(dev, op, data) ((dev)->d_ioctl(dev, op, data)) 31 | 32 | void dev_init(void); 33 | struct inode *dev_create_inode(void); 34 | 35 | #endif /* !__KERN_FS_DEVS_DEV_H__ */ 36 | 37 | -------------------------------------------------------------------------------- /code-with-comments/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 | #include 15 | 16 | #define STDIN_BUFSIZE 4096 17 | 18 | static char stdin_buffer[STDIN_BUFSIZE]; 19 | static off_t p_rpos, p_wpos; 20 | static wait_queue_t __wait_queue, *wait_queue = &__wait_queue; 21 | 22 | void 23 | dev_stdin_write(char c) { 24 | LOG("dev_stdin_write:\n"); 25 | bool intr_flag; 26 | if (c != '\0') { 27 | local_intr_save(intr_flag); 28 | { 29 | stdin_buffer[p_wpos % STDIN_BUFSIZE] = c; 30 | if (p_wpos - p_rpos < STDIN_BUFSIZE) { 31 | p_wpos ++; 32 | } 33 | if (!wait_queue_empty(wait_queue)) { 34 | wakeup_queue(wait_queue, WT_KBD, 1); 35 | } 36 | } 37 | local_intr_restore(intr_flag); 38 | } 39 | } 40 | 41 | static int 42 | dev_stdin_read(char *buf, size_t len) { 43 | int ret = 0; 44 | bool intr_flag; 45 | local_intr_save(intr_flag); 46 | { 47 | for (; ret < len; ret ++, p_rpos ++) { 48 | try_again: 49 | if (p_rpos < p_wpos) { 50 | *buf ++ = stdin_buffer[p_rpos % STDIN_BUFSIZE]; 51 | } 52 | else { 53 | wait_t __wait, *wait = &__wait; 54 | // 切换至睡眠状态,进入等待队列 55 | wait_current_set(wait_queue, wait, WT_KBD); 56 | local_intr_restore(intr_flag); 57 | 58 | schedule(); 59 | 60 | local_intr_save(intr_flag); 61 | wait_current_del(wait_queue, wait); 62 | if (wait->wakeup_flags == WT_KBD) { 63 | goto try_again; 64 | } 65 | break; 66 | } 67 | } 68 | } 69 | local_intr_restore(intr_flag); 70 | return ret; 71 | } 72 | 73 | static int 74 | stdin_open(struct device *dev, uint32_t open_flags) { 75 | if (open_flags != O_RDONLY) { 76 | return -E_INVAL; 77 | } 78 | return 0; 79 | } 80 | 81 | static int 82 | stdin_close(struct device *dev) { 83 | return 0; 84 | } 85 | 86 | static int 87 | stdin_io(struct device *dev, struct iobuf *iob, bool write) { 88 | if (!write) { 89 | int ret; 90 | if ((ret = dev_stdin_read(iob->io_base, iob->io_resid)) > 0) { 91 | iob->io_resid -= ret; 92 | } 93 | return ret; 94 | } 95 | return -E_INVAL; 96 | } 97 | 98 | static int 99 | stdin_ioctl(struct device *dev, int op, void *data) { 100 | return -E_INVAL; 101 | } 102 | 103 | static void 104 | stdin_device_init(struct device *dev) { 105 | LOG("stdin_device_init:\n"); 106 | dev->d_blocks = 0; 107 | dev->d_blocksize = 1; 108 | dev->d_open = stdin_open; 109 | dev->d_close = stdin_close; 110 | dev->d_io = stdin_io; 111 | dev->d_ioctl = stdin_ioctl; 112 | p_rpos = p_wpos = 0; 113 | wait_queue_init(wait_queue); 114 | LOG_TAB("stdin inode 的 device 部分初始化完毕.\n"); 115 | LOG_TAB("初始化完毕: stdin 等待队列.\n"); 116 | } 117 | 118 | void 119 | dev_init_stdin(void) { 120 | LOG("dev_init_stdin:\n"); 121 | struct inode *node; 122 | if ((node = dev_create_inode()) == NULL) { 123 | panic("stdin: dev_create_node.\n"); 124 | } 125 | LOG_TAB("已创建 stdin inode, 类型为 device\n"); 126 | stdin_device_init(vop_info(node, device)); 127 | 128 | int ret; 129 | if ((ret = vfs_add_dev("stdin", node, 0)) != 0) { 130 | panic("stdin: vfs_add_dev: %e.\n", ret); 131 | } 132 | LOG_TAB("已将 stdin inode 加入到 vdev_list.\n"); 133 | } 134 | 135 | -------------------------------------------------------------------------------- /code-with-comments/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-with-comments/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 | /* 15 | * 文件, 16 | * 17 | * 从进程的角度描述了一个进程在访问文件时需要了解的: 18 | * - 文件标识 19 | * - 文件读写的位置 20 | * - 文件引用情况 21 | * 22 | * 作用范围是某一具体进程 23 | */ 24 | struct file { 25 | enum { 26 | // 文件状态: 不存在/已初始化/已打开/已关闭 27 | FD_NONE, FD_INIT, FD_OPENED, FD_CLOSED, 28 | } status; 29 | bool readable; 30 | bool writable; 31 | int fd; // 文件在 filemap 中的索引值 32 | off_t pos; // 当前位置 33 | struct inode *node; // 该文件对应的 inode 指针 34 | int open_count; // 打开此文件的次数 35 | }; 36 | 37 | void fd_array_init(struct file *fd_array); 38 | void fd_array_open(struct file *file); 39 | void fd_array_close(struct file *file); 40 | void fd_array_dup(struct file *to, struct file *from); 41 | bool file_testfd(int fd, bool readable, bool writable); 42 | 43 | int file_open(char *path, uint32_t open_flags); 44 | int file_close(int fd); 45 | int file_read(int fd, void *base, size_t len, size_t *copied_store); 46 | int file_write(int fd, void *base, size_t len, size_t *copied_store); 47 | int file_seek(int fd, off_t pos, int whence); 48 | int file_fstat(int fd, struct stat *stat); 49 | int file_fsync(int fd); 50 | int file_getdirentry(int fd, struct dirent *dirent); 51 | int file_dup(int fd1, int fd2); 52 | int file_pipe(int fd[]); 53 | int file_mkfifo(const char *name, uint32_t open_flags); 54 | 55 | static inline int 56 | fopen_count(struct file *file) { 57 | return file->open_count; 58 | } 59 | 60 | static inline int 61 | fopen_count_inc(struct file *file) { 62 | file->open_count += 1; 63 | return file->open_count; 64 | } 65 | 66 | static inline int 67 | fopen_count_dec(struct file *file) { 68 | file->open_count -= 1; 69 | return file->open_count; 70 | } 71 | 72 | #endif /* !__KERN_FS_FILE_H__ */ 73 | 74 | -------------------------------------------------------------------------------- /code-with-comments/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 | //called when init_main proc start 12 | void 13 | fs_init(void) { 14 | LOG_LINE("初始化开始:文件系统"); 15 | LOG("fs_init:\n"); 16 | 17 | vfs_init(); 18 | LOG_TAB("初始化完毕:vfs\n"); 19 | dev_init(); 20 | LOG_TAB("初始化完毕:dev\n"); 21 | sfs_init(); 22 | LOG_TAB("初始化完毕:sfs\n"); 23 | 24 | LOG_LINE("初始化完毕:文件系统"); 25 | } 26 | 27 | void 28 | fs_cleanup(void) { 29 | vfs_cleanup(); 30 | } 31 | 32 | void 33 | lock_files(struct files_struct *filesp) { 34 | down(&(filesp->files_sem)); 35 | } 36 | 37 | void 38 | unlock_files(struct files_struct *filesp) { 39 | up(&(filesp->files_sem)); 40 | } 41 | 42 | /* 43 | * 创建一个进程的文件列表. 44 | * 45 | * 用于新进程的初始化. 46 | */ 47 | struct files_struct * 48 | files_create(void) { 49 | //LOG("[files_create]\n"); 50 | static_assert((int)FILES_STRUCT_NENTRY > 128); 51 | struct files_struct *filesp; 52 | // 1. 分配两块内存用于存储文件结构体+fd 数组.内存大小为一整页. 53 | if ((filesp = kmalloc(sizeof(struct files_struct) + FILES_STRUCT_BUFSIZE)) != NULL) { 54 | // 2. 当前工作目录是 NULL 55 | filesp->pwd = NULL; 56 | // 打开的文件列表是 57 | filesp->fd_array = (void *)(filesp + 1); 58 | filesp->files_count = 0; 59 | sem_init(&(filesp->files_sem), 1); 60 | fd_array_init(filesp->fd_array); 61 | } 62 | return filesp; 63 | } 64 | //Called when a proc exit 65 | void 66 | files_destroy(struct files_struct *filesp) { 67 | // LOG("[files_destroy]\n"); 68 | assert(filesp != NULL && files_count(filesp) == 0); 69 | if (filesp->pwd != NULL) { 70 | vop_ref_dec(filesp->pwd); 71 | } 72 | int i; 73 | struct file *file = filesp->fd_array; 74 | for (i = 0; i < FILES_STRUCT_NENTRY; i ++, file ++) { 75 | if (file->status == FD_OPENED) { 76 | fd_array_close(file); 77 | } 78 | assert(file->status == FD_NONE); 79 | } 80 | kfree(filesp); 81 | } 82 | 83 | void 84 | files_closeall(struct files_struct *filesp) { 85 | // LOG("[files_closeall]\n"); 86 | assert(filesp != NULL && files_count(filesp) > 0); 87 | int i; 88 | struct file *file = filesp->fd_array; 89 | //skip the stdin & stdout 90 | for (i = 2, file += 2; i < FILES_STRUCT_NENTRY; i ++, file ++) { 91 | if (file->status == FD_OPENED) { 92 | fd_array_close(file); 93 | } 94 | } 95 | } 96 | 97 | int 98 | dup_files(struct files_struct *to, struct files_struct *from) { 99 | // LOG("[dup_files]\n"); 100 | assert(to != NULL && from != NULL); 101 | assert(files_count(to) == 0 && files_count(from) > 0); 102 | if ((to->pwd = from->pwd) != NULL) { 103 | vop_ref_inc(to->pwd); 104 | } 105 | int i; 106 | struct file *to_file = to->fd_array, *from_file = from->fd_array; 107 | for (i = 0; i < FILES_STRUCT_NENTRY; i ++, to_file ++, from_file ++) { 108 | if (from_file->status == FD_OPENED) { 109 | /* alloc_fd first */ 110 | to_file->status = FD_INIT; 111 | fd_array_dup(to_file, from_file); 112 | } 113 | } 114 | return 0; 115 | } 116 | 117 | -------------------------------------------------------------------------------- /code-with-comments/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 | #define DISK1_DEV_NO 3 15 | 16 | // fs.[hc] 将文件视为进程资源并从进程的视角对其管理 17 | 18 | void fs_init(void); 19 | void fs_cleanup(void); 20 | 21 | struct inode; 22 | struct file; 23 | 24 | /* 25 | * 进程的文件控制块 26 | */ 27 | struct files_struct { 28 | struct inode *pwd; // inode, 当前工作目录 29 | struct file *fd_array; // open 的文件列表 30 | int files_count; // open 的文件的个数 31 | semaphore_t files_sem; // lock protect sem 32 | }; 33 | 34 | #define FILES_STRUCT_BUFSIZE (PGSIZE - sizeof(struct files_struct)) 35 | #define FILES_STRUCT_NENTRY (FILES_STRUCT_BUFSIZE / sizeof(struct file)) 36 | 37 | void lock_files(struct files_struct *filesp); 38 | void unlock_files(struct files_struct *filesp); 39 | 40 | struct files_struct *files_create(void); 41 | void files_destroy(struct files_struct *filesp); 42 | void files_closeall(struct files_struct *filesp); 43 | int dup_files(struct files_struct *to, struct files_struct *from); 44 | 45 | static inline int 46 | files_count(struct files_struct *filesp) { 47 | return filesp->files_count; 48 | } 49 | 50 | static inline int 51 | files_count_inc(struct files_struct *filesp) { 52 | filesp->files_count += 1; 53 | return filesp->files_count; 54 | } 55 | 56 | static inline int 57 | files_count_dec(struct files_struct *filesp) { 58 | filesp->files_count -= 1; 59 | return filesp->files_count; 60 | } 61 | 62 | #endif /* !__KERN_FS_FS_H__ */ 63 | 64 | -------------------------------------------------------------------------------- /code-with-comments/kern/fs/iobuf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | 10 | /* 11 | * iobuf_init - init io buffer struct. 12 | * set up io_base to point to the buffer you want to transfer to, and set io_len to the length of buffer; 13 | * initialize io_offset as desired; 14 | * initialize io_resid to the total amount of data that can be transferred through this io. 15 | */ 16 | struct iobuf * 17 | iobuf_init(struct iobuf *iob, void *base, size_t len, off_t offset) { 18 | LOG("iobuf_init:\n"); 19 | iob->io_base = base; 20 | iob->io_offset = offset; 21 | iob->io_len = iob->io_resid = len; 22 | return iob; 23 | } 24 | 25 | /* iobuf_move - move data (iob->io_base ---> data OR data --> iob->io.base) in memory 26 | * @copiedp: the size of data memcopied 27 | * 28 | * iobuf_move may be called repeatedly on the same io to transfer 29 | * additional data until the available buffer space the io refers to 30 | * is exhausted. 31 | * 32 | * iobuffer 与 内存 data 之间的数据转移(复制) 33 | * 34 | * 若m2b=0,则从内存 buffer到设备 data 35 | * 若 m2b=1,则从设备data到内存 buffer 36 | */ 37 | //iobuf_move(iob, disk0_buffer, alen, 1, &copied); 38 | int 39 | iobuf_move(struct iobuf *iob, void *data, size_t len, bool m2b, size_t *copiedp) { 40 | size_t alen; 41 | if ((alen = iob->io_resid) > len) { 42 | alen = len; 43 | } 44 | if (alen > 0) { 45 | void *src = iob->io_base, *dst = data; 46 | if (m2b) {//read. 47 | void *tmp = src; 48 | src = dst, dst = tmp; 49 | } 50 | memmove(dst, src, alen); 51 | iobuf_skip(iob, alen), len -= alen; 52 | } 53 | if (copiedp != NULL) { 54 | *copiedp = alen; 55 | } 56 | return (len == 0) ? 0 : -E_NO_MEM; 57 | } 58 | 59 | /* 60 | * iobuf_move_zeros - set io buffer zero 61 | * @copiedp: the size of data memcopied 62 | */ 63 | int 64 | iobuf_move_zeros(struct iobuf *iob, size_t len, size_t *copiedp) { 65 | size_t alen; 66 | if ((alen = iob->io_resid) > len) { 67 | alen = len; 68 | } 69 | if (alen > 0) { 70 | memset(iob->io_base, 0, alen); 71 | iobuf_skip(iob, alen), len -= alen; 72 | } 73 | if (copiedp != NULL) { 74 | *copiedp = alen; 75 | } 76 | return (len == 0) ? 0 : -E_NO_MEM; 77 | } 78 | 79 | /* 80 | * iobuf_skip - change the current position of io buffer 81 | * iobuf向高地址方向移动 n 个字节. 82 | */ 83 | void 84 | iobuf_skip(struct iobuf *iob, size_t n) { 85 | assert(iob->io_resid >= n); 86 | iob->io_base += n, iob->io_offset += n, iob->io_resid -= n; 87 | } 88 | 89 | -------------------------------------------------------------------------------- /code-with-comments/kern/fs/iobuf.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_FS_IOBUF_H__ 2 | #define __KERN_FS_IOBUF_H__ 3 | 4 | #include 5 | 6 | // 参考陈老师另一个实现的注释: https://github.com/chyyuu/ucore-x64-with-golang/blob/master/ucore/src/kern-ucore/fs/iobuf.h 7 | 8 | 9 | /** 10 | * 此 iobuf是模仿自 BSD 的 uio 简化而来,参考 https://www.freebsd.org/cgi/man.cgi?query=uio&sektion=9&manpath=freebsd-release-ports 11 | * 12 | * 在 ucore 中,用于用户地址与内核地址之间的数据复制. 13 | * 此结构用一些字段"定义"了内存中的一段目标地址. 14 | * 可以理解为一个"消息",描述了要传输数据使用的信息 15 | * 16 | * 17 | * 使用模式: 18 | * 19 | * 1. 设定目标设备的地址 io_offset 20 | * 2. 设定内存地址 io_base,内存 buffer 长度 io_len 21 | * 3. 设定需要传输的数据总量,一般与 io_len 相等 22 | * 23 | * 24 | * 25 | * 26 | */ 27 | 28 | /* 29 | * iobuf is a buffer Rd/Wr status record 30 | * 31 | * io buffer : 读写状态记录器 32 | * 33 | * io_base : 内存目标地址 34 | * io_len : buffer 长度 35 | * io_resid : 还剩多少没有传输完毕 36 | * io_offset: 在目标对象(设备)中的偏移量 37 | */ 38 | struct iobuf { 39 | void *io_base; // the base addr of buffer (used for Rd/Wr) 40 | off_t io_offset; // current Rd/Wr position in buffer, will have been incremented by the amount transferred 41 | size_t io_len; // the length of buffer (used for Rd/Wr) 42 | size_t io_resid; // current resident length need to Rd/Wr, will have been decremented by the amount transferred. 43 | }; 44 | 45 | // "use" 是指已经拷贝了的数量. 46 | #define iobuf_used(iob) ((size_t)((iob)->io_len - (iob)->io_resid)) 47 | 48 | struct iobuf *iobuf_init(struct iobuf *iob, void *base, size_t len, off_t offset); 49 | int iobuf_move(struct iobuf *iob, void *data, size_t len, bool m2b, size_t *copiedp); 50 | int iobuf_move_zeros(struct iobuf *iob, size_t len, size_t *copiedp); 51 | void iobuf_skip(struct iobuf *iob, size_t n); 52 | 53 | #endif /* !__KERN_FS_IOBUF_H__ */ 54 | 55 | -------------------------------------------------------------------------------- /code-with-comments/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) //4*8 10 | 11 | struct bitmap { 12 | uint32_t nbits; // bitmap 总位数 13 | uint32_t nwords; // bitmap 总word数, 14 | WORD_TYPE *map; // 指向位图起始地址 15 | }; 16 | 17 | // bitmap_create - allocate a new bitmap object. 18 | // 创建一个 nbits 位的 bitmap 19 | struct bitmap * 20 | bitmap_create(uint32_t nbits) { 21 | static_assert(WORD_BITS != 0); 22 | assert(nbits != 0 && nbits + WORD_BITS > nbits); 23 | 24 | struct bitmap *bitmap; 25 | if ((bitmap = kmalloc(sizeof(struct bitmap))) == NULL) { 26 | return NULL; 27 | } 28 | 29 | uint32_t nwords = ROUNDUP_DIV(nbits, WORD_BITS); 30 | WORD_TYPE *map; 31 | if ((map = kmalloc(sizeof(WORD_TYPE) * nwords)) == NULL) { 32 | kfree(bitmap); 33 | return NULL; 34 | } 35 | 36 | bitmap->nbits = nbits, bitmap->nwords = nwords; 37 | bitmap->map = memset(map, 0xFF, sizeof(WORD_TYPE) * nwords); 38 | 39 | /* mark any leftover bits at the end in use(0) */ 40 | if (nbits != nwords * WORD_BITS) { 41 | uint32_t ix = nwords - 1, overbits = nbits - ix * WORD_BITS; 42 | 43 | assert(nbits / WORD_BITS == ix); 44 | assert(overbits > 0 && overbits < WORD_BITS); 45 | 46 | for (; overbits < WORD_BITS; overbits ++) { 47 | bitmap->map[ix] ^= (1 << overbits); 48 | } 49 | } 50 | return bitmap; 51 | } 52 | 53 | // bitmap_alloc - locate a cleared bit, set it, and return its index. 54 | int 55 | bitmap_alloc(struct bitmap *bitmap, uint32_t *index_store) { 56 | WORD_TYPE *map = bitmap->map; 57 | uint32_t ix, offset, nwords = bitmap->nwords; 58 | for (ix = 0; ix < nwords; ix ++) { 59 | if (map[ix] != 0) { 60 | for (offset = 0; offset < WORD_BITS; offset ++) { 61 | WORD_TYPE mask = (1 << offset); 62 | if (map[ix] & mask) { 63 | map[ix] ^= mask; 64 | *index_store = ix * WORD_BITS + offset; 65 | return 0; 66 | } 67 | } 68 | assert(0); 69 | } 70 | } 71 | return -E_NO_MEM; 72 | } 73 | 74 | // bitmap_translate - according index, get the related word and mask 75 | static void 76 | bitmap_translate(struct bitmap *bitmap, uint32_t index, WORD_TYPE **word, WORD_TYPE *mask) { 77 | assert(index < bitmap->nbits); 78 | uint32_t ix = index / WORD_BITS, offset = index % WORD_BITS; 79 | *word = bitmap->map + ix; 80 | *mask = (1 << offset); 81 | } 82 | 83 | // bitmap_test - according index, get the related value (0 OR 1) in the bitmap 84 | bool 85 | bitmap_test(struct bitmap *bitmap, uint32_t index) { 86 | WORD_TYPE *word, mask; 87 | bitmap_translate(bitmap, index, &word, &mask); 88 | return (*word & mask); 89 | } 90 | 91 | // bitmap_free - according index, set related bit to 1 92 | void 93 | bitmap_free(struct bitmap *bitmap, uint32_t index) { 94 | WORD_TYPE *word, mask; 95 | bitmap_translate(bitmap, index, &word, &mask); 96 | assert(!(*word & mask)); 97 | *word |= mask; 98 | } 99 | 100 | // bitmap_destroy - free memory contains bitmap 101 | void 102 | bitmap_destroy(struct bitmap *bitmap) { 103 | kfree(bitmap->map); 104 | kfree(bitmap); 105 | } 106 | 107 | // bitmap_getdata - return bitmap->map, return the length of bits to len_store 108 | void * 109 | bitmap_getdata(struct bitmap *bitmap, size_t *len_store) { 110 | if (len_store != NULL) { 111 | *len_store = sizeof(WORD_TYPE) * bitmap->nwords; 112 | } 113 | return bitmap->map; 114 | } 115 | 116 | -------------------------------------------------------------------------------- /code-with-comments/kern/fs/sfs/bitmap.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_FS_SFS_BITMAP_H__ 2 | #define __KERN_FS_SFS_BITMAP_H__ 3 | 4 | #include 5 | 6 | 7 | /* 8 | * Fixed-size array of bits. (Intended for storage management.) 9 | * 10 | * Functions: 11 | * bitmap_create - allocate a new bitmap object. 12 | * Returns NULL on error. 13 | * bitmap_getdata - return pointer to raw bit data (for I/O). 14 | * bitmap_alloc - locate a cleared bit, set it, and return its index. 15 | * bitmap_mark - set a clear bit by its index. 16 | * bitmap_unmark - clear a set bit by its index. 17 | * bitmap_isset - return whether a particular bit is set or not. 18 | * bitmap_destroy - destroy bitmap. 19 | */ 20 | 21 | 22 | struct bitmap; 23 | 24 | struct bitmap *bitmap_create(uint32_t nbits); // allocate a new bitmap object. 25 | int bitmap_alloc(struct bitmap *bitmap, uint32_t *index_store); // locate a cleared bit, set it, and return its index. 26 | bool bitmap_test(struct bitmap *bitmap, uint32_t index); // return whether a particular bit is set or not. 27 | void bitmap_free(struct bitmap *bitmap, uint32_t index); // according index, set related bit to 1 28 | void bitmap_destroy(struct bitmap *bitmap); // free memory contains bitmap 29 | void *bitmap_getdata(struct bitmap *bitmap, size_t *len_store); // return pointer to raw bit data (for I/O) 30 | 31 | #endif /* !__KERN_FS_SFS_BITMAP_H__ */ 32 | 33 | -------------------------------------------------------------------------------- /code-with-comments/kern/fs/sfs/sfs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | /* 8 | * sfs_init - mount sfs on disk0 9 | * 10 | * CALL GRAPH: 11 | * kern_init-->fs_init-->sfs_init 12 | */ 13 | void 14 | sfs_init(void) { 15 | LOG("sfs_init:\n"); 16 | int ret; 17 | if ((ret = sfs_mount("disk0")) != 0) { 18 | panic("failed: sfs: sfs_mount: %e.\n", ret); 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /code-with-comments/kern/fs/sfs/sfs_lock.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | 6 | /* 7 | * lock_sfs_fs - lock the process of SFS Filesystem Rd/Wr Disk Block 8 | * 9 | * called by: sfs_load_inode, sfs_sync, sfs_reclaim 10 | */ 11 | void 12 | lock_sfs_fs(struct sfs_fs *sfs) { 13 | down(&(sfs->fs_sem)); 14 | } 15 | 16 | /* 17 | * lock_sfs_io - lock the process of SFS File Rd/Wr Disk Block 18 | * 19 | * called by: sfs_rwblock, sfs_clear_block, sfs_sync_super 20 | */ 21 | void 22 | lock_sfs_io(struct sfs_fs *sfs) { 23 | down(&(sfs->io_sem)); 24 | } 25 | 26 | /* 27 | * unlock_sfs_fs - unlock the process of SFS Filesystem Rd/Wr Disk Block 28 | * 29 | * called by: sfs_load_inode, sfs_sync, sfs_reclaim 30 | */ 31 | void 32 | unlock_sfs_fs(struct sfs_fs *sfs) { 33 | up(&(sfs->fs_sem)); 34 | } 35 | 36 | /* 37 | * unlock_sfs_io - unlock the process of sfs Rd/Wr Disk Block 38 | * 39 | * called by: sfs_rwblock sfs_clear_block sfs_sync_super 40 | */ 41 | void 42 | unlock_sfs_io(struct sfs_fs *sfs) { 43 | up(&(sfs->io_sem)); 44 | } 45 | -------------------------------------------------------------------------------- /code-with-comments/kern/fs/swap/swapfs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | void 12 | swapfs_init(void) { 13 | static_assert((PGSIZE % SECTSIZE) == 0); 14 | if (!ide_device_valid(SWAP_DEV_NO)) { 15 | panic("swap fs isn't available.\n"); 16 | } 17 | max_swap_offset = ide_device_size(SWAP_DEV_NO) / (PGSIZE / SECTSIZE); 18 | LOG("swapfs_init: 交换分区条件已满足: 分页大小是扇区大小的整数倍.\n"); 19 | LOG_TAB("已将 %d 号ide磁盘设为交换分区.\n",SWAP_DEV_NO); 20 | LOG_TAB("此磁盘大小为 %u byte\n",ide_device_size(SWAP_DEV_NO)); 21 | LOG("swapfs_init end.\n"); 22 | } 23 | 24 | int 25 | swapfs_read(swap_entry_t entry, struct Page *page) { 26 | return ide_read_secs(SWAP_DEV_NO, swap_offset(entry) * PAGE_NSECT, page2kva(page), PAGE_NSECT); 27 | } 28 | 29 | int 30 | swapfs_write(swap_entry_t entry, struct Page *page) { 31 | return ide_write_secs(SWAP_DEV_NO, swap_offset(entry) * PAGE_NSECT, page2kva(page), PAGE_NSECT); 32 | } 33 | 34 | -------------------------------------------------------------------------------- /code-with-comments/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-with-comments/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); // Open or create a file. FLAGS/MODE per the syscall. 10 | int sysfile_close(int fd); // Close a vnode opened 11 | int sysfile_read(int fd, void *base, size_t len); // Read file 12 | int sysfile_write(int fd, void *base, size_t len); // Write file 13 | int sysfile_seek(int fd, off_t pos, int whence); // Seek file 14 | int sysfile_fstat(int fd, struct stat *stat); // Stat file 15 | int sysfile_fsync(int fd); // Sync file 16 | int sysfile_chdir(const char *path); // change DIR 17 | int sysfile_mkdir(const char *path); // create DIR 18 | int sysfile_link(const char *path1, const char *path2); // set a path1's link as path2 19 | int sysfile_rename(const char *path1, const char *path2); // rename file 20 | int sysfile_unlink(const char *path); // unlink a path 21 | int sysfile_getcwd(char *buf, size_t len); // get current working directory 22 | int sysfile_getdirentry(int fd, struct dirent *direntp); // get the file entry in DIR 23 | int sysfile_dup(int fd1, int fd2); // duplicate file 24 | int sysfile_pipe(int *fd_store); // build PIPE 25 | int sysfile_mkfifo(const char *name, uint32_t open_flags); // build named PIPE 26 | 27 | #endif /* !__KERN_FS_SYSFILE_H__ */ 28 | 29 | -------------------------------------------------------------------------------- /code-with-comments/kern/fs/vfs/inode.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | /* 13 | * 分配一个 inode 结构,用于初始化指定类型的设备 14 | * 15 | */ 16 | struct inode * 17 | __alloc_inode(int type) { 18 | LOG("__alloc_inode: type = %d\n",type); 19 | struct inode *node; 20 | if ((node = kmalloc(sizeof(struct inode))) != NULL) { 21 | node->in_type = type; 22 | } 23 | return node; 24 | } 25 | 26 | /* * 27 | * inode_init - initialize a inode structure 28 | * invoked by vop_init 29 | * */ 30 | void 31 | inode_init(struct inode *node, const struct inode_ops *ops, struct fs *fs) { 32 | node->ref_count = 0; 33 | node->open_count = 0; 34 | node->in_ops = ops, node->in_fs = fs; 35 | vop_ref_inc(node); 36 | } 37 | 38 | /* * 39 | * inode_kill - kill a inode structure 40 | * invoked by vop_kill 41 | * */ 42 | void 43 | inode_kill(struct inode *node) { 44 | assert(inode_ref_count(node) == 0); 45 | assert(inode_open_count(node) == 0); 46 | kfree(node); 47 | } 48 | 49 | /* * 50 | * inode_ref_inc - increment ref_count 51 | * invoked by vop_ref_inc 52 | * */ 53 | int 54 | inode_ref_inc(struct inode *node) { 55 | node->ref_count += 1; 56 | return node->ref_count; 57 | } 58 | 59 | /* * 60 | * inode_ref_dec - decrement ref_count 61 | * invoked by vop_ref_dec 62 | * calls vop_reclaim if the ref_count hits zero 63 | * */ 64 | int 65 | inode_ref_dec(struct inode *node) { 66 | assert(inode_ref_count(node) > 0); 67 | int ref_count, ret; 68 | node->ref_count-= 1; 69 | ref_count = node->ref_count; 70 | if (ref_count == 0) { 71 | if ((ret = vop_reclaim(node)) != 0 && ret != -E_BUSY) { 72 | LOG("vfs: warning: vop_reclaim: %e.\n", ret); 73 | } 74 | } 75 | return ref_count; 76 | } 77 | 78 | /* * 79 | * inode_open_inc - increment the open_count 80 | * invoked by vop_open_inc 81 | * */ 82 | int 83 | inode_open_inc(struct inode *node) { 84 | node->open_count += 1; 85 | return node->open_count; 86 | } 87 | 88 | /* * 89 | * inode_open_dec - decrement the open_count 90 | * invoked by vop_open_dec 91 | * calls vop_close if the open_count hits zero 92 | * */ 93 | int 94 | inode_open_dec(struct inode *node) { 95 | assert(inode_open_count(node) > 0); 96 | int open_count, ret; 97 | node->open_count -= 1; 98 | open_count = node->open_count; 99 | if (open_count == 0) { 100 | if ((ret = vop_close(node)) != 0) { 101 | LOG("vfs: warning: vop_close: %e.\n", ret); 102 | } 103 | } 104 | return open_count; 105 | } 106 | 107 | /* * 108 | * inode_check - check the various things being valid 109 | * called before all vop_* calls 110 | * */ 111 | void 112 | inode_check(struct inode *node, const char *opstr) { 113 | assert(node != NULL && node->in_ops != NULL); 114 | assert(node->in_ops->vop_magic == VOP_MAGIC); 115 | int ref_count = inode_ref_count(node), open_count = inode_open_count(node); 116 | assert(ref_count >= open_count && open_count >= 0); 117 | assert(ref_count < MAX_INODE_COUNT && open_count < MAX_INODE_COUNT); 118 | } 119 | 120 | -------------------------------------------------------------------------------- /code-with-comments/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 | // __alloc_fs - allocate memory for fs, and set fs type 16 | struct fs * 17 | __alloc_fs(int type) { 18 | struct fs *fs; 19 | if ((fs = kmalloc(sizeof(struct fs))) != NULL) { 20 | fs->fs_type = type; 21 | } 22 | return fs; 23 | } 24 | 25 | // vfs_init - vfs initialize 26 | void 27 | vfs_init(void) { 28 | sem_init(&bootfs_sem, 1); 29 | vfs_devlist_init(); 30 | } 31 | 32 | // lock_bootfs - lock for bootfs 33 | static void 34 | lock_bootfs(void) { 35 | down(&bootfs_sem); 36 | } 37 | // ulock_bootfs - ulock for bootfs 38 | static void 39 | unlock_bootfs(void) { 40 | up(&bootfs_sem); 41 | } 42 | 43 | // change_bootfs - set the new fs inode 44 | static void 45 | change_bootfs(struct inode *node) { 46 | struct inode *old; 47 | lock_bootfs(); 48 | { 49 | old = bootfs_node, bootfs_node = node; 50 | } 51 | unlock_bootfs(); 52 | if (old != NULL) { 53 | vop_ref_dec(old); 54 | } 55 | } 56 | 57 | // vfs_set_bootfs - change the dir of file system 58 | int 59 | vfs_set_bootfs(char *fsname) { 60 | struct inode *node = NULL; 61 | if (fsname != NULL) { 62 | char *s; 63 | if ((s = strchr(fsname, ':')) == NULL || s[1] != '\0') { 64 | return -E_INVAL; 65 | } 66 | int ret; 67 | if ((ret = vfs_chdir(fsname)) != 0) { 68 | return ret; 69 | } 70 | if ((ret = vfs_get_curdir(&node)) != 0) { 71 | return ret; 72 | } 73 | } 74 | change_bootfs(node); 75 | return 0; 76 | } 77 | 78 | // vfs_get_bootfs - get the inode of bootfs 79 | int 80 | vfs_get_bootfs(struct inode **node_store) { 81 | struct inode *node = NULL; 82 | if (bootfs_node != NULL) { 83 | lock_bootfs(); 84 | { 85 | if ((node = bootfs_node) != NULL) { 86 | vop_ref_inc(bootfs_node); 87 | } 88 | } 89 | unlock_bootfs(); 90 | } 91 | if (node == NULL) { 92 | return -E_NOENT; 93 | } 94 | *node_store = node; 95 | return 0; 96 | } 97 | 98 | -------------------------------------------------------------------------------- /code-with-comments/kern/fs/vfs/vfsfile.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | // open file in vfs, get/create inode for file with filename path. 11 | 12 | /** 13 | * 功能: 返回指定路径的 inode. 14 | * 参数: 路径,flag. 15 | * 机制: 1. flag 校验 2. 16 | * 17 | */ 18 | int 19 | vfs_open(char *path, uint32_t open_flags, struct inode **node_store) { 20 | // 1. 确定读写等属性 21 | bool can_write = 0; 22 | switch (open_flags & O_ACCMODE) { 23 | case O_RDONLY: 24 | break; 25 | case O_WRONLY: 26 | case O_RDWR: 27 | can_write = 1; 28 | break; 29 | default: 30 | return -E_INVAL; 31 | } 32 | 33 | if (open_flags & O_TRUNC) { 34 | if (!can_write) { 35 | return -E_INVAL; 36 | } 37 | } 38 | 39 | int ret; 40 | struct inode *node; 41 | bool excl = (open_flags & O_EXCL) != 0; 42 | bool create = (open_flags & O_CREAT) != 0; 43 | ret = vfs_lookup(path, &node); 44 | // ret=0 说明已经找到,否则考察是否创建 45 | if (ret != 0) { 46 | if (ret == -16 && (create)) {// todo: 改为 -E_NOENT 47 | char *name; 48 | struct inode *dir; 49 | // 要创建 node,首先要找到此路径所属的 dir 和名称 50 | if ((ret = vfs_lookup_parent(path, &dir, &name)) != 0) { 51 | return ret; 52 | } 53 | // 创建 inode并返回 54 | ret = vop_create(dir, name, excl, &node); 55 | } else return ret; 56 | } else if (excl && create) { 57 | return -E_EXISTS; 58 | } 59 | assert(node != NULL); 60 | 61 | if ((ret = vop_open(node, open_flags)) != 0) { 62 | vop_ref_dec(node); 63 | return ret; 64 | } 65 | 66 | vop_open_inc(node); 67 | if (open_flags & O_TRUNC || create) { 68 | if ((ret = vop_truncate(node, 0)) != 0) { 69 | vop_open_dec(node); 70 | vop_ref_dec(node); 71 | return ret; 72 | } 73 | } 74 | *node_store = node; 75 | return 0; 76 | } 77 | 78 | // close file in vfs 79 | int 80 | vfs_close(struct inode *node) { 81 | vop_open_dec(node); 82 | vop_ref_dec(node); 83 | return 0; 84 | } 85 | 86 | // unimplement 87 | int 88 | vfs_unlink(char *path) { 89 | return -E_UNIMP; 90 | } 91 | 92 | // unimplement 93 | int 94 | vfs_rename(char *old_path, char *new_path) { 95 | return -E_UNIMP; 96 | } 97 | 98 | // unimplement 99 | int 100 | vfs_link(char *old_path, char *new_path) { 101 | return -E_UNIMP; 102 | } 103 | 104 | // unimplement 105 | int 106 | vfs_symlink(char *old_path, char *new_path) { 107 | return -E_UNIMP; 108 | } 109 | 110 | // unimplement 111 | int 112 | vfs_readlink(char *path, struct iobuf *iob) { 113 | return -E_UNIMP; 114 | } 115 | 116 | // unimplement 117 | int 118 | vfs_mkdir(char *path){ 119 | return -E_UNIMP; 120 | } 121 | -------------------------------------------------------------------------------- /code-with-comments/kern/fs/vfs/vfslookup.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /* 9 | * get_device- Common code to pull the device name, if any, off the front of a 10 | * path and choose the inode to begin the name lookup relative to. 11 | * 12 | * 解析路径,获取对应的 inode. 13 | * 14 | */ 15 | 16 | static int 17 | get_device(char *path, char **subpath, struct inode **node_store) { 18 | // 1. 获取冒号或斜杠的位置 19 | int i, slash = -1, colon = -1; 20 | for (i = 0; path[i] != '\0'; i ++) { 21 | if (path[i] == ':') { colon = i; break; } 22 | if (path[i] == '/') { slash = i; break; } 23 | } 24 | if (colon < 0 && slash != 0) { 25 | /* 26 | * 27 | * 没有冒号,且第一个字符不是/ , 例如abc/c 28 | * - 说明没有指定设备;这是一个相对路径或者就是个文件名. 29 | * - 接下来从当前文件夹开始,把整个字符串作为子路径. 30 | * - 返回pwd 的 inode 31 | * */ 32 | *subpath = path; 33 | // 由于是相对路径,所以返回当前工作目录的 inode 34 | return vfs_get_curdir(node_store); 35 | } 36 | 37 | if (colon > 0) { 38 | /** 39 | * 有冒号且不位于第一个位置,说明指定了设备.例如 C:/abc/d 40 | * - 用冒号位置截断字符串 41 | */ 42 | /* device:path - get root of device's filesystem */ 43 | // C\0/abc/d 44 | path[colon] = '\0'; 45 | 46 | /* device:/path - skip slash, treat as device:path */ 47 | while (path[++ colon] == '/'); 48 | // 返回纯子路径 abc/d 49 | *subpath = path + colon; 50 | return vfs_get_root(path, node_store); 51 | } 52 | /** 53 | * 54 | * 其他情况: 55 | * 有冒号且位于第一个位置,说明是当前文件系统的根相对路径,如 :abc 56 | * 没有冒号,且斜杠位于第 1 个位置,说明是boot 文件系统的根相对路径,如 /abc 57 | * 58 | */ 59 | int ret; 60 | if (*path == '/') { 61 | if ((ret = vfs_get_bootfs(node_store)) != 0) { 62 | return ret; 63 | } 64 | } 65 | else { 66 | assert(*path == ':'); 67 | struct inode *node; 68 | if ((ret = vfs_get_curdir(&node)) != 0) { 69 | return ret; 70 | } 71 | /* The current directory may not be a device, so it must have a fs. */ 72 | assert(node->in_fs != NULL); 73 | *node_store = fsop_get_root(node->in_fs); 74 | vop_ref_dec(node); 75 | } 76 | 77 | /* ///... or :/... */ 78 | while (*(++ path) == '/'); 79 | *subpath = path; 80 | return 0; 81 | } 82 | 83 | /* 84 | * vfs_lookup - get the inode according to the path filename 85 | * 86 | * path --> inode 87 | */ 88 | int 89 | vfs_lookup(char *path, struct inode **node_store) { 90 | int ret; 91 | struct inode *node; 92 | // path --> path1,最终文件所在的目录 inode 93 | if ((ret = get_device(path, &path, &node)) != 0) { 94 | return ret; 95 | } 96 | // inode,path1 --> node_store 97 | if (*path != '\0') { 98 | ret = vop_lookup(node, path, node_store); 99 | vop_ref_dec(node); 100 | return ret; 101 | } 102 | *node_store = node; 103 | return 0; 104 | } 105 | 106 | /* 107 | * vfs_lookup_parent - Name-to-vnode translation. 108 | * (In BSD, both of these are subsumed by namei().) 109 | * 110 | * 111 | */ 112 | int 113 | vfs_lookup_parent(char *path, struct inode **node_store, char **endp){ 114 | int ret; 115 | struct inode *node; 116 | if ((ret = get_device(path, &path, &node)) != 0) { 117 | return ret; 118 | } 119 | *endp = path; 120 | *node_store = node; 121 | return 0; 122 | } 123 | -------------------------------------------------------------------------------- /code-with-comments/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 | /* 12 | * get_cwd_nolock - retrieve current process's working directory. without lock protect 13 | */ 14 | static struct inode * 15 | get_cwd_nolock(void) { 16 | return current->filesp->pwd; 17 | } 18 | /* 19 | * set_cwd_nolock - set current working directory. 20 | */ 21 | static void 22 | set_cwd_nolock(struct inode *pwd) { 23 | current->filesp->pwd = pwd; 24 | } 25 | 26 | /* 27 | * lock_cfs - lock the fs related process on current process 28 | */ 29 | static void 30 | lock_cfs(void) { 31 | lock_files(current->filesp); 32 | } 33 | /* 34 | * unlock_cfs - unlock the fs related process on current process 35 | */ 36 | static void 37 | unlock_cfs(void) { 38 | unlock_files(current->filesp); 39 | } 40 | 41 | /* 42 | * vfs_get_curdir - Get current directory as a inode. 43 | * 44 | */ 45 | int 46 | vfs_get_curdir(struct inode **dir_store) { 47 | struct inode *node; 48 | if ((node = get_cwd_nolock()) != NULL) { 49 | vop_ref_inc(node); 50 | *dir_store = node; 51 | return 0; 52 | } 53 | return -E_NOENT; 54 | } 55 | 56 | /* 57 | * vfs_set_curdir - Set current directory as a inode. 58 | * The passed inode must in fact be a directory. 59 | */ 60 | int 61 | vfs_set_curdir(struct inode *dir) { 62 | int ret = 0; 63 | lock_cfs(); 64 | struct inode *old_dir; 65 | if ((old_dir = get_cwd_nolock()) != dir) { 66 | if (dir != NULL) { 67 | uint32_t type; 68 | if ((ret = vop_gettype(dir, &type)) != 0) { 69 | goto out; 70 | } 71 | if (!S_ISDIR(type)) { 72 | ret = -E_NOTDIR; 73 | goto out; 74 | } 75 | vop_ref_inc(dir); 76 | } 77 | set_cwd_nolock(dir); 78 | if (old_dir != NULL) { 79 | vop_ref_dec(old_dir); 80 | } 81 | } 82 | out: 83 | unlock_cfs(); 84 | return ret; 85 | } 86 | 87 | /* 88 | * vfs_chdir - Set current directory, as a pathname. Use vfs_lookup to translate 89 | * it to a inode. 90 | */ 91 | int 92 | vfs_chdir(char *path) { 93 | int ret; 94 | struct inode *node; 95 | if ((ret = vfs_lookup(path, &node)) == 0) { 96 | ret = vfs_set_curdir(node); 97 | vop_ref_dec(node); 98 | } 99 | return ret; 100 | } 101 | /* 102 | * vfs_getcwd - retrieve current working directory(cwd). 103 | */ 104 | int 105 | vfs_getcwd(struct iobuf *iob) { 106 | int ret; 107 | struct inode *node; 108 | if ((ret = vfs_get_curdir(&node)) != 0) { 109 | return ret; 110 | } 111 | assert(node->in_fs != NULL); 112 | 113 | const char *devname = vfs_get_devname(node->in_fs); 114 | if ((ret = iobuf_move(iob, (char *)devname, strlen(devname), 1, NULL)) != 0) { 115 | goto out; 116 | } 117 | char colon = ':'; 118 | if ((ret = iobuf_move(iob, &colon, sizeof(colon), 1, NULL)) != 0) { 119 | goto out; 120 | } 121 | ret = vop_namefile(node, iob); 122 | 123 | out: 124 | vop_ref_dec(node); 125 | return ret; 126 | } 127 | 128 | -------------------------------------------------------------------------------- /code-with-comments/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 | 21 | /** 22 | * 内核总控函数,依次初始化: 23 | * 24 | * 1. 控制台 25 | * 1. 物理内存 26 | * 2. 虚拟内存 27 | * 3. 调度器 28 | * 4. 进程表 29 | * 5. 磁盘驱动 30 | * 6. 置换管理 31 | * 7. 文件系统 32 | */ 33 | int 34 | kern_init(void) { 35 | extern char edata[], end[]; 36 | memset(edata, 0, end - edata); // 清空 bss 段 37 | 38 | cons_init(); // init the console 39 | 40 | print_history(); 41 | print_kerninfo(); 42 | 43 | //grade_backtrace(); 44 | 45 | pmm_init(); // init physical memory management 46 | 47 | pic_init(); // init interrupt controller 48 | idt_init(); // init interrupt descriptor table 49 | 50 | vmm_init(); // init virtual memory management 51 | sched_init(); // init scheduler 52 | proc_init(); // init process table 53 | 54 | ide_init(); // init ide devices 55 | swap_init(); // init swap 56 | fs_init(); // init fs 57 | 58 | clock_init(); // init clock interrupt 59 | intr_enable(); // enable irq interrupt 60 | 61 | cpu_idle(); // run idle process 62 | } 63 | 64 | void __attribute__((noinline)) 65 | grade_backtrace2(int arg0, int arg1, int arg2, int arg3) { 66 | mon_backtrace(0, NULL, NULL); 67 | } 68 | 69 | void __attribute__((noinline)) 70 | grade_backtrace1(int arg0, int arg1) { 71 | grade_backtrace2(arg0, (int)&arg0, arg1, (int)&arg1); 72 | } 73 | 74 | void __attribute__((noinline)) 75 | grade_backtrace0(int arg0, int arg1, int arg2) { 76 | grade_backtrace1(arg0, arg2); 77 | } 78 | 79 | void 80 | grade_backtrace(void) { 81 | grade_backtrace0(0, (int)kern_init, 0xffff0000); 82 | } 83 | 84 | static void 85 | lab1_print_cur_status(void) { 86 | static int round = 0; 87 | uint16_t reg1, reg2, reg3, reg4; 88 | asm volatile ( 89 | "mov %%cs, %0;" 90 | "mov %%ds, %1;" 91 | "mov %%es, %2;" 92 | "mov %%ss, %3;" 93 | : "=m"(reg1), "=m"(reg2), "=m"(reg3), "=m"(reg4)); 94 | LOG("%d: @ring %d\n", round, reg1 & 3); 95 | LOG("%d: cs = %x\n", round, reg1); 96 | LOG("%d: ds = %x\n", round, reg2); 97 | LOG("%d: es = %x\n", round, reg3); 98 | LOG("%d: ss = %x\n", round, reg4); 99 | round ++; 100 | } 101 | -------------------------------------------------------------------------------- /code-with-comments/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-with-comments/kern/libs/stdio.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 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 | -------------------------------------------------------------------------------- /code-with-comments/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-with-comments/kern/mm/default_pmm.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_MM_DEFAULT_PMM_H__ 2 | #define __KERN_MM_DEFAULT_PMM_H__ 3 | 4 | #include 5 | 6 | extern const struct pmm_manager default_pmm_manager; 7 | extern free_area_t free_area; 8 | #endif /* ! __KERN_MM_DEFAULT_PMM_H__ */ 9 | 10 | -------------------------------------------------------------------------------- /code-with-comments/kern/mm/kmalloc.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 kmalloc_init(void); 9 | 10 | void *kmalloc(size_t n); 11 | void kfree(void *objp); 12 | 13 | size_t kallocated(void); 14 | 15 | #endif /* !__KERN_MM_SLAB_H__ */ 16 | 17 | -------------------------------------------------------------------------------- /code-with-comments/kern/mm/swap.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_MM_SWAP_H__ 2 | #define __KERN_MM_SWAP_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /* * 10 | * swap_entry_t 11 | * -------------------------------------------- 12 | * | offset | reserved | 0 | 13 | * -------------------------------------------- 14 | * 24 bits 7 bits 1 bit 15 | * */ 16 | 17 | #define MAX_SWAP_OFFSET_LIMIT (1 << 24) 18 | 19 | extern size_t max_swap_offset; 20 | 21 | /* * 22 | * swap_offset - takes a swap_entry (saved in pte), and returns 23 | * the corresponding offset in swap mem_map. 24 | * */ 25 | #define swap_offset(entry) ({ \ 26 | size_t __offset = (entry >> 8); \ 27 | if (!(__offset > 0 && __offset < max_swap_offset)) { \ 28 | panic("invalid swap_entry_t = %08x.\n", entry); \ 29 | } \ 30 | __offset; \ 31 | }) 32 | 33 | struct swap_manager 34 | { 35 | const char *name; 36 | /* Global initialization for the swap manager */ 37 | int (*init) (void); 38 | /* Initialize the priv data inside mm_struct */ 39 | int (*init_mm) (struct mm_struct *mm); 40 | /* Called when tick interrupt occured */ 41 | int (*tick_event) (struct mm_struct *mm); 42 | /* Called when map a swappable page into the mm_struct */ 43 | int (*map_swappable) (struct mm_struct *mm, uintptr_t addr, struct Page *page, int swap_in); 44 | /* When a page is marked as shared, this routine is called to 45 | * delete the addr entry from the swap manager */ 46 | int (*set_unswappable) (struct mm_struct *mm, uintptr_t addr); 47 | /* Try to swap out a page, return then victim */ 48 | int (*swap_out_victim) (struct mm_struct *mm, struct Page **ptr_page, int in_tick); 49 | /* check the page relpacement algorithm */ 50 | int (*check_swap)(void); 51 | }; 52 | 53 | extern volatile int swap_init_ok; 54 | int swap_init(void); 55 | int swap_init_mm(struct mm_struct *mm); 56 | int swap_tick_event(struct mm_struct *mm); 57 | int swap_map_swappable(struct mm_struct *mm, uintptr_t addr, struct Page *page, int swap_in); 58 | int swap_set_unswappable(struct mm_struct *mm, uintptr_t addr); 59 | int swap_out(struct mm_struct *mm, int n, int in_tick); 60 | int swap_in(struct mm_struct *mm, uintptr_t addr, struct Page **ptr_result); 61 | 62 | //#define MEMBER_OFFSET(m,t) ((int)(&((t *)0)->m)) 63 | //#define FROM_MEMBER(m,t,a) ((t *)((char *)(a) - MEMBER_OFFSET(m,t))) 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /code-with-comments/kern/mm/swap_fifo.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_MM_SWAP_FIFO_H__ 2 | #define __KERN_MM_SWAP_FIFO_H__ 3 | 4 | #include 5 | extern struct swap_manager swap_manager_fifo; 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /code-with-comments/kern/process/entry.S: -------------------------------------------------------------------------------- 1 | # 内核线程入口点,就是内核线程函数fn的驱动 2 | 3 | .text 4 | .globl kernel_thread_entry 5 | kernel_thread_entry: # void kernel_thread(void) 6 | 7 | pushl %edx # push arg 8 | call *%ebx # call fn 9 | 10 | pushl %eax # save the return value of fn(arg) 11 | call do_exit # call do_exit to terminate current thread 12 | 13 | -------------------------------------------------------------------------------- /code-with-comments/kern/process/switch.S: -------------------------------------------------------------------------------- 1 | .text 2 | .globl switch_to 3 | 4 | # struct context { 5 | # uint32_t eip; 6 | # uint32_t esp; 7 | # uint32_t ebx; 8 | # uint32_t ecx; 9 | # uint32_t edx; 10 | # uint32_t esi; 11 | # uint32_t edi; 12 | # uint32_t ebp; 13 | # }; 14 | 15 | # switch_to(struct context *from, struct context *to); 16 | # 注意 context 在 PCB 中以结构体而非指针类型保存. 17 | # 注意函数栈帧, 进入函数体内之后,从上到下的栈内参数有三: &(next->context), &(prev->context), 返回地址. 18 | 19 | switch_to: # switch_to(from, to) 20 | 21 | # 在栈上保存 from 的执行现场 22 | movl 4(%esp), %eax # eax 指向 from,其实也指向了 from 的 eip 23 | popl 0(%eax) # pop 前,esp 指向调用者的 eip,即返回地址,pop 后直接把 eip 赋给了 from 的 eip 变量. 然后 esp 指向了 from. 24 | movl %esp, 4(%eax) # 把当前各种寄存器的值保存在 from context 的内存中. 25 | movl %ebx, 8(%eax) 26 | movl %ecx, 12(%eax) 27 | movl %edx, 16(%eax) 28 | movl %esi, 20(%eax) 29 | movl %edi, 24(%eax) 30 | movl %ebp, 28(%eax) 31 | 32 | # 把 to 中的值赋给寄存器 33 | movl 4(%esp), %eax # not 8(%esp): popped return address already. to context 的地址赋给 eax. 34 | # eax 指向了 to 35 | movl 28(%eax), %ebp # 36 | movl 24(%eax), %edi 37 | movl 20(%eax), %esi 38 | movl 16(%eax), %edx 39 | movl 12(%eax), %ecx 40 | movl 8(%eax), %ebx 41 | movl 4(%eax), %esp 42 | 43 | pushl 0(%eax) # push eip 当前 eax指向to 的eip.这里把它入栈,这样执行 ret 就会执行到to 的控制流. 44 | 45 | ret 46 | 47 | -------------------------------------------------------------------------------- /code-with-comments/kern/schedule/rr_sched.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | static void 9 | RR_init(struct run_queue *rq) { 10 | list_init(&(rq->run_list)); 11 | rq->proc_num = 0; 12 | } 13 | 14 | static void 15 | RR_enqueue(struct run_queue *rq, struct proc_struct *proc) { 16 | LOG("RR_enqueue:\n"); 17 | assert(list_empty(&(proc->run_link))); 18 | list_add_before(&(rq->run_list), &(proc->run_link)); 19 | if (proc->time_slice == 0 || proc->time_slice > rq->max_time_slice) { 20 | proc->time_slice = rq->max_time_slice; 21 | } 22 | proc->rq = rq; 23 | rq->proc_num ++; 24 | LOG_TAB("运行队列长度更新为: %d\n",rq->proc_num); 25 | 26 | } 27 | 28 | static void 29 | RR_dequeue(struct run_queue *rq, struct proc_struct *proc) { 30 | assert(!list_empty(&(proc->run_link)) && proc->rq == rq); 31 | list_del_init(&(proc->run_link)); 32 | rq->proc_num --; 33 | } 34 | 35 | static struct proc_struct * 36 | RR_pick_next(struct run_queue *rq) { 37 | list_entry_t *le = list_next(&(rq->run_list)); 38 | if (le != &(rq->run_list)) { 39 | return le2proc(le, run_link); 40 | } 41 | return NULL; 42 | } 43 | 44 | static void 45 | RR_proc_tick(struct run_queue *rq, struct proc_struct *proc) { 46 | if (proc->time_slice > 0) { 47 | proc->time_slice --; 48 | } 49 | if (proc->time_slice == 0) { 50 | proc->need_resched = 1; 51 | } 52 | } 53 | 54 | struct sched_class RR_sched_class = { 55 | .name = "RR_scheduler", 56 | .init = RR_init, 57 | .enqueue = RR_enqueue, 58 | .dequeue = RR_dequeue, 59 | .pick_next = RR_pick_next, 60 | .proc_tick = RR_proc_tick, 61 | }; 62 | 63 | -------------------------------------------------------------------------------- /code-with-comments/kern/schedule/rr_sched.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_SCHEDULE_SCHED_RR_H__ 2 | #define __KERN_SCHEDULE_SCHED_RR_H__ 3 | 4 | #include 5 | 6 | /** 7 | * 将 rr 调度器类暴露出来,作为向外提供的接口,供 sched.c 配置 8 | */ 9 | extern struct sched_class RR_sched_class; 10 | 11 | #endif /* !__KERN_SCHEDULE_SCHED_RR_H__ */ 12 | 13 | -------------------------------------------------------------------------------- /code-with-comments/kern/schedule/sched.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_SCHEDULE_SCHED_H__ 2 | #define __KERN_SCHEDULE_SCHED_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | //todo: 更优雅的策略配置方式? 9 | #define _SCHED_POLICY_ _SCHED_RR_ 10 | 11 | #define _SCHED_RR_ 0 12 | #define _SCHED_STRIDE_ 1 13 | 14 | struct proc_struct; 15 | 16 | /** 17 | * 定时器--基于时间的调度机制 18 | */ 19 | typedef struct { 20 | unsigned int expires; // 此 itmer 的生命值(时间片的数量) 21 | struct proc_struct *proc; 22 | list_entry_t timer_link; // timer 所在的队列 23 | } timer_t; 24 | 25 | #define le2timer(le, member) \ 26 | to_struct((le), timer_t, member) 27 | 28 | static inline timer_t * 29 | timer_init(timer_t *timer, struct proc_struct *proc, int expires) { 30 | timer->expires = expires; 31 | timer->proc = proc; 32 | list_init(&(timer->timer_link)); 33 | return timer; 34 | } 35 | 36 | struct run_queue; 37 | 38 | // 调度器类的设计借鉴了 linux 的设计思想,扩展性很强.这些类封装了调度策略. 39 | // 参考: https://www.cnblogs.com/vamei/archive/2018/07/25/9364382.html 40 | struct sched_class { 41 | // the name of sched_class 42 | const char *name; 43 | // Init the run queue 44 | void (*init)(struct run_queue *rq); 45 | // put the proc into runqueue, and this function must be called with rq_lock 46 | void (*enqueue)(struct run_queue *rq, struct proc_struct *proc); 47 | // get the proc out runqueue, and this function must be called with rq_lock 48 | void (*dequeue)(struct run_queue *rq, struct proc_struct *proc); 49 | // choose the next runnable task 50 | struct proc_struct *(*pick_next)(struct run_queue *rq); 51 | // dealer of the time-tick 52 | void (*proc_tick)(struct run_queue *rq, struct proc_struct *proc); 53 | 54 | /* for SMP support in the future 55 | * load_balance 56 | * void (*load_balance)(struct rq* rq); 57 | * get some proc from this rq, used in load_balance, 58 | * return value is the num of gotten proc 59 | * int (*get_proc)(struct rq* rq, struct proc* procs_moved[]); 60 | */ 61 | }; 62 | 63 | /** 64 | * 就绪队列, 在用户看来都是正在运行,不断地切换上下文 65 | */ 66 | struct run_queue { 67 | list_entry_t run_list; 68 | unsigned int proc_num; 69 | int max_time_slice; 70 | // For LAB6 ONLY 71 | skew_heap_entry_t *lab6_run_pool; 72 | }; 73 | 74 | void sched_init(void); 75 | void wakeup_proc(struct proc_struct *proc); 76 | void schedule(void); 77 | void add_timer(timer_t *timer); 78 | void del_timer(timer_t *timer); 79 | void run_timer_list(void); 80 | 81 | #endif /* !__KERN_SCHEDULE_SCHED_H__ */ 82 | 83 | -------------------------------------------------------------------------------- /code-with-comments/kern/schedule/stride_sched.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_SCHEDULE_SCHED_stride_H__ 2 | #define __KERN_SCHEDULE_SCHED_stride_H__ 3 | 4 | #include 5 | 6 | /** 7 | * 将 stride 调度器类暴露出来,作为向外提供的接口,供 sched.c 配置 8 | */ 9 | extern struct sched_class stride_sched_class; 10 | 11 | #endif /* !__KERN_SCHEDULE_SCHED_stride_H__ */ 12 | 13 | -------------------------------------------------------------------------------- /code-with-comments/kern/sync/monitor.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | // Initialize monitor. 9 | void 10 | monitor_init (monitor_t * mtp, size_t num_cv) { 11 | int i; 12 | assert(num_cv>0); 13 | mtp->next_count = 0; 14 | mtp->cv = NULL; 15 | sem_init(&(mtp->mutex), 1); //unlocked 16 | sem_init(&(mtp->next), 0); 17 | mtp->cv =(condvar_t *) kmalloc(sizeof(condvar_t)*num_cv); 18 | assert(mtp->cv!=NULL); 19 | for(i=0; icv[i].count=0; 21 | sem_init(&(mtp->cv[i].sem),0); 22 | mtp->cv[i].owner=mtp; 23 | } 24 | } 25 | 26 | // Unlock one of threads waiting on the condition variable. 27 | void 28 | cond_signal (condvar_t *cvp) { 29 | //LAB7 EXERCISE1: YOUR CODE 30 | LOG("cond_signal begin: cvp %x, cvp->count %d, cvp->owner->next_count %d\n", cvp, cvp->count, cvp->owner->next_count); 31 | /* 32 | * cond_signal(cv) { 33 | * if(cv.count>0) { 34 | * mt.next_count ++; 35 | * signal(cv.sem); 36 | * wait(mt.next); 37 | * mt.next_count--; 38 | * } 39 | * } 40 | */ 41 | if(cvp->count>0) { 42 | cvp->owner->next_count ++; 43 | up(&(cvp->sem)); 44 | down(&(cvp->owner->next)); 45 | cvp->owner->next_count --; 46 | } 47 | LOG("cond_signal end: cvp %x, cvp->count %d, cvp->owner->next_count %d\n", cvp, cvp->count, cvp->owner->next_count); 48 | } 49 | 50 | // Suspend calling thread on a condition variable waiting for condition Atomically unlocks 51 | // mutex and suspends calling thread on conditional variable after waking up locks mutex. Notice: mp is mutex semaphore for monitor's procedures 52 | void 53 | cond_wait (condvar_t *cvp) { 54 | //LAB7 EXERCISE1: YOUR CODE 55 | LOG("cond_wait begin: cvp %x, cvp->count %d, cvp->owner->next_count %d\n", cvp, cvp->count, cvp->owner->next_count); 56 | /* 57 | * cv.count ++; 58 | * if(mt.next_count>0) 59 | * signal(mt.next) 60 | * else 61 | * signal(mt.mutex); 62 | * wait(cv.sem); 63 | * cv.count --; 64 | */ 65 | cvp->count++; 66 | if(cvp->owner->next_count > 0) 67 | up(&(cvp->owner->next)); 68 | else 69 | up(&(cvp->owner->mutex)); 70 | down(&(cvp->sem)); 71 | cvp->count --; 72 | LOG("cond_wait end: cvp %x, cvp->count %d, cvp->owner->next_count %d\n", cvp, cvp->count, cvp->owner->next_count); 73 | } 74 | -------------------------------------------------------------------------------- /code-with-comments/kern/sync/monitor.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_SYNC_MONITOR_CONDVAR_H__ 2 | #define __KERN_SYNC_MOINTOR_CONDVAR_H__ 3 | 4 | #include 5 | 6 | /** 7 | * 管程实现.参考 [操作系统概念]7.7 节. 8 | * 9 | * In [OS CONCEPT] 7.7 section, the accurate define and approximate implementation of MONITOR was introduced. 10 | * INTRODUCTION: 11 | * Monitors were invented by C. A. R. Hoare and Per Brinch Hansen, and were first implemented in Brinch Hansen's 12 | * Concurrent Pascal language. Generally, a monitor is a language construct and the compiler usually enforces mutual exclusion. Compare this with semaphores, which are usually an OS construct. 13 | * DEFNIE & CHARACTERISTIC: 14 | * A monitor is a collection of procedures, variables, and data structures grouped together. 15 | * Processes can call the monitor procedures but cannot access the internal data structures. 16 | * Only one process at a time may be be active in a monitor. 17 | * Condition variables allow for blocking and unblocking. 18 | * cv.wait() blocks a process. 19 | * The process is said to be waiting for (or waiting on) the condition variable cv. 20 | * cv.signal() (also called cv.notify) unblocks a process waiting for the condition variable cv. 21 | * When this occurs, we need to still require that only one process is active in the monitor. This can be done in several ways: 22 | * on some systems the old process (the one executing the signal) leaves the monitor and the new one enters 23 | * on some systems the signal must be the last statement executed inside the monitor. 24 | * on some systems the old process will block until the monitor is available again. 25 | * on some systems the new process (the one unblocked by the signal) will remain blocked until the monitor is available again. 26 | * If a condition variable is signaled with nobody waiting, the signal is lost. Compare this with semaphores, in which a signal will allow a process that executes a wait in the future to no block. 27 | * You should not think of a condition variable as a variable in the traditional sense. 28 | * It does not have a value. 29 | * Think of it as an object in the OOP sense. 30 | * It has two methods, wait and signal that manipulate the calling process. 31 | * IMPLEMENTATION: 32 | * monitor mt { 33 | * ----------------variable------------------ 34 | * semaphore mutex; 35 | * semaphore next; 36 | * int next_count; 37 | * condvar {int count, sempahore sem} cv[N]; 38 | * other variables in mt; 39 | * --------condvar wait/signal--------------- 40 | * cond_wait (cv) { 41 | * cv.count ++; 42 | * if(mt.next_count>0) 43 | * signal(mt.next) 44 | * else 45 | * signal(mt.mutex); 46 | * wait(cv.sem); 47 | * cv.count --; 48 | * } 49 | * 50 | * cond_signal(cv) { 51 | * if(cv.count>0) { 52 | * mt.next_count ++; 53 | * signal(cv.sem); 54 | * wait(mt.next); 55 | * mt.next_count--; 56 | * } 57 | * } 58 | * --------routines in monitor--------------- 59 | * routineA_in_mt () { 60 | * wait(mt.mutex); 61 | * ... 62 | * real body of routineA 63 | * ... 64 | * if(next_count>0) 65 | * signal(mt.next); 66 | * else 67 | * signal(mt.mutex); 68 | * } 69 | */ 70 | 71 | typedef struct monitor monitor_t; 72 | 73 | typedef struct condvar{ 74 | semaphore_t sem; // the sem semaphore is used to down the waiting proc, and the signaling proc should up the waiting proc 75 | int count; // the number of waiters on condvar 76 | monitor_t * owner; // the owner(monitor) of this condvar 77 | } condvar_t; 78 | 79 | typedef struct monitor{ 80 | semaphore_t mutex; // the mutex lock for going into the routines in monitor, should be initialized to 1 81 | semaphore_t next; // the next semaphore is used to down the signaling proc itself, and the other OR wakeuped waiting proc should wake up the sleeped signaling proc. 82 | int next_count; // the number of of sleeped signaling proc 83 | condvar_t *cv; // the condvars in monitor 84 | } monitor_t; 85 | 86 | // 初始化管程中的变量 87 | void monitor_init (monitor_t *cvp, size_t num_cv); 88 | // Unlock one of threads waiting on the condition variable. 89 | void cond_signal (condvar_t *cvp); 90 | // Suspend calling thread on a condition variable waiting for condition atomically unlock mutex in monitor, 91 | // and suspends calling thread on conditional variable after waking up locks mutex. 92 | void cond_wait (condvar_t *cvp); 93 | 94 | #endif /* !__KERN_SYNC_MONITOR_CONDVAR_H__ */ 95 | -------------------------------------------------------------------------------- /code-with-comments/kern/sync/sem.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | void 11 | sem_init(semaphore_t *sem, int value) { 12 | sem->value = value; 13 | wait_queue_init(&(sem->wait_queue)); 14 | } 15 | 16 | static __noinline void __up(semaphore_t *sem, uint32_t wait_state) { 17 | bool intr_flag; 18 | local_intr_save(intr_flag); 19 | { 20 | wait_t *wait; 21 | if ((wait = wait_queue_first(&(sem->wait_queue))) == NULL) { 22 | sem->value ++; 23 | } 24 | else { 25 | assert(wait->proc->wait_state == wait_state); 26 | wakeup_wait(&(sem->wait_queue), wait, wait_state, 1); 27 | } 28 | } 29 | local_intr_restore(intr_flag); 30 | } 31 | 32 | static __noinline uint32_t __down(semaphore_t *sem, uint32_t wait_state) { 33 | bool intr_flag; 34 | local_intr_save(intr_flag); 35 | if (sem->value > 0) { 36 | sem->value --; 37 | local_intr_restore(intr_flag); 38 | return 0; 39 | } 40 | wait_t __wait, *wait = &__wait; 41 | wait_current_set(&(sem->wait_queue), wait, wait_state); 42 | local_intr_restore(intr_flag); 43 | 44 | schedule(); 45 | 46 | local_intr_save(intr_flag); 47 | wait_current_del(&(sem->wait_queue), wait); 48 | local_intr_restore(intr_flag); 49 | 50 | if (wait->wakeup_flags != wait_state) { 51 | return wait->wakeup_flags; 52 | } 53 | return 0; 54 | } 55 | 56 | void 57 | up(semaphore_t *sem) { 58 | __up(sem, WT_KSEM); 59 | } 60 | 61 | void 62 | down(semaphore_t *sem) { 63 | uint32_t flags = __down(sem, WT_KSEM); 64 | assert(flags == 0); 65 | } 66 | 67 | bool 68 | try_down(semaphore_t *sem) { 69 | bool intr_flag, ret = 0; 70 | local_intr_save(intr_flag); 71 | if (sem->value > 0) { 72 | sem->value --, ret = 1; 73 | } 74 | local_intr_restore(intr_flag); 75 | return ret; 76 | } 77 | 78 | -------------------------------------------------------------------------------- /code-with-comments/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 | wait_queue_t wait_queue; 11 | } semaphore_t; 12 | 13 | void sem_init(semaphore_t *sem, int value); 14 | void up(semaphore_t *sem); 15 | void down(semaphore_t *sem); 16 | bool try_down(semaphore_t *sem); 17 | 18 | #endif /* !__KERN_SYNC_SEM_H__ */ 19 | 20 | -------------------------------------------------------------------------------- /code-with-comments/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 | #endif /* !__KERN_SYNC_SYNC_H__ */ 31 | 32 | -------------------------------------------------------------------------------- /code-with-comments/kern/sync/wait.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void 8 | wait_init(wait_t *wait, struct proc_struct *proc) { 9 | wait->proc = proc; 10 | wait->wakeup_flags = WT_INTERRUPTED; 11 | list_init(&(wait->wait_link)); 12 | } 13 | 14 | void 15 | wait_queue_init(wait_queue_t *queue) { 16 | list_init(&(queue->wait_head)); 17 | } 18 | 19 | void 20 | wait_queue_add(wait_queue_t *queue, wait_t *wait) { 21 | assert(list_empty(&(wait->wait_link)) && wait->proc != NULL); 22 | wait->wait_queue = queue; 23 | list_add_before(&(queue->wait_head), &(wait->wait_link)); 24 | } 25 | 26 | void 27 | wait_queue_del(wait_queue_t *queue, wait_t *wait) { 28 | assert(!list_empty(&(wait->wait_link)) && wait->wait_queue == queue); 29 | list_del_init(&(wait->wait_link)); 30 | } 31 | 32 | wait_t * 33 | wait_queue_next(wait_queue_t *queue, wait_t *wait) { 34 | assert(!list_empty(&(wait->wait_link)) && wait->wait_queue == queue); 35 | list_entry_t *le = list_next(&(wait->wait_link)); 36 | if (le != &(queue->wait_head)) { 37 | return le2wait(le, wait_link); 38 | } 39 | return NULL; 40 | } 41 | 42 | wait_t * 43 | wait_queue_prev(wait_queue_t *queue, wait_t *wait) { 44 | assert(!list_empty(&(wait->wait_link)) && wait->wait_queue == queue); 45 | list_entry_t *le = list_prev(&(wait->wait_link)); 46 | if (le != &(queue->wait_head)) { 47 | return le2wait(le, wait_link); 48 | } 49 | return NULL; 50 | } 51 | 52 | wait_t * 53 | wait_queue_first(wait_queue_t *queue) { 54 | list_entry_t *le = list_next(&(queue->wait_head)); 55 | if (le != &(queue->wait_head)) { 56 | return le2wait(le, wait_link); 57 | } 58 | return NULL; 59 | } 60 | 61 | wait_t * 62 | wait_queue_last(wait_queue_t *queue) { 63 | list_entry_t *le = list_prev(&(queue->wait_head)); 64 | if (le != &(queue->wait_head)) { 65 | return le2wait(le, wait_link); 66 | } 67 | return NULL; 68 | } 69 | 70 | bool 71 | wait_queue_empty(wait_queue_t *queue) { 72 | return list_empty(&(queue->wait_head)); 73 | } 74 | 75 | bool 76 | wait_in_queue(wait_t *wait) { 77 | return !list_empty(&(wait->wait_link)); 78 | } 79 | 80 | void 81 | wakeup_wait(wait_queue_t *queue, wait_t *wait, uint32_t wakeup_flags, bool del) { 82 | if (del) { 83 | wait_queue_del(queue, wait); 84 | } 85 | wait->wakeup_flags = wakeup_flags; 86 | wakeup_proc(wait->proc); 87 | } 88 | 89 | void 90 | wakeup_first(wait_queue_t *queue, uint32_t wakeup_flags, bool del) { 91 | wait_t *wait; 92 | if ((wait = wait_queue_first(queue)) != NULL) { 93 | wakeup_wait(queue, wait, wakeup_flags, del); 94 | } 95 | } 96 | 97 | void 98 | wakeup_queue(wait_queue_t *queue, uint32_t wakeup_flags, bool del) { 99 | wait_t *wait; 100 | if ((wait = wait_queue_first(queue)) != NULL) { 101 | if (del) { 102 | do { 103 | wakeup_wait(queue, wait, wakeup_flags, 1); 104 | } while ((wait = wait_queue_first(queue)) != NULL); 105 | } 106 | else { 107 | do { 108 | wakeup_wait(queue, wait, wakeup_flags, 0); 109 | } while ((wait = wait_queue_next(queue, wait)) != NULL); 110 | } 111 | } 112 | } 113 | 114 | /** 115 | * 让给定的 wait 与当前的进程相关联,并让当前进程进入等待队列 116 | * 117 | */ 118 | void 119 | wait_current_set(wait_queue_t *queue, wait_t *wait, uint32_t wait_state) { 120 | assert(current != NULL); 121 | wait_init(wait, current); 122 | current->state = PROC_SLEEPING; 123 | current->wait_state = wait_state; 124 | wait_queue_add(queue, wait); 125 | } 126 | 127 | -------------------------------------------------------------------------------- /code-with-comments/kern/sync/wait.h: -------------------------------------------------------------------------------- 1 | #ifndef __KERN_SYNC_WAIT_H__ 2 | #define __KERN_SYNC_WAIT_H__ 3 | 4 | #include 5 | 6 | // 等待队列 7 | typedef struct { 8 | list_entry_t wait_head; 9 | } wait_queue_t; 10 | 11 | struct proc_struct; 12 | 13 | typedef struct { 14 | struct proc_struct *proc; // 等待进程 15 | uint32_t wakeup_flags; // 进程被放入等待队列的原因标记 16 | wait_queue_t *wait_queue; // 指向wait_t 结构所属于的 wait_queue 17 | list_entry_t wait_link; 18 | } wait_t; 19 | 20 | #define le2wait(le, member) \ 21 | to_struct((le), wait_t, member) 22 | 23 | void wait_init(wait_t *wait, struct proc_struct *proc); 24 | void wait_queue_init(wait_queue_t *queue); 25 | void wait_queue_add(wait_queue_t *queue, wait_t *wait); 26 | void wait_queue_del(wait_queue_t *queue, wait_t *wait); 27 | 28 | wait_t *wait_queue_next(wait_queue_t *queue, wait_t *wait); 29 | wait_t *wait_queue_prev(wait_queue_t *queue, wait_t *wait); 30 | wait_t *wait_queue_first(wait_queue_t *queue); 31 | wait_t *wait_queue_last(wait_queue_t *queue); 32 | 33 | bool wait_queue_empty(wait_queue_t *queue); 34 | bool wait_in_queue(wait_t *wait); 35 | void wakeup_wait(wait_queue_t *queue, wait_t *wait, uint32_t wakeup_flags, bool del); 36 | void wakeup_first(wait_queue_t *queue, uint32_t wakeup_flags, bool del); 37 | void wakeup_queue(wait_queue_t *queue, uint32_t wakeup_flags, bool del); 38 | 39 | void wait_current_set(wait_queue_t *queue, wait_t *wait, uint32_t wait_state); 40 | 41 | #define wait_current_del(queue, wait) \ 42 | do { \ 43 | if (wait_in_queue(wait)) { \ 44 | wait_queue_del(queue, wait); \ 45 | } \ 46 | } while (0) 47 | 48 | #endif /* !__KERN_SYNC_WAIT_H__ */ 49 | 50 | -------------------------------------------------------------------------------- /code-with-comments/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-with-comments/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 | /** 处理器定义的中断号 **/ 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 | // IRQ = Interrupt Request 32 | #define IRQ_OFFSET 32 // IRQ 0 corresponds to int IRQ_OFFSET 33 | 34 | #define IRQ_TIMER 0 35 | #define IRQ_KBD 1 36 | #define IRQ_COM1 4 37 | #define IRQ_IDE1 14 38 | #define IRQ_IDE2 15 39 | #define IRQ_ERROR 19 40 | #define IRQ_SPURIOUS 31 41 | 42 | /* * 43 | * These are arbitrarily chosen, but with care not to overlap 44 | * processor defined exceptions or interrupt vectors. 45 | * */ 46 | #define T_SWITCH_TOU 120 // user/kernel switch 47 | #define T_SWITCH_TOK 121 // user/kernel switch 48 | 49 | /* 执行pushal 指令时,这些寄存器值入栈 */ 50 | /* 参考 syscall,这些都是系统调用时传入的参数和返回值参数;eax 接收返回值 */ 51 | struct pushregs { 52 | uint32_t reg_edi; 53 | uint32_t reg_esi; 54 | uint32_t reg_ebp; 55 | uint32_t reg_oesp; /* Useless */ 56 | uint32_t reg_ebx; 57 | uint32_t reg_edx; 58 | uint32_t reg_ecx; 59 | uint32_t reg_eax; 60 | }; 61 | 62 | struct trapframe { 63 | struct pushregs tf_regs; // pushal 64 | uint16_t tf_gs; 65 | uint16_t tf_padding0; 66 | uint16_t tf_fs; 67 | uint16_t tf_padding1; 68 | uint16_t tf_es; 69 | uint16_t tf_padding2; 70 | uint16_t tf_ds; 71 | uint16_t tf_padding3; 72 | uint32_t tf_trapno; 73 | /* 下列字段由 x86 硬件定义 */ 74 | uint32_t tf_err; 75 | uintptr_t tf_eip; // 产生中断后 76 | uint16_t tf_cs; 77 | uint16_t tf_padding4; 78 | uint32_t tf_eflags; 79 | /* 下列字段近用于跨级别调用,如从 user 跨入 kernel */ 80 | uintptr_t tf_esp; 81 | uint16_t tf_ss; 82 | uint16_t tf_padding5; 83 | } __attribute__((packed));//取消结构在编译过程中的优化对齐,按照实际结构对齐. 84 | 85 | void idt_init(void); 86 | void print_trapframe(struct trapframe *tf); 87 | void print_regs(struct pushregs *regs); 88 | bool trap_in_kernel(struct trapframe *tf); 89 | 90 | #endif /* !__KERN_TRAP_TRAP_H__ */ 91 | 92 | -------------------------------------------------------------------------------- /code-with-comments/kern/trap/trapentry.S: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | # struct pushregs { 4 | # uint32_t reg_edi; 5 | # uint32_t reg_esi; 6 | # uint32_t reg_ebp; 7 | # uint32_t reg_oesp; /* Useless */ 8 | # uint32_t reg_ebx; 9 | # uint32_t reg_edx; 10 | # uint32_t reg_ecx; 11 | # uint32_t reg_eax; 12 | # }; 13 | 14 | # struct trapframe { 15 | # struct pushregs tf_regs; 4 pushal 16 | # uint16_t tf_gs; 3 17 | # uint16_t tf_padding0; 18 | # uint16_t tf_fs; 2 19 | # uint16_t tf_padding1; 20 | # uint16_t tf_es; 1 21 | # uint16_t tf_padding2; 22 | # uint16_t tf_ds; 0 23 | # uint16_t tf_padding3; 24 | # uint32_t tf_trapno; 25 | # /* below here defined by x86 hardware */ 26 | # uint32_t tf_err; 27 | # uintptr_t tf_eip; 28 | # uint16_t tf_cs; 29 | # uint16_t tf_padding4; 30 | # uint32_t tf_eflags; 31 | # /* below here only when crossing rings, such as from user to kernel */ 32 | # uintptr_t tf_esp; 33 | # uint16_t tf_ss; 34 | # uint16_t tf_padding5; 35 | # } __attribute__((packed)); 36 | 37 | 38 | 39 | # vectors.S 把所有 trap 发送到此 40 | .text 41 | .globl __alltraps 42 | __alltraps: 43 | # 中断陷入执行至此,由于 int 指令的结果,栈上已有 44 | # | trapno | 45 | # | errno | 46 | # | eip | 47 | # | cs | 48 | # | eflags | 49 | # | ss | 50 | # | sp | 51 | 52 | # 继续 push 寄存器值,以在栈空间构造struct trapframe中断帧.每个 pushl 都压入一个 uint32,对应 trapframe 中两个 uint16. 53 | pushl %ds 54 | pushl %es 55 | pushl %fs 56 | pushl %gs 57 | # pushal = pushregs 58 | pushal 59 | 60 | # 设置内核的 ds,es段地址为GD_KDATA,准备内核环境 61 | movl $GD_KDATA, %eax 62 | movw %ax, %ds 63 | movw %ax, %es 64 | 65 | # 把刚刚构造的 trap frame 的地址作为参数传入trap(),并调用 66 | pushl %esp 67 | call trap 68 | 69 | # 清理调用 trap 前压栈的 esp 70 | popl %esp 71 | 72 | # 通过__trapret从中断返回. 73 | # 中断返回: 74 | # 75 | 76 | 77 | 78 | .globl __trapret 79 | __trapret: 80 | # 1. 恢复各种寄存器值 81 | popal 82 | 83 | popl %gs 84 | popl %fs 85 | popl %es 86 | popl %ds 87 | 88 | # 去掉 trap number 和 error code 89 | addl $0x8, %esp 90 | # int n 命令: 91 | # 1. 标志寄存器入栈 92 | # 2. CS,IP 入栈,(IP)=(n*4), (CS)=(n*4+2) 93 | # iret 命令: 94 | # 1. 恢复 CS,IP 95 | # 2. 恢复标志寄存器 96 | # 3. 恢复 ESP,SS.(权限发生变化) 97 | iret 98 | 99 | # forkrets(current->tf); 100 | # 参数是当前进程的 tf 101 | # 此处直接利用参数中的 tf,设置新的进程的各种状态 102 | .globl forkrets 103 | forkrets: 104 | # set stack to this new process's trapframe 105 | movl 4(%esp), %esp 106 | jmp __trapret 107 | -------------------------------------------------------------------------------- /code-with-comments/libs/atomic.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIBS_ATOMIC_H__ 2 | #define __LIBS_ATOMIC_H__ 3 | 4 | /* Atomic operations that C can't guarantee us. Useful for resource counting etc.. */ 5 | 6 | static inline void set_bit(int nr, volatile void *addr) __attribute__((always_inline)); 7 | static inline void clear_bit(int nr, volatile void *addr) __attribute__((always_inline)); 8 | static inline void change_bit(int nr, volatile void *addr) __attribute__((always_inline)); 9 | static inline bool test_and_set_bit(int nr, volatile void *addr) __attribute__((always_inline)); 10 | static inline bool test_and_clear_bit(int nr, volatile void *addr) __attribute__((always_inline)); 11 | static inline bool test_bit(int nr, volatile void *addr) __attribute__((always_inline)); 12 | 13 | /* * 14 | * set_bit - Atomically set a bit in memory 15 | * @nr: the bit to set 16 | * @addr: the address to start counting from 17 | * 18 | * Note that @nr may be almost arbitrarily large; this function is not 19 | * restricted to acting on a single-word quantity. 20 | * */ 21 | static inline void 22 | set_bit(int nr, volatile void *addr) { 23 | asm volatile ("btsl %1, %0" :"=m" (*(volatile long *)addr) : "Ir" (nr)); 24 | } 25 | 26 | /* * 27 | * clear_bit - Atomically clears a bit in memory 28 | * @nr: the bit to clear 29 | * @addr: the address to start counting from 30 | * */ 31 | static inline void 32 | clear_bit(int nr, volatile void *addr) { 33 | asm volatile ("btrl %1, %0" :"=m" (*(volatile long *)addr) : "Ir" (nr)); 34 | } 35 | 36 | /* * 37 | * change_bit - Atomically toggle a bit in memory 38 | * @nr: the bit to change 39 | * @addr: the address to start counting from 40 | * */ 41 | static inline void 42 | change_bit(int nr, volatile void *addr) { 43 | asm volatile ("btcl %1, %0" :"=m" (*(volatile long *)addr) : "Ir" (nr)); 44 | } 45 | 46 | /* * 47 | * test_bit - Determine whether a bit is set 48 | * @nr: the bit to test 49 | * @addr: the address to count from 50 | * */ 51 | static inline bool 52 | test_bit(int nr, volatile void *addr) { 53 | int oldbit; 54 | asm volatile ("btl %2, %1; sbbl %0,%0" : "=r" (oldbit) : "m" (*(volatile long *)addr), "Ir" (nr)); 55 | return oldbit != 0; 56 | } 57 | 58 | /* * 59 | * test_and_set_bit - Atomically set a bit and return its old value 60 | * @nr: the bit to set 61 | * @addr: the address to count from 62 | * */ 63 | static inline bool 64 | test_and_set_bit(int nr, volatile void *addr) { 65 | int oldbit; 66 | asm volatile ("btsl %2, %1; sbbl %0, %0" : "=r" (oldbit), "=m" (*(volatile long *)addr) : "Ir" (nr) : "memory"); 67 | return oldbit != 0; 68 | } 69 | 70 | /* * 71 | * test_and_clear_bit - Atomically clear a bit and return its old value 72 | * @nr: the bit to clear 73 | * @addr: the address to count from 74 | * */ 75 | static inline bool 76 | test_and_clear_bit(int nr, volatile void *addr) { 77 | int oldbit; 78 | asm volatile ("btrl %2, %1; sbbl %0, %0" : "=r" (oldbit), "=m" (*(volatile long *)addr) : "Ir" (nr) : "memory"); 79 | return oldbit != 0; 80 | } 81 | #endif /* !__LIBS_ATOMIC_H__ */ 82 | 83 | -------------------------------------------------------------------------------- /code-with-comments/libs/defs.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIBS_DEFS_H__ 2 | #define __LIBS_DEFS_H__ 3 | 4 | #ifndef NULL 5 | #define NULL ((void *)0) 6 | #endif 7 | 8 | #define __always_inline inline __attribute__((always_inline)) 9 | #define __noinline __attribute__((noinline)) 10 | #define __noreturn __attribute__((noreturn)) 11 | 12 | #define CHAR_BIT 8 13 | 14 | /* Represents true-or-false values */ 15 | typedef int bool; 16 | 17 | /* Explicitly-sized versions of integer types */ 18 | typedef char int8_t; 19 | typedef unsigned char uint8_t; 20 | typedef short int16_t; 21 | typedef unsigned short uint16_t; 22 | typedef int int32_t; 23 | typedef unsigned int uint32_t; 24 | typedef long long int64_t; 25 | typedef unsigned long long uint64_t; 26 | 27 | /* * 28 | * Pointers and addresses are 32 bits long. 29 | * We use pointer types to represent addresses, 30 | * uintptr_t to represent the numerical values of addresses. 31 | * */ 32 | typedef int32_t intptr_t; 33 | typedef uint32_t uintptr_t; // 32bit=4byte 34 | 35 | /* size_t is used for memory object sizes */ 36 | typedef uintptr_t size_t; 37 | 38 | /* off_t is used for file offsets and lengths */ 39 | typedef intptr_t off_t; 40 | 41 | /* used for page numbers */ 42 | typedef size_t ppn_t; 43 | 44 | /* * 45 | * Rounding operations (efficient when n is a power of 2) 46 | * Round down to the nearest multiple of n 47 | * */ 48 | // 把 a 向下取整至最近的 n 的倍数 49 | #define ROUNDDOWN(a, n) ({ \ 50 | size_t __a = (size_t)(a); \ 51 | (typeof(a))(__a - __a % (n)); \ 52 | }) 53 | 54 | /* Round up to the nearest multiple of n */ 55 | // 把 a 向上取整至最近的 n 的倍数 56 | #define ROUNDUP(a, n) ({ \ 57 | size_t __n = (size_t)(n); \ 58 | (typeof(a))(ROUNDDOWN((size_t)(a) + __n - 1, __n)); \ 59 | }) 60 | 61 | /* Round up the result of dividing of n */ 62 | /** 把 a/n 的结果向上取整.如 33/4 结果为 9 **/ 63 | #define ROUNDUP_DIV(a, n) ({ \ 64 | uint32_t __n = (uint32_t)(n); \ 65 | (typeof(a))(((a) + __n - 1) / __n); \ 66 | }) 67 | 68 | /* Return the offset of 'member' relative to the beginning of a struct type */ 69 | #define offsetof(type, member) \ 70 | ((size_t)(&((type *)0)->member)) 71 | 72 | /* * 73 | * to_struct - get the struct from a ptr 74 | * @ptr: a struct pointer of member 75 | * @type: the type of the struct this is embedded in 76 | * @member: the name of the member within the struct 77 | * */ 78 | #define to_struct(ptr, type, member) \ 79 | ((type *)((char *)(ptr) - offsetof(type, member))) 80 | 81 | #endif /* !__LIBS_DEFS_H__ */ 82 | 83 | -------------------------------------------------------------------------------- /code-with-comments/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-with-comments/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-with-comments/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-with-comments/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-with-comments/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-with-comments/libs/skew_heap.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIBS_SKEW_HEAP_H__ 2 | #define __LIBS_SKEW_HEAP_H__ 3 | 4 | 5 | /** 6 | * 斜堆相关算法 7 | * 8 | */ 9 | struct skew_heap_entry { 10 | struct skew_heap_entry *parent, *left, *right; 11 | }; 12 | 13 | typedef struct skew_heap_entry skew_heap_entry_t; 14 | 15 | typedef int(*compare_f)(void *a, void *b); 16 | 17 | static inline void skew_heap_init(skew_heap_entry_t *a) __attribute__((always_inline)); 18 | static inline skew_heap_entry_t *skew_heap_merge( 19 | skew_heap_entry_t *a, skew_heap_entry_t *b, 20 | compare_f comp); 21 | static inline skew_heap_entry_t *skew_heap_insert( 22 | skew_heap_entry_t *a, skew_heap_entry_t *b, 23 | compare_f comp) __attribute__((always_inline)); 24 | static inline skew_heap_entry_t *skew_heap_remove( 25 | skew_heap_entry_t *a, skew_heap_entry_t *b, 26 | compare_f comp) __attribute__((always_inline)); 27 | 28 | static inline void 29 | skew_heap_init(skew_heap_entry_t *a) 30 | { 31 | a->left = a->right = a->parent = NULL; 32 | } 33 | 34 | static inline skew_heap_entry_t * 35 | skew_heap_merge(skew_heap_entry_t *a, skew_heap_entry_t *b, 36 | compare_f comp) 37 | { 38 | if (a == NULL) return b; 39 | else if (b == NULL) return a; 40 | 41 | skew_heap_entry_t *l, *r; 42 | if (comp(a, b) == -1) 43 | { 44 | r = a->left; 45 | l = skew_heap_merge(a->right, b, comp); 46 | 47 | a->left = l; 48 | a->right = r; 49 | if (l) l->parent = a; 50 | 51 | return a; 52 | } 53 | else 54 | { 55 | r = b->left; 56 | l = skew_heap_merge(a, b->right, comp); 57 | 58 | b->left = l; 59 | b->right = r; 60 | if (l) l->parent = b; 61 | 62 | return b; 63 | } 64 | } 65 | 66 | static inline skew_heap_entry_t * 67 | skew_heap_insert(skew_heap_entry_t *a, skew_heap_entry_t *b, 68 | compare_f comp) 69 | { 70 | skew_heap_init(b); 71 | return skew_heap_merge(a, b, comp); 72 | } 73 | 74 | static inline skew_heap_entry_t * 75 | skew_heap_remove(skew_heap_entry_t *a, skew_heap_entry_t *b, 76 | compare_f comp) 77 | { 78 | skew_heap_entry_t *p = b->parent; 79 | skew_heap_entry_t *rep = skew_heap_merge(b->left, b->right, comp); 80 | if (rep) rep->parent = p; 81 | 82 | if (p) 83 | { 84 | if (p->left == b) 85 | p->left = rep; 86 | else p->right = rep; 87 | return a; 88 | } 89 | else return rep; 90 | } 91 | 92 | #endif /* !__LIBS_SKEW_HEAP_H__ */ 93 | -------------------------------------------------------------------------------- /code-with-comments/libs/stat.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIBS_STAT_H__ 2 | #define __LIBS_STAT_H__ 3 | 4 | #include 5 | 6 | /** 7 | * 文件信息 8 | */ 9 | struct stat { 10 | uint32_t st_mode; // protection mode and file type 11 | size_t st_nlinks; // number of hard links 12 | size_t st_blocks; // number of blocks file is using 13 | size_t st_size; // file size (bytes) 14 | }; 15 | 16 | #define S_IFMT 070000 // mask for type of file 17 | #define S_IFREG 010000 // ordinary regular file 18 | #define S_IFDIR 020000 // directory 19 | #define S_IFLNK 030000 // symbolic link 20 | #define S_IFCHR 040000 // character device 21 | #define S_IFBLK 050000 // block device 22 | 23 | #define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) // regular file 24 | #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) // directory 25 | #define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) // symlink 26 | #define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) // char device 27 | #define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) // block device 28 | 29 | #endif /* !__LIBS_STAT_H__ */ 30 | 31 | -------------------------------------------------------------------------------- /code-with-comments/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-with-comments/libs/stdio.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIBS_STDIO_H__ 2 | #define __LIBS_STDIO_H__ 3 | 4 | #include 5 | #include 6 | 7 | 8 | /* kern/libs/stdio.c */ 9 | int cprintf(const char *fmt, ...); 10 | int vcprintf(const char *fmt, va_list ap); 11 | void cputchar(int c); 12 | int cputs(const char *str); 13 | int getchar(void); 14 | 15 | /* kern/libs/readline.c */ 16 | char *readline(const char *prompt); 17 | 18 | /* libs/printfmt.c */ 19 | void printfmt(void (*putch)(int, void *, int), int fd, void *putdat, const char *fmt, ...); 20 | void vprintfmt(void (*putch)(int, void *, int), int fd, void *putdat, const char *fmt, va_list ap); 21 | int snprintf(char *str, size_t size, const char *fmt, ...); 22 | int vsnprintf(char *str, size_t size, const char *fmt, va_list ap); 23 | 24 | #endif /* !__LIBS_STDIO_H__ */ 25 | 26 | -------------------------------------------------------------------------------- /code-with-comments/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-with-comments/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-with-comments/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_yield 10 13 | #define SYS_sleep 11 14 | #define SYS_kill 12 15 | #define SYS_gettime 17 16 | #define SYS_getpid 18 17 | #define SYS_mmap 20 18 | #define SYS_munmap 21 19 | #define SYS_shmem 22 20 | #define SYS_putc 30 21 | #define SYS_pgdir 31 22 | #define SYS_open 100 23 | #define SYS_close 101 24 | #define SYS_read 102 25 | #define SYS_write 103 26 | #define SYS_seek 104 27 | #define SYS_fstat 110 28 | #define SYS_fsync 111 29 | #define SYS_getcwd 121 30 | #define SYS_getdirentry 128 31 | #define SYS_dup 130 32 | /* OLNY FOR LAB6 */ 33 | #define SYS_lab6_set_priority 255 34 | 35 | /* SYS_fork flags */ 36 | #define CLONE_VM 0x00000100 // set if VM shared between processes 37 | #define CLONE_THREAD 0x00000200 // thread group 38 | #define CLONE_FS 0x00000800 // set if shared between processes 39 | 40 | /* VFS flags */ 41 | // flags for open: choose one of these 42 | #define O_RDONLY 0 // open for reading only 43 | #define O_WRONLY 1 // open for writing only 44 | #define O_RDWR 2 // open for reading and writing 45 | // then or in any of these: 46 | #define O_CREAT 0x00000004 // create file if it does not exist 47 | #define O_EXCL 0x00000008 // error if O_CREAT and the file exists 48 | #define O_TRUNC 0x00000010 // truncate file upon open,不可与只读共存 49 | #define O_APPEND 0x00000020 // append on each write 50 | // additonal related definition 51 | #define O_ACCMODE 3 // mask for O_RDONLY / O_WRONLY / O_RDWR 52 | 53 | #define NO_FD -0x9527 // invalid fd 54 | 55 | /* lseek codes */ 56 | #define LSEEK_SET 0 // seek relative to beginning of file 57 | #define LSEEK_CUR 1 // seek relative to current position in file 58 | #define LSEEK_END 2 // seek relative to end of file 59 | 60 | #define FS_MAX_DNAME_LEN 31 61 | #define FS_MAX_FNAME_LEN 255 62 | #define FS_MAX_FPATH_LEN 4095 63 | 64 | #define EXEC_MAX_ARG_NUM 32 65 | #define EXEC_MAX_ARG_LEN 4095 66 | 67 | #endif /* !__LIBS_UNISTD_H__ */ 68 | 69 | -------------------------------------------------------------------------------- /code-with-comments/readme.md: -------------------------------------------------------------------------------- 1 | ## Quickstart 2 | 3 | **编译并运行** 4 | 5 | - `make qemu-nox` 6 | 7 | **退出系统** 8 | 9 | - `Ctrl + A,X`. 10 | 11 | **gdb 调试** 12 | 13 | 调整 makefile,将 gnome 换成 zsh,选项变为 c,将 i386-elf-gdb 换成gdb. 14 | 15 | 建议调试方法: 16 | 1. 启动 1 个窗口,执行 make dbg4ec 17 | 2. 启动另一个窗口,执行 make debug-gdb, 即可分开gdb 输出和 qemu 输出,避免花屏,输出更加清晰 18 | 19 | ## CLion 环境搭建 20 | 21 | 参考 jetbrains [官方文档](https://www.jetbrains.com/help/clion/managing-makefile-projects.html) 22 | 23 | -------------------------------------------------------------------------------- /code-with-comments/tools/boot.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf32-i386") 2 | OUTPUT_ARCH(i386) 3 | 4 | /** .data 5 | * .startup 6 | * 0x7C00 .text 7 | */ 8 | 9 | SECTIONS { 10 | . = 0x7C00; 11 | 12 | .startup : { 13 | *bootasm.o(.text) 14 | } 15 | 16 | .text : { *(.text) } 17 | .data : { *(.data .rodata) } 18 | 19 | /DISCARD/ : { *(.eh_*) } 20 | } 21 | -------------------------------------------------------------------------------- /code-with-comments/tools/function.mk: -------------------------------------------------------------------------------- 1 | # https://blog.csdn.net/u013484370/article/details/50638353 2 | 3 | OBJPREFIX := __objs_ 4 | 5 | .SECONDEXPANSION: 6 | # -------------------- function begin -------------------- 7 | 8 | # list all files in some directories: (#directories, #types) 9 | # 返回相应directories目录下所有 类型为types的文件 10 | listf = $(filter $(if $(2),$(addprefix %.,$(2)),%),\ 11 | $(wildcard $(addsuffix $(SLASH)*,$(1)))) 12 | 13 | # get .o obj files: (#files[, packet]) 14 | # 给出以.o结尾的obj文件名列表files,和软件包名称packet,返回相应文件的目标文件名称 15 | toobj = $(addprefix $(OBJDIR)$(SLASH)$(if $(2),$(2)$(SLASH)),\ 16 | $(addsuffix .o,$(basename $(1)))) 17 | 18 | # get .d dependency files: (#files[, packet]) 19 | todep = $(patsubst %.o,%.d,$(call toobj,$(1),$(2))) 20 | 21 | # 加前缀. bin/$(1) 22 | totarget = $(addprefix $(BINDIR)$(SLASH),$(1)) 23 | 24 | # change $(name) to $(OBJPREFIX)$(name): (#names) 25 | packetname = $(if $(1),$(addprefix $(OBJPREFIX),$(1)),$(OBJPREFIX)) 26 | 27 | # cc compile template, generate rule for dep, obj: (file, cc[, flags, dir]) 28 | define cc_template 29 | $$(call todep,$(1),$(4)): $(1) | $$$$(dir $$$$@) 30 | @$(2) -I$$(dir $(1)) $(3) -MM $$< -MT "$$(patsubst %.d,%.o,$$@) $$@"> $$@ 31 | $$(call toobj,$(1),$(4)): $(1) | $$$$(dir $$$$@) 32 | @echo + cc $$< 33 | $(V)$(2) -I$$(dir $(1)) $(3) -c $$< -o $$@ 34 | ALLOBJS += $$(call toobj,$(1),$(4)) 35 | endef 36 | 37 | # compile file: (#files, cc[, flags, dir]) 38 | define do_cc_compile 39 | $$(foreach f,$(1),$$(eval $$(call cc_template,$$(f),$(2),$(3),$(4)))) 40 | endef 41 | 42 | # add files to packet: (#files, cc[, flags, packet, dir]) 43 | define do_add_files_to_packet 44 | __temp_packet__ := $(call packetname,$(4)) 45 | ifeq ($$(origin $$(__temp_packet__)),undefined) 46 | $$(__temp_packet__) := 47 | endif 48 | __temp_objs__ := $(call toobj,$(1),$(5)) 49 | $$(foreach f,$(1),$$(eval $$(call cc_template,$$(f),$(2),$(3),$(5)))) 50 | $$(__temp_packet__) += $$(__temp_objs__) 51 | endef 52 | 53 | # add objs to packet: (#objs, packet) 54 | define do_add_objs_to_packet 55 | __temp_packet__ := $(call packetname,$(2)) 56 | ifeq ($$(origin $$(__temp_packet__)),undefined) 57 | $$(__temp_packet__) := 58 | endif 59 | $$(__temp_packet__) += $(1) 60 | endef 61 | 62 | # add packets and objs to target (target, #packes, #objs[, cc, flags]) 63 | define do_create_target 64 | __temp_target__ = $(call totarget,$(1)) 65 | __temp_objs__ = $$(foreach p,$(call packetname,$(2)),$$($$(p))) $(3) 66 | TARGETS += $$(__temp_target__) 67 | ifneq ($(4),) 68 | $$(__temp_target__): $$(__temp_objs__) | $$$$(dir $$$$@) 69 | $(V)$(4) $(5) $$^ -o $$@ 70 | else 71 | $$(__temp_target__): $$(__temp_objs__) | $$$$(dir $$$$@) 72 | endif 73 | endef 74 | 75 | # finish all 76 | define do_finish_all 77 | ALLDEPS = $$(ALLOBJS:.o=.d) 78 | $$(sort $$(dir $$(ALLOBJS)) $(BINDIR)$(SLASH) $(OBJDIR)$(SLASH)): 79 | @$(MKDIR) $$@ 80 | endef 81 | 82 | # -------------------- function end -------------------- 83 | # compile file: (#files, cc[, flags, dir]) 84 | cc_compile = $(eval $(call do_cc_compile,$(1),$(2),$(3),$(4))) 85 | 86 | # add files to packet: (#files, cc[, flags, packet, dir]) 87 | add_files = $(eval $(call do_add_files_to_packet,$(1),$(2),$(3),$(4),$(5))) 88 | 89 | # add objs to packet: (#objs, packet) 90 | add_objs = $(eval $(call do_add_objs_to_packet,$(1),$(2))) 91 | 92 | # add packets and objs to target (target, #packes, #objs, cc, [, flags]) 93 | create_target = $(eval $(call do_create_target,$(1),$(2),$(3),$(4),$(5))) 94 | 95 | read_packet = $(foreach p,$(call packetname,$(1)),$($(p))) 96 | 97 | add_dependency = $(eval $(1): $(2)) 98 | 99 | finish_all = $(eval $(call do_finish_all)) 100 | 101 | -------------------------------------------------------------------------------- /code-with-comments/tools/gdbinit: -------------------------------------------------------------------------------- 1 | file bin/kernel 2 | target remote :1234 3 | break kern_init 4 | -------------------------------------------------------------------------------- /code-with-comments/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 | . = ALIGN(0x1000); 48 | .data.pgdir : { 49 | *(.data.pgdir) 50 | } 51 | 52 | PROVIDE(edata = .); 53 | 54 | .bss : { 55 | *(.bss) 56 | } 57 | 58 | PROVIDE(end = .);/* bootloader加载ucore的结束地址 */ 59 | 60 | /DISCARD/ : { 61 | *(.eh_frame .note.GNU-stack) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /code-with-comments/tools/sign.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int 7 | main(int argc, char *argv[]) { 8 | fprintf(stdout,"\n----------boot sector 生成程序----------\n\n"); 9 | fprintf(stdout,"源文件: %s, 目标磁盘文件: %s.\n,",argv[1],argv[2]); 10 | fprintf(stdout,"原理: 复制源文件至缓冲区,校验大小,把第 511 和 512 个字节置为 0x55 和 0xAA 写入目标文件.\n"); 11 | 12 | 13 | struct stat st; 14 | if (argc != 3) { 15 | fprintf(stderr, "Usage: \n"); 16 | return -1; 17 | } 18 | if (stat(argv[1], &st) != 0) { 19 | fprintf(stderr, "Error opening file '%s': %s\n", argv[1], strerror(errno)); 20 | return -1; 21 | } 22 | //printf("'%s' size: %lld bytes\n", argv[1], (long long)st.st_size); 23 | if (st.st_size > 510) { 24 | fprintf(stderr, "%lld >> 510!!\n", (long long)st.st_size); 25 | return -1; 26 | }else{ 27 | fprintf(stdout, "文件大小校验: 可执行文件大小 = %lld < 510, 校验通过.\n",(long long)st.st_size); 28 | } 29 | char buf[512]; 30 | memset(buf, 0, sizeof(buf)); 31 | FILE *ifp = fopen(argv[1], "rb"); 32 | int size = fread(buf, 1, st.st_size, ifp); 33 | if (size != st.st_size) { 34 | fprintf(stderr, "read '%s' error, size is %d.\n", argv[1], size); 35 | return -1; 36 | } 37 | fclose(ifp); 38 | buf[510] = 0x55; 39 | buf[511] = 0xAA; 40 | FILE *ofp = fopen(argv[2], "wb+"); 41 | size = fwrite(buf, 1, 512, ofp); 42 | if (size != 512) { 43 | fprintf(stderr, "write '%s' error, size is %d.\n", argv[2], size); 44 | return -1; 45 | } 46 | fclose(ofp); 47 | printf("\n----------512 字节 boot sector: '%s' 构建成功!----------\n\n", argv[2]); 48 | return 0; 49 | } 50 | 51 | -------------------------------------------------------------------------------- /code-with-comments/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-with-comments/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-with-comments/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-with-comments/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-with-comments/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-with-comments/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 | else { 22 | cprintf("I am parent, fork a child pid %d\n",pid); 23 | } 24 | assert(pid > 0); 25 | cprintf("I am the parent, waiting now..\n"); 26 | 27 | assert(waitpid(pid, &code) == 0 && code == magic); 28 | assert(waitpid(pid, &code) != 0 && wait() != 0); 29 | cprintf("waitpid %d ok.\n", pid); 30 | 31 | cprintf("exit pass.\n"); 32 | return 0; 33 | } 34 | 35 | -------------------------------------------------------------------------------- /code-with-comments/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-with-comments/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-with-comments/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-with-comments/user/forktree.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define DEPTH 4 6 | #define SLEEP_TIME 400 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 | cprintf("forktree process will sleep %d ticks\n",SLEEP_TIME); 35 | sleep(SLEEP_TIME); 36 | forktree(""); 37 | return 0; 38 | } 39 | 40 | -------------------------------------------------------------------------------- /code-with-comments/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-with-comments/user/libs/dir.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | DIR dir, *dirp=&dir; 12 | 13 | // path -- > DIR 14 | DIR * 15 | opendir(const char *path) { 16 | 17 | if ((dirp->fd = open(path, O_RDONLY)) < 0) { 18 | goto failed; 19 | } 20 | struct stat __stat, *stat = &__stat; 21 | if (fstat(dirp->fd, stat) != 0 || !S_ISDIR(stat->st_mode)) { 22 | goto failed; 23 | } 24 | dirp->dirent.offset = 0; 25 | return dirp; 26 | 27 | failed: 28 | return NULL; 29 | } 30 | 31 | struct dirent * 32 | readdir(DIR *dirp) { 33 | if (sys_getdirentry(dirp->fd, &(dirp->dirent)) == 0) { 34 | return &(dirp->dirent); 35 | } 36 | return NULL; 37 | } 38 | 39 | void 40 | closedir(DIR *dirp) { 41 | close(dirp->fd); 42 | } 43 | 44 | int 45 | getcwd(char *buffer, size_t len) { 46 | return sys_getcwd(buffer, len); 47 | } 48 | 49 | -------------------------------------------------------------------------------- /code-with-comments/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 | 18 | #endif /* !__USER_LIBS_DIR_H__ */ 19 | 20 | -------------------------------------------------------------------------------- /code-with-comments/user/libs/file.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int 10 | open(const char *path, uint32_t open_flags) { 11 | return sys_open(path, open_flags); 12 | } 13 | 14 | int 15 | close(int fd) { 16 | return sys_close(fd); 17 | } 18 | 19 | /** 20 | * 从 fd 读取len 个字节到 base 21 | */ 22 | int 23 | read(int fd, void *base, size_t len) { 24 | return sys_read(fd, base, len); 25 | } 26 | 27 | int 28 | write(int fd, void *base, size_t len) { 29 | return sys_write(fd, base, len); 30 | } 31 | 32 | int 33 | seek(int fd, off_t pos, int whence) { 34 | return sys_seek(fd, pos, whence); 35 | } 36 | 37 | int 38 | fstat(int fd, struct stat *stat) { 39 | return sys_fstat(fd, stat); 40 | } 41 | 42 | int 43 | fsync(int fd) { 44 | return sys_fsync(fd); 45 | } 46 | 47 | int 48 | dup2(int fd1, int fd2) { 49 | return sys_dup(fd1, fd2); 50 | } 51 | 52 | static char 53 | transmode(struct stat *stat) { 54 | uint32_t mode = stat->st_mode; 55 | if (S_ISREG(mode)) return 'r'; 56 | if (S_ISDIR(mode)) return 'd'; 57 | if (S_ISLNK(mode)) return 'l'; 58 | if (S_ISCHR(mode)) return 'c'; 59 | if (S_ISBLK(mode)) return 'b'; 60 | return '-'; 61 | } 62 | 63 | void 64 | print_stat(const char *name, int fd, struct stat *stat) { 65 | cprintf("[%03d] %s\n", fd, name); 66 | cprintf(" mode : %c\n", transmode(stat)); 67 | cprintf(" links : %lu\n", stat->st_nlinks); 68 | cprintf(" blocks : %lu\n", stat->st_blocks); 69 | cprintf(" size : %lu\n", stat->st_size); 70 | } 71 | 72 | -------------------------------------------------------------------------------- /code-with-comments/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-with-comments/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 | 12 | # move down the esp register 13 | # since it may cause page fault in backtrace 14 | subl $0x20, %esp 15 | 16 | # save argc and argv on stack 17 | pushl %ecx 18 | pushl %ebx 19 | 20 | # call user-program function 21 | call umain 22 | 1: jmp 1b 23 | 24 | 25 | -------------------------------------------------------------------------------- /code-with-comments/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-with-comments/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-with-comments/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 | 67 | static void 68 | fputch(char c, int *cnt, int fd) { 69 | write(fd, &c, sizeof(char)); 70 | (*cnt) ++; 71 | } 72 | 73 | int 74 | vfprintf(int fd, const char *fmt, va_list ap) { 75 | int cnt = 0; 76 | vprintfmt((void*)fputch, fd, &cnt, fmt, ap); 77 | return cnt; 78 | } 79 | 80 | int 81 | fprintf(int fd, const char *fmt, ...) { 82 | va_list ap; 83 | 84 | va_start(ap, fmt); 85 | int cnt = vfprintf(fd, fmt, ap); 86 | va_end(ap); 87 | 88 | return cnt; 89 | } 90 | -------------------------------------------------------------------------------- /code-with-comments/user/libs/syscall.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | #define MAX_ARGS 5 10 | 11 | static inline int 12 | syscall(int num, ...) { 13 | va_list ap; 14 | va_start(ap, num); 15 | uint32_t a[MAX_ARGS]; 16 | int i, ret; 17 | for (i = 0; i < MAX_ARGS; i ++) { 18 | a[i] = va_arg(ap, uint32_t); 19 | } 20 | va_end(ap); 21 | // 事实上构造了 trapframe 的 22 | asm volatile ( 23 | "int %1;" // int = 24 | : "=a" (ret) // 输出约束:返回值写入到 eax 25 | : "i" (T_SYSCALL), // 输入操作数: 系统调用导致的中断 26 | "a" (num), // eax, 中断号, trap_no 27 | "d" (a[0]), // edx 28 | "c" (a[1]), // ecx 29 | "b" (a[2]), // ebx 30 | "D" (a[3]), // edi 31 | "S" (a[4]) // esi 32 | : "cc", "memory"); // 乱码列表: 1 可能影响标志位 2 内存可能改变 33 | return ret; 34 | } 35 | 36 | int 37 | sys_exit(int error_code) { 38 | return syscall(SYS_exit, error_code); 39 | } 40 | 41 | int 42 | sys_fork(void) { 43 | return syscall(SYS_fork); 44 | } 45 | 46 | int 47 | sys_wait(int pid, int *store) { 48 | return syscall(SYS_wait, pid, store); 49 | } 50 | 51 | int 52 | sys_yield(void) { 53 | return syscall(SYS_yield); 54 | } 55 | 56 | int 57 | sys_kill(int pid) { 58 | return syscall(SYS_kill, pid); 59 | } 60 | 61 | int 62 | sys_getpid(void) { 63 | return syscall(SYS_getpid); 64 | } 65 | 66 | int 67 | sys_putc(int c) { 68 | return syscall(SYS_putc, c); 69 | } 70 | 71 | int 72 | sys_pgdir(void) { 73 | return syscall(SYS_pgdir); 74 | } 75 | 76 | void 77 | sys_lab6_set_priority(uint32_t priority) 78 | { 79 | syscall(SYS_lab6_set_priority, priority); 80 | } 81 | 82 | int 83 | sys_sleep(unsigned int time) { 84 | return syscall(SYS_sleep, time); 85 | } 86 | 87 | size_t 88 | sys_gettime(void) { 89 | return syscall(SYS_gettime); 90 | } 91 | 92 | int 93 | sys_exec(const char *name, int argc, const char **argv) { 94 | return syscall(SYS_exec, name, argc, argv); 95 | } 96 | 97 | int 98 | sys_open(const char *path, uint32_t open_flags) { 99 | return syscall(SYS_open, path, open_flags); 100 | } 101 | 102 | int 103 | sys_close(int fd) { 104 | return syscall(SYS_close, fd); 105 | } 106 | 107 | int 108 | sys_read(int fd, void *base, size_t len) { 109 | return syscall(SYS_read, fd, base, len); 110 | } 111 | 112 | int 113 | sys_write(int fd, void *base, size_t len) { 114 | return syscall(SYS_write, fd, base, len); 115 | } 116 | 117 | int 118 | sys_seek(int fd, off_t pos, int whence) { 119 | return syscall(SYS_seek, fd, pos, whence); 120 | } 121 | 122 | int 123 | sys_fstat(int fd, struct stat *stat) { 124 | return syscall(SYS_fstat, fd, stat); 125 | } 126 | 127 | int 128 | sys_fsync(int fd) { 129 | return syscall(SYS_fsync, fd); 130 | } 131 | 132 | int 133 | sys_getcwd(char *buffer, size_t len) { 134 | return syscall(SYS_getcwd, buffer, len); 135 | } 136 | 137 | int 138 | sys_getdirentry(int fd, struct dirent *dirent) { 139 | return syscall(SYS_getdirentry, fd, dirent); 140 | } 141 | 142 | int 143 | sys_dup(int fd1, int fd2) { 144 | return syscall(SYS_dup, fd1, fd2); 145 | } 146 | -------------------------------------------------------------------------------- /code-with-comments/user/libs/syscall.h: -------------------------------------------------------------------------------- 1 | #ifndef __USER_LIBS_SYSCALL_H__ 2 | #define __USER_LIBS_SYSCALL_H__ 3 | 4 | // 均对应内核函数 do_xxx 5 | 6 | // 进程相关的系统调用 7 | int sys_exit(int error_code); 8 | int sys_fork(void); 9 | int sys_wait(int pid, int *store); 10 | int sys_exec(const char *name, int argc, const char **argv); 11 | int sys_yield(void); 12 | int sys_kill(int pid); 13 | int sys_getpid(void); 14 | int sys_putc(int c); 15 | int sys_pgdir(void); 16 | int sys_sleep(unsigned int time); 17 | size_t sys_gettime(void); 18 | 19 | struct stat; 20 | struct dirent; 21 | 22 | // 文件相关的系统调用 23 | int sys_open(const char *path, uint32_t open_flags); 24 | int sys_close(int fd); 25 | int sys_read(int fd, void *base, size_t len); 26 | int sys_write(int fd, void *base, size_t len); 27 | int sys_seek(int fd, off_t pos, int whence); 28 | int sys_fstat(int fd, struct stat *stat); 29 | int sys_fsync(int fd); 30 | int sys_getcwd(char *buffer, size_t len); 31 | int sys_getdirentry(int fd, struct dirent *dirent); 32 | int sys_dup(int fd1, int fd2); 33 | void sys_lab6_set_priority(uint32_t priority); //only for lab6 34 | 35 | 36 | #endif /* !__USER_LIBS_SYSCALL_H__ */ 37 | 38 | -------------------------------------------------------------------------------- /code-with-comments/user/libs/ulib.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | static lock_t fork_lock = INIT_LOCK; 10 | 11 | void 12 | lock_fork(void) { 13 | lock(&fork_lock); 14 | } 15 | 16 | void 17 | unlock_fork(void) { 18 | unlock(&fork_lock); 19 | } 20 | 21 | void 22 | exit(int error_code) { 23 | sys_exit(error_code); 24 | cprintf("BUG: exit failed.\n"); 25 | while (1); 26 | } 27 | 28 | int 29 | fork(void) { 30 | return sys_fork(); 31 | } 32 | 33 | int 34 | wait(void) { 35 | return sys_wait(0, NULL); 36 | } 37 | 38 | int 39 | waitpid(int pid, int *store) { 40 | return sys_wait(pid, store); 41 | } 42 | 43 | void 44 | yield(void) { 45 | sys_yield(); 46 | } 47 | 48 | int 49 | kill(int pid) { 50 | return sys_kill(pid); 51 | } 52 | 53 | int 54 | getpid(void) { 55 | return sys_getpid(); 56 | } 57 | 58 | //print_pgdir - print the PDT&PT 59 | void 60 | print_pgdir(void) { 61 | sys_pgdir(); 62 | } 63 | 64 | void 65 | lab6_set_priority(uint32_t priority) 66 | { 67 | sys_lab6_set_priority(priority); 68 | } 69 | 70 | int 71 | sleep(unsigned int time) { 72 | return sys_sleep(time); 73 | } 74 | 75 | unsigned int 76 | gettime_msec(void) { 77 | return (unsigned int)sys_gettime(); 78 | } 79 | 80 | int 81 | __exec(const char *name, const char **argv) { 82 | int argc = 0; 83 | while (argv[argc] != NULL) { 84 | argc ++; 85 | } 86 | return sys_exec(name, argc, argv); 87 | } 88 | -------------------------------------------------------------------------------- /code-with-comments/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 __noreturn __panic(const char *file, int line, const char *fmt, ...); 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 __noreturn exit(int error_code); 29 | int fork(void); 30 | int wait(void); 31 | int waitpid(int pid, int *store); 32 | void yield(void); 33 | int kill(int pid); 34 | int getpid(void); 35 | void print_pgdir(void); 36 | int sleep(unsigned int time); 37 | unsigned int gettime_msec(void); 38 | int __exec(const char *name, const char **argv); 39 | 40 | #define __exec0(name, path, ...) \ 41 | ({ const char *argv[] = {path, ##__VA_ARGS__, NULL}; __exec(name, argv); }) 42 | 43 | #define exec(path, ...) __exec0(NULL, path, ##__VA_ARGS__) 44 | #define nexec(name, path, ...) __exec0(name, path, ##__VA_ARGS__) 45 | 46 | void lab6_set_priority(uint32_t priority); //only for lab6 47 | 48 | #endif /* !__USER_LIBS_ULIB_H__ */ 49 | 50 | -------------------------------------------------------------------------------- /code-with-comments/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 | int fd1, ret; 11 | if ((fd1 = open(path, open_flags)) < 0) { 12 | return fd1; 13 | } 14 | if (fd1 != fd2) { 15 | close(fd2); 16 | ret = dup2(fd1, fd2); 17 | close(fd1); 18 | } 19 | return ret; 20 | } 21 | 22 | void 23 | umain(int argc, char *argv[]) { 24 | int fd; 25 | if ((fd = initfd(0, "stdin:", O_RDONLY)) < 0) { 26 | warn("open failed: %e.\n", fd); 27 | } 28 | if ((fd = initfd(1, "stdout:", O_WRONLY)) < 0) { 29 | warn("open failed: %e.\n", fd); 30 | } 31 | int ret = main(argc, argv); 32 | exit(ret); 33 | } 34 | 35 | -------------------------------------------------------------------------------- /code-with-comments/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 | int ret; 48 | DIR *dirp = opendir("."); 49 | 50 | if (dirp == NULL) { 51 | return -1; 52 | } 53 | struct dirent *direntp; 54 | while ((direntp = readdir(dirp)) != NULL) { 55 | if ((ret = getstat(direntp->name, stat)) != 0) { 56 | goto failed; 57 | } 58 | lsstat(stat, direntp->name); 59 | } 60 | printf("lsdir: step 4\n"); 61 | closedir(dirp); 62 | return 0; 63 | failed: 64 | closedir(dirp); 65 | return ret; 66 | } 67 | 68 | int 69 | ls(const char *path) { 70 | struct stat __stat, *stat = &__stat; 71 | int ret, type; 72 | if ((ret = getstat(path, stat)) != 0) { 73 | return ret; 74 | } 75 | 76 | static const char *filetype[] = { 77 | " [ file ]", 78 | " [directory]", 79 | " [ symlink ]", 80 | " [character]", 81 | " [ block ]", 82 | " [ ????? ]", 83 | }; 84 | switch (getmode(stat->st_mode)) { 85 | case '0': type = 0; break; 86 | case 'd': type = 1; break; 87 | case 'l': type = 2; break; 88 | case 'c': type = 3; break; 89 | case 'b': type = 4; break; 90 | default: type = 5; break; 91 | } 92 | 93 | printf(" @ is %s", filetype[type]); 94 | printf(" %d(hlinks)", stat->st_nlinks); 95 | printf(" %d(blocks)", stat->st_blocks); 96 | printf(" %d(bytes) : @'%s'\n", stat->st_size, path); 97 | if (S_ISDIR(stat->st_mode)) { 98 | return lsdir(path); 99 | } 100 | return 0; 101 | } 102 | 103 | int 104 | main(int argc, char **argv) { 105 | if (argc == 1) { 106 | return ls("."); 107 | } 108 | else { 109 | int i, ret; 110 | for (i = 1; i < argc; i ++) { 111 | if ((ret = ls(argv[i])) != 0) { 112 | return ret; 113 | } 114 | } 115 | } 116 | return 0; 117 | } 118 | 119 | -------------------------------------------------------------------------------- /code-with-comments/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 = 21; 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-with-comments/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-with-comments/user/priority.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define TOTAL 5 7 | /* to get enough accuracy, MAX_TIME (the running time of each process) should >1000 mseconds. */ 8 | #define MAX_TIME 1000 9 | #define SLEEP_TIME 400 10 | unsigned int acc[TOTAL]; 11 | int status[TOTAL]; 12 | int pids[TOTAL]; 13 | 14 | static void 15 | spin_delay(void) 16 | { 17 | int i; 18 | volatile int j; 19 | for (i = 0; i != 200; ++ i) 20 | { 21 | j = !j; 22 | } 23 | } 24 | 25 | int 26 | main(void) { 27 | int i,time; 28 | cprintf("priority process will sleep %d ticks\n",SLEEP_TIME); 29 | sleep(SLEEP_TIME); 30 | memset(pids, 0, sizeof(pids)); 31 | lab6_set_priority(TOTAL + 1); 32 | 33 | for (i = 0; i < TOTAL; i ++) { 34 | acc[i]=0; 35 | if ((pids[i] = fork()) == 0) { 36 | lab6_set_priority(i + 1); 37 | acc[i] = 0; 38 | while (1) { 39 | spin_delay(); 40 | ++ acc[i]; 41 | if(acc[i]%4000==0) { 42 | if((time=gettime_msec())>SLEEP_TIME+MAX_TIME) { 43 | cprintf("child pid %d, acc %d, time %d\n",getpid(),acc[i],time); 44 | exit(acc[i]); 45 | } 46 | } 47 | } 48 | 49 | } 50 | if (pids[i] < 0) { 51 | goto failed; 52 | } 53 | } 54 | 55 | cprintf("main: fork ok,now need to wait pids.\n"); 56 | 57 | for (i = 0; i < TOTAL; i ++) { 58 | status[i]=0; 59 | waitpid(pids[i],&status[i]); 60 | cprintf("main: pid %d, acc %d, time %d\n",pids[i],status[i],gettime_msec()); 61 | } 62 | cprintf("main: wait pids over\n"); 63 | cprintf("stride sched correct result:"); 64 | for (i = 0; i < TOTAL; i ++) 65 | { 66 | cprintf(" %d", (status[i] * 2 / status[0] + 1) / 2); 67 | } 68 | cprintf("\n"); 69 | 70 | return 0; 71 | 72 | failed: 73 | for (i = 0; i < TOTAL; i ++) { 74 | if (pids[i] > 0) { 75 | kill(pids[i]); 76 | } 77 | } 78 | panic("FAIL: T.T\n"); 79 | } 80 | 81 | -------------------------------------------------------------------------------- /code-with-comments/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 safe_open(const char *path, int open_flags) 13 | { 14 | int fd = open(path, open_flags); 15 | printf("fd is %d\n",fd); 16 | assert(fd >= 0); 17 | return fd; 18 | } 19 | 20 | static struct stat *safe_fstat(int fd) 21 | { 22 | static struct stat __stat, *stat = &__stat; 23 | int ret = fstat(fd, stat); 24 | assert(ret == 0); 25 | return stat; 26 | } 27 | 28 | 29 | static void safe_read(int fd, void *data, size_t len) 30 | { 31 | int ret = read(fd, data, len); 32 | assert(ret == len); 33 | } 34 | 35 | 36 | int main(void) 37 | { 38 | int fd1 = safe_open("sfs_filetest1", O_RDONLY); 39 | // struct stat *stat = safe_fstat(fd1); 40 | // assert(stat->st_size >= 0 && stat->st_blocks >= 0); 41 | char buf[4099]; 42 | safe_read(fd1, buf, sizeof(buf)); 43 | printf("sfs_filetest1 pass.\n"); 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /code-with-comments/user/sleep.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void 5 | sleepy(int pid) { 6 | int i, time = 100; 7 | for (i = 0; i < 10; i ++) { 8 | sleep(time); 9 | cprintf("sleep %d x %d slices.\n", i + 1, time); 10 | } 11 | exit(0); 12 | } 13 | 14 | int 15 | main(void) { 16 | unsigned int time = gettime_msec(); 17 | int pid1, exit_code; 18 | 19 | if ((pid1 = fork()) == 0) { 20 | sleepy(pid1); 21 | } 22 | 23 | assert(waitpid(pid1, &exit_code) == 0 && exit_code == 0); 24 | cprintf("use %04d msecs.\n", gettime_msec() - time); 25 | cprintf("sleep pass.\n"); 26 | return 0; 27 | } 28 | 29 | -------------------------------------------------------------------------------- /code-with-comments/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-with-comments/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-with-comments/user/spin.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int 5 | main(void) { 6 | int pid, ret, i ,j; 7 | cprintf("I am the parent. Forking the child...\n"); 8 | pid = fork(); 9 | if (pid== 0) { 10 | cprintf("I am the child. spinning ...\n"); 11 | while (1); 12 | }else if (pid<0) { 13 | panic("fork child error\n"); 14 | } 15 | cprintf("I am the parent. Running the child...\n"); 16 | 17 | yield(); 18 | yield(); 19 | yield(); 20 | 21 | cprintf("I am the parent. Killing the child...\n"); 22 | 23 | assert((ret = kill(pid)) == 0); 24 | cprintf("kill returns %d\n", ret); 25 | 26 | assert((ret = waitpid(pid, NULL)) == 0); 27 | cprintf("wait returns %d\n", ret); 28 | 29 | cprintf("spin may pass.\n"); 30 | return 0; 31 | } 32 | 33 | -------------------------------------------------------------------------------- /code-with-comments/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-with-comments/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-with-comments/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 | -------------------------------------------------------------------------------- /images/Canonical Device.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/Canonical Device.png -------------------------------------------------------------------------------- /images/PTE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/PTE.png -------------------------------------------------------------------------------- /images/SFS 磁盘组织.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/SFS 磁盘组织.png -------------------------------------------------------------------------------- /images/VFS 与 SFS 的衔接.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/VFS 与 SFS 的衔接.png -------------------------------------------------------------------------------- /images/fork-文件描述块.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/fork-文件描述块.png -------------------------------------------------------------------------------- /images/gdb 调试用户程序.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/gdb 调试用户程序.jpg -------------------------------------------------------------------------------- /images/gdb调试用户态程序 4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/gdb调试用户态程序 4.png -------------------------------------------------------------------------------- /images/gdb调试用户态程序 5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/gdb调试用户态程序 5.png -------------------------------------------------------------------------------- /images/gdb调试用户态程序3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/gdb调试用户态程序3.png -------------------------------------------------------------------------------- /images/gdb调试用户程序 2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/gdb调试用户程序 2.png -------------------------------------------------------------------------------- /images/io_buffer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/io_buffer.png -------------------------------------------------------------------------------- /images/iobuf 与 disk0_buffer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/iobuf 与 disk0_buffer.png -------------------------------------------------------------------------------- /images/iobuf含义.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/iobuf含义.png -------------------------------------------------------------------------------- /images/kernel 链接信息.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/kernel 链接信息.png -------------------------------------------------------------------------------- /images/vdev_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/vdev_list.png -------------------------------------------------------------------------------- /images/中断寻址.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/中断寻址.png -------------------------------------------------------------------------------- /images/中断结构.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/中断结构.png -------------------------------------------------------------------------------- /images/内核数据结构-pages.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/内核数据结构-pages.png -------------------------------------------------------------------------------- /images/内核虚拟地址.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/内核虚拟地址.png -------------------------------------------------------------------------------- /images/双向链表示例.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/双向链表示例.png -------------------------------------------------------------------------------- /images/哈希表.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/哈希表.png -------------------------------------------------------------------------------- /images/存储管理模块依赖图.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/存储管理模块依赖图.png -------------------------------------------------------------------------------- /images/文件系统分析 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/文件系统分析 1.png -------------------------------------------------------------------------------- /images/文件系统分析 2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/文件系统分析 2.png -------------------------------------------------------------------------------- /images/文件系统分析 3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/文件系统分析 3.png -------------------------------------------------------------------------------- /images/文件系统架构.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/文件系统架构.png -------------------------------------------------------------------------------- /images/文件系统类图fs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/文件系统类图fs.png -------------------------------------------------------------------------------- /images/文件系统类图inode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/文件系统类图inode.png -------------------------------------------------------------------------------- /images/文件系统设计图.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/文件系统设计图.png -------------------------------------------------------------------------------- /images/物理内存初始状态.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/物理内存初始状态.png -------------------------------------------------------------------------------- /images/物理页示意图.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/物理页示意图.png -------------------------------------------------------------------------------- /images/目录树的磁盘级表示1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/目录树的磁盘级表示1.png -------------------------------------------------------------------------------- /images/目录树的磁盘级表示2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/目录树的磁盘级表示2.png -------------------------------------------------------------------------------- /images/磁盘区块.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/磁盘区块.png -------------------------------------------------------------------------------- /images/线性地址结构.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/线性地址结构.png -------------------------------------------------------------------------------- /images/虚拟内存管理.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/虚拟内存管理.png -------------------------------------------------------------------------------- /images/虚拟内存维护.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/虚拟内存维护.png -------------------------------------------------------------------------------- /images/虚拟地址空间和物理地址空间的示意图.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/虚拟地址空间和物理地址空间的示意图.png -------------------------------------------------------------------------------- /images/进程与文件数据结构.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/进程与文件数据结构.png -------------------------------------------------------------------------------- /images/进程数据结构 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/images/进程数据结构 1.png -------------------------------------------------------------------------------- /mindmaps/操作系统机制.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/mindmaps/操作系统机制.xmind -------------------------------------------------------------------------------- /mindmaps/操作系统设计.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/mindmaps/操作系统设计.xmind -------------------------------------------------------------------------------- /mindmaps/虚拟化.xmind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/mindmaps/虚拟化.xmind -------------------------------------------------------------------------------- /notes/bitmap.md: -------------------------------------------------------------------------------- 1 | ## 文件系统中的 bitmap 结构 2 | 3 | ### Q 文件系统中的 bitmap 结构是为了解决什么问题? 4 | 5 | bitmap 用尽可能少的信息量存储磁盘数据的使用情况. 6 | 7 | ### Q 如何表示? 8 | 9 | 每个 bit 对应一个 block 的占用情况. 10 | 11 | ### Q 效率如何? 12 | 13 | 元数据量/数据量 = bit / block 14 | 15 | 如果用1整个 block 作为位图,那么能表示的数据空间是 block 个 block.而每个 block 是 4KB, 故共 4K*4K = 16MB. 16 | 17 | 18 | ### Q ucore 是如何表示 bitmap 的? 19 | 20 | 类似内存分段寻址,每个bit index 的逻辑地址是 word + mask. mask 可以理解为偏移量的掩码表示. 21 | 22 | 23 | ``` 24 | bit_status = (*word) & mask 25 | = block_index/word_bits & mask 26 | ``` 27 | 28 | ### Q ucore 实现 bitmap 工具的关键函数是什么? 29 | 30 | block 索引到 word-mask的转换函数: 31 | 32 | ```C 33 | static void 34 | bitmap_translate(struct bitmap *bitmap, uint32_t index, WORD_TYPE **word, WORD_TYPE *mask); 35 | ``` 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /notes/lab 7.md: -------------------------------------------------------------------------------- 1 | ## lab7 实验笔记 2 | 3 | 互斥: 唯一且排他 4 | 同步: 使有序 5 | 6 | ## ucore 中哪些地方使用了信号量? 7 | 8 | 换句话说就是用信号量初始化了哪些变量?搜索后得知: 9 | 10 | ```C 11 | disk0_device_init -> sem_init(&(disk0_sem), 1); 12 | files_create -> sem_init(&(filesp->files_sem), 1); 13 | sfs_do_mount -> sem_init(&(sfs->fs_sem), 1); 14 | -> sem_init(&(sfs->io_sem), 1); 15 | -> sem_init(&(sfs->mutex_sem), 1); 16 | sfs_create_inode -> sem_init(&(sin->sem), 1); 17 | vfs_init -> sem_init(&bootfs_sem, 1); 18 | vfs_devlist_init -> sem_init(&vdev_list_sem, 1); 19 | } 20 | ...省略 21 | ``` 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /notes/lab5.md: -------------------------------------------------------------------------------- 1 | 操作系统是一个基于事件的软件,这里操作系统需要响应的事件包括三类:外设中断、CPU执行异常(比如访存错误)、陷入(系统调用) 2 | 3 | ## 机制: 系统调用 4 | 5 | ## 机制: 执行二进制文件 6 | 7 | 函数原型: 8 | 9 | ``` 10 | do_execve(const char *name, size_t len, unsigned char *binary, size_t size) 11 | ``` 12 | 13 | 1. 合法性检查 14 | 2. 设置页表 15 | 3. -------------------------------------------------------------------------------- /notes/lab6.md: -------------------------------------------------------------------------------- 1 | # ucore Lab4 实验笔记 2 | 3 | ## 一个进程,何时通知内核让出资源(调用 schedule)? 4 | 5 | 当该进程没有其他事情可做的时候. 6 | 7 | 比如系统调用 do_exit,把自己的资源尽可能清理干净后,剩下无法完全清理的资源,只能等待父进程回收,这时应当让出计算资源. 8 | 9 | 再如do_wait,等待子进程退出的时候,确实没有其他事情可做,也应当让出资源. 10 | 11 | 另外就是用户进程主动调用`sleep`的情况. 12 | 13 | ## 何时进入运行队列? 14 | 15 | - wakeup_proc 16 | - 6 17 | 18 | ## 调度器的基本操作 19 | 20 | - 在就绪进程集合中选择 21 | - 进入就绪进程集合 22 | - 离开就绪进程集合 23 | 24 | ## 问题: 何时调用 schedule(),何时仅仅添加到就绪队列enqueue? 25 | 26 | - 前者的含义是"立即运行下一个就绪进程",一些特殊情况往往必须要调用,比如`exit`,`wait`,`sleep`等,如果仅仅是添加到队列中,当前进程会白白浪费时间. 27 | - 后者意味着可以有所延迟. 28 | 29 | ## 内核抢占点 30 | 31 | 1. 用户调度: 32 | 33 | - `fork` 34 | - `exit` 35 | 36 | ## 等待的原因有哪些? 37 | 38 | - 39 | - 等待子进程 40 | - 等待内核信号量 41 | - 等待 timer 42 | - 等待键盘输入 43 | 44 | ``` 45 | #define WT_INTERRUPTED 0x80000000 // the wait state could be interrupted 46 | #define WT_CHILD (0x00000001 | WT_INTERRUPTED) // wait child process 47 | #define WT_KSEM 0x00000100 // wait kernel semaphore 48 | #define WT_TIMER (0x00000002 | WT_INTERRUPTED) // wait timer 49 | #define WT_KBD (0x00000004 | WT_INTERRUPTED) // wait the input of keyboard 50 | ``` 51 | 52 | ## wakup_proc、 shedule、 run_timer_list 之间的关系是什么? 53 | 54 | 好像只有时钟中断才是最"不可抵抗"的因素,每次时钟中断都会把控制权交给内核,准确的说是交给了时钟中断处理函数`run_timer_list`. 55 | 56 | 这里有思维上的转变.当中断的数据结构和控制器初始化完毕之后,我们的主视角其实不再是"内核进程","用户进程",而是从时钟中断处理函数出发的时间线. 57 | 58 | ## timer_list是在何时初始化的? 59 | 60 | sched_init -------------------------------------------------------------------------------- /notes/ucore 中的数据结构与算法.md: -------------------------------------------------------------------------------- 1 | ## ucore 中的表结构 2 | 3 | ## 1 基本管理器-链表 4 | 5 | 通常使用一个链表结构来维护多个同类型的数据.为了提高性能,可能会同时用哈希表维护数据. 6 | 7 | ```C 8 | struct list_entry { 9 | struct list_entry *prev, *next; 10 | }; 11 | 12 | typedef struct list_entry list_entry_t; 13 | ``` 14 | 15 | 如果想让某种结构可以被某个管理节点维护,需要在结构中声明节点变量,如 16 | 17 | ```C 18 | struct proc_struct { 19 | enum proc_state state; // Process state 20 | int pid; // Process ID 21 | //省略... 22 | list_entry_t list_link; // Process link list 23 | list_entry_t hash_link; // Process hash list 24 | } 25 | ``` 26 | 27 | 最后形成的结构大概如图: 28 | 29 | ![](https://github.com/libinyl/ucore-study/blob/master/images/%E5%8F%8C%E5%90%91%E9%93%BE%E8%A1%A8%E7%A4%BA%E4%BE%8B.png?raw=1) 30 | 31 | 当遍历到某个节点后,如何对应到包含此节点的结构体? 32 | 33 | 34 | ```C 35 | // proc.h 36 | #define le2proc(le, member)\ 37 | to_struct((le), struct proc_struct, member) 38 | 39 | // def.h 40 | #define to_struct(ptr, type, member)\ 41 | ((type *)((char *)(ptr) - offsetof(type, member))) 42 | ``` 43 | 基于如上定义,典型的查找用例如下.给定`link`地址/结构体类型/link 具体名称 即可找到对应结构体的地址. 44 | 45 | ```C 46 | // usage 47 | list_entry_t *le = list_next(&(rq->run_list)); // 获取管理节点(的地址) 48 | 49 | if (le == &rq->run_list) 50 | return NULL; 51 | 52 | struct proc_struct *p = le2proc(le, run_link); 53 | ``` 54 | 55 | 原理是,只要给定节点(link)地址,在给定对应的结构体类型,就可以通过`offset`算出此节点在对应结构体内的偏移;而结构体内地址的layout是随成员变量增长的,于是**结构体地址=link成员地址-link成员在结构体内的偏移量**. 56 | 57 | ## 2 查找加速-哈希表 58 | 59 | 与链表类似,凡是需要用哈希表管理的,均需要在结构体内声明哈希节点,仍如`proc_struct`所示. 60 | 61 | 对于每种类型的`struct`,都应有专用的 hash 方法: 62 | 63 | ```C 64 | // proc.c 65 | #define HASH_SHIFT 10 66 | #define HASH_LIST_SIZE (1 << HASH_SHIFT) 67 | #define pid_hashfn(x) (hash32(x, HASH_SHIFT)) 68 | 69 | // has list for process set based on pid 70 | static list_entry_t hash_list[HASH_LIST_SIZE]; 71 | // hash_proc - add proc into proc hash_list 72 | static void 73 | hash_proc(struct proc_struct *proc) { 74 | list_add(hash_list + pid_hashfn(proc->pid), &(proc->hash_link)); 75 | } 76 | // hash.c 77 | /* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */ 78 | #define GOLDEN_RATIO_PRIME_32 0x9e370001UL 79 | 80 | uint32_t 81 | hash32(uint32_t val, unsigned int bits) { 82 | uint32_t hash = val * GOLDEN_RATIO_PRIME_32; 83 | return (hash >> (32 - bits)); 84 | } 85 | ``` 86 | 以上是根据进程 id 进行hash 并维护的主要函数和宏定义. 87 | 88 | 经过哈希处理之后,每个哈希节点都称为表头,随元素增长分别延伸,如图.(注:理想情况下分布应较为均匀) 89 | 90 | ![](https://github.com/libinyl/ucore-study/blob/master/images/%E5%93%88%E5%B8%8C%E8%A1%A8.png?raw=1) 91 | 92 | -------------------------------------------------------------------------------- /notes/ucore 分析之——文件系统的面向对象实现: 手写虚函数表.md: -------------------------------------------------------------------------------- 1 | ## ucore 分析之——文件系统的面向对象实现(一): 手写虚函数表 2 | 3 | 这篇文章的灵感来自 @冯东 大佬的回答: 4 | 5 | C++中有哪些设计精良的部分(精华),还有哪些是不值得花费很多时间探究的知识点? - 冯东的回答 - 知乎 6 | https://www.zhihu.com/question/32271535/answer/55386211 7 | 8 | 看了回答中推荐的文章之后,我才稍微更加理解了用 C 写面向对象代码的方式。这种编码风格强烈地体现在文件系统的实现--我们需要处理太多类型的设备,太多不同类型的文件系统,最后却统统抽象出一个"文件", 人类真的是懒惰到家了,真棒👍! 9 | 10 | ## 设备的统一 11 | 12 | 系统需要与数不胜数的设备打交道。有的以字符为单位读写,像键盘,串口,调制解调器,打印机之类,我们称之为**字符设备**, 它们往往可以顺序读写,但通常没法随机读写;有的以固定大小的块为单位读写,像磁盘,U 盘,SD 卡等等,每个块都有编址,所以可以方便地随机读写,在任意位置读写一定长度的数据,我们称之为**块设备**; 还有更复杂的**网络设备**, 操作的单位是网络报文,系统通过网络接口支持各层级的协议。 13 | 14 | 历史上对不同类型的设备可能需要分别处理,意味着开发者面临着多种 API, 一些早期的系统甚至需要用不同的命令处理位于不同软盘的文件。而 Unix 把一些进程间通信的概念(管道,套接字,共享内存等)也集成到文件的 api 管理范畴,open 一个文件,进程就多维护一个文件描述符,作为对二进制流的 IO 接口。从 Unix 之后,文件不再仅仅是指持久化存储的数据,更是涵盖了多种具体类型的,强大而简单的抽象。 15 | 16 | ![](https://github.com/libinyl/lcore/blob/master/images/%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%88%86%E6%9E%90%203.png?raw=1) 17 | 18 | ## 文件系统的统一 19 | 20 | 想知道你的 linux 系统支持哪些文件系统,只需执行 `cat /proc/filesystems`, 我安装的 ubuntu 显示有 33 种--是的,需要再向上抽象一层,否则操作系统真的要分别管理它们,这太累了。linux 确实做了抽象,可以参考 [Overview of the Linux Virtual File System](https://www.kernel.org/doc/Documentation/filesystems/vfs.txt) 了解细节。总之,为了支持各种类型的文件系统,以及为了提供更丰富的功能,一个 VFS(虚拟文件系统)势在必得。 21 | 22 | ![](https://github.com/libinyl/lcore/blob/master/images/%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%88%86%E6%9E%90%202.png?raw=1) 23 | 24 | 25 | ## 文件的组织 26 | 27 | 人类渴望简单,简单就是符合直觉。(待第二篇补充...) 28 | 29 | ## ucore 的文件系统 30 | 31 | (以下内容假设读者了解 ucore 源码) 32 | 33 | 我们知道文件描述符于进程而言的重要性,也熟悉用法:`open`, `read`,`llseek`, `write`, `close`, 一气呵成。这些都是在与`VFS`打交道, 它帮我们分配`fd`, 根据路径名找到对应的`inode`, 最后返回 `fd`. 在这个过程中, `VFS` 不需要了解下层具体的文件系统如何实现`read`, `write`, 只要调用就好; 也不需要关心是什么文件, 只要解析(resolve)到具体的`inode`就好: 34 | 35 | ![](https://github.com/libinyl/lcore/blob/master/images/%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%88%86%E6%9E%90%201.png?raw=1) 36 | 37 | 38 | **VFS** 39 | 40 | 从(ucore)操作系统的视角来看, VFS 的实现基于以下概念: 41 | 42 | - 最抽象的管理单位是虚拟设备`vdev`, 用链表类结构(`vdev_list`)维护; 43 | - 每个 `vdev` 都有一个字符串类型的名字用于标识(identify); 44 | - 每个具体设备都抽象为`inode`,被`vdev`维护; 45 | - `vdev`分为可挂载(mountable)和不可挂载的; 46 | - 每个可挂载的`vdev`都可以被其对应的文件系统识别并挂载, 用 `fs`字段维护. 47 | 48 | 其实这就是`vfs_dev_t`结构: 49 | 50 | ```C 51 | typedef struct { 52 | const char *devname; // 设备名称 53 | struct inode *devnode; // 代表设备 54 | struct fs *fs; // 可挂载设备挂载后的文件系统结构 55 | bool mountable; // 是否可挂载 56 | list_entry_t vdev_link; // 链表节点 57 | } vfs_dev_t; 58 | ``` 59 | 60 | 对于不可挂载的设备而言, `fs` 会被初始化为 `NULL`. 61 | 62 | 63 | **inode** 64 | 65 | 我感觉 inode 的概念比较复杂, 而复杂的原因是其在不同语境下似乎有不同的语义. 由于之前写 `class` 用的是 C++ 或 Java, 刚开始接触 inode 的时候真心难以理解. 这时开头那篇文章才把我指点清楚, inode 的复杂含义背后是面向对象的设计思想. 66 | 67 | 68 | ## 插播: C 与 C++ 在面向对象方面的对比, 以 inode 为例 69 | 70 | **struct 与 class 的区别** 71 | 72 | 如果是仅在 C++语境下讨论它们的区别, 那就是几乎没有区别, 仅仅是成员默认访问权限的区别;而如果是 C 的 `struct` 与 C++ 的 `class` 的对比, 思维上会有很大的差异: C 的`struct` 忠实地记录了实际的内存结构, 我们在编程时真的是 **面向内存编程**, 为了实现继承和多态, 往往要付出成倍的代价; 而 C++ 的 `class` 则可以提供足够抽象的描述, 隐去很多繁杂的细节, 但也有考虑过多的负担. 73 | 74 | 以 `inode` 为例. 如果用 C++ 改写代码,最终形成的类图是这样的: 75 | 76 | ![](https://github.com/libinyl/lcore/blob/master/images/%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E7%B1%BB%E5%9B%BEfs.png?raw=1) 77 | 78 | ![](https://github.com/libinyl/lcore/blob/master/images/%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E7%B1%BB%E5%9B%BEinode.png?raw=1) 79 | 80 | 代码见链接(只突出继承关系, 无具体实现): 81 | 82 | https://github.com/libinyl/lcore/tree/master/blogcode/%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E5%88%86%E6%9E%90 83 | 84 | inode 有以下含义: 85 | 86 | ..未完待续... 87 | 88 | 89 | 90 | 91 | 92 | ## 参考资料 93 | 94 | - [ph7spot: in-unix-everything-is-a-file](https://ph7spot.com/musings/in-unix-everything-is-a-file) 95 | - [yarchive: everything_is_file](https://yarchive.net/comp/linux/everything_is_file.html) 96 | - [Wikipedia: Computer_file](https://en.wikipedia.org/wiki/Computer_file) 97 | - [Wikipedia: Everything_is_a_file](https://en.wikipedia.org/wiki/Everything_is_a_file) 98 | - [Wikipedia: File_systems_supported_by_the_Linux_kernel](https://en.wikipedia.org/wiki/Category:File_systems_supported_by_the_Linux_kernel) -------------------------------------------------------------------------------- /notes/ucore 拓展之——日志输出及控制,调试逻辑优化.md: -------------------------------------------------------------------------------- 1 | ## ucore 拓展之——日志输出及控制,调试逻辑优化 2 | 3 | 说实话我比较怀疑 ucore 的作者移除了原有的日志模块,否则靠一条条 `cprintf` 来调试真的太难受了。.. 不过也有可能是故意留给学生来处理的?不管怎样,在我尝试增加了日志模块后(尽管非常简陋,约 100 行代码),及时地输出一些调试信息对我理解整个系统起了很大帮助。这里简单介绍下,也欢迎大家试用。 4 | 5 | 另外在文末给出一行命令,用于优化 gdb 的调试效果。 6 | 7 | 日志控制代码位于`kdebug.[hc]`, 实现了 1) *基本的日志输出;* 2) *模块级开关控制;* 3) *区域开关控制* 8 | 9 | **基本使用** 10 | 11 | 使用方法:只需`#incdlue `, 然后就可以像使用`cprintf`一样使用`LOG`来打印调试信息了。另附一个加了一个 tab 的 `LOG_TAB`。 12 | 13 | **模块级开关控制** 14 | 15 | 在 `kdebug.h` 中可见形如`#define IS_LOG_GLOBAL_ON 1`的宏,只需分别配置为 1 或 0 即可开关对应模块的日志输出。这里把`kern`下的每个文件夹看做一个模块。 16 | 17 | **区域级开关控制** 18 | 19 | 有时想临时屏蔽某个函数或者某个文件的日志输出,这时只需用宏`_NO_LOG_START`和`_NO_LOG_END`包裹对应的代码区域就可以了。注意这里加了一个小检测,**你必须成对使用它们,否则不会编译通过。** 20 | 21 | 代码链接见下,欢迎(酌情)使用~ 22 | 23 | - [kdebug.h](https://github.com/libinyl/lcore/blob/master/code-with-comments/kern/debug/kdebug.h) 24 | - [kdebug.c](https://github.com/libinyl/lcore/blob/master/code-with-comments/kern/debug/kdebug.c) 25 | 26 | ------- 27 | 28 | ## 关于 gdb 的调试优化 29 | 30 | 源码中给出的调试方法`make debug[-nox]`把 QEMU 作为后台 job 启动,并把输出重定向到标准输出,导致在 tui 模式下输出中文会乱码;此外还有其他奇奇怪怪的乱码问题。如果有小伙伴觉得不太爽的话,可以在 makefile 中加一条: 31 | 32 | ``` 33 | debug-gdb: $(UCOREIMG) $(SWAPIMG) $(SFSIMG) 34 | $(V)$(TERMINAL) -c "$(GDB) -q -x tools/gdbinit" 35 | ``` 36 | 37 | 这样,打开一个 terminal, 键入`make dbg4ec`, 再打开一个 terminal, 键入`make debug-gdb`即可把日志信息输出到第一个终端,而在第二个终端用 tui 轻松调试了。 -------------------------------------------------------------------------------- /notes/ucore 拓展之——用 gdb 调试程序从用户态到内核态的整个流程.md: -------------------------------------------------------------------------------- 1 | ## ucore 拓展之——用 gdb 调试程序从用户态到内核态再回到用户态的整个流程 2 | 3 | 说起来你可能不信, 为了调试用户态程序, 我第一反应是在 ucore 上装个 gdb! 当我还在故作深沉考察可行性的时候,stackoverflow 已经给了我一句劝告: gdb 比你想象的要更强大. 4 | 5 | 每个程序员, 每次解决一个未曾谋面的新问题后, 都会持续大概 5 分钟的自我陶醉, 我可真太牛逼了, 然后冷静分析下来发现, 其实这已经是二三十年前的技术了...但不管怎样, 都要有从不知道到知道的过程, 姑且记录下来. 6 | 7 | 以 `ls` 为例, 起码要向控制台输出当前文件列表, 即多次调用 `printf`; 而`printf`会进行系统调用`write`,再往后就是中断的生成, 派发和处理, 再往后io系统向`stdin`输出信息...如何跟踪? 8 | 9 | **答案: 多用 `(gdb)file` 命令.** 10 | 11 | 1. 在`Makefile`中添加下列目标, 令 qemu 把输出重定向到串口的标准输出: 12 | 13 | ```makefile 14 | dbg-u2k: $(UCOREIMG) $(SWAPIMG) $(SFSIMG) 15 | $(V)$(QEMU) -S -s -serial mon:stdio $(QEMUOPTS) 16 | ``` 17 | 18 | 2. 清空 `.gdbinit`, 除非了解它的作用; 19 | 3. 定位到 ucore 项目根目录下, 执行 `make dbg-u2k`, ucore 编译完毕并被 qemu 加载,停留在第一条指令之前; 20 | 4. 此时在另一终端执行`gdb bin/kernel`, 并`target remote localhost:1234`连接上 qemu, 观察到熟悉的提示信息.事实上到此为止与往常没有明显不同. 现在可以键入`c`,让内核自由运行,直到运行了shell. 21 | 5. 现在的状态是什么? 你可以枉顾 gdb 的存在,在 ucore 执行你的用户程序,如下图: 22 | 23 | ![](https://github.com/libinyl/lcore/blob/master/images/gdb%20%E8%B0%83%E8%AF%95%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F.jpg?raw=1) 24 | 25 | 1. 但是此时 gdb 加载的是 kernel 的符号.现在只需`Ctrl C`中断 gdb,再键入`file disk0/ls`,即可加载 ls 的符号! 这是...热加载? 26 | 2. 此时键入`b main`,就可以像调试普通用户态程序一样调试 `ls` 了, 如下: 27 | 28 | ![](https://github.com/libinyl/lcore/blob/master/images/gdb%E8%B0%83%E8%AF%95%E7%94%A8%E6%88%B7%E7%A8%8B%E5%BA%8F%202.png?raw=1) 29 | 30 | 1. 同样,当在用户程序遇到系统调用时不用慌,跟进去,用 file切成内核即可!比如我们跟踪到了函数`lsstat`, 想跟入 `printf` 一探究竟: 31 | 32 | ![](https://github.com/libinyl/lcore/blob/master/images/gdb%E8%B0%83%E8%AF%95%E7%94%A8%E6%88%B7%E6%80%81%E7%A8%8B%E5%BA%8F3.png?raw=1) 33 | 34 | 最终我们一路跟踪到`user/libs/syscall.c`的`syscall`, 即将陷入中断.此时再执行`n`,就跟不到代码了. 35 | 36 | ![](https://github.com/libinyl/lcore/blob/master/images/gdb%E8%B0%83%E8%AF%95%E7%94%A8%E6%88%B7%E6%80%81%E7%A8%8B%E5%BA%8F%204.png?raw=1) 37 | 38 | 此时只需键入`file bin/kernel`,就进入了内核态的调试环境!再打个断点, 如`b trap`, 就接住这个系统调用了! 39 | 40 | ![](https://github.com/libinyl/lcore/blob/master/images/gdb%E8%B0%83%E8%AF%95%E7%94%A8%E6%88%B7%E6%80%81%E7%A8%8B%E5%BA%8F%205.png?raw=1) 41 | 42 | 我想,linux 内核调试起来大概也是如此的流程? 43 | 44 | 45 | ## 相关原理 46 | 47 | **当在 gdb 命令窗口键入 Ctrl C, 发生了什么?** 48 | 49 | 首先我们可以看到 gdb 的输出: 50 | 51 | > Program received signal SIGINT, Interrupt. 52 | 53 | 事实是: **GDB帮用户拦截了致命的信号.** 54 | 55 | 键入`(gdb) info signals`可以查看 gdb 帮我们拦截的信号: 56 | 57 | ``` 58 | Signal Stop Print Pass to program Description 59 | 60 | SIGHUP Yes Yes Yes Hangup 61 | SIGINT Yes Yes No Interrupt 62 | SIGQUIT Yes Yes Yes Quit 63 | SIGILL Yes Yes Yes Illegal instruction 64 | SIGTRAP Yes Yes No Trace/breakpoint trap 65 | SIGABRT Yes Yes Yes Aborted 66 | ... 67 | ``` 68 | 69 | 可以观察到, `Ctrl C` 对应的 *SIGINT* 信号被 gdb 所捕获并输出, 并没有真正传递给进程.所以我们可以利用这个间隙来调整 gdb 的选项,就像刚才一样加载其他文件的符号,有了从用户态到内核态来去自由的机会.不过这也许只是手段之一吧,以后有了其他发现再回来更新. 70 | 71 | 72 | ## 更多资料 73 | 74 | - [Debugging with GDB, 5.4 Signals](https://sourceware.org/gdb/onlinedocs/gdb/Signals.html) 75 | - [Stack Overflow: Debugging user-code on xv6 with gdb](https://stackoverflow.com/questions/10534798/debugging-user-code-on-xv6-with-gdb) -------------------------------------------------------------------------------- /notes/ucore 文件系统疑似 bug 记录.md: -------------------------------------------------------------------------------- 1 | ## bug 说明: 2 | 3 | 准确的说应该是 mksfs ——SFS 文件系统制作工具 "mksfs" 的 bug. 4 | 5 | mksfs 工具用于将宿主机指定目录下所有文件,按照 SFS 文件系统的格式写入到指定的虚拟硬盘中。 6 | 7 | 此 bug 将导致用 mksfs 工具制作文件系统时,如果宿主机提供的文件的名字超过 252 个字符,则操作系统运行时只能读到前 252 个字符;而系统声明最多支持文件名字符数为 255。 8 | 9 | 复现方法很方便,不一定真要写入一个有 255 个字符名字的文件,只需把 mksfs 中声明支持文件名最大字符数的宏 `SFS_MAX_FNAME_LEN` 改为较小值,比如改为 15. 正常编译并启动系统,shell 键入 `ls`, 会发现总长度为 15 个字符的文件 `faultreadkernel` 被截断成 `faultreadker`, 共 15 - 3 = 12 个字符。 10 | 11 | ## 原因: 12 | 13 | mksfs 工具制作 SFS 文件系统时,`add_entry` 操作中,`write_block` 的参数不正确,写入数据大小不应是 `sizeof(entry->name)`,而应该是 `sizeof(struct sfs_entry)`。 14 | 15 | `entry` 作为目录类型 `inode` 的数据内容,只包含两个元素:子节点的 `ino` 及其 `name`, `ino`的类型是 `uint32`, `name` 的类型是 `char[SFS_MAX_FNAME_LEN + 1]`。 16 | 17 | bug 代码相当于只写入了 `ino` 和 `name` 的一部分内容,且未包含最后的 `'\0'` 。由于 `sizeof(entry->name) = 256`(包括最后的 `'\0'`), 而 `ino` 是 `uint32` 类型,占 4 个字节,所以 name 的最后 3 个字符将丢失,剩余不含 `'\0'` 的部分共 252 个字符。 18 | 19 | 这个 bug 可能还有一个风险:文件系统在读取此 `entry` 的 `name` 时,寻找的是 `null-terminated string`,而由于上述截断的发生,可能写入磁盘的不完整文件名之后紧邻的不是 `'\0'`, 这就麻烦大了,会有兼容性问题。不过暂时没去查 C 语言是否规定全局 `struct` 中的 `char array` 会不会被初始化为 `\0`,如果不会的话,那就确有问题了。 20 | 21 | ## 附 问题代码: 22 | 23 | ```C 24 | static void 25 | add_entry(struct sfs_fs *sfs, struct cache_inode *current, struct cache_inode *file, const char *name) { 26 | static struct sfs_entry __entry, *entry = &__entry; 27 | assert(current->inode.type == SFS_TYPE_DIR && strlen(name) <= SFS_MAX_FNAME_LEN); 28 | entry->ino = file->ino, strcpy(entry->name, name); 29 | uint32_t entry_ino = sfs_alloc_ino(sfs); 30 | write_block(sfs, entry, sizeof(entry->name), entry_ino); // bug! 31 | append_block(sfs, current, sizeof(entry->name), entry_ino, name); 32 | file->inode.nlinks ++; 33 | } 34 | ``` -------------------------------------------------------------------------------- /notes/信号量.md: -------------------------------------------------------------------------------- 1 | ## 信号量特点 2 | 3 | - 信号量: 保证原子更新的整数 4 | - 0值: 占用中或锁定中 正值: 可用 5 | - 不可能为负值 6 | - 7 | 8 | -------------------------------------------------------------------------------- /notes/内存管理概览.md: -------------------------------------------------------------------------------- 1 | # 1 内存管理概览 2 | 3 | ## 1.1 背景 计算机存储架构 4 | 5 | ![](https://upload.wikimedia.org/wikipedia/commons/3/3e/Computer_storage_types.svg) 6 | 7 | > 参考[链接](https://en.wikipedia.org/wiki/Computer_data_storage#Secondary_storage) 8 | 9 | - 主存通过两条**内存总线**与cpu 相连:数据总线和地址总线. 10 | 11 | ## 1.2 问题提出 12 | 13 | - 如何分配 n 个字节的内存? 14 | - 如何释放 n 个字节的内存? 15 | 16 | ## 1.3 管理方案 17 | 18 | **单一连续分配** 19 | 20 | 最简单的内存管理技术,一个应用占用整块内存.例如MS-DOS.通过置换技术实现分时复用. 21 | 22 | **分区分配** 23 | 24 | - 把内存分为连续的区块 25 | - 每个区块对应一个程序 26 | 27 | **分段管理** 28 | 29 | - 通过基址+偏移量把主存分段(segments) 30 | 31 | **分页管理** 32 | 33 | - 主存被切分为定长单元 34 | - 虚拟内存空间也被分为同样的定长单元 35 | - MMU 把 page 映射到 frame. 36 | - 物理内存以页为单位管理 37 | - 虚拟地址空间呈现连续性 38 | 39 | ## 1.4 接口描述 40 | 41 | void *kmalloc(size_t n); 42 | void kfree(void *p); 43 | 44 | ## 1.5 参考资料 45 | 46 | - [维基百科: 内存管理](https://en.wikipedia.org/wiki/Memory_management_(operating_systems)#Single_contiguous_allocation) 47 | - [维基百科: 内存分段](https://en.wikipedia.org/wiki/Memory_segmentation) 48 | 49 | # 2 虚拟内存管理 50 | 51 | ## 2.1 问题提出 52 | 53 | 主存不够用. 54 | 55 | ## 2.2 方案 56 | 57 | 把主存看做是磁盘的缓存,建立虚拟内存. 58 | -------------------------------------------------------------------------------- /notes/函数调用与中断.md: -------------------------------------------------------------------------------- 1 | ## 函数调用,中断,系统调用,calling convection (仅为个人理解) 2 | 3 | ## 函数调用是什么? 4 | 5 | 暂不考虑返回值,函数调用就是**同一等级的,带参数的,可恢复的控制流转移**. 6 | 7 | - **同一等级**,意味着是内核态的函数调用,或者用户态的函数调用,不涉及权限的更改. 8 | - **控制流转移**,要求最终把ip,或者 cs 和 ip 设定为目标控制流起始点. 9 | - **带参数**,要求把参数置于 `caller` 和 `callee` 都可访问的位置. 10 | - **可恢复**,要求把返回地址置于`callee` 可访问的位置. 11 | 12 | ## 实现某种**calling convection**需要确定什么? 13 | 14 | - 参数入栈顺序,LTR or RTL ? 15 | - 栈上参数清理者,caller or callee ? 16 | 17 | ## 进入一个函数后,如何构建新的**call frame**? 18 | 19 | 我个人理解,ebp,esp 是作为函数而言,独立于**calling convection**的概念. 20 | 21 | 函数需要独立可使用的栈空间,由 ebp,esp 定义.因此进入新的函数(后),需要配置独立的栈空间.但又由于需要恢复,所以还需保存之前的ebp.而 esp 始终是绝对值,无需保存. 22 | 23 | ## 以`cdecl`为例说明以上概念. 24 | 25 | 参考[](https://en.wikipedia.org/wiki/X86_calling_conventions). 26 | 27 | 考虑如下C 代码: 28 | 29 | ```C 30 | int callee(int, int, int); 31 | 32 | int caller(void) 33 | { 34 | return callee(1, 2, 3) + 5; 35 | } 36 | ``` 37 | 38 | 翻译为 x86 汇编: 39 | 40 | 调用新函数前: 41 | 42 | ``` 43 | | ↓ | ← ebp 44 | | | 45 | | | 46 | | | ← esp 47 | | | 48 | | | 49 | | | 50 | ``` 51 | 52 | 调用新函数中: 53 | ``` 54 | | ↓ | 55 | | | 56 | | | 57 | | ebp | ← ebp 58 | | | 59 | | | 60 | | | ← esp 61 | ``` 62 | 63 | 64 | 65 | ```x86asm 66 | caller: 67 | ; 构建新的 call frame 68 | push ebp ; 保存旧的 call frame, 69 | mov ebp, esp ; 初始化新的 call frame.此后 ebp 不变,esp 向下增长 70 | 71 | ; 所有参数压栈 72 | push 3 73 | push 2 74 | push 1 75 | 76 | call callee ; 调用函数 = push ip, jump addr 77 | 78 | add eax, 5 ; 返回值存储在 eax 中 79 | 80 | ; 恢复旧的 call frame 81 | mov esp, ebp ; 恢复 caller 的 esp. 82 | 83 | pop ebp ; 恢复 caller 的 ebp 84 | ret ; return = pop eip,jmp to it 85 | ``` 86 | 87 | 88 | 89 | ## 中断是什么? 90 | 91 | **目标是内核服务的控制流转移** 92 | 93 | 中断也是控制流转移,但转移的目标是内核区专门定义的服务代码,包括 94 | 95 | - 系统调用 96 | - 软件异常(除零异常等) 97 | - 硬件中断 98 | 99 | 以及其他. 100 | 101 | 其存在的意义就是对控制转移进行严格限制. 102 | 103 | ## 构成中断的要素有哪些? 104 | 105 | 与函数调用类似,中断也有类似的要素: 106 | 107 | - **可能跨等级的控制流转移**,需要权限校验. 108 | - **控制流转移**,要求最终寻址到处理对应中断的函数并执行. 109 | - **带参数**,中断向量,在内存中定义. 110 | - **可恢复**,这里的可恢复,是指恢复至用户态的执行环境.用户态的执行环境变量很多,ucore 用 trapframe 表示.与普通调用不同的是,*在返回时,trapframe可能会被改变.* 111 | 112 | ![](/images/中断寻址.png) 113 | 114 | ## 结合代码说明上述概念 115 | 116 | 如上图,我们已经在函数`idt_init`中对 IDT 表进行了初始化,并把base,limit 送入到了 IDTR. 117 | 118 | **可恢复** 119 | 120 | 通常中断发生时,计算机正在执行用户态程序.为了在中断服务程序执行完毕之后可以恢复到之前的控制流,需要保存状态. 121 | 122 | **对于非系统调用** 123 | 124 | 以除 0 异常为例.cpu 已经定义了一系列异常的向量号码,是不可改变的(?).查阅手册 `Table 6-1`知,除 0 异常号是 0. 125 | 126 | ### 如何修改时钟周期? 127 | 128 | - clock.c -------------------------------------------------------------------------------- /notes/基于分页机制的虚拟内存管理实现.md: -------------------------------------------------------------------------------- 1 | ## 背景 2 | 3 | 基于分段的内存管理机制解决了两个问题: 4 | 5 | - 地址空间没有隔离 6 | - 程序运行的地址不确定 7 | 8 | 为了解决内存空间不够用的问题,建立了虚拟内存,即内存与磁盘的置换机制. 9 | 10 | ## 问题提出 11 | 12 | 分段内存管理效率较低.如果内存不足,被换入到磁盘的空间是整个程序的空间,会产生大量 IO 操作,性能较差. 13 | 14 | 怎样在有限内存的情况下**减少 I/O 频率**,进一步提升性能? 15 | 16 | ## 方案提出 17 | 18 | - 以某一较小定长值为单位管理内存,以内存置换的频数. 19 | 20 | ## 实现目标 21 | 22 | - **实现** 以定长值(页)为单位的内存和分配和释放接口,即`struct page *alloc_pages(size_t n)`和`void free_pages(struct page *,size_t)`; 23 | - **重构** `kmalloc/kfree` 24 | - **重构** `swap_in/swap_out` 25 | 26 | ## mmu 机制 27 | 28 | ![](https://github.com/libinyl/CS-notes/blob/master/images/intel/v3/Figure%204-2.%20Linear-Address%20Translation%20to%20a%204-KByte%20Page%20using%2032-Bit%20Paging.png) 29 | 30 | ## 必需数据结构 31 | 32 | - 基本页数据结构`struct Page` 33 | - 以`page`为单位的内存描述链表`pages` 34 | - 空闲 `page` 描述表`free_page_list` 35 | 36 | ## 页面换出 37 | 38 | **何时换出?** 39 | 40 | 消极策略:内存不够时换出.如何描述内存不够?`alloc_page`返回为 `null` 即为内存不够. 41 | 42 | **可以换出谁?** 43 | 44 | 不是所有的页都可以换出,如内核页.如何标记它们?ucore 使用 `mm_struct`和`vma_struct`来标记合法的连续内存. 45 | 46 | ![](/images/虚拟内存管理.png) 47 | 48 | 49 | **具体换出谁** 50 | 51 | 由函数`swap_out_victim`挑选可以被换出的页.在`fifo`的策略下,`mm_struct`的`sm_priv`维护着先入先出队列. 52 | 53 | 如何维护的? 54 | 55 | 56 | 57 | 如何挑选? 58 | 59 | - 内核页绝对不能换出.如何标记? 60 | 61 | ## 参考资料 62 | 63 | - [CSDN: Linux分页机制之分页机制的演变--Linux内存管理(七)](https://blog.csdn.net/gatieme/article/details/52402967) -------------------------------------------------------------------------------- /notes/心得.md: -------------------------------------------------------------------------------- 1 | 操作系统作为内核,通过各种机制向提供应用程序服务.学习内核的过程有一大困难:我们通常是先学"机制",即内核是如何"提供"服务的,而在写代码时是要"建立"这样的服务.在建立的过程中,往往难以有可以上手的环境去测试,或者不知道如何去验证自己写的是否正确,只能像写文科题目一样,按照理论的步骤去添加代码.这种感觉很不好. 2 | 3 | 现代操作系统经过多年的进化,尽管有一些历史原因留下的坑,但其中很多设计非常巧妙,非常精炼.这也导致了很多设计目标互相耦合.但仔细挖掘后,我们可以尽量把这些机制"线性"化,目标是把这些零碎的知识"点"最后连接成有机的"知识". 4 | 5 | 6 | 1. 访问内存 7 | 1. 地址翻译 8 | 2. 地址检查 9 | 3. 缺页异常处理 10 | 4. 页面置换 11 | 12 | 讲义: 13 | 14 | ## 1. 虚拟化 15 | 16 | 17 | ---- 18 | 19 | ## 学习方法 20 | 21 | 在学习一个新的机制时,首先要按照自己的想法,自底向上地思考.为了完成这个工作,至少需要那些接口?需要哪些数据结构?然后再考虑上层的东西. 22 | 23 | - 理论学习:top-down 24 | - 工程学习:down-top 25 | 26 | - 理论的关注点:问题定义,流程归纳,状态转换,要素定义,数据结构,方案设计与比较,图示描述 27 | - 实践的关注点:数据结构,非主题但必需的问题讨论,代码讲解 28 | - 阅读代码不畅,很可能是基础不牢.需要下降,把底层的代码了解清楚 29 | - 在阅读代码细节之前,先想想如果我来实现,会如何实现?会用到哪些结构? 30 | 31 | 链表专门用于虚拟化!! 32 | 33 | ## 关于机制: 34 | 35 | ## ucore 模块划分 36 | 37 | - 进程管理 38 | - 中断管理 39 | - 内存管理 40 | - 设备管理 41 | 42 | ## 进程的创建 43 | 44 | - 分配内存 45 | - 加载可执行文件 46 | 47 | ## 基础内核进程 48 | 49 | - idle 进程,负责所有内核进程的调度 50 | - init_main,负责创建用户进程管理者 51 | - user_main,负责创建用户进程 52 | 53 | ## 特权级切换: int iret 54 | 55 | ## 编程思想 56 | 57 | 资源管理思想 58 | 59 | 资源池+索引值 60 | 61 | - 内存分配 62 | - 打开文件列表 -------------------------------------------------------------------------------- /notes/总线相关.md: -------------------------------------------------------------------------------- 1 | ## 两种 IO: 2 | 3 | - DMA, https://en.wikipedia.org/wiki/Direct_memory_access 4 | - Memory-mapped I/O, https://en.wikipedia.org/wiki/Memory-mapped_I/O 5 | 6 | 解释: 7 | 8 | - youtube: https://www.youtube.com/watch?v=aT5XMOrid7Y 9 | - cmu 公开课: http://www.cs.uwm.edu/classes/cs315/Bacon/Lecture/HTML/ch14s03.html 10 | 11 | DMA 需要CPU 提供额外的命令. 12 | 13 | ## ISA 14 | 15 | 16 | 17 | http://www.hardwarebook.info/ISA 18 | 19 | 3F0-3F7 Floppy Disk Controller -------------------------------------------------------------------------------- /notes/总结.md: -------------------------------------------------------------------------------- 1 | # ucore 设计思路分析 2 | 3 | ## 整体分析 4 | 5 | 操作系统至少要完成两个主要功能: 文件 IO 和程序执行,而程序的执行又依赖于 IO 6 | 7 | ## IO 子系统 8 | 9 | 与设备交互的系统. 10 | 11 | 设备有很多种,数据传输速度差别很大,因此需要区别对待. 12 | 13 | 设备类型 访问单位 访问顺序 IO 命令 举例 14 | 字符设备 字节 顺序访问 get()/put()等 键盘/鼠标 15 | 块设备 块 均匀访问 原始IO或文件系统接口/内存映射文件访问 磁盘/软盘 16 | 网络设备 格式化报文交换 - send/receive网络接口,多种网络协议 网卡,蓝牙 17 | 18 | 每类设备有自己的驱动 19 | 20 | 内存映射:load/store 21 | 22 | ## 什么是同步 IO,什么是异步 IO,它们的区别是什么? 23 | 24 | 同步 IO 与异步 IO 的区别在于,**当设备进行 IO 操作(磁盘缓存<->盘片)时,内核对应的发起此次 IO 的进程是否在执行其他操作?如果是,说明是异步.如果不是(也就是发起 IO 的进程正在等待),则为同步.** 25 | -------------------------------------------------------------------------------- /notes/教程.md: -------------------------------------------------------------------------------- 1 | # 面向实现编程 2 | 3 | # 1 ucore.img = bootblock + kernel 4 | 5 | 我们 **希望** 构建一个操作系统镜像文件 ucore.img, 让 cpu 加载运行。**事实上** cpu 的运行模式是,上电,执行 BIOS; BIOS 会进行自检,并加载镜像的第一个扇区。**但是** kernel 不一定比一个 sector 小。我们要假设 kernel 可能占用多于一个 sector 的空间。**所以** 我们把 ucore.img 分成两部分,一部分是 bootblock, 大小等于一个 sector, 包含小于一个 sector 的 bootloader, 被 BIOS 加载到内存;另一部分是 kernel, 被刚刚加载到内存的 bootloader 加载到内存。bootloader 可能还有其他用好处和用处。 6 | 7 | # 制作 bootsector 8 | 9 | ## bootloader 的设计 10 | 11 | 我们 **希望** bootloader 最终能加载 kernel 文件;我们**希望**这个加载过程用 C 语言代码实现。**但是** CPU 在开始执行 bootloader 代码时还没有 C 语言环境,**所以**我们要用汇编代码建立一个良好的 C语言环境. 12 | 13 | ## bootsector 签名程序 sign.c 14 | 15 | 我们 **希望** BIOS 至少能正确加载`bootsector`. 16 | 17 | **事实上** BIOS 会对 bootsector 进行校验,考察这个 512 字节大小的 sector 最后两个字节,应该是 `0x55` 和 `0xAA`. 18 | 19 | **所以** 我们在制作 bootsector 时一定要注意把最后的两个字节正确设置。这部分的 **实现** 可以参考 `sign.c`. 此文件可以独立编译,用于给输入文件填上最后两个字节的"签名". 如果输入文件大小大于 510 字节会报错。 20 | -------------------------------------------------------------------------------- /notes/网络编程.md: -------------------------------------------------------------------------------- 1 | ## 网络编程的问题与解决方案 2 | 3 | **问题** fork 进程后,子进程调用 exit 退出,会变为僵尸进程,占用内核资源.只要父进程不退出,子进程就一直僵尸. 4 | 5 | **解决方案** 在父进程安装信号处理函数,内部调用 wait.这样一来子进程退出后,父进程捕捉到信号,在 wait 中清理僵尸进程. 6 | 7 | **问题** 信号是不排队的.如果有多个子进程同时崩溃,父进程的wait处理结果是不确定的. 8 | 9 | **解决方案** 用 waitpid(). 10 | 11 | **问题** 当服务器崩溃时,向客户端发送 FIN .客户端无法感知到.因为客户端正阻塞在 fget(),无法接受 FIN,即"顾此失彼".客户端难以同时处理tcp 和 stdin两个输入. 12 | 13 | **解决方案** IO 复用. 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /notes/自问自答.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /notes/速查表.md: -------------------------------------------------------------------------------- 1 | ![](/images/内核虚拟地址.png) 2 | 3 | ## 物理地址与内核虚拟地址 4 | 5 | 宏/函数 | 含义 | 计算方式 6 | -----|----|----- 7 | PADDR(kva) | 内核虚拟地址->物理地址 | 物理地址=内核虚拟地址-KERNBASE 8 | KADDR(pa) | 物理地址->内核虚拟地址 | 内核虚拟地址=物理地址+KERNBASE 9 | 10 | 11 | 12 | 13 | 宏/函数 | 含义 | 计算方式 14 | -----|----|----- 15 | page2ppn | 页指针->物理页号 | 物理页号=页指针-页基址 16 | page2pa | 页指针->物理地址 | 页物理地址=页指针 17 | pa2page | 物理地址->页指针 | 18 | 19 | ## 地址翻译 20 | 21 | ![](/images/线性地址结构.png) 22 | 23 | 宏/函数 | 含义 | 计算方式 24 | -----|----|----- 25 | PDX(la) | 线性地址->页目录索引 | 页目录索引=线性地址 >> 22 & 0x3FF 26 | PTX(la) | 线性地址->页表索引 | 页表索引=线性地址 >> 12 & 0x3FF 27 | PPN(la) | 线性地址->物理页号 | 物理页号=线性地址 >> 12 28 | PGOFF(la) | 线性地址->物理页内偏移 | 物理页内偏移=线性地址 & 0xFFF 29 | 30 | ![](https://github.com/libinyl/CS-notes/blob/master/images/intel/v3/Figure%204-2.%20Linear-Address%20Translation%20to%20a%204-KByte%20Page%20using%2032-Bit%20Paging.png?raw=true) 31 | 32 | 宏/函数 | 含义 | 计算方式 33 | -----|----|----- 34 | PTE_ADDR(pte) | pte->pte 中维护的物理页地址 | 物理页地址=pte>>12 35 | PDE_ADDR(pde) | pde->pde 中维护的pte地址 36 | 37 | ![](/images/虚拟内存维护.png) 38 | 39 | > 图片来源: https://manybutfinite.com/post/how-the-kernel-manages-your-memory 40 | 41 | ## 虚拟内存合法性 42 | 43 | 属性 | 值 44 | ---|-- 45 | VM_READ | 0x00000001 46 | VM_WRITE | 0x00000002 47 | VM_EXEC | 0x00000004 48 | 49 | 50 | ## 常用缩写 51 | 52 | 缩写/前缀 | 全称 | 示例 53 | ------|----|--- 54 | nr | number | nr_system_calls = 67 -------------------------------------------------------------------------------- /others/IDE 文档ATA-d1410r3a.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/others/IDE 文档ATA-d1410r3a.pdf -------------------------------------------------------------------------------- /others/ucore.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/others/ucore.xls -------------------------------------------------------------------------------- /ppts/任务管理.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/ppts/任务管理.pptx -------------------------------------------------------------------------------- /ppts/内存管理.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/ppts/内存管理.pptx -------------------------------------------------------------------------------- /ppts/数据结构.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/ppts/数据结构.pptx -------------------------------------------------------------------------------- /ppts/文件系统.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/ppts/文件系统.pptx -------------------------------------------------------------------------------- /ppts/网络编程.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/ppts/网络编程.pptx -------------------------------------------------------------------------------- /ppts/进程.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/libinyl/lcore/9d7894792b4005af1925ee25e030b1374acf9853/ppts/进程.pptx --------------------------------------------------------------------------------