前言:
相信每個自學操作系統的同學,大致學習路線都離不開 HIT-OS、MIT-6.S081、MIT-6.824、MIT-6.828等經典的公開課。但學習完這些經典公開課并完成相應的Lab,很多同學腦海中對于操作系統的知識其實都是零散的,讓你從頭開始編寫一個操作系統,我相信大部分人還是無從下手。因為Lab只是修改相應的核心模塊,對于整體系統的組織、模塊間的處理等細節,往往沒有人去關注,也就是說我們還需要進一步把這些概念串起來、鞏固起來。那么,我相信大部分人都有過一個想法:“我能不能自己寫一個操作系統”,這可能是大部分操作系統開發人員的夢想吧。
因此!本項目將展示如何從零開始使用 ANSI C 編寫出一個基于 64 位 RISC-V 架構的操作系統——Jokerix,該系統支持在內核上運行用戶態(User/Application mode)的終端,并輸入命令執行其他程序。
源碼公開:Joker001014/Jokerix (github.com)
目錄:
0 前置知識 【Create my OS】0 前置知識 | JokerDebug (joker001014.github.io)
0.1 RISC-V硬件機制0.2 RISC-V 匯編0.3 SBI 規范0.4 GDB 調試0.5 Jokerix 體系結構0.6 實驗環境
1 最小內核 【Create my OS】1 最小內核 | JokerDebug (joker001014.github.io)
1.1 內核入口點1.2 生成內核鏡像1.3 使用 QEMU 運行1.4 封裝 SBI接口
2 開啟中斷 【Create my OS】2 開啟中斷 | JokerDebug (joker001014.github.io)
2.1 RISC-V 中斷機制2.2 觸發斷點2.3 中斷上下文2.4 開啟時鐘中斷
3 內存管理 【Create my OS】3 內存管理 | JokerDebug (joker001014.github.io)
3.1 Buddy System3.2 動態內存分配3.3 內存按頁分配框架3.4 基于線段樹的頁幀分配
4 虛擬內存 【Create my OS】4 虛擬內存 | JokerDebug (joker001014.github.io)
4.1 Sv39內核映射4.2 實現頁表4.3 內核重映射
5 內核線程 【Create my OS】5 內核線程 | JokerDebug (joker001014.github.io)
5.1 線程切換5.2 構造線程結構5.3 從啟動線程到新線程
6 線程調度 【Create my OS】6 線程調度 | JokerDebug (joker001014.github.io)
6.1 線程管理6.2 調度線程6.3 Round-Robin 調度算法6.4 調度測試
7 用戶線程 【Create my OS】7 用戶線程 | JokerDebug (joker001014.github.io)
7.1 創建用戶程序7.2 實現系統調用7.3 進程內存空間7.4 創建用戶進程
8 文件系統 【Create my OS】8 文件系統 | JokerDebug (joker001014.github.io)
8.1 SimpleFS8.2 打包鏡像8.3 內核文件驅動8.4 文件系統測試
9 實現終端 【Create my OS】9 實現終端 | JokerDebug (joker001014.github.io)
9.1 鍵盤中斷9.2 條件變量與輸入緩沖9.3 echo 程序9.4 實現終端
編寫代碼文件時間線:
步驟 | 功能 | 文件(斜體表示二次修改) |
---|---|---|
1 | CPU自檢,跳轉到Bootloader | / |
2 | 將內核代碼從磁盤加載到內存(Bootloader),由OpenSBI提供:把 CPU 從 M-Mode 切換到 S-Mode,并跳轉到一個固定的地址 0x80200000 處 | / |
3 | 編寫內核入口點:設置OS啟動棧,跳轉到main.c 執行 | kernel/entry.S kernel/main.c |
4 | 將entry.S 和main.c 編譯和鏈接生成ELF文件(需存放在0x80200000 ),進一步生成二進制鏡像文件 | Makefile kernel/kernel.ld |
5 | QEMU加載鏡像文件,至此成功運行操作系統。 | / |
6 | 封裝SBI接口ecall ;調用SBI接口實現 printf 功能 | kernel/sbi.h kernel/printf.c |
7 | 封裝CSR讀寫;初始化中斷處理程序入口,設置斷點中斷處理程序 | kernel/riscv.h kernel/interrupt.c |
8 | 保存和恢復中斷上下文信息 | kernel/context.h kernel/interrupt.S |
9 | 初始化開啟時鐘中斷,設置時鐘中斷處理程序 | kernel/timer.c kernel/interrupt.c |
10 | 基于二叉樹的動態內存分配,采用Buddy System Allocation算法 | kernel/heap.c kernel/consts.h |
11 | 基于線段樹的頁幀分配 | kernel/memory.c |
12 | 設置頁表,將內核運行在虛擬地址空間 | kernel/kernel.ld kernel/entry.S |
13 | 實現三級頁表,將內核各個段映射到頁表上 | kernel/mapping.c |
14 | 借助中斷恢復機制創建內核線程,及線程上下文切換 | kernel/thread.c kernel/switch.S kernel/context.h |
15 | 線程管理框架,創建調度線程 | kernel/processor.c kernel/thread.c |
16 | 實現Round-Robin線程調度算法 | kernele/rrscheduler.c |
17 | 實現系統調用 | user/syscall.h |
18 | 實現用戶態printf、動態內存分配、用戶程序入口點、用戶測試函數 | user/io.c user/malloc.c user/entry.c user/ulib.h user/hello.c |
19 | 編譯用戶程序并鏈接,將用戶程序合并到內核 | user/Makefile user/linkUser.asm |
20 | 處理用戶態系統調用 | kernel/interrupt.ckernel/syscall.c |
21 | 編譯的用戶程序為ELF文件,實現ELF文件加載和內存映射 | kernel/elf.c kernel/mapping.c |
22 | 創建用戶線程結構(創建用戶棧、創建內核棧、創建上下文) | kernel/thread.c kernel/mapping.c |
23 | 打包生成文件系統鏡像fs.img,將文件系統內容合并到內核 | mkfs/mksfs.c mkfs/simplefs.h kernel/linkFS.asm Makefile |
24 | 從文件系統中找到 Inode,加載 ELF 文件數據到字節數組中 | kernel/fs.c kernel/main.c kernel/thread.c |
25 | 處理鍵盤中斷,實現條件變量,維護等待線程隊列 | kernel/queue.c kernel/condition.c kernel/interrupt.c kernel/mapping.c kerne/processor.c |
26 | 標準輸入緩沖區,維護緩存內容和條件變量 | kernel/stdin.c |