├── doc ├── DESIGN.md └── pics │ ├── 02-ed.png │ └── 01-explorer.png ├── src ├── docs │ ├── exit.txt │ ├── clear.txt │ ├── pwd.txt │ ├── mkdir.txt │ ├── file.txt │ ├── help.txt │ ├── kill.txt │ ├── cp.txt │ ├── less.txt │ ├── cat.txt │ ├── ed.txt │ ├── fg.txt │ ├── ls.txt │ ├── exec.txt │ ├── ps.txt │ └── cd.txt ├── include │ ├── config.h │ ├── kernel │ │ ├── kernel.h │ │ ├── memory.h │ │ ├── filesys │ │ │ ├── afs │ │ │ │ ├── file_type.h │ │ │ │ ├── _design.txt │ │ │ │ ├── blk_mem_buf.h │ │ │ │ ├── file_opr.h │ │ │ │ ├── disk_cache.h │ │ │ │ ├── file.h │ │ │ │ └── afs.h │ │ │ ├── import │ │ │ │ └── import.h │ │ │ ├── dpt.h │ │ │ ├── syscall.h │ │ │ └── filesys.h │ │ ├── execelf │ │ │ ├── readelf.h │ │ │ └── execelf.h │ │ ├── sysmsg │ │ │ ├── sysmsg_syscall.h │ │ │ ├── sysmsg.h │ │ │ └── sysmsg_src.h │ │ ├── console │ │ │ ├── console.h │ │ │ ├── con_buf.h │ │ │ └── print.h │ │ ├── memory │ │ │ ├── page_desc.h │ │ │ ├── vir_page_man.h │ │ │ ├── phy_mem_man.h │ │ │ └── vir_mem_man.h │ │ ├── rlist_node_alloc.h │ │ ├── explorer │ │ │ ├── disp.h │ │ │ ├── cmds.h │ │ │ ├── explorer.h │ │ │ ├── _design.txt │ │ │ └── screen.h │ │ ├── driver │ │ │ ├── kbdriver.h │ │ │ └── diskdriver.h │ │ ├── process │ │ │ ├── semaphore.h │ │ │ ├── spinlock.h │ │ │ └── thread.h │ │ ├── boot.h │ │ ├── syscall.h │ │ ├── assert.h │ │ ├── interrupt.h │ │ ├── asm.h │ │ └── seg_desc.h │ ├── shared │ │ ├── stdbool.h │ │ ├── freelist.h │ │ ├── explorer.h │ │ ├── stdint.h │ │ ├── asm.h │ │ ├── ctype.h │ │ ├── string.h │ │ ├── utility.h │ │ ├── rbtree.h │ │ ├── path.h │ │ ├── proc_mem.h │ │ ├── sysmsg.h │ │ ├── ptrlist.h │ │ ├── atrc.h │ │ ├── screen.h │ │ ├── keyboard.h │ │ ├── filesys.h │ │ ├── syscall.h │ │ └── sys.h │ └── lib │ │ ├── input.h │ │ ├── path.h │ │ ├── _sys │ │ └── _mem.h │ │ ├── mem.h │ │ ├── assert.h │ │ ├── fstm.h │ │ └── splock.h ├── applications │ ├── ed │ │ ├── rf.h │ │ ├── rf.c │ │ ├── ed.h │ │ └── main.c │ ├── pwd │ │ └── main.c │ ├── ls │ │ └── main.c │ ├── help │ │ └── main.c │ ├── mkdir │ │ └── main.c │ ├── cat │ │ └── main.c │ ├── cp │ │ └── main.c │ └── file │ │ └── main.c ├── lib │ ├── assert.c │ ├── _sys │ │ └── _start.c │ ├── path.c │ ├── input.c │ └── fstm.c ├── kernel │ ├── main.c │ ├── process │ │ ├── thread.s │ │ └── semaphore.c │ ├── console │ │ ├── con_buf.c │ │ └── print.c │ ├── assert.c │ ├── rlist_node_alloc.c │ ├── kernel.c │ ├── filesys │ │ ├── afs │ │ │ └── blk_mem_buf.c │ │ ├── dpt.c │ │ └── import │ │ │ └── import.c │ ├── memory │ │ └── vir_page_man.c │ ├── sysmsg │ │ ├── sysmsg.c │ │ ├── sysmsg_syscall.c │ │ └── sysmsg_src.c │ ├── explorer │ │ ├── cmds │ │ │ ├── exec.c │ │ │ ├── cd.c │ │ │ └── procs.c │ │ └── disp.c │ ├── execelf │ │ ├── readelf.c │ │ └── execelf.c │ ├── syscall.c │ └── interrupt │ │ └── interrupt.s ├── tools │ ├── disk.h │ ├── bin_trans │ │ └── main.cpp │ ├── mkdpt │ │ └── main.cpp │ └── disk_ipt │ │ └── main.cpp ├── shared │ ├── sys │ │ ├── proc.c │ │ ├── keyboard.c │ │ ├── expl.c │ │ ├── sysmsg.c │ │ ├── filesys.c │ │ └── conio.c │ ├── freelist.c │ ├── atrc.c │ ├── ptrlist.c │ └── string.c └── boot │ ├── mbr.s │ └── boot.s ├── .gitignore ├── bochsrc.txt ├── make ├── lib ├── shared ├── tool ├── application └── kernel ├── LICENSE ├── README.md ├── makefile ├── setup_old.sh └── setup.sh /doc/DESIGN.md: -------------------------------------------------------------------------------- 1 | # TinyOS设计概述 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/docs/exit.txt: -------------------------------------------------------------------------------- 1 | Shutdown. 2 | Usage: exit -------------------------------------------------------------------------------- /src/docs/clear.txt: -------------------------------------------------------------------------------- 1 | Clear explorer output. 2 | Usage: clear -------------------------------------------------------------------------------- /src/docs/pwd.txt: -------------------------------------------------------------------------------- 1 | Print current working directory. 2 | Usage: pwd -------------------------------------------------------------------------------- /src/docs/mkdir.txt: -------------------------------------------------------------------------------- 1 | Create empty driectory. 2 | Usage: mkdir dir1 [dir2] ... -------------------------------------------------------------------------------- /doc/pics/02-ed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TinyOSOrg/TinyOS/HEAD/doc/pics/02-ed.png -------------------------------------------------------------------------------- /src/docs/file.txt: -------------------------------------------------------------------------------- 1 | Save process output to specified file. 2 | Usage: (...) | file filename -------------------------------------------------------------------------------- /src/docs/help.txt: -------------------------------------------------------------------------------- 1 | Command/application documentation. 2 | Usage: help command/application -------------------------------------------------------------------------------- /src/docs/kill.txt: -------------------------------------------------------------------------------- 1 | Kill processes with specified pid. 2 | Usage: kill pid1 [pid2] [pid3] ... -------------------------------------------------------------------------------- /doc/pics/01-explorer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TinyOSOrg/TinyOS/HEAD/doc/pics/01-explorer.png -------------------------------------------------------------------------------- /src/docs/cp.txt: -------------------------------------------------------------------------------- 1 | Make a copy of specified file. 2 | Usage: cp source-filename destination-filename -------------------------------------------------------------------------------- /src/docs/less.txt: -------------------------------------------------------------------------------- 1 | View file content (read only). 2 | Usage: less filename 3 | (...) | less -------------------------------------------------------------------------------- /src/docs/cat.txt: -------------------------------------------------------------------------------- 1 | Print file content / process output to screen 2 | Usage: cat filename 3 | (...) | cat -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bochs.out 2 | 3 | .vscode/ 4 | 5 | *.o 6 | *.d 7 | *.bin 8 | *.bootbin 9 | *.img 10 | 11 | build/ 12 | -------------------------------------------------------------------------------- /src/docs/ed.txt: -------------------------------------------------------------------------------- 1 | Simple text file edtior. 2 | Usage: ed filename 3 | If specified file doesn't exist, ed will create it with empty content. -------------------------------------------------------------------------------- /src/docs/fg.txt: -------------------------------------------------------------------------------- 1 | Make a process (running in background) foreground. 2 | Usage: fg [pid] 3 | With pid omitted, process created most recently will be chosen. -------------------------------------------------------------------------------- /src/include/config.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_CONFIG_H 2 | #define TINY_OS_CONFIG_H 3 | 4 | /* 去除所有运行时断言 */ 5 | // #define NO_ASSERT 6 | 7 | #endif /* TINY_OS_CONFIG_H */ 8 | -------------------------------------------------------------------------------- /src/docs/ls.txt: -------------------------------------------------------------------------------- 1 | List all files in current working directory. 2 | Usage: ls 3 | Output: 4 | (d/r) filename 5 | where d = directory 6 | r = regular file -------------------------------------------------------------------------------- /src/include/kernel/kernel.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_KERNEL_H 2 | #define TINY_OS_KERNEL_H 3 | 4 | void init_kernel(); 5 | 6 | void destroy_kernel(); 7 | 8 | #endif /* TINY_OS_KERNEL_H */ 9 | -------------------------------------------------------------------------------- /src/applications/ed/rf.h: -------------------------------------------------------------------------------- 1 | #ifndef ED_RF_H 2 | #define ED_RF_H 3 | 4 | #include 5 | 6 | void rf_init(usr_file_handle file); 7 | 8 | char rf_provider(); 9 | 10 | #endif /* ED_RF_H */ 11 | -------------------------------------------------------------------------------- /src/include/kernel/memory.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_MEMORY_H 2 | #define TINY_OS_MEMORY_H 3 | 4 | #include 5 | #include 6 | 7 | #endif /* TINY_OS_MEMORY_H */ 8 | -------------------------------------------------------------------------------- /src/docs/exec.txt: -------------------------------------------------------------------------------- 1 | Create a user process with specified name with an elf file. 2 | Usage: exec filename procname ...(args) 3 | If procname == "`", filename will be the final process name. 4 | exec doesn't support pipe between processes. -------------------------------------------------------------------------------- /src/include/kernel/filesys/afs/file_type.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_AFS_FILE_TYPE_H 2 | #define TINY_OS_AFS_FILE_TYPE_H 3 | 4 | #define AFS_FILE_TYPE_REGULAR 1 5 | #define AFS_FILE_TYPE_DIRECTORY 2 6 | 7 | #endif /* TINY_OS_AFS_FILE_TYPE_H */ 8 | -------------------------------------------------------------------------------- /src/lib/assert.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void _lib_assert_impl(const char * file, const char *func, int line) 5 | { 6 | printf("%LAssertion failed in %s, %s, %u\n", file, func, (uint32_t)line); 7 | } 8 | -------------------------------------------------------------------------------- /src/docs/ps.txt: -------------------------------------------------------------------------------- 1 | List all running user processes. 2 | Usage: ps 3 | If all information can be printed without rolling the screen, 4 | ps will simply list of processes in explorer. 5 | Otherwise, follow the hints on the screen to browse process list. -------------------------------------------------------------------------------- /src/include/shared/stdbool.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_SHARD_STDBOOL_H 2 | #define TINY_OS_SHARD_STDBOOL_H 3 | 4 | #ifndef bool 5 | #define bool int 6 | #define true 1 7 | #define false 0 8 | #endif 9 | 10 | #endif /* TINY_OS_SHARD_STDBOOL_H */ 11 | -------------------------------------------------------------------------------- /src/include/lib/input.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_LIB_INPUT_H 2 | #define TINY_OS_LIB_INPUT_H 3 | 4 | void _init_input(); 5 | 6 | /* 7 | 阻塞地从explorer处获取一个字符 8 | 在进程自身无显示缓存时有效,否则该函数不会返回 9 | */ 10 | char get_char(); 11 | 12 | #endif /* TINY_OS_LIB_INPUT_H */ 13 | -------------------------------------------------------------------------------- /src/applications/pwd/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | expl_new_line(); 9 | printf("Current working directory: %s", argv[0]); 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /src/include/lib/path.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_LIB_PATH_H 2 | #define TINY_OS_LIB_PATH_H 3 | 4 | #include 5 | 6 | /* input包含分区信息,再给个delta,合成并得到dp和分区内路径 */ 7 | char *malloc_and_cat_path(const char *input, const char *delta, 8 | filesys_dp_handle *out_dp); 9 | 10 | #endif /* TINY_OS_LIB_PATH_H */ 11 | -------------------------------------------------------------------------------- /bochsrc.txt: -------------------------------------------------------------------------------- 1 | megs: 128 2 | 3 | display_library: x 4 | 5 | romimage: file=$BXSHARE/BIOS-bochs-latest 6 | vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest 7 | 8 | boot: disk 9 | 10 | log: bochs.out 11 | 12 | mouse: enabled=0 13 | 14 | ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 15 | ata0-master: type=disk, path="hd.img", mode=flat 16 | -------------------------------------------------------------------------------- /src/include/kernel/execelf/readelf.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_READELF_H 2 | #define TINY_OS_READELF_H 3 | 4 | #include 5 | 6 | /* 7 | 装载一个32位elf程序 8 | elf_addr为文件内容在内存中的地址 9 | 返回值为程序入口指针 10 | 11 | beg和end用来返回elf中程序所占区域[beg, end) 12 | */ 13 | void *load_elf(const void *elf_addr, size_t *beg, size_t *end); 14 | 15 | #endif /* TINY_OS_READELF_H */ 16 | -------------------------------------------------------------------------------- /src/include/kernel/sysmsg/sysmsg_syscall.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_PROC_SYSMSG_SYSCALL_H 2 | #define TINY_OS_PROC_SYSMSG_SYSCALL_H 3 | 4 | #include 5 | 6 | /* 初始化内核消息系统调用 */ 7 | void init_sysmsg_syscall(); 8 | 9 | /* 内核消息系统调用实现 */ 10 | uint32_t syscall_sysmsg_impl(uint32_t func, uint32_t arg1, uint32_t arg2); 11 | 12 | #endif /* TINY_OS_PROC_SYSMSG_SYSCALL_H */ 13 | -------------------------------------------------------------------------------- /src/include/lib/_sys/_mem.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_LIB_dSYS_dMEM_H 2 | #define TINY_OS_LIB_dSYS_dMEM_H 3 | 4 | #include 5 | #include 6 | 7 | void _init_mem_man(); 8 | 9 | /* 返回的结果为4字节对齐,失败时返回NULL */ 10 | void *_malloc(size_t size); 11 | 12 | /* ptr为调用_malloc得到的结果 */ 13 | void _free(void *ptr); 14 | 15 | #endif /* TINY_OS_LIB_dSYS_dMEM_H */ 16 | -------------------------------------------------------------------------------- /src/kernel/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | int main() 8 | { 9 | init_kernel(); 10 | 11 | create_process("explorer", explorer, true); 12 | 13 | while(true) 14 | { 15 | do_releasing_thds_procs(); 16 | yield_CPU(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/tools/disk.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_TOOLS_DISK_H 2 | #define TINY_OS_TOOLS_DISK_H 3 | 4 | /* 5 | 外部工具中有很多是关于磁盘映像操作的 6 | 这里定义它们的共有参数 7 | */ 8 | 9 | /* 磁盘最大扇区号 */ 10 | #define DISK_MAX_SECTOR_NUMBER 262079 11 | 12 | /* import分区起始扇区 */ 13 | #define DISK_IMPORT_DP_BEGIN 182144 14 | 15 | /* import分区结束扇区 */ 16 | #define DISK_IMPORT_DP_END DISK_MAX_SECTOR_NUMBER 17 | 18 | #endif /* TINY_OS_TOOLS_DISK_H */ 19 | -------------------------------------------------------------------------------- /src/include/kernel/filesys/afs/_design.txt: -------------------------------------------------------------------------------- 1 | AFS设计概要 2 | 3 | 抽象分层: 4 | 5 | 1. 物理层。物理层直接面对磁盘上的扇区,向上层提供以下操作: 6 | (1) 磁盘空闲块的分配和释放 7 | (2) 块读写 8 | (3) entry分配和释放 9 | 2. 节点层。节点层向上层提供以下操作: 10 | (2) 文件指针,即某个entry对应的文件的描述符 11 | (3) 打开,读取和写入entry文件 12 | 3. 目录层。目录层提供entry层面的目录服务,包括: 13 | (1) 目录文件结构 14 | 4. 文件系统层。文件系统层提供以下抽象: 15 | (1) 目录遍历、创建和销毁 16 | (2) 文件创建、读取、写入和销毁。工作文件槽在这一层实现 17 | (3) 文件锁 18 | -------------------------------------------------------------------------------- /src/include/kernel/console/console.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_CONSOLE_H 2 | #define TINY_OS_CONSOLE_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | /* 初始化控制台 */ 9 | void init_console(); 10 | 11 | /* 取得显存console buffer */ 12 | #define get_sys_con_buf() ((struct con_buf*)0xc00b8000) 13 | 14 | /* 控制台系统调用实现 */ 15 | uint32_t syscall_console_impl(uint32_t func, uint32_t arg); 16 | 17 | #endif /* TINY_OS_CONSOLE_H */ 18 | -------------------------------------------------------------------------------- /src/include/kernel/filesys/afs/blk_mem_buf.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_FILESYS_AFS_BLK_MEM_BUF_H 2 | #define TINY_OS_FILESYS_AFS_BLK_MEM_BUF_H 3 | 4 | /* 用来分配block和扇区内存缓冲 */ 5 | 6 | void init_afs_buffer_allocator(); 7 | 8 | void *afs_alloc_block_buffer(); 9 | 10 | void afs_free_block_buffer(void *buf); 11 | 12 | void *afs_alloc_sector_buffer(); 13 | 14 | void afs_free_sector_buffer(void *buf); 15 | 16 | #endif /* TINY_OS_FILESYS_AFS_BLK_MEM_BUF_H */ 17 | -------------------------------------------------------------------------------- /src/shared/sys/proc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | uint32_t get_pid() 5 | { 6 | return syscall_param0(SYSCALL_GET_PROCESS_ID); 7 | } 8 | 9 | void yield_cpu() 10 | { 11 | syscall_param0(SYSCALL_YIELD_CPU); 12 | } 13 | 14 | void exit_thread() 15 | { 16 | syscall_param0(SYSCALL_EXIT_THREAD); 17 | } 18 | 19 | bool new_thread(void (*entry)()) 20 | { 21 | return syscall_param1(SYSCALL_NEW_THREAD, entry); 22 | } 23 | -------------------------------------------------------------------------------- /make/lib: -------------------------------------------------------------------------------- 1 | LIB_C_FILES = $(shell find ./src/lib/ -name "*.c") 2 | LIB_O_FILES = $(patsubst %.c, %.o, $(LIB_C_FILES)) 3 | LIB_D_FILES = $(patsubst %.c, %.d, $(LIB_C_FILES)) 4 | 5 | $(LIB_O_FILES) : %.o : %.c 6 | $(CC) $(CC_FLAGS) -c $< -o $@ 7 | 8 | $(LIB_D_FILES) : %.d : %.c 9 | @set -e; \ 10 | rm -f $@; \ 11 | $(CC) -MM $(CC_FLAGS) $< $(CC_INCLUDE_FLAGS) > $@.$$$$.dtmp; \ 12 | sed 's,\(.*\)\.o\:,$*\.o $*\.d\:,g' < $@.$$$$.dtmp > $@; \ 13 | rm -f $@.$$$$.dtmp 14 | 15 | -include $(LIB_D_FILES) -------------------------------------------------------------------------------- /src/include/kernel/console/con_buf.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_CONSOLE_CON_BUF_H 2 | #define TINY_OS_CONSOLE_CON_BUF_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | struct con_buf 10 | { 11 | char data[CON_BUF_BYTE_SIZE]; 12 | struct semaphore lock; 13 | uint16_t cursor; 14 | }; 15 | 16 | struct con_buf *kalloc_con_buf(); 17 | 18 | void free_con_buf(struct con_buf *buf); 19 | 20 | #endif /* TINY_OS_CONSOLE_CON_BUF_H */ 21 | -------------------------------------------------------------------------------- /make/shared: -------------------------------------------------------------------------------- 1 | SHARED_C_FILES = $(shell find ./src/shared/ -name "*.c") 2 | SHARED_O_FILES = $(patsubst %.c, %.o, $(SHARED_C_FILES)) 3 | SHARED_D_FILES = $(patsubst %.c, %.d, $(SHARED_C_FILES)) 4 | 5 | $(SHARED_O_FILES) : %.o : %.c 6 | $(CC) $(CC_FLAGS) -c $< -o $@ 7 | 8 | $(SHARED_D_FILES) : %.d : %.c 9 | @set -e; \ 10 | rm -f $@; \ 11 | $(CC) -MM $(CC_FLAGS) $< $(CC_INCLUDE_FLAGS) > $@.$$$$.dtmp; \ 12 | sed 's,\(.*\)\.o\:,$*\.o $*\.d\:,g' < $@.$$$$.dtmp > $@; \ 13 | rm -f $@.$$$$.dtmp 14 | 15 | -include $(SHARED_D_FILES) -------------------------------------------------------------------------------- /src/include/kernel/filesys/import/import.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_FILESYS_IMPORT_IMPORT_H 2 | #define TINY_OS_FILESYS_IMPORT_IMPORT_H 3 | 4 | #include 5 | 6 | /* 7 | Import分区是用于开发和测试的一种特殊磁盘分区 8 | 9 | 由于TinyOS还没有任何获取虚拟机外的文件的手段,要获取从外部交叉编译得到的程序,直接以flat模式从磁盘映像上获取是最为方便的 10 | Import分区就是用来做这个的分区…… 11 | 12 | Import分区的结构定义在shared/filesys/import/import.h中 13 | */ 14 | 15 | /* 从以beg开头的import分区中导入外部文件 */ 16 | void ipt_import_from_dp(uint32_t dp_beg); 17 | 18 | #endif /* TINY_OS_FILESYS_IMPORT_IMPORT_H */ 19 | -------------------------------------------------------------------------------- /src/include/lib/mem.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_LIB_MEM_H 2 | #define TINY_OS_LIB_MEM_H 3 | 4 | #include 5 | 6 | static inline void *malloc(size_t size) 7 | { 8 | extern void *_malloc(size_t); 9 | return _malloc(size); 10 | } 11 | 12 | static inline void free(void *ptr) 13 | { 14 | extern void _free(void*); 15 | _free(ptr); 16 | } 17 | 18 | /* IMPROVE */ 19 | static inline void *remalloc(void *ptr, size_t size) 20 | { 21 | free(ptr); 22 | return malloc(size); 23 | } 24 | 25 | #endif /* TINY_OS_LIB_MEM_H */ 26 | -------------------------------------------------------------------------------- /src/include/kernel/memory/page_desc.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_PAGE_DESC_H 2 | #define TINY_OS_PAGE_DESC_H 3 | 4 | #include 5 | 6 | typedef uint32_t page_desc_attrib; 7 | 8 | #define PAGE_PRESENT_TRUE ((page_desc_attrib)1) 9 | #define PAGE_PRESENT_FALSE ((page_desc_attrib)0) 10 | 11 | #define PAGE_RW_READ_ONLY ((page_desc_attrib)(0 << 1)) 12 | #define PAGE_RW_READ_WRITE ((page_desc_attrib)(1 << 1)) 13 | 14 | #define PAGE_USER_USER ((page_desc_attrib)(1 << 2)) 15 | #define PAGE_USER_SUPER ((page_desc_attrib)(0 << 2)) 16 | 17 | #endif /* TINY_OS_PAGE_DESC_H */ 18 | -------------------------------------------------------------------------------- /src/include/kernel/rlist_node_alloc.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_RLIST_NODE_ALLOC_H 2 | #define TINY_OS_RLIST_NODE_ALLOC_H 3 | 4 | #include 5 | 6 | /* 7 | 内核中许多地方要用到rlist 8 | 这里做一个公共的节点分配和释放器 9 | 谁让内核层面没有malloc和free可以用呢 10 | */ 11 | 12 | /* 在虚拟内存管理系统初始化之后、用到rlist node allocator之前调用 */ 13 | void init_kernel_rlist_node_alloc(); 14 | 15 | /* 申请一个常驻内存的rlist node */ 16 | struct rlist_node *kernel_resident_rlist_node_alloc(); 17 | 18 | /* 释放一个常驻内存的rlist node */ 19 | void kernel_resident_rlist_node_dealloc(struct rlist_node *node); 20 | 21 | #endif /* TINY_OS_RLIST_NODE_ALLOC_H */ 22 | -------------------------------------------------------------------------------- /src/docs/cd.txt: -------------------------------------------------------------------------------- 1 | Change current working directory. 2 | Usage: cd pathname 3 | A valid pathname must be in one of the following form: 4 | 1. . 5 | current working directory 6 | 2. .. 7 | parent of current working directory 8 | 3. dirname 9 | path relative to current working directory 10 | 4. absolute path 11 | absolute path under current disk partition 12 | 4. dp_number:absolute path 13 | absolute path under specified disk partition (by partition number) 14 | 5. dp_name>absolute path 15 | absolute path under specified disk partition (by partition name) -------------------------------------------------------------------------------- /src/include/kernel/explorer/disp.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_EXPLORER_DISP_H 2 | #define TINY_OS_EXPLORER_DISP_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | void init_disp(); 9 | 10 | void disp_set_cursor(uint8_t x, uint8_t y); 11 | 12 | void disp_cursor_end(); 13 | 14 | void disp_get_cursor(uint8_t *x, uint8_t *y); 15 | 16 | void disp_put_char(char ch); 17 | 18 | void disp_put_str(const char *str); 19 | 20 | void disp_put_line_str(const char *str); 21 | 22 | void disp_new_line(); 23 | 24 | void disp_printf(const char *fmt, ...); 25 | 26 | #endif /* TINY_OS_EXPLORER_DISP_H */ 27 | -------------------------------------------------------------------------------- /src/shared/sys/keyboard.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | bool is_key_pressed(uint8_t kc) 7 | { 8 | return syscall_param2(SYSCALL_KEYBOARD_QUERY, 9 | KEYBOARD_SYSCALL_FUNCTION_IS_KEY_PRESSED, kc) != 0; 10 | } 11 | 12 | void register_key_msg() 13 | { 14 | syscall_param1(SYSCALL_SYSMSG_OPERATION, 15 | SYSMSG_SYSCALL_FUNCTION_REGISTER_KEYBOARD_MSG); 16 | } 17 | 18 | void register_char_msg() 19 | { 20 | syscall_param1(SYSCALL_SYSMSG_OPERATION, 21 | SYSMSG_SYSCALL_FUNCTION_REGISTER_CHAR_MSG); 22 | } 23 | 24 | -------------------------------------------------------------------------------- /src/include/lib/assert.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_LIB_ASSERT_H 2 | #define TINY_OS_LIB_ASSERT_H 3 | 4 | /* 5 | emm,这个宏在fail的时候只能挡住它所在的线程 6 | 要让assert能多线程运作,需要OS支持,我懒得加了…… 7 | */ 8 | #ifndef _LIB_ASSERT_OFF 9 | #define assert(EXPL) \ 10 | do { \ 11 | extern void _lib_assert_impl(const char *, \ 12 | const char *, \ 13 | int); \ 14 | if(!(EXPL)) \ 15 | _lib_assert_impl(__FILE__, __FUNCTION__, __LINE__); \ 16 | } while(0) 17 | #else 18 | #define assert(EXPL) do { } while(0) 19 | #endif 20 | 21 | #endif /* TINY_OS_LIB_ASSERT_H */ 22 | -------------------------------------------------------------------------------- /src/include/shared/freelist.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_LIB_FREELIST_H 2 | #define TINY_OS_LIB_FREELIST_H 3 | 4 | #include 5 | #include 6 | 7 | /* 自由链表句柄 */ 8 | typedef uint32_t freelist_handle; 9 | 10 | /* 初始化一个自由链表 */ 11 | void init_freelist(freelist_handle *handle); 12 | 13 | /* 14 | 向自由链表中插入一块区域 15 | 区域大小应不小于sizeof(void*) 16 | */ 17 | void add_freelist(freelist_handle *handle, void *mem_zone); 18 | 19 | /* 一个自由链表是否为空 */ 20 | bool is_freelist_empty(freelist_handle *handle); 21 | 22 | /* 23 | 从自由链表中取出一块区域 24 | 链表为空时返回NULL 25 | */ 26 | void *fetch_freelist(freelist_handle *handle); 27 | 28 | #endif /* TINY_OS_LIB_FREELIST_H */ 29 | -------------------------------------------------------------------------------- /src/lib/_sys/_start.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | void _start() 8 | { 9 | extern int main(int, char **); 10 | 11 | _init_input(); 12 | _init_mem_man(); 13 | 14 | uint32_t parg = PROC_ARG_ZONE_ADDR; 15 | char *argv[EXEC_ELF_ARG_MAX_COUNT + 1]; 16 | 17 | uint32_t argc = *(uint32_t*)parg; 18 | parg += sizeof(uint32_t); 19 | 20 | for(uint32_t i = 0; i < argc; ++i) 21 | argv[i] = (char*)(parg + i * EXEC_ELF_ARG_BUF_SIZE); 22 | argv[argc] = NULL; 23 | 24 | main(argc, argv); 25 | 26 | pipe_null_char(); 27 | exit_thread(); 28 | } 29 | -------------------------------------------------------------------------------- /src/include/shared/explorer.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_SHARED_EXPLORER_H 2 | #define TINY_OS_SHARED_EXPLORER_H 3 | 4 | #include 5 | #include 6 | 7 | struct expl_output_msg 8 | { 9 | sysmsg_type type; // 应为SYSMSG_TYPE_EXPL_OUTPUT 10 | char ch; 11 | char _padding[3]; 12 | uint32_t out_pid; 13 | uint32_t out_uid; 14 | }; 15 | 16 | struct expl_input_msg 17 | { 18 | sysmsg_type type; // 应为SYSMSG_TYPE_EXPL_INPUT 19 | char params[SYSMSG_PARAM_SIZE]; 20 | }; 21 | 22 | STATIC_ASSERT(sizeof(struct expl_output_msg) == sizeof(struct sysmsg), 23 | invalid_size_of_expl_output_msg); 24 | 25 | #endif /* TINY_OS_SHARED_EXPLORER_H */ 26 | -------------------------------------------------------------------------------- /src/include/kernel/driver/kbdriver.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_KB_DRIVER_H 2 | #define TINY_OS_KB_DRIVER_H 3 | 4 | #include 5 | 6 | /* 7 | 键盘驱动 8 | */ 9 | 10 | struct PCB; 11 | 12 | /* 键盘驱动初始化 */ 13 | void init_kb_driver(); 14 | 15 | /* 16 | 订阅键盘消息 17 | 通常由进程自己调用 18 | */ 19 | void subscribe_kb(struct PCB *pcb); 20 | 21 | /* 22 | 订阅字符输入消息 23 | */ 24 | void subscribe_char(struct PCB *pcb); 25 | 26 | /* 查询某个按键的状态 */ 27 | bool kis_key_pressed(uint8_t keycode); 28 | 29 | /* 30 | 键盘状态查询相关的系统调用 31 | 参数是功能号,见shared/syscall/keyboard 32 | */ 33 | uint32_t syscall_keyboard_query_impl(uint32_t func, uint32_t arg); 34 | 35 | #endif /* TINY_OS_KB_DRIVER_H */ 36 | -------------------------------------------------------------------------------- /src/shared/sys/expl.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | bool alloc_fg() 5 | { 6 | return syscall_param0(SYSCALL_EXPL_ALLOC_FOREGROUND); 7 | } 8 | 9 | bool free_fg() 10 | { 11 | return syscall_param0(SYSCALL_EXPL_FREE_FOREGROUND); 12 | } 13 | 14 | bool alloc_con_buf() 15 | { 16 | return syscall_param0(SYSCALL_EXPL_ALLOC_CON_BUF); 17 | } 18 | 19 | void put_char_expl(char ch) 20 | { 21 | uint32_t arg = ch; 22 | syscall_param1(SYSCALL_EXPL_PUT_CHAR, arg); 23 | } 24 | 25 | void expl_new_line() 26 | { 27 | syscall_param0(SYSCALL_EXPL_NEW_LINE); 28 | } 29 | 30 | void pipe_null_char() 31 | { 32 | syscall_param0(SYSCALL_PIPE_NULL_CHAR); 33 | } 34 | -------------------------------------------------------------------------------- /src/include/kernel/process/semaphore.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_SEMAPHORE_H 2 | #define TINY_OS_SEMAPHORE_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | /* 9 | 内核信号量,提供PV原语 10 | P: 11 | if(--value < 0) 12 | block(); 13 | V: 14 | if(++value <= 0) 15 | awake_one(); 16 | */ 17 | 18 | struct semaphore 19 | { 20 | volatile int32_t val; 21 | rlist blocked_threads; 22 | }; 23 | 24 | /* 信号量初始化 */ 25 | void init_semaphore(struct semaphore *s, int32_t init_val); 26 | 27 | /* P */ 28 | void semaphore_wait(struct semaphore *s); 29 | 30 | /* V */ 31 | void semaphore_signal(struct semaphore *s); 32 | 33 | #endif /* TINY_OS_SEMAPHORE_H */ 34 | -------------------------------------------------------------------------------- /src/include/kernel/execelf/execelf.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_EXEC_ELF_EXEC_H 2 | #define TINY_OS_EXEC_ELF_EXEC_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | enum exec_elf_result 9 | { 10 | exec_elf_success, // 进程创建成功 11 | exec_elf_file_error, // elf文件打开/读取出现错误 12 | exec_elf_invalid_elf, // elf文件格式错误 13 | }; 14 | 15 | /* 以磁盘上的一个elf文件为程序创建一个进程 */ 16 | enum exec_elf_result exec_elf(const char *proc_name, 17 | filesys_dp_handle dp, const char *elf_path, 18 | bool is_PL_0, uint32_t argc, const char **argv, 19 | uint32_t *pid); 20 | 21 | #endif /* TINY_OS_EXEC_ELF_EXEC_H */ 22 | -------------------------------------------------------------------------------- /src/include/kernel/explorer/cmds.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_EXPLORER_PROCS_H 2 | #define TINY_OS_EXPLORER_PROCS_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | /* Explorer中的部分内建命令 */ 9 | 10 | /* 输出进程列表 */ 11 | void expl_show_procs(); 12 | 13 | /* cd,失败时返回false */ 14 | bool expl_cd(filesys_dp_handle *dp, char *cur, 15 | uint32_t max_len, const char *arg); 16 | 17 | /* 18 | exec,执行一个用户程序 19 | args为 20 | 程序路径(绝对/相对) 参数1 参数2 …… 21 | */ 22 | bool expl_exec(filesys_dp_handle dp, const char *working_dir, 23 | const char *dst, const char *proc_name, 24 | const char **args, uint32_t args_cnt, 25 | uint32_t *_pid); 26 | 27 | #endif /* TINY_OS_EXPLORER_PROCS_H */ 28 | -------------------------------------------------------------------------------- /src/lib/path.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | char *malloc_and_cat_path(const char *input, const char *delta, 8 | filesys_dp_handle *out_dp) 9 | { 10 | filesys_dp_handle dp = get_dp_handle_from_path(input, malloc, free); 11 | if(dp >= DPT_UNIT_COUNT) 12 | return NULL; 13 | 14 | uint32_t size = strlen(input) + strlen(delta) + 1; 15 | char *ret = malloc(size); 16 | if(!ret) 17 | return NULL; 18 | 19 | if(!cat_path_ex_s(dp, skip_dp_in_abs_path(input), 20 | delta, out_dp, ret, size)) 21 | { 22 | free(ret); 23 | return NULL; 24 | } 25 | 26 | return ret; 27 | } 28 | -------------------------------------------------------------------------------- /src/include/kernel/process/spinlock.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_PROCESS_SPIN_LOCK_H 2 | #define TINY_OS_PROCESS_SPIN_LOCK_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | /* 自旋锁实现的互斥量,不解释 */ 10 | 11 | // typedef volatile uint32_t spinlock; in thread.h 12 | 13 | static inline void init_spinlock(spinlock *lock) 14 | { 15 | *lock = 0; 16 | } 17 | 18 | /* 在单核时,自旋锁的等待循环完全是时间浪费(并不能避免线程切换开销),所以这里的lock在发生自旋时会yield CPU */ 19 | static inline void spinlock_lock(spinlock *lock) 20 | { 21 | while(xchg_u32(lock, 1)) 22 | yield_CPU(); 23 | } 24 | 25 | static inline void spinlock_unlock(spinlock *lock) 26 | { 27 | __asm__ __volatile__("" : : : "memory"); 28 | *lock = 0; 29 | } 30 | 31 | #endif /* TINY_OS_PROCESS_SPIN_LOCK_H */ 32 | -------------------------------------------------------------------------------- /src/kernel/process/thread.s: -------------------------------------------------------------------------------- 1 | [bits 32] 2 | 3 | section .text 4 | 5 | global switch_to_thread 6 | global jmp_to_thread 7 | 8 | ; void switch_to_thread(struct TCB *src, struct TCB *dst); 9 | switch_to_thread: 10 | 11 | push esi 12 | push edi 13 | push ebx 14 | push ebp 15 | 16 | ; 取得src指针值 17 | mov eax, [esp + 20] 18 | ; 栈指针 -> src->ker_stack 19 | mov [eax], esp 20 | 21 | ; 取得dst指针值 22 | mov eax, [esp + 24] 23 | ; dst->ker_stack -> 栈指针 24 | mov esp, [eax] 25 | 26 | pop ebp 27 | pop ebx 28 | pop edi 29 | pop esi 30 | 31 | ret 32 | 33 | ; void jmp_to_thread(struct TCB *dst); 34 | jmp_to_thread: 35 | 36 | mov eax, [esp + 4] 37 | mov esp, [eax] 38 | 39 | pop ebp 40 | pop ebx 41 | pop edi 42 | pop esi 43 | 44 | ret -------------------------------------------------------------------------------- /src/include/kernel/filesys/dpt.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_DISK_PARTITION_TABLE_H 2 | #define TINY_OS_DISK_PARTITION_TABLE_H 3 | 4 | #include 5 | #include 6 | 7 | /* 初始化分区表 */ 8 | void init_dpt(); 9 | 10 | /* 取得第idx个分区表项 */ 11 | struct dpt_unit *get_dpt_unit(size_t idx); 12 | 13 | /* 将一个分区格式化为指定的类型 */ 14 | bool reformat_dp(size_t idx, disk_partition_type type); 15 | 16 | /* 取得某个分区文件系统的句柄 */ 17 | uint32_t get_dp_fs_handler(size_t idx); 18 | 19 | /* 由名字取得分区句柄,失败时返回DPT_UNIT_COUNT */ 20 | filesys_dp_handle get_dp_handle_by_name(const char *name); 21 | 22 | /* 将分区表写回到磁盘 */ 23 | void restore_dpt(); 24 | 25 | /* 销毁分区模块内容,顺带会销毁文件系统句柄 */ 26 | void destroy_dpt(); 27 | 28 | filesys_dp_handle syscall_get_dp_handle_impl(const char *name); 29 | 30 | #endif /* TINY_OS_DISK_PARTITION_TABLE_H */ 31 | -------------------------------------------------------------------------------- /src/shared/freelist.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define FL ((struct freelist_node*)handle) 5 | 6 | struct freelist_node 7 | { 8 | struct freelist_node *next; 9 | }; 10 | 11 | void init_freelist(freelist_handle *handle) 12 | { 13 | FL->next = NULL; 14 | } 15 | 16 | void add_freelist(freelist_handle *handle, void *mem_zone) 17 | { 18 | struct freelist_node *node = (struct freelist_node*)mem_zone; 19 | node->next = FL->next; 20 | FL->next = node; 21 | } 22 | 23 | bool is_freelist_empty(freelist_handle *handle) 24 | { 25 | return FL->next == NULL; 26 | } 27 | 28 | void *fetch_freelist(freelist_handle *handle) 29 | { 30 | if(is_freelist_empty(handle)) 31 | return NULL; 32 | void *rt = FL->next; 33 | FL->next = FL->next->next; 34 | return rt; 35 | } 36 | -------------------------------------------------------------------------------- /src/kernel/console/con_buf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | STATIC_ASSERT(sizeof(struct con_buf) < 4096, invalid_size_of_con_buf); 10 | 11 | struct con_buf *kalloc_con_buf() 12 | { 13 | struct con_buf *ret = (struct con_buf*)alloc_ker_page(false); 14 | memset(ret->data, 0x0, CON_BUF_BYTE_SIZE); 15 | ret->cursor = 0; 16 | init_semaphore(&ret->lock, 1); 17 | for(uint32_t i = 0; i < CON_BUF_CHAR_COUNT; ++i) 18 | { 19 | ret->data[i * 2] = ' '; 20 | ret->data[i * 2 + 1] = CH_GRAY | BG_BLACK; 21 | } 22 | return ret; 23 | } 24 | 25 | void free_con_buf(struct con_buf *buf) 26 | { 27 | free_ker_page(buf); 28 | } 29 | -------------------------------------------------------------------------------- /src/shared/sys/sysmsg.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | bool has_sysmsg() 6 | { 7 | return syscall_param1(SYSCALL_SYSMSG_OPERATION, 8 | SYSMSG_SYSCALL_FUNCTION_IS_EMPTY) 9 | == false; 10 | } 11 | 12 | bool peek_sysmsg(uint32_t opr, struct sysmsg *msg) 13 | { 14 | return syscall_param3(SYSCALL_SYSMSG_OPERATION, 15 | SYSMSG_SYSCALL_FUNCTION_PEEK_MSG, opr, msg) 16 | != false; 17 | } 18 | 19 | void wait_for_sysmsg() 20 | { 21 | syscall_param1(SYSCALL_SYSMSG_OPERATION, 22 | SYSMSG_SYSCALL_FUNCTION_BLOCK_ONTO_SYSMSG); 23 | } 24 | 25 | void clr_sysmsgs() 26 | { 27 | struct sysmsg msg; 28 | while(peek_sysmsg(SYSMSG_SYSCALL_PEEK_OPERATION_REMOVE, &msg)) 29 | ; 30 | } 31 | -------------------------------------------------------------------------------- /src/include/kernel/explorer/explorer.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_EXPLORER_EXPLORER_H 2 | #define TINY_OS_EXPLORER_EXPLORER_H 3 | 4 | #include 5 | 6 | struct PCB; 7 | 8 | /* Explorer入口,用于创建explorer线程 */ 9 | void explorer(); 10 | 11 | /* 当一个前台进程被kill时,需要通过该函数来通知explorer */ 12 | void foreground_exit(struct PCB *pcb); 13 | 14 | /* 系统调用实现:申请成为前台进程 */ 15 | uint32_t syscall_alloc_fg_impl(); 16 | 17 | /* 系统调用实现:若自己处于前台,把自己切下去 */ 18 | uint32_t syscall_free_fg_impl(); 19 | 20 | /* 系统调用实现:申请屏幕显示缓存 */ 21 | uint32_t syscall_alloc_con_buf_impl(); 22 | 23 | /* 系统调用实现:在disp区域输出一个字符 */ 24 | uint32_t syscall_put_char_expl_impl(uint32_t arg); 25 | 26 | /* 系统调用实现:让disp区域开个新行 */ 27 | uint32_t syscall_expl_new_line_impl(); 28 | 29 | /* 系统调用进程:给管道的接收进程发个空字符 */ 30 | uint32_t syscall_expl_pipe_null_char(); 31 | 32 | #endif /* TINY_OS_EXPLORER_EXPLORER_H */ 33 | -------------------------------------------------------------------------------- /src/applications/ed/rf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "rf.h" 5 | 6 | #define BUF_SIZE 128 7 | 8 | static usr_file_handle fp; 9 | static uint32_t fpos, fsize; 10 | 11 | static char buf[BUF_SIZE]; 12 | static uint32_t buf_idx; 13 | 14 | void rf_init(usr_file_handle file) 15 | { 16 | fp = file; 17 | fpos = 0; 18 | fsize = get_file_size(file); 19 | 20 | buf_idx = BUF_SIZE; 21 | } 22 | 23 | char rf_provider() 24 | { 25 | if(buf_idx >= BUF_SIZE) 26 | { 27 | if(fpos >= fsize) 28 | return '\0'; 29 | 30 | uint32_t delta = MIN(BUF_SIZE, fsize - fpos); 31 | uint32_t offset = BUF_SIZE - delta; 32 | read_file(fp, fpos, delta, buf + offset); 33 | fpos += delta; 34 | buf_idx = offset; 35 | } 36 | 37 | return buf[buf_idx++]; 38 | } 39 | -------------------------------------------------------------------------------- /make/tool: -------------------------------------------------------------------------------- 1 | # 1: 伪目标名字 2: 生成目标路径变量 2 | define make_tool 3 | 4 | $(2) = ./build/$(1) 5 | 6 | .PHONY : $(1) 7 | $(1) : $$($(2)) 8 | 9 | $(2)$(CPP_SUFFIX) = $$(shell find ./src/tools/$(1)/ -name "*.cpp") 10 | $(2)$(O_SUFFIX) = $$(patsubst %.cpp, %.o, $$($(2)$(CPP_SUFFIX))) 11 | $(2)$(D_SUFFIX) = $$(patsubst %.cpp, %.d, $$($(2)$(CPP_SUFFIX))) 12 | 13 | $$($(2)) : $$($(2)$(O_SUFFIX)) 14 | $$(CPPC) $$^ -o $$@ 15 | 16 | $$($(2)$(O_SUFFIX)) : %.o : %.cpp 17 | $$(CPPC) $$(CPPC_FLAGS) -c $$< -o $$@ 18 | 19 | $$($(2)$(D_SUFFIX)) : %.d : %.cpp 20 | @set -e; \ 21 | rm -f $$@; \ 22 | $$(CPPC) -MM $$(CPPC_FLAGS) $$< $$(CPPC_INCLUDE_FLAGS) > $$@.$$$$$$$$.dtmp; \ 23 | sed 's,\(.*\)\.o\:,$$*\.o $$*\.d\:,g' < $$@.$$$$$$$$.dtmp > $$@; \ 24 | rm -f $$@.$$$$$$$$.dtmp 25 | 26 | -include $$($(2)$(D_SUFFIX)) 27 | 28 | TOOLS += $$($(2)) 29 | 30 | TOOLS_TGTS += $(1) 31 | 32 | endef 33 | -------------------------------------------------------------------------------- /src/include/kernel/boot.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_BOOT_H 2 | #define TINY_OS_BOOT_H 3 | 4 | /* 总内存容量由bootloader读取,被放在这 */ 5 | #define TOTAL_MEMORY_SIZE_ADDR 0x500 6 | 7 | /* 内核栈末尾(物理) */ 8 | #define KER_STACK_PHY_END 0x200000 9 | 10 | /* 内核栈的起始值(虚拟) */ 11 | #define KER_STACK_INIT_VAL 0xc01ff000 12 | 13 | /* 内核页目录开头(物理) */ 14 | #define KER_PDE_PHY_ADDR 0x200000 15 | 16 | /* 内核地址空间起点 */ 17 | #define KER_ADDR_BEGIN 0xc0000000 18 | 19 | /* 内核页目录地址(虚拟) */ 20 | #define KER_PDE_VIR_ADDR (0xc0000000 + KER_PDE_PHY_ADDR) 21 | 22 | /* 静态内核存储区开头 */ 23 | #define STATIC_KERNEL_MEM_START 0xc0300000 24 | 25 | /* 26 | 静态内核存储区大小 27 | 应是0x1000的整数倍 28 | */ 29 | #define STATIC_KERNEL_MEM_SIZE 0x200000 30 | 31 | /* bootloader在虚拟内存中的位置 */ 32 | #define BOOTLOADER_START_ADDR 0xc0000900 33 | 34 | /* 全局描述符表在虚存中的位置 */ 35 | #define GDT_START (BOOTLOADER_START_ADDR + 3) 36 | 37 | #endif /* TINY_OS_BOOT_H */ 38 | -------------------------------------------------------------------------------- /make/application: -------------------------------------------------------------------------------- 1 | # 1: 伪目标名字 2: 生成目标路径变量 2 | define make_app 3 | 4 | $(2) = ./build/$(1) 5 | 6 | .PHONY : $(1) 7 | $(1) : $$($(2)) 8 | 9 | $(2)$(C_SUFFIX) = $$(shell find ./src/applications/$(1)/ -name "*.c") 10 | $(2)$(O_SUFFIX) = $$(patsubst %.c, %.o, $$($(2)$(C_SUFFIX))) 11 | $(2)$(D_SUFFIX) = $$(patsubst %.c, %.d, $$($(2)$(C_SUFFIX))) 12 | 13 | $$($(2)) : $$($(2)$(O_SUFFIX)) $$(LIB_O_FILES) $$(SHARED_O_FILES) 14 | $$(LD) $$(LD_FLAGS) $$^ -o $$@ 15 | 16 | $$($(2)$(O_SUFFIX)) : %.o : %.c 17 | $$(CC) $$(CC_FLAGS) -c $$< -o $$@ 18 | 19 | $$($(2)$(D_SUFFIX)) : %.d : %.c 20 | @set -e; \ 21 | rm -f $$@; \ 22 | $$(CC) -MM $$(CC_FLAGS) $$< $$(CC_INCLUDE_FLAGS) > $$@.$$$$$$$$.dtmp; \ 23 | sed 's,\(.*\)\.o\:,$$*\.o $$*\.d\:,g' < $$@.$$$$$$$$.dtmp > $$@; \ 24 | rm -f $$@.$$$$$$$$.dtmp 25 | 26 | -include $$($(2)$(D_SUFFIX)) 27 | 28 | APPS += $$($(2)) 29 | 30 | APPS_TGTS += $(1) 31 | 32 | endef 33 | -------------------------------------------------------------------------------- /src/tools/bin_trans/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | int main(int argc, char *argv[]) 10 | { 11 | if(argc != 2) 12 | { 13 | cout << "Usage: bin_trans binary_file_name" << endl; 14 | return -1; 15 | } 16 | 17 | ifstream fin(argv[1], ifstream::in | ifstream::binary); 18 | if(!fin) 19 | { 20 | cout << "Failed to open file: " << argv[1] << endl; 21 | return -1; 22 | } 23 | 24 | string content = string(istreambuf_iterator(fin), 25 | istreambuf_iterator()); 26 | int count = 0; 27 | for(char c : content) 28 | { 29 | cout << (int)c << ", "; 30 | if(count++ % 20 == 0) 31 | cout << endl; 32 | } 33 | cout << "\b\b"; 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /src/include/kernel/syscall.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_SYSCALL_H 2 | #define TINY_OS_SYSCALL_H 3 | 4 | #include 5 | 6 | /* 7 | 系统调用设计: 8 | 仿照linux,以0x80号中断作为系统调用入口 9 | 以寄存器传参: 10 | eax为系统调用编号 11 | ebx为第一个实参 12 | ecx为第二个实参 13 | edx为第三个实参 14 | 15 | 以下是3个参数的系统调用的参考实现 16 | 对用户进程而言,相关代码当然应该在用户代码段中了,所以在这里没有定义成函数 17 | 18 | // 不妨设系统调用号为N 19 | uint32_t syscall_with_3_params_in_user_program(uint32_t arg1, uint32_t arg2, uint32_t arg3) 20 | { 21 | uint32_t rt; 22 | asm volatile ("int $0x80;" 23 | : "=a" (rt) 24 | : "a" (N), "b" (arg1), "c" (arg2), "d" (arg3) 25 | : "memory"); 26 | return rt; 27 | } 28 | 29 | !!!注意,内联汇编int的时候,一定要用一个变量接受eax的返回值 30 | */ 31 | 32 | /* 系统调用初始化,至少在中断初始化后调用 */ 33 | void init_syscall(); 34 | 35 | #endif /* TINY_OS_SYSCALL_H */ 36 | -------------------------------------------------------------------------------- /src/include/lib/fstm.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_LIB_FSTM_H 2 | #define TINY_OS_LIB_FSTM_H 3 | 4 | #include 5 | 6 | #define FSTM_BUF_SIZE_DEFAULT 128 7 | 8 | typedef struct 9 | { 10 | // 文件指针 11 | usr_file_handle fp; 12 | // 文件中的下一个读取位置 13 | uint32_t fpos; 14 | // 文件大小 15 | uint32_t fsize; 16 | // 缓冲区大小 17 | size_t bsize; 18 | // 缓冲区内的下一个读取位置 19 | size_t bidx; 20 | // 缓冲区内的有效数据区大小 21 | size_t dsize; 22 | // 缓冲区入口,gcc扩展 23 | uint8_t buf[0]; 24 | } ifstm_t; 25 | 26 | #define FSTM_EOF ((char)0xff) 27 | 28 | /* 创建一个输入文件流 */ 29 | ifstm_t *ifstm_init(filesys_dp_handle dp, const char *path, 30 | size_t buf_size); 31 | 32 | /* 读输入文件流中的下一个字符 */ 33 | char ifstm_next(ifstm_t *fstm); 34 | 35 | /* 销毁一个输入文件流 */ 36 | void ifstm_free(ifstm_t *fstm); 37 | 38 | /* 输入文件流中还有多少字符 */ 39 | size_t ifstm_remain_size(ifstm_t *fstm); 40 | 41 | #endif /* TINY_OS_LIB_FSTM_H */ 42 | -------------------------------------------------------------------------------- /src/include/kernel/memory/vir_page_man.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_VIR_PAGE_MAN_H 2 | #define TINY_OS_VIR_PAGE_MAN_H 3 | 4 | #include 5 | 6 | /* 页级虚拟地址空间管理 */ 7 | struct vir_page_man; 8 | 9 | /* 虚拟页管理器为4字节对齐 */ 10 | #define VIRTUAL_PAGE_MANAGER_ALIGN 4 11 | 12 | /* 13 | 计算一个虚拟页管理器占多少个字节,以方便空间申请 14 | 管辖的范围是[begin, end) 15 | */ 16 | size_t get_vir_page_man_byte_size(size_t pool_begin, size_t pool_end); 17 | 18 | /* 初始化一个虚拟页管理器,要求page_man空间已分配 */ 19 | void init_vir_page_man(struct vir_page_man *page_man, 20 | size_t pool_begin, size_t pool_end); 21 | 22 | /* 23 | 在虚拟地址空间管理器中分配一个页 24 | 返回页的首字节地址 25 | 虚拟地址空间不足时返回0 26 | */ 27 | uint32_t alloc_page_in_vir_addr_space(struct vir_page_man *page_man); 28 | 29 | /* 30 | 在虚拟地址空间中释放一个页 31 | 若addr并非page_man中的已分配页,将导致未定义行为 32 | */ 33 | void free_page_in_vir_addr_space(struct vir_page_man *page_man, uint32_t addr); 34 | 35 | #endif /* TINY_OS_VIR_PAGE_MAN_H */ 36 | -------------------------------------------------------------------------------- /src/include/shared/stdint.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_SHARD_STDINT_H 2 | #define TINY_OS_SHARD_STDINT_H 3 | 4 | #ifndef TINY_OS_NO_INTDEF 5 | 6 | typedef signed char int8_t; 7 | typedef signed short int16_t; 8 | typedef signed int int32_t; 9 | typedef signed long long int64_t; 10 | 11 | typedef unsigned char uint8_t; 12 | typedef unsigned short uint16_t; 13 | typedef unsigned int uint32_t; 14 | typedef unsigned long long uint64_t; 15 | 16 | typedef uint32_t size_t; 17 | typedef int32_t ptrdiff_t; 18 | 19 | #define LLONG_MAX 0x7fffffffffffffffLL 20 | #define LLONG_MIN 0x8000000000000000LL 21 | 22 | #define INT_MAX 0x7fffffff 23 | #define INT_MIN 0x80000000 24 | 25 | #define SHRT_MAX 0x7fff 26 | 27 | #define UINT_MAX 0xffffffff 28 | 29 | #define UCHAR_MAX 0x255 30 | 31 | #define CHAR_BIT 8 32 | 33 | #endif /* no TINY_OS_NO_INTDEF */ 34 | 35 | #ifndef NULL 36 | #define NULL ((void*)0) 37 | #endif 38 | 39 | #endif /* TINY_OS_SHARD_STDINT_H */ 40 | -------------------------------------------------------------------------------- /src/include/lib/splock.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_LIB_SPLOCK_H 2 | #define TINY_OS_LIB_SPLOCK_H 3 | 4 | #include 5 | #include 6 | 7 | typedef uint32_t splock_t; 8 | 9 | static inline void sp_init(splock_t *lock) 10 | { 11 | *lock = 0; 12 | } 13 | 14 | bool sp_trylock(splock_t *lock) 15 | { 16 | uint32_t x = 1; 17 | asm volatile ("xchgl %0, %1" 18 | : "=r" (x) 19 | : "m" (*lock), "0" (x) 20 | : "memory"); 21 | return !x; 22 | } 23 | 24 | void sp_lock(splock_t *lock) 25 | { 26 | extern void yield_cpu(); 27 | while(({ 28 | uint32_t x = 1; 29 | asm volatile ("xchgl %0, %1" 30 | : "=r" (x) 31 | : "m" (*lock), "0" (x) 32 | : "memory"); 33 | x; 34 | })) 35 | yield_cpu(); 36 | } 37 | 38 | void sp_unlock(splock_t *lock) 39 | { 40 | asm volatile("" : : : "memory"); 41 | *lock = 0; 42 | } 43 | 44 | #endif /* TINY_OS_LIB_SPLOCK_H */ 45 | -------------------------------------------------------------------------------- /src/include/shared/asm.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_SHARED_ASM_H 2 | #define TINY_OS_SHARED_ASM_H 3 | 4 | #include 5 | 6 | /* 7 | 返回从低往高第一个不为0的位的位置 8 | bits不得为0 9 | */ 10 | static inline uint32_t find_lowest_nonzero_bit(uint32_t bits) 11 | { 12 | uint32_t rt; 13 | asm volatile ("bsf %1, %%eax; movl %%eax, %0" : "=r" (rt) : "r" (bits) : "%eax"); 14 | return rt; 15 | } 16 | 17 | /* 18 | 返回从低往高最后一个不为0的位的位置 19 | bits不得为0 20 | */ 21 | static inline uint32_t find_highest_nonzero_bit(uint32_t bits) 22 | { 23 | uint32_t rt; 24 | asm volatile ("bsr %1, %%eax; movl %%eax, %0" : "=r" (rt) : "r" (bits) : "%eax"); 25 | return rt; 26 | } 27 | 28 | /* 原子地将p设置为x并返回x的值 */ 29 | static inline uint32_t xchg_u32(volatile uint32_t *p, uint32_t x) 30 | { 31 | asm volatile("xchgl %0, %1" 32 | : "=r" (x) 33 | : "m" (*p), "0" (x) 34 | : "memory"); 35 | return x; 36 | } 37 | 38 | #endif /* TINY_OS_SHARED_ASM_H */ 39 | -------------------------------------------------------------------------------- /src/include/kernel/filesys/afs/file_opr.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_FILESYS_AFS_FILE_OPR_H 2 | #define TINY_OS_FILESYS_AFS_FILE_OPR_H 3 | 4 | enum afs_file_operation_status 5 | { 6 | afs_file_opr_success, // 操作正常完成 7 | afs_file_opr_writing_lock, // 试图打开一个有写入锁的文件 8 | afs_file_opr_reading_lock, // 试图以读写模式打开一个有读取锁的文件 9 | afs_file_opr_not_opening, // 要关闭的文件并不在已打开文件列表中 10 | afs_file_opr_limit_exceeded, // 文件读写范围超出文件大小 11 | afs_file_opr_no_empty_entry, // 创建文件失败:没有空闲的entry 12 | afs_file_opr_no_empty_block, // 创建/扩充文件失败:没有空闲的block 13 | afs_file_opr_read_only, // 试图写入一个只读文件 14 | afs_file_opr_invalid_new_size, // 扩充文件时,新的大小不是合法值 15 | afs_file_opr_not_found, // 文件不存在 16 | afs_file_opr_rm_nonempty, // 试图删除一个非空文件夹 17 | afs_file_opr_file_existed, // 试图创建一个与其他某个文件同名的文件 18 | afs_file_opr_rm_locked, // 试图删除一个有人在用的文件 19 | afs_file_opr_rm_wrong_type, // 删除文件时指定的类型不匹配 20 | }; 21 | 22 | #endif /* TINY_OS_FILESYS_AFS_FILE_OPR_H */ 23 | -------------------------------------------------------------------------------- /src/kernel/assert.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | void _fatal_error_impl(const char *prefix, const char *filename, const char *function, int line, const char *msg) 11 | { 12 | _disable_intr(); 13 | 14 | struct con_buf *buf = get_sys_con_buf(); 15 | 16 | kput_char(buf, '\n'); 17 | kput_str(buf, prefix); 18 | kput_str(buf, filename); 19 | kput_str(buf, ", "); 20 | kput_str(buf, function); 21 | kput_str(buf, ", line "); 22 | 23 | char int_str_buf[40]; 24 | uint32_to_str(line, int_str_buf); 25 | kput_str(buf, int_str_buf); 26 | 27 | uint32_to_str(get_cur_PCB()->pid, int_str_buf); 28 | kput_str(buf, " from proc "); 29 | kput_str(buf, int_str_buf); 30 | 31 | kput_str(buf, ": "); 32 | kput_str(buf, msg); 33 | 34 | while(true) 35 | ; 36 | } 37 | -------------------------------------------------------------------------------- /src/include/kernel/memory/phy_mem_man.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_PHY_MEM_MAN_H 2 | #define TINY_OS_PHY_MEM_MAN_H 3 | 4 | /* 页级存储管理 */ 5 | 6 | #include 7 | #include 8 | 9 | /* 内核虚拟地址分配(base = 0xc0000000): 10 | 1M~2M:内核栈 11 | 跟着是页目录和初始页表,正好占1M 12 | 然后跟着就是内核固有的内存区域,一直到3M + 内核固有区域 13 | 前4M是映射到物理地址的0-4M的 14 | 15 | 再之后就是内核虚拟页管理器在管了,以页为单位分配 16 | 换句话说,内核层面没有malloc和free,只有alloc_page和free_page…… 17 | */ 18 | 19 | size_t get_mem_total_bytes(); 20 | 21 | /* 分配一块固定大小的、在整个系统运行期间常驻的内核内存区域 */ 22 | void *alloc_static_kernel_mem(size_t bytes, size_t align_bytes); 23 | 24 | /* 初始化整个页内存管理器 */ 25 | void init_phy_mem_man(); 26 | 27 | /* 28 | 分配一个物理页,返回值为物理地址 29 | resident为false表示非常驻,反之表示常驻内存(不会被换出) 30 | */ 31 | uint32_t alloc_phy_page(bool resident); 32 | 33 | /* 34 | 释放一个物理页 35 | 若页面不在物理页管理器管理范围内,或本来就没被占用,则返回false 36 | */ 37 | void free_phy_page(uint32_t page_phy_addr); 38 | 39 | /* 还剩多少个物理页空闲 */ 40 | uint32_t get_free_phy_page_count(); 41 | 42 | #endif /* TINY_OS_PHY_MEM_MAN_H */ 43 | -------------------------------------------------------------------------------- /src/include/shared/ctype.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_SHARD_CTYPE_H 2 | #define TINY_OS_SHARD_CTYPE_H 3 | 4 | #include 5 | 6 | static inline bool isprint(char ch) 7 | { 8 | return 32 <= ch && ch <= 126; 9 | } 10 | 11 | static inline bool isalpha(char ch) 12 | { 13 | return ('a' <= ch && ch <= 'z') || 14 | ('A' <= ch && ch <= 'Z'); 15 | } 16 | 17 | static inline bool isdigit(char ch) 18 | { 19 | return '0' <= ch && ch <= '9'; 20 | } 21 | 22 | static inline bool isalnum(char ch) 23 | { 24 | return isalpha(ch) || isdigit(ch); 25 | } 26 | 27 | static inline bool isspace(char ch) 28 | { 29 | // 暂时只管这三个…… 30 | return ch == ' ' || ch == '\n' || ch == '\t'; 31 | } 32 | 33 | static inline char to_upper(char ch) 34 | { 35 | if('a' <= ch && ch <= 'z') 36 | return ch - 'a' + 'A'; 37 | return ch; 38 | } 39 | 40 | static inline char to_lower(char ch) 41 | { 42 | if('A' <= ch && ch <= 'Z') 43 | return ch - 'A' + 'a'; 44 | return ch; 45 | } 46 | 47 | #endif /* TINY_OS_SHARD_CTYPE_H */ 48 | -------------------------------------------------------------------------------- /src/include/shared/string.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYOS_SHARD_STRING_H 2 | #define TINYOS_SHARD_STRING_H 3 | 4 | #include 5 | #include 6 | 7 | size_t strlen(const char *str); 8 | 9 | void strcpy(char *dst, const char *src); 10 | 11 | void strcpy_s(char *dst, const char *src, size_t buf_size); 12 | 13 | int strcmp(const char *lhs, const char *rhs); 14 | 15 | int strcoll(const char *L, const char *R); 16 | 17 | void strcat(char *fst, const char *snd); 18 | 19 | #define STRING_NPOS ((uint32_t)0xffffffff) 20 | 21 | uint32_t strfind(const char *str, char c, uint32_t beg); 22 | 23 | const char *strchr(const char *str, int ch); 24 | 25 | void uint32_to_str(uint32_t intval, char *buf); 26 | 27 | bool str_to_uint32(const char *str, uint32_t *val); 28 | 29 | void memset(void *dst, uint8_t val, size_t byte_size); 30 | 31 | void memcpy(void *dst, const void *src, size_t byte_size); 32 | 33 | int memcmp(const void *L, const void *R, size_t byte_size); 34 | 35 | uint32_t strhash(const char *str); 36 | 37 | #endif /* TINYOS_SHARD_STRING_H */ 38 | -------------------------------------------------------------------------------- /src/include/kernel/explorer/_design.txt: -------------------------------------------------------------------------------- 1 | ================================================================================================ 2 | 3 | explorer是最基本的用户界面,大致相当于linux中的shell,用户通过explorer可以访问目录、启动程序和查看进程等 4 | 5 | 进程有两种输入输出模式,一种是接管所有输入输出,一种是托管给explorer。 6 | 7 | 当进程接管所有输入输出时 8 | 若进程处于前台,则: 9 | 默认输出到屏幕上 10 | 可以接收键盘消息 11 | 若进程处于后台,则: 12 | 原本到屏幕的输出都被转到一块显示缓存上 13 | 键盘消息被屏蔽 14 | 当进程将输入输出托管给explorer时 15 | 若进程处于前台,则: 16 | 可以通过系统调用从explorer命令行接受输入,并不能接收键盘消息 17 | 若进程处于后台,则: 18 | 可以输出到explorer上,但不能获取输入 19 | 20 | 任何进程,不管处于前台还是后台,都随时可以在stdout上输出字符。一个进程的stdout默认会输出到explorer上, 21 | 也可以被重定向到别的进程的输入 22 | 23 | 默认情况下,进程的输入输出都是托管给explorer的,可以通过系统调用来接管自己的输入输出 24 | 25 | ================================================================================================ 26 | 27 | 实现上,给PCB添加一个foreground_flag作为是否处于前台的标志;添加一个显示缓存指针,该指针 28 | 为空时表明输入输出被托送给explorer,否则该进程接管所有输入输出 29 | 30 | 将一个接管了输入输出的进程进行前后台的切换时,要在它的显示缓存和实际显存间拷贝数据 31 | 32 | explorer自己也有显示缓存指针,或者说它就是一个接管了输入输出的进程,只不过是内核级的,权限很高罢了 33 | 另外,explorer总是要接收键盘消息,因为它即使处于后台也需要探测用户按下的C+Z之类的 34 | -------------------------------------------------------------------------------- /src/lib/input.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | static char input_buf[SYSMSG_PARAM_SIZE + 1]; 9 | 10 | static uint32_t input_buf_idx; 11 | 12 | void _init_input() 13 | { 14 | memset(input_buf, 0x0, SYSMSG_PARAM_SIZE); 15 | input_buf_idx = 0; 16 | } 17 | 18 | char get_char() 19 | { 20 | if(input_buf[input_buf_idx]) 21 | return input_buf[input_buf_idx++]; 22 | 23 | while(true) 24 | { 25 | wait_for_sysmsg(); 26 | struct sysmsg msg; 27 | if(peek_sysmsg(SYSMSG_SYSCALL_PEEK_OPERATION_REMOVE, &msg)) 28 | { 29 | if(msg.type == SYSMSG_TYPE_EXPL_INPUT) 30 | { 31 | memcpy(input_buf, (char*)msg.params, SYSMSG_PARAM_SIZE); 32 | input_buf_idx = 0; 33 | break; 34 | } 35 | else if(msg.type == SYSMSG_TYPE_PIPE_NULL_CHAR) 36 | { 37 | return '\0'; 38 | } 39 | } 40 | } 41 | 42 | return input_buf[input_buf_idx++]; 43 | } 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 AirGuanZ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/applications/ls/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | expl_new_line(); 9 | 10 | // 解析自己现在所在分区和路径 11 | 12 | filesys_dp_handle dp = get_dp_handle_from_path( 13 | argv[0], malloc, free); 14 | if(dp >= DPT_UNIT_COUNT) 15 | { 16 | printf("Invalid dp name"); 17 | return -1; 18 | } 19 | const char *path = skip_dp_in_abs_path(argv[0]); 20 | 21 | uint32_t file_cnt; 22 | if(get_child_file_count(dp, path, &file_cnt) != filesys_opr_success) 23 | { 24 | printf("Failed to open directory: %s", argv[0]); 25 | return -1; 26 | } 27 | 28 | printf("File count: %u", file_cnt); 29 | 30 | for(uint32_t i = 0; i < file_cnt; ++i) 31 | { 32 | struct syscall_filesys_file_info info; 33 | if(get_child_file_info(dp, path, i, &info) != filesys_opr_success) 34 | { 35 | printf("\nFailed to fetch file into: %s, %u", argv[0], i); 36 | return -1; 37 | } 38 | printf("\n%s %s", (info.is_dir ? "d" : "r"), info.name); 39 | } 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /src/applications/help/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define DOC_DP 0 9 | #define DOC_PATH_PREFIX ("/docs/") 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | if(argc > 2) 14 | { 15 | printf("%LUsage: help\n"); 16 | printf(" help [command]"); 17 | return -1; 18 | } 19 | 20 | const char *arg = (argc == 2) ? argv[1] : "help"; 21 | size_t path_buf_size = strlen(DOC_PATH_PREFIX) + strlen(arg) + 1; 22 | char *path = malloc(path_buf_size); 23 | if(!path) 24 | { 25 | printf("%LMemory allocation failed..."); 26 | return -1; 27 | } 28 | strcpy(path, DOC_PATH_PREFIX); 29 | strcat(path, arg); 30 | 31 | ifstm_t *f = ifstm_init(DOC_DP, path, FSTM_BUF_SIZE_DEFAULT); 32 | if(!f) 33 | { 34 | printf("%LNo documentation for command '%s'", arg); 35 | return -1; 36 | } 37 | 38 | expl_new_line(); 39 | char ch; 40 | while((ch = ifstm_next(f)) != FSTM_EOF) 41 | put_char(ch); 42 | 43 | ifstm_free(f); 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /src/include/shared/utility.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_SHARD_UTILITY_H 2 | #define TINY_OS_SHARD_UTILITY_H 3 | 4 | #include 5 | 6 | /* static_assert一直到C11才有,这里通过数组大小非负来模拟之 */ 7 | #define STATIC_ASSERT(EXPR, MSG) \ 8 | typedef char static_assert_failed__##MSG[2 * !!(EXPR) - 1] 9 | 10 | #define MAX(a, b) ((a) > (b) ? (a) : (b)) 11 | 12 | #define MIN(a, b) ((a) < (b) ? (a) : (b)) 13 | 14 | /* 15 | 给定一个结构名和一个成员名,取得 -(成员在结构体内的偏移量) 16 | 在成员指针上加上这一偏移量,就能得到结构体指针 17 | */ 18 | #define MEM_TO_STRUCT_OFFSET(STRUCT, MEM) \ 19 | (-(int32_t)(&((STRUCT*)0->MEM))) 20 | 21 | /* 22 | 给定一个结构体名和其中的两个成员名,取得 成员2偏移量 - 成员1偏移量 23 | 在成员1指针上加上该偏移,就能得到成员2指针 24 | */ 25 | #define MEM_TO_MEM_OFFSET(STRUCT, MEM1, MEM2) \ 26 | ((int32_t)(&(((STRUCT*)0)->MEM2)) - \ 27 | (int32_t)(&(((STRUCT*)0)->MEM1))) 28 | 29 | /* 跟据成员地址取得包含它的结构体地址 */ 30 | #define GET_STRUCT_FROM_MEMBER(STU, MEM, p_mem) \ 31 | ((STU*)((char*)(p_mem) - (char*)(&((STU*)0)->MEM))) 32 | 33 | #define offsetof(S, M) ((size_t)&(((S*)0)->M)) 34 | 35 | #define ARRAY_SIZE(A) (sizeof(A) / sizeof(A[0])) 36 | 37 | static inline uint32_t ceil_int_div(uint32_t a, uint32_t b) 38 | { 39 | return (a / b) + ((a % b) ? 1u : 0u); 40 | } 41 | 42 | #endif /* TINY_OS_SHARD_UTILITY_H */ 43 | -------------------------------------------------------------------------------- /src/applications/ed/ed.h: -------------------------------------------------------------------------------- 1 | #ifndef ED_ED_H 2 | #define ED_ED_H 3 | 4 | #include 5 | 6 | /* editor状态 */ 7 | typedef struct 8 | { 9 | filesys_dp_handle dp; // 正在编辑的文件所处分区 10 | char *file; // 正在编辑的文件路径 11 | 12 | bool dirty; // 是否有未保存的内容 13 | 14 | int scr_top_lineno; // 位于屏幕顶端位置是哪个显示行 15 | int cur_x, cur_y; // 在屏幕上的x、y坐标 16 | 17 | int cur_exp_x; // 光标的期望x位置 18 | // 纵向转移时保持不变 19 | // 横向转移和输入字符时和实际位置同步 20 | 21 | char *text; // 没错就是这么暴力( 22 | int text_buf_size; // 缓冲区大小 23 | int gap_beg, gap_end; // gap区间[beg, end) 24 | 25 | char *bg_buf; // 后台显示缓冲 26 | } ed_t; 27 | 28 | /* 字符流接口 */ 29 | typedef char (*ED_TEXT_PROVIDER)(); 30 | 31 | /* 默认字符流:总是返回空字符 */ 32 | char default_ed_text_provider_null(); 33 | 34 | /* 从一个字符流创建一个editor */ 35 | ed_t *new_ed(filesys_dp_handle dp, const char *filename, 36 | ED_TEXT_PROVIDER text_provider); 37 | 38 | /* 销毁一个编辑器 */ 39 | void free_ed(ed_t *ed); 40 | 41 | /* editor主循环 */ 42 | void ed_mainloop(ed_t *ed); 43 | 44 | #endif /* ED_ED_H */ 45 | -------------------------------------------------------------------------------- /src/include/kernel/assert.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_FATAL_ERROR_H 2 | #define TINY_OS_FATAL_ERROR_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | #define FATAL_ERROR(MSG) _fatal_error_impl("Fatal error in ", \ 9 | __FILE__, __FUNCTION__, \ 10 | __LINE__, MSG) 11 | 12 | #ifdef NO_ASSERT 13 | #define ASSERT_M(EXPR, MSG) ((void)0) 14 | #define ASSERT(EXPR) ((void)0) 15 | #else 16 | #define ASSERT_M(EXPR, MSG) \ 17 | do { \ 18 | if(!(EXPR)) \ 19 | _fatal_error_impl("Assert failed in ", \ 20 | __FILE__, __FUNCTION__, \ 21 | __LINE__, MSG); \ 22 | } while(0) 23 | 24 | #define ASSERT(EXPR) \ 25 | do { \ 26 | if(!(EXPR)) \ 27 | _fatal_error_impl("Assert failed in ", \ 28 | __FILE__, __FUNCTION__, \ 29 | __LINE__, "\b\b"); \ 30 | } while(0) 31 | #endif 32 | 33 | void _fatal_error_impl(const char *prefix, const char *filename, 34 | const char *function, int line, const char *msg); 35 | 36 | #endif /* TINY_OS_FATAL_ERROR_H */ 37 | -------------------------------------------------------------------------------- /src/kernel/rlist_node_alloc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | /* 记录空闲rlist node的自由链表 */ 8 | static freelist_handle unused_resident_rlist_nodes; 9 | 10 | void init_kernel_rlist_node_alloc() 11 | { 12 | init_freelist(&unused_resident_rlist_nodes); 13 | } 14 | 15 | /* 16 | 这个函数可能被多个进程并行调用,而那些进程很可能是不关中断的 17 | 所以这里的alloc和free都要关中断操作 18 | */ 19 | struct rlist_node *kernel_resident_rlist_node_alloc() 20 | { 21 | intr_state is = fetch_and_disable_intr(); 22 | 23 | if(is_freelist_empty(&unused_resident_rlist_nodes)) 24 | { 25 | struct rlist_node *new_nodes = (struct rlist_node*)alloc_ker_page(true); 26 | size_t end = 4096 / sizeof(struct rlist_node); 27 | for(size_t i = 0;i != end; ++i) 28 | add_freelist(&unused_resident_rlist_nodes, &new_nodes[i]); 29 | } 30 | 31 | struct rlist_node *ret = (struct rlist_node*)fetch_freelist(&unused_resident_rlist_nodes); 32 | set_intr_state(is); 33 | return ret; 34 | } 35 | 36 | void kernel_resident_rlist_node_dealloc(struct rlist_node *node) 37 | { 38 | intr_state is = fetch_and_disable_intr(); 39 | add_freelist(&unused_resident_rlist_nodes, node); 40 | set_intr_state(is); 41 | } 42 | -------------------------------------------------------------------------------- /src/kernel/process/semaphore.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | /* 8 | 现在的信号量实现得很暴力:关中断…… 9 | 有闲心再改吧……先做个能跑起来的 10 | */ 11 | 12 | void init_semaphore(struct semaphore *s, int32_t init_val) 13 | { 14 | ASSERT(s && init_val > 0); 15 | s->val = init_val; 16 | init_rlist(&s->blocked_threads); 17 | } 18 | 19 | void semaphore_wait(struct semaphore *s) 20 | { 21 | intr_state intr_s = fetch_and_disable_intr(); 22 | 23 | if(--s->val < 0) 24 | { 25 | struct TCB *tcb = get_cur_TCB(); 26 | push_back_rlist(&s->blocked_threads, tcb, 27 | kernel_resident_rlist_node_alloc); 28 | tcb->blocked_sph = s; 29 | block_cur_thread(); 30 | } 31 | 32 | set_intr_state(intr_s); 33 | } 34 | 35 | void semaphore_signal(struct semaphore *s) 36 | { 37 | intr_state intr_s = fetch_and_disable_intr(); 38 | 39 | if(++s->val <= 0 && !is_rlist_empty(&s->blocked_threads)) 40 | { 41 | struct TCB *th = pop_front_rlist(&s->blocked_threads, 42 | kernel_resident_rlist_node_dealloc); 43 | th->blocked_sph = NULL; 44 | awake_thread(th); 45 | } 46 | 47 | set_intr_state(intr_s); 48 | } 49 | -------------------------------------------------------------------------------- /src/include/kernel/console/print.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_PRINT_H 2 | #define TINY_OS_PRINT_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | /* 9 | 设置光标位置 10 | assert(pos < 2000); 11 | */ 12 | void kset_cursor_pos(struct con_buf *buf, uint16_t pos); 13 | 14 | /* 15 | 设置光标位置 16 | assert(row < 25 && col < 80); 17 | */ 18 | void kset_cursor_row_col(struct con_buf *buf, uint8_t row, uint8_t col); 19 | 20 | /* 21 | 取得光标位置 22 | ret = 80 * row + col 23 | */ 24 | uint16_t kget_cursor_pos(struct con_buf *buf); 25 | 26 | /* 27 | 取得光标位置 28 | ret = (row << 8) | col 29 | */ 30 | uint16_t kget_cursor_row_col(struct con_buf *buf); 31 | 32 | /* 屏幕滚动一行 */ 33 | void kroll_screen(struct con_buf *buf); 34 | 35 | /* 指定的行范围 */ 36 | void kroll_screen_row_between(struct con_buf *buf, 37 | uint32_t beg, uint32_t end); 38 | 39 | /* 40 | 在光标位置处输出字符并自动调整光标 41 | 对特殊字符,仅支持换行(\n),退格(backspace),水平制表(\t) 42 | 光标超出屏幕范围时会自动滚屏 43 | */ 44 | void kput_char(struct con_buf *buf, char ch); 45 | 46 | char kget_char(struct con_buf *buf, uint16_t pos); 47 | 48 | void kput_str(struct con_buf *buf, const char *str); 49 | 50 | /* ch就得是普通字符,控制字符一律UB */ 51 | void kset_char(struct con_buf *buf, uint16_t pos, char ch); 52 | 53 | void kset_attrib(struct con_buf *buf, uint16_t pos, char attrib); 54 | 55 | #endif /* TINY_OS_PRINT_H */ 56 | -------------------------------------------------------------------------------- /src/include/shared/rbtree.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_SHARD_RBTREE_H 2 | #define TINY_OS_SHARD_RBTREE_H 3 | 4 | #include 5 | #include 6 | 7 | /* 8 | 侵入式红黑树节点 9 | 要求:任何节点地址都是2字节对齐的,否则UB,虽然这很难有机会违背…… 10 | */ 11 | struct rb_node 12 | { 13 | // parent的最低位记录颜色 14 | struct rb_node *parent; 15 | struct rb_node *left, *right; 16 | }; 17 | 18 | /* 红黑树句柄 */ 19 | struct rb_tree 20 | { 21 | struct rb_node *root; 22 | struct rb_node nil; 23 | }; 24 | 25 | void rb_init(struct rb_tree *tree); 26 | 27 | /* 用于比较红黑树中两个节点的键值大小 */ 28 | typedef bool (*rb_less_func)(const void *L, const void *R); 29 | 30 | /* 在红黑树中查找指定键值,找不到时返回NULL 31 | 对每个查询路径上的节点地址N,less被以下面的方式调用: 32 | less((char*)N + key_offset, key) 或 33 | less(key, (char*)N + key_offset) 34 | key_offset可以用下面定义的宏取得 35 | */ 36 | struct rb_node *rb_find(struct rb_tree *tree, int32_t key_offset, 37 | const void *key, rb_less_func less); 38 | 39 | /* 40 | 插入节点 41 | 若节点已经存在,返回false 42 | */ 43 | bool rb_insert(struct rb_tree *tree, struct rb_node *node, 44 | int32_t key_offset, rb_less_func less); 45 | 46 | void rb_erase(struct rb_tree *tree, struct rb_node *node, 47 | int32_t key_offset, rb_less_func less); 48 | 49 | struct rb_node *rb_minimum(struct rb_node *nil, struct rb_node *node); 50 | 51 | #endif /* TINY_OS_SHARD_RBTREE_H */ 52 | -------------------------------------------------------------------------------- /src/include/kernel/memory/vir_mem_man.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_VIR_MEM_MAN_H 2 | #define TINY_OS_VIR_MEM_MAN_H 3 | 4 | /* 虚拟地址空间的创建、启用和销毁 */ 5 | 6 | #include 7 | #include 8 | 9 | /* 最多支持多少个虚拟地址空间(除ker_addr_space) */ 10 | #define MAX_VIR_ADDR_SPACE_COUNT 64 11 | 12 | /* 初始化整个虚拟地址空间管理系统,在init_phy_mem_man()之后即可调用 */ 13 | void init_vir_mem_man(); 14 | 15 | /* 分配一个内核页(占用内核虚拟地址空间) */ 16 | void *alloc_ker_page(bool resident); 17 | 18 | /* 释放一个内核页 */ 19 | void free_ker_page(void *page); 20 | 21 | /* 22 | 虚拟地址空间句柄 23 | */ 24 | typedef struct _vir_addr_space vir_addr_space; 25 | 26 | /* 27 | 创建一个虚拟地址空间并返回其句柄 28 | 初始虚拟地址空间中有些部分是已经被用了的,使用情况如下: 29 | 高1GB - 4KB永远和内核共享 30 | 最高的页目录项指向页目录自身所在物理页(虽然按理说它应该指向一个页表) 31 | 32 | 创建的虚拟页目录本身所在的物理页是常驻内存的 33 | */ 34 | vir_addr_space *create_vir_addr_space(); 35 | 36 | /* 37 | 将某个虚拟地址空间设置为当前正使用 38 | 不合法参数将导致未定义行为 39 | */ 40 | void set_current_vir_addr_space(vir_addr_space *addr_space); 41 | 42 | /* 取得当前虚拟地址空间句柄 */ 43 | vir_addr_space *get_current_vir_addr_space(); 44 | 45 | /* 46 | 取得自bootloader开始内核所使用的虚拟地址空间句柄 47 | 虽然这玩意儿并没有什么卵用 48 | */ 49 | vir_addr_space *get_ker_vir_addr_space(); 50 | 51 | /* 52 | 销毁某个虚拟地址空间 53 | 其占用的所有物理页均将被释放 54 | */ 55 | void destroy_vir_addr_space(vir_addr_space *addr_space); 56 | 57 | /* 返回一个虚拟空间标号 */ 58 | size_t get_usr_vir_addr_idx(vir_addr_space *rec); 59 | 60 | #endif /* TINY_OS_VIR_MEM_MAN_H */ 61 | -------------------------------------------------------------------------------- /src/applications/mkdir/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | /* 8 | path应具有以下形式: 9 | (/blabla)+ 10 | 一段一段地处理 11 | */ 12 | void make_dir_chain(filesys_dp_handle dp, const char *path) 13 | { 14 | char *pp = malloc(strlen(path) + 1); 15 | size_t ip = 0; 16 | while(path[ip]) 17 | { 18 | pp[ip] = path[ip]; 19 | ++ip; 20 | while(path[ip] && path[ip] != '/') 21 | { 22 | pp[ip] = path[ip]; 23 | ++ip; 24 | } 25 | pp[ip] = '\0'; 26 | 27 | make_directory(dp, pp); 28 | } 29 | free(pp); 30 | } 31 | 32 | int main(int argc, char *argv[]) 33 | { 34 | if(argc < 2) 35 | { 36 | printf("%LUsage: mkdir dir1 [dir2] ..."); 37 | return -1; 38 | } 39 | 40 | for(int i = 1; i < argc; ++i) 41 | { 42 | filesys_dp_handle dp; 43 | char *path = malloc_and_cat_path(argv[0], argv[i], &dp); 44 | if(!path) 45 | { 46 | printf("%LInvalid directory name: %s", argv[i]); 47 | return -1; 48 | } 49 | 50 | compress_path(path); 51 | if(strlen(path) == 1) 52 | { 53 | printf("%LInvalid directory name: %s", argv[i]); 54 | return -1; 55 | } 56 | make_dir_chain(dp, path); 57 | 58 | free(path); 59 | } 60 | 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /src/kernel/kernel.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | void init_kernel() 16 | { 17 | /* 时钟中断频率 */ 18 | set_8253_freq(100); 19 | 20 | /* 中断系统 */ 21 | init_IDT(); 22 | 23 | /* 物理内存 */ 24 | init_phy_mem_man(); 25 | 26 | /* 虚拟内存 */ 27 | init_vir_mem_man(); 28 | 29 | /* 内核链表分配 */ 30 | init_kernel_rlist_node_alloc(); 31 | 32 | /* 内核线程 */ 33 | init_thread_man(); 34 | 35 | /* 进程管理 */ 36 | init_process_man(); 37 | 38 | /* 系统调用 */ 39 | init_syscall(); 40 | 41 | /* 控制台 */ 42 | init_console(); 43 | 44 | /* 内核消息传递 */ 45 | init_sysmsg(); 46 | 47 | /* 内核消息系统调用 */ 48 | init_sysmsg_syscall(); 49 | 50 | /* 键盘驱动 */ 51 | init_kb_driver(); 52 | 53 | /* 硬盘驱动 */ 54 | init_disk_driver(); 55 | 56 | /* 文件系统 */ 57 | init_filesys(); 58 | 59 | /* 磁盘分区 */ 60 | init_dpt(); 61 | 62 | _enable_intr(); 63 | } 64 | 65 | void destroy_kernel() 66 | { 67 | kill_all_processes(); 68 | destroy_dpt(); 69 | destroy_filesys(); 70 | } 71 | -------------------------------------------------------------------------------- /src/applications/cat/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char *argv[]) 9 | { 10 | // 接受来自stdin的输入 11 | if(argc < 2) 12 | { 13 | char ch; 14 | while((ch = get_char())) 15 | put_char(ch); 16 | return 0; 17 | } 18 | 19 | for(int i = 1; i < argc; ++i) 20 | { 21 | expl_new_line(); 22 | 23 | filesys_dp_handle dp; 24 | char *path = malloc_and_cat_path(argv[0], argv[i], &dp); 25 | if(!path) 26 | { 27 | printf("Invalid filename: %s", argv[i]); 28 | return -1; 29 | } 30 | 31 | usr_file_handle fp; 32 | if(open_file(dp, path, false, &fp) != filesys_opr_success) 33 | { 34 | printf("Failed to open file: %u:%s", dp, path); 35 | return -1; 36 | } 37 | 38 | uint32_t file_size = get_file_size(dp); 39 | char buf[128]; uint32_t fpos = 0; 40 | 41 | while(fpos < file_size) 42 | { 43 | uint32_t delta = MIN(128, file_size - fpos); 44 | read_file(fp, fpos, delta, buf); 45 | 46 | for(int i = 0; i < delta; ++i) 47 | put_char(buf[i]); 48 | 49 | fpos += delta; 50 | } 51 | 52 | close_file(fp); 53 | free(path); 54 | } 55 | 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /src/include/kernel/sysmsg/sysmsg.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_SYSMSG_H 2 | #define TINY_OS_SYSMSG_H 3 | 4 | #include 5 | #include 6 | 7 | /* 8 | 每个进程都有一个消息队列,位于内核地址空间中,大小非常有限 9 | 进程通过系统调用访问这个队列 10 | 11 | 发送方和接收方阻不阻塞在系统调用层面实现,不在消息队列本身层面实现 12 | */ 13 | 14 | /* 内核消息队列句柄,放到PCB中 */ 15 | struct sysmsg_queue 16 | { 17 | // 消息缓冲区,逻辑上为环形 18 | struct sysmsg *msgs; 19 | // 队列头部下标,msgs[head]为第一个有效消息 20 | size_t head; 21 | // 队列尾部下标,msgs[tail]为下一条来的消息的空位 22 | size_t tail; 23 | // 队列中的消息数量 24 | size_t size; 25 | }; 26 | 27 | /* 初始化内核进程消息管理系统 */ 28 | void init_sysmsg(); 29 | 30 | /* 31 | 初始化一个给定的内核消息队列 32 | 包括分配队列空间 33 | */ 34 | void init_sysmsg_queue(struct sysmsg_queue *queue); 35 | 36 | /* 干掉一个内核消息队列,一般在进程销毁的时候调用 */ 37 | void destroy_sysmsg_queue(struct sysmsg_queue *queue); 38 | 39 | /* 40 | 发送一条消息到某个队列,返回是否发送成功 41 | msg中的数据会被copy走 42 | */ 43 | bool send_sysmsg(struct sysmsg_queue *queue, const struct sysmsg *msg); 44 | 45 | /* 一个消息队列是否为空 */ 46 | bool is_sysmsg_queue_empty(const struct sysmsg_queue *queue); 47 | 48 | /* 一个消息队列是否已满 */ 49 | bool is_sysmsg_queue_full(const struct sysmsg_queue *queue); 50 | 51 | /* 52 | 取得消息队列第一条消息,并不弹出 53 | 若队列为空,返回NULL 54 | */ 55 | const struct sysmsg *fetch_sysmsg_queue_front(const struct sysmsg_queue *queue); 56 | 57 | /* 58 | 弹出队列第一条消息 59 | 若队列为空,返回false 60 | */ 61 | bool pop_sysmsg_queue_front(struct sysmsg_queue *queue, struct sysmsg *output); 62 | 63 | #endif /* TINY_OS_SYSMSG_H */ 64 | -------------------------------------------------------------------------------- /src/include/kernel/filesys/syscall.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_FILESYS_SYSCALL_H 2 | #define TINY_OS_FILESYS_SYSCALL_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | enum filesys_opr_result syscall_filesys_open_impl( 9 | struct syscall_filesys_open_params *params); 10 | 11 | enum filesys_opr_result syscall_filesys_close_impl( 12 | usr_file_handle file); 13 | 14 | enum filesys_opr_result syscall_filesys_mkfile_impl( 15 | filesys_dp_handle dp, const char *path); 16 | 17 | enum filesys_opr_result syscall_filesys_rmfile_impl( 18 | filesys_dp_handle dp, const char *path); 19 | 20 | enum filesys_opr_result syscall_filesys_mkdir_impl( 21 | filesys_dp_handle dp, const char *path); 22 | 23 | enum filesys_opr_result syscall_filesys_rmdir_impl( 24 | filesys_dp_handle dp, const char *path); 25 | 26 | uint32_t syscall_filesys_get_file_size_impl( 27 | usr_file_handle file); 28 | 29 | enum filesys_opr_result syscall_filesys_write_impl( 30 | struct syscall_filesys_write_params *params); 31 | 32 | enum filesys_opr_result syscall_filesys_read_impl( 33 | struct syscall_filesys_read_params *params); 34 | 35 | enum filesys_opr_result syscall_filesys_get_file_count( 36 | filesys_dp_handle dp, const char *path, 37 | uint32_t *rt); 38 | 39 | enum filesys_opr_result syscall_filesys_get_child_info( 40 | struct syscall_filesys_get_child_info_params *params); 41 | 42 | #endif /* TINY_OS_FILESYS_SYSCALL_H */ 43 | -------------------------------------------------------------------------------- /make/kernel: -------------------------------------------------------------------------------- 1 | # 写入磁盘映像的文件列表 2 | BOOTBIN_FILE = src/boot/mbr.bootbin \ 3 | src/boot/bootloader.bootbin \ 4 | src/boot/kernel.bootbin 5 | 6 | KER_C_FILES = $(shell find ./src/kernel/ -name "*.c") 7 | 8 | KER_O_FILES = $(patsubst %.c, %.o, $(KER_C_FILES)) 9 | KER_D_FILES = $(patsubst %.c, %.d, $(KER_C_FILES)) 10 | 11 | KER_S_FILES = $(shell find ./src/kernel/ -name "*.s") 12 | 13 | KER_BIN_FILES = $(patsubst %.s, %.bin, $(KER_S_FILES)) 14 | 15 | KER_ENTRY_ADDR = 0xc0002000 16 | 17 | $(HD) : $(BOOTBIN_FILE) 18 | dd if=src/boot/mbr.bootbin of=$(HD) bs=512 count=1 conv=notrunc 19 | dd if=src/boot/bootloader.bootbin of=$(HD) bs=512 count=4 seek=1 conv=notrunc 20 | dd if=src/boot/kernel.bootbin of=$(HD) bs=512 count=200 seek=9 conv=notrunc 21 | 22 | # MBR编译 23 | src/boot/mbr.bootbin : src/boot/mbr.s src/boot/boot.s 24 | $(ASM) $(ASM_FLAGS) $< -o $@ 25 | 26 | # bootloader 27 | src/boot/bootloader.bootbin : src/boot/bootloader.s src/boot/boot.s 28 | $(ASM) $(ASM_FLAGS) $< -o $@ 29 | 30 | src/boot/kernel.bootbin : $(KER_O_FILES) $(KER_BIN_FILES) $(SHARED_O_FILES) 31 | $(LD) $(LD_FLAGS) $^ -Ttext $(KER_ENTRY_ADDR) -e main -o $@ 32 | 33 | $(KER_O_FILES) : %.o : %.c 34 | $(CC) $(CC_FLAGS) -c $< -o $@ 35 | 36 | %.bin : %.s 37 | $(ASM) $(ASM_FLAGS) -f elf $< -o $@ 38 | 39 | # 头文件依赖 40 | 41 | $(KER_D_FILES) : %.d : %.c 42 | @set -e; \ 43 | rm -f $@; \ 44 | $(CC) -MM $(CC_FLAGS) $< $(CC_INCLUDE_FLAGS) > $@.$$$$.dtmp; \ 45 | sed 's,\(.*\)\.o\:,$*\.o $*\.d\:,g' < $@.$$$$.dtmp > $@; \ 46 | rm -f $@.$$$$.dtmp 47 | 48 | -include $(KER_D_FILES) -------------------------------------------------------------------------------- /src/include/shared/path.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_SHARD_PATH_H 2 | #define TINY_OS_SHARD_PATH_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | /* 常见的关于路径字符串的操作 */ 9 | 10 | /* 判断一个路径是否是绝对路径 */ 11 | bool is_absolute_path(const char *path); 12 | 13 | /* 判断一个路径是否指定了分区 */ 14 | bool is_path_containning_dp(const char *path); 15 | 16 | /* 从一个路径中提取出分区名,返回实际复制的字符数 */ 17 | uint32_t get_dp_from_path_s(const char *path, 18 | char *dst, uint32_t buf_size); 19 | 20 | /* 从一个路径中提取出分区handle,失败时返回 DPT_UNIT_COUNT */ 21 | filesys_dp_handle get_dp_handle_from_path(const char *path, 22 | void *(*_malloc)(size_t), 23 | void (*_free)(void*)); 24 | 25 | /* 跳过一个路径中的分区部分,要求输入是包含分区的 */ 26 | const char *skip_dp_in_abs_path(const char *path); 27 | 28 | /* 29 | 给定当前路径和delta路径,取得叠加后的结果 30 | dst不能含有分区 31 | 缓冲区不够时返回false 32 | */ 33 | bool cat_path_s(const char *src, const char *delta, 34 | char *dst, uint32_t buf_size); 35 | 36 | /* 同上,但会考虑分区的切换 */ 37 | bool cat_path_ex_s(filesys_dp_handle src_dp, const char *src_path, 38 | const char *delta, 39 | filesys_dp_handle *out_dp, char *out_path, 40 | uint32_t out_path_buf_size); 41 | 42 | /* 给定一个文件路径,将其转换为父目录路径 */ 43 | bool to_parent_dir(char *filepath); 44 | 45 | /* 原地把一个路径中的..和.字给压缩掉,返回压缩后路径字符串的长度 */ 46 | uint32_t compress_path(char *path); 47 | 48 | #endif /* TINY_OS_SHARD_PATH_H */ 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TinyOS 2 | 3 | 学习用小型操作系统,运行在x86(32位)单核计算机上。Bootloader部分参考了《操作系统真象还原》一书,其他的部分就放飞自我、甚至可以说是非Unix-like了。 4 | 5 | --- 6 | 7 | ## 特性 8 | 9 | - [x] 分页内存管理 10 | - [x] 抢占式线程调度 11 | - [x] 信号量 12 | - [x] 进程资源管理 13 | - [x] 系统调用框架 14 | - [x] 键盘驱动程序 15 | - [x] 进程间消息传递 16 | - [x] 文件系统 17 | - [x] 用户界面 18 | - [x] 管道通信 19 | - [x] cat等基本应用程序,以及一个简易文本编辑器 20 | 21 | ## 编译 22 | 23 | bochs的编译运行依赖于: 24 | 25 | > bochs 2.65+, gnu make, gcc, g++, ld, nasm, dd, bximage(通常随bochs一起安装) 26 | 27 | 要使用bochs运行该系统,可执行以下步骤: 28 | 29 | 1. 跟据bochs所附带的显示插件,修改`bochsrc.txt`中的`display_library`项 30 | 2. 初次运行前,运行`make fs`初始化磁盘映像 31 | 3. 运行`make run`以构建项目并启动虚拟机 32 | 33 | 由于磁盘映像创建工具bximage的命令参数格式曾发生变动,因此若无法正确初始化磁盘映像文件,可尝试运行`bash setup.sh`以解决问题。 34 | 35 | ## 交互 36 | 37 | ![ss01](./doc/pics/01-explorer.png) 38 | ![ss02](./doc/pics/02-ed.png) 39 | 40 | 系统默认交互界面分为Output区域和Command区域,前者用于显示输出,后者用于输入命令。系统已经提供的命令包括: 41 | 42 | 1. cd path : 修改当前工作路径 43 | 2. clear : 清空Output区域 44 | 3. exec path name ... : 从一个elf文件创建一个进程 45 | 4. exit : 退出系统 46 | 5. fg [pid] : 将一个后台进程切换到前台 47 | 6. kill p1 [p2] ... : 销毁一些进程 48 | 7. ps : 查看后台运行的进程列表 49 | 50 | 此外,还有以下应用程序可供使用: 51 | 52 | 1. cat : 查看文件内容 53 | 2. cp : 复制文件 54 | 3. ed : 一个简单的文本编辑器 55 | 4. file : 将管线输出保存到文件 56 | 5. help : 查看命令/应用程序的帮助信息 57 | 6. less : 以只读方式浏览文件内容 58 | 7. ls : 查看当前工作路径下的文件列表 59 | 8. pwd : 查看当前工作路径 60 | 61 | 输入`help command/application`可以查看命令或应用程序的用法。 62 | -------------------------------------------------------------------------------- /src/include/kernel/driver/diskdriver.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_DISK_DRIVER_H 2 | #define TINY_OS_DISK_DRIVER_H 3 | 4 | #include 5 | 6 | /* 7 | 硬盘任务调度: 8 | 维护一个阻塞线程队列,唤醒的时候从中选一个 9 | */ 10 | 11 | typedef uint8_t disk_rw_task_type; 12 | 13 | #define DISK_RW_TASK_TYPE_READ 0 14 | #define DISK_RW_TASK_TYPE_WRITE 1 15 | 16 | #define DISK_SECTOR_BYTE_SIZE 512 17 | 18 | /* 磁盘读写任务 */ 19 | struct disk_rw_task 20 | { 21 | disk_rw_task_type type; 22 | size_t sector_base; 23 | size_t sector_cnt; 24 | union 25 | { 26 | void *read_dst; 27 | const void *write_src; 28 | } addr; 29 | }; 30 | 31 | void init_disk_driver(); 32 | 33 | /* 34 | 执行一个无缓冲硬盘读写 35 | 所以addr不能缺页 36 | */ 37 | void disk_rw_raw(const struct disk_rw_task *task); 38 | 39 | #define disk_read(SEC, CNT, DATA) \ 40 | do { \ 41 | struct disk_rw_task task = \ 42 | { \ 43 | .type = DISK_RW_TASK_TYPE_READ, \ 44 | .sector_base = (SEC), \ 45 | .sector_cnt = (CNT), \ 46 | .addr.read_dst = (DATA) \ 47 | }; \ 48 | disk_rw_raw(&task); \ 49 | } while(0) 50 | 51 | #define disk_write(SEC, CNT, DATA) \ 52 | do { \ 53 | struct disk_rw_task task = \ 54 | { \ 55 | .type = DISK_RW_TASK_TYPE_WRITE, \ 56 | .sector_base = (SEC), \ 57 | .sector_cnt = (CNT), \ 58 | .addr.write_src = (DATA) \ 59 | }; \ 60 | disk_rw_raw(&task); \ 61 | } while(0) 62 | 63 | #endif /* TINY_OS_DISK_DRIVER_H */ 64 | -------------------------------------------------------------------------------- /src/include/kernel/sysmsg/sysmsg_src.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_SYSMSG_SRC_H 2 | #define TINY_OS_SYSMSG_SRC_H 3 | 4 | #include 5 | 6 | /* 7 | 因为效率问题,系统中消息总线是不打算做的 8 | 所以每种消息源维护自己要通知的进程列表,本文件中的接口提供了该机制 9 | 反过来,当进程挂掉的时候,也要通知到消息源 10 | 11 | 于是每个消息源维护一个链表A,数据是进程PCB 12 | 同时进程也维护一个链表B,遍历B可以从所有和该进程相关的A中把该进程删掉 13 | */ 14 | 15 | struct PCB; 16 | 17 | /* 消息源持有的接收者列表,即A链表 */ 18 | struct sysmsg_receiver_list 19 | { 20 | ilist processes; 21 | }; 22 | 23 | /* PCB端的链表B的节点 */ 24 | struct sysmsg_rcv_src_list_node 25 | { 26 | struct PCB *pcb; 27 | struct ilist_node rcv_node; // A中的节点,即消息源持有的接收者链表中的节点 28 | struct ilist_node src_node; // B中的节点,即PCB持有的消息源链表中的节点 29 | }; 30 | 31 | /* PCB端的消息源列表,即B链表 */ 32 | struct sysmsg_source_list 33 | { 34 | ilist sources; 35 | }; 36 | 37 | /* 两种表的初始化和销毁 */ 38 | 39 | #define init_sysmsg_receiver_list(X) init_ilist(&(X)->processes) 40 | 41 | #define init_sysmsg_sources_list(X) init_ilist(&(X)->sources) 42 | 43 | void destroy_sysmsg_receiver_list(struct sysmsg_receiver_list *receiver_list); 44 | 45 | void destroy_sysmsg_source_list(struct sysmsg_source_list *source_list); 46 | 47 | /* 把某条消息发送到一组进程 */ 48 | void send_msg_to_procs(struct sysmsg_receiver_list *rcv, const struct sysmsg *msg, bool (*mask_func)(const struct PCB*)); 49 | 50 | /* 把进程注册到消息源,提供A、B链表即可,会建立起其间的链接 */ 51 | void register_sysmsg_source(struct PCB *pcb, 52 | struct sysmsg_receiver_list *rcv, 53 | struct sysmsg_source_list *src); 54 | 55 | /* 没错,注册了就别想删(因为解除一个链接要线性搜索链表…… */ 56 | 57 | #endif /* TINY_OS_SYSMSG_SRC_H */ 58 | -------------------------------------------------------------------------------- /src/include/shared/proc_mem.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_SHARED_PROC_MEM_H 2 | #define TINY_OS_SHARED_PROC_MEM_H 3 | 4 | #include 5 | 6 | /* 关于进程虚拟地址空间可用区间的划分 */ 7 | 8 | /* 9 | 进程初始虚拟地址空间规划: 10 | addr space 11 | || 低地址区域: 12 | || 0~(USER_STACK_BITMAP_ADDR - 1): 空闲 13 | || USER_STACK_BITMAP_ADDR处为调用栈分配位图 14 | || 位图之后紧跟usr_addr_interval 15 | || 之后的空间均为空闲 16 | || 高地址区域: 17 | || elf文件缓存 18 | || 进程参数区 19 | \/ 调用栈 20 | */ 21 | 22 | /* 用户栈最高地址 */ 23 | #define USER_STACK_TOP_ADDR ((uint32_t)0xbffff * (uint32_t)0x1000) 24 | 25 | /* 默认用户栈大小:1M */ 26 | #define USER_STACK_SIZE 0x100000 27 | 28 | /* 用户栈位图起始地址 */ 29 | #define USER_STACK_BITMAP_ADDR 0x100000 30 | 31 | /* 32 | 一个进程最多包含多少线程 33 | 应是32的整数倍 34 | */ 35 | #define MAX_PROCESS_THREADS 32 36 | 37 | /* 有多少个用户栈位图 */ 38 | #define USER_THREAD_STACK_BITMAP_COUNT (MAX_PROCESS_THREADS >> 5) 39 | 40 | /* 每个参数的buffer size */ 41 | #define EXEC_ELF_ARG_BUF_SIZE 256 42 | 43 | /* 至多有多少参数 */ 44 | #define EXEC_ELF_ARG_MAX_COUNT 24 45 | 46 | /* 进程参数区起始地址 */ 47 | #define PROC_ARG_ZONE_ADDR \ 48 | (USER_STACK_TOP_ADDR - MAX_PROCESS_THREADS * USER_STACK_SIZE - \ 49 | EXEC_ELF_ARG_MAX_COUNT * EXEC_ELF_ARG_BUF_SIZE - sizeof(uint32_t)) 50 | 51 | struct usr_addr_interval 52 | { 53 | size_t beg1, size1; 54 | size_t beg2, size2; 55 | }; 56 | 57 | /* 用户地址空间空闲区间存放在哪里 */ 58 | #define USR_ADDR_INTERVAL_ADDR \ 59 | (USER_STACK_BITMAP_ADDR + \ 60 | sizeof(uint32_t) * USER_THREAD_STACK_BITMAP_COUNT) 61 | 62 | #endif /* TINY_OS_SHARED_PROC_MEM_H */ 63 | -------------------------------------------------------------------------------- /src/applications/ed/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "ed.h" 5 | #include "rf.h" 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | if(argc != 2) 10 | { 11 | printf("%LUsage: ed filename"); 12 | return -1; 13 | } 14 | 15 | // 解析待打开的文件路径 16 | filesys_dp_handle dp; 17 | char *path = malloc_and_cat_path(argv[0], argv[1], &dp); 18 | if(!path) 19 | { 20 | printf("%LInvalid filename: %s", argv[1]); 21 | return -1; 22 | } 23 | 24 | usr_file_handle fp; 25 | enum filesys_opr_result frt = open_file(dp, path, false, &fp); 26 | 27 | ed_t *ed = NULL; 28 | 29 | if(frt == filesys_opr_success) 30 | { 31 | rf_init(fp); 32 | ed = new_ed(dp, path, rf_provider); 33 | close_file(fp); 34 | } 35 | else if(frt == filesys_opr_not_found && 36 | make_file(dp, path) == filesys_opr_success) 37 | { 38 | // 如果找不到,就认为这是在试图创建一个新文件 39 | ed = new_ed(dp, path, default_ed_text_provider_null); 40 | } 41 | else 42 | { 43 | printf("%LInvalid filename: %s", argv[1]); 44 | return -1; 45 | } 46 | 47 | // 神秘的错误 48 | if(!ed) 49 | { 50 | printf("%LUnknown error"); 51 | return -1; 52 | } 53 | 54 | // 系统资源申请 55 | if(!alloc_con_buf()) 56 | { 57 | printf("%LFailed to allocate screen buffer"); 58 | return -1; 59 | } 60 | alloc_fg(); 61 | 62 | register_key_msg(); 63 | register_char_msg(); 64 | 65 | ed_mainloop(ed); 66 | 67 | free_ed(ed); 68 | return 0; 69 | } 70 | -------------------------------------------------------------------------------- /src/include/kernel/explorer/screen.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_EXPLORER_SCREEN_H 2 | #define TINY_OS_EXPLORER_SCREEN_H 3 | 4 | #include 5 | #include 6 | 7 | struct PCB; 8 | 9 | #define SCR_CMD_WIDTH (CON_BUF_ROW_SIZE - 0) 10 | #define SCR_CMD_HEIGHT 3 11 | 12 | #define SCR_DISP_WIDTH SCR_CMD_WIDTH 13 | #define SCR_DISP_HEIGHT (CON_BUF_COL_SIZE - 2 - SCR_CMD_HEIGHT) 14 | 15 | /* 清除整个屏幕的内容 */ 16 | void scr_clr(); 17 | 18 | /* 绘制展示区标题栏 */ 19 | void scr_disp_caption(const char *title); 20 | 21 | /* 绘制命令区标题栏 */ 22 | void scr_cmd_caption(const char *title); 23 | 24 | /* 清空展示区显示 */ 25 | void clr_disp(); 26 | 27 | /* 清空命令区显示 */ 28 | void clr_cmd(); 29 | 30 | /* 设置显示区字符 */ 31 | void disp_char(uint8_t x, uint8_t y, char ch); 32 | 33 | /* 设置显示区字符 */ 34 | void disp_char2(uint16_t pos, char ch); 35 | 36 | /* 设置显示区字符属性 */ 37 | void disp_attrib(uint8_t x, uint8_t y, uint8_t attrib); 38 | 39 | /* 设置显示区字符属性 */ 40 | void disp_attrib2(uint16_t pos, uint8_t attrib); 41 | 42 | /* disp区滚屏一行 */ 43 | void disp_roll_screen(); 44 | 45 | /* 设置控制区区字符 */ 46 | void cmd_char(uint8_t x, uint8_t y, char ch); 47 | 48 | /* 设置控制区字符 */ 49 | void cmd_char2(uint16_t pos, char ch); 50 | 51 | /* 设置控制区字符属性 */ 52 | void cmd_attrib(uint8_t x, uint8_t y, uint8_t attrib); 53 | 54 | /* 设置控制区字符属性 */ 55 | void cmd_attrib2(uint16_t pos, uint8_t attrib); 56 | 57 | /* 在显示区显示一个字符串,到行尾自动截断 */ 58 | void disp_show_str(uint8_t x, uint8_t y, const char *str); 59 | 60 | /* 将屏幕内容拷贝到一个进程的显示缓冲区 */ 61 | void copy_scr_to_con_buf(struct PCB *pcb); 62 | 63 | /* 将一个进程后台缓冲区的内容拷贝到屏幕 */ 64 | void copy_con_buf_to_scr(struct PCB *pcb); 65 | 66 | #endif /* TINY_OS_EXPLORER_SCREEN_H */ 67 | -------------------------------------------------------------------------------- /src/lib/fstm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | ifstm_t *ifstm_init(filesys_dp_handle dp, const char *path, 8 | size_t buf_size) 9 | { 10 | usr_file_handle fp; 11 | if(open_file(dp, path, false, &fp) != filesys_opr_success) 12 | return NULL; 13 | 14 | ifstm_t *ret = malloc(sizeof(ifstm_t) + buf_size); 15 | if(!ret) 16 | { 17 | close_file(fp); 18 | return NULL; 19 | } 20 | 21 | ret->fp = fp; 22 | ret->fpos = 0; 23 | ret->fsize = get_file_size(fp); 24 | ret->bsize = buf_size; 25 | ret->bidx = 0; 26 | ret->dsize = 0; 27 | 28 | return ret; 29 | } 30 | 31 | char ifstm_next(ifstm_t *fstm) 32 | { 33 | if(!fstm) 34 | return FSTM_EOF; 35 | 36 | if(fstm->bidx >= fstm->dsize) 37 | { 38 | if(fstm->fpos >= fstm->fsize) 39 | return FSTM_EOF; 40 | 41 | size_t delta = MIN(fstm->bsize, fstm->fsize - fstm->fpos); 42 | 43 | // 这里没有做关于读取结果的任何检查 44 | // 因为在这种情况下读取失败是种不可理喻的情况,可能意味着文件系统bug 45 | // 如果有问题就让它暴露出来好了 46 | read_file(fstm->fp, fstm->fpos, delta, fstm->buf); 47 | 48 | fstm->dsize = delta; 49 | fstm->bidx = 0; 50 | fstm->fpos += delta; 51 | } 52 | 53 | return fstm->buf[fstm->bidx++]; 54 | } 55 | 56 | void ifstm_free(ifstm_t *fstm) 57 | { 58 | if(!fstm) 59 | return; 60 | 61 | close_file(fstm->fp); 62 | free(fstm); 63 | } 64 | 65 | size_t ifstm_remain_size(ifstm_t *fstm) 66 | { 67 | return fstm ? (fstm->fsize - fstm->fpos + fstm->dsize - fstm->bidx) : 0; 68 | } 69 | -------------------------------------------------------------------------------- /src/include/shared/sysmsg.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_SHARD_SYSMSG_H 2 | #define TINY_OS_SHARD_SYSMSG_H 3 | 4 | #include 5 | #include 6 | 7 | /* 8 | 每个进程有自己的系统消息队列 9 | 下面是于此相关的系统调用约定 10 | */ 11 | 12 | /* 13 | 各种消息队列操作共用同一个系统调用号,所以第一个参数是功能号 14 | 后面的参数含义由功能号定义 15 | */ 16 | 17 | /* 本进程系统消息队列是否为空,无参数 */ 18 | #define SYSMSG_SYSCALL_FUNCTION_IS_EMPTY 0 19 | 20 | /* 21 | 第一个参数:对消息的处理方式,可按位或,见下面的各种PEEK_OPERATION 22 | 第二个参数:输出缓冲区在用户虚拟地址空间中的地址 23 | 返回值:是否peek到消息 24 | */ 25 | #define SYSMSG_SYSCALL_FUNCTION_PEEK_MSG 1 26 | 27 | #define SYSMSG_SYSCALL_PEEK_OPERATION_REMOVE 1 28 | 29 | /* 注册接受键盘消息,无参数 */ 30 | #define SYSMSG_SYSCALL_FUNCTION_REGISTER_KEYBOARD_MSG 2 31 | 32 | /* 注册接受字符消息,无参数 */ 33 | #define SYSMSG_SYSCALL_FUNCTION_REGISTER_CHAR_MSG 3 34 | 35 | /* 将当前线程阻塞在进程消息队列中,无参数 */ 36 | #define SYSMSG_SYSCALL_FUNCTION_BLOCK_ONTO_SYSMSG 4 37 | 38 | #define SYSMSG_SYSCALL_FUNCTION_COUNT 5 39 | 40 | /* 41 | 内核进程消息类型 42 | 只能是预定义好的,并不能运行时注册增删 43 | */ 44 | typedef uint32_t sysmsg_type; 45 | 46 | /* 合法的消息类型 */ 47 | 48 | #define SYSMSG_TYPE_KEYBOARD 0 /* 键盘按下或释放,参数定义在kernel/kbdriver.h中 */ 49 | 50 | #define SYSMSG_TYPE_CHAR 1 /* 字符输入消息,参数定义在kernel/kbdriver.h中 */ 51 | 52 | #define SYSMSG_TYPE_EXPL_INPUT 2 /* 来自explorer的输入 */ 53 | 54 | #define SYSMSG_TYPE_EXPL_NEW_LINE 3 /* 让explorer开个新行 */ 55 | 56 | #define SYSMSG_TYPE_EXPL_OUTPUT 4 /* 到explorer的输出 */ 57 | 58 | #define SYSMSG_TYPE_PIPE_NULL_CHAR 5 /* 设有进程 A | B,A调用该函数会让B得到一个空字符 */ 59 | 60 | /* 61 | 内核消息参数字节数 62 | 消息传递并不是拿来大规模发送数据的,所以允许的参数就很有限了…… 63 | 至于这块空间如何解释,每种消息有自己的约定 64 | */ 65 | #define SYSMSG_PARAM_SIZE 12 66 | 67 | /* 内核进程消息 */ 68 | struct sysmsg 69 | { 70 | sysmsg_type type; 71 | uint8_t params[SYSMSG_PARAM_SIZE]; 72 | }; 73 | 74 | #endif /* TINY_OS_SHARD_SYSCALL_SYSMSG_H */ 75 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CC_INCLUDE_FLAGS = -nostdinc -I src/include/ 3 | CC_FLAGS = -m32 $(CC_INCLUDE_FLAGS) \ 4 | -fno-stack-protector -std=gnu99 \ 5 | -fno-builtin -Werror -Wall -O2 6 | 7 | CPPC = g++ 8 | CPPC_INCLUDE_FLAGS = -I src/include/ -I . 9 | CPPC_FLAGS = -std=c++14 -Werror -Wall -O2 $(CPPC_INCLUDE_FLAGS) \ 10 | -Wno-unused-result 11 | 12 | LD = ld 13 | LD_FLAGS = -m elf_i386 14 | 15 | ASM = nasm 16 | ASM_FLAGS = 17 | 18 | C_SUFFIX = _C_FILES 19 | CPP_SUFFIX = _CPP_FILES 20 | O_SUFFIX = _O_FILES 21 | D_SUFFIX = _D_FILES 22 | 23 | TOOLS = 24 | TOOLS_TGTS = 25 | 26 | APPS = 27 | APPS_TGTS = 28 | 29 | include ./make/tool 30 | include ./make/application 31 | 32 | # disk img 33 | HD = hd.img 34 | 35 | .PHONY : all 36 | all : $(HD) apps tools 37 | 38 | include ./make/lib 39 | include ./make/shared 40 | include ./make/kernel 41 | 42 | $(eval $(call make_tool,mkdpt,MKDPT)) 43 | $(eval $(call make_tool,bin_trans,BIN_TRANS)) 44 | $(eval $(call make_tool,disk_ipt,DISK_IPT)) 45 | 46 | $(eval $(call make_app,cat,CAT)) 47 | $(eval $(call make_app,cp,CP)) 48 | $(eval $(call make_app,ed,ED)) 49 | $(eval $(call make_app,file,FILE)) 50 | $(eval $(call make_app,help,HELP)) 51 | $(eval $(call make_app,less,LESS)) 52 | $(eval $(call make_app,ls,LS)) 53 | $(eval $(call make_app,mkdir,MKDIR)) 54 | $(eval $(call make_app,pwd,PWD)) 55 | 56 | .PHONY : apps 57 | apps : $(APPS_TGTS) 58 | 59 | .PHONY : tools 60 | tools : $(TOOLS_TGTS) 61 | 62 | .PHONY: clean 63 | clean : 64 | rm -f $(shell find ./src/ -name "*.dtmp") 65 | rm -f $(shell find ./src/ -name "*.o") 66 | rm -f $(shell find ./src/ -name "*.d") 67 | rm -f $(shell find ./src/ -name "*.bootbin") 68 | rm -f $(shell find ./src/ -name "*.bin") 69 | rm -f $(TOOLS) $(APPS) 70 | 71 | .PHONY: run 72 | run : 73 | make all 74 | echo c | bochs 75 | 76 | .PHONY: fs 77 | fs : 78 | bash setup_old.sh 79 | make clean 80 | -------------------------------------------------------------------------------- /src/applications/cp/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char *argv[]) 9 | { 10 | expl_new_line(); 11 | 12 | if(argc < 3) 13 | { 14 | printf("Usage: cp src dst"); 15 | return -1; 16 | } 17 | 18 | const char *_src_name = argv[1]; 19 | const char *_dst_name = argv[2]; 20 | 21 | filesys_dp_handle src_dp, dst_dp; 22 | char *src_name = malloc_and_cat_path(argv[0], _src_name, &src_dp); 23 | char *dst_name = malloc_and_cat_path(argv[0], _dst_name, &dst_dp); 24 | 25 | if(!src_name) 26 | { 27 | printf("Invalid src path: %s", _src_name); 28 | return -1; 29 | } 30 | 31 | if(!dst_name) 32 | { 33 | printf("Invalid dst path: %s", _dst_name); 34 | return -1; 35 | } 36 | 37 | usr_file_handle sfp, dfp; 38 | if(open_file(src_dp, src_name, false, &sfp) != filesys_opr_success) 39 | { 40 | printf("Failed to open src file: %s", _src_name); 41 | return -1; 42 | } 43 | 44 | remove_file(dst_dp, dst_name); make_file(dst_dp, dst_name); 45 | if(open_file(dst_dp, dst_name, true, &dfp) != filesys_opr_success) 46 | { 47 | printf("Failed to open dst file: %s", _dst_name); 48 | return -1; 49 | } 50 | 51 | uint32_t file_size = get_file_size(sfp); 52 | uint8_t buf[128]; uint32_t fpos = 0; 53 | 54 | while(fpos < file_size) 55 | { 56 | uint32_t delta = file_size - fpos; 57 | if(delta > 128) 58 | delta = 128; 59 | read_file(sfp, fpos, delta, buf); 60 | write_file(dfp, fpos, delta, buf); 61 | fpos += delta; 62 | } 63 | 64 | close_file(sfp); 65 | close_file(dfp); 66 | 67 | printf("Done"); 68 | 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /src/boot/mbr.s: -------------------------------------------------------------------------------- 1 | %include "src/boot/boot.s" 2 | 3 | section MBR vstart=0x7c00 4 | mov ax, cs 5 | mov ds, ax 6 | mov es, ax 7 | mov ss, ax 8 | mov fs, ax 9 | mov sp, 0x7c00 10 | 11 | ; 清屏 12 | mov ax, 0x0600 13 | mov bx, 0x0700 14 | mov cx, 0 15 | mov dx, 0x184f 16 | int 0x10 17 | 18 | ; 加载bootloader到 BOOTLOADER_START_ADDR 并执行之 19 | mov eax, BOOTLOADER_START_SECTOR 20 | mov bx, BOOTLOADER_START_ADDR 21 | mov cx, BOOTLOADER_SECTOR_COUNT 22 | call read_disk 23 | 24 | jmp BOOTLOADER_START_ADDR 25 | 26 | ; eax:LBA 27 | ; bx :目的地址 28 | ; cx :扇区数目 29 | 30 | read_disk: 31 | ; 备份eax和cx,等会儿会覆盖这俩 32 | mov esi, eax 33 | mov di, cx 34 | 35 | ; 设置扇区数 36 | mov dx, 0x1f2 37 | mov al, cl 38 | out dx, al 39 | mov eax, esi 40 | 41 | ; 写入LBA的低三个字节 42 | mov dx, 0x1f3 43 | out dx, al 44 | 45 | mov cl, 8 46 | shr eax, cl 47 | mov dx, 0x1f4 48 | out dx, al 49 | 50 | shr eax, cl 51 | mov dx, 0x1f5 52 | out dx, al 53 | 54 | ; 写入Device端口,用al来构造其值 55 | shr eax, cl 56 | and al, 0x0f 57 | or al, 0xe0 58 | mov dx, 0x1f6 59 | out dx, al 60 | 61 | ; 写Command 62 | ; 0x20为读,0x30为写 63 | mov dx, 0x1f7 64 | mov al, 0x20 65 | out dx, al 66 | 67 | ; 轮询硬盘状态直到数据准备就绪 68 | waiting_disk_reading: 69 | in al, dx ; Command和Status是同一个端口号,无需准备dx 70 | and al, 0x88 ; 提取第3位和第7位 71 | cmp al, 0x8 ; 第3位为1,第7位为0 72 | jnz waiting_disk_reading 73 | 74 | ; 从Data(0x1f0)端口读数据 75 | 76 | ; 计算读取次数 77 | ; 一次读两个字节,一个扇区需要读256次 78 | mov ax, di 79 | mov dx, 256 80 | mul dx 81 | mov cx, ax 82 | 83 | mov dx, 0x1f0 84 | read_from_disk_port_to_mem: 85 | in ax, dx 86 | mov [bx], ax 87 | add bx, 2 88 | loop read_from_disk_port_to_mem 89 | 90 | ret 91 | 92 | times 510 - ($ - $$) db 0 93 | db 0x55, 0xaa 94 | -------------------------------------------------------------------------------- /src/include/shared/ptrlist.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_LIB_PTRLIST_H 2 | #define TINY_OS_LIB_PTRLIST_H 3 | 4 | #include 5 | 6 | /*===================================================================== 7 | 非侵入双向循环链表 8 | =====================================================================*/ 9 | 10 | /* 循环链表节点 */ 11 | struct rlist_node 12 | { 13 | struct rlist_node *last; 14 | struct rlist_node *next; 15 | void *ptr; 16 | }; 17 | 18 | struct rlist_handle 19 | { 20 | struct rlist_node *last; 21 | struct rlist_node *next; 22 | }; 23 | 24 | /* 循环链表句柄 */ 25 | typedef struct rlist_handle rlist; 26 | 27 | void init_rlist(rlist *L); 28 | 29 | /* 循环链表节点分配器 */ 30 | typedef struct rlist_node *(*rlist_node_allocator)(); 31 | /* 循环链表节点释放器 */ 32 | typedef void (*rlist_node_deallocator)(struct rlist_node*); 33 | 34 | void push_back_rlist(rlist *L, void *ptr, rlist_node_allocator node_alloc); 35 | void *pop_back_rlist(rlist *L, rlist_node_deallocator node_dealloc); 36 | 37 | void push_front_rlist(rlist *L, void *ptr, rlist_node_allocator node_alloc); 38 | void *pop_front_rlist(rlist *L, rlist_node_deallocator node_dealloc); 39 | 40 | void *back_rlist(rlist *L); 41 | void *front_rlist(rlist *L); 42 | 43 | bool is_rlist_empty(rlist *L); 44 | 45 | /*===================================================================== 46 | 侵入式双向循环链表 47 | =====================================================================*/ 48 | 49 | struct ilist_node 50 | { 51 | struct ilist_node *last; 52 | struct ilist_node *next; 53 | }; 54 | 55 | /* 链表句柄 */ 56 | typedef struct ilist_node ilist; 57 | 58 | void init_ilist(ilist *L); 59 | 60 | void push_back_ilist(ilist *L, struct ilist_node *node); 61 | struct ilist_node *pop_front_ilist(ilist *L); 62 | 63 | bool is_ilist_empty(ilist *L); 64 | 65 | void erase_from_ilist(struct ilist_node *node); 66 | 67 | #endif /* TINY_OS_LIB_PTRLIST_H */ 68 | -------------------------------------------------------------------------------- /src/kernel/filesys/afs/blk_mem_buf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | static freelist_handle blk_buf_fl; 9 | 10 | static freelist_handle sec_buf_fl; 11 | 12 | void init_afs_buffer_allocator() 13 | { 14 | init_freelist(&blk_buf_fl); 15 | init_freelist(&sec_buf_fl); 16 | } 17 | 18 | STATIC_ASSERT(AFS_BLOCK_BYTE_SIZE <= 4096, 19 | too_large_afs_block_size); 20 | 21 | /* 22 | 这个函数可能被多个进程并行调用,而那些进程很可能是不关中断的 23 | 所以这里的alloc和free都要关中断操作 24 | */ 25 | void *afs_alloc_block_buffer() 26 | { 27 | intr_state is = fetch_and_disable_intr(); 28 | 29 | if(is_freelist_empty(&blk_buf_fl)) 30 | { 31 | char *page = (char*)alloc_ker_page(true); 32 | for(size_t i = 0; i < 4096 / AFS_BLOCK_BYTE_SIZE; ++i) 33 | add_freelist(&blk_buf_fl, page + AFS_BLOCK_BYTE_SIZE * i); 34 | } 35 | 36 | void *ret = fetch_freelist(&blk_buf_fl); 37 | set_intr_state(is); 38 | return ret; 39 | } 40 | 41 | void afs_free_block_buffer(void *buf) 42 | { 43 | intr_state is = fetch_and_disable_intr(); 44 | add_freelist(&blk_buf_fl, buf); 45 | set_intr_state(is); 46 | } 47 | 48 | void *afs_alloc_sector_buffer() 49 | { 50 | intr_state is = fetch_and_disable_intr(); 51 | 52 | if(is_freelist_empty(&sec_buf_fl)) 53 | { 54 | char *block = (char*)afs_alloc_block_buffer(); 55 | for(size_t i = 0; i < AFS_BLOCK_SECTOR_COUNT; ++i) 56 | add_freelist(&sec_buf_fl, block + AFS_SECTOR_BYTE_SIZE * i); 57 | } 58 | 59 | void *ret = fetch_freelist(&sec_buf_fl); 60 | set_intr_state(is); 61 | return ret; 62 | } 63 | 64 | void afs_free_sector_buffer(void *buf) 65 | { 66 | intr_state is = fetch_and_disable_intr(); 67 | add_freelist(&sec_buf_fl, buf); 68 | set_intr_state(is); 69 | } 70 | -------------------------------------------------------------------------------- /src/include/kernel/filesys/afs/disk_cache.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_FILESYS_AFS_SECTOR_CACHE_H 2 | #define TINY_OS_FILESYS_AFS_SECTOR_CACHE_H 3 | 4 | #include 5 | 6 | /* 7 | 进程对磁盘的访问通常也是有时空局部性的,因此这里做个LRU的磁盘访问cache,不考虑抖动什么的 8 | */ 9 | 10 | /* 11 | 提供一个全局磁盘读写缓冲区,给定扇区号/块号和块内偏移、长度,能够访问磁盘上该块的数据 12 | 13 | 缓冲区基于linked map实现,采用LRU策略管理 14 | 15 | 块的读写缓冲用于文件读写 16 | 扇区的读写缓冲应该主要是用于entry访问 17 | 要求扇区请求和块请求不能有任何重叠,否则UB 18 | 19 | 扇区有读写和读读互斥: 20 | 如果扇区A被读入导致扇区B需要被释放,那么由读入A的线程将B标记为待释放。此时: 21 | 22 | 如果B没有操作者,就直接由读入A的线程把B释放、写回 23 | 如果B有操作者,就由最后一个离开的操作者将B释放 24 | 25 | 读者计数器和销毁标记均用关中断保护 26 | 27 | 读者写者都算是操作者。 28 | 29 | 块则没有互斥,因为块读写用于文件操作,应该由文件系统负责互斥 30 | */ 31 | 32 | void init_afs_disk_cache(); 33 | 34 | void afs_read_from_sector(uint32_t sec, size_t offset, size_t size, void *data); 35 | 36 | void afs_write_to_sector(uint32_t sec, size_t offset, size_t size, const void *data); 37 | 38 | /* 39 | 释放所有扇区缓存 40 | 比如关机的时候/销毁文件系统的时候用 41 | 调用时,文件系统须保证没有别的线程会调用afs_read/write_from/to_sector函数 42 | */ 43 | void afs_release_all_sector_cache(); 44 | 45 | /* 获取某个扇区的缓存区以用于读取,用完一定要调用对应的end函数 */ 46 | const void *afs_read_from_sector_begin(uint32_t sec); 47 | 48 | void afs_read_from_sector_end(uint32_t sec); 49 | 50 | /* 获取某个扇区的缓存区以用于写入,用完一定要调用对应的end函数 */ 51 | void *afs_write_to_sector_begin(uint32_t sec); 52 | 53 | void afs_write_to_sector_end(uint32_t sec); 54 | 55 | void afs_read_from_block(uint32_t sec, size_t offset, size_t size, void *data); 56 | 57 | void afs_write_to_block(uint32_t sec, size_t offset, size_t size, const void *data); 58 | 59 | void afs_release_all_block_cache(); 60 | 61 | const void *afs_read_from_block_begin(uint32_t sec); 62 | 63 | void afs_read_from_block_end(uint32_t sec); 64 | 65 | void *afs_write_to_block_begin(uint32_t sec); 66 | 67 | void afs_write_to_block_end(uint32_t sec); 68 | 69 | #endif /* TINY_OS_FILESYS_AFS_SECTOR_CACHE_H */ 70 | -------------------------------------------------------------------------------- /src/tools/mkdpt/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | extern "C" 11 | { 12 | #define TINY_OS_NO_INTDEF 13 | #include 14 | } 15 | 16 | dpt_unit dpts[DPT_UNIT_COUNT]; 17 | 18 | int main(int argc, const char *argv[]) 19 | { 20 | using namespace std; 21 | 22 | if(argc != 2) 23 | { 24 | cout << "Usage: mkdpt [disk image file name]" << endl; 25 | return 0; 26 | } 27 | 28 | for(size_t i = 1; i != DPT_UNIT_COUNT; ++i) 29 | { 30 | dpt_unit &dpt = dpts[i]; 31 | dpt.type = DISK_PT_NONEXISTENT; 32 | dpt.sector_begin = 0; 33 | dpt.sector_end = 0; 34 | strcpy(dpt.name, ("init-pt-" + to_string(i)).c_str()); 35 | } 36 | 37 | // 第一个分区用作afs分区 38 | dpts[0].type = DISK_PT_NOFS; 39 | dpts[0].sector_begin = DPT_SECTOR_POSITION + 1; 40 | dpts[0].sector_end = (DISK_IMPORT_DP_BEGIN - 1); 41 | strcpy(dpts[0].name, "sys"); 42 | 43 | #define LAST_DPT_IDX (DPT_UNIT_COUNT - 1) 44 | // 最后一个分区用作import分区 45 | dpts[LAST_DPT_IDX].type = DISK_PT_IMPORT; 46 | dpts[LAST_DPT_IDX].sector_begin = DISK_IMPORT_DP_BEGIN; 47 | dpts[LAST_DPT_IDX].sector_end = DISK_IMPORT_DP_END; 48 | strcpy(dpts[LAST_DPT_IDX].name, "import"); 49 | #undef LAST_DPT_IDX 50 | 51 | ofstream fout("mkdpttmp", ofstream::binary | ofstream::out); 52 | if(!fout) 53 | { 54 | cout << "Failed to open tmp file: mkdpttmp" << endl; 55 | return -1; 56 | } 57 | 58 | fout.write((const char*)&dpts, sizeof(dpts)); 59 | fout.close(); 60 | 61 | stringstream sst; 62 | sst << "dd if=mkdpttmp of=" << argv[1] << " bs=512 count=1 seek=" 63 | << to_string(DPT_SECTOR_POSITION) << " conv=notrunc"; 64 | system(sst.str().c_str()); 65 | system("rm -f mkdpttmp"); 66 | 67 | cout << "DPT inited" << endl; 68 | } 69 | -------------------------------------------------------------------------------- /src/include/shared/atrc.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_SHARD_ATRC_H 2 | #define TINY_OS_SHARD_ATRC_H 3 | 4 | #include 5 | #include 6 | 7 | /* 8 | atrc是一种提供以下操作的容器: 9 | 1. 创建时指定空间上限,除元素空间外额外空间开销为O(1) 10 | 2. O(1)时间分配一个新元素空间,返回一个该元素的句柄 11 | 3. O(1)时间跟据句柄得到元素空间 12 | 4. O(1)时间跟据句柄释放元素空间 13 | 5. O(n)时间遍历所有元素,其中n是空间上限 14 | 就是数组 + 自由链表封装了一下( 15 | 16 | C语言没有泛型我要死了…… 17 | */ 18 | 19 | typedef int32_t atrc_elem_handle; 20 | 21 | #define ATRC_ELEM_HANDLE_NULL (-1) 22 | 23 | #define ATRC_ELEM_SIZE(T) \ 24 | ({ struct T_ \ 25 | { \ 26 | int32_t idx_field_padding; T t; \ 27 | }; \ 28 | sizeof(struct T_); }) 29 | 30 | struct atrc 31 | { 32 | int32_t fst_avl_idx; 33 | int32_t total_size; 34 | void *data; 35 | }; 36 | 37 | /* elem_size应通过宏ATRC_ELEM_SIZE(elem_type)得到 */ 38 | void init_atrc(struct atrc *a, size_t elem_size, 39 | void *data_zone, size_t data_zone_size); 40 | 41 | /* atrc容器是否已经装满 */ 42 | #define is_atrc_full(A) ((A)->fst_avl_idx == ATRC_ELEM_HANDLE_NULL) 43 | 44 | /* 取得一个atrc容器中以UNIT为句柄的元素地址 */ 45 | #define get_atrc_unit(A, ELEM_SIZE, UNIT) \ 46 | ((void*)((uint32_t)((A)->data) + (ELEM_SIZE) * (UNIT) + 4)) 47 | 48 | bool is_atrc_unit_valid(struct atrc *a, size_t elem_size, atrc_elem_handle unit); 49 | 50 | uint32_t get_atrc_unit_idxfield(struct atrc *a, size_t elem_size, atrc_elem_handle unit); 51 | 52 | /* 在一个atrc容器中申请一个元素,返回其句柄。失败时返回ATRC_ELEM_HANDLE_NULL */ 53 | atrc_elem_handle alloc_atrc_unit(struct atrc *a, size_t elem_size); 54 | 55 | /* 释放一个atrc容器中句柄unit代表的元素 */ 56 | void free_atrc_unit(struct atrc *a, size_t elem_size, atrc_elem_handle unit); 57 | 58 | /* 以下begin,next,end三剑客和STL迭代器用法相同 */ 59 | 60 | atrc_elem_handle atrc_begin(struct atrc *a, size_t elem_size); 61 | 62 | atrc_elem_handle atrc_next(struct atrc *a, size_t elem_size, atrc_elem_handle unit); 63 | 64 | #define atrc_end() ATRC_ELEM_HANDLE_NULL 65 | 66 | #endif /* TINY_OS_SHARD_ATRC_H */ 67 | -------------------------------------------------------------------------------- /setup_old.sh: -------------------------------------------------------------------------------- 1 | rm -rf build 2 | rm -f hd.img 3 | bximage -hd -size=128M -mode=flat -q hd.img 4 | mkdir build 5 | make clean tools apps 6 | ./build/mkdpt hd.img 7 | ./build/disk_ipt hd.img ./build/cat /apps/cat \ 8 | ./build/cp /apps/cp \ 9 | ./build/ed /apps/ed \ 10 | ./build/file /apps/file \ 11 | ./build/help /apps/help \ 12 | ./build/less /apps/less \ 13 | ./build/ls /apps/ls \ 14 | ./build/mkdir /apps/mkdir \ 15 | ./build/pwd /apps/pwd \ 16 | ./src/docs/cat.txt /docs/cat \ 17 | ./src/docs/cd.txt /docs/cd \ 18 | ./src/docs/clear.txt /docs/clear \ 19 | ./src/docs/cp.txt /docs/cp \ 20 | ./src/docs/ed.txt /docs/ed \ 21 | ./src/docs/exec.txt /docs/exec \ 22 | ./src/docs/exit.txt /docs/exit \ 23 | ./src/docs/fg.txt /docs/fg \ 24 | ./src/docs/file.txt /docs/file \ 25 | ./src/docs/help.txt /docs/help \ 26 | ./src/docs/kill.txt /docs/kill \ 27 | ./src/docs/less.txt /docs/less \ 28 | ./src/docs/ls.txt /docs/ls \ 29 | ./src/docs/mkdir.txt /docs/mkdir \ 30 | ./src/docs/ps.txt /docs/ps \ 31 | ./src/docs/pwd.txt /docs/pwd \ 32 | ./makefile /makefile 33 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | rm -rf build 2 | rm -f hd.img 3 | bximage -mode=create -hd=128M -imgmode=flat -q hd.img 4 | mkdir build 5 | make clean tools apps 6 | ./build/mkdpt hd.img 7 | ./build/disk_ipt hd.img ./build/cat /apps/cat \ 8 | ./build/cp /apps/cp \ 9 | ./build/ed /apps/ed \ 10 | ./build/file /apps/file \ 11 | ./build/help /apps/help \ 12 | ./build/less /apps/less \ 13 | ./build/ls /apps/ls \ 14 | ./build/mkdir /apps/mkdir \ 15 | ./build/pwd /apps/pwd \ 16 | ./src/docs/cat.txt /docs/cat \ 17 | ./src/docs/cd.txt /docs/cd \ 18 | ./src/docs/clear.txt /docs/clear \ 19 | ./src/docs/cp.txt /docs/cp \ 20 | ./src/docs/ed.txt /docs/ed \ 21 | ./src/docs/exec.txt /docs/exec \ 22 | ./src/docs/exit.txt /docs/exit \ 23 | ./src/docs/fg.txt /docs/fg \ 24 | ./src/docs/file.txt /docs/file \ 25 | ./src/docs/help.txt /docs/help \ 26 | ./src/docs/kill.txt /docs/kill \ 27 | ./src/docs/less.txt /docs/less \ 28 | ./src/docs/ls.txt /docs/ls \ 29 | ./src/docs/mkdir.txt /docs/mkdir \ 30 | ./src/docs/ps.txt /docs/ps \ 31 | ./src/docs/pwd.txt /docs/pwd \ 32 | ./makefile /makefile 33 | -------------------------------------------------------------------------------- /src/kernel/memory/vir_page_man.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | struct vir_page_man 10 | { 11 | size_t begin, end; 12 | size_t total, unused; 13 | 14 | // IMPROVE:没错,暴力位图 15 | // 为1表示可用,为0表示已占用 16 | uint32_t bitmap[0]; 17 | }; 18 | 19 | size_t get_vir_page_man_byte_size(size_t pool_begin, size_t pool_end) 20 | { 21 | ASSERT(pool_begin < pool_end); 22 | 23 | return ((pool_end - pool_begin) / 32) * sizeof(uint32_t) 24 | + sizeof(struct vir_page_man); 25 | } 26 | 27 | void init_vir_page_man(struct vir_page_man *page_man, 28 | size_t pool_begin, size_t pool_end) 29 | { 30 | ASSERT(page_man != NULL); 31 | ASSERT(pool_begin < pool_end); 32 | 33 | page_man->begin = pool_begin; 34 | page_man->end = pool_end; 35 | page_man->total = pool_end - pool_begin; 36 | page_man->unused = page_man->total; 37 | 38 | memset((char*)page_man->bitmap, 0xff, page_man->total / 32 * sizeof(uint32_t)); 39 | } 40 | 41 | uint32_t alloc_page_in_vir_addr_space(struct vir_page_man *page_man) 42 | { 43 | ASSERT(page_man != NULL); 44 | if(page_man->unused == 0) 45 | return 0; 46 | 47 | for(size_t bmp_idx = 0; ; ++bmp_idx) 48 | { 49 | if(page_man->bitmap[bmp_idx] != 0) 50 | { 51 | uint32_t loc_idx = find_lowest_nonzero_bit(page_man->bitmap[bmp_idx]); 52 | page_man->bitmap[bmp_idx] &= ~(1 << loc_idx); 53 | --page_man->unused; 54 | return (((bmp_idx << 5) + loc_idx) + page_man->begin) << 12; 55 | } 56 | } 57 | return 0; 58 | } 59 | 60 | void free_page_in_vir_addr_space(struct vir_page_man *page_man, uint32_t addr) 61 | { 62 | ASSERT(page_man != NULL); 63 | ASSERT(page_man->unused < page_man->total); 64 | ++page_man->unused; 65 | uint32_t idx = (addr >> 12) - page_man->begin; 66 | page_man->bitmap[idx >> 5] |= (1 << (idx & 0x1f)); 67 | } 68 | -------------------------------------------------------------------------------- /src/include/shared/screen.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_SHARD_SCREEN_H 2 | #define TINY_OS_SHARD_SCREEN_H 3 | 4 | #define CH_BLACK 0b0000 5 | #define CH_BLUE 0b0001 6 | #define CH_GREEN 0b0010 7 | #define CH_CYAN 0b0011 8 | #define CH_RED 0b0100 9 | #define CH_MAGENTA 0b0101 10 | #define CH_BROWN 0b0110 11 | #define CH_GRAY 0b0111 12 | 13 | #define CH_LIGHT 0b1000 14 | 15 | #define BG_BLACK 0b00000000 16 | #define BG_BLUE 0b00010000 17 | #define BG_GREEN 0b00100000 18 | #define BG_CYAN 0b00110000 19 | #define BG_RED 0b01000000 20 | #define BG_MAGENTA 0b01010000 21 | #define BG_BROWN 0b01100000 22 | #define BG_GRAY 0b01110000 23 | 24 | #define CH_GLIM 0b10000000 25 | 26 | #define CON_BUF_BYTE_SIZE (80 * 25 * 2) 27 | 28 | #define CON_BUF_CHAR_COUNT (80 * 25) 29 | 30 | #define CON_BUF_ROW_SIZE 80 31 | #define CON_BUF_COL_SIZE 25 32 | 33 | /* console相关的系统调用第一个参数为操作类型,后面的才是真正的调用参数 */ 34 | 35 | /* high16:pos,low8:char */ 36 | #define CONSOLE_SYSCALL_FUNCTION_SET_CHAR 0 37 | /* high16:pos,low8:attrib */ 38 | #define CONSOLE_SYSCALL_FUNCTION_SET_ATTRIB 1 39 | /* high16:pos,high8(low16):char,low8:attrib */ 40 | #define CONSOLE_SYSCALL_FUNCTION_SET_CHAR_ATTRIB 2 41 | /* void */ 42 | #define CONSOLE_SYSCALL_FUNCTION_CLEAR_SCREEN 3 43 | 44 | /* 80 * row + col */ 45 | #define CONSOLE_SYSCALL_FUNCTION_SET_CURSOR 4 46 | /* 47 | void 48 | return:80 * row + col 49 | */ 50 | #define CONSOLE_SYSCALL_FUNCTION_GET_CURSOR 5 51 | 52 | /* low8:char */ 53 | #define CONSOLE_SYSCALL_FUNCTION_PUT_CHAR 6 54 | /* pointer to str */ 55 | #define CONSOLE_SYSCALL_FUNCTION_PUT_STR 7 56 | /* void */ 57 | #define CONSOLE_SYSCALL_FUNCTION_ROLL_SCREEN 8 58 | 59 | /* low16: pos */ 60 | #define CONSOLE_SYSCALL_FUNCTION_GET_CHAR 9 61 | 62 | /* 63 | 在一定y范围内滚屏 64 | high8(low16): beg 65 | low8(low16) : end 66 | */ 67 | #define CONSOLE_SYSCALL_FUNCTION_ROLL_SCREEN_BETWEEN 10 68 | 69 | /* 手动指定缓存内容 */ 70 | #define CONSOLE_SYSCALL_FUNCTION_SET_BUFFER_DATA 11 71 | 72 | /* 控制台系统系统调用功能号数量 */ 73 | #define CONSOLE_SYSCALL_FUNCTION_COUNT 12 74 | 75 | #endif /* TINY_OS_SHARD_SCREEN_H */ 76 | -------------------------------------------------------------------------------- /src/include/kernel/interrupt.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_INTERRUPT_H 2 | #define TINY_OS_INTERRUPT_H 3 | 4 | #include 5 | #include 6 | 7 | /* 0x20~0x2f号中断为8259A所用 */ 8 | 9 | #define IDT_DESC_COUNT 0x81 10 | 11 | #define INTR_NUMBER_DIVIDE_ERROR 0 12 | #define INTR_NUMBER_DEBUG 1 13 | #define INTR_NUMBER_NMI 2 14 | #define INTR_NUMBER_BREAKPOINT 3 15 | #define INTR_NUMBER_INT_OVERFLOW 4 16 | #define INTR_NUMBER_BOUND_OUT 5 17 | #define INTR_NUMBER_UNDEFINED_INSTR 6 18 | #define INTR_NUMBER_DEVICE_NOT_AVAILABLE 7 19 | #define INTR_NUMBER_DOUBLE_FAULT 8 20 | #define INTR_NUMBER_NO_FLOAT_PROC 9 21 | #define INTR_NUMBER_INVALID_TSS 10 22 | #define INTR_NUMBER_SEG_NOT_P 11 23 | #define INTR_NUMBER_STK_SEG_FAULT 12 24 | #define INTR_NUMBER_GENERAL_PROTECTION 13 25 | #define INTR_NUMBER_PAGE_FAULT 14 26 | /* 15 reserved */ 27 | #define INTR_NUMBER_FLOAT_ERROR 16 28 | #define INTR_NUMBER_ALIGNMENT_CHECK 17 29 | #define INTR_NUMBER_MACHINE_CHECK 18 30 | #define INTR_NUMBER_SIMD_FLOAT_EXCEPTION 19 31 | 32 | #define INTR_NUMBER_CLOCK 32 33 | #define INTR_NUMBER_KEYBOARD 33 34 | 35 | #define INTR_NUMBER_DISK 46 36 | 37 | /* 和linux一样,0x80号中断用作系统调用 */ 38 | #define INTR_NUMBER_SYSCALL 128 39 | 40 | void init_IDT(); 41 | 42 | /* 43 | 合法的intr_function签名包括 44 | void function(); 45 | void function(uint32_t intr_number); 46 | void function(uint32_t intr_number, uint32_t err_code); 47 | */ 48 | void set_intr_function(uint8_t intr_number, void (*func)()); 49 | 50 | /* 51 | 设置时钟中断频率 52 | */ 53 | void set_8253_freq(uint16_t freq); 54 | 55 | /* 关于中断的状态标志 */ 56 | typedef uint32_t intr_state; 57 | 58 | /* 标志中的中断是否打开 */ 59 | bool is_intr_on(intr_state state); 60 | 61 | /* 取得当前计算机所处的中断状态 */ 62 | intr_state get_intr_state(); 63 | 64 | /* 设置中断状态 */ 65 | void set_intr_state(intr_state state); 66 | 67 | /* 关中断并取得中断状态 */ 68 | intr_state fetch_and_disable_intr(); 69 | 70 | /* 开中断并取得开之前的中断状态 */ 71 | intr_state fetch_and_enable_intr(); 72 | 73 | #endif /* TINY_OS_INTERRUPT_H */ 74 | -------------------------------------------------------------------------------- /src/include/kernel/filesys/filesys.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_FILESYS_FILESYS_H 2 | #define TINY_OS_FILESYS_FILESYS_H 3 | 4 | #include 5 | #include 6 | 7 | void init_filesys(); 8 | 9 | void destroy_filesys(); 10 | 11 | /* (只读模式)打开一个文件 */ 12 | file_handle kopen_regular_reading(filesys_dp_handle dp, const char *path, 13 | enum filesys_opr_result *rt); 14 | 15 | /* 以写模式打开一个文件 */ 16 | file_handle kopen_regular_writing(filesys_dp_handle dp, const char *path, 17 | enum filesys_opr_result *rt); 18 | 19 | /* 获知一个目录下有多少文件 */ 20 | uint32_t kget_child_file_count(filesys_dp_handle dp, const char *path, 21 | enum filesys_opr_result *rt); 22 | 23 | /* 取得某目录下第idx个文件的信息 */ 24 | enum filesys_opr_result kget_child_file_info(filesys_dp_handle dp, const char *path, uint32_t idx, 25 | struct syscall_filesys_file_info *info); 26 | 27 | /* 关闭一个文件 */ 28 | enum filesys_opr_result kclose_file(filesys_dp_handle dp, file_handle file); 29 | 30 | /* 创建一个空文件 */ 31 | enum filesys_opr_result kmake_regular(filesys_dp_handle dp, const char *path); 32 | 33 | /* 删除一个文件 */ 34 | enum filesys_opr_result kremove_regular(filesys_dp_handle dp, const char *path); 35 | 36 | /* 创建一个空目录 */ 37 | enum filesys_opr_result kmake_directory(filesys_dp_handle dp, const char *path); 38 | 39 | /* 删除一个空目录 */ 40 | enum filesys_opr_result kremove_directory(filesys_dp_handle dp, const char *path); 41 | 42 | /* 取得一个文件的字节数 */ 43 | uint32_t kget_regular_size(filesys_dp_handle dp, file_handle file); 44 | 45 | /* 46 | 向一个常规文件写入二进制内容 47 | 设文件大小为file_size,则写入合法当且仅当 48 | fpos <= file_size 49 | */ 50 | enum filesys_opr_result kwrite_to_regular( 51 | filesys_dp_handle dp, file_handle file, 52 | uint32_t fpos, uint32_t size, 53 | const void *data); 54 | 55 | /* 从常规文件中读二进制内容 */ 56 | enum filesys_opr_result kread_from_regular( 57 | filesys_dp_handle dp, file_handle file, 58 | uint32_t fpos, uint32_t size, 59 | void *data); 60 | 61 | #endif /* TINY_OS_FILESYS_FILESYS_H */ 62 | -------------------------------------------------------------------------------- /src/shared/atrc.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define ATRC_ELEM_USED (-2) 4 | 5 | #define IDX_FIELD(S) (*(uint32_t*)((uint32_t)(S) - 4)) 6 | 7 | void init_atrc(struct atrc *a, size_t elem_size, 8 | void *data_zone, size_t data_zone_size) 9 | { 10 | uint32_t end = data_zone_size / elem_size; 11 | 12 | a->fst_avl_idx = (end ? 0 : ATRC_ELEM_HANDLE_NULL); 13 | a->data = data_zone; 14 | a->total_size = (int32_t)end; 15 | 16 | char *d = (char*)data_zone + 4; 17 | for(size_t i = 0; i + 1 < end; ++i) 18 | { 19 | IDX_FIELD(d) = i + 1; 20 | d += elem_size; 21 | } 22 | IDX_FIELD(d) = ATRC_ELEM_HANDLE_NULL; 23 | } 24 | 25 | bool is_atrc_unit_valid(struct atrc *a, size_t elem_size, atrc_elem_handle unit) 26 | { 27 | return 0 <= unit && unit < a->total_size && 28 | get_atrc_unit_idxfield(a, elem_size, unit) == ATRC_ELEM_USED; 29 | } 30 | 31 | uint32_t get_atrc_unit_idxfield(struct atrc *a, size_t elem_size, atrc_elem_handle unit) 32 | { 33 | return IDX_FIELD(get_atrc_unit(a, elem_size, unit)); 34 | } 35 | 36 | atrc_elem_handle alloc_atrc_unit(struct atrc *a, size_t elem_size) 37 | { 38 | if(is_atrc_full(a)) 39 | return ATRC_ELEM_HANDLE_NULL; 40 | 41 | atrc_elem_handle ret = a->fst_avl_idx; 42 | void *unit = get_atrc_unit(a, elem_size, ret); 43 | a->fst_avl_idx = IDX_FIELD(unit); 44 | IDX_FIELD(unit) = ATRC_ELEM_USED; 45 | 46 | return ret; 47 | } 48 | 49 | void free_atrc_unit(struct atrc *a, size_t elem_size, atrc_elem_handle unit) 50 | { 51 | void *u = get_atrc_unit(a, elem_size, unit); 52 | IDX_FIELD(u) = a->fst_avl_idx; 53 | a->fst_avl_idx = unit; 54 | } 55 | 56 | atrc_elem_handle atrc_begin(struct atrc *a, size_t elem_size) 57 | { 58 | for(atrc_elem_handle i = 0; i < a->total_size; ++i) 59 | { 60 | if(IDX_FIELD(get_atrc_unit(a, elem_size, i)) == ATRC_ELEM_USED) 61 | return i; 62 | } 63 | return atrc_end(); 64 | } 65 | 66 | atrc_elem_handle atrc_next(struct atrc *a, size_t elem_size, atrc_elem_handle unit) 67 | { 68 | for(atrc_elem_handle i = unit + 1; i < a->total_size; ++i) 69 | { 70 | if(IDX_FIELD(get_atrc_unit(a, elem_size, i)) == ATRC_ELEM_USED) 71 | return i; 72 | } 73 | return atrc_end(); 74 | } 75 | -------------------------------------------------------------------------------- /src/applications/file/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | int main(int argc, char *argv[]) 10 | { 11 | if(argc < 2 || argc > 3) 12 | { 13 | printf("%LUsage: mf filename [n]"); 14 | return -1; 15 | } 16 | 17 | bool no_retry = (argc == 3) && strcmp(argv[2], "n") == 0; 18 | 19 | filesys_dp_handle dp; 20 | char *path = malloc_and_cat_path(argv[0], argv[1], &dp); 21 | if(!path) 22 | { 23 | printf("%LInvalid argument: %s", argv[1]); 24 | return -1; 25 | } 26 | 27 | usr_file_handle fp; 28 | enum filesys_opr_result frt; 29 | 30 | while(true) 31 | { 32 | frt = remove_file(dp, path); 33 | if(frt == filesys_opr_not_found) 34 | break; 35 | if(frt != filesys_opr_locked || no_retry) 36 | { 37 | printf("%LFailed to remove existing file: %u:%s, err = %u", 38 | dp, path, frt); 39 | return -1; 40 | } 41 | yield_cpu(); 42 | } 43 | 44 | while((frt = make_file(dp, path)) != filesys_opr_success) 45 | { 46 | if(frt != filesys_opr_locked || no_retry) 47 | { 48 | printf("%LFailed to create existing file: %u:%s, err = %u", 49 | dp, path, frt); 50 | return -1; 51 | } 52 | yield_cpu(); 53 | } 54 | 55 | while((frt = open_file(dp, path, true, &fp)) != filesys_opr_success) 56 | { 57 | if(frt != filesys_opr_locked || no_retry) 58 | { 59 | printf("%LFailed to open existing file: %u:%s, err = %u", 60 | dp, path, frt); 61 | return -1; 62 | } 63 | yield_cpu(); 64 | } 65 | 66 | #define BUF_SIZE 128 67 | 68 | uint32_t fpos = 0; 69 | char buf[BUF_SIZE]; int idx = 0; 70 | 71 | char ch; 72 | while((ch = get_char())) 73 | { 74 | buf[idx++] = ch; 75 | if(idx >= BUF_SIZE) 76 | { 77 | write_file(fp, fpos, BUF_SIZE, buf); 78 | fpos += BUF_SIZE; 79 | idx = 0; 80 | } 81 | } 82 | 83 | if(idx) 84 | write_file(fp, fpos, idx, buf); 85 | 86 | close_file(fp); 87 | free(path); 88 | } 89 | -------------------------------------------------------------------------------- /src/kernel/sysmsg/sysmsg.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | /* 消息队列容量 */ 11 | #define SYSMSG_QUEUE_MAX_SIZE (4096 / sizeof(struct sysmsg)) 12 | 13 | void init_sysmsg() 14 | { 15 | // 暂时没啥好做的…… 16 | } 17 | 18 | void init_sysmsg_queue(struct sysmsg_queue *queue) 19 | { 20 | ASSERT(queue); 21 | queue->msgs = (struct sysmsg*)alloc_ker_page(false); 22 | queue->head = 0; 23 | queue->tail = 0; 24 | queue->size = 0; 25 | } 26 | 27 | void destroy_sysmsg_queue(struct sysmsg_queue *queue) 28 | { 29 | ASSERT(queue); 30 | free_ker_page(queue->msgs); 31 | } 32 | 33 | bool send_sysmsg(struct sysmsg_queue *queue, const struct sysmsg *msg) 34 | { 35 | ASSERT(queue && msg); 36 | 37 | if(queue->size >= SYSMSG_QUEUE_MAX_SIZE) 38 | return false; 39 | 40 | memcpy((char*)&queue->msgs[queue->tail], (char*)msg, sizeof(struct sysmsg)); 41 | queue->tail = (queue->tail + 1) % SYSMSG_QUEUE_MAX_SIZE; 42 | ++queue->size; 43 | 44 | // 唤醒被消息队列阻塞的线程 45 | struct PCB *pcb = GET_STRUCT_FROM_MEMBER(struct PCB, sys_msgs, queue); 46 | if(pcb->sysmsg_blocked_tcb) 47 | { 48 | awake_thread(pcb->sysmsg_blocked_tcb); 49 | pcb->sysmsg_blocked_tcb = NULL; 50 | } 51 | 52 | return true; 53 | } 54 | 55 | bool is_sysmsg_queue_empty(const struct sysmsg_queue *queue) 56 | { 57 | ASSERT(queue); 58 | return queue->size == 0; 59 | } 60 | 61 | bool is_sysmsg_queue_full(const struct sysmsg_queue *queue) 62 | { 63 | ASSERT(queue); 64 | return queue->size >= SYSMSG_QUEUE_MAX_SIZE; 65 | } 66 | 67 | const struct sysmsg *fetch_sysmsg_queue_front(const struct sysmsg_queue *queue) 68 | { 69 | ASSERT(queue); 70 | return queue->size == 0 ? NULL : &queue->msgs[queue->head]; 71 | } 72 | 73 | bool pop_sysmsg_queue_front(struct sysmsg_queue *queue, struct sysmsg *output) 74 | { 75 | ASSERT(queue && output); 76 | 77 | if(queue->size == 0) 78 | return false; 79 | 80 | memcpy((char*)output, (char*)&queue->msgs[queue->head], sizeof(struct sysmsg)); 81 | queue->head = (queue->head + 1) % SYSMSG_QUEUE_MAX_SIZE; 82 | --queue->size; 83 | 84 | return true; 85 | } 86 | -------------------------------------------------------------------------------- /src/kernel/explorer/cmds/exec.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | static bool expl_exec_impl(filesys_dp_handle dp, const char *working_dir, 13 | const char *dst, const char *proc_name, 14 | const char **args, uint32_t args_cnt, bool pa, 15 | uint32_t *_pid) 16 | { 17 | const char *arg_working_dir = working_dir; 18 | if(pa) 19 | working_dir = "/apps"; 20 | 21 | if(strcmp(proc_name, "`") == 0) 22 | proc_name = dst; 23 | 24 | // 路径缓存 25 | char *path_buf = (char*)alloc_ker_page(false); 26 | 27 | #define DP_STR_BUF_SIZE 2048 28 | #define DP_STR_OFFSET (4096 - DP_STR_BUF_SIZE) 29 | 30 | // 用来传递的实际参数数组,在原参数数组前面缀上一个工作目录 31 | const char *targs[args_cnt + 1]; 32 | 33 | uint32_t dst_dp; 34 | if(!cat_path_ex_s(dp, working_dir, dst, 35 | &dst_dp, path_buf, DP_STR_OFFSET)) 36 | goto FAILED; 37 | 38 | uint32_t pid; 39 | 40 | char *arg_cur_buf = path_buf + DP_STR_OFFSET; 41 | uint32_to_str(dst_dp, arg_cur_buf); 42 | strcat(arg_cur_buf, ":"); 43 | strcat(arg_cur_buf, arg_working_dir); 44 | 45 | // 填充实际参数数组 46 | targs[0] = arg_cur_buf; 47 | for(uint32_t i = 1; i <= args_cnt; ++i) 48 | targs[i] = args[i - 1]; 49 | 50 | enum exec_elf_result rt = exec_elf( 51 | proc_name, dst_dp, path_buf, false, args_cnt + 1, targs, &pid); 52 | 53 | if(rt != exec_elf_success) 54 | goto FAILED; 55 | 56 | if(_pid) 57 | *_pid = pid; 58 | 59 | free_ker_page(path_buf); 60 | return true; 61 | 62 | FAILED: 63 | 64 | free_ker_page(path_buf); 65 | if(!pa) 66 | return expl_exec_impl(0, working_dir, dst, proc_name, args, args_cnt, true, _pid); 67 | return false; 68 | } 69 | 70 | bool expl_exec(filesys_dp_handle dp, const char *working_dir, 71 | const char *dst, const char *proc_name, const char **args, uint32_t args_cnt, 72 | uint32_t *_pid) 73 | { 74 | return expl_exec_impl(dp, working_dir, dst, proc_name, args, args_cnt, false, _pid); 75 | } 76 | -------------------------------------------------------------------------------- /src/tools/disk_ipt/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | extern "C" 13 | { 14 | #define TINY_OS_NO_INTDEF 15 | #include 16 | } 17 | 18 | using namespace std; 19 | 20 | int main(int argc, char *argv[]) 21 | { 22 | if(argc < 4 || (argc - 2) % 2 == 1) 23 | { 24 | cout << "Usage: disk_ipt disk_img [filename1 dstname1] ..." << endl; 25 | return -1; 26 | } 27 | 28 | // 打开临时输出文件 29 | ofstream tout("disk_ipt_tmp", ofstream::out | ofstream::binary); 30 | 31 | uint32_t file_count = (argc - 2) / 2; 32 | tout.write((const char*)&file_count, sizeof(uint32_t)); 33 | 34 | // 写入临时文件的总字节数 35 | size_t total_byte_size = sizeof(uint32_t); 36 | 37 | for(int i = 2; i < argc; i += 2) 38 | { 39 | // 读取文件所有内容 40 | 41 | ifstream fin(argv[i], ifstream::in | ifstream::binary); 42 | if(!fin) 43 | { 44 | cout << "Failed to open file " << argv[i] << endl; 45 | return -1; 46 | } 47 | 48 | fin.seekg(0, ios::end); 49 | vector data(fin.tellg()); 50 | 51 | fin.seekg(0, ios::beg); 52 | fin.read(data.data(), data.size()); 53 | 54 | fin.close(); 55 | 56 | // 写入目标分区号 57 | uint32_t dp = 0; 58 | tout.write((const char*)&dp, sizeof(uint32_t)); 59 | 60 | // 写入目标路径 61 | tout.write(argv[i + 1], IPT_PATH_BUF_SIZE); 62 | 63 | // 写入目标文件大小 64 | uint32_t file_size = data.size(); 65 | tout.write((const char*)&file_size, sizeof(uint32_t)); 66 | 67 | // 写入目标文件内容 68 | tout.write((const char*)data.data(), data.size()); 69 | 70 | total_byte_size += sizeof(uint32_t) * 2 + IPT_PATH_BUF_SIZE 71 | + data.size(); 72 | } 73 | 74 | tout.close(); 75 | 76 | uint32_t sec_cnt = total_byte_size / 512 + 77 | (total_byte_size % 512 ? 1 : 0); 78 | 79 | stringstream sst; 80 | sst << "dd if=disk_ipt_tmp of=" << argv[1] << " bs=512 count=" 81 | << sec_cnt << " seek=" << to_string(DISK_IMPORT_DP_BEGIN) 82 | << " conv=notrunc"; 83 | system(sst.str().c_str()); 84 | system("rm -f disk_ipt_tmp"); 85 | 86 | cout << "Import dp inited" << endl; 87 | } 88 | -------------------------------------------------------------------------------- /src/kernel/explorer/cmds/cd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | bool expl_cd(filesys_dp_handle *dp, char *cur, 13 | uint32_t max_len, const char *dst) 14 | { 15 | // 申请一块缓冲区作为dst缓冲 16 | char *cur_tmp = (char*)alloc_ker_page(false); 17 | char *dp_name_buf = cur_tmp + max_len; 18 | 19 | // 目标是带分区号的绝对路径 20 | if(is_path_containning_dp(dst)) 21 | { 22 | // 获取分区编号 23 | uint32_t dp_name_len = get_dp_from_path_s( 24 | dst, dp_name_buf, DP_NAME_BUF_SIZE); 25 | 26 | if(!dp_name_len) 27 | goto FAILED; 28 | 29 | uint32_t new_dp; 30 | 31 | // 是数字形式的分区号 32 | if(dp_name_buf[dp_name_len - 1] == ':') 33 | { 34 | dp_name_buf[dp_name_len - 1] = '\0'; 35 | if(!str_to_uint32(dp_name_buf, &new_dp)) 36 | goto FAILED; 37 | } 38 | else // 是分区名 39 | { 40 | ASSERT(dp_name_buf[dp_name_len - 1] == '>'); 41 | 42 | dp_name_buf[dp_name_len - 1] = '\0'; 43 | new_dp = get_dp_handle_by_name(dp_name_buf); 44 | if(new_dp >= DPT_UNIT_COUNT) 45 | goto FAILED; 46 | } 47 | 48 | if(!cat_path_s(cur, skip_dp_in_abs_path(dst), 49 | cur_tmp, max_len)) 50 | goto FAILED; 51 | 52 | if(get_child_file_count(new_dp, cur_tmp, NULL) 53 | != filesys_opr_success) 54 | goto FAILED; 55 | 56 | strcpy(cur, cur_tmp); 57 | *dp = new_dp; 58 | 59 | goto SUCCEED; 60 | } 61 | 62 | // 目标不带分区,尝试拼接路径 63 | if(!cat_path_s(cur, dst, cur_tmp, max_len)) 64 | goto FAILED; 65 | if(get_child_file_count(*dp, cur_tmp, NULL) != filesys_opr_success) 66 | goto FAILED; 67 | 68 | strcpy(cur, cur_tmp); 69 | 70 | goto SUCCEED; 71 | 72 | FAILED: 73 | 74 | free_ker_page(cur_tmp); 75 | disp_printf("Invalid cd destination: %s", dst); 76 | return false; 77 | 78 | SUCCEED: 79 | 80 | compress_path(cur); 81 | free_ker_page(cur_tmp); 82 | disp_printf("Current working directory: %u:%s", 83 | *dp, cur); 84 | return true; 85 | } 86 | -------------------------------------------------------------------------------- /src/kernel/sysmsg/sysmsg_syscall.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | static uint32_t (*functions[SYSMSG_SYSCALL_FUNCTION_COUNT])(uint32_t, uint32_t); 13 | 14 | static uint32_t proc_sysmsg_syscall_is_empty(uint32_t a, uint32_t b) 15 | { 16 | return is_sysmsg_queue_empty(&get_cur_TCB()->pcb->sys_msgs); 17 | } 18 | 19 | static uint32_t proc_sysmsg_syscall_peek_msg(uint32_t opr, uint32_t output) 20 | { 21 | struct sysmsg *msg = (struct sysmsg*)output; 22 | if(!msg) 23 | return false; 24 | 25 | struct sysmsg_queue *queue = &get_cur_TCB()->pcb->sys_msgs; 26 | if(is_sysmsg_queue_empty(queue)) 27 | return false; 28 | 29 | if(opr & SYSMSG_SYSCALL_PEEK_OPERATION_REMOVE) 30 | pop_sysmsg_queue_front(queue, msg); 31 | else 32 | memcpy((char*)msg, (char*)fetch_sysmsg_queue_front(queue), sizeof(struct sysmsg)); 33 | 34 | return true; 35 | } 36 | 37 | static uint32_t proc_sysmsg_syscall_register_kbmsg(uint32_t a, uint32_t b) 38 | { 39 | subscribe_kb(get_cur_TCB()->pcb); 40 | return 0; 41 | } 42 | 43 | static uint32_t proc_sysmsg_syscall_register_charmsg(uint32_t a, uint32_t b) 44 | { 45 | subscribe_char(get_cur_TCB()->pcb); 46 | return 0; 47 | } 48 | 49 | static uint32_t proc_sysmsg_syscall_block_onto_sysmsg(uint32_t a, uint32_t b) 50 | { 51 | if(get_cur_PCB()->sys_msgs.size) 52 | return 0; 53 | block_cur_thread_onto_sysmsg(); 54 | return 0; 55 | } 56 | 57 | void init_sysmsg_syscall() 58 | { 59 | functions[SYSMSG_SYSCALL_FUNCTION_IS_EMPTY] = 60 | proc_sysmsg_syscall_is_empty; 61 | functions[SYSMSG_SYSCALL_FUNCTION_PEEK_MSG] = 62 | proc_sysmsg_syscall_peek_msg; 63 | functions[SYSMSG_SYSCALL_FUNCTION_REGISTER_KEYBOARD_MSG] = 64 | proc_sysmsg_syscall_register_kbmsg; 65 | functions[SYSMSG_SYSCALL_FUNCTION_REGISTER_CHAR_MSG] = 66 | proc_sysmsg_syscall_register_charmsg; 67 | functions[SYSMSG_SYSCALL_FUNCTION_BLOCK_ONTO_SYSMSG] = 68 | proc_sysmsg_syscall_block_onto_sysmsg; 69 | } 70 | 71 | uint32_t syscall_sysmsg_impl(uint32_t func, uint32_t arg1, uint32_t arg2) 72 | { 73 | if(func >= SYSMSG_SYSCALL_FUNCTION_COUNT) 74 | return 0; 75 | return functions[func](arg1, arg2); 76 | } 77 | -------------------------------------------------------------------------------- /src/include/kernel/asm.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_IO_PORT 2 | #define TINY_OS_IO_PORT 3 | 4 | #include 5 | #include 6 | 7 | static inline uint8_t _in_byte_from_port(uint16_t port) 8 | { 9 | uint8_t rt; 10 | asm volatile ("in %1, %0" : "=a" (rt) : "d" (port)); 11 | return rt; 12 | } 13 | 14 | static inline void _in_words_from_port(uint16_t port, void *dst, size_t wcnt) 15 | { 16 | asm volatile ("cld; rep insw" : "+D" (dst), "+c" (wcnt) : "d" (port) : "memory"); 17 | } 18 | 19 | static inline void _out_byte_to_port(uint16_t port, uint8_t data) 20 | { 21 | asm volatile ("out %0, %1" : : "a" (data), "d" (port)); 22 | } 23 | 24 | static inline void _out_double_byte_to_port(uint16_t port, uint16_t data) 25 | { 26 | asm volatile ("out %0, %1" : : "a" (data), "d" (port)); 27 | } 28 | 29 | static inline void _out_words_to_port(uint16_t port, const void *dst, uint32_t wcnt) 30 | { 31 | asm volatile ("cld; rep outsw" : "+S" (dst), "+c" (wcnt) : "d" (port)); 32 | } 33 | 34 | static inline void _load_IDT(uint64_t arg) 35 | { 36 | asm volatile ("lidt %0" : : "m" (arg)); 37 | } 38 | 39 | static inline void _enable_intr() 40 | { 41 | asm volatile ("sti"); 42 | } 43 | 44 | static inline void _disable_intr() 45 | { 46 | asm volatile ("cli"); 47 | } 48 | 49 | static inline void _load_cr3(uint32_t val) 50 | { 51 | asm volatile ("movl %0, %%cr3" : : "r" (val) : "memory"); 52 | } 53 | 54 | static inline void _refresh_vir_addr_in_TLB(uint32_t vir_addr) 55 | { 56 | asm volatile ("invlpg %0" : : "m" (vir_addr) : "memory"); 57 | } 58 | 59 | static inline uint32_t _get_cr2() 60 | { 61 | uint32_t rt; 62 | asm volatile ("movl %%cr2, %0" : "=r" (rt)); 63 | return rt; 64 | } 65 | 66 | static inline uint32_t _get_cr3() 67 | { 68 | uint32_t rt; 69 | asm volatile ("movl %%cr3, %0" : "=r" (rt)); 70 | return rt; 71 | } 72 | 73 | static inline uint32_t _get_esp() 74 | { 75 | uint32_t rt; 76 | asm volatile ("movl %%esp, %0" : "=r" (rt)); 77 | return rt; 78 | } 79 | 80 | static inline uint32_t _get_eflag() 81 | { 82 | uint32_t rt; 83 | asm volatile ("pushfl; popl %0" : "=g" (rt)); 84 | return rt; 85 | } 86 | 87 | static inline void _load_GDT(uint32_t base, uint32_t size) 88 | { 89 | uint64_t opr = ((uint64_t)base << 16) | size; 90 | asm volatile ("lgdt %0" : : "m" (opr)); 91 | } 92 | 93 | static inline void _ltr(uint16_t sel) 94 | { 95 | asm volatile ("ltr %w0" : : "r" (sel)); 96 | } 97 | 98 | #endif /* TINY_OS_IO_PORT */ 99 | -------------------------------------------------------------------------------- /src/shared/ptrlist.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void init_rlist(rlist *L) 5 | { 6 | L->last = L->next = (struct rlist_node*)L; 7 | } 8 | 9 | void push_back_rlist(rlist *L, void *ptr, rlist_node_allocator node_alloc) 10 | { 11 | struct rlist_node *new_node = node_alloc(); 12 | 13 | new_node->ptr = ptr; 14 | new_node->next = (struct rlist_node*)L; 15 | new_node->last = L->last; 16 | 17 | L->last->next = new_node; 18 | L->last = new_node; 19 | } 20 | 21 | void *pop_back_rlist(rlist *L, rlist_node_deallocator node_dealloc) 22 | { 23 | if(is_rlist_empty(L)) 24 | return NULL; 25 | 26 | void *rt = L->last->ptr; 27 | struct rlist_node *back_last = L->last->last; 28 | back_last->next = (struct rlist_node*)L; 29 | node_dealloc(L->last); 30 | L->last = back_last; 31 | 32 | return rt; 33 | } 34 | 35 | void push_front_rlist(rlist *L, void *ptr, rlist_node_allocator node_alloc) 36 | { 37 | struct rlist_node *new_node = node_alloc(); 38 | 39 | new_node->ptr = ptr; 40 | new_node->next = L->next; 41 | new_node->last = (struct rlist_node*)L; 42 | 43 | L->next->last = new_node; 44 | L->next = new_node; 45 | } 46 | 47 | void *pop_front_rlist(rlist *L, rlist_node_deallocator node_dealloc) 48 | { 49 | if(is_rlist_empty(L)) 50 | return NULL; 51 | 52 | void *rt = L->next->ptr; 53 | struct rlist_node *front_next = L->next->next; 54 | front_next->last = (struct rlist_node*)L; 55 | node_dealloc(L->next); 56 | L->next = front_next; 57 | 58 | return rt; 59 | } 60 | 61 | void *back_rlist(rlist *L) 62 | { 63 | return is_rlist_empty(L) ? NULL : L->last->ptr; 64 | } 65 | 66 | void *front_rlist(rlist *L) 67 | { 68 | return is_rlist_empty(L) ? NULL : L->next->ptr; 69 | } 70 | 71 | bool is_rlist_empty(rlist *L) 72 | { 73 | return L->last == (struct rlist_node*)L; 74 | } 75 | 76 | void init_ilist(ilist *L) 77 | { 78 | L->last = L->next = L; 79 | } 80 | 81 | void push_back_ilist(ilist *L, struct ilist_node *node) 82 | { 83 | node->last = L->last; 84 | node->next = L; 85 | L->last->next = node; 86 | L->last = node; 87 | } 88 | 89 | struct ilist_node *pop_front_ilist(ilist *L) 90 | { 91 | if(is_ilist_empty(L)) 92 | return NULL; 93 | struct ilist_node *rt = L->next; 94 | rt->next->last = L; 95 | L->next = rt->next; 96 | rt->last = rt->next = NULL; 97 | return rt; 98 | } 99 | 100 | bool is_ilist_empty(ilist *L) 101 | { 102 | return L->next == L; 103 | } 104 | 105 | void erase_from_ilist(struct ilist_node *node) 106 | { 107 | node->last->next = node->next; 108 | node->next->last = node->last; 109 | node->last = node->next = NULL; 110 | } 111 | -------------------------------------------------------------------------------- /src/kernel/sysmsg/sysmsg_src.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | /* 用来分配sysmsg_rcv_src_list_node的自由链表 */ 11 | static freelist_handle sysmsg_rcv_src_list_node_freelist; 12 | 13 | struct sysmsg_rcv_src_list_node *alloc_sysmsg_rcv_src_list_node() 14 | { 15 | if(is_freelist_empty(&sysmsg_rcv_src_list_node_freelist)) 16 | { 17 | struct sysmsg_rcv_src_list_node *new_nodes = 18 | (struct sysmsg_rcv_src_list_node *)alloc_ker_page(false); 19 | for(size_t i = 0;i < 4096 / sizeof(struct sysmsg_rcv_src_list_node); ++i) 20 | add_freelist(&sysmsg_rcv_src_list_node_freelist, 21 | &new_nodes[i]); 22 | } 23 | return fetch_freelist(&sysmsg_rcv_src_list_node_freelist); 24 | } 25 | 26 | void destroy_sysmsg_receiver_list(struct sysmsg_receiver_list *L) 27 | { 28 | ASSERT(L); 29 | 30 | while(!is_ilist_empty(&L->processes)) 31 | { 32 | struct ilist_node *ori_node = pop_front_ilist(&L->processes); 33 | struct sysmsg_rcv_src_list_node *dst_node = 34 | GET_STRUCT_FROM_MEMBER(struct sysmsg_rcv_src_list_node, 35 | rcv_node, ori_node); 36 | erase_from_ilist(&dst_node->src_node); 37 | add_freelist(&sysmsg_rcv_src_list_node_freelist, dst_node); 38 | } 39 | } 40 | 41 | void destroy_sysmsg_source_list(struct sysmsg_source_list *L) 42 | { 43 | ASSERT(L); 44 | 45 | while(!is_ilist_empty(&L->sources)) 46 | { 47 | struct ilist_node *ori_node = pop_front_ilist(&L->sources); 48 | struct sysmsg_rcv_src_list_node *dst_node = 49 | GET_STRUCT_FROM_MEMBER(struct sysmsg_rcv_src_list_node, 50 | src_node, ori_node); 51 | erase_from_ilist(&dst_node->rcv_node); 52 | add_freelist(&sysmsg_rcv_src_list_node_freelist, dst_node); 53 | } 54 | } 55 | 56 | void send_msg_to_procs(struct sysmsg_receiver_list *rcv, const struct sysmsg *msg, bool (*mask_func)(const struct PCB*)) 57 | { 58 | for(struct ilist_node *n = rcv->processes.next; 59 | n != &rcv->processes; n = n->next) 60 | { 61 | struct PCB *pcb = GET_STRUCT_FROM_MEMBER(struct sysmsg_rcv_src_list_node, 62 | rcv_node, n)->pcb; 63 | if(mask_func(pcb)) 64 | send_sysmsg(&pcb->sys_msgs, msg); 65 | } 66 | } 67 | 68 | void register_sysmsg_source(struct PCB *pcb, 69 | struct sysmsg_receiver_list *rcv, 70 | struct sysmsg_source_list *src) 71 | { 72 | ASSERT(rcv && src); 73 | 74 | struct sysmsg_rcv_src_list_node *node = alloc_sysmsg_rcv_src_list_node(); 75 | push_back_ilist(&rcv->processes, &node->rcv_node); 76 | push_back_ilist(&src->sources, &node->src_node); 77 | node->pcb = pcb; 78 | } 79 | -------------------------------------------------------------------------------- /src/include/kernel/filesys/afs/file.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_FILESYS_AFS_FILE_H 2 | #define TINY_OS_FILESYS_AFS_FILE_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | /* 一个打开的文件槽句柄 */ 11 | struct afs_file_desc; 12 | 13 | void init_afs_file(); 14 | 15 | /* 在磁盘上创建一个大小为0的空文件,返回entry index */ 16 | uint32_t afs_create_empty_file( 17 | struct afs_dp_head *head, 18 | uint32_t type, 19 | enum afs_file_operation_status *rt); 20 | 21 | /* 在磁盘上删除一个文件并释放其entry */ 22 | void afs_remove_file(struct afs_dp_head *head, 23 | uint32_t entry_idx, 24 | enum afs_file_operation_status *rt); 25 | 26 | /* 27 | 打开一个用于读的文件 28 | 成功时返回desc指针 29 | 若返回值为空,可检查rt指示的错误类型 30 | */ 31 | struct afs_file_desc *afs_open_file_for_reading( 32 | struct afs_dp_head *head, 33 | uint32_t entry_idx, 34 | enum afs_file_operation_status *rt); 35 | 36 | /* 打开一个可读写的文件 */ 37 | struct afs_file_desc *afs_open_file_for_writing( 38 | struct afs_dp_head *head, 39 | uint32_t entry_idx, 40 | enum afs_file_operation_status *rt); 41 | 42 | /* 尝试把一个以只读模式打开的文件转为以可读写模式打开,失败时返回false */ 43 | bool afs_convert_reading_to_writing(struct afs_dp_head *head, 44 | struct afs_file_desc *desc); 45 | 46 | /* 关闭一个以只读方式打开的文件 */ 47 | void afs_close_file_for_reading(struct afs_dp_head *head, 48 | struct afs_file_desc *file); 49 | 50 | /* 关闭一个可读写的文件 */ 51 | void afs_close_file_for_writing(struct afs_dp_head *head, 52 | struct afs_file_desc *file); 53 | 54 | /* 55 | 读某个文件中的二进制内容 56 | 当读取范围超出文件大小时会失败 57 | */ 58 | bool afs_read_binary(struct afs_dp_head *head, 59 | struct afs_file_desc *file, 60 | uint32_t fpos, uint32_t size, 61 | void *data, 62 | enum afs_file_operation_status *rt); 63 | 64 | /* 65 | 将二进制内容写入到某个文件 66 | 当文件大小不足时会失败 67 | */ 68 | bool afs_write_binary(struct afs_dp_head *head, 69 | struct afs_file_desc *file, 70 | uint32_t fpos, uint32_t bytes, 71 | const void *data, 72 | enum afs_file_operation_status *rt); 73 | 74 | /* 扩充某个以可写方式打开的文件的大小,末尾扩充部分的内容为undefined */ 75 | bool afs_expand_file(struct afs_dp_head *head, 76 | struct afs_file_desc *file, 77 | uint32_t new_size, 78 | enum afs_file_operation_status *rt); 79 | 80 | /* 81 | 查看某个文件是否处于被打开的状态 82 | 一般由目录操作者调用,调用前最好把目录锁住 83 | */ 84 | bool afs_is_file_open(struct afs_dp_head *head, uint32_t entry); 85 | 86 | struct afs_file_entry *afs_extract_file_entry(struct afs_file_desc *desc); 87 | 88 | bool afs_is_file_wlocked(struct afs_file_desc *desc); 89 | 90 | #endif /* TINY_OS_FILESYS_AFS_FILE_H */ 91 | -------------------------------------------------------------------------------- /src/kernel/execelf/readelf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | /* 11 | IMPROVE:load_elf应该进行适当的合法性检查 12 | */ 13 | 14 | #define PT_LOAD 1 15 | 16 | #define EI_NIDENT 16 17 | 18 | #define ELF32_Addr uint32_t 19 | #define ELF32_Half uint16_t 20 | #define ELF32_Off uint32_t 21 | #define ELF32_SWord int32_t 22 | #define ELF32_Word uint32_t 23 | 24 | typedef struct { 25 | unsigned char e_ident[EI_NIDENT]; 26 | ELF32_Half e_type; 27 | ELF32_Half e_machine; 28 | ELF32_Word e_version; 29 | ELF32_Addr e_entry; // virtual address program entry 30 | ELF32_Off e_phoff; // program header offset 31 | ELF32_Off e_shoff; 32 | ELF32_Word e_flags; 33 | ELF32_Half e_ehsize; // elf header size 34 | ELF32_Half e_phentsize; // program header size 35 | ELF32_Half e_phnum; // program header numbers 36 | ELF32_Half e_shentsize; 37 | ELF32_Half e_shnum; 38 | ELF32_Half e_shstrndx; 39 | } elf32_ehdr; 40 | 41 | typedef struct { 42 | ELF32_Word p_type; // Only PT_LOAD need loading 43 | ELF32_Off p_offset; 44 | ELF32_Addr p_vaddr; 45 | ELF32_Addr p_paddr; 46 | ELF32_Word p_filesz; 47 | ELF32_Word p_memsz; 48 | ELF32_Word p_flags; 49 | ELF32_Word p_align; 50 | } elf32_phdr; 51 | 52 | void *load_elf(const void *_filestart, size_t *beg, size_t *end) 53 | { 54 | ASSERT(beg && end); 55 | size_t _beg = 0xffffffff, _end = 0; 56 | 57 | elf32_ehdr eh; 58 | const char *filestart = (const char *)_filestart; 59 | 60 | uint8_t magic_iden[EI_NIDENT] = { 0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01 }; 61 | 62 | int pos = 0; 63 | for (pos = 0; pos < EI_NIDENT; pos++) 64 | { 65 | eh.e_ident[pos] = *(filestart + pos); 66 | if(eh.e_ident[pos] != magic_iden[pos]) 67 | return NULL; 68 | } 69 | 70 | //initialize ELF header 71 | 72 | memcpy((char*)&eh, filestart, sizeof(eh)); 73 | pos += sizeof(eh); 74 | 75 | elf32_phdr header; 76 | pos = eh.e_phoff; 77 | for(uint16_t i = 0; i < eh.e_phnum; i++) 78 | { 79 | memcpy((char*)&header, filestart + pos, sizeof(header)); 80 | pos += sizeof(header); 81 | 82 | if(header.p_type != PT_LOAD) 83 | continue; 84 | 85 | memcpy((char*)header.p_vaddr, (const char *)(filestart + header.p_offset), 86 | header.p_filesz); 87 | if(header.p_memsz > header.p_filesz) 88 | { 89 | memset((char *)((char*)header.p_vaddr + header.p_filesz), 0x0, 90 | header.p_memsz - header.p_filesz); 91 | } 92 | 93 | _beg = MIN(_beg, header.p_vaddr); 94 | _end = MAX(_end, header.p_vaddr + header.p_memsz); 95 | } 96 | 97 | *beg = _beg, *end = _end; 98 | return (void*)eh.e_entry; 99 | } 100 | -------------------------------------------------------------------------------- /src/include/kernel/process/thread.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_THREAD_H 2 | #define TINY_OS_THREAD_H 3 | 4 | #include 5 | #include 6 | 7 | /* 操作实现在spinlock.h中,TCB要用这个所以提前声明在这了…… */ 8 | typedef volatile uint32_t spinlock; 9 | 10 | /* process control block */ 11 | struct PCB; 12 | 13 | struct semaphore; 14 | 15 | /* 线程状态:运行,就绪,阻塞 */ 16 | enum thread_state 17 | { 18 | thread_state_running, 19 | thread_state_ready, 20 | thread_state_blocked, 21 | thread_state_killed 22 | }; 23 | 24 | /* 25 | thread control block 26 | 并不是task control block 27 | */ 28 | struct TCB 29 | { 30 | // 每个线程都持有一个内核栈 31 | // 在“低特权级 -> 高特权级”以及刚进入线程时会用到 32 | void *ker_stack; 33 | 34 | // 初始内核栈 35 | void *init_ker_stack; 36 | 37 | enum thread_state state; 38 | 39 | struct PCB *pcb; 40 | 41 | // 一个线程可能被阻塞在某个信号量上 42 | struct semaphore *blocked_sph; 43 | 44 | // 各种侵入式链表的节点 45 | 46 | struct ilist_node ready_block_threads_node; //就绪线程队列、信号量阻塞队列 47 | struct ilist_node threads_in_proc_node; // 每个进程的线程表 48 | 49 | // 线程销毁标记 50 | // 用于保护特定的系统调用不因线程销毁而被打断 51 | spinlock syscall_protector_lock; 52 | uint32_t syscall_protector_count; 53 | bool thread_kill_flag; 54 | }; 55 | 56 | /* 57 | 用来创建新内核线程时的函数入口 58 | void*用于参数传递 59 | */ 60 | typedef void (*thread_exec_func)(void*); 61 | 62 | /* 63 | 线程栈初始化时栈顶的内容 64 | 这个结构参考了真像还原一书 65 | 利用ret指令及其参数在栈中分布的特点来实现控制流跨线程跳转 66 | 可以统一第一次进入线程以及以后调度该线程时的操作 67 | */ 68 | struct thread_init_stack 69 | { 70 | // 由callee保持的寄存器 71 | uint32_t ebp, ebx, edi, esi; 72 | 73 | // 函数入口 74 | uint32_t eip; 75 | 76 | // 占位,因为需要一个返回地址的空间 77 | uint32_t dummy_addr; 78 | 79 | // 线程入口及参数 80 | thread_exec_func func; 81 | void *func_param; 82 | }; 83 | 84 | /* 初始化内核线程管理系统 */ 85 | void init_thread_man(); 86 | 87 | /* 创建新内核线程并加入调度 */ 88 | struct TCB *create_thread(thread_exec_func func, void *params, 89 | struct PCB *pcb); 90 | 91 | /* 取得当前线程的TCB */ 92 | struct TCB *get_cur_TCB(); 93 | 94 | /* 阻塞自己,注意系统不会维护阻塞线程 */ 95 | void block_cur_thread(); 96 | 97 | /* 将自己阻塞到进程消息队列上 */ 98 | void block_cur_thread_onto_sysmsg(); 99 | 100 | /* 唤醒一个blocked线程,将其变为ready */ 101 | void awake_thread(struct TCB *tcb); 102 | 103 | /* 干掉一个线程,若触发了延时销毁,返回false */ 104 | bool kill_thread(struct TCB *tcb); 105 | 106 | /* 107 | 每个线程结束的时候自己调用 108 | */ 109 | void kexit_thread(); 110 | 111 | /* 112 | 清理待释放的线程和进程资源 113 | */ 114 | void do_releasing_thds_procs(); 115 | 116 | /* 117 | 让出CPU,让自己进入ready队列 118 | 好人才会做的事 119 | */ 120 | void yield_CPU(); 121 | 122 | /* 进入系统调用保护模式,由可能被打断的系统调用实现负责调用 */ 123 | void thread_syscall_protector_entry(); 124 | 125 | /* 离开系统调用保护模式,由可能被打断的系统调用实现负责调用 */ 126 | void thread_syscall_protector_exit(); 127 | 128 | /* 129 | 临时禁用线程调度器,只有禁用者能将其再次开启 130 | 若禁用者本身被阻塞,那么会运行idle线程 131 | */ 132 | void disable_thread_scheduler(); 133 | 134 | void enable_thread_scheduler(); 135 | 136 | #endif /* TINY_OS_THREAD_H */ 137 | -------------------------------------------------------------------------------- /src/kernel/console/print.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | void kset_cursor_pos(struct con_buf *buf, uint16_t pos) 10 | { 11 | ASSERT(pos < CON_BUF_CHAR_COUNT); 12 | buf->cursor = pos; 13 | } 14 | 15 | void kset_cursor_row_col(struct con_buf *buf, uint8_t row, uint8_t col) 16 | { 17 | kset_cursor_pos(buf, 80 * row + col); 18 | } 19 | 20 | uint16_t kget_cursor_pos(struct con_buf *buf) 21 | { 22 | return buf->cursor; 23 | } 24 | 25 | uint16_t kget_cursor_row_col(struct con_buf *buf) 26 | { 27 | uint8_t row, col; 28 | uint16_t pos = kget_cursor_pos(buf); 29 | row = pos / 80; 30 | col = pos % 80; 31 | return (row << 8) | col; 32 | } 33 | 34 | void kroll_screen_row_between(struct con_buf *buf, 35 | uint32_t beg, uint32_t end) 36 | { 37 | memcpy(buf->data + (beg * 2 * CON_BUF_ROW_SIZE), 38 | buf->data + ((beg + 1) * 2 * CON_BUF_ROW_SIZE), 39 | (end - beg - 1) * 2 * CON_BUF_ROW_SIZE); 40 | char *d = buf->data + (end - 1) * 2 * CON_BUF_ROW_SIZE; 41 | for(uint32_t i = 0; i < CON_BUF_ROW_SIZE; ++i) 42 | d[i << 1] = ' '; 43 | } 44 | 45 | void kroll_screen(struct con_buf *buf) 46 | { 47 | kroll_screen_row_between(buf, 0, CON_BUF_COL_SIZE); 48 | } 49 | 50 | static inline void kset_word(struct con_buf *buf, uint16_t cursor, uint8_t fst, uint8_t snd) 51 | { 52 | char* addr = buf->data + (cursor << 1); 53 | *addr = fst; 54 | *(addr + 1) = snd; 55 | } 56 | 57 | void kput_char(struct con_buf *buf, char ch) 58 | { 59 | // 取得光标位置 60 | uint16_t cursor_pos = kget_cursor_pos(buf); 61 | 62 | if(ch == '\n' || ch == '\r') // 换行 63 | { 64 | cursor_pos += (80 - cursor_pos % 80); 65 | } 66 | else if(ch == '\b') // 退格 67 | { 68 | if(cursor_pos != 0) 69 | kset_word(buf, --cursor_pos, (uint8_t)' ', 0x07); 70 | } 71 | else if(ch == '\t') // 水平制表四空格,不服憋着 72 | { 73 | cursor_pos += (4 - (cursor_pos + 1) % 4); 74 | } 75 | else // 普通字符 76 | { 77 | if(!isprint(ch)) 78 | ch = '?'; 79 | kset_word(buf, cursor_pos++, (uint8_t)ch, 0x07); 80 | } 81 | 82 | // 滚屏 83 | if(cursor_pos >= 2000) 84 | { 85 | kroll_screen(buf); 86 | cursor_pos = 1920; 87 | } 88 | 89 | // 更新光标位置 90 | kset_cursor_pos(buf, cursor_pos); 91 | } 92 | 93 | char kget_char(struct con_buf *buf, uint16_t pos) 94 | { 95 | if(2 * pos < CON_BUF_BYTE_SIZE) 96 | return buf->data[pos * 2]; 97 | return'\0'; 98 | } 99 | 100 | void kput_str(struct con_buf *buf, const char *str) 101 | { 102 | while(*str) 103 | kput_char(buf, *str++); 104 | } 105 | 106 | void kset_char(struct con_buf *buf, uint16_t pos, char ch) 107 | { 108 | if(!isprint(ch)) 109 | ch = '?'; 110 | *(buf->data + (pos << 1)) = ch; 111 | } 112 | 113 | void kset_attrib(struct con_buf *buf, uint16_t pos, char attrib) 114 | { 115 | *(buf->data + (pos << 1) + 1) = attrib; 116 | } 117 | -------------------------------------------------------------------------------- /src/include/kernel/seg_desc.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_SEG_DESC_H 2 | #define TINY_OS_SEG_DESC_H 3 | 4 | #include 5 | 6 | /* 7 | 段描述符的基本构成 8 | 和src/boot/boot.s中的定义基本一致,含义参见之 9 | 10 | 这个文件中的东西基本没有原创的( 11 | */ 12 | 13 | #define SEG_DESC_G_4K (1 << 7) 14 | #define SEG_DESC_D_32 (1 << 6) 15 | #define SEG_DESC_L_32 (0 << 5) 16 | #define SEG_DESC_AVL (0 << 4) 17 | 18 | #define SEG_DESC_P (1 << 7) 19 | #define SEG_DESC_DPL_0 (0 << 5) 20 | #define SEG_DESC_DPL_3 (3 << 5) 21 | 22 | #define SEG_DESC_S_SYS (0 << 4) 23 | #define SEG_DESC_S_NONSYS (1 << 4) 24 | 25 | #define SEG_DESC_TYPE_CODE 8 26 | #define SEG_DESC_TYPE_DATA 2 27 | #define SEG_DESC_TYPE_TSS 9 28 | 29 | /* 任务状态段(Task State Segment)描述符基本构成 */ 30 | 31 | #define TSS_DESC_D (0 << 6) 32 | 33 | /* 段选择子的基本构成 */ 34 | 35 | #define SEG_SEL_RPL_0 0x0 36 | #define SEG_SEL_RPL_1 0x1 37 | #define SEG_SEL_RPL_2 0x2 38 | #define SEG_SEL_RPL_3 0x3 39 | 40 | #define SEG_SEL_USE_GDT (0 << 2) 41 | #define SEG_SEL_USE_LDT (1 << 2) 42 | 43 | /* 内核代码段,数据段,栈段 */ 44 | 45 | #define SEG_SEL_KERNEL_CODE ((1 << 3) | SEG_SEL_USE_GDT | SEG_SEL_RPL_0) 46 | #define SEG_SEL_KERNEL_DATA ((2 << 3) | SEG_SEL_USE_GDT | SEG_SEL_RPL_0) 47 | #define SEG_SEL_KERNEL_STACK SEG_SEL_KERNEL_DATA 48 | 49 | /* TSS选择子 */ 50 | 51 | #define TSS_SEL ((3 << 3) | SEG_SEL_USE_GDT | SEG_SEL_RPL_0) 52 | 53 | /* 用户代码段、数据段 */ 54 | 55 | #define SEG_SEL_USER_CODE ((4 << 3) | SEG_SEL_USE_GDT | SEG_SEL_RPL_3) 56 | #define SEG_SEL_USER_DATA ((5 << 3) | SEG_SEL_USE_GDT | SEG_SEL_RPL_3) 57 | #define SEG_SEL_USER_STACK SEG_SEL_USER_DATA 58 | 59 | #define GDT_ATTRIB_HIGH (SEG_DESC_G_4K | \ 60 | SEG_DESC_D_32 | \ 61 | SEG_DESC_L_32 | \ 62 | SEG_DESC_AVL) 63 | #define GDT_ATTRIB_LOW_CODE (SEG_DESC_P | \ 64 | SEG_DESC_DPL_3 | \ 65 | SEG_DESC_S_NONSYS | \ 66 | SEG_DESC_TYPE_CODE) 67 | #define GDT_ATTRIB_LOW_DATA (SEG_DESC_P | \ 68 | SEG_DESC_DPL_3 | \ 69 | SEG_DESC_S_NONSYS | \ 70 | SEG_DESC_TYPE_DATA) 71 | #define TSS_ATTRIB_HIGH (SEG_DESC_G_4K | \ 72 | TSS_DESC_D | \ 73 | SEG_DESC_L_32 | \ 74 | SEG_DESC_AVL) 75 | #define TSS_ATTRIB_LOW (SEG_DESC_P | \ 76 | SEG_DESC_DPL_0 | \ 77 | SEG_DESC_S_SYS | \ 78 | SEG_DESC_TYPE_TSS) 79 | 80 | /* 81 | GDT表项 82 | 小端序真方便,赞美x86! 83 | */ 84 | struct iGDT 85 | { 86 | uint32_t low; 87 | uint32_t high; 88 | }; 89 | 90 | static inline void make_iGDT(struct iGDT *output, 91 | uint32_t base, uint32_t limit, 92 | uint8_t attrib_low, uint8_t attrib_high) 93 | { 94 | output->low = ((base & 0x0000ffff) << 16) | (limit & 0x0000ffff); 95 | output->high = ((base >> 24) << 24) | 96 | ((((limit & 0x000f0000) >> 16) + attrib_high) << 16) | 97 | (attrib_low << 8) | ((base & 0x00ff0000) >> 16); 98 | } 99 | 100 | #endif /* TINY_OS_SEG_DESC_H */ 101 | -------------------------------------------------------------------------------- /src/kernel/filesys/dpt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | #define DPT_BYTE_SIZE (sizeof(struct dpt_unit) * DPT_UNIT_COUNT) 12 | 13 | /* 分区表内容 */ 14 | static struct dpt_unit *dpts; 15 | 16 | /* 分区fs handlers */ 17 | static uint32_t dp_fs_handles[DPT_UNIT_COUNT]; 18 | 19 | void init_dpt() 20 | { 21 | // 这里直接申请一个扇区的大小,后面那点零头不用在意,主要是重写dpt的时候方便 22 | dpts = alloc_static_kernel_mem(DISK_SECTOR_BYTE_SIZE, sizeof(struct dpt_unit)); 23 | 24 | // dpt_sec_data在内核进程栈上,不用担心缺页,所以直接无缓冲读取 25 | uint8_t dpt_sec_data[DISK_SECTOR_BYTE_SIZE]; 26 | disk_read(DPT_SECTOR_POSITION, 1, dpt_sec_data); 27 | memcpy((char*)dpts, (const char*)dpt_sec_data, DPT_BYTE_SIZE); 28 | 29 | for(size_t i = 0;i != DPT_UNIT_COUNT; ++i) 30 | { 31 | struct dpt_unit *u = &dpts[i]; 32 | switch(u->type) 33 | { 34 | case DISK_PT_AFS: 35 | dp_fs_handles[i] = (uint32_t)afs_init_dp_handler(u->sector_begin); 36 | break; 37 | default: 38 | dp_fs_handles[i] = 0; 39 | } 40 | } 41 | } 42 | 43 | struct dpt_unit *get_dpt_unit(size_t idx) 44 | { 45 | if(idx >= DPT_UNIT_COUNT) 46 | return NULL; 47 | return &dpts[idx]; 48 | } 49 | 50 | bool reformat_dp(size_t idx, disk_partition_type type) 51 | { 52 | // 先销毁原来的文件系统handler 53 | struct dpt_unit *u = &dpts[idx]; 54 | switch(u->type) 55 | { 56 | case DISK_PT_AFS: 57 | afs_release_dp_handler(dp_fs_handles[idx]); 58 | break; 59 | } 60 | 61 | u->type = DISK_PT_NOFS; 62 | dp_fs_handles[idx] = 0; 63 | 64 | switch(type) 65 | { 66 | case DISK_PT_AFS: 67 | if(!afs_reformat_dp(u->sector_begin, u->sector_end - u->sector_begin)) 68 | { 69 | u->type = DISK_PT_NOFS; 70 | return false; 71 | } 72 | dp_fs_handles[idx] = (uint32_t)afs_init_dp_handler(u->sector_begin); 73 | } 74 | 75 | u->type = type; 76 | return true; 77 | } 78 | 79 | uint32_t get_dp_fs_handler(size_t idx) 80 | { 81 | return dp_fs_handles[idx]; 82 | } 83 | 84 | filesys_dp_handle get_dp_handle_by_name(const char *name) 85 | { 86 | for(filesys_dp_handle ret = 0; ret < DPT_UNIT_COUNT; ++ret) 87 | { 88 | if(strcmp(get_dpt_unit(ret)->name, name) == 0) 89 | return ret; 90 | } 91 | return DPT_UNIT_COUNT; 92 | } 93 | 94 | void restore_dpt() 95 | { 96 | disk_write(DPT_SECTOR_POSITION, 1, dpts); 97 | } 98 | 99 | void destroy_dpt() 100 | { 101 | for(uint32_t i = 0; i < DPT_UNIT_COUNT; ++i) 102 | { 103 | struct dpt_unit *u = get_dpt_unit(i); 104 | switch(u->type) 105 | { 106 | case DISK_PT_AFS: 107 | afs_release_dp_handler(get_dp_fs_handler(i)); 108 | break; 109 | } 110 | } 111 | 112 | restore_dpt(); 113 | } 114 | 115 | filesys_dp_handle syscall_get_dp_handle_impl(const char *name) 116 | { 117 | return get_dp_handle_by_name(name); 118 | } 119 | -------------------------------------------------------------------------------- /src/include/shared/keyboard.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_LIB_KEYBOARD_H 2 | #define TINY_OS_LIB_KEYBOARD_H 3 | 4 | #include 5 | 6 | /* 虚拟键值定义 */ 7 | 8 | /* 9 | 字母:ASCII码(大写) 10 | 数字:'0'~'9' 11 | */ 12 | 13 | #define VK_NULL 255 14 | 15 | #define VK_ESCAPE 0 16 | 17 | #define VK_F1 1 18 | #define VK_F2 2 19 | #define VK_F3 3 20 | #define VK_F4 4 21 | #define VK_F5 5 22 | #define VK_F6 6 23 | #define VK_F7 7 24 | #define VK_F8 8 25 | #define VK_F9 9 26 | #define VK_F10 10 27 | #define VK_F11 11 28 | #define VK_F12 12 29 | 30 | #define VK_SIM 13 /* `~ */ 31 | #define VK_MINUS 14 /* -_ */ 32 | #define VK_EQUAL 15 /* =+ */ 33 | 34 | #define VK_TAB 16 35 | #define VK_BS 17 /* backspace */ 36 | #define VK_ENTER 18 37 | #define VK_SPACE 19 38 | 39 | #define VK_LBRAC 20 /* [{ */ 40 | #define VK_RBRAC 21 /* ]} */ 41 | #define VK_BACKSL 22 /* \| */ 42 | #define VK_SEMICOL 23 /* ;: */ 43 | #define VK_QOT 24 /* '" */ 44 | #define VK_COMMA 25 /* ,< */ 45 | #define VK_POINT 26 /* .> */ 46 | #define VK_DIV 27 /* /? */ 47 | 48 | #define VK_LSHIFT 28 49 | #define VK_RSHIFT 29 50 | #define VK_LCTRL 30 51 | #define VK_RCTRL 31 52 | #define VK_LALT 32 53 | #define VK_RALT 33 54 | 55 | #define VK_CAPS 34 /* caps lock */ 56 | 57 | #define VK_NUMLOCK 35 58 | #define VK_SCRLOCK 36 59 | 60 | #define VK_PAD_HOME 37 61 | #define VK_PAD_UP 38 62 | #define VK_PAD_DOWN 39 63 | #define VK_PAD_LEFT 40 64 | #define VK_PAD_RIGHT 41 65 | #define VK_PAD_PGUP 42 66 | #define VK_PAD_PGDOWN 43 67 | #define VK_PAD_FIVE 44 68 | #define VK_PAD_END 45 69 | #define VK_PAD_INS 46 70 | #define VK_PAD_DEL 47 71 | #define VK_PAD_PLUS 48 72 | #define VK_PAD_ENTER 49 73 | #define VK_PAD_MINUS 50 74 | #define VK_PAD_DIV 51 75 | 76 | #define VK_INSERT 52 77 | #define VK_HOME 53 78 | #define VK_PGUP 54 79 | #define VK_PGDOWN 55 80 | #define VK_DELETE 56 81 | #define VK_END 57 82 | #define VK_LEFT 58 83 | #define VK_RIGHT 59 84 | #define VK_UP 60 85 | #define VK_DOWN 61 86 | 87 | /* 88 | 系统调用功能号:某个按键是否按下 89 | 第一个参数为虚拟键值 90 | */ 91 | #define KEYBOARD_SYSCALL_FUNCTION_IS_KEY_PRESSED 0 92 | 93 | /*================================================================================ 94 | 按键消息和字符消息 95 | ================================================================================*/ 96 | 97 | /* 98 | msg参数含义: 99 | struct 100 | { 101 | uint32_t key 102 | uint32_t flags 103 | uint32_t reserved 104 | } 105 | 106 | flags0 down/up 107 | */ 108 | struct kbmsg_struct 109 | { 110 | sysmsg_type type; // 为SYSMSG_TYPE_KEYBOARD 111 | uint32_t key; 112 | uint32_t flags; 113 | uint32_t reserved; 114 | }; 115 | 116 | /* 117 | char消息 118 | struct 119 | { 120 | uint32_t char 121 | } 122 | */ 123 | struct kbchar_msg_struct 124 | { 125 | sysmsg_type type; // 为SYSMSG_TYPE_CHAR 126 | uint32_t ch; 127 | uint32_t reserved1; 128 | uint32_t reserved2; 129 | }; 130 | 131 | #define KBMSG_FLAG_UP 0x1 132 | 133 | #endif /* TINY_OS_LIB_KEYBOARD_H */ 134 | -------------------------------------------------------------------------------- /src/kernel/explorer/disp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | static uint8_t cx, cy; 8 | 9 | void init_disp() 10 | { 11 | cx = cy = 0; 12 | } 13 | 14 | void disp_set_cursor(uint8_t x, uint8_t y) 15 | { 16 | cx = x, cy = y; 17 | } 18 | 19 | void disp_cursor_end() 20 | { 21 | cx = SCR_DISP_WIDTH - 1; 22 | cy = SCR_DISP_HEIGHT - 1; 23 | } 24 | 25 | void disp_get_cursor(uint8_t *x, uint8_t *y) 26 | { 27 | if(x) *x = cx; 28 | if(y) *y = cy; 29 | } 30 | 31 | void disp_put_char(char ch) 32 | { 33 | if(ch == '\n') 34 | { 35 | cx = 0; 36 | if(cy >= SCR_DISP_HEIGHT - 1) 37 | disp_roll_screen(); 38 | else 39 | ++cy; 40 | } 41 | else if(ch == '\t') 42 | { 43 | for(int t = 4 - (cx % 4); t > 0; --t) 44 | disp_put_char(' '); 45 | } 46 | else 47 | { 48 | disp_char(cx, cy, ch); 49 | if(++cx >= SCR_DISP_WIDTH) 50 | { 51 | cx = 0; 52 | if(cy >= SCR_DISP_HEIGHT - 1) 53 | disp_roll_screen(); 54 | else 55 | ++cy; 56 | } 57 | } 58 | } 59 | 60 | void disp_put_str(const char *str) 61 | { 62 | while(*str) 63 | disp_put_char(*str++); 64 | } 65 | 66 | void disp_put_line_str(const char *str) 67 | { 68 | while(*str && cx < SCR_DISP_WIDTH) 69 | disp_put_char(*str++); 70 | if(*str) 71 | disp_put_char(*str); 72 | } 73 | 74 | void disp_new_line() 75 | { 76 | if(cx > 0) 77 | disp_put_char('\n'); 78 | } 79 | 80 | void disp_printf(const char *fmt, ...) 81 | { 82 | const char *next_param = (const char *)&fmt + 4; 83 | char int_buf[32]; 84 | while(*fmt) 85 | { 86 | if(*fmt == '%') 87 | { 88 | switch(*++fmt) 89 | { 90 | case 'u': 91 | uint32_to_str(*(uint32_t*)next_param, int_buf); 92 | disp_put_str(int_buf); 93 | next_param += 4; 94 | break; 95 | case 's': 96 | disp_put_str(*(char**)next_param); 97 | next_param += 4; 98 | break; 99 | case '%': 100 | disp_put_char('%'); 101 | break; 102 | case 'c': 103 | disp_put_char((char)*(uint32_t*)next_param); 104 | next_param += 4; 105 | break; 106 | case 'l': 107 | { 108 | uint32_to_str(*(uint32_t*)next_param, int_buf); 109 | next_param += 4; 110 | uint32_t width = *(uint32_t*)next_param; 111 | next_param += 4; 112 | 113 | disp_put_str(int_buf); 114 | uint32_t int_len = strlen(int_buf); 115 | while(width-- > int_len) 116 | disp_put_char(' '); 117 | } 118 | break; 119 | case '\0': 120 | return; 121 | } 122 | ++fmt; 123 | } 124 | else 125 | disp_put_char(*fmt++); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/kernel/filesys/import/import.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #define IPT_SECTOR_BYTE_SIZE 512 10 | 11 | /* 12 | 导入过程是对import分区的一次线性扫描,但只占用一个扇区大小的内存空间 13 | 因此,当扫描跨磁盘扇区时,这部分空间的内容要自动替换,扫描指针也要更新 14 | 这些信息由ipt_context追踪 15 | */ 16 | struct ipt_context 17 | { 18 | uint32_t cur_sec; 19 | uint32_t lcl_pos; 20 | uint8_t *data; 21 | }; 22 | 23 | /* 开始import分区扫描 */ 24 | static void ipt_begin(struct ipt_context *ctx, uint32_t beg_sec) 25 | { 26 | ctx->cur_sec = beg_sec; 27 | ctx->lcl_pos = 0; 28 | 29 | // 说是只有一个扇区,咱们还是只能申请一个页 30 | // 这是个设计失误,即文件系统没有提供一个统一的扇区级内存管理系统 31 | ctx->data = (uint8_t*)alloc_ker_page(false); 32 | disk_read(beg_sec, 1, ctx->data); 33 | } 34 | 35 | /* 36 | 取得import分区的下一个字节 37 | 为什么只能一个字节一个字节地读呢?因为这样比较好写,而且import本来就不是核心功能…… 38 | */ 39 | static uint8_t ipt_next(struct ipt_context *ctx) 40 | { 41 | uint8_t ret = ctx->data[ctx->lcl_pos++]; 42 | 43 | // 是否要更新缓存扇区 44 | if(ctx->lcl_pos >= IPT_SECTOR_BYTE_SIZE) 45 | { 46 | ctx->cur_sec++; 47 | ctx->lcl_pos = 0; 48 | disk_read(ctx->cur_sec, 1, ctx->data); 49 | } 50 | 51 | return ret; 52 | } 53 | 54 | /* 结束对import分区的扫描,释放临时空间 */ 55 | static void ipt_end(struct ipt_context *ctx) 56 | { 57 | free_ker_page(ctx->data); 58 | } 59 | 60 | void ipt_import_from_dp(uint32_t dp_beg) 61 | { 62 | struct ipt_context ctx; 63 | ipt_begin(&ctx, dp_beg); 64 | 65 | // 临时字节指针 66 | uint8_t *p; 67 | #define PS(V) do { p = (uint8_t*)(V); } while(0) 68 | #define PB() do { *p++ = ipt_next(&ctx); } while(0) 69 | #define PR(DST) \ 70 | do { PS(DST); for(size_t i = 0; i < sizeof(*DST); ++i) PB(); } while(0) 71 | 72 | // 首先取得文件数量,连续读sizeof(uint32_t)个字节 73 | // x86是小端序,所以直接地址递增 74 | 75 | uint32_t file_count; 76 | PR(&file_count); 77 | 78 | // 一个一个读文件 79 | while(file_count-- > 0) 80 | { 81 | // 分区号 82 | uint32_t dp; 83 | PR(&dp); 84 | 85 | // 文件名 86 | char path[IPT_PATH_BUF_SIZE]; 87 | PS(path); 88 | for(size_t i = 0; i < IPT_PATH_BUF_SIZE; ++i) 89 | PB(); 90 | 91 | // 文件字节数 92 | uint32_t file_size; 93 | PR(&file_size); 94 | 95 | // 读文件内容并写入到磁盘上的文件系统 96 | 97 | usr_file_handle fp; 98 | remove_file(dp, path); 99 | make_file(dp, path); 100 | if(open_file(dp, path, true, &fp) != filesys_opr_success) 101 | { 102 | ipt_end(&ctx); 103 | return; 104 | } 105 | 106 | uint32_t fpos = 0; 107 | while(fpos < file_size) 108 | { 109 | uint8_t buf[256]; 110 | uint32_t remain = file_size - fpos; 111 | uint32_t delta = MIN(remain, 256); 112 | 113 | PS(buf); 114 | for(uint32_t i = 0; i < delta; ++i) 115 | PB(); 116 | 117 | write_file(fp, fpos, delta, buf); 118 | fpos += delta; 119 | } 120 | 121 | close_file(fp); 122 | } 123 | 124 | ipt_end(&ctx); 125 | 126 | #undef PS 127 | #undef PB 128 | #undef PR 129 | } 130 | -------------------------------------------------------------------------------- /src/kernel/syscall.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | typedef void (*syscall_impl)(); 14 | 15 | syscall_impl syscall_func_table[SYSCALL_COUNT]; 16 | 17 | void init_syscall() 18 | { 19 | // declared in kernel/process/process.h 20 | 21 | syscall_func_table[SYSCALL_GET_PROCESS_ID] = 22 | (syscall_impl)&syscall_get_cur_PID_impl; 23 | syscall_func_table[SYSCALL_YIELD_CPU] = 24 | (syscall_impl)&syscall_yield_CPU_impl; 25 | syscall_func_table[SYSCALL_EXIT_THREAD] = 26 | (syscall_impl)&syscall_thread_exit_impl; 27 | syscall_func_table[SYSCALL_NEW_THREAD] = 28 | (syscall_impl)&syscall_new_thread_impl; 29 | 30 | // declared in kernel/console/console.h 31 | 32 | syscall_func_table[SYSCALL_CONSOLE_OPERATION] = 33 | (syscall_impl)&syscall_console_impl; 34 | 35 | // declared in kernel/sysmsg/sysmsg_syscall.h 36 | 37 | syscall_func_table[SYSCALL_SYSMSG_OPERATION] = 38 | (syscall_impl)&syscall_sysmsg_impl; 39 | 40 | // declared in kernel/kbdriver.h 41 | 42 | syscall_func_table[SYSCALL_KEYBOARD_QUERY] = 43 | (syscall_impl)&syscall_keyboard_query_impl; 44 | 45 | // declared in kernel/filesys/syscall.h 46 | 47 | syscall_func_table[SYSCALL_FILESYS_OPEN] = 48 | (syscall_impl)&syscall_filesys_open_impl; 49 | syscall_func_table[SYSCALL_FILESYS_CLOSE] = 50 | (syscall_impl)&syscall_filesys_close_impl; 51 | syscall_func_table[SYSCALL_FILESYS_MKFILE] = 52 | (syscall_impl)&syscall_filesys_mkfile_impl; 53 | syscall_func_table[SYSCALL_FILESYS_RMFILE] = 54 | (syscall_impl)&syscall_filesys_rmfile_impl; 55 | syscall_func_table[SYSCALL_FILESYS_MKDIR] = 56 | (syscall_impl)&syscall_filesys_mkdir_impl; 57 | syscall_func_table[SYSCALL_FILESYS_RMDIR] = 58 | (syscall_impl)&syscall_filesys_rmdir_impl; 59 | syscall_func_table[SYSCALL_FILESYS_GET_SIZE] = 60 | (syscall_impl)&syscall_filesys_get_file_size_impl; 61 | syscall_func_table[SYSCALL_FILESYS_WRITE] = 62 | (syscall_impl)&syscall_filesys_write_impl; 63 | syscall_func_table[SYSCALL_FILESYS_READ] = 64 | (syscall_impl)&syscall_filesys_read_impl; 65 | syscall_func_table[SYSCALL_FILESYS_GET_CHILD_COUNT] = 66 | (syscall_impl)&syscall_filesys_get_file_count; 67 | syscall_func_table[SYSCALL_FILESYS_GET_CHILD_INFO] = 68 | (syscall_impl)&syscall_filesys_get_child_info; 69 | 70 | // declared in kernel/filesys/dpt.h 71 | 72 | syscall_func_table[SYSCALL_DP_GET_HANDLE] = 73 | (syscall_impl)&syscall_get_dp_handle_impl; 74 | 75 | // declared in kernel/explorer/explorer.h 76 | 77 | syscall_func_table[SYSCALL_EXPL_ALLOC_FOREGROUND] = 78 | (syscall_impl)&syscall_alloc_fg_impl; 79 | syscall_func_table[SYSCALL_EXPL_FREE_FOREGROUND] = 80 | (syscall_impl)&syscall_free_fg_impl; 81 | syscall_func_table[SYSCALL_EXPL_ALLOC_CON_BUF] = 82 | (syscall_impl)&syscall_alloc_con_buf_impl; 83 | syscall_func_table[SYSCALL_EXPL_PUT_CHAR] = 84 | (syscall_impl)&syscall_put_char_expl_impl; 85 | syscall_func_table[SYSCALL_EXPL_NEW_LINE] = 86 | (syscall_impl)&syscall_expl_new_line_impl; 87 | syscall_func_table[SYSCALL_PIPE_NULL_CHAR] = 88 | (syscall_impl)&syscall_expl_pipe_null_char; 89 | } 90 | -------------------------------------------------------------------------------- /src/shared/string.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | size_t strlen(const char *str) 5 | { 6 | size_t rt = 0; 7 | while(str[rt]) 8 | ++rt; 9 | return rt; 10 | } 11 | 12 | void strcpy(char *dst, const char *src) 13 | { 14 | while((*dst++ = *src++)) 15 | ; 16 | } 17 | 18 | void strcpy_s(char *dst, const char *src, size_t buf_size) 19 | { 20 | while(buf_size-- > 1 && (*dst++ = *src++)) 21 | ; 22 | if(!buf_size) 23 | *dst = '\0'; 24 | } 25 | 26 | int strcmp(const char *lhs, const char *rhs) 27 | { 28 | char L, R; 29 | while(((L = *lhs) != '\0') & ((R = *rhs) != '\0')) 30 | { 31 | if(L < R) 32 | return -1; 33 | else if(L > R) 34 | return 1; 35 | else 36 | ++lhs, ++rhs; 37 | } 38 | return L ? 1 : (R ? -1 : 0); 39 | } 40 | 41 | int strcoll(const char *L, const char *R) 42 | { 43 | return strcmp(L, R); 44 | } 45 | 46 | void strcat(char *fst, const char *snd) 47 | { 48 | while(*fst) 49 | ++fst; 50 | strcpy(fst, snd); 51 | } 52 | 53 | uint32_t strfind(const char *str, char c, uint32_t beg) 54 | { 55 | while(str[beg]) 56 | { 57 | if(str[beg] == c) 58 | return beg; 59 | ++beg; 60 | } 61 | return STRING_NPOS; 62 | } 63 | 64 | const char *strchr(const char *str, int ch) 65 | { 66 | size_t offset = strfind(str, (char)ch, 0); 67 | if(offset != STRING_NPOS) 68 | return str + offset; 69 | return NULL; 70 | } 71 | 72 | void uint32_to_str(uint32_t intval, char *buf) 73 | { 74 | size_t idx = 0; 75 | 76 | if(intval == 0) 77 | { 78 | buf[0] = '0'; 79 | buf[1] = '\0'; 80 | return; 81 | } 82 | 83 | while(intval) 84 | { 85 | buf[idx++] = (intval % 10) + '0'; 86 | intval = intval / 10; 87 | } 88 | 89 | int end = idx / 2; 90 | for(int i = 0;i < end; ++i) 91 | { 92 | int tmp = buf[i]; 93 | buf[i] = buf[idx - 1 - i]; 94 | buf[idx - 1 - i] = tmp; 95 | } 96 | 97 | buf[idx] = '\0'; 98 | } 99 | 100 | bool str_to_uint32(const char *str, uint32_t *_val) 101 | { 102 | if(str[0] == '0' && str[1]) 103 | return false; 104 | 105 | uint32_t val = 0; 106 | while(*str) 107 | { 108 | if(!isdigit(*str)) 109 | return false; 110 | val = 10 * val + (*str++ - '0'); 111 | } 112 | 113 | if(_val) 114 | *_val = val; 115 | return true; 116 | } 117 | 118 | void memset(void *_dst, uint8_t val, size_t byte_size) 119 | { 120 | char *dst = (char*)_dst; 121 | for(size_t i = 0;i != byte_size; ++i) 122 | dst[i] = val; 123 | } 124 | 125 | void memcpy(void *_dst, const void *_src, size_t byte_size) 126 | { 127 | char *dst = (char*)_dst, *src = (char*)_src; 128 | for(size_t i = 0;i != byte_size; ++i) 129 | dst[i] = src[i]; 130 | } 131 | 132 | int memcmp(const void *L, const void *R, size_t byte_size) 133 | { 134 | uint8_t *l = (uint8_t*)L, *r = (uint8_t*)R; 135 | for(size_t i = 0; i < byte_size; ++i) 136 | { 137 | if(l[i] < r[i]) 138 | return -1; 139 | if(l[i] > r[i]) 140 | return 1; 141 | } 142 | return 0; 143 | } 144 | 145 | /* 算法:ELFHash */ 146 | uint32_t strhash(const char *str) 147 | { 148 | uint32_t ret = 0, t = 0; 149 | while(*str) 150 | { 151 | ret = (ret << 4) + *str++; 152 | if((t = ret & 0xf0000000) != 0) 153 | ret = (ret ^ (t >> 24)) & (~t); 154 | } 155 | return ret & 0x7fffffff; 156 | } 157 | -------------------------------------------------------------------------------- /src/shared/sys/filesys.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | enum filesys_opr_result open_file(filesys_dp_handle dp, 5 | const char *path, bool writing, 6 | usr_file_handle *result) 7 | { 8 | struct syscall_filesys_open_params args = 9 | { 10 | .writing = writing, 11 | .dp = dp, 12 | .path = path, 13 | .result = result 14 | }; 15 | return syscall_param1(SYSCALL_FILESYS_OPEN, &args); 16 | } 17 | 18 | enum filesys_opr_result close_file(usr_file_handle file) 19 | { 20 | return syscall_param1(SYSCALL_FILESYS_CLOSE, file); 21 | } 22 | 23 | enum filesys_opr_result make_file(filesys_dp_handle dp, 24 | const char *path) 25 | { 26 | return syscall_param2(SYSCALL_FILESYS_MKFILE, dp, path); 27 | } 28 | 29 | enum filesys_opr_result remove_file(filesys_dp_handle dp, 30 | const char *path) 31 | { 32 | return syscall_param2(SYSCALL_FILESYS_RMFILE, dp, path); 33 | } 34 | 35 | enum filesys_opr_result make_directory(filesys_dp_handle dp, 36 | const char *path) 37 | { 38 | return syscall_param2(SYSCALL_FILESYS_MKDIR, dp, path); 39 | } 40 | 41 | enum filesys_opr_result remove_directory(filesys_dp_handle dp, 42 | const char *path) 43 | { 44 | return syscall_param2(SYSCALL_FILESYS_RMDIR, dp, path); 45 | } 46 | 47 | uint32_t get_file_size(usr_file_handle file) 48 | { 49 | return syscall_param1(SYSCALL_FILESYS_GET_SIZE, file); 50 | } 51 | 52 | enum filesys_opr_result write_file(usr_file_handle file, 53 | uint32_t fpos, uint32_t byte_size, 54 | const void *data) 55 | { 56 | struct syscall_filesys_write_params args = 57 | { 58 | .file = file, 59 | .fpos = fpos, 60 | .byte_size = byte_size, 61 | .data_src = data 62 | }; 63 | return syscall_param1(SYSCALL_FILESYS_WRITE, &args); 64 | } 65 | 66 | enum filesys_opr_result read_file(usr_file_handle file, 67 | uint32_t fpos, uint32_t byte_size, 68 | void *data) 69 | { 70 | struct syscall_filesys_read_params args = 71 | { 72 | .file = file, 73 | .fpos = fpos, 74 | .byte_size = byte_size, 75 | .data_dst = data 76 | }; 77 | return syscall_param1(SYSCALL_FILESYS_READ, &args); 78 | } 79 | 80 | enum filesys_opr_result get_child_file_count(filesys_dp_handle dp, 81 | const char *path, 82 | uint32_t *_rt) 83 | { 84 | enum filesys_opr_result ret; uint32_t rt; 85 | ret = syscall_param3(SYSCALL_FILESYS_GET_CHILD_COUNT, dp, path, &rt); 86 | if(_rt) *_rt = rt; 87 | return ret; 88 | } 89 | 90 | enum filesys_opr_result get_child_file_info(filesys_dp_handle dp, 91 | const char *path, 92 | uint32_t idx, 93 | struct syscall_filesys_file_info *rt) 94 | { 95 | struct syscall_filesys_get_child_info_params args = 96 | { 97 | .dp = dp, 98 | .path = path, 99 | .idx = idx, 100 | .info = rt 101 | }; 102 | return syscall_param1(SYSCALL_FILESYS_GET_CHILD_INFO, &args); 103 | } 104 | 105 | filesys_dp_handle get_dp(const char *name) 106 | { 107 | return syscall_param1(SYSCALL_DP_GET_HANDLE, name); 108 | } 109 | -------------------------------------------------------------------------------- /src/boot/boot.s: -------------------------------------------------------------------------------- 1 | ;===================================================== 2 | ; mbr如何加载bootloader 3 | 4 | ; loader被加载到内存中的位置 5 | BOOTLOADER_START_ADDR equ 0x900 6 | ; loader从哪个扇区开始 7 | BOOTLOADER_START_SECTOR equ 0x1 8 | ; 加载loader的时候读多少个扇区 9 | BOOTLOADER_SECTOR_COUNT equ 0x4 10 | 11 | ;===================================================== 12 | ; kernel 13 | 14 | KERNEL_START_ADDR equ 0x70000 15 | KERNEL_START_SECTOR equ 0x9 16 | KERNEL_SECTOR_COUNT equ 0xc8 17 | 18 | ;===================================================== 19 | ; 总内存容量存放在哪 20 | ; 4个字节 21 | 22 | TOTAL_MEMORY_SIZE_ADDR equ 0x500 23 | 24 | ;===================================================== 25 | ; 全局描述符表 26 | 27 | ;----------------------------------------------------- 28 | ; 段描述符,按平坦模式定义 29 | 30 | ; G字段,为1表示segment limit单位为4K 31 | SEGMENT_DESC_G_4K equ 0_1_000_00000_00000_00000_00000b 32 | 33 | ; D字段,为1表示默认操作均按32位进行 34 | SEGMENT_DESC_D_32 equ 00_1_00_00000_00000_00000_00000b 35 | 36 | ; L字段,不开64位代码段,设置为0 37 | SEGMENT_DESC_L_32 equ 000_0_0_00000_00000_00000_00000b 38 | 39 | ; AVL字段 40 | SEGMENT_DESC_AVL equ 0000_0_00000_00000_00000_00000b 41 | 42 | ; 段界限 43 | SEGMENT_DESC_LIMIT_CODE equ 1111_0_00000_00000_00000b 44 | SEGMENT_DESC_LIMIT_DATA equ 1111_0_00000_00000_00000b 45 | SEGMENT_DESC_LIMIT_VIDEO equ 0000_0_00000_00000_00000b 46 | 47 | SEGMENT_DESC_P equ 1_00000_00000_00000b 48 | 49 | ; 特权级0-3,0为最高特权 50 | SEGMENT_DESC_DPL_0 equ 00_000_00000_00000b 51 | SEGMENT_DESC_DPL_1 equ 01_000_00000_00000b 52 | SEGMENT_DESC_DPL_2 equ 10_000_00000_00000b 53 | SEGMENT_DESC_DPL_3 equ 11_000_00000_00000b 54 | 55 | ; 系统段/非系统段 56 | SEGMENT_DESC_S_SYS equ 0_00_00000_00000b 57 | SEGMENT_DESC_S_NONSYS equ 1_00_00000_00000b 58 | 59 | ; 代码段:可执行,非一致,不可读,accessed为false 60 | SEGMENT_DESC_TYPE_CODE equ 1000_00000000b 61 | ; 数据段,不可执行,扩展方向向上,可写,accessed为false 62 | SEGMENT_DESC_TYPE_DATA equ 0010_00000000b 63 | 64 | SEGMENT_DESC_CODE_HIGH equ (0x00 << 24) + \ 65 | SEGMENT_DESC_G_4K + \ 66 | SEGMENT_DESC_D_32 + \ 67 | SEGMENT_DESC_L_32 + \ 68 | SEGMENT_DESC_AVL + \ 69 | SEGMENT_DESC_LIMIT_CODE + \ 70 | SEGMENT_DESC_P + \ 71 | SEGMENT_DESC_DPL_0 + \ 72 | SEGMENT_DESC_S_NONSYS + \ 73 | SEGMENT_DESC_TYPE_CODE + \ 74 | 0X00 75 | 76 | SEGMENT_DESC_DATA_HIGH equ (0x00 << 24) + \ 77 | SEGMENT_DESC_G_4K + \ 78 | SEGMENT_DESC_D_32 + \ 79 | SEGMENT_DESC_L_32 + \ 80 | SEGMENT_DESC_AVL + \ 81 | SEGMENT_DESC_LIMIT_DATA + \ 82 | SEGMENT_DESC_P + \ 83 | SEGMENT_DESC_DPL_0 + \ 84 | SEGMENT_DESC_S_NONSYS + \ 85 | SEGMENT_DESC_TYPE_DATA + \ 86 | 0X00 87 | 88 | ;----------------------------------------------------- 89 | ; 段选择子 90 | 91 | ; 特权级 92 | SEGMENT_SELECTOR_ATTRIB_RPL_0 equ 00b 93 | SEGMENT_SELECTOR_ATTRIB_RPL_1 equ 01b 94 | SEGMENT_SELECTOR_ATTRIB_RPL_2 equ 10b 95 | SEGMENT_SELECTOR_ATTRIB_RPL_3 equ 11b 96 | 97 | SEGMENT_SELECTOR_ATTRIB_USE_LDT equ 100b 98 | SEGMENT_SELECTOR_ATTRIB_USE_GDT equ 000b 99 | 100 | ;===================================================== 101 | ; 分页 102 | 103 | PAGE_DIR_ENTRY_ADDR equ 0x200000 104 | 105 | PAGE_PRESENT_TRUE equ 1b 106 | PAGE_PRESENT_FALSE equ 0b 107 | 108 | PAGE_READ_WRITE_READ_ONLY equ 00b 109 | PAGE_READ_WRITE_READ_WRITE equ 10b 110 | 111 | PAGE_USER_USER equ 100b 112 | PAGE_USER_SUPER equ 000b 113 | -------------------------------------------------------------------------------- /src/kernel/explorer/cmds/procs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | struct proc_info 14 | { 15 | uint32_t pid; 16 | char name[PROCESS_NAME_MAX_LENGTH + 1]; 17 | }; 18 | 19 | STATIC_ASSERT(sizeof(struct proc_info) * MAX_PROCESS_COUNT <= 4096, 20 | invalid_size_of_proc_info_buffer); 21 | 22 | /* 将所有进程的显示数据放入buf数组中 */ 23 | static void get_procs_info(struct proc_info *buf, uint32_t *cnt) 24 | { 25 | ASSERT(buf && cnt); 26 | intr_state is = fetch_and_disable_intr(); 27 | 28 | uint32_t _cnt = 0; 29 | 30 | // 跳过0号bootloader进程和1号explorer进程,其他进程都计入表中 31 | for(uint32_t pid = 2; pid < MAX_PROCESS_COUNT; ++pid) 32 | { 33 | struct PCB *pcb = get_PCB_by_pid(pid); 34 | if(!pcb) 35 | continue; 36 | buf[_cnt].pid = pcb->pid; 37 | strcpy_s(buf[_cnt].name, pcb->name, 38 | PROCESS_NAME_MAX_LENGTH + 1); 39 | ++_cnt; 40 | } 41 | 42 | set_intr_state(is); 43 | 44 | *cnt = _cnt; 45 | } 46 | 47 | /* 每个显示页能放多少条进程信息 */ 48 | #define PROCS_PER_PAGE (SCR_DISP_HEIGHT - 1) 49 | 50 | /* 在显示区输出一页进程信息 */ 51 | static void show_procs_page(struct proc_info *buf, 52 | uint32_t cnt, uint32_t page_idx, 53 | bool clear) 54 | { 55 | if(clear) 56 | { 57 | clr_disp(); 58 | disp_set_cursor(0, 0); 59 | } 60 | 61 | disp_printf("pid name\n"); 62 | 63 | uint32_t y = 1, idx = page_idx * PROCS_PER_PAGE; 64 | while(y < SCR_DISP_HEIGHT && idx < cnt) 65 | { 66 | disp_new_line(); 67 | struct proc_info *info = &buf[idx]; 68 | 69 | disp_printf("%l", info->pid, 6); 70 | disp_put_line_str(info->name); 71 | 72 | ++y, ++idx; 73 | } 74 | } 75 | 76 | void expl_show_procs() 77 | { 78 | // 取得所有进程信息 79 | struct proc_info *buf = (struct proc_info*)alloc_ker_page(false); 80 | if(!buf) 81 | return; 82 | uint32_t cnt; 83 | get_procs_info(buf, &cnt); 84 | 85 | if(!cnt) 86 | { 87 | disp_printf("No active process"); 88 | return; 89 | } 90 | 91 | uint32_t max_page_idx = ceil_int_div(cnt, PROCS_PER_PAGE) - 1; 92 | uint32_t page_idx = 0; 93 | 94 | bool only_one_page = (max_page_idx == 0); 95 | show_procs_page(buf, cnt, page_idx, !only_one_page); 96 | 97 | // 如果只有一页,直接退了 98 | if(only_one_page) 99 | { 100 | free_ker_page(buf); 101 | clr_sysmsgs(); 102 | return; 103 | } 104 | 105 | scr_disp_caption("Processe List"); 106 | scr_cmd_caption("[Q] Quit [N] Next Page [B] Last Page"); 107 | 108 | while(true) 109 | { 110 | // 取得一条键盘按下的消息 111 | struct sysmsg msg; 112 | if(!peek_sysmsg(SYSMSG_SYSCALL_PEEK_OPERATION_REMOVE, &msg)) 113 | continue; 114 | if(msg.type != SYSMSG_TYPE_KEYBOARD || !is_kbmsg_down(&msg)) 115 | continue; 116 | uint8_t key = get_kbmsg_key(&msg); 117 | 118 | // Quit 119 | if(key == 'Q') 120 | break; 121 | 122 | // 下一页 123 | if(key == 'N' && page_idx < max_page_idx) 124 | { 125 | ++page_idx; 126 | show_procs_page(buf, cnt, page_idx, true); 127 | } 128 | 129 | // 上一页 130 | if(key == 'B' && page_idx > 0) 131 | { 132 | --page_idx; 133 | show_procs_page(buf, cnt, page_idx, true); 134 | } 135 | } 136 | 137 | free_ker_page(buf); 138 | clr_sysmsgs(); 139 | } 140 | -------------------------------------------------------------------------------- /src/include/kernel/filesys/afs/afs.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_FILESYS_AFS_AFS_H 2 | #define TINY_OS_FILESYS_AFS_AFS_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | /* 12 | FIXME:1M以上的文件导入可能导致目录文件写坏 13 | 这个bug好让人绝望,我为什么要设计索引树结构啊…… 14 | */ 15 | 16 | struct afs_dp_head; 17 | struct afs_file_desc; 18 | 19 | /*====================================================== 20 | 目录文件格式描述: 21 | uint32_t count; // 目录项数量 22 | uint32_t zone; // 目录项空间大小 23 | { 24 | char name[MAX + 1]; // 文件名 25 | uint32_t entry_index; // 文件entry位置 26 | } * count; 27 | ======================================================*/ 28 | 29 | void init_afs(); 30 | 31 | void destroy_afs(); 32 | 33 | /* 单个文件名最大长度 */ 34 | #define AFS_FILE_NAME_MAX_LENGTH FILE_NAME_MAX_LEN 35 | 36 | /* 37 | 以下函数均为线程安全,遇到互斥时会操作失败 38 | 具体调用结果应通过rt获得,无rt形参表示在参数合法时函数执行不可能失败。 39 | */ 40 | 41 | bool afs_reformat_dp(uint32_t beg, uint32_t cnt); 42 | 43 | struct afs_dp_head *afs_init_dp_handler(uint32_t beg); 44 | 45 | void afs_restore_dp_handler(uint32_t handler); 46 | 47 | void afs_release_dp_handler(uint32_t handler); 48 | 49 | struct afs_file_desc *afs_open_regular_file_for_reading_by_path( 50 | struct afs_dp_head *head, 51 | const char *path, 52 | enum afs_file_operation_status *rt); 53 | 54 | struct afs_file_desc * afs_open_regular_file_for_writing_by_path( 55 | struct afs_dp_head *head, 56 | const char *path, 57 | enum afs_file_operation_status *rt); 58 | 59 | struct afs_file_desc *afs_open_dir_file_for_reading_by_path( 60 | struct afs_dp_head *head, 61 | const char *path, 62 | enum afs_file_operation_status *rt); 63 | 64 | struct afs_file_desc *afs_open_dir_file_for_writing_by_path( 65 | struct afs_dp_head *head, 66 | const char *path, 67 | enum afs_file_operation_status *rt); 68 | 69 | void afs_close_file(struct afs_dp_head *head, 70 | struct afs_file_desc *file_desc); 71 | 72 | uint32_t afs_create_dir_file_raw(struct afs_dp_head *head, 73 | uint32_t parent_dir, bool root, 74 | enum afs_file_operation_status *rt); 75 | 76 | void afs_create_dir_file_by_path(struct afs_dp_head *head, 77 | const char *path, 78 | enum afs_file_operation_status *rt); 79 | 80 | void afs_create_regular_file_by_path(struct afs_dp_head *head, 81 | const char *path, 82 | enum afs_file_operation_status *rt); 83 | 84 | void afs_remove_file_by_path(struct afs_dp_head *head, 85 | const char *path, 86 | uint32_t type, 87 | enum afs_file_operation_status *rt); 88 | 89 | uint32_t afs_get_file_byte_size(struct afs_file_desc *file); 90 | 91 | void afs_expand_regular_file(struct afs_dp_head *head, 92 | struct afs_file_desc *file, 93 | uint32_t new_size, 94 | enum afs_file_operation_status *rt); 95 | 96 | enum afs_file_operation_status afs_get_dir_unit(struct afs_dp_head *head, 97 | struct afs_file_desc *dir, 98 | uint32_t idx, 99 | struct syscall_filesys_file_info *info); 100 | 101 | #endif /* TINY_OS_FILESYS_AFS_AFS_H */ 102 | -------------------------------------------------------------------------------- /src/include/shared/filesys.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_SHARD_FILESYS_FILESYS_H 2 | #define TINY_OS_SHARD_FILESYS_FILESYS_H 3 | 4 | #include 5 | #include 6 | 7 | /*================================================================================ 8 | 文件系统相关 9 | ================================================================================*/ 10 | 11 | enum filesys_opr_result 12 | { 13 | filesys_opr_success, // 操作成功完成 14 | filesys_opr_locked, // 文件有互斥锁(读/写均有可能) 15 | filesys_opr_out_of_range, // 超出文件大小范围 16 | filesys_opr_no_disk_space, // 磁盘空间不足 17 | filesys_opr_read_only, // 对只读文件进行改动 18 | filesys_opr_not_found, // 文件不存在 19 | filesys_opr_existed, // 已有同名文件 20 | filesys_opr_rm_nonempty, // 试图删除非空目录 21 | filesys_opr_invalid_dp, // 非法文件分区 22 | filesys_opr_file_table_full, // 进程打开的文件数过多 23 | filesys_opr_invalid_args, // 参数非法 24 | filesys_opr_wrong_type, // 常规文件和目录文件混淆 25 | filesys_opr_others, // 其他错误 26 | }; 27 | 28 | #define FILE_NAME_MAX_LEN 63 29 | 30 | typedef uint32_t file_handle; 31 | 32 | typedef uint32_t filesys_dp_handle; 33 | 34 | typedef atrc_elem_handle usr_file_handle; 35 | 36 | /*================================================================================ 37 | 磁盘分区类型 38 | 取值见下方宏定义 39 | ================================================================================*/ 40 | typedef uint32_t disk_partition_type; 41 | 42 | #define DISK_PT_NONEXISTENT 0 /* 不存在(分区表项无效) */ 43 | #define DISK_PT_NOFS 1 /* 存在但未格式化 */ 44 | #define DISK_PT_SWAP 2 /* 交换分区 */ 45 | #define DISK_PT_IMPORT 3 /* 文件交换分区,用于测试时从外部将文件导入虚拟机 */ 46 | #define DISK_PT_AFS 4 /* 建立了AFS */ 47 | 48 | #define DISK_PT_FORMATTING 255 /* 格式化中,禁止访问 */ 49 | 50 | /* 分区名字最大长度 */ 51 | #define DP_NAME_BUF_SIZE 16 52 | 53 | /* 分区表项数,注意整个分区表不要超过一个扇区大小 */ 54 | #define DPT_UNIT_COUNT 16 55 | 56 | /* 分区表单位结构 */ 57 | struct dpt_unit 58 | { 59 | disk_partition_type type; 60 | uint32_t sector_begin; 61 | uint32_t sector_end; 62 | char name[DP_NAME_BUF_SIZE]; 63 | }; 64 | 65 | /* 分区表本身位于ata0磁盘中的LBA扇区号 */ 66 | #define DPT_SECTOR_POSITION 300 67 | 68 | /*================================================================================ 69 | Import分区分区结构: 70 | uint32_t file_count: 分区中有多少个文件 71 | ipt_disk_file { 72 | uint32_t dp : 分区号 73 | path[IPT_PATH_BUF_SIZE] : 文件路径 74 | uint32_t file_byte_size : 文件字节数 75 | byte file[file_byte_size] : 文件内容 76 | } * file_count 77 | 注意这个结构是packed的,不要引入任何对齐padding 78 | ================================================================================*/ 79 | 80 | #define IPT_PATH_BUF_SIZE 64 81 | 82 | /*================================================================================ 83 | 文件系统相关的系统调用的参数结构体 84 | ================================================================================*/ 85 | 86 | struct syscall_filesys_open_params 87 | { 88 | bool writing; 89 | filesys_dp_handle dp; 90 | const char *path; 91 | usr_file_handle *result; 92 | }; 93 | 94 | struct syscall_filesys_read_params 95 | { 96 | usr_file_handle file; 97 | uint32_t fpos, byte_size; 98 | void *data_dst; 99 | }; 100 | 101 | struct syscall_filesys_write_params 102 | { 103 | usr_file_handle file; 104 | uint32_t fpos, byte_size; 105 | const void *data_src; 106 | }; 107 | 108 | struct syscall_filesys_get_child_info_params 109 | { 110 | filesys_dp_handle dp; 111 | const char *path; 112 | uint32_t idx; 113 | struct syscall_filesys_file_info *info; 114 | }; 115 | 116 | struct syscall_filesys_file_info 117 | { 118 | bool is_dir; 119 | char name[FILE_NAME_MAX_LEN + 1]; 120 | }; 121 | 122 | #endif /* TINY_OS_SHARD_FILESYS_FILESYS_H */ 123 | -------------------------------------------------------------------------------- /src/shared/sys/conio.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define CONSOLE_SYSCALL(N, arg) \ 7 | do { uint32_t dummy_ret; \ 8 | __asm__ __volatile__ ("int $0x80" \ 9 | : "=a" (dummy_ret) \ 10 | : "a" (SYSCALL_CONSOLE_OPERATION), \ 11 | "b" (N), \ 12 | "c" (arg) \ 13 | : "memory"); } while(0) 14 | 15 | #define CONSOLE_SYSCALL_RET(N, arg, ret) \ 16 | do { \ 17 | __asm__ __volatile__ ("int $0x80" \ 18 | : "=a" (ret) \ 19 | : "a" (SYSCALL_CONSOLE_OPERATION), \ 20 | "b" (N), \ 21 | "c" (arg) \ 22 | : "memory"); } while(0) 23 | 24 | void set_char_row_col(uint8_t row, uint8_t col, char ch) 25 | { 26 | uint32_t arg = ((row * 80 + col) << 16) | (uint8_t)ch; 27 | CONSOLE_SYSCALL(CONSOLE_SYSCALL_FUNCTION_SET_CHAR, arg); 28 | } 29 | 30 | void set_char_at(uint16_t pos, char ch) 31 | { 32 | set_char_row_col(pos / 80, pos % 80, ch); 33 | } 34 | 35 | void set_char_attrib_row_col(uint8_t row, uint8_t col, uint8_t attrib) 36 | { 37 | uint32_t arg = ((row * 80 + col) << 16) | (uint8_t)attrib; 38 | CONSOLE_SYSCALL(CONSOLE_SYSCALL_FUNCTION_SET_ATTRIB, arg); 39 | } 40 | 41 | void get_cursor_row_col(uint8_t *row, uint8_t *col) 42 | { 43 | uint32_t rt; 44 | CONSOLE_SYSCALL_RET(CONSOLE_SYSCALL_FUNCTION_GET_CURSOR, 0, rt); 45 | if(row) 46 | *row = (uint8_t)(rt / 80); 47 | if(col) 48 | *col = (uint8_t)(rt % 80); 49 | } 50 | 51 | void set_cursor_row_col(uint8_t row, uint8_t col) 52 | { 53 | uint32_t arg = 80 * row + col; 54 | CONSOLE_SYSCALL(CONSOLE_SYSCALL_FUNCTION_SET_CURSOR, arg); 55 | } 56 | 57 | char get_char_row_col(uint8_t row, uint8_t col) 58 | { 59 | uint32_t arg = 80 * row + col; 60 | uint32_t ret; 61 | CONSOLE_SYSCALL_RET(CONSOLE_SYSCALL_FUNCTION_GET_CHAR, arg, ret); 62 | return (char)ret; 63 | } 64 | 65 | void put_char(char ch) 66 | { 67 | uint32_t arg = ch; 68 | CONSOLE_SYSCALL(CONSOLE_SYSCALL_FUNCTION_PUT_CHAR, arg); 69 | } 70 | 71 | void put_str(const char *str) 72 | { 73 | while(*str) 74 | put_char(*str++); 75 | } 76 | 77 | void printf(const char *fmt, ...) 78 | { 79 | const char *next_param = (const char *)&fmt + 4; 80 | char int_buf[32]; 81 | while(*fmt) 82 | { 83 | if(*fmt == '%') 84 | { 85 | switch(*++fmt) 86 | { 87 | case 'u': 88 | uint32_to_str(*(uint32_t*)next_param, int_buf); 89 | put_str(int_buf); 90 | next_param += 4; 91 | break; 92 | case 's': 93 | put_str(*(char**)next_param); 94 | next_param += 4; 95 | break; 96 | case '%': 97 | put_char('%'); 98 | break; 99 | case 'c': 100 | put_char((char)*(uint32_t*)next_param); 101 | next_param += 4; 102 | break; 103 | case '\0': 104 | return; 105 | case 'L': 106 | expl_new_line(); 107 | break; 108 | } 109 | ++fmt; 110 | } 111 | else 112 | put_char(*fmt++); 113 | } 114 | } 115 | 116 | void roll_scr(uint32_t beg_row, uint32_t end_row) 117 | { 118 | uint32_t arg = (((beg_row & 0xff) << 8) | (end_row & 0xff)) & 0xffff; 119 | CONSOLE_SYSCALL(CONSOLE_SYSCALL_FUNCTION_ROLL_SCREEN_BETWEEN, arg); 120 | } 121 | 122 | void clr_scr() 123 | { 124 | CONSOLE_SYSCALL(CONSOLE_SYSCALL_FUNCTION_CLEAR_SCREEN, 0); 125 | } 126 | 127 | void set_scr(void *data) 128 | { 129 | CONSOLE_SYSCALL(CONSOLE_SYSCALL_FUNCTION_SET_BUFFER_DATA, data); 130 | } 131 | -------------------------------------------------------------------------------- /src/include/shared/syscall.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_SHARD_SYSCALL_H 2 | #define TINY_OS_SHARD_SYSCALL_H 3 | 4 | /* 系统调用入口数量 */ 5 | #define SYSCALL_COUNT 25 6 | 7 | /* 一个合法的系统调用应返回void或uint32_t,有0~3个uint32_t大小的参数 */ 8 | 9 | /* 10 | 取得当前进程ID 11 | uint32_t impl(); 12 | */ 13 | #define SYSCALL_GET_PROCESS_ID 0 14 | 15 | /* 暂时让出CPU让别的线程执行,无参数无返回值 */ 16 | #define SYSCALL_YIELD_CPU (SYSCALL_GET_PROCESS_ID + 1) 17 | 18 | /* 干掉自己所处的线程,无参数无返回值 */ 19 | #define SYSCALL_EXIT_THREAD (SYSCALL_YIELD_CPU + 1) 20 | 21 | /* 22 | 在本进程中创建一个新线程 23 | uint32_t impl(void(*entry)()); 24 | 返回false时创建失败 25 | */ 26 | #define SYSCALL_NEW_THREAD (SYSCALL_EXIT_THREAD + 1) 27 | 28 | /* 29 | 控制台操作 30 | func和arg含义见 kernel/console/console.h 31 | uint32_t impl(uint32_t func, uint32_t arg); 32 | */ 33 | #define SYSCALL_CONSOLE_OPERATION (SYSCALL_NEW_THREAD + 1) 34 | 35 | /* 36 | 系统消息队列操作 37 | 参数含义见 kernel/sysmsg/proc_sysmsg_syscall.h 38 | uint32_t impl(uint32_t func, uint32_t arg1, uint32_t arg2); 39 | */ 40 | #define SYSCALL_SYSMSG_OPERATION (SYSCALL_CONSOLE_OPERATION + 1) 41 | 42 | /* 43 | 键盘查询 44 | 参数含义见kernel/kbdriver.h 45 | uint32_t impl(uint32_t func, uint32_t arg); 46 | */ 47 | #define SYSCALL_KEYBOARD_QUERY (SYSCALL_SYSMSG_OPERATION + 1) 48 | 49 | /* 文件系统相关,参数见kernel/filesys/syscall.h */ 50 | 51 | #define SYSCALL_FILESYS_OPEN (SYSCALL_KEYBOARD_QUERY + 1) 52 | #define SYSCALL_FILESYS_CLOSE (SYSCALL_FILESYS_OPEN + 1) 53 | 54 | #define SYSCALL_FILESYS_MKFILE (SYSCALL_FILESYS_CLOSE + 1) 55 | #define SYSCALL_FILESYS_RMFILE (SYSCALL_FILESYS_MKFILE + 1) 56 | 57 | #define SYSCALL_FILESYS_MKDIR (SYSCALL_FILESYS_RMFILE + 1) 58 | #define SYSCALL_FILESYS_RMDIR (SYSCALL_FILESYS_MKDIR + 1) 59 | 60 | #define SYSCALL_FILESYS_GET_SIZE (SYSCALL_FILESYS_RMDIR + 1) 61 | 62 | #define SYSCALL_FILESYS_READ (SYSCALL_FILESYS_GET_SIZE + 1) 63 | #define SYSCALL_FILESYS_WRITE (SYSCALL_FILESYS_READ + 1) 64 | 65 | #define SYSCALL_FILESYS_GET_CHILD_COUNT (SYSCALL_FILESYS_WRITE + 1) 66 | 67 | #define SYSCALL_FILESYS_GET_CHILD_INFO (SYSCALL_FILESYS_GET_CHILD_COUNT + 1) 68 | 69 | #define SYSCALL_DP_GET_HANDLE (SYSCALL_FILESYS_GET_CHILD_INFO + 1) 70 | 71 | /* 72 | 申请称为当前的前台进程,无参数 73 | 成功时返回true;若此时有别的前台进程,则会申请失败,返回false 74 | */ 75 | #define SYSCALL_EXPL_ALLOC_FOREGROUND (SYSCALL_DP_GET_HANDLE + 1) 76 | 77 | /* 78 | 把自己切到后台 79 | 若自己本来就不处于前台,返回false;否则切换成功,返回true 80 | */ 81 | #define SYSCALL_EXPL_FREE_FOREGROUND (SYSCALL_EXPL_ALLOC_FOREGROUND + 1) 82 | 83 | #define SYSCALL_EXPL_ALLOC_CON_BUF (SYSCALL_EXPL_FREE_FOREGROUND + 1) 84 | 85 | /* 86 | 在disp区域输出一个字符 87 | 若调用方有自己的显示缓存,那么什么也不做,直接返回 88 | 若调用方处于前台,那么输出字符后返回 89 | 若调用方处于后台,那么一直等待直到进程被切换到前台后才输出字符并返回 90 | 91 | 仅一个参数 uint32_t arg,其最低字节为要输出的字符 92 | */ 93 | #define SYSCALL_EXPL_PUT_CHAR (SYSCALL_EXPL_ALLOC_CON_BUF + 1) 94 | 95 | #define SYSCALL_EXPL_NEW_LINE (SYSCALL_EXPL_PUT_CHAR + 1) 96 | 97 | #define SYSCALL_PIPE_NULL_CHAR (SYSCALL_EXPL_NEW_LINE + 1) 98 | 99 | #define syscall_param0(N) \ 100 | ({ uint32_t r; \ 101 | asm volatile ("int $0x80;" \ 102 | : "=a" (r) \ 103 | : "a" (N) \ 104 | : "memory"); \ 105 | r; }) 106 | 107 | #define syscall_param1(N, arg1) \ 108 | ({ uint32_t r; \ 109 | asm volatile ("int $0x80" \ 110 | : "=a" (r) \ 111 | : "a" (N), "b" (arg1) \ 112 | : "memory"); \ 113 | r; }) 114 | 115 | #define syscall_param2(N, arg1, arg2) \ 116 | ({ uint32_t r; \ 117 | asm volatile ("int $0x80" \ 118 | : "=a" (r) \ 119 | : "a" (N), "b" (arg1), "c" (arg2) \ 120 | : "memory"); \ 121 | r; }) 122 | 123 | #define syscall_param3(N, arg1, arg2, arg3) \ 124 | ({ uint32_t r; \ 125 | asm volatile ("int $0x80" \ 126 | : "=a" (r) \ 127 | : "a" (N), "b" (arg1), "c" (arg2), "d" (arg3) \ 128 | : "memory"); \ 129 | r; }) 130 | 131 | #endif /* TINY_OS_SHARD_SYSCALL_H */ 132 | -------------------------------------------------------------------------------- /src/kernel/interrupt/interrupt.s: -------------------------------------------------------------------------------- 1 | [bits 32] 2 | 3 | %define WITH_ERR_CODE push 0 4 | %define WITHOUT_ERR_CODE nop 5 | 6 | extern put_str 7 | extern intr_function 8 | 9 | %macro INTR_VECTOR 2 10 | section .intr_vec_text 11 | intr_%1_entry: 12 | ; 统一错误码所占栈空间 13 | %2 14 | 15 | push ds 16 | push es 17 | push fs 18 | push gs 19 | pushad 20 | 21 | push eax 22 | mov ax, 0x10 23 | mov ds, ax 24 | mov es, ax 25 | mov fs, ax 26 | mov gs, ax 27 | pop eax 28 | 29 | mov al, 0x20 30 | out 0xa0, al 31 | out 0x20, al 32 | 33 | push dword %1 ; 中断号作为intr_function参数,不管对方用不用 34 | call [intr_function + %1 * 4] 35 | 36 | jmp intr_proc_end 37 | 38 | section .intr_vec_data 39 | dd intr_%1_entry 40 | %endmacro 41 | 42 | section .intr_vec_text 43 | global intr_proc_end 44 | intr_proc_end: 45 | add esp, 4 ; 弹出中断号和错误码参数 46 | popad 47 | pop gs 48 | pop fs 49 | pop es 50 | pop ds 51 | add esp, 4 ; 弹出错误码 52 | iret 53 | 54 | section .intr_vec_data 55 | 56 | global intr_entry_table 57 | intr_entry_table: 58 | 59 | INTR_VECTOR 0x00, WITH_ERR_CODE ; 除0 60 | INTR_VECTOR 0x01, WITH_ERR_CODE ; debug 61 | INTR_VECTOR 0x02, WITH_ERR_CODE ; NMI 62 | INTR_VECTOR 0x03, WITH_ERR_CODE ; 断点 63 | INTR_VECTOR 0x04, WITH_ERR_CODE ; INTF 64 | INTR_VECTOR 0x05, WITH_ERR_CODE ; 越界 65 | INTR_VECTOR 0x06, WITH_ERR_CODE ; 未知指令 66 | INTR_VECTOR 0x07, WITH_ERR_CODE ; 设备不可用 67 | INTR_VECTOR 0x08, WITHOUT_ERR_CODE ; double fault 68 | INTR_VECTOR 0x09, WITH_ERR_CODE ; 无fpu 69 | INTR_VECTOR 0x0a, WITHOUT_ERR_CODE ; 非法TSS 70 | INTR_VECTOR 0x0b, WITHOUT_ERR_CODE ; seg not p 71 | INTR_VECTOR 0x0c, WITH_ERR_CODE ; 栈段GG 72 | INTR_VECTOR 0x0d, WITHOUT_ERR_CODE ; GP 73 | INTR_VECTOR 0x0e, WITHOUT_ERR_CODE ; pagefault 74 | INTR_VECTOR 0x0f, WITH_ERR_CODE ; reserved 75 | INTR_VECTOR 0x10, WITH_ERR_CODE ; 浮点错误 76 | INTR_VECTOR 0x11, WITHOUT_ERR_CODE ; alignment check 77 | INTR_VECTOR 0x12, WITH_ERR_CODE ; machine check 78 | INTR_VECTOR 0x13, WITH_ERR_CODE ; SIMD浮点异常 79 | INTR_VECTOR 0x14, WITH_ERR_CODE ; reserved 80 | INTR_VECTOR 0x15, WITH_ERR_CODE ; reserved 81 | INTR_VECTOR 0x16, WITH_ERR_CODE ; reserved 82 | INTR_VECTOR 0x17, WITH_ERR_CODE ; reserved 83 | INTR_VECTOR 0x18, WITHOUT_ERR_CODE ; reserved 84 | INTR_VECTOR 0x19, WITH_ERR_CODE ; reserved 85 | INTR_VECTOR 0x1a, WITHOUT_ERR_CODE ; reserved 86 | INTR_VECTOR 0x1b, WITHOUT_ERR_CODE ; reserved 87 | INTR_VECTOR 0x1c, WITH_ERR_CODE ; reserved 88 | INTR_VECTOR 0x1d, WITHOUT_ERR_CODE ; reserved 89 | INTR_VECTOR 0x1e, WITHOUT_ERR_CODE ; reserved 90 | INTR_VECTOR 0x1f, WITH_ERR_CODE ; reserved 91 | INTR_VECTOR 0x20, WITH_ERR_CODE ; 时钟 92 | INTR_VECTOR 0x21, WITH_ERR_CODE ; 键盘 93 | INTR_VECTOR 0x22, WITH_ERR_CODE ; 级联用 94 | INTR_VECTOR 0x23, WITH_ERR_CODE ; 串口2 95 | INTR_VECTOR 0x24, WITH_ERR_CODE ; 串口1 96 | INTR_VECTOR 0x25, WITH_ERR_CODE ; 并口2 97 | INTR_VECTOR 0x26, WITH_ERR_CODE ; 软盘 98 | INTR_VECTOR 0x27, WITH_ERR_CODE ; 并口1 99 | INTR_VECTOR 0x28, WITH_ERR_CODE ; 实时时钟 100 | INTR_VECTOR 0x29, WITH_ERR_CODE ; 重定向 101 | INTR_VECTOR 0x2a, WITH_ERR_CODE ; reserved 102 | INTR_VECTOR 0x2b, WITH_ERR_CODE ; reserved 103 | INTR_VECTOR 0x2c, WITH_ERR_CODE ; ps/2鼠标 104 | INTR_VECTOR 0x2d, WITH_ERR_CODE ; fpu异常 105 | INTR_VECTOR 0x2e, WITH_ERR_CODE ; 硬盘 106 | INTR_VECTOR 0x2f, WITH_ERR_CODE ; reserved 107 | 108 | extern syscall_func_table 109 | 110 | section .text 111 | 112 | global global_syscall_entry 113 | global_syscall_entry: 114 | 115 | push 0 116 | push ds 117 | push es 118 | push fs 119 | push gs 120 | pushad 121 | 122 | push eax 123 | mov ax, 0x10 124 | mov ds, ax 125 | mov es, ax 126 | mov fs, ax 127 | mov gs, ax 128 | pop eax 129 | 130 | push 0x80 131 | 132 | push edx 133 | push ecx 134 | push ebx 135 | call [syscall_func_table + eax * 4] 136 | 137 | add esp, 12 138 | mov [esp + 4 * 8], eax 139 | jmp intr_proc_end 140 | -------------------------------------------------------------------------------- /src/kernel/execelf/execelf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | /* 12 | exec要完成以下事情(顺序无先后): 13 | 创建进程 14 | 进程参数填充 15 | 装载进程代码 16 | 17 | 步骤: 18 | 1. 关中断 19 | 2. 创建一个虚拟地址空间A,把自己的虚拟地址空间临时切换到A,没错这里需要改PCB,这个耦合我暂时想不到怎么去掉 20 | 因为等会儿读文件的时候会有进程切换,如果不改PCB,等切换回来的时候虚拟地址空间就不对了 21 | 3. 把elf文件内容装载好,把入口地址和参数都放到特定地址,注意这里读文件会执行调度器 22 | 4. 以A创建一个进程,执行入口是elf的入口地址 23 | 5. 把自己的PCB中的虚拟地址空间换回来 24 | 6. 恢复原中断状态 25 | 26 | elf入口函数自己去把命令行参数从特定地址取出来 27 | */ 28 | 29 | /* elf文件缓存区大小 */ 30 | #define PROC_FILE_BUF_SIZE (100 * 1024 * 1024) 31 | 32 | /* elf文件缓存区起始地址 */ 33 | #define PROC_FILE_BUF_ADDR (PROC_ARG_ZONE_ADDR - PROC_FILE_BUF_SIZE) 34 | 35 | #define EXEC_ELF_EXIT(rt) \ 36 | do { \ 37 | pcb->addr_space = ori_addr_space; \ 38 | set_current_vir_addr_space(ori_addr_space); \ 39 | set_intr_state(is); \ 40 | return (rt); \ 41 | } while(0) 42 | 43 | #define EXEC_ELF_ERROR(rt) \ 44 | do { \ 45 | destroy_vir_addr_space(new_addr_space); \ 46 | EXEC_ELF_EXIT(rt); \ 47 | } while(0) 48 | 49 | enum exec_elf_result exec_elf(const char *proc_name, 50 | filesys_dp_handle dp, const char *elf_path, 51 | bool is_PL_0, uint32_t argc, const char **argv, 52 | uint32_t *_pid) 53 | { 54 | intr_state is = fetch_and_disable_intr(); 55 | struct PCB *pcb = get_cur_PCB(); 56 | 57 | ASSERT(argc < EXEC_ELF_ARG_MAX_COUNT); 58 | 59 | // 备份原虚拟地址空间,设置新的虚拟地址空间 60 | vir_addr_space *ori_addr_space = pcb->addr_space; 61 | vir_addr_space *new_addr_space = create_vir_addr_space(); 62 | pcb->addr_space = new_addr_space; 63 | set_current_vir_addr_space(new_addr_space); 64 | 65 | // 尝试打开elf文件 66 | usr_file_handle fp; 67 | if(open_file(dp, elf_path, false, &fp) != filesys_opr_success) 68 | EXEC_ELF_ERROR(exec_elf_file_error); 69 | 70 | // 检查文件大小是否越界 71 | uint32_t file_size = get_file_size(fp); 72 | if(file_size > PROC_FILE_BUF_SIZE) 73 | { 74 | close_file(fp); 75 | EXEC_ELF_ERROR(exec_elf_file_error); 76 | } 77 | 78 | // 读取文件缓存 79 | if(read_file(fp, 0, file_size, (void*)PROC_FILE_BUF_ADDR) 80 | != filesys_opr_success) 81 | { 82 | close_file(fp); 83 | EXEC_ELF_ERROR(exec_elf_file_error); 84 | } 85 | 86 | close_file(fp); 87 | 88 | // 装载elf 89 | size_t prog_beg, prog_end; 90 | void *entry_addr = load_elf((const void*)PROC_FILE_BUF_ADDR, 91 | &prog_beg, &prog_end); 92 | if(!entry_addr) 93 | EXEC_ELF_ERROR(exec_elf_invalid_elf); 94 | 95 | // 拷贝参数到缓存区域 96 | char *p_buf = (char*)PROC_ARG_ZONE_ADDR; 97 | *(uint32_t*)p_buf = argc; 98 | p_buf += sizeof(uint32_t); 99 | for(uint32_t i = 0; i < argc; ++i) 100 | { 101 | strcpy_s(p_buf, argv[i], EXEC_ELF_ARG_BUF_SIZE); 102 | p_buf += EXEC_ELF_ARG_BUF_SIZE; 103 | } 104 | 105 | // 放置usr_addr_interval 106 | struct usr_addr_interval *free_space = 107 | (struct usr_addr_interval *)USR_ADDR_INTERVAL_ADDR; 108 | 109 | free_space->beg1 = USR_ADDR_INTERVAL_ADDR + 110 | sizeof(struct usr_addr_interval); 111 | free_space->size1 = (prog_beg > free_space->beg1) ? 112 | (prog_beg - free_space->beg1) : 0; 113 | free_space->beg2 = prog_end; 114 | free_space->size2 = (PROC_ARG_ZONE_ADDR > free_space->beg2) ? 115 | (PROC_ARG_ZONE_ADDR - free_space->beg2) : 0; 116 | 117 | // 进程创建 118 | uint32_t pid = create_process_with_addr_space( 119 | proc_name, (process_exec_func)entry_addr, 120 | new_addr_space, is_PL_0); 121 | if(_pid) 122 | *_pid = pid; 123 | 124 | EXEC_ELF_EXIT(exec_elf_success); 125 | } 126 | 127 | #undef EXEC_ELF_ERROR 128 | #undef EXEC_ELF_EXIT 129 | -------------------------------------------------------------------------------- /src/include/shared/sys.h: -------------------------------------------------------------------------------- 1 | #ifndef TINY_OS_SHARD_SYS_H 2 | #define TINY_OS_SHARD_SYS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | /* 进程/线程相关 */ 11 | 12 | uint32_t get_pid(); 13 | 14 | void yield_cpu(); 15 | 16 | void exit_thread(); 17 | 18 | bool new_thread(void (*entry)()); 19 | 20 | /* 屏幕输出相关 */ 21 | 22 | void set_char_row_col(uint8_t row, uint8_t col, char ch); 23 | 24 | void set_char_at(uint16_t pos, char ch); 25 | 26 | void set_char_attrib_row_col(uint8_t row, uint8_t col, uint8_t attrib); 27 | 28 | void get_cursor_row_col(uint8_t *row, uint8_t *col); 29 | 30 | void set_cursor_row_col(uint8_t row, uint8_t col); 31 | 32 | char get_char_row_col(uint8_t row, uint8_t col); 33 | 34 | void put_char(char ch); 35 | 36 | void put_str(const char *str); 37 | 38 | void printf(const char *fmt, ...); 39 | 40 | void roll_scr(uint32_t beg_row, uint32_t end_row); 41 | 42 | void clr_scr(); 43 | 44 | void set_scr(void *data); 45 | 46 | /* 文件系统相关 */ 47 | 48 | enum filesys_opr_result open_file(filesys_dp_handle dp, 49 | const char *path, bool writing, 50 | usr_file_handle *result); 51 | 52 | enum filesys_opr_result close_file(usr_file_handle file); 53 | 54 | enum filesys_opr_result make_file(filesys_dp_handle dp, 55 | const char *path); 56 | 57 | enum filesys_opr_result remove_file(filesys_dp_handle dp, 58 | const char *path); 59 | 60 | enum filesys_opr_result make_directory(filesys_dp_handle dp, 61 | const char *path); 62 | 63 | enum filesys_opr_result remove_directory(filesys_dp_handle dp, 64 | const char *path); 65 | 66 | uint32_t get_file_size(usr_file_handle file); 67 | 68 | enum filesys_opr_result write_file(usr_file_handle file, 69 | uint32_t fpos, uint32_t byte_size, 70 | const void *data); 71 | 72 | enum filesys_opr_result read_file(usr_file_handle file, 73 | uint32_t fpos, uint32_t byte_size, 74 | void *data); 75 | 76 | enum filesys_opr_result get_child_file_count(filesys_dp_handle dp, 77 | const char *path, 78 | uint32_t *rt); 79 | 80 | enum filesys_opr_result get_child_file_info(filesys_dp_handle dp, 81 | const char *path, 82 | uint32_t idx, 83 | struct syscall_filesys_file_info *rt); 84 | 85 | filesys_dp_handle get_dp(const char *name); 86 | 87 | /* 键盘状态与消息相关 */ 88 | 89 | /* 某个给定的按键是否处于按压状态 */ 90 | bool is_key_pressed(uint8_t kc); 91 | 92 | /* 注册按键消息 */ 93 | void register_key_msg(); 94 | 95 | /* 注册字符消息 */ 96 | void register_char_msg(); 97 | 98 | #define is_kbmsg_down(MSG_PTR) \ 99 | ((((struct kbmsg_struct*)(MSG_PTR))->flags & KBMSG_FLAG_UP) == 0) 100 | 101 | #define is_kbmsg_up(MSG_PTR) (!is_kbmsg_down(MSG_PTR)) 102 | 103 | #define get_kbmsg_key(MSG_PTR) ((uint8_t)((struct kbmsg_struct*)(MSG_PTR))->key) 104 | 105 | #define get_chmsg_char(MSG_PTR) ((char)((struct kbchar_msg_struct*)(MSG_PTR))->ch) 106 | 107 | /* 消息队列相关 */ 108 | 109 | /* 查询消息队列是否不为空 */ 110 | bool has_sysmsg(); 111 | 112 | /* 尝试取走一条消息,opr见shared/sysmsg/common,无消息时返回false */ 113 | bool peek_sysmsg(uint32_t opr, struct sysmsg *msg); 114 | 115 | /* 阻塞自己,直到一条消息到来 */ 116 | void wait_for_sysmsg(); 117 | 118 | /* 清空消息队列 */ 119 | void clr_sysmsgs(); 120 | 121 | /* explorer相关 */ 122 | 123 | /* 申请成为前台进程,失败时返回false */ 124 | bool alloc_fg(); 125 | 126 | /* 申请称为后台进程,成功时返回true。若本来就处于后台,返回false */ 127 | bool free_fg(); 128 | 129 | /* 申请后台屏幕缓存,成功时返回true。若本来就有缓存或者内存不足,返回false */ 130 | bool alloc_con_buf(); 131 | 132 | /* 往expl屏幕上输出一个字符,具体行为见shared/syscall.h */ 133 | void put_char_expl(char ch); 134 | 135 | /* 让expl腾出一个新输出行,行为类似put_char_expl */ 136 | void expl_new_line(); 137 | 138 | /* 给管道目标输送一个空字符 */ 139 | void pipe_null_char(); 140 | 141 | #endif /* TINY_OS_SHARD_SYS_H */ 142 | --------------------------------------------------------------------------------