├── .gitignore ├── LICENSE ├── Makefile ├── Makefile.lab ├── NJU-OS ├── 01-操作系统概述.md ├── 02-操作系统上的程序.md ├── 03-多处理器编程-从入门到放弃.md ├── 04-理解并发程序执行.md ├── 05-并发控制-互斥.md ├── 06-并发控制-同步.md ├── 07-真实世界的并发编程.md ├── 08-并发Bug和应对.md ├── 09-操作系统的状态机模型.md ├── 10-状态机模型的应用.md ├── 11-操作系统上的进程.md ├── 12-进程的地址空间.md ├── 13-系统调用和-UNIX-Shell.md ├── 14-C标准库的实现.md ├── 15-A-fork()-in-the-Road.md ├── 16-可执行文件.md ├── 17-可执行文件的加载.md ├── 18-xv6代码导读.md ├── 19-Xv6上下文切换.md ├── 20-处理器调度.md ├── 21-操作系统设计.md ├── 22-极限速通操作系统实验.md ├── 23-存储设备原理.md ├── 24-输入输出设备.md ├── 25-设备驱动程序.md ├── 26-文件系统API.md ├── 27-FAT和UNIX文件系统.md ├── 28-持久数据的可靠性.md ├── 29-Xv6文件系统实现.md ├── 31-Android系统.md ├── 32-课程总结.md └── doc │ ├── 2S-motherboard.jpg │ ├── 6502-pinout.jpg │ ├── 80486-arch.png │ ├── CAP-theorem.png │ ├── EPYC-NUMA.png │ ├── ERA-1101.png │ ├── EUV.png │ ├── FAT-dent.png │ ├── FAT-number.png │ ├── GPU-arch.png │ ├── IDA.png │ ├── Kirin-9000.jpg │ ├── MLFQ.png │ ├── Mandelbrot.png │ ├── NES-motherboard.png │ ├── Snipaste_2022-06-26_23-38-57.jpeg │ ├── Snipaste_2022-06-27_22-34-00.jpeg │ ├── UEFI-booting-seq.png │ ├── ajjl.png │ ├── altair-8800.jpg │ ├── android-activity.png │ ├── android-stack.png │ ├── apple-garage.png │ ├── apple2-inside.jpg │ ├── assassins-creed.jpg │ ├── av-bug.png │ ├── bios-firmware.png │ ├── boom-pipeline-detailed.png │ ├── calcomp-565.jpg │ ├── canary_with_miner.png │ ├── canonical-device.png │ ├── cat-crash-consistency.jpg │ ├── cdplay.gif │ ├── cgroups.jpg │ ├── cheating.png │ ├── cih-virus.png │ ├── contra.jpg │ ├── core-memory.jpg │ ├── deadlock-car.png │ ├── delay-memory-fig2-s.png │ ├── dining-philosophers.png │ ├── disk-mechanism.jpg │ ├── ext2-dirent.jpg │ ├── ext2-inode.gif │ ├── fake-hdd.jpg │ ├── fat32_layout.gif │ ├── floppy-drives.jpg │ ├── fortran-card.jpg │ ├── fortran-card.png │ ├── fritz.jpg │ ├── fs-ext2.png │ ├── fs-journaling.png │ ├── fsck-recovery.png │ ├── ghost-sched.png │ ├── hadoop-ecosystem.png │ ├── hard-disk-mag.jpg │ ├── hdd-capacity.png │ ├── image-20220702225528562.png │ ├── image-20220702230117046.png │ ├── image-20220709203704901.png │ ├── image-20220710150030702.png │ ├── image-20220713222913392.png │ ├── image-20220720205930587.png │ ├── image-20220724122254113.png │ ├── image-20220724144537165.png │ ├── image-20220724150505571.png │ ├── image-20220724151243599.png │ ├── image-20220724164401900.png │ ├── image-20220724223652446.png │ ├── image-20220724223842509.png │ ├── image-20220724235040023.png │ ├── image-20220724235129813.png │ ├── image-20220724235916216.png │ ├── image-20220725000355096.png │ ├── image-20220725213231744.png │ ├── image-20220725215330868.png │ ├── image-20220725215522290.png │ ├── image-20220725225115818.png │ ├── image-20220725225334403.png │ ├── image-20220725225427825.png │ ├── image-20220807154510653.png │ ├── image-20220807161153704.png │ ├── image-20220812215212517.png │ ├── image-20220812215528270.png │ ├── image-20220812215732141.png │ ├── image-20220812220208830.png │ ├── image-20220812232253998.png │ ├── intel-cpu-reset.png │ ├── ken-quote.png │ ├── kernel-rmap.png │ ├── knight.png │ ├── lfg.png │ ├── linux-bio.png │ ├── mag-draw-board.jpg │ ├── mag-drum.jpg │ ├── mai-fast13.jpg │ ├── mandelbrot-my.png │ ├── marsbot.png │ ├── mechanical-tm.jpg │ ├── mem-weak@2x.png │ ├── microkernel.jpg │ ├── microkernel.png │ ├── minix3-desktop.png │ ├── minixarch.png │ ├── nand-flash.jpg │ ├── nes-ppu.png │ ├── nes-scroll.gif │ ├── nes-sprite.png │ ├── nju-lib.jpg │ ├── nuke-launch.gif │ ├── os-classify.png │ ├── ov-bug.png │ ├── power-curve.png │ ├── process-groups-sessions.png │ ├── promises.png │ ├── ps-effect.jpg │ ├── qb.png │ ├── qin-rx.png │ ├── race.png │ ├── raid5.png │ ├── sc.png │ ├── sched-rr.png │ ├── sketchpad.png │ ├── social-media.png │ ├── sos-on-beach.jpg │ ├── speed-up.png │ ├── spinlock-scalability.png │ ├── ssd.png │ ├── tcmalloc.png │ ├── texture-mapping.jpg │ ├── tmux-cheatsheet.png │ ├── tocttou.png │ ├── tree-rotate.png │ ├── tty-session.png │ ├── unix-programs.png │ ├── upan.jpg │ ├── v-rally.png │ ├── vaccum-tube.png │ ├── waigua.png │ ├── x86-tso.png │ ├── xv6-process-memory.png │ └── xv6-syscalls.png ├── README.md ├── abstract-machine ├── .gitignore ├── LICENSE ├── Makefile ├── README ├── am │ ├── Makefile │ ├── include │ │ ├── am.h │ │ ├── amdev.h │ │ └── arch │ │ │ ├── mips32-nemu.h │ │ │ ├── native.h │ │ │ ├── riscv32-nemu.h │ │ │ ├── riscv64-mycpu.h │ │ │ ├── riscv64-nemu.h │ │ │ ├── spike.h │ │ │ ├── x86-nemu.h │ │ │ ├── x86-qemu.h │ │ │ └── x86_64-qemu.h │ └── src │ │ ├── native │ │ ├── cte.c │ │ ├── ioe.c │ │ ├── ioe │ │ │ ├── audio.c │ │ │ ├── disk.c │ │ │ ├── gpu.c │ │ │ ├── input.c │ │ │ └── timer.c │ │ ├── mpe.c │ │ ├── platform.c │ │ ├── platform.h │ │ ├── trap.S │ │ ├── trm.c │ │ └── vme.c │ │ └── x86 │ │ ├── nemu │ │ ├── cte.c │ │ ├── start.S │ │ ├── trap.S │ │ └── vme.c │ │ ├── qemu │ │ ├── boot │ │ │ ├── Makefile │ │ │ ├── genboot.py │ │ │ ├── main.c │ │ │ └── start.S │ │ ├── cte.c │ │ ├── ioe.c │ │ ├── mpe.c │ │ ├── start32.S │ │ ├── start64.S │ │ ├── trap32.S │ │ ├── trap64.S │ │ ├── trm.c │ │ ├── vme.c │ │ └── x86-qemu.h │ │ └── x86.h ├── klib │ ├── Makefile │ ├── include │ │ ├── klib-macros.h │ │ └── klib.h │ └── src │ │ ├── cpp.c │ │ ├── int64.c │ │ ├── stdio.c │ │ ├── stdlib.c │ │ └── string.c └── scripts │ ├── isa │ ├── x86.mk │ └── x86_64.mk │ ├── native.mk │ ├── platform │ └── qemu.mk │ ├── x86-qemu.mk │ └── x86_64-qemu.mk ├── amgame ├── .gitignore ├── Makefile ├── compile_commands.json ├── include │ ├── com.h │ ├── game.h │ ├── snake.h │ └── video.h ├── src │ ├── game.c │ ├── keyboard.c │ ├── snake.c │ └── video.c └── tags ├── crepl ├── Makefile ├── README.md ├── crepl.c └── 实验记录.md ├── frecov ├── Makefile ├── README.md ├── frecov.c └── 实验记录.md ├── images ├── 1.png ├── 3DhTVVP9avTrH.jpg ├── chenguanxi.jpg ├── crepl-demo.gif ├── fat-filename.png ├── fork状态图1.PNG ├── fork状态图2.PNG ├── frecov-example.png ├── frecov实验结果.png ├── git-fire.png ├── hog-cell-gradients.png ├── network-trace.png ├── python-repl.svg ├── rtfm.jpg ├── sperf-demo.gif ├── sperf.jpg ├── 图形化布局.PNG └── 实验结果.PNG ├── kernel ├── .gitignore ├── Makefile ├── compile_commands.json ├── framework │ ├── kernel.h │ └── main.c ├── include │ ├── common.h │ ├── devices.h │ └── os.h ├── src │ ├── dev │ │ ├── dev.c │ │ ├── dev_input.c │ │ ├── dev_sd.c │ │ ├── dev_tty.c │ │ └── dev_video.c │ ├── kmt.c │ ├── os.c │ └── pmm.c ├── tags └── test │ ├── am.h │ ├── common.h │ ├── test.c │ └── thread.h ├── libco ├── Makefile ├── README.md ├── co.c ├── co.h ├── demo │ ├── Makefile │ ├── demo.c │ ├── demo1.c │ ├── demo2.c │ ├── demo3.c │ ├── main.c │ ├── run.sh │ ├── test0.c │ ├── test1.c │ └── test2.c ├── tests │ ├── Makefile │ ├── co-test.h │ └── main.c └── 实验记录.md ├── pstree ├── Makefile ├── README.md ├── my-pstree.c └── pstree.c ├── sperf ├── Makefile ├── README.md ├── simple-sperf │ ├── Makefile │ └── sperf.c ├── sperf.c └── 实验记录.md └── thread ├── demo-thread.c ├── shm-test.c ├── stack-probe.c └── thread.h /.gitignore: -------------------------------------------------------------------------------- 1 | .* 2 | *.[oad] 3 | !.gitignore 4 | *~ 5 | a.out 6 | a.out-* 7 | *-32* 8 | *-64* 9 | *.pdf 10 | .DS_Store 11 | a.dSYM 12 | *.so 13 | *.out -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | export TOKEN := ??? 2 | 3 | # ----- DO NOT MODIFY ----- 4 | 5 | ifeq ($(NAME),) 6 | $(error Should make in each lab's directory) 7 | endif 8 | 9 | SRCS := $(shell find . -maxdepth 1 -name "*.c") 10 | DEPS := $(shell find . -maxdepth 1 -name "*.h") $(SRCS) 11 | CFLAGS += -O1 -std=gnu11 -ggdb -Wall -Werror -Wno-unused-result -Wno-unused-value -Wno-unused-variable 12 | 13 | .PHONY: all test clean 14 | 15 | .DEFAULT_GOAL := all 16 | 17 | $(NAME)-64: $(DEPS) # 64bit binary 18 | gcc -m64 $(CFLAGS) $(SRCS) -o $@ $(LDFLAGS) 19 | 20 | $(NAME)-32: $(DEPS) # 32bit binary 21 | gcc -m32 $(CFLAGS) $(SRCS) -o $@ $(LDFLAGS) 22 | 23 | $(NAME)-64.so: $(DEPS) # 64bit shared library 24 | gcc -fPIC -shared -m64 $(CFLAGS) $(SRCS) -o $@ $(LDFLAGS) 25 | 26 | $(NAME)-32.so: $(DEPS) # 32bit shared library 27 | gcc -fPIC -shared -m32 $(CFLAGS) $(SRCS) -o $@ $(LDFLAGS) 28 | 29 | clean: 30 | rm -f $(NAME)-64 $(NAME)-32 $(NAME)-64.so $(NAME)-32.so 31 | 32 | include ../Makefile.lab 33 | -------------------------------------------------------------------------------- /Makefile.lab: -------------------------------------------------------------------------------- 1 | # ----- DO NOT MODIFY ----- 2 | 3 | export COURSE := OS2022 4 | URL := 'http://jyywiki.cn/static/submit-os2022.sh' 5 | 6 | submit: 7 | @cd $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) && \ 8 | curl -sSLf '$(URL)' && \ 9 | curl -sSLf '$(URL)' | bash 10 | 11 | git: 12 | @git add $(shell find . -name "*.c") $(shell find . -name "*.h") -A --ignore-errors 13 | @while (test -e .git/index.lock); do sleep 0.1; done 14 | @(uname -a && uptime) | git commit -F - -q --author='tracer-nju ' --no-verify --allow-empty 15 | @sync 16 | -------------------------------------------------------------------------------- /NJU-OS/18-xv6代码导读.md: -------------------------------------------------------------------------------- 1 | # xv6 代码导读 2 | 3 | ## Overview 4 | 5 | 复习 6 | 7 | - 应用视角的操作系统:对象 + API 8 | - 把操作系统当提供服务的 “黑盒子” 9 | 10 | ------ 11 | 12 | 本次课回答的问题 13 | 14 | - **Q**: 如何理解 “操作系统就是 C 程序”? 15 | 16 | ------ 17 | 18 | 本次课主要内容 19 | 20 | - xv6 简介 21 | - xv6 代码导读 22 | 23 | ## 一、xv6 简介 24 | 25 | ### 1、UNIX 传奇 26 | 27 | 一万行代码得到一个真正的、好用的操作系统 28 | 29 | - [The UNIX time sharing system](https://dl.acm.org/doi/10.1145/357980.358014) (SOSP'73 and CACM'74) 30 | - 免费授权给高校使用,它实在太适合教学了! 31 | - [UNIX v6 book](http://jyywiki.cn/pages/OS/manuals/unix-v6-book.pdf) 32 | 33 | ![img](./doc/unix-programs.png) 34 | 35 | ### 2、xv6 系统调用 API 36 | 37 | 21 个系统调用 (参考 [sh-xv6.c](http://jyywiki.cn/pages/OS/2022/demos/sh-xv6.c) 使用的系统调用) 38 | 39 | ![img](./doc/xv6-syscalls.png) 40 | 41 | ### 3、xv6: UNIX v6 的现代 “克隆” 42 | 43 | 接近完整的 UNIX Shell 体验 44 | 45 | - 基本工具集 (wc, echo, cat, ...) 46 | - 命令执行、管道、重定向 47 | - 支持多处理器 48 | - Now in RISC-V! 49 | 50 | 它真的是一个 “可用” 的操作系统! 51 | 52 | - 时间回到 1970s 53 | - 这些系统调用就足够支撑刚才提到的应用 54 | - cc, as, ld, vi, sed, awk, troff, lp, ... 55 | 56 | ### 4、xv6 系统实现 57 | 58 | 这是一份包含了很多 Good Practice 的代码 59 | 60 | - 对初学者来说更像是一个 “艺术品” 61 | - 从代码里吸取智慧 62 | - 注释的方式,命名的方式等等 63 | 64 | ------ 65 | 66 | RTFM 67 | 68 | - [xv6: A simple, Unix-like teaching operating system](http://jyywiki.cn/pages/OS/manuals/xv6-riscv-rev2.pdf) 69 | - 宝藏手册,包含了所有细节和 “为什么要这么做”,推荐阅读 70 | 71 | ------ 72 | 73 | RTFSC 74 | 75 | - [xv6-riscv](https://github.com/mit-pdos/xv6-riscv) 76 | - 会分几次课讲解 77 | 78 | **jyy 大佬在学习 linux 代码的时候也会看不懂,但是他会联想 linux 下的代码对应到 xv6 上是哪里,他就明白了** 79 | 80 | ### 5、项目构建与运行 81 | 82 | RTFSC: Makefile 83 | 84 | - 相比 AbstractMachine (跨平台/体系结构) 容易很多 85 | - 先找到构建目标 86 | - 然后老规矩: `make -nB` 87 | - 你可以根据需要修改一些配置 88 | - 优化等级、CPU 数、编译指令等 89 | 90 | ------ 91 | 92 | 复习:“程序的执行 (状态变化序列) 有时比代码 (状态机) 更容易理解” 93 | 94 | - 可以用于配制 vscode 95 | - Quick quiz: 如何自动生成 `compile_commands.json`? 96 | 97 | ```bash 98 | $ bear make qemu 99 | ``` 100 | 101 | 所有的 vscode 中编译错误(所有的红线)就消失了 102 | 103 | **正确的工具太重要了,好的工具会促使人愿意去读代码,帮助人克服惰性** 104 | 105 | ## 二、xv6 中的进程 106 | 107 | ### 1、xv6 进程的地址空间 108 | 109 | 回顾:进程 = 运行的状态机 (user/) 110 | 111 | - gcc/ld 创建:代码、数据 112 | - 参考 ldscript 113 | - 运行时分配:堆栈 114 | - 包含 exec 的参数 115 | - 例子:`init.c` 和 `sh.c` ([sh-xv6.c](http://jyywiki.cn/pages/OS/2022/demos/sh-xv6.c) 的真身) 116 | 117 | ------ 118 | 119 | MAXVA 处有两个神奇的页面 120 | 121 | - Trampoline 和 trapframe 122 | - 由操作系统分配,用户进程无权访问 123 | 124 | ![img](./doc/xv6-process-memory.png) 125 | 126 | ### 2、调试用户代码 127 | 128 | 试一试 init 进程 129 | 130 | - `proc.c` 中包含一段 initcode 131 | - 我们可以调试它!(`b *0`) 132 | - 系统调用实现:编号放入 a7 寄存器,执行 ecall 指令 133 | - man 2 syscall 134 | - 然后再调试 `_init` 135 | - `add-symbol-file user/_init` 加载调试信息 136 | 137 | ------ 138 | 139 | 使用 QEMU 140 | 141 | - 查看地址空间 `info mem` 142 | - 对照手册,查看寄存器,例如 `p/x $stvec` 143 | - 可以打上断点 (`b *$stvec`) 144 | 145 | 【1:10:40】开始教大家调试 146 | 147 | make qemu-gdb 148 | 149 | ## 三、xv6 系统调用 150 | 151 | ### 1、xv6 系统调用 152 | 153 | RISC-V user-level ecall 指令 154 | 155 | - 关闭中断 156 | - 复制 $pc 到 $sepc 157 | - 设置 $sstatus 为 S-mode 158 | - 设置 $scause 为 trap 的原因 (ecall, 8) 159 | - 跳转到 $stvec ($pc = $stvec) 160 | 161 | ------ 162 | 163 | 在 xv6 中 164 | 165 | - Trampoline: $stvec = 0x3ffffff000 (只读) 166 | - Trapframe (0x3fffffe000): 保存进程寄存器现场的内存 167 | 168 | ### 2、Trampoline (跳板) 169 | 170 | trampoline.S (汇编代码) 171 | 172 | - 对 ecall 瞬间的状态做快照 173 | - **填充 `struct trapframe` (proc.h)** 174 | - 利用 $sscratch (S-mode scratch) 保存所有寄存器 175 | - 切换到内核栈 (相当于切换到进程对应的 “内核线程”, [L2](http://jyywiki.cn/OS/2022/labs/L2)) 176 | - 切换到内核地址空间 177 | - 修改 $satp (S-mode address translation and protection) 178 | - sfence.vma 179 | - 跳转到 `tf->kernel_trap` 180 | - 痛苦时间解除,进入 C 代码 181 | 182 | ### 3、系统调用处理 183 | 184 | `struct proc *p = myproc()` 185 | 186 | - 我们可以在 gdb 中查看 “进程” 在操作系统内的数据结构表示 187 | - `p/x *p` 188 | - 可以看到 trapframe 的地址 (和地址空间中映射的完全一样) 189 | - `p/x *p->trapframe` (a7 = 0x7) 190 | - 检查 `scause == 8` (syscall) 191 | - $epc += 4 (更正返回地址) 192 | - 打开中断 193 | - 执行系统调用 194 | - `usertrapret()` 返回 195 | - ecall 的逆操作 196 | 197 | ## 总结 198 | 199 | 本次课回答的问题 200 | 201 | - **Q**: 如何理解 “操作系统就是 C 程序”? 202 | 203 | ------ 204 | 205 | Take-away messages 206 | 207 | - Talk is cheap. Show me the code. 208 | - [RTFM](http://jyywiki.cn/pages/OS/manuals/xv6-riscv-rev2.pdf), [RTFSC](https://github.com/mit-pdos/xv6-riscv) 209 | - 用好现代工具 210 | - gdb tui + python, vscode, ... -------------------------------------------------------------------------------- /NJU-OS/19-Xv6上下文切换.md: -------------------------------------------------------------------------------- 1 | # Xv6 上下文切换 2 | 3 | ## Overview 4 | 5 | 复习 6 | 7 | - xv6 的系统调用实现:大家听得一头雾水,但留了个印象 8 | - ecall 指令:跳转到 trampoline 代码 9 | - 保存所有寄存器到 trapframe 10 | - 使内核代码能够继续执行 11 | 12 | ------ 13 | 14 | 本次课回答的问题 15 | 16 | - **Q**: 为什么要这么做? 17 | 18 | ------ 19 | 20 | 本次课主要内容 21 | 22 | - 上下文切换的原理与实现 23 | 24 | ## 一、处理器的虚拟化 25 | 26 | ### 1、今天借助代码回答一个根本性的问题 27 | 28 | 为什么死循环不能使计算机被彻底卡死? 29 | 30 | 原理上 31 | 32 | - 硬件会发生中断 (类似于 “强行插入” 的 ecall) 33 | - 切换到操作系统代码执行 34 | - 操作系统代码可以切换到另一个进程执行 35 | 36 | ------ 37 | 38 | 实际上 39 | 40 | - (在代码层次)到底是如何发生的? 41 | - 上一次课调试了代码,有了第一印象 42 | - 今天再补充一些细节 43 | 44 | ### 2、热身:协程库 45 | 46 | ```python 47 | def positive_integers(): 48 | i = 0 49 | while i := i + 1: 50 | yield i 51 | ``` 52 | 53 | `positive_integers()` 并不是 “调用” 它执行 54 | 55 | - 而是返回一个 generator 56 | - generator 可以调用,到 yield 后 “封存” 状态 57 | - 我们用这个特性实现了 [model-checker.py](http://jyywiki.cn/pages/OS/2022/demos/model-checker.py) 58 | 59 | ------ 60 | 61 | 我们同样也可以在 C 里这么做 62 | 63 | - `call yield` 切换到另一个执行流 64 | - 所有执行流共享内存 65 | - 拥有独立的寄存器和堆栈 66 | 67 | ### 3、复习:程序的状态 68 | 69 | 寄存器 70 | 71 | - 32 个通用寄存器 + $pc 72 | - `$x0 ($zero), $x1 ($ra), ..., $x31` 73 | 74 | ------ 75 | 76 | 内存 77 | 78 | - $satp “配置” 出的地址空间 79 | - QEMU: info mem 查看 80 | - 再次调试 initcode 81 | 82 | ------ 83 | 84 | 持有的操作系统对象 (不可见) 85 | 86 | - 程序只能看见 “文件描述符” (系统调用返回值, a0, syscall.c) 87 | - 回顾 [minimal.S](http://jyywiki.cn/pages/OS/2022/demos/minimal.S) 88 | 89 | ### 4、虚拟化:状态机的管理 90 | 91 | 寄存器组 ($x0...$x31, $pc) 只有一份,物理内存也只有一份 92 | 93 | - 寄存器的虚拟化:我们可以把寄存器保存到内存 94 | - 内存的虚拟化:$satp 的数据结构 95 | 96 | ------ 97 | 98 | 操作系统代码最重要的 invariant (假设单处理器) 99 | 100 | - **操作系统代码开始真正 “处理” 系统调用/中断时,所有进程的状态都被 “封存” 在操作系统中** 101 | - 可以通过 `struct proc` 里的指针访问 (`struct trapframe`) 102 | - 中断/异常处理的一小段代码需要保证这一点 103 | - 中断返回时,把进程的状态机 “恢复” 到 CPU 104 | 105 | ### 5、状态的封存:Trivial 的操作系统实现 106 | 107 | 用最直观的 “封存” 方式 108 | 109 | - **直接都保存到内存** 110 | - 假设操作系统代码直接 “看到” 所有物理内存 (L1) 111 | 112 | ```c 113 | struct page { int prot; void *va, *pa; } 114 | struct proc { 115 | uint64_t x1, x2, ... x31; 116 | struct page pages[MAXPAGES]; 117 | }; 118 | ``` 119 | 120 | - 保存:把 x1, ..., x31 保存到当前的 proc 即可 121 | - 就满足了 “状态机封存” 的 invariant 122 | - 恢复:把 pages 送到 $satp 对应的数据结构里 123 | - 通常我们是把这个数据结构准备好,只要一个赋值就行 124 | 125 | ### 6、状态的封存:体系结构相关的处理 126 | 127 | x86-64 128 | 129 | - 中断/异常会伴随堆栈切换 130 | - 通过 TSS 指定一个 “内核栈” 131 | - 中断前的寄存器保存在堆栈上 (典型的 CISC 行为) 132 | - [感受一下有多复杂](https://www.felixcloutier.com/x86/intn:into:int3:int1) 133 | - 这块空间可以顺便用来保存寄存器 134 | - 参考 AbstractMachine (trap64.S; x86-qemu.h) 135 | 136 | ------ 137 | 138 | xv6 (不限于 RISC-V) 139 | 140 | - 把进程的 trap frame 分配到固定地址 (通过$stap) 141 | - trap frame 保存在 $sscratch 142 | - 保存完毕后切换到内核线程执行 (包括堆栈切换) 143 | 144 | ### 7、再次调试系统调用 145 | 146 | ecall 指令的行为 147 | 148 | - 关闭中断 149 | - 复制 `$pc 到 $sepc` 150 | - 设置 `$sstatus 为 S-mode,$scause 为 trap 的原因 (ecall, 8)` 151 | - 跳转到 $stvec (S-mode trap vector) 152 | 153 | ecall 时额外的系统状态 154 | 155 | - $satp 控制了 “虚假” 的地址空间 156 | - 进程访问内存时仿佛戴了 VR 157 | - $sscratch 保存了进程的 trap frame 地址 158 | - 均由操作系统设置 159 | 160 | ### 8、Trampoline 代码完成的工作 161 | 162 | 把寄存器保存到 trap frame 163 | 164 | - 全靠 (struct trapframe *)$sscratch 寄存器 165 | 166 | ------ 167 | 168 | 切换到内核线程 169 | 170 | - 堆栈切换: $sp ← `tf->kernel_sp` 171 | - 设置当前处理: $tp ← `tf->kernel_hartid` 172 | - 设置页表: $satp ←tf->kernel_trap 173 | - xv6: 与物理内存一一映射 174 | - 通过 info mem 查看内核线程的地址空间映射 175 | - 低位的内存是 PLIC (0xc000000) 和 UART (0x10000000) 176 | - 物理内存一一映射 (A = Access, D = Dirty, xv6 中不使用) 177 | - 跳转到处理程序 `tf->kernel_trap` 执行 178 | 179 | ### 9、调用 usertrap() 后的系统状态 180 | 181 | 所有进程都被 “封存” 182 | 183 | - 通过 `struct proc` 就可以找到寄存器、内存、操作系统对象、…… 184 | - 进程对应的 “内核线程” 开始执行 185 | - L2 - Kernel Multithreading 186 | - 从另一个角度,“进程” 就是拥有了地址空间的线程 187 | 188 | ------ 189 | 190 | 操作系统代码可以为所欲为 191 | 192 | - 修改任何一个状态机 193 | - 例如,执行系统调用 194 | - 执行系统调用时可能发生 I/O 中断 195 | - 将任何另一个状态机调度到处理器上 (userret) 196 | 197 | ### 10、小结:状态机的封存 198 | 199 | 在执行完 “寄存器现场保存” 之后 200 | 201 | - 操作系统处于 “invariant 成立” 的状态 202 | - 每个进程的状态机都被 “封存” 203 | - 能被操作系统内核代码访问 204 | - xv6: `struct proc` 205 | - 操作系统可以把任何一个状态机 “加载” 回 CPU 206 | - 恢复寄存器和 `$satp,然后 sret (保持 invariant, 包括 $scratch)` 207 | 208 | ------ 209 | 210 | 因为被封存,我们的处理器可以选择把任何一个状态机恢复 211 | 212 | - 机制:允许在中断/异常返回时把任何进程加载回 CPU 213 | - 策略:处理器调度 (下次课) 214 | 215 | ## 总结 216 | 217 | 本次课回答的问题 218 | 219 | - **Q**: 操作系统是如何完成进程之间的切换的? 220 | 221 | ------ 222 | 223 | Take-away messages 224 | 225 | - “操作系统是中断处理程序” 226 | - ecall 后执行 trampoline 代码 (操作系统控制) 227 | - 进入系统调用后,就完全是状态机 (取 mem[$pc] 指令执行) 228 | - “操作系统是状态机的管理者” 229 | - 操作系统持有所有物理页面 (通过 $stap 任意映射) 230 | - 用数据结构 (struct proc) 表示进程对象 231 | - 进程的页面 (包括 trapframe) 实现**状态的封存** 232 | - ecall → invariant (状态机被封存) → schedule → sret -------------------------------------------------------------------------------- /NJU-OS/22-极限速通操作系统实验.md: -------------------------------------------------------------------------------- 1 | # 极限速通操作系统实验 -------------------------------------------------------------------------------- /NJU-OS/29-Xv6文件系统实现.md: -------------------------------------------------------------------------------- 1 | # Xv6 文件系统实现 2 | 3 | ## Overview 4 | 5 | 复习 6 | 7 | - 文件系统:bread/bwrite 上的数据结构 8 | - balloc/bfree 9 | - 文件:FAT (链表)/UNIX 文件系统 (索引) 10 | - 目录文件 11 | - 持久数据的可靠性 12 | - RAID 和日志 13 | 14 | ------ 15 | 16 | 本次课回答的问题 17 | 18 | - **Q**: 到底能不能看一看文件系统实现的代码? 19 | 20 | ------ 21 | 22 | 本次课主要内容 23 | 24 | - Xv6 文件系统实现 25 | 26 | ## 一、文件系统:复习 27 | 28 | ### 1、“磁盘上的数据结构” 29 | 30 | 支持的操作 31 | 32 | - 目录 (索引) 33 | - “图书馆” - mkdir, rmdir, link, unlink, open, ... 34 | - 文件 (虚拟磁盘) 35 | - “图书” - read, write, mmap, ... 36 | - 文件描述符 (偏移量) 37 | - “书签” - lseek 38 | 39 | ------ 40 | 41 | 实现的方法 42 | 43 | - block I/O → block 管理 → 文件 → 目录文件 44 | - FAT: 文件信息 “分别” 保存在链表和目录项中 45 | - UNIX 文件系统:集中存储文件对象 46 | 47 | ## 二、RTFSC 48 | 49 | (讨论:假设你第一次阅读这部分代码,应该怎么做?) 50 | 51 | ### 1、mkfs: 创建文件系统 (格式化) 52 | 53 | ``` 54 | // Disk layout: 55 | // [ boot block | sb block | log | inode blocks 56 | // | free bit map | data blocks ] 57 | ``` 58 | 59 | 可以知道每一部分的含义 60 | 61 | - boot block - 启动加载器 62 | - sb block (super block) - 文件系统元数据 63 | - log - 日志 (崩溃恢复) 64 | - inode blocks 65 | - free bitmap - balloc/bfree 66 | - data blocks 67 | - RTFSC! 68 | 69 | --- 70 | 71 | “只管分配、不管回收” (类似于极限速通) 72 | 73 | - rsect/wsect (bread/bwrite) 74 | - balloc/bzero 75 | - ialloc 76 | - iappend 77 | - rinode/winode 78 | 79 | ------ 80 | 81 | RTFSC 的正确方式 82 | 83 | - “读代码不如读执行”: [trace.py](http://jyywiki.cn/pages/OS/2022/demos/trace.py) 84 | - `gdb -ex 'source mkfs/trace.py' mkfs/mkfs` 85 | 86 | ```python 87 | TRACED = 'bwrite balloc ialloc iappend rinode winode rsect wsect'.split() 88 | IGNORE = 'ip xp buf'.split() 89 | 90 | class trace(gdb.Breakpoint): 91 | def stop(self): 92 | f, bt = gdb.selected_frame(), [] 93 | while f and f.is_valid(): 94 | if (name := f.name()) in TRACED: 95 | lvars = [f'{sym.name}={sym.value(f)}' 96 | for sym in f.block() 97 | if sym.is_argument and sym.name not in IGNORE] 98 | bt.append(f'\033[32m{name}\033[0m({", ".join(lvars)})') 99 | f = f.older() 100 | print(' ' * (len(bt) - 1) + bt[0]) 101 | return False # won't stop at this breakpoint 102 | 103 | gdb.execute('set prompt off') 104 | gdb.execute('set pagination off') 105 | for fn in TRACED: 106 | trace(fn) 107 | gdb.execute('run fs.img README user/_ls') 108 | gdb.execute('quit') 109 | ``` 110 | 111 | ## 三、调试代码 112 | 113 | ### 1、调试系统调用 114 | 115 | 有很多选择 116 | 117 | - open - 路径解析、创建文件描述符 118 | - read/write - 文件描述符和数据操作 119 | - link - 文件元数据操作 120 | - ... 121 | 122 | ------ 123 | 124 | 应该选哪一个? 125 | 126 | - 取决于你对代码的熟悉程度和信心 127 | - 有信心可以选复杂一些的 128 | - 没有信心可以选简单一些的 129 | - 但如果有了刚才的铺垫,应该都有信心! 130 | 131 | ## 四、崩溃恢复 132 | 133 | ### 1、能否让我们调试崩溃恢复的代码? 134 | 135 | > “Get out of your comfort zone.” 136 | 137 | 懒惰是我们的本性 138 | 139 | - “调试这部分代码有点小麻烦” 140 | - “反正考试也不考,算了吧” 141 | - 一定要相信是可以优雅地做到的 142 | 143 | ------ 144 | 145 | 课程作业的意义 146 | 147 | - 逼迫大家克服懒惰 148 | - 好作业的设计必须是 “不吃苦做不出来” 149 | - 获得激励和 “self motivation” 150 | 151 | ### 2、故障注入 (Fault Injection) 152 | 153 | Crash = “断电” 154 | 155 | ```c 156 | void crash() { 157 | static int count = 100; 158 | if (--count < 0) { 159 | printf("crash\n"); 160 | *((int *)0x100000) = 0x5555; 161 | } 162 | } 163 | ``` 164 | 165 | - (“[sifive finisher](https://patchwork.kernel.org/project/linux-riscv/patch/20191107212408.11857-3-hch@lst.de/)”) 166 | 167 | ------ 168 | 169 | xv6 是相对比较 deterministic 的 170 | 171 | - 枚举可能的 count 172 | - 我们就得到了一个 “测试框架”! 173 | - 我们用类似的 trick 模拟应用程序写入数据后的系统崩溃 174 | 175 | ## 总结 176 | 177 | 本次课回答的问题 178 | 179 | - Q 180 | 181 | : 到底怎么实现一个真正的文件系统? 182 | 183 | - Xv6 文件系统:mkfs; 系统调用实现和日志 184 | 185 | ------ 186 | 187 | Takeaway messages 188 | 189 | - 调试代码的建议 190 | - 先了解一下你要调试的对象 191 | - 然后从 trace 开始 192 | - 不要惧怕调试任何一部分 -------------------------------------------------------------------------------- /NJU-OS/31-Android系统.md: -------------------------------------------------------------------------------- 1 | # Android 系统 2 | 3 | ## Overview 4 | 5 | - 应用视角的操作系统 6 | - 对象 + API 7 | - 硬件视角的操作系统 8 | - 一个控制了整个计算机硬件的程序 9 | 10 | ## Android 11 | 12 | [Android 官方主页](https://developer.android.google.cn/) 13 | 14 | - Linux + Framework + JVM 15 | - 在 Linux/Java 上做了个二次开发? 16 | - 并不完全是:Android 定义了应用模型 17 | - 支持 Java 是一个非常高瞻远瞩的决定 18 | - Qualcomm MSM7201 19 | - ARMv6 指令集 20 | - 528MHz x 1CPU, 顺序八级流水线 21 | - TSMC 90nm 22 | - “跑个地图都会卡” 23 | - 但摩尔定律生效了! 24 | 25 | ## Android Apps 26 | 27 | 一个运行在 Java 虚拟机 ([Android Runtime](http://aospxref.com/android-12.0.0_r3/xref/art/)) 上的应用程序 28 | 29 | - Platform (Framework) 30 | - NDK (Native Development Kit) 31 | - Java Native Interface (C/C++ 代码) 32 | 33 | 官方文档 (RTFM) 34 | 35 | - [Kotlin](https://developer.android.google.cn/kotlin) 36 | - [Platform](https://developer.android.google.cn/reference/packages) 37 | - [android.view.View](https://developer.android.google.cn/reference/android/view/View): “the basic building block for user interface components” 38 | - [android.webkit.WebView](https://developer.android.google.cn/reference/android/webkit/WebView) - 嵌入应用的网页 39 | - [android.hardware.camera2](https://developer.android.google.cn/reference/android/hardware/camera2/package-summary) - 相机 40 | - [android.database.database](https://developer.android.google.cn/reference/android/database/sqlite/package-summary) - 数据库 41 | 42 | ### “四大组件” 43 | 44 | Activity 45 | 46 | - 应用程序的 UI 界面 (Event Driven) 47 | - 存在一个 Activity Stack (应用拉起) 48 | 49 | Service 50 | 51 | - 无界面的后台服务 52 | 53 | Broadcast 54 | 55 | - 接受系统消息,做出反应 56 | - 例如 “插上电源”、“Wifi 断开” 57 | 58 | ContentProvider 59 | 60 | - 可以在应用间共享的数据存储 (insert, update, query, ...) 61 | 62 | 应用就是如下的时间循环: 63 | 64 | ![android-activity](./doc/android-activity.png) 65 | 66 | ## Android 系统 67 | 68 | ### Platform API 之下:一个 “微内核” 69 | 70 | 通过 “Binder IPC” 71 | 72 | - Remote Procedure Call (RPC) 73 | - `remote.transact()` 74 | - 在性能优化和易用之间的权衡 75 | - 注册机制 76 | - 相比之下,管道/套接字就太 “底层” 了,需要手工管理的东西太多 77 | - 基于共享内存实现 78 | - Linux Kernel binder driver 79 | - 服务端线程池 80 | 81 | ![android-stack](./doc/android-stack.png) 82 | 83 | ### 然后……海量的代码 84 | 85 | 例子:如何杀死一个 Android 进程? 86 | 87 | - RTFSC:[ActivityManagerService.java](http://aospxref.com/android-12.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java#3688) 88 | - Android 每个 App 都有独立的 uid 89 | - 遍历进程表,找到属于 uid 的进程 90 | - Process.KillProcessGroup 91 | - [间隔 5ms,连续杀死 40 次](http://aospxref.com/android-12.0.0_r3/xref/system/core/libprocessgroup/processgroup.cpp#411),防止数据竞争 92 | - Operating System Transactions 的必要性 93 | 94 | 那么,我们是不是就可以利用数据竞争进程保活了呢? 95 | 96 | - 成为孤儿进程从而不会立即收到 SIGKILL 信号 97 | - 在被杀死后立即唤醒另一个进程:[flock-demo.c](http://jyywiki.cn/pages/OS/2022/demos/flock-demo.c) 98 | - [A lightweight framework for fine-grained lifecycle control of Android applications](https://dl.acm.org/doi/10.1145/3302424.3303956) (EuroSys'19); “diehard apps” 99 | 100 | ### 一个真正的 “操作系统” 101 | 102 | adb (Android Debug Bridge) 103 | 104 | - adb push/pull/install 105 | - adb shell 106 | - screencap /sdcard/screen.png 107 | - sendevent 108 | - adb forward 109 | - adb logcat/jdwp 110 | 111 | 一系列衍生的工具 112 | 113 | - 开发者选项 114 | - scrcpy 115 | - Monkey/UI Automator 116 | 117 | ## 总结 118 | 119 | 本次课回答的问题 120 | 121 | - **Q**: 一个真正 “实用” 的操作系统 (生态) 是如何构成的? 122 | 123 | Takeaway messages 124 | 125 | - 服务、服务、服务 126 | - Android Platform API 127 | - Google Mobile Service (GMS) 128 | - 海量的工程细节 129 | - 复杂系统无处不在 130 | - 能驾驭整个系统复杂性的架构师 131 | - 大量高水准的工程师,他们都在哪里? -------------------------------------------------------------------------------- /NJU-OS/doc/2S-motherboard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/2S-motherboard.jpg -------------------------------------------------------------------------------- /NJU-OS/doc/6502-pinout.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/6502-pinout.jpg -------------------------------------------------------------------------------- /NJU-OS/doc/80486-arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/80486-arch.png -------------------------------------------------------------------------------- /NJU-OS/doc/CAP-theorem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/CAP-theorem.png -------------------------------------------------------------------------------- /NJU-OS/doc/EPYC-NUMA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/EPYC-NUMA.png -------------------------------------------------------------------------------- /NJU-OS/doc/ERA-1101.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/ERA-1101.png -------------------------------------------------------------------------------- /NJU-OS/doc/EUV.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/EUV.png -------------------------------------------------------------------------------- /NJU-OS/doc/FAT-dent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/FAT-dent.png -------------------------------------------------------------------------------- /NJU-OS/doc/FAT-number.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/FAT-number.png -------------------------------------------------------------------------------- /NJU-OS/doc/GPU-arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/GPU-arch.png -------------------------------------------------------------------------------- /NJU-OS/doc/IDA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/IDA.png -------------------------------------------------------------------------------- /NJU-OS/doc/Kirin-9000.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/Kirin-9000.jpg -------------------------------------------------------------------------------- /NJU-OS/doc/MLFQ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/MLFQ.png -------------------------------------------------------------------------------- /NJU-OS/doc/Mandelbrot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/Mandelbrot.png -------------------------------------------------------------------------------- /NJU-OS/doc/NES-motherboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/NES-motherboard.png -------------------------------------------------------------------------------- /NJU-OS/doc/Snipaste_2022-06-26_23-38-57.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/Snipaste_2022-06-26_23-38-57.jpeg -------------------------------------------------------------------------------- /NJU-OS/doc/Snipaste_2022-06-27_22-34-00.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/Snipaste_2022-06-27_22-34-00.jpeg -------------------------------------------------------------------------------- /NJU-OS/doc/UEFI-booting-seq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/UEFI-booting-seq.png -------------------------------------------------------------------------------- /NJU-OS/doc/ajjl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/ajjl.png -------------------------------------------------------------------------------- /NJU-OS/doc/altair-8800.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/altair-8800.jpg -------------------------------------------------------------------------------- /NJU-OS/doc/android-activity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/android-activity.png -------------------------------------------------------------------------------- /NJU-OS/doc/android-stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/android-stack.png -------------------------------------------------------------------------------- /NJU-OS/doc/apple-garage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/apple-garage.png -------------------------------------------------------------------------------- /NJU-OS/doc/apple2-inside.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/apple2-inside.jpg -------------------------------------------------------------------------------- /NJU-OS/doc/assassins-creed.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/assassins-creed.jpg -------------------------------------------------------------------------------- /NJU-OS/doc/av-bug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/av-bug.png -------------------------------------------------------------------------------- /NJU-OS/doc/bios-firmware.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/bios-firmware.png -------------------------------------------------------------------------------- /NJU-OS/doc/boom-pipeline-detailed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/boom-pipeline-detailed.png -------------------------------------------------------------------------------- /NJU-OS/doc/calcomp-565.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/calcomp-565.jpg -------------------------------------------------------------------------------- /NJU-OS/doc/canary_with_miner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/canary_with_miner.png -------------------------------------------------------------------------------- /NJU-OS/doc/canonical-device.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/canonical-device.png -------------------------------------------------------------------------------- /NJU-OS/doc/cat-crash-consistency.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/cat-crash-consistency.jpg -------------------------------------------------------------------------------- /NJU-OS/doc/cdplay.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/cdplay.gif -------------------------------------------------------------------------------- /NJU-OS/doc/cgroups.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/cgroups.jpg -------------------------------------------------------------------------------- /NJU-OS/doc/cheating.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/cheating.png -------------------------------------------------------------------------------- /NJU-OS/doc/cih-virus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/cih-virus.png -------------------------------------------------------------------------------- /NJU-OS/doc/contra.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/contra.jpg -------------------------------------------------------------------------------- /NJU-OS/doc/core-memory.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/core-memory.jpg -------------------------------------------------------------------------------- /NJU-OS/doc/deadlock-car.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/deadlock-car.png -------------------------------------------------------------------------------- /NJU-OS/doc/delay-memory-fig2-s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/delay-memory-fig2-s.png -------------------------------------------------------------------------------- /NJU-OS/doc/dining-philosophers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/dining-philosophers.png -------------------------------------------------------------------------------- /NJU-OS/doc/disk-mechanism.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/disk-mechanism.jpg -------------------------------------------------------------------------------- /NJU-OS/doc/ext2-dirent.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/ext2-dirent.jpg -------------------------------------------------------------------------------- /NJU-OS/doc/ext2-inode.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/ext2-inode.gif -------------------------------------------------------------------------------- /NJU-OS/doc/fake-hdd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/fake-hdd.jpg -------------------------------------------------------------------------------- /NJU-OS/doc/fat32_layout.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/fat32_layout.gif -------------------------------------------------------------------------------- /NJU-OS/doc/floppy-drives.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/floppy-drives.jpg -------------------------------------------------------------------------------- /NJU-OS/doc/fortran-card.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/fortran-card.jpg -------------------------------------------------------------------------------- /NJU-OS/doc/fortran-card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/fortran-card.png -------------------------------------------------------------------------------- /NJU-OS/doc/fritz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/fritz.jpg -------------------------------------------------------------------------------- /NJU-OS/doc/fs-ext2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/fs-ext2.png -------------------------------------------------------------------------------- /NJU-OS/doc/fs-journaling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/fs-journaling.png -------------------------------------------------------------------------------- /NJU-OS/doc/fsck-recovery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/fsck-recovery.png -------------------------------------------------------------------------------- /NJU-OS/doc/ghost-sched.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/ghost-sched.png -------------------------------------------------------------------------------- /NJU-OS/doc/hadoop-ecosystem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/hadoop-ecosystem.png -------------------------------------------------------------------------------- /NJU-OS/doc/hard-disk-mag.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/hard-disk-mag.jpg -------------------------------------------------------------------------------- /NJU-OS/doc/hdd-capacity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/hdd-capacity.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220702225528562.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220702225528562.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220702230117046.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220702230117046.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220709203704901.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220709203704901.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220710150030702.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220710150030702.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220713222913392.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220713222913392.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220720205930587.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220720205930587.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220724122254113.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220724122254113.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220724144537165.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220724144537165.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220724150505571.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220724150505571.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220724151243599.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220724151243599.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220724164401900.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220724164401900.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220724223652446.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220724223652446.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220724223842509.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220724223842509.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220724235040023.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220724235040023.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220724235129813.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220724235129813.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220724235916216.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220724235916216.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220725000355096.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220725000355096.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220725213231744.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220725213231744.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220725215330868.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220725215330868.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220725215522290.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220725215522290.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220725225115818.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220725225115818.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220725225334403.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220725225334403.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220725225427825.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220725225427825.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220807154510653.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220807154510653.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220807161153704.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220807161153704.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220812215212517.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220812215212517.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220812215528270.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220812215528270.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220812215732141.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220812215732141.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220812220208830.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220812220208830.png -------------------------------------------------------------------------------- /NJU-OS/doc/image-20220812232253998.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/image-20220812232253998.png -------------------------------------------------------------------------------- /NJU-OS/doc/intel-cpu-reset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/intel-cpu-reset.png -------------------------------------------------------------------------------- /NJU-OS/doc/ken-quote.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/ken-quote.png -------------------------------------------------------------------------------- /NJU-OS/doc/kernel-rmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/kernel-rmap.png -------------------------------------------------------------------------------- /NJU-OS/doc/knight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/knight.png -------------------------------------------------------------------------------- /NJU-OS/doc/lfg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/lfg.png -------------------------------------------------------------------------------- /NJU-OS/doc/linux-bio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/linux-bio.png -------------------------------------------------------------------------------- /NJU-OS/doc/mag-draw-board.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/mag-draw-board.jpg -------------------------------------------------------------------------------- /NJU-OS/doc/mag-drum.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/mag-drum.jpg -------------------------------------------------------------------------------- /NJU-OS/doc/mai-fast13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/mai-fast13.jpg -------------------------------------------------------------------------------- /NJU-OS/doc/mandelbrot-my.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/mandelbrot-my.png -------------------------------------------------------------------------------- /NJU-OS/doc/marsbot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/marsbot.png -------------------------------------------------------------------------------- /NJU-OS/doc/mechanical-tm.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/mechanical-tm.jpg -------------------------------------------------------------------------------- /NJU-OS/doc/mem-weak@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/mem-weak@2x.png -------------------------------------------------------------------------------- /NJU-OS/doc/microkernel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/microkernel.jpg -------------------------------------------------------------------------------- /NJU-OS/doc/microkernel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/microkernel.png -------------------------------------------------------------------------------- /NJU-OS/doc/minix3-desktop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/minix3-desktop.png -------------------------------------------------------------------------------- /NJU-OS/doc/minixarch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/minixarch.png -------------------------------------------------------------------------------- /NJU-OS/doc/nand-flash.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/nand-flash.jpg -------------------------------------------------------------------------------- /NJU-OS/doc/nes-ppu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/nes-ppu.png -------------------------------------------------------------------------------- /NJU-OS/doc/nes-scroll.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/nes-scroll.gif -------------------------------------------------------------------------------- /NJU-OS/doc/nes-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/nes-sprite.png -------------------------------------------------------------------------------- /NJU-OS/doc/nju-lib.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/nju-lib.jpg -------------------------------------------------------------------------------- /NJU-OS/doc/nuke-launch.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/nuke-launch.gif -------------------------------------------------------------------------------- /NJU-OS/doc/os-classify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/os-classify.png -------------------------------------------------------------------------------- /NJU-OS/doc/ov-bug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/ov-bug.png -------------------------------------------------------------------------------- /NJU-OS/doc/power-curve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/power-curve.png -------------------------------------------------------------------------------- /NJU-OS/doc/process-groups-sessions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/process-groups-sessions.png -------------------------------------------------------------------------------- /NJU-OS/doc/promises.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/promises.png -------------------------------------------------------------------------------- /NJU-OS/doc/ps-effect.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/ps-effect.jpg -------------------------------------------------------------------------------- /NJU-OS/doc/qb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/qb.png -------------------------------------------------------------------------------- /NJU-OS/doc/qin-rx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/qin-rx.png -------------------------------------------------------------------------------- /NJU-OS/doc/race.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/race.png -------------------------------------------------------------------------------- /NJU-OS/doc/raid5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/raid5.png -------------------------------------------------------------------------------- /NJU-OS/doc/sc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/sc.png -------------------------------------------------------------------------------- /NJU-OS/doc/sched-rr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/sched-rr.png -------------------------------------------------------------------------------- /NJU-OS/doc/sketchpad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/sketchpad.png -------------------------------------------------------------------------------- /NJU-OS/doc/social-media.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/social-media.png -------------------------------------------------------------------------------- /NJU-OS/doc/sos-on-beach.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/sos-on-beach.jpg -------------------------------------------------------------------------------- /NJU-OS/doc/speed-up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/speed-up.png -------------------------------------------------------------------------------- /NJU-OS/doc/spinlock-scalability.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/spinlock-scalability.png -------------------------------------------------------------------------------- /NJU-OS/doc/ssd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/ssd.png -------------------------------------------------------------------------------- /NJU-OS/doc/tcmalloc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/tcmalloc.png -------------------------------------------------------------------------------- /NJU-OS/doc/texture-mapping.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/texture-mapping.jpg -------------------------------------------------------------------------------- /NJU-OS/doc/tmux-cheatsheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/tmux-cheatsheet.png -------------------------------------------------------------------------------- /NJU-OS/doc/tocttou.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/tocttou.png -------------------------------------------------------------------------------- /NJU-OS/doc/tree-rotate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/tree-rotate.png -------------------------------------------------------------------------------- /NJU-OS/doc/tty-session.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/tty-session.png -------------------------------------------------------------------------------- /NJU-OS/doc/unix-programs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/unix-programs.png -------------------------------------------------------------------------------- /NJU-OS/doc/upan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/upan.jpg -------------------------------------------------------------------------------- /NJU-OS/doc/v-rally.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/v-rally.png -------------------------------------------------------------------------------- /NJU-OS/doc/vaccum-tube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/vaccum-tube.png -------------------------------------------------------------------------------- /NJU-OS/doc/waigua.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/waigua.png -------------------------------------------------------------------------------- /NJU-OS/doc/x86-tso.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/x86-tso.png -------------------------------------------------------------------------------- /NJU-OS/doc/xv6-process-memory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/xv6-process-memory.png -------------------------------------------------------------------------------- /NJU-OS/doc/xv6-syscalls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/NJU-OS/doc/xv6-syscalls.png -------------------------------------------------------------------------------- /abstract-machine/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !*/ 3 | !*.h 4 | !*.c 5 | !*.cc 6 | !*.S 7 | !*.ld 8 | !*.sh 9 | !*.py 10 | !*.mk 11 | !Makefile 12 | !README 13 | !LICENSE 14 | .* 15 | _* 16 | *~ 17 | build/ 18 | !.gitignore 19 | .vscode -------------------------------------------------------------------------------- /abstract-machine/LICENSE: -------------------------------------------------------------------------------- 1 | The AbstractMachine software is: 2 | 3 | Copyright (c) 2018-2021 Yanyan Jiang and Zihao Yu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /abstract-machine/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for AbstractMachine Kernels and Libraries 2 | 3 | ### *Get a more readable version of this Makefile* by `make html` (requires python-markdown) 4 | html: 5 | cat Makefile | sed 's/^\([^#]\)/ \1/g' | markdown_py > Makefile.html 6 | .PHONY: html 7 | 8 | ## 1. Basic Setup and Checks 9 | 10 | ### Default to create a bare-metal kernel image 11 | ifeq ($(MAKECMDGOALS),) 12 | MAKECMDGOALS = image 13 | .DEFAULT_GOAL = image 14 | endif 15 | 16 | ### Override checks when `make clean/clean-all/html` 17 | ifeq ($(findstring $(MAKECMDGOALS),clean|clean-all|html),) 18 | 19 | ### Print build info message 20 | $(info # Building $(NAME)-$(MAKECMDGOALS) [$(ARCH)]) 21 | 22 | ### Check: environment variable `$AM_HOME` looks sane 23 | ifeq ($(wildcard $(AM_HOME)/am/include/am.h),) 24 | $(error $$AM_HOME must be an AbstractMachine repo) 25 | endif 26 | 27 | ### Check: environment variable `$ARCH` must be in the supported list 28 | ARCHS = $(basename $(notdir $(shell ls $(AM_HOME)/scripts/*.mk))) 29 | ifeq ($(filter $(ARCHS), $(ARCH)), ) 30 | $(error Expected $$ARCH in {$(ARCHS)}, Got "$(ARCH)") 31 | endif 32 | 33 | ### Extract instruction set architecture (`ISA`) and platform from `$ARCH`. Example: `ARCH=x86_64-qemu -> ISA=x86_64; PLATFORM=qemu` 34 | ARCH_SPLIT = $(subst -, ,$(ARCH)) 35 | ISA = $(word 1,$(ARCH_SPLIT)) 36 | PLATFORM = $(word 2,$(ARCH_SPLIT)) 37 | 38 | ### Check if there is something to build 39 | ifeq ($(flavor SRCS), undefined) 40 | $(error Nothing to build) 41 | endif 42 | 43 | ### Checks end here 44 | endif 45 | 46 | ## 2. General Compilation Targets 47 | 48 | ### Create the destination directory (`build/$ARCH`) 49 | WORK_DIR = $(shell pwd) 50 | DST_DIR = $(WORK_DIR)/build/$(ARCH) 51 | $(shell mkdir -p $(DST_DIR)) 52 | 53 | ### Compilation targets (a binary image or archive) 54 | IMAGE_REL = build/$(NAME)-$(ARCH) 55 | IMAGE = $(abspath $(IMAGE_REL)) 56 | ARCHIVE = $(WORK_DIR)/build/$(NAME)-$(ARCH).a 57 | 58 | ### Collect the files to be linked: object files (`.o`) and libraries (`.a`) 59 | OBJS = $(addprefix $(DST_DIR)/, $(addsuffix .o, $(basename $(SRCS)))) 60 | LIBS := $(sort $(LIBS) am klib) # lazy evaluation ("=") causes infinite recursions 61 | LINKAGE = $(OBJS) \ 62 | $(addsuffix -$(ARCH).a, $(join \ 63 | $(addsuffix /build/, $(addprefix $(AM_HOME)/, $(LIBS))), \ 64 | $(LIBS) )) 65 | 66 | ## 3. General Compilation Flags 67 | 68 | ### (Cross) compilers, e.g., mips-linux-gnu-g++ 69 | AS = $(CROSS_COMPILE)gcc 70 | CC = $(CROSS_COMPILE)gcc 71 | CXX = $(CROSS_COMPILE)g++ 72 | LD = $(CROSS_COMPILE)ld 73 | OBJDUMP = $(CROSS_COMPILE)objdump 74 | OBJCOPY = $(CROSS_COMPILE)objcopy 75 | READELF = $(CROSS_COMPILE)readelf 76 | 77 | ### Compilation flags 78 | INC_PATH += $(WORK_DIR)/include $(addsuffix /include/, $(addprefix $(AM_HOME)/, $(LIBS))) 79 | INCFLAGS += $(addprefix -I, $(INC_PATH)) 80 | 81 | CFLAGS += -O2 -MMD -Wall -Werror $(INCFLAGS) \ 82 | -D__ISA__=\"$(ISA)\" -D__ISA_$(shell echo $(ISA) | tr a-z A-Z)__ \ 83 | -D__ARCH__=$(ARCH) -D__ARCH_$(shell echo $(ARCH) | tr a-z A-Z | tr - _) \ 84 | -D__PLATFORM__=$(PLATFORM) -D__PLATFORM_$(shell echo $(PLATFORM) | tr a-z A-Z | tr - _) \ 85 | -DARCH_H=\"arch/$(ARCH).h\" \ 86 | -fno-asynchronous-unwind-tables -fno-builtin -fno-stack-protector \ 87 | -Wno-main -U_FORTIFY_SOURCE 88 | CXXFLAGS += $(CFLAGS) -ffreestanding -fno-rtti -fno-exceptions 89 | ASFLAGS += -MMD $(INCFLAGS) 90 | 91 | ## 4. Arch-Specific Configurations 92 | 93 | ### Paste in arch-specific configurations (e.g., from `scripts/x86_64-qemu.mk`) 94 | -include $(AM_HOME)/scripts/$(ARCH).mk 95 | 96 | ### Fall back to native gcc/binutils if there is no cross compiler 97 | ifeq ($(wildcard $(shell which $(CC))),) 98 | $(info # $(CC) not found; fall back to default gcc and binutils) 99 | CROSS_COMPILE := 100 | endif 101 | 102 | ## 5. Compilation Rules 103 | 104 | ### Rule (compile): a single `.c` -> `.o` (gcc) 105 | $(DST_DIR)/%.o: %.c 106 | @mkdir -p $(dir $@) && echo + CC $< 107 | @$(CC) -std=gnu11 $(CFLAGS) -c -o $@ $(realpath $<) 108 | 109 | ### Rule (compile): a single `.cc` -> `.o` (g++) 110 | $(DST_DIR)/%.o: %.cc 111 | @mkdir -p $(dir $@) && echo + CXX $< 112 | @$(CXX) -std=c++17 $(CXXFLAGS) -c -o $@ $(realpath $<) 113 | 114 | ### Rule (compile): a single `.cpp` -> `.o` (g++) 115 | $(DST_DIR)/%.o: %.cpp 116 | @mkdir -p $(dir $@) && echo + CXX $< 117 | @$(CXX) -std=c++17 $(CXXFLAGS) -c -o $@ $(realpath $<) 118 | 119 | ### Rule (compile): a single `.S` -> `.o` (gcc, which preprocesses and calls as) 120 | $(DST_DIR)/%.o: %.S 121 | @mkdir -p $(dir $@) && echo + AS $< 122 | @$(AS) $(ASFLAGS) -c -o $@ $(realpath $<) 123 | 124 | ### Rule (recursive make): build a dependent library (am, klib, ...) 125 | $(LIBS): %: 126 | @$(MAKE) -s -C $(AM_HOME)/$* archive 127 | 128 | ### Rule (link): objects (`*.o`) and libraries (`*.a`) -> `IMAGE.elf`, the final ELF binary to be packed into image (ld) 129 | $(IMAGE).elf: $(OBJS) am $(LIBS) 130 | @echo + LD "->" $(IMAGE_REL).elf 131 | @$(LD) $(LDFLAGS) -o $(IMAGE).elf --start-group $(LINKAGE) --end-group 132 | 133 | ### Rule (archive): objects (`*.o`) -> `ARCHIVE.a` (ar) 134 | $(ARCHIVE): $(OBJS) 135 | @echo + AR "->" $(shell realpath $@ --relative-to .) 136 | @ar rcs $(ARCHIVE) $(OBJS) 137 | 138 | ### Rule (`#include` dependencies): paste in `.d` files generated by gcc on `-MMD` 139 | -include $(addprefix $(DST_DIR)/, $(addsuffix .d, $(basename $(SRCS)))) 140 | 141 | ## 6. Miscellaneous 142 | 143 | ### Build order control 144 | image: image-dep 145 | archive: $(ARCHIVE) 146 | image-dep: $(OBJS) am $(LIBS) 147 | @echo \# Creating image [$(ARCH)] 148 | .PHONY: image image-dep archive run $(LIBS) 149 | 150 | ### Clean a single project (remove `build/`) 151 | clean: 152 | rm -rf Makefile.html $(WORK_DIR)/build/ 153 | .PHONY: clean 154 | 155 | ### Clean all sub-projects within depth 2 (and ignore errors) 156 | CLEAN_ALL = $(dir $(shell find . -mindepth 2 -name Makefile)) 157 | clean-all: $(CLEAN_ALL) clean 158 | $(CLEAN_ALL): 159 | -@$(MAKE) -s -C $@ clean 160 | .PHONY: clean-all $(CLEAN_ALL) 161 | -------------------------------------------------------------------------------- /abstract-machine/README: -------------------------------------------------------------------------------- 1 | AbstractMachine is a minimal, modularized, and machine-independent 2 | abstraction layer of the computer hardware: 3 | 4 | * physical memory and direct execution (The "Turing Machine"); 5 | * basic model for input and output devices (I/O Extension); 6 | * interrupt/exception and processor context management (Context Extension); 7 | * virtual memory and protection (Virtual Memory Extension); 8 | * multiprocessing (Multiprocessing Extension). 9 | 10 | CONTACTS 11 | 12 | Bug reports and suggestions go to Yanyan Jiang (jyy@nju.edu.cn) and Zihao 13 | Yu (yuzihao@ict.ac.cn). 14 | -------------------------------------------------------------------------------- /abstract-machine/am/Makefile: -------------------------------------------------------------------------------- 1 | NAME := am 2 | SRCS = $(addprefix src/, $(AM_SRCS)) 3 | INC_PATH += $(AM_HOME)/am/src 4 | 5 | include $(AM_HOME)/Makefile 6 | -------------------------------------------------------------------------------- /abstract-machine/am/include/am.h: -------------------------------------------------------------------------------- 1 | #ifndef AM_H__ 2 | #define AM_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include ARCH_H // this macro is defined in $CFLAGS 8 | // examples: "arch/x86-qemu.h", "arch/native.h", ... 9 | 10 | // Memory protection flags 11 | #define MMAP_NONE 0x00000000 // no access 12 | #define MMAP_READ 0x00000001 // can read 13 | #define MMAP_WRITE 0x00000002 // can write 14 | 15 | // Memory area for [@start, @end) 16 | typedef struct { 17 | void *start, *end; 18 | } Area; 19 | 20 | // Arch-dependent processor context 21 | typedef struct Context Context; 22 | 23 | // An event of type @event, caused by @cause of pointer @ref 24 | typedef struct { 25 | enum { 26 | EVENT_NULL = 0, 27 | EVENT_YIELD, EVENT_SYSCALL, EVENT_PAGEFAULT, EVENT_ERROR, 28 | EVENT_IRQ_TIMER, EVENT_IRQ_IODEV, 29 | } event; 30 | uintptr_t cause, ref; 31 | const char *msg; 32 | } Event; 33 | 34 | // A protected address space with user memory @area 35 | // and arch-dependent @ptr 36 | typedef struct { 37 | int pgsize; 38 | Area area; 39 | void *ptr; 40 | } AddrSpace; 41 | 42 | #ifdef __cplusplus 43 | extern "C" { 44 | #endif 45 | 46 | // ----------------------- TRM: Turing Machine ----------------------- 47 | extern Area heap; 48 | void putch (char ch); 49 | void halt (int code) __attribute__((__noreturn__)); 50 | 51 | // -------------------- IOE: Input/Output Devices -------------------- 52 | bool ioe_init (void); 53 | void ioe_read (int reg, void *buf); 54 | void ioe_write (int reg, void *buf); 55 | #include "amdev.h" 56 | 57 | // ---------- CTE: Interrupt Handling and Context Switching ---------- 58 | bool cte_init (Context *(*handler)(Event ev, Context *ctx)); 59 | void yield (void); 60 | bool ienabled (void); 61 | void iset (bool enable); 62 | Context *kcontext (Area kstack, void (*entry)(void *), void *arg); 63 | 64 | // ----------------------- VME: Virtual Memory ----------------------- 65 | bool vme_init (void *(*pgalloc)(int), void (*pgfree)(void *)); 66 | void protect (AddrSpace *as); 67 | void unprotect (AddrSpace *as); 68 | void map (AddrSpace *as, void *vaddr, void *paddr, int prot); 69 | Context *ucontext (AddrSpace *as, Area kstack, void *entry); 70 | 71 | // ---------------------- MPE: Multi-Processing ---------------------- 72 | bool mpe_init (void (*entry)()); 73 | int cpu_count (void); 74 | int cpu_current (void); 75 | int atomic_xchg (int *addr, int newval); 76 | 77 | #ifdef __cplusplus 78 | } 79 | #endif 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /abstract-machine/am/include/amdev.h: -------------------------------------------------------------------------------- 1 | #ifndef __AMDEV_H__ 2 | #define __AMDEV_H__ 3 | 4 | // **MAY SUBJECT TO CHANGE IN THE FUTURE** 5 | 6 | #define AM_DEVREG(id, reg, perm, ...) \ 7 | enum { AM_##reg = (id) }; \ 8 | typedef struct { __VA_ARGS__; } AM_##reg##_T; 9 | 10 | AM_DEVREG( 1, UART_CONFIG, RD, bool present); 11 | AM_DEVREG( 2, UART_TX, WR, char data); 12 | AM_DEVREG( 3, UART_RX, RD, char data); 13 | AM_DEVREG( 4, TIMER_CONFIG, RD, bool present, has_rtc); 14 | AM_DEVREG( 5, TIMER_RTC, RD, int year, month, day, hour, minute, second); 15 | AM_DEVREG( 6, TIMER_UPTIME, RD, uint64_t us); 16 | AM_DEVREG( 7, INPUT_CONFIG, RD, bool present); 17 | AM_DEVREG( 8, INPUT_KEYBRD, RD, bool keydown; int keycode); 18 | AM_DEVREG( 9, GPU_CONFIG, RD, bool present, has_accel; int width, height, vmemsz); 19 | AM_DEVREG(10, GPU_STATUS, RD, bool ready); 20 | AM_DEVREG(11, GPU_FBDRAW, WR, int x, y; void *pixels; int w, h; bool sync); 21 | AM_DEVREG(12, GPU_MEMCPY, WR, uint32_t dest; void *src; int size); 22 | AM_DEVREG(13, GPU_RENDER, WR, uint32_t root); 23 | AM_DEVREG(14, AUDIO_CONFIG, RD, bool present; int bufsize); 24 | AM_DEVREG(15, AUDIO_CTRL, WR, int freq, channels, samples); 25 | AM_DEVREG(16, AUDIO_STATUS, RD, int count); 26 | AM_DEVREG(17, AUDIO_PLAY, WR, Area buf); 27 | AM_DEVREG(18, DISK_CONFIG, RD, bool present; int blksz, blkcnt); 28 | AM_DEVREG(19, DISK_STATUS, RD, bool ready); 29 | AM_DEVREG(20, DISK_BLKIO, WR, bool write; void *buf; int blkno, blkcnt); 30 | AM_DEVREG(21, NET_CONFIG, RD, bool present); 31 | AM_DEVREG(22, NET_STATUS, RD, int rx_len, tx_len); 32 | AM_DEVREG(23, NET_TX, WR, Area buf); 33 | AM_DEVREG(24, NET_RX, WR, Area buf); 34 | 35 | // Input 36 | 37 | #define AM_KEYS(_) \ 38 | _(ESCAPE) _(F1) _(F2) _(F3) _(F4) _(F5) _(F6) _(F7) _(F8) _(F9) _(F10) _(F11) _(F12) \ 39 | _(GRAVE) _(1) _(2) _(3) _(4) _(5) _(6) _(7) _(8) _(9) _(0) _(MINUS) _(EQUALS) _(BACKSPACE) \ 40 | _(TAB) _(Q) _(W) _(E) _(R) _(T) _(Y) _(U) _(I) _(O) _(P) _(LEFTBRACKET) _(RIGHTBRACKET) _(BACKSLASH) \ 41 | _(CAPSLOCK) _(A) _(S) _(D) _(F) _(G) _(H) _(J) _(K) _(L) _(SEMICOLON) _(APOSTROPHE) _(RETURN) \ 42 | _(LSHIFT) _(Z) _(X) _(C) _(V) _(B) _(N) _(M) _(COMMA) _(PERIOD) _(SLASH) _(RSHIFT) \ 43 | _(LCTRL) _(APPLICATION) _(LALT) _(SPACE) _(RALT) _(RCTRL) \ 44 | _(UP) _(DOWN) _(LEFT) _(RIGHT) _(INSERT) _(DELETE) _(HOME) _(END) _(PAGEUP) _(PAGEDOWN) 45 | 46 | #define AM_KEY_NAMES(key) AM_KEY_##key, 47 | enum { 48 | AM_KEY_NONE = 0, 49 | AM_KEYS(AM_KEY_NAMES) 50 | }; 51 | 52 | // GPU 53 | 54 | #define AM_GPU_TEXTURE 1 55 | #define AM_GPU_SUBTREE 2 56 | #define AM_GPU_NULL 0xffffffff 57 | 58 | typedef uint32_t gpuptr_t; 59 | 60 | struct gpu_texturedesc { 61 | uint16_t w, h; 62 | gpuptr_t pixels; 63 | } __attribute__((packed)); 64 | 65 | struct gpu_canvas { 66 | uint16_t type, w, h, x1, y1, w1, h1; 67 | gpuptr_t sibling; 68 | union { 69 | gpuptr_t child; 70 | struct gpu_texturedesc texture; 71 | }; 72 | } __attribute__((packed)); 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /abstract-machine/am/include/arch/mips32-nemu.h: -------------------------------------------------------------------------------- 1 | #ifndef __ARCH_H__ 2 | #define __ARCH_H__ 3 | 4 | struct Context { 5 | // TODO: fix the order of these members to match trap.S 6 | uintptr_t hi, gpr[32], epc, cause, lo, status; 7 | void *pdir; 8 | }; 9 | 10 | #define GPR1 gpr[2] // v0 11 | #define GPR2 gpr[0] 12 | #define GPR3 gpr[0] 13 | #define GPR4 gpr[0] 14 | #define GPRx gpr[0] 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /abstract-machine/am/include/arch/native.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCH_H__ 2 | #define ARCH_H__ 3 | 4 | #ifndef __USE_GNU 5 | # define __USE_GNU 6 | #endif 7 | 8 | #include 9 | 10 | struct Context { 11 | uintptr_t ksp; 12 | void *vm_head; 13 | ucontext_t uc; 14 | // skip the red zone of the stack frame, see the amd64 ABI manual for details 15 | uint8_t redzone[128]; 16 | }; 17 | 18 | #define GPR1 uc.uc_mcontext.gregs[REG_RDI] 19 | #define GPR2 uc.uc_mcontext.gregs[REG_RSI] 20 | #define GPR3 uc.uc_mcontext.gregs[REG_RDX] 21 | #define GPR4 uc.uc_mcontext.gregs[REG_RCX] 22 | #define GPRx uc.uc_mcontext.gregs[REG_RAX] 23 | 24 | #undef __USE_GNU 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /abstract-machine/am/include/arch/riscv32-nemu.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCH_H__ 2 | #define ARCH_H__ 3 | 4 | struct Context { 5 | // TODO: fix the order of these members to match trap.S 6 | uintptr_t mepc, mcause, gpr[32], mstatus; 7 | void *pdir; 8 | }; 9 | 10 | #define GPR1 gpr[17] // a7 11 | #define GPR2 gpr[0] 12 | #define GPR3 gpr[0] 13 | #define GPR4 gpr[0] 14 | #define GPRx gpr[0] 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /abstract-machine/am/include/arch/riscv64-mycpu.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCH_H__ 2 | #define ARCH_H__ 3 | 4 | struct Context { 5 | // TODO: fix the order of these members to match trap.S 6 | uintptr_t mepc, mcause, gpr[32], mstatus; 7 | }; 8 | 9 | #define GPR1 gpr[17] // a7 10 | #define GPR2 gpr[0] 11 | #define GPR3 gpr[0] 12 | #define GPR4 gpr[0] 13 | #define GPRx gpr[0] 14 | #endif 15 | -------------------------------------------------------------------------------- /abstract-machine/am/include/arch/riscv64-nemu.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCH_H__ 2 | #define ARCH_H__ 3 | 4 | struct Context { 5 | // TODO: fix the order of these members to match trap.S 6 | uintptr_t mepc, mcause, gpr[32], mstatus; 7 | void *pdir; 8 | }; 9 | 10 | #define GPR1 gpr[17] // a7 11 | #define GPR2 gpr[0] 12 | #define GPR3 gpr[0] 13 | #define GPR4 gpr[0] 14 | #define GPRx gpr[0] 15 | #endif 16 | -------------------------------------------------------------------------------- /abstract-machine/am/include/arch/spike.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCH_H__ 2 | #define ARCH_H__ 3 | 4 | struct Context { 5 | uintptr_t gpr[1]; 6 | }; 7 | 8 | #define GPR1 gpr[0] 9 | #define GPR2 gpr[0] 10 | #define GPR3 gpr[0] 11 | #define GPR4 gpr[0] 12 | #define GPRx gpr[0] 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /abstract-machine/am/include/arch/x86-nemu.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCH_H__ 2 | #define ARCH_H__ 3 | 4 | struct Context { 5 | // TODO: fix the order of these members to match trap.S 6 | uintptr_t esi, ebx, eax, eip, edx, eflags, ecx, cs, esp, edi, ebp; 7 | void *cr3; 8 | int irq; 9 | }; 10 | 11 | #define GPR1 eax 12 | #define GPR2 eip 13 | #define GPR3 eip 14 | #define GPR4 eip 15 | #define GPRx eip 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /abstract-machine/am/include/arch/x86-qemu.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCH_H__ 2 | #define ARCH_H__ 3 | 4 | struct Context { 5 | void *cr3; 6 | uint32_t ds, eax, ebx, ecx, edx, 7 | esp0, esi, edi, ebp, 8 | eip, cs, eflags, esp, ss3; 9 | }; 10 | 11 | #define GPR1 eax 12 | #define GPR2 ebx 13 | #define GPR3 ecx 14 | #define GPR4 edx 15 | #define GPRx eax 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /abstract-machine/am/include/arch/x86_64-qemu.h: -------------------------------------------------------------------------------- 1 | #ifndef ARCH_H__ 2 | #define ARCH_H__ 3 | 4 | struct Context { 5 | void *cr3; 6 | uint64_t rax, rbx, rcx, rdx, 7 | rbp, rsi, rdi, 8 | r8, r9, r10, r11, 9 | r12, r13, r14, r15, 10 | rip, cs, rflags, 11 | rsp, ss, rsp0; 12 | }; 13 | 14 | 15 | #define GPR1 rdi 16 | #define GPR2 rsi 17 | #define GPR3 rdx 18 | #define GPR4 rcx 19 | #define GPRx rax 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /abstract-machine/am/src/native/ioe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | bool __am_has_ioe = false; 5 | static bool ioe_init_done = false; 6 | 7 | void __am_timer_init(); 8 | void __am_gpu_init(); 9 | void __am_input_init(); 10 | void __am_audio_init(); 11 | void __am_disk_init(); 12 | void __am_input_config(AM_INPUT_CONFIG_T *); 13 | void __am_timer_config(AM_TIMER_CONFIG_T *); 14 | void __am_timer_rtc(AM_TIMER_RTC_T *); 15 | void __am_timer_uptime(AM_TIMER_UPTIME_T *); 16 | void __am_input_keybrd(AM_INPUT_KEYBRD_T *); 17 | void __am_gpu_config(AM_GPU_CONFIG_T *); 18 | void __am_gpu_status(AM_GPU_STATUS_T *); 19 | void __am_gpu_fbdraw(AM_GPU_FBDRAW_T *); 20 | void __am_audio_config(AM_AUDIO_CONFIG_T *); 21 | void __am_audio_ctrl(AM_AUDIO_CTRL_T *); 22 | void __am_audio_status(AM_AUDIO_STATUS_T *); 23 | void __am_audio_play(AM_AUDIO_PLAY_T *); 24 | void __am_disk_config(AM_DISK_CONFIG_T *cfg); 25 | void __am_disk_status(AM_DISK_STATUS_T *stat); 26 | void __am_disk_blkio(AM_DISK_BLKIO_T *io); 27 | static void __am_uart_config(AM_UART_CONFIG_T *cfg) { cfg->present = false; } 28 | static void __am_net_config (AM_NET_CONFIG_T *cfg) { cfg->present = false; } 29 | 30 | typedef void (*handler_t)(void *buf); 31 | static void *lut[128] = { 32 | [AM_TIMER_CONFIG] = __am_timer_config, 33 | [AM_TIMER_RTC ] = __am_timer_rtc, 34 | [AM_TIMER_UPTIME] = __am_timer_uptime, 35 | [AM_INPUT_CONFIG] = __am_input_config, 36 | [AM_INPUT_KEYBRD] = __am_input_keybrd, 37 | [AM_GPU_CONFIG ] = __am_gpu_config, 38 | [AM_GPU_FBDRAW ] = __am_gpu_fbdraw, 39 | [AM_GPU_STATUS ] = __am_gpu_status, 40 | [AM_UART_CONFIG ] = __am_uart_config, 41 | [AM_AUDIO_CONFIG] = __am_audio_config, 42 | [AM_AUDIO_CTRL ] = __am_audio_ctrl, 43 | [AM_AUDIO_STATUS] = __am_audio_status, 44 | [AM_AUDIO_PLAY ] = __am_audio_play, 45 | [AM_DISK_CONFIG ] = __am_disk_config, 46 | [AM_DISK_STATUS ] = __am_disk_status, 47 | [AM_DISK_BLKIO ] = __am_disk_blkio, 48 | [AM_NET_CONFIG ] = __am_net_config, 49 | }; 50 | 51 | bool ioe_init() { 52 | panic_on(cpu_current() != 0, "call ioe_init() in other CPUs"); 53 | panic_on(ioe_init_done, "double-initialization"); 54 | __am_has_ioe = true; 55 | return true; 56 | } 57 | 58 | static void fail(void *buf) { panic("access nonexist register"); } 59 | 60 | void __am_ioe_init() { 61 | for (int i = 0; i < LENGTH(lut); i++) 62 | if (!lut[i]) lut[i] = fail; 63 | __am_timer_init(); 64 | __am_gpu_init(); 65 | __am_input_init(); 66 | __am_audio_init(); 67 | __am_disk_init(); 68 | ioe_init_done = true; 69 | } 70 | 71 | static void do_io(int reg, void *buf) { 72 | if (!ioe_init_done) { 73 | __am_ioe_init(); 74 | } 75 | ((handler_t)lut[reg])(buf); 76 | } 77 | 78 | void ioe_read (int reg, void *buf) { do_io(reg, buf); } 79 | void ioe_write(int reg, void *buf) { do_io(reg, buf); } 80 | -------------------------------------------------------------------------------- /abstract-machine/am/src/native/ioe/audio.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | static int rfd = -1, wfd = -1; 8 | static volatile int count = 0; 9 | 10 | void __am_audio_init() { 11 | int fds[2]; 12 | int ret = pipe2(fds, O_NONBLOCK); 13 | assert(ret == 0); 14 | rfd = fds[0]; 15 | wfd = fds[1]; 16 | } 17 | 18 | static void audio_play(void *userdata, uint8_t *stream, int len) { 19 | int nread = len; 20 | if (count < len) nread = count; 21 | int b = 0; 22 | while (b < nread) { 23 | int n = read(rfd, stream, nread); 24 | if (n > 0) b += n; 25 | } 26 | 27 | count -= nread; 28 | if (len > nread) { 29 | memset(stream + nread, 0, len - nread); 30 | } 31 | } 32 | 33 | static void audio_write(uint8_t *buf, int len) { 34 | int nwrite = 0; 35 | while (nwrite < len) { 36 | int n = write(wfd, buf, len); 37 | if (n == -1) n = 0; 38 | count += n; 39 | nwrite += n; 40 | } 41 | } 42 | 43 | void __am_audio_ctrl(AM_AUDIO_CTRL_T *ctrl) { 44 | SDL_AudioSpec s = {}; 45 | s.freq = ctrl->freq; 46 | s.format = AUDIO_S16SYS; 47 | s.channels = ctrl->channels; 48 | s.samples = ctrl->samples; 49 | s.callback = audio_play; 50 | s.userdata = NULL; 51 | 52 | count = 0; 53 | int ret = SDL_InitSubSystem(SDL_INIT_AUDIO); 54 | if (ret == 0) { 55 | SDL_OpenAudio(&s, NULL); 56 | SDL_PauseAudio(0); 57 | } 58 | } 59 | 60 | void __am_audio_status(AM_AUDIO_STATUS_T *stat) { 61 | stat->count = count; 62 | } 63 | 64 | void __am_audio_play(AM_AUDIO_PLAY_T *ctl) { 65 | int len = ctl->buf.end - ctl->buf.start; 66 | audio_write(ctl->buf.start, len); 67 | } 68 | 69 | void __am_audio_config(AM_AUDIO_CONFIG_T *cfg) { 70 | cfg->present = true; 71 | cfg->bufsize = fcntl(rfd, F_GETPIPE_SZ); 72 | } 73 | -------------------------------------------------------------------------------- /abstract-machine/am/src/native/ioe/disk.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define BLKSZ 512 7 | 8 | static int disk_size = 0; 9 | static FILE *fp = NULL; 10 | 11 | void __am_disk_init() { 12 | const char *diskimg = getenv("diskimg"); 13 | if (diskimg) { 14 | fp = fopen(diskimg, "r+"); 15 | if (fp) { 16 | fseek(fp, 0, SEEK_END); 17 | disk_size = (ftell(fp) + 511) / 512; 18 | rewind(fp); 19 | } 20 | } 21 | } 22 | 23 | void __am_disk_config(AM_DISK_CONFIG_T *cfg) { 24 | cfg->present = (fp != NULL); 25 | cfg->blksz = BLKSZ; 26 | cfg->blkcnt = disk_size; 27 | } 28 | 29 | void __am_disk_status(AM_DISK_STATUS_T *stat) { 30 | stat->ready = 1; 31 | } 32 | 33 | void __am_disk_blkio(AM_DISK_BLKIO_T *io) { 34 | if (fp) { 35 | fseek(fp, io->blkno * BLKSZ, SEEK_SET); 36 | int ret; 37 | if (io->write) ret = fwrite(io->buf, io->blkcnt * BLKSZ, 1, fp); 38 | else ret = fread(io->buf, io->blkcnt * BLKSZ, 1, fp); 39 | assert(ret == 1); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /abstract-machine/am/src/native/ioe/gpu.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | //#define MODE_800x600 6 | #ifdef MODE_800x600 7 | # define W 800 8 | # define H 600 9 | #else 10 | # define W 400 11 | # define H 300 12 | #endif 13 | 14 | #define FPS 60 15 | 16 | #define RMASK 0x00ff0000 17 | #define GMASK 0x0000ff00 18 | #define BMASK 0x000000ff 19 | #define AMASK 0x00000000 20 | 21 | static SDL_Window *window = NULL; 22 | static SDL_Surface *surface = NULL; 23 | 24 | static Uint32 texture_sync(Uint32 interval, void *param) { 25 | SDL_BlitScaled(surface, NULL, SDL_GetWindowSurface(window), NULL); 26 | SDL_UpdateWindowSurface(window); 27 | return interval; 28 | } 29 | 30 | void __am_gpu_init() { 31 | SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER); 32 | window = SDL_CreateWindow("Native Application", 33 | SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 34 | #ifdef MODE_800x600 35 | W, H, 36 | #else 37 | W * 2, H * 2, 38 | #endif 39 | SDL_WINDOW_SHOWN); 40 | surface = SDL_CreateRGBSurface(SDL_SWSURFACE, W, H, 32, 41 | RMASK, GMASK, BMASK, AMASK); 42 | SDL_AddTimer(1000 / FPS, texture_sync, NULL); 43 | } 44 | 45 | void __am_gpu_config(AM_GPU_CONFIG_T *cfg) { 46 | *cfg = (AM_GPU_CONFIG_T) { 47 | .present = true, .has_accel = false, 48 | .width = W, .height = H, 49 | .vmemsz = 0 50 | }; 51 | } 52 | 53 | void __am_gpu_status(AM_GPU_STATUS_T *stat) { 54 | stat->ready = true; 55 | } 56 | 57 | void __am_gpu_fbdraw(AM_GPU_FBDRAW_T *ctl) { 58 | int x = ctl->x, y = ctl->y, w = ctl->w, h = ctl->h; 59 | if (w == 0 || h == 0) return; 60 | feclearexcept(-1); 61 | SDL_Surface *s = SDL_CreateRGBSurfaceFrom(ctl->pixels, w, h, 32, w * sizeof(uint32_t), 62 | RMASK, GMASK, BMASK, AMASK); 63 | SDL_Rect rect = { .x = x, .y = y }; 64 | SDL_BlitSurface(s, NULL, surface, &rect); 65 | SDL_FreeSurface(s); 66 | } 67 | -------------------------------------------------------------------------------- /abstract-machine/am/src/native/ioe/input.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define KEYDOWN_MASK 0x8000 5 | 6 | #define KEY_QUEUE_LEN 1024 7 | static int key_queue[KEY_QUEUE_LEN] = {}; 8 | static int key_f = 0, key_r = 0; 9 | static SDL_mutex *key_queue_lock = NULL; 10 | 11 | #define XX(k) [SDL_SCANCODE_##k] = AM_KEY_##k, 12 | static int keymap[256] = { 13 | AM_KEYS(XX) 14 | }; 15 | 16 | static int event_thread(void *args) { 17 | SDL_Event event; 18 | while (1) { 19 | SDL_WaitEvent(&event); 20 | switch (event.type) { 21 | case SDL_QUIT: halt(0); 22 | case SDL_KEYDOWN: 23 | case SDL_KEYUP: { 24 | SDL_Keysym k = event.key.keysym; 25 | int keydown = event.key.type == SDL_KEYDOWN; 26 | int scancode = k.scancode; 27 | if (keymap[scancode] != 0) { 28 | int am_code = keymap[scancode] | (keydown ? KEYDOWN_MASK : 0); 29 | SDL_LockMutex(key_queue_lock); 30 | key_queue[key_r] = am_code; 31 | key_r = (key_r + 1) % KEY_QUEUE_LEN; 32 | SDL_UnlockMutex(key_queue_lock); 33 | void __am_send_kbd_intr(); 34 | __am_send_kbd_intr(); 35 | } 36 | break; 37 | } 38 | } 39 | } 40 | } 41 | 42 | void __am_input_init() { 43 | key_queue_lock = SDL_CreateMutex(); 44 | SDL_CreateThread(event_thread, "event thread", NULL); 45 | } 46 | 47 | void __am_input_config(AM_INPUT_CONFIG_T *cfg) { 48 | cfg->present = true; 49 | } 50 | 51 | void __am_input_keybrd(AM_INPUT_KEYBRD_T *kbd) { 52 | int k = AM_KEY_NONE; 53 | 54 | SDL_LockMutex(key_queue_lock); 55 | if (key_f != key_r) { 56 | k = key_queue[key_f]; 57 | key_f = (key_f + 1) % KEY_QUEUE_LEN; 58 | } 59 | SDL_UnlockMutex(key_queue_lock); 60 | 61 | kbd->keydown = (k & KEYDOWN_MASK ? true : false); 62 | kbd->keycode = k & ~KEYDOWN_MASK; 63 | } 64 | -------------------------------------------------------------------------------- /abstract-machine/am/src/native/ioe/timer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static struct timeval boot_time = {}; 6 | 7 | void __am_timer_config(AM_TIMER_CONFIG_T *cfg) { 8 | cfg->present = cfg->has_rtc = true; 9 | } 10 | 11 | void __am_timer_rtc(AM_TIMER_RTC_T *rtc) { 12 | time_t t = time(NULL); 13 | struct tm *tm = localtime(&t); 14 | rtc->second = tm->tm_sec; 15 | rtc->minute = tm->tm_min; 16 | rtc->hour = tm->tm_hour; 17 | rtc->day = tm->tm_mday; 18 | rtc->month = tm->tm_mon + 1; 19 | rtc->year = tm->tm_year + 1900; 20 | } 21 | 22 | void __am_timer_uptime(AM_TIMER_UPTIME_T *uptime) { 23 | struct timeval now; 24 | gettimeofday(&now, NULL); 25 | long seconds = now.tv_sec - boot_time.tv_sec; 26 | long useconds = now.tv_usec - boot_time.tv_usec; 27 | uptime->us = seconds * 1000000 + (useconds + 500); 28 | } 29 | 30 | void __am_timer_init() { 31 | gettimeofday(&boot_time, NULL); 32 | } 33 | -------------------------------------------------------------------------------- /abstract-machine/am/src/native/mpe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "platform.h" 3 | 4 | int __am_mpe_init = 0; 5 | extern bool __am_has_ioe; 6 | void __am_ioe_init(); 7 | 8 | bool mpe_init(void (*entry)()) { 9 | __am_mpe_init = 1; 10 | 11 | int sync_pipe[2]; 12 | assert(0 == pipe(sync_pipe)); 13 | 14 | for (int i = 1; i < cpu_count(); i++) { 15 | if (fork() == 0) { 16 | char ch; 17 | assert(read(sync_pipe[0], &ch, 1) == 1); 18 | assert(ch == '+'); 19 | close(sync_pipe[0]); close(sync_pipe[1]); 20 | 21 | thiscpu->cpuid = i; 22 | __am_init_timer_irq(); 23 | entry(); 24 | } 25 | } 26 | 27 | if (__am_has_ioe) { 28 | __am_ioe_init(); 29 | } 30 | 31 | for (int i = 1; i < cpu_count(); i++) { 32 | assert(write(sync_pipe[1], "+", 1) == 1); 33 | } 34 | close(sync_pipe[0]); close(sync_pipe[1]); 35 | 36 | entry(); 37 | panic("MP entry should not return\n"); 38 | } 39 | 40 | int cpu_count() { 41 | extern int __am_ncpu; 42 | return __am_ncpu; 43 | } 44 | 45 | int cpu_current() { 46 | return thiscpu->cpuid; 47 | } 48 | 49 | int atomic_xchg(int *addr, int newval) { 50 | return atomic_exchange((int *)addr, newval); 51 | } 52 | -------------------------------------------------------------------------------- /abstract-machine/am/src/native/platform.h: -------------------------------------------------------------------------------- 1 | #ifndef __PLATFORM_H__ 2 | #define __PLATFORM_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | void __am_get_example_uc(Context *r); 11 | void __am_get_intr_sigmask(sigset_t *s); 12 | int __am_is_sigmask_sti(sigset_t *s); 13 | void __am_init_timer_irq(); 14 | void __am_pmem_map(void *va, void *pa, int prot); 15 | void __am_pmem_unmap(void *va); 16 | 17 | // per-cpu structure 18 | typedef struct { 19 | void *vm_head; 20 | uintptr_t ksp; 21 | int cpuid; 22 | Event ev; // similar to cause register in mips/riscv 23 | uint8_t sigstack[SIGSTKSZ]; 24 | } __am_cpu_t; 25 | extern __am_cpu_t *__am_cpu_struct; 26 | #define thiscpu __am_cpu_struct 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /abstract-machine/am/src/native/trap.S: -------------------------------------------------------------------------------- 1 | .global __am_kcontext_start 2 | __am_kcontext_start: 3 | // rdi = arg, rsi = entry 4 | 5 | // (rsp + 8) should be multiple of 16 when 6 | // control is transfered to the function entry point. 7 | // See amd64 ABI manual for more details 8 | andq $0xfffffffffffffff0, %rsp 9 | call *%rsi 10 | call __am_panic_on_return 11 | -------------------------------------------------------------------------------- /abstract-machine/am/src/native/trm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void __am_platform_dummy(); 6 | void __am_exit_platform(int code); 7 | 8 | void trm_init() { 9 | __am_platform_dummy(); 10 | } 11 | 12 | void putch(char ch) { 13 | putchar(ch); 14 | } 15 | 16 | void halt(int code) { 17 | const char *fmt = "Exit code = 40h\n"; 18 | for (const char *p = fmt; *p; p++) { 19 | char ch = *p; 20 | if (ch == '0' || ch == '4') { 21 | ch = "0123456789abcdef"[(code >> (ch - '0')) & 0xf]; 22 | } 23 | putch(ch); 24 | } 25 | __am_exit_platform(code); 26 | putstr("Should not reach here!\n"); 27 | while (1); 28 | } 29 | 30 | Area heap = {}; 31 | -------------------------------------------------------------------------------- /abstract-machine/am/src/native/vme.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include "platform.h" 4 | 5 | #define USER_SPACE RANGE(0x40000000, 0xc0000000) 6 | 7 | typedef struct PageMap { 8 | void *va; 9 | void *pa; 10 | struct PageMap *next; 11 | int prot; 12 | int is_mapped; 13 | char key[32]; // used for hsearch_r() 14 | } PageMap; 15 | 16 | typedef struct VMHead { 17 | PageMap *head; 18 | struct hsearch_data hash; 19 | int nr_page; 20 | } VMHead; 21 | 22 | #define list_foreach(p, head) \ 23 | for (p = (PageMap *)(head); p != NULL; p = p->next) 24 | 25 | extern int __am_pgsize; 26 | static int vme_enable = 0; 27 | static void* (*pgalloc)(int) = NULL; 28 | static void (*pgfree)(void *) = NULL; 29 | 30 | bool vme_init(void* (*pgalloc_f)(int), void (*pgfree_f)(void*)) { 31 | pgalloc = pgalloc_f; 32 | pgfree = pgfree_f; 33 | vme_enable = 1; 34 | return true; 35 | } 36 | 37 | void protect(AddrSpace *as) { 38 | assert(as != NULL); 39 | VMHead *h = pgalloc(__am_pgsize); // used as head of the list 40 | assert(h != NULL); 41 | memset(h, 0, sizeof(*h)); 42 | int max_pg = (USER_SPACE.end - USER_SPACE.start) / __am_pgsize; 43 | int ret = hcreate_r(max_pg, &h->hash); 44 | assert(ret != 0); 45 | 46 | as->ptr = h; 47 | as->pgsize = __am_pgsize; 48 | as->area = USER_SPACE; 49 | } 50 | 51 | void unprotect(AddrSpace *as) { 52 | } 53 | 54 | void __am_switch(Context *c) { 55 | if (!vme_enable) return; 56 | 57 | VMHead *head = c->vm_head; 58 | VMHead *now_head = thiscpu->vm_head; 59 | if (head == now_head) goto end; 60 | 61 | PageMap *pp; 62 | if (now_head != NULL) { 63 | // munmap all mappings 64 | list_foreach(pp, now_head->head) { 65 | if (pp->is_mapped) { 66 | __am_pmem_unmap(pp->va); 67 | pp->is_mapped = false; 68 | } 69 | } 70 | } 71 | 72 | if (head != NULL) { 73 | // mmap all mappings 74 | list_foreach(pp, head->head) { 75 | assert(IN_RANGE(pp->va, USER_SPACE)); 76 | __am_pmem_map(pp->va, pp->pa, pp->prot); 77 | pp->is_mapped = true; 78 | } 79 | } 80 | 81 | end: 82 | thiscpu->vm_head = head; 83 | } 84 | 85 | void map(AddrSpace *as, void *va, void *pa, int prot) { 86 | assert(IN_RANGE(va, USER_SPACE)); 87 | assert((uintptr_t)va % __am_pgsize == 0); 88 | assert((uintptr_t)pa % __am_pgsize == 0); 89 | assert(as != NULL); 90 | PageMap *pp = NULL; 91 | VMHead *vm_head = as->ptr; 92 | assert(vm_head != NULL); 93 | char buf[32]; 94 | snprintf(buf, 32, "%x", va); 95 | ENTRY item = { .key = buf }; 96 | ENTRY *item_find; 97 | hsearch_r(item, FIND, &item_find, &vm_head->hash); 98 | if (item_find == NULL) { 99 | pp = pgalloc(__am_pgsize); // this will waste memory, any better idea? 100 | snprintf(pp->key, 32, "%x", va); 101 | item.key = pp->key; 102 | item.data = pp; 103 | int ret = hsearch_r(item, ENTER, &item_find, &vm_head->hash); 104 | assert(ret != 0); 105 | vm_head->nr_page ++; 106 | } else { 107 | pp = item_find->data; 108 | } 109 | pp->va = va; 110 | pp->pa = pa; 111 | pp->prot = prot; 112 | pp->is_mapped = false; 113 | pp->next = vm_head->head; 114 | vm_head->head = pp; 115 | 116 | if (vm_head == thiscpu->vm_head) { 117 | // enforce the map immediately 118 | __am_pmem_map(pp->va, pp->pa, pp->prot); 119 | pp->is_mapped = true; 120 | } 121 | } 122 | 123 | Context* ucontext(AddrSpace *as, Area kstack, void *entry) { 124 | Context *c = (Context*)kstack.end - 1; 125 | 126 | __am_get_example_uc(c); 127 | c->uc.uc_mcontext.gregs[REG_RIP] = (uintptr_t)entry; 128 | c->uc.uc_mcontext.gregs[REG_RSP] = (uintptr_t)USER_SPACE.end; 129 | 130 | int ret = sigemptyset(&(c->uc.uc_sigmask)); // enable interrupt 131 | assert(ret == 0); 132 | c->vm_head = as->ptr; 133 | 134 | c->ksp = (uintptr_t)kstack.end; 135 | 136 | return c; 137 | } 138 | 139 | int __am_in_userspace(void *addr) { 140 | return vme_enable && thiscpu->vm_head != NULL && IN_RANGE(addr, USER_SPACE); 141 | } 142 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/nemu/cte.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define NR_IRQ 256 // IDT size 6 | #define SEG_KCODE 1 7 | #define SEG_KDATA 2 8 | 9 | static Context* (*user_handler)(Event, Context*) = NULL; 10 | 11 | void __am_irq0(); 12 | void __am_vecsys(); 13 | void __am_vectrap(); 14 | void __am_vecnull(); 15 | 16 | 17 | Context* __am_irq_handle(Context *c) { 18 | if (user_handler) { 19 | Event ev = {0}; 20 | switch (c->irq) { 21 | default: ev.event = EVENT_ERROR; break; 22 | } 23 | 24 | c = user_handler(ev, c); 25 | assert(c != NULL); 26 | } 27 | 28 | return c; 29 | } 30 | 31 | bool cte_init(Context*(*handler)(Event, Context*)) { 32 | static GateDesc32 idt[NR_IRQ]; 33 | 34 | // initialize IDT 35 | for (unsigned int i = 0; i < NR_IRQ; i ++) { 36 | idt[i] = GATE32(STS_TG, KSEL(SEG_KCODE), __am_vecnull, DPL_KERN); 37 | } 38 | 39 | // ----------------------- interrupts ---------------------------- 40 | idt[32] = GATE32(STS_IG, KSEL(SEG_KCODE), __am_irq0, DPL_KERN); 41 | // ---------------------- system call ---------------------------- 42 | idt[0x80] = GATE32(STS_TG, KSEL(SEG_KCODE), __am_vecsys, DPL_USER); 43 | idt[0x81] = GATE32(STS_TG, KSEL(SEG_KCODE), __am_vectrap, DPL_KERN); 44 | 45 | set_idt(idt, sizeof(idt)); 46 | 47 | // register event handler 48 | user_handler = handler; 49 | 50 | return true; 51 | } 52 | 53 | 54 | Context* kcontext(Area kstack, void (*entry)(void *), void *arg) { 55 | return NULL; 56 | } 57 | 58 | void yield() { 59 | asm volatile("int $0x81"); 60 | } 61 | 62 | bool ienabled() { 63 | return false; 64 | } 65 | 66 | void iset(bool enable) { 67 | } 68 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/nemu/start.S: -------------------------------------------------------------------------------- 1 | .section entry, "ax" 2 | .globl _start 3 | .type _start, @function 4 | 5 | _start: 6 | mov $0, %ebp 7 | mov $_stack_pointer, %esp 8 | call _trm_init # never return 9 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/nemu/trap.S: -------------------------------------------------------------------------------- 1 | #----|------------entry------------|---irq id---|-----handler-----| 2 | .globl __am_vecsys; __am_vecsys: pushl $0x80; jmp __am_asm_trap 3 | .globl __am_vectrap; __am_vectrap: pushl $0x81; jmp __am_asm_trap 4 | .globl __am_irq0; __am_irq0: pushl $32; jmp __am_asm_trap 5 | .globl __am_vecnull; __am_vecnull: pushl $-1; jmp __am_asm_trap 6 | 7 | 8 | __am_asm_trap: 9 | pushal 10 | 11 | pushl $0 12 | 13 | pushl %esp 14 | call __am_irq_handle 15 | 16 | addl $4, %esp 17 | 18 | addl $4, %esp 19 | popal 20 | addl $4, %esp 21 | 22 | iret 23 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/nemu/vme.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static AddrSpace kas = {}; 6 | static void* (*pgalloc_usr)(int) = NULL; 7 | static void (*pgfree_usr)(void*) = NULL; 8 | static int vme_enable = 0; 9 | 10 | static Area segments[] = { // Kernel memory mappings 11 | NEMU_PADDR_SPACE 12 | }; 13 | 14 | #define USER_SPACE RANGE(0x40000000, 0xc0000000) 15 | 16 | bool vme_init(void* (*pgalloc_f)(int), void (*pgfree_f)(void*)) { 17 | pgalloc_usr = pgalloc_f; 18 | pgfree_usr = pgfree_f; 19 | 20 | kas.ptr = pgalloc_f(PGSIZE); 21 | 22 | int i; 23 | for (i = 0; i < LENGTH(segments); i ++) { 24 | void *va = segments[i].start; 25 | for (; va < segments[i].end; va += PGSIZE) { 26 | map(&kas, va, va, 0); 27 | } 28 | } 29 | 30 | set_cr3(kas.ptr); 31 | set_cr0(get_cr0() | CR0_PG); 32 | vme_enable = 1; 33 | 34 | return true; 35 | } 36 | 37 | void protect(AddrSpace *as) { 38 | PTE *updir = (PTE*)(pgalloc_usr(PGSIZE)); 39 | as->ptr = updir; 40 | as->area = USER_SPACE; 41 | as->pgsize = PGSIZE; 42 | // map kernel space 43 | memcpy(updir, kas.ptr, PGSIZE); 44 | } 45 | 46 | void unprotect(AddrSpace *as) { 47 | } 48 | 49 | void __am_get_cur_as(Context *c) { 50 | c->cr3 = (vme_enable ? (void *)get_cr3() : NULL); 51 | } 52 | 53 | void __am_switch(Context *c) { 54 | if (vme_enable && c->cr3 != NULL) { 55 | set_cr3(c->cr3); 56 | } 57 | } 58 | 59 | void map(AddrSpace *as, void *va, void *pa, int prot) { 60 | } 61 | 62 | Context* ucontext(AddrSpace *as, Area kstack, void *entry) { 63 | return NULL; 64 | } 65 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/qemu/boot/Makefile: -------------------------------------------------------------------------------- 1 | SRCS := start.S main.c 2 | bootblock.o: $(SRCS) Makefile 3 | @echo + CC $(SRCS) 4 | @$(CROSS_COMPILE)gcc -static -m32 -fno-pic -Os -nostdlib -Ttext 0x7c00 -I$(AM_HOME)/am/src -o bootblock.o $(SRCS) 5 | @python3 genboot.py bootblock.o 6 | 7 | clean: 8 | rm -rf *.o 9 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/qemu/boot/genboot.py: -------------------------------------------------------------------------------- 1 | import os, sys, pathlib, subprocess 2 | 3 | f = pathlib.Path(sys.argv[1]) 4 | try: 5 | objcopy = os.getenv('CROSS_COMPILE', '') + 'objcopy' 6 | data = subprocess.run( 7 | [objcopy, '-S', '-O', 'binary', '-j', '.text', f, '/dev/stdout'], 8 | capture_output=True).stdout 9 | assert len(data) <= 510 10 | data += b'\0' * (510 - len(data)) + b'\x55\xaa' 11 | f.write_bytes(data) 12 | except: 13 | f.unlink() 14 | raise 15 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/qemu/boot/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define SECTSIZE 512 6 | #define ARGSIZE 1024 7 | 8 | static inline void wait_disk(void) { 9 | while ((inb(0x1f7) & 0xc0) != 0x40); 10 | } 11 | 12 | static inline void read_disk(void *buf, int sect) { 13 | wait_disk(); 14 | outb(0x1f2, 1); 15 | outb(0x1f3, sect); 16 | outb(0x1f4, sect >> 8); 17 | outb(0x1f5, sect >> 16); 18 | outb(0x1f6, (sect >> 24) | 0xE0); 19 | outb(0x1f7, 0x20); 20 | wait_disk(); 21 | for (int i = 0; i < SECTSIZE / 4; i ++) { 22 | ((uint32_t *)buf)[i] = inl(0x1f0); 23 | } 24 | } 25 | 26 | static inline void copy_from_disk(void *buf, int nbytes, int disk_offset) { 27 | uint32_t cur = (uint32_t)buf & ~(SECTSIZE - 1); 28 | uint32_t ed = (uint32_t)buf + nbytes; 29 | uint32_t sect = (disk_offset / SECTSIZE) + (ARGSIZE / SECTSIZE) + 1; 30 | for(; cur < ed; cur += SECTSIZE, sect ++) 31 | read_disk((void *)cur, sect); 32 | } 33 | 34 | static void load_program(uint32_t filesz, uint32_t memsz, uint32_t paddr, uint32_t offset) { 35 | copy_from_disk((void *)paddr, filesz, offset); 36 | char *bss = (void *)(paddr + filesz); 37 | for (uint32_t i = filesz; i != memsz; i++) { 38 | *bss++ = 0; 39 | } 40 | } 41 | 42 | static void load_elf64(Elf64_Ehdr *elf) { 43 | Elf64_Phdr *ph = (Elf64_Phdr *)((char *)elf + elf->e_phoff); 44 | for (int i = 0; i < elf->e_phnum; i++, ph++) { 45 | load_program( 46 | (uint32_t)ph->p_filesz, 47 | (uint32_t)ph->p_memsz, 48 | (uint32_t)ph->p_paddr, 49 | (uint32_t)ph->p_offset 50 | ); 51 | } 52 | } 53 | 54 | static void load_elf32(Elf32_Ehdr *elf) { 55 | Elf32_Phdr *ph = (Elf32_Phdr *)((char *)elf + elf->e_phoff); 56 | for (int i = 0; i < elf->e_phnum; i++, ph++) { 57 | load_program( 58 | (uint32_t)ph->p_filesz, 59 | (uint32_t)ph->p_memsz, 60 | (uint32_t)ph->p_paddr, 61 | (uint32_t)ph->p_offset 62 | ); 63 | } 64 | } 65 | 66 | void load_kernel(void) { 67 | Elf32_Ehdr *elf32 = (void *)0x8000; 68 | Elf64_Ehdr *elf64 = (void *)0x8000; 69 | int is_ap = boot_record()->is_ap; 70 | 71 | if (!is_ap) { 72 | // load argument (string) to memory 73 | copy_from_disk((void *)MAINARG_ADDR, 1024, -1024); 74 | // load elf header to memory 75 | copy_from_disk(elf32, 4096, 0); 76 | if (elf32->e_machine == EM_X86_64) { 77 | load_elf64(elf64); 78 | } else { 79 | load_elf32(elf32); 80 | } 81 | } else { 82 | // everything should be loaded 83 | } 84 | 85 | if (elf32->e_machine == EM_X86_64) { 86 | ((void(*)())(uint32_t)elf64->e_entry)(); 87 | } else { 88 | ((void(*)())(uint32_t)elf32->e_entry)(); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/qemu/boot/start.S: -------------------------------------------------------------------------------- 1 | #define CR0_PE 0x00000001 2 | 3 | #define GDT_ENTRY(n) \ 4 | ((n) << 3) 5 | 6 | #define SEG_NULLASM \ 7 | .word 0, 0; \ 8 | .byte 0, 0, 0, 0 9 | 10 | #define SEG_ASM(type, base, lim) \ 11 | .word (((lim) >> 12) & 0xffff), ((base) & 0xffff); \ 12 | .byte (((base) >> 16) & 0xff), (0x90 | (type)), \ 13 | (0xC0 | (((lim) >> 28) & 0xf)), (((base) >> 24) & 0xff) 14 | 15 | .code16 16 | .globl _start 17 | _start: 18 | cli 19 | 20 | xorw %ax, %ax 21 | movw %ax, %ds 22 | movw %ax, %es 23 | movw %ax, %ss 24 | 25 | # Set a 640 x 480 x 32 video mode 26 | mov $0x4f01, %ax 27 | mov $0x0112, %cx 28 | mov $0x4000, %di 29 | int $0x10 30 | 31 | mov $0x4f02, %ax 32 | mov $0x4112, %bx 33 | int $0x10 34 | 35 | lgdt gdtdesc 36 | movl %cr0, %eax 37 | orl $CR0_PE, %eax 38 | movl %eax, %cr0 39 | ljmp $GDT_ENTRY(1), $start32 40 | 41 | .code32 42 | start32: 43 | movw $GDT_ENTRY(2), %ax 44 | movw %ax, %ds 45 | movw %ax, %es 46 | movw %ax, %ss 47 | 48 | movl $0xa000, %esp 49 | call load_kernel 50 | 51 | # GDT 52 | .p2align 2 53 | gdt: 54 | SEG_NULLASM 55 | SEG_ASM(0xA, 0x0, 0xffffffff) 56 | SEG_ASM(0x2, 0x0, 0xffffffff) 57 | 58 | gdtdesc: 59 | .word (gdtdesc - gdt - 1) 60 | .long gdt 61 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/qemu/cte.c: -------------------------------------------------------------------------------- 1 | #include "x86-qemu.h" 2 | 3 | static Context* (*user_handler)(Event, Context*) = NULL; 4 | #if __x86_64__ 5 | static GateDesc64 idt[NR_IRQ]; 6 | #define GATE GATE64 7 | #else 8 | static GateDesc32 idt[NR_IRQ]; 9 | #define GATE GATE32 10 | #endif 11 | 12 | #define IRQHANDLE_DECL(id, dpl, err) \ 13 | void __am_irq##id(); 14 | 15 | IRQS(IRQHANDLE_DECL) 16 | void __am_irqall(); 17 | void __am_kcontext_start(); 18 | 19 | void __am_irq_handle(struct trap_frame *tf) { 20 | Context *saved_ctx = &tf->saved_context; 21 | Event ev = { 22 | .event = EVENT_NULL, 23 | .cause = 0, .ref = 0, 24 | .msg = "(no message)", 25 | }; 26 | 27 | #if __x86_64 28 | saved_ctx->rip = tf->rip; 29 | saved_ctx->cs = tf->cs; 30 | saved_ctx->rflags = tf->rflags; 31 | saved_ctx->rsp = tf->rsp; 32 | saved_ctx->rsp0 = CPU->tss.rsp0; 33 | saved_ctx->ss = tf->ss; 34 | #else 35 | saved_ctx->eip = tf->eip; 36 | saved_ctx->cs = tf->cs; 37 | saved_ctx->eflags = tf->eflags; 38 | saved_ctx->esp0 = CPU->tss.esp0; 39 | saved_ctx->ss3 = USEL(SEG_UDATA); 40 | // no ss/esp saved for DPL_KERNEL 41 | saved_ctx->esp = (tf->cs & DPL_USER ? tf->esp : (uint32_t)(tf + 1) - 8); 42 | #endif 43 | saved_ctx->cr3 = (void *)get_cr3(); 44 | 45 | #define IRQ T_IRQ0 + 46 | #define MSG(m) ev.msg = m; 47 | 48 | if (IRQ 0 <= tf->irq && tf->irq < IRQ 32) { 49 | __am_lapic_eoi(); 50 | } 51 | 52 | switch (tf->irq) { 53 | case IRQ 0: MSG("timer interrupt (lapic)") 54 | ev.event = EVENT_IRQ_TIMER; break; 55 | case IRQ 1: MSG("I/O device IRQ1 (keyboard)") 56 | ev.event = EVENT_IRQ_IODEV; break; 57 | case IRQ 4: MSG("I/O device IRQ4 (COM1)") 58 | ev.event = EVENT_IRQ_IODEV; break; 59 | case EX_SYSCALL: MSG("int $0x80 system call") 60 | ev.event = EVENT_SYSCALL; break; 61 | case EX_YIELD: MSG("int $0x81 yield") 62 | ev.event = EVENT_YIELD; break; 63 | case EX_DE: MSG("DE #0 divide by zero") 64 | ev.event = EVENT_ERROR; break; 65 | case EX_UD: MSG("UD #6 invalid opcode") 66 | ev.event = EVENT_ERROR; break; 67 | case EX_NM: MSG("NM #7 coprocessor error") 68 | ev.event = EVENT_ERROR; break; 69 | case EX_DF: MSG("DF #8 double fault") 70 | ev.event = EVENT_ERROR; break; 71 | case EX_TS: MSG("TS #10 invalid TSS") 72 | ev.event = EVENT_ERROR; break; 73 | case EX_NP: MSG("NP #11 segment/gate not present") 74 | ev.event = EVENT_ERROR; break; 75 | case EX_SS: MSG("SS #12 stack fault") 76 | ev.event = EVENT_ERROR; break; 77 | case EX_GP: MSG("GP #13, general protection fault") 78 | ev.event = EVENT_ERROR; break; 79 | case EX_PF: MSG("PF #14, page fault, @cause: PROT_XXX") 80 | ev.event = EVENT_PAGEFAULT; 81 | if (tf->errcode & 0x1) ev.cause |= MMAP_NONE; 82 | if (tf->errcode & 0x2) ev.cause |= MMAP_WRITE; 83 | else ev.cause |= MMAP_READ; 84 | ev.ref = get_cr2(); 85 | break; 86 | default: MSG("unrecognized interrupt/exception") 87 | ev.event = EVENT_ERROR; 88 | ev.cause = tf->errcode; 89 | break; 90 | } 91 | 92 | Context *ret_ctx = user_handler(ev, saved_ctx); 93 | panic_on(!ret_ctx, "returning to NULL context"); 94 | 95 | if (ret_ctx->cr3) { 96 | set_cr3(ret_ctx->cr3); 97 | #if __x86_64__ 98 | CPU->tss.rsp0 = ret_ctx->rsp0; 99 | #else 100 | CPU->tss.ss0 = KSEL(SEG_KDATA); 101 | CPU->tss.esp0 = ret_ctx->esp0; 102 | #endif 103 | } 104 | 105 | __am_iret(ret_ctx); 106 | } 107 | 108 | bool cte_init(Context *(*handler)(Event, Context *)) { 109 | panic_on(cpu_current() != 0, "init CTE in non-bootstrap CPU"); 110 | panic_on(!handler, "no interrupt handler"); 111 | 112 | for (int i = 0; i < NR_IRQ; i ++) { 113 | idt[i] = GATE(STS_TG, KSEL(SEG_KCODE), __am_irqall, DPL_KERN); 114 | } 115 | #define IDT_ENTRY(id, dpl, err) \ 116 | idt[id] = GATE(STS_TG, KSEL(SEG_KCODE), __am_irq##id, DPL_##dpl); 117 | IRQS(IDT_ENTRY) 118 | 119 | user_handler = handler; 120 | return true; 121 | } 122 | 123 | void yield() { 124 | interrupt(0x81); 125 | } 126 | 127 | bool ienabled() { 128 | return (get_efl() & FL_IF) != 0; 129 | } 130 | 131 | void iset(bool enable) { 132 | if (enable) sti(); 133 | else cli(); 134 | } 135 | 136 | void __am_panic_on_return() { panic("kernel context returns"); } 137 | 138 | Context* kcontext(Area kstack, void (*entry)(void *), void *arg) { 139 | Context *ctx = kstack.end - sizeof(Context); 140 | *ctx = (Context) { 0 }; 141 | 142 | #if __x86_64__ 143 | ctx->cs = KSEL(SEG_KCODE); 144 | ctx->rip = (uintptr_t)__am_kcontext_start; 145 | ctx->rflags = FL_IF; 146 | ctx->rsp = (uintptr_t)kstack.end; 147 | #else 148 | ctx->ds = KSEL(SEG_KDATA); 149 | ctx->cs = KSEL(SEG_KCODE); 150 | ctx->eip = (uintptr_t)__am_kcontext_start; 151 | ctx->eflags = FL_IF; 152 | ctx->esp = (uintptr_t)kstack.end; 153 | #endif 154 | 155 | ctx->GPR1 = (uintptr_t)arg; 156 | ctx->GPR2 = (uintptr_t)entry; 157 | 158 | return ctx; 159 | } 160 | 161 | void __am_percpu_initirq() { 162 | __am_ioapic_enable(IRQ_KBD, 0); 163 | __am_ioapic_enable(IRQ_COM1, 0); 164 | set_idt(idt, sizeof(idt)); 165 | } 166 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/qemu/mpe.c: -------------------------------------------------------------------------------- 1 | #include "x86-qemu.h" 2 | 3 | struct cpu_local __am_cpuinfo[MAX_CPU] = {}; 4 | static void (* volatile user_entry)(); 5 | static int ap_ready = 0; 6 | 7 | static void call_user_entry() { 8 | user_entry(); 9 | panic("MPE entry should not return"); 10 | } 11 | 12 | bool mpe_init(void (*entry)()) { 13 | user_entry = entry; 14 | boot_record()->jmp_code = 0x000bfde9; // (16-bit) jmp (0x7c00) 15 | for (int cpu = 1; cpu < __am_ncpu; cpu++) { 16 | boot_record()->is_ap = 1; 17 | __am_lapic_bootap(cpu, (void *)boot_record()); 18 | while (xchg(&ap_ready, 0) != 1) { 19 | pause(); 20 | } 21 | } 22 | call_user_entry(); 23 | return true; 24 | } 25 | 26 | static void othercpu_entry() { 27 | __am_percpu_init(); 28 | xchg(&ap_ready, 1); 29 | call_user_entry(); 30 | } 31 | 32 | void __am_othercpu_entry() { 33 | stack_switch_call(stack_top(&CPU->stack), othercpu_entry, 0); 34 | } 35 | 36 | int cpu_count() { 37 | return __am_ncpu; 38 | } 39 | 40 | int cpu_current(void) { 41 | return __am_lapic[8] >> 24; 42 | } 43 | 44 | int atomic_xchg(int *addr, int newval) { 45 | return xchg(addr, newval); 46 | } 47 | 48 | void __am_stop_the_world() { 49 | boot_record()->jmp_code = 0x0000feeb; // (16-bit) jmp . 50 | for (int cpu_ = 0; cpu_ < __am_ncpu; cpu_++) { 51 | if (cpu_ != cpu_current()) { 52 | __am_lapic_bootap(cpu_, (void *)boot_record()); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/qemu/start32.S: -------------------------------------------------------------------------------- 1 | #include "x86-qemu.h" 2 | 3 | .globl _start 4 | _start: 5 | pushl $MAINARG_ADDR 6 | pushl $0 7 | jmp _start_c 8 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/qemu/start64.S: -------------------------------------------------------------------------------- 1 | #include 2 | #include "x86-qemu.h" 3 | 4 | .code32 5 | .globl _start 6 | _start: 7 | movl $(PDPT_ADDR | PTE_P | PTE_W), %eax 8 | cmpl (PML4_ADDR), %eax 9 | je .long_mode_init 10 | 11 | movl $(PDPT_ADDR | PTE_P | PTE_W), %eax 12 | movl %eax, (PML4_ADDR) 13 | 14 | movl $0, %ecx 15 | movl $512, %esi // 512 pages 16 | // | 17 | .loop: // x 18 | movl %ecx, %eax // | 19 | shll $30, %eax // | 20 | orl $(PTE_P | PTE_W | PTE_PS), %eax // 1 GiB page 21 | movl %eax, PDPT_ADDR(, %ecx, 8) 22 | 23 | movl %ecx, %eax 24 | shrl $2, %eax 25 | movl %eax, PDPT_ADDR + 4(, %ecx, 8) 26 | 27 | inc %ecx 28 | cmp %esi, %ecx 29 | jne .loop 30 | 31 | .long_mode_init: 32 | movl $PML4_ADDR, %eax 33 | movl %eax, %cr3 // %cr3 = PML4 base 34 | movl $CR4_PAE, %eax 35 | movl %eax, %cr4 // %cr4.PAE = 1 36 | movl $0xc0000080, %ecx 37 | rdmsr 38 | orl $0x100, %eax 39 | wrmsr // %EFER.LME = 1 40 | movl %cr0, %eax 41 | orl $CR0_PG, %eax 42 | movl %eax, %cr0 // %cr0.PG = 1 43 | lgdt gdt_ptr // bootstrap GDT 44 | ljmp $8, $_start64 // should not return 45 | 46 | .code64 47 | _start64: 48 | movw $0, %ax 49 | movw %ax, %ds 50 | movw %ax, %es 51 | movw %ax, %ss 52 | movw %ax, %fs 53 | movw %ax, %gs 54 | 55 | movq $MAINARG_ADDR, %rdi 56 | pushq $0 57 | jmp _start_c 58 | 59 | .align 16 60 | gdt_ptr: 61 | .word gdt64_end - gdt64_begin - 1 62 | .quad gdt64_begin 63 | 64 | gdt64_begin: 65 | .long 0x00000000 // 0: null desc 66 | .long 0x00000000 67 | .long 0x00000000 // 1: code 68 | .long 0x00209800 69 | gdt64_end: 70 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/qemu/trap32.S: -------------------------------------------------------------------------------- 1 | #include "x86-qemu.h" 2 | 3 | .globl __am_kcontext_start 4 | __am_kcontext_start: 5 | // eax = arg, ebx = entry 6 | pushl %eax 7 | pushl $__am_panic_on_return 8 | jmpl *%ebx 9 | 10 | trap: 11 | cli 12 | 13 | subl $20, %esp 14 | pushl %ebp 15 | pushl %edi 16 | pushl %esi 17 | pushl $0 18 | pushl %edx 19 | pushl %ecx 20 | pushl %ebx 21 | pushl %eax 22 | movw %ds, %ax 23 | pushl %eax 24 | pushl $0 25 | 26 | movw $KSEL(SEG_KDATA), %ax 27 | movw %ax, %ds 28 | movw %ax, %es 29 | movw %ax, %ss 30 | 31 | pushl %esp 32 | call __am_irq_handle 33 | 34 | .globl __am_iret 35 | __am_iret: 36 | addl $4, %esp 37 | popl %eax 38 | movl %eax, %esp 39 | 40 | addl $4, %esp 41 | popl %eax 42 | movw %ax, %ds 43 | movw %ax, %es 44 | 45 | cmpw $KSEL(SEG_KCODE), 36(%esp) 46 | je .kernel_iret 47 | 48 | .user_iret: 49 | popl %eax 50 | popl %ebx 51 | popl %ecx 52 | popl %edx 53 | addl $4, %esp 54 | popl %esi 55 | popl %edi 56 | popl %ebp 57 | iret 58 | 59 | .kernel_iret: 60 | popl %eax 61 | popl %ebx 62 | popl %ecx 63 | popl %edx 64 | addl $4, %esp 65 | 66 | /* stack frame: 67 | 28 ss 68 | 24 esp (not popped by iret when returning to ring0) 69 | 20 eflags ---> move to new-esp 70 | 16 cs 71 | 12 eip 72 | 8 ebp 73 | 4 edi 74 | 0 esi <--- %esp 75 | */ 76 | 77 | movl %esp, %ebp 78 | movl 24(%ebp), %edi // %edi is new-esp 79 | 80 | movl 20(%ebp), %esi; movl %esi, -4(%edi) 81 | movl 16(%ebp), %esi; movl %esi, -8(%edi) 82 | movl 12(%ebp), %esi; movl %esi, -12(%edi) 83 | movl 8(%ebp), %esi; movl %esi, -16(%edi) 84 | movl 4(%ebp), %esi; movl %esi, -20(%edi) 85 | movl 0(%ebp), %esi; movl %esi, -24(%edi) 86 | 87 | leal -24(%edi), %esp 88 | 89 | popl %esi 90 | popl %edi 91 | popl %ebp 92 | iret 93 | 94 | #define NOERR push $0 95 | #define ERR 96 | #define IRQ_DEF(id, dpl, err) \ 97 | .globl __am_irq##id; __am_irq##id: cli; err; push $id; jmp trap; 98 | IRQS(IRQ_DEF) 99 | .globl __am_irqall; __am_irqall: cli; push $0; push $-1; jmp trap; 100 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/qemu/trap64.S: -------------------------------------------------------------------------------- 1 | #include "x86-qemu.h" 2 | 3 | .globl __am_kcontext_start 4 | __am_kcontext_start: 5 | // rdi = arg, rsi = entry 6 | pushq $__am_panic_on_return 7 | jmpq *%rsi 8 | 9 | trap: 10 | cli 11 | subq $48, %rsp 12 | pushq %r15 13 | pushq %r14 14 | pushq %r13 15 | pushq %r12 16 | pushq %r11 17 | pushq %r10 18 | pushq %r9 19 | pushq %r8 20 | pushq %rdi 21 | pushq %rsi 22 | pushq %rbp 23 | pushq %rdx 24 | pushq %rcx 25 | pushq %rbx 26 | pushq %rax 27 | pushq $0 // cr3, saved in __am_irq_handle 28 | 29 | movq %rsp, %rdi 30 | call __am_irq_handle 31 | 32 | .globl __am_iret 33 | __am_iret: 34 | movq %rdi, %rsp 35 | movq 160(%rsp), %rax 36 | movw %ax, %ds 37 | movw %ax, %es 38 | addq $8, %rsp 39 | popq %rax 40 | popq %rbx 41 | popq %rcx 42 | popq %rdx 43 | popq %rbp 44 | popq %rsi 45 | popq %rdi 46 | popq %r8 47 | popq %r9 48 | popq %r10 49 | popq %r11 50 | popq %r12 51 | popq %r13 52 | popq %r14 53 | popq %r15 54 | iretq 55 | 56 | #define NOERR push $0 57 | #define ERR 58 | #define IRQ_DEF(id, dpl, err) \ 59 | .globl __am_irq##id; __am_irq##id: cli; err; push $id; jmp trap; 60 | IRQS(IRQ_DEF) 61 | .globl __am_irqall; __am_irqall: cli; push $0; push $-1; jmp trap; 62 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/qemu/trm.c: -------------------------------------------------------------------------------- 1 | #include "x86-qemu.h" 2 | 3 | Area heap = {}; 4 | int __am_ncpu = 0; 5 | 6 | int main(const char *args); 7 | 8 | static void call_main(const char *args) { 9 | halt(main(args)); 10 | } 11 | 12 | void _start_c(char *args) { 13 | if (boot_record()->is_ap) { 14 | __am_othercpu_entry(); 15 | } else { 16 | __am_bootcpu_init(); 17 | stack_switch_call(stack_top(&CPU->stack), call_main, (uintptr_t)args); 18 | } 19 | } 20 | 21 | void __am_bootcpu_init() { 22 | heap = __am_heap_init(); 23 | __am_lapic_init(); 24 | __am_ioapic_init(); 25 | __am_percpu_init(); 26 | } 27 | 28 | void __am_percpu_init() { 29 | __am_percpu_initgdt(); 30 | __am_percpu_initlapic(); 31 | __am_percpu_initirq(); 32 | } 33 | 34 | void putch(char ch) { 35 | #define COM1 0x3f8 36 | outb(COM1, ch); 37 | } 38 | 39 | void halt(int code) { 40 | const char *hex = "0123456789abcdef"; 41 | const char *fmt = "CPU #$ Halt (40).\n"; 42 | cli(); 43 | __am_stop_the_world(); 44 | for (const char *p = fmt; *p; p++) { 45 | char ch = *p; 46 | switch (ch) { 47 | case '$': 48 | putch(hex[cpu_current()]); 49 | break; 50 | case '0': case '4': 51 | putch(hex[(code >> (ch - '0')) & 0xf]); 52 | break; 53 | default: 54 | putch(ch); 55 | } 56 | } 57 | outw(0x604, 0x2000); // offer of qemu :) 58 | while (1) hlt(); 59 | } 60 | 61 | Area __am_heap_init() { 62 | extern char end; 63 | outb(0x70, 0x34); 64 | uint32_t lo = inb(0x71); 65 | outb(0x70, 0x35); 66 | uint32_t hi = inb(0x71) + 1; 67 | return RANGE(ROUNDUP(&end, 1 << 20), (uintptr_t)((lo | hi << 8) << 16)); 68 | } 69 | 70 | void __am_lapic_init() { 71 | for (char *st = (char *)0xf0000; st != (char *)0xffffff; st ++) { 72 | if (*(volatile uint32_t *)st == 0x5f504d5f) { 73 | uint32_t mpconf_ptr = ((volatile MPDesc *)st)->conf; 74 | MPConf *conf = (void *)((uintptr_t)(mpconf_ptr)); 75 | __am_lapic = (void *)((uintptr_t)(conf->lapicaddr)); 76 | for (volatile char *ptr = (char *)(conf + 1); 77 | ptr < (char *)conf + conf->length; ptr += 8) { 78 | if (*ptr == '\0') { 79 | ptr += 12; 80 | panic_on(++__am_ncpu > MAX_CPU, "cannot support > MAX_CPU processors"); 81 | } 82 | } 83 | return; 84 | } 85 | } 86 | bug(); 87 | } 88 | 89 | void __am_percpu_initgdt() { 90 | #if __x86_64__ 91 | SegDesc *gdt = CPU->gdt; 92 | TSS64 *tss = &CPU->tss; 93 | gdt[SEG_KCODE] = SEG64(STA_X | STA_R, DPL_KERN); 94 | gdt[SEG_KDATA] = SEG64(STA_W, DPL_KERN); 95 | gdt[SEG_UCODE] = SEG64(STA_X | STA_R, DPL_USER); 96 | gdt[SEG_UDATA] = SEG64(STA_W, DPL_USER); 97 | gdt[SEG_TSS] = SEG16(STS_T32A, tss, sizeof(*tss)-1, DPL_KERN); 98 | bug_on((uintptr_t)tss >> 32); 99 | set_gdt(gdt, sizeof(gdt[0]) * (NR_SEG + 1)); 100 | set_tr(KSEL(SEG_TSS)); 101 | #else 102 | SegDesc *gdt = CPU->gdt; 103 | TSS32 *tss = &CPU->tss; 104 | gdt[SEG_KCODE] = SEG32(STA_X | STA_R, 0, 0xffffffff, DPL_KERN); 105 | gdt[SEG_KDATA] = SEG32(STA_W, 0, 0xffffffff, DPL_KERN); 106 | gdt[SEG_UCODE] = SEG32(STA_X | STA_R, 0, 0xffffffff, DPL_USER); 107 | gdt[SEG_UDATA] = SEG32(STA_W, 0, 0xffffffff, DPL_USER); 108 | gdt[SEG_TSS] = SEG16(STS_T32A, tss, sizeof(*tss)-1, DPL_KERN); 109 | set_gdt(gdt, sizeof(gdt[0]) * NR_SEG); 110 | set_tr(KSEL(SEG_TSS)); 111 | #endif 112 | } 113 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/qemu/vme.c: -------------------------------------------------------------------------------- 1 | #include "x86-qemu.h" 2 | 3 | const struct mmu_config mmu = { 4 | .pgsize = 4096, 5 | #if __x86_64__ 6 | .ptlevels = 4, 7 | .pgtables = { 8 | { "CR3", 0x000000000000, 0, 0 }, 9 | { "PML4", 0xff8000000000, 39, 9 }, 10 | { "PDPT", 0x007fc0000000, 30, 9 }, 11 | { "PD", 0x00003fe00000, 21, 9 }, 12 | { "PT", 0x0000001ff000, 12, 9 }, 13 | }, 14 | #else 15 | .ptlevels = 2, 16 | .pgtables = { 17 | { "CR3", 0x00000000, 0, 0 }, 18 | { "PD", 0xffc00000, 22, 10 }, 19 | { "PT", 0x003ff000, 12, 10 }, 20 | }, 21 | #endif 22 | }; 23 | 24 | static const struct vm_area vm_areas[] = { 25 | #ifdef __x86_64__ 26 | { RANGE(0x100000000000, 0x108000000000), 0 }, // 512 GiB user space 27 | { RANGE(0x000000000000, 0x008000000000), 1 }, // 512 GiB kernel 28 | #else 29 | { RANGE( 0x40000000, 0x80000000), 0 }, // 1 GiB user space 30 | { RANGE( 0x00000000, 0x40000000), 1 }, // 1 GiB kernel 31 | { RANGE( 0xfd000000, 0x00000000), 1 }, // memory-mapped I/O 32 | #endif 33 | }; 34 | #define uvm_area (vm_areas[0].area) 35 | 36 | static uintptr_t *kpt; 37 | static void *(*pgalloc)(int size); 38 | static void (*pgfree)(void *); 39 | 40 | static void *pgallocz() { 41 | uintptr_t *base = pgalloc(mmu.pgsize); 42 | panic_on(!base, "cannot allocate page"); 43 | for (int i = 0; i < mmu.pgsize / sizeof(uintptr_t); i++) { 44 | base[i] = 0; 45 | } 46 | return base; 47 | } 48 | 49 | static int indexof(uintptr_t addr, const struct ptinfo *info) { 50 | return ((uintptr_t)addr & info->mask) >> info->shift; 51 | } 52 | 53 | static uintptr_t baseof(uintptr_t addr) { 54 | return addr & ~(mmu.pgsize - 1); 55 | } 56 | 57 | static uintptr_t *ptwalk(AddrSpace *as, uintptr_t addr, int flags) { 58 | uintptr_t cur = (uintptr_t)&as->ptr; 59 | 60 | for (int i = 0; i <= mmu.ptlevels; i++) { 61 | const struct ptinfo *ptinfo = &mmu.pgtables[i]; 62 | uintptr_t *pt = (uintptr_t *)cur, next_page; 63 | int index = indexof(addr, ptinfo); 64 | if (i == mmu.ptlevels) return &pt[index]; 65 | 66 | if (!(pt[index] & PTE_P)) { 67 | next_page = (uintptr_t)pgallocz(); 68 | pt[index] = next_page | PTE_P | flags; 69 | } else { 70 | next_page = baseof(pt[index]); 71 | } 72 | cur = next_page; 73 | } 74 | bug(); 75 | } 76 | 77 | static void teardown(int level, uintptr_t *pt) { 78 | if (level > mmu.ptlevels) return; 79 | for (int index = 0; index < (1 << mmu.pgtables[level].bits); index++) { 80 | if ((pt[index] & PTE_P) && (pt[index] & PTE_U)) { 81 | teardown(level + 1, (void *)baseof(pt[index])); 82 | } 83 | } 84 | if (level >= 1) { 85 | pgfree(pt); 86 | } 87 | } 88 | 89 | bool vme_init(void *(*_pgalloc)(int size), void (*_pgfree)(void *)) { 90 | panic_on(cpu_current() != 0, "init VME in non-bootstrap CPU"); 91 | pgalloc = _pgalloc; 92 | pgfree = _pgfree; 93 | 94 | #if __x86_64__ 95 | kpt = (void *)PML4_ADDR; 96 | #else 97 | AddrSpace as; 98 | as.ptr = NULL; 99 | for (int i = 0; i < LENGTH(vm_areas); i++) { 100 | const struct vm_area *vma = &vm_areas[i]; 101 | if (vma->kernel) { 102 | for (uintptr_t cur = (uintptr_t)vma->area.start; 103 | cur != (uintptr_t)vma->area.end; 104 | cur += mmu.pgsize) { 105 | *ptwalk(&as, cur, PTE_W) = cur | PTE_P | PTE_W; 106 | } 107 | } 108 | } 109 | kpt = (void *)baseof((uintptr_t)as.ptr); 110 | #endif 111 | 112 | set_cr3(kpt); 113 | set_cr0(get_cr0() | CR0_PG); 114 | return true; 115 | } 116 | 117 | void protect(AddrSpace *as) { 118 | uintptr_t *upt = pgallocz(); 119 | 120 | for (int i = 0; i < LENGTH(vm_areas); i++) { 121 | const struct vm_area *vma = &vm_areas[i]; 122 | if (vma->kernel) { 123 | const struct ptinfo *info = &mmu.pgtables[1]; // level-1 page table 124 | for (uintptr_t cur = (uintptr_t)vma->area.start; 125 | cur != (uintptr_t)vma->area.end; 126 | cur += (1L << info->shift)) { 127 | int index = indexof(cur, info); 128 | upt[index] = kpt[index]; 129 | } 130 | } 131 | } 132 | as->pgsize = mmu.pgsize; 133 | as->area = uvm_area; 134 | as->ptr = (void *)((uintptr_t)upt | PTE_P | PTE_U); 135 | } 136 | 137 | void unprotect(AddrSpace *as) { 138 | teardown(0, (void *)&as->ptr); 139 | } 140 | 141 | void map(AddrSpace *as, void *va, void *pa, int prot) { 142 | panic_on(!IN_RANGE(va, uvm_area), "mapping an invalid address"); 143 | panic_on((uintptr_t)va != ROUNDDOWN(va, mmu.pgsize) || 144 | (uintptr_t)pa != ROUNDDOWN(pa, mmu.pgsize), "non-page-boundary address"); 145 | 146 | uintptr_t *ptentry = ptwalk(as, (uintptr_t)va, PTE_W | PTE_U); 147 | if (prot == MMAP_NONE) { 148 | panic_on(!(*ptentry & PTE_P), "unmapping a non-mapped page"); 149 | *ptentry = 0; 150 | } else { 151 | panic_on(*ptentry & PTE_P, "remapping a mapped page"); 152 | uintptr_t pte = (uintptr_t)pa | PTE_P | PTE_U | ((prot & MMAP_WRITE) ? PTE_W : 0); 153 | *ptentry = pte; 154 | } 155 | ptwalk(as, (uintptr_t)va, PTE_W | PTE_U); 156 | } 157 | 158 | Context *ucontext(AddrSpace *as, Area kstack, void *entry) { 159 | Context *ctx = kstack.end - sizeof(Context); 160 | *ctx = (Context) { 0 }; 161 | 162 | #if __x86_64__ 163 | ctx->cs = USEL(SEG_UCODE); 164 | ctx->ss = USEL(SEG_UDATA); 165 | ctx->rip = (uintptr_t)entry; 166 | ctx->rflags = FL_IF; 167 | ctx->rsp = (uintptr_t)uvm_area.end; 168 | ctx->rsp0 = (uintptr_t)kstack.end; 169 | #else 170 | ctx->cs = USEL(SEG_UCODE); 171 | ctx->ds = USEL(SEG_UDATA); 172 | ctx->ss3 = USEL(SEG_UDATA); 173 | ctx->eip = (uintptr_t)entry; 174 | ctx->eflags = FL_IF; 175 | ctx->esp = (uintptr_t)uvm_area.end; 176 | ctx->esp0 = (uintptr_t)kstack.end; 177 | #endif 178 | ctx->cr3 = as->ptr; 179 | 180 | return ctx; 181 | } 182 | -------------------------------------------------------------------------------- /abstract-machine/am/src/x86/qemu/x86-qemu.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define PML4_ADDR 0x1000 4 | #define PDPT_ADDR 0x2000 5 | 6 | #define NR_SEG 6 // GDT size 7 | #define SEG_KCODE 1 // Kernel code 8 | #define SEG_KDATA 2 // Kernel data/stack 9 | #define SEG_UCODE 3 // User code 10 | #define SEG_UDATA 4 // User data/stack 11 | #define SEG_TSS 5 // Global unique task state segement 12 | 13 | #define NR_IRQ 256 // IDT size 14 | 15 | #ifndef __ASSEMBLER__ 16 | 17 | #include 18 | #include 19 | 20 | struct kernel_stack { 21 | uint8_t stack[8192]; 22 | }; 23 | 24 | static inline void *stack_top(struct kernel_stack *stk) { 25 | return stk->stack + sizeof(stk->stack); 26 | } 27 | 28 | struct mmu_config { 29 | int ptlevels, pgsize; 30 | struct ptinfo { 31 | const char *name; 32 | uintptr_t mask; 33 | int shift, bits; 34 | } pgtables[]; 35 | }; 36 | 37 | struct vm_area { 38 | Area area; 39 | int kernel; 40 | }; 41 | 42 | void __am_iret(Context *ctx); 43 | 44 | struct cpu_local { 45 | AddrSpace *uvm; 46 | #if __x86_64__ 47 | SegDesc gdt[NR_SEG + 1]; 48 | TSS64 tss; 49 | #else 50 | SegDesc gdt[NR_SEG]; 51 | TSS32 tss; 52 | #endif 53 | struct kernel_stack stack; 54 | }; 55 | 56 | #if __x86_64__ 57 | struct trap_frame { 58 | Context saved_context; 59 | uint64_t irq, errcode; 60 | uint64_t rip, cs, rflags, rsp, ss; 61 | }; 62 | #else 63 | struct trap_frame { 64 | Context saved_context; 65 | uint32_t irq, errcode; 66 | uint32_t eip, cs, eflags, esp, ss; 67 | }; 68 | #endif 69 | 70 | extern volatile uint32_t *__am_lapic; 71 | extern int __am_ncpu; 72 | extern struct cpu_local __am_cpuinfo[MAX_CPU]; 73 | 74 | #define CPU (&__am_cpuinfo[cpu_current()]) 75 | 76 | #define bug_on(cond) \ 77 | do { \ 78 | if (cond) panic("internal error (likely a bug in AM)"); \ 79 | } while (0) 80 | 81 | #define bug() bug_on(1) 82 | 83 | // apic utils 84 | void __am_lapic_eoi(); 85 | void __am_ioapic_init(); 86 | void __am_lapic_bootap(uint32_t cpu, void *address); 87 | void __am_ioapic_enable(int irq, int cpu); 88 | 89 | // x86-specific operations 90 | void __am_bootcpu_init(); 91 | void __am_percpu_init(); 92 | Area __am_heap_init(); 93 | void __am_lapic_init(); 94 | void __am_othercpu_entry(); 95 | void __am_percpu_initirq(); 96 | void __am_percpu_initgdt(); 97 | void __am_percpu_initlapic(); 98 | void __am_stop_the_world(); 99 | 100 | #endif 101 | -------------------------------------------------------------------------------- /abstract-machine/klib/Makefile: -------------------------------------------------------------------------------- 1 | NAME = klib 2 | SRCS = $(shell find src/ -name "*.c") 3 | include $(AM_HOME)/Makefile 4 | -------------------------------------------------------------------------------- /abstract-machine/klib/include/klib-macros.h: -------------------------------------------------------------------------------- 1 | #ifndef KLIB_MACROS_H__ 2 | #define KLIB_MACROS_H__ 3 | 4 | #define ROUNDUP(a, sz) ((((uintptr_t)a) + (sz) - 1) & ~((sz) - 1)) 5 | #define ROUNDDOWN(a, sz) ((((uintptr_t)a)) & ~((sz) - 1)) 6 | #define LENGTH(arr) (sizeof(arr) / sizeof((arr)[0])) 7 | #define RANGE(st, ed) (Area) { .start = (void *)(st), .end = (void *)(ed) } 8 | #define IN_RANGE(ptr, area) ((area).start <= (ptr) && (ptr) < (area).end) 9 | 10 | #define STRINGIFY(s) #s 11 | #define TOSTRING(s) STRINGIFY(s) 12 | #define _CONCAT(x, y) x ## y 13 | #define CONCAT(x, y) _CONCAT(x, y) 14 | 15 | #define putstr(s) \ 16 | ({ for (const char *p = s; *p; p++) putch(*p); }) 17 | 18 | #define io_read(reg) \ 19 | ({ reg##_T __io_param; \ 20 | ioe_read(reg, &__io_param); \ 21 | __io_param; }) 22 | 23 | #define io_write(reg, ...) \ 24 | ({ reg##_T __io_param = (reg##_T) { __VA_ARGS__ }; \ 25 | ioe_write(reg, &__io_param); }) 26 | 27 | #define static_assert(const_cond) \ 28 | static char CONCAT(_static_assert_, __LINE__) [(const_cond) ? 1 : -1] __attribute__((unused)) 29 | 30 | #define panic_on(cond, s) \ 31 | ({ if (cond) { \ 32 | putstr("AM Panic: "); putstr(s); \ 33 | putstr(" @ " __FILE__ ":" TOSTRING(__LINE__) " \n"); \ 34 | halt(1); \ 35 | } }) 36 | 37 | #define panic(s) panic_on(1, s) 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /abstract-machine/klib/include/klib.h: -------------------------------------------------------------------------------- 1 | #ifndef KLIB_H__ 2 | #define KLIB_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | // #define __NATIVE_USE_KLIB__ 13 | 14 | // string.h 15 | void *memset (void *s, int c, size_t n); 16 | void *memcpy (void *dst, const void *src, size_t n); 17 | void *memmove (void *dst, const void *src, size_t n); 18 | int memcmp (const void *s1, const void *s2, size_t n); 19 | size_t strlen (const char *s); 20 | char *strcat (char *dst, const char *src); 21 | char *strcpy (char *dst, const char *src); 22 | char *strncpy (char *dst, const char *src, size_t n); 23 | int strcmp (const char *s1, const char *s2); 24 | int strncmp (const char *s1, const char *s2, size_t n); 25 | 26 | // stdlib.h 27 | void srand (unsigned int seed); 28 | int rand (void); 29 | void *malloc (size_t size); 30 | void free (void *ptr); 31 | int abs (int x); 32 | int atoi (const char *nptr); 33 | 34 | // stdio.h 35 | int printf (const char *format, ...); 36 | int sprintf (char *str, const char *format, ...); 37 | int snprintf (char *str, size_t size, const char *format, ...); 38 | int vsprintf (char *str, const char *format, va_list ap); 39 | int vsnprintf (char *str, size_t size, const char *format, va_list ap); 40 | 41 | // assert.h 42 | #ifdef NDEBUG 43 | #define assert(ignore) ((void)0) 44 | #else 45 | #define assert(cond) \ 46 | do { \ 47 | if (!(cond)) { \ 48 | printf("Assertion fail at %s:%d\n", __FILE__, __LINE__); \ 49 | halt(1); \ 50 | } \ 51 | } while (0) 52 | #endif 53 | 54 | #ifdef __cplusplus 55 | } 56 | #endif 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /abstract-machine/klib/src/cpp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #ifndef __ISA_NATIVE__ 5 | 6 | void __dso_handle() { 7 | } 8 | 9 | void __cxa_guard_acquire() { 10 | } 11 | 12 | void __cxa_guard_release() { 13 | } 14 | 15 | void __cxa_atexit() { 16 | assert(0); 17 | } 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /abstract-machine/klib/src/stdio.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | #if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__) 8 | 9 | enum NUM_TYPE { DEC, HEX }; 10 | static const char num[] = { 11 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 12 | 'a', 'b', 'c', 'd', 'e', 'f' 13 | }; 14 | 15 | void putnum(enum NUM_TYPE type, unsigned int n) { 16 | int stack[20], tt = 0; 17 | int mod; 18 | 19 | switch (type) { 20 | case DEC: 21 | mod = 10; 22 | if ((int)n < 0) { 23 | putch('-'); 24 | n = -(int)n; 25 | } 26 | break; 27 | case HEX: 28 | mod = 16; 29 | putstr("0x"); 30 | break; 31 | default: 32 | panic("Number Type Error"); 33 | break; 34 | } 35 | 36 | while (n) { 37 | stack[ ++ tt] = n % mod; 38 | n /= mod; 39 | } 40 | while (tt) { 41 | putch(num[stack[tt -- ]]); 42 | } 43 | } 44 | 45 | int printf(const char *fmt, ...) { 46 | va_list ap; 47 | char cur_fmt; 48 | int d; 49 | char c, *s; 50 | uintptr_t p; 51 | 52 | va_start(ap, fmt); 53 | while (*fmt) { 54 | switch (cur_fmt = *fmt++) { 55 | case '%': 56 | panic_on(!(*fmt), "Format error"); 57 | switch (cur_fmt = *fmt++) { 58 | case 'c': 59 | c = (char)va_arg(ap, int); 60 | putch(c); 61 | break; 62 | case 'd': 63 | d = va_arg(ap, int); 64 | putnum(DEC, d); 65 | break; 66 | case 's': 67 | s = va_arg(ap, char *); 68 | putstr(s); 69 | break; 70 | case 'x': 71 | d = va_arg(ap, int); 72 | putnum(HEX, d); 73 | break; 74 | case 'p': 75 | p = va_arg(ap, uintptr_t); 76 | putnum(HEX, p); 77 | break; 78 | default: 79 | panic("No corresponding format\n"); 80 | break; 81 | } 82 | break; 83 | default: 84 | putch(cur_fmt); 85 | break; 86 | } 87 | } 88 | va_end(ap); 89 | 90 | return 0; 91 | } 92 | 93 | int vsprintf(char *out, const char *fmt, va_list ap) { 94 | panic("Not implemented"); 95 | } 96 | 97 | int sprintf(char *out, const char *fmt, ...) { 98 | panic("Not implemented"); 99 | } 100 | 101 | int snprintf(char *out, size_t n, const char *fmt, ...) { 102 | panic("Not implemented"); 103 | } 104 | 105 | int vsnprintf(char *out, size_t n, const char *fmt, va_list ap) { 106 | panic("Not implemented"); 107 | } 108 | 109 | #endif 110 | -------------------------------------------------------------------------------- /abstract-machine/klib/src/stdlib.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__) 6 | static unsigned long int next = 1; 7 | 8 | int rand(void) { 9 | // RAND_MAX assumed to be 32767 10 | next = next * 1103515245 + 12345; 11 | return (unsigned int)(next/65536) % 32768; 12 | } 13 | 14 | void srand(unsigned int seed) { 15 | next = seed; 16 | } 17 | 18 | int abs(int x) { 19 | return (x < 0 ? -x : x); 20 | } 21 | 22 | int atoi(const char* nptr) { 23 | int x = 0; 24 | while (*nptr == ' ') { nptr ++; } 25 | while (*nptr >= '0' && *nptr <= '9') { 26 | x = x * 10 + *nptr - '0'; 27 | nptr ++; 28 | } 29 | return x; 30 | } 31 | 32 | void *malloc(size_t size) { 33 | // On native, malloc() will be called during initializaion of C runtime. 34 | // Therefore do not call panic() here, else it will yield a dead recursion: 35 | // panic() -> putchar() -> (glibc) -> malloc() -> panic() 36 | #if !(defined(__ISA_NATIVE__) && defined(__NATIVE_USE_KLIB__)) 37 | panic("Not implemented"); 38 | #endif 39 | return NULL; 40 | } 41 | 42 | void free(void *ptr) { 43 | } 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /abstract-machine/klib/src/string.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__) 6 | 7 | size_t strlen(const char *s) { 8 | panic("Not implemented"); 9 | } 10 | 11 | char *strcpy(char *dst, const char *src) { 12 | panic("Not implemented"); 13 | } 14 | 15 | char *strncpy(char *dst, const char *src, size_t n) { 16 | panic("Not implemented"); 17 | } 18 | 19 | char *strcat(char *dst, const char *src) { 20 | panic("Not implemented"); 21 | } 22 | 23 | int strcmp(const char *s1, const char *s2) { 24 | panic("Not implemented"); 25 | } 26 | 27 | int strncmp(const char *s1, const char *s2, size_t n) { 28 | panic("Not implemented"); 29 | } 30 | 31 | void *memset(void *s, int c, size_t n) { 32 | if (s) { 33 | char *ps = (char *)s; 34 | while (n--) { 35 | *ps++ = c; 36 | } 37 | } 38 | 39 | return s; 40 | } 41 | 42 | void *memmove(void *dst, const void *src, size_t n) { 43 | panic("Not implemented"); 44 | } 45 | 46 | void *memcpy(void *out, const void *in, size_t n) { 47 | panic("Not implemented"); 48 | } 49 | 50 | int memcmp(const void *s1, const void *s2, size_t n) { 51 | panic("Not implemented"); 52 | } 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /abstract-machine/scripts/isa/x86.mk: -------------------------------------------------------------------------------- 1 | export CROSS_COMPILE := x86_64-linux-gnu- 2 | CFLAGS += -m32 -fno-pic -fno-omit-frame-pointer -march=i386 3 | CFLAGS += -fcf-protection=none # remove endbr32 in Ubuntu 20.04 with a CPU newer than Comet Lake 4 | ASFLAGS += -m32 -fno-pic 5 | LDFLAGS += -melf_i386 6 | -------------------------------------------------------------------------------- /abstract-machine/scripts/isa/x86_64.mk: -------------------------------------------------------------------------------- 1 | export CROSS_COMPILE := x86_64-linux-gnu- 2 | CFLAGS += -m64 -fPIC -mno-sse 3 | ASFLAGS += -m64 -fPIC 4 | LDFLAGS += -melf_x86_64 5 | -------------------------------------------------------------------------------- /abstract-machine/scripts/native.mk: -------------------------------------------------------------------------------- 1 | AM_SRCS := native/trm.c \ 2 | native/ioe.c \ 3 | native/cte.c \ 4 | native/trap.S \ 5 | native/vme.c \ 6 | native/mpe.c \ 7 | native/platform.c \ 8 | native/ioe/input.c \ 9 | native/ioe/timer.c \ 10 | native/ioe/gpu.c \ 11 | native/ioe/audio.c \ 12 | native/ioe/disk.c \ 13 | 14 | CFLAGS += -fpie 15 | ASFLAGS += -fpie -pie 16 | 17 | image: 18 | @echo + LD "->" $(IMAGE_REL) 19 | @g++ -pie -o $(IMAGE) -Wl,--whole-archive $(LINKAGE) -Wl,-no-whole-archive -lSDL2 -ldl 20 | 21 | run: image 22 | $(IMAGE) 23 | 24 | gdb: image 25 | gdb -ex "handle SIGUSR1 SIGUSR2 SIGSEGV noprint nostop" $(IMAGE) 26 | -------------------------------------------------------------------------------- /abstract-machine/scripts/platform/qemu.mk: -------------------------------------------------------------------------------- 1 | .PHONY: build-arg 2 | 3 | LDFLAGS += -N -Ttext-segment=0x00100000 4 | QEMU_FLAGS += -serial mon:stdio \ 5 | -machine accel=tcg \ 6 | -smp "$(smp)" \ 7 | -drive format=raw,file=$(IMAGE) 8 | 9 | build-arg: image 10 | @( echo -n $(mainargs); ) | dd if=/dev/stdin of=$(IMAGE) bs=512 count=2 seek=1 conv=notrunc status=none 11 | 12 | BOOT_HOME := $(AM_HOME)/am/src/x86/qemu/boot 13 | 14 | image: $(IMAGE).elf 15 | @$(MAKE) -s -C $(BOOT_HOME) 16 | @echo + CREATE "->" $(IMAGE_REL) 17 | @( cat $(BOOT_HOME)/bootblock.o; head -c 1024 /dev/zero; cat $(IMAGE).elf ) > $(IMAGE) 18 | -------------------------------------------------------------------------------- /abstract-machine/scripts/x86-qemu.mk: -------------------------------------------------------------------------------- 1 | include $(AM_HOME)/scripts/isa/x86.mk 2 | include $(AM_HOME)/scripts/platform/qemu.mk 3 | 4 | AM_SRCS := x86/qemu/start32.S \ 5 | x86/qemu/trap32.S \ 6 | x86/qemu/trm.c \ 7 | x86/qemu/cte.c \ 8 | x86/qemu/ioe.c \ 9 | x86/qemu/vme.c \ 10 | x86/qemu/mpe.c 11 | 12 | run: build-arg 13 | @qemu-system-i386 $(QEMU_FLAGS) 14 | -------------------------------------------------------------------------------- /abstract-machine/scripts/x86_64-qemu.mk: -------------------------------------------------------------------------------- 1 | include $(AM_HOME)/scripts/isa/x86_64.mk 2 | include $(AM_HOME)/scripts/platform/qemu.mk 3 | 4 | AM_SRCS := x86/qemu/start64.S \ 5 | x86/qemu/trap64.S \ 6 | x86/qemu/trm.c \ 7 | x86/qemu/cte.c \ 8 | x86/qemu/ioe.c \ 9 | x86/qemu/vme.c \ 10 | x86/qemu/mpe.c 11 | 12 | run: build-arg 13 | @qemu-system-x86_64 $(QEMU_FLAGS) 14 | -------------------------------------------------------------------------------- /amgame/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | -------------------------------------------------------------------------------- /amgame/Makefile: -------------------------------------------------------------------------------- 1 | NAME := amgame 2 | SRCS := $(shell find -L ./src/ -name "*.c") 3 | export MODULE := L0 4 | export AM_HOME := $(PWD)/../abstract-machine 5 | ifeq ($(ARCH),) 6 | export ARCH := x86_64-qemu 7 | endif 8 | 9 | include $(AM_HOME)/Makefile 10 | include ../Makefile.lab 11 | image: git 12 | -------------------------------------------------------------------------------- /amgame/compile_commands.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "arguments": [ 4 | "x86_64-linux-gnu-gcc", 5 | "-c", 6 | "-std=gnu11", 7 | "-O2", 8 | "-Wall", 9 | "-Werror", 10 | "-I/home/insorker/study/os-workbench-2022/amgame/include", 11 | "-I/home/insorker/study/os-workbench-2022/amgame/../abstract-machine/am/include/", 12 | "-I/home/insorker/study/os-workbench-2022/amgame/../abstract-machine/klib/include/", 13 | "-D__ISA__=\"x86_64\"", 14 | "-D__ISA_X86_64__", 15 | "-D__ARCH__=x86_64-qemu", 16 | "-D__ARCH_X86_64_QEMU", 17 | "-D__PLATFORM__=qemu", 18 | "-D__PLATFORM_QEMU", 19 | "-DARCH_H=\"arch/x86_64-qemu.h\"", 20 | "-fno-asynchronous-unwind-tables", 21 | "-fno-builtin", 22 | "-fno-stack-protector", 23 | "-Wno-main", 24 | "-U_FORTIFY_SOURCE", 25 | "-m64", 26 | "-fPIC", 27 | "-mno-sse", 28 | "-o", 29 | "/home/insorker/study/os-workbench-2022/amgame/build/x86_64-qemu/./src/game.o", 30 | "src/game.c" 31 | ], 32 | "directory": "/home/insorker/study/os-workbench-2022/amgame", 33 | "file": "src/game.c" 34 | } 35 | ] -------------------------------------------------------------------------------- /amgame/include/com.h: -------------------------------------------------------------------------------- 1 | #ifndef COM_H 2 | #define COM_H 3 | 4 | #define GRID_SIZE 10 5 | #define GRID_PADDING 1 6 | #define GRID_COLOR 0x000000 7 | #define SNAKE_SIZE (GRID_SIZE - GRID_PADDING * 2) 8 | #define SNAKE_COLOR 0xff0000 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /amgame/include/game.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | // void splash(); 8 | void get_key(Direction *dir); 9 | 10 | void draw_snake(Snake *sk); 11 | void draw_snake_move(Snake *sk, Direction dir, int *game_state); 12 | void draw_snake_clear(Snake *sk); 13 | -------------------------------------------------------------------------------- /amgame/include/snake.h: -------------------------------------------------------------------------------- 1 | #ifndef SNAKE_H 2 | #define SNAKE_H 3 | 4 | #define SNAKE_INIT_SIZE 3 5 | #define SNAKE_MAX_SIZE 10 6 | 7 | typedef enum { NONE=0, UP=-1, DOWN=1, LEFT=-1, RIGHT=1 } STEP; 8 | typedef struct Direction { 9 | STEP x, y; 10 | } Direction; 11 | typedef struct Position { 12 | int x, y; 13 | } Position; 14 | 15 | typedef struct SnakeBody { 16 | Direction dir; 17 | Position pos; 18 | } SnakeBody; 19 | 20 | typedef struct Snake { 21 | int size; 22 | Direction dir; 23 | SnakeBody body[SNAKE_MAX_SIZE + 1]; 24 | } Snake; 25 | 26 | void sk_init(Snake *sk); 27 | int sk_conflict(Snake *sk, Direction dir); 28 | void sk_move(Snake *sk); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /amgame/include/video.h: -------------------------------------------------------------------------------- 1 | #ifndef VIDEO_H 2 | #define VIDEO_H 3 | 4 | extern int w, h; 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /amgame/src/game.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define FPS 30 5 | static int game_state = 0; 6 | 7 | void init(Snake *sk, Direction *dir) { 8 | sk_init(sk); 9 | *dir = sk->dir; 10 | draw_snake(sk); 11 | } 12 | 13 | // Operating system is a C program! 14 | int main(const char *args) { 15 | ioe_init(); 16 | 17 | /* puts("mainargs = \""); */ 18 | /* puts(args); // make run mainargs=xxx */ 19 | /* puts("\"\n"); */ 20 | 21 | int next_frame = 0; 22 | int curr_frame = 0; 23 | Snake sk; 24 | Direction dir; 25 | 26 | init(&sk, &dir); 27 | 28 | while (1) { 29 | if (game_state != 0) { 30 | draw_snake_clear(&sk); 31 | game_state = 0; 32 | init(&sk, &dir); 33 | } 34 | 35 | while (curr_frame < next_frame) { 36 | get_key(&dir); 37 | curr_frame = io_read(AM_TIMER_UPTIME).us / (1000000 / FPS); 38 | } 39 | if (curr_frame % 15 == 0) { 40 | draw_snake_move(&sk, dir, &game_state); 41 | } 42 | 43 | next_frame += 1; 44 | } 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /amgame/src/keyboard.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define KEYNAME(key) \ 6 | [AM_KEY_##key] = #key, 7 | static const char *key_names[] = { 8 | AM_KEYS(KEYNAME) 9 | }; 10 | 11 | void get_key(Direction *dir) { 12 | AM_INPUT_KEYBRD_T event = { .keycode = AM_KEY_NONE }; 13 | ioe_read(AM_INPUT_KEYBRD, &event); 14 | if (event.keydown && event.keycode == AM_KEY_ESCAPE) halt(0); 15 | if (event.keydown && event.keycode != AM_KEY_NONE) { 16 | printf("Key pressed: "); 17 | switch (*key_names[event.keycode]) { 18 | case 'W': dir->x = NONE, dir->y = UP; break; 19 | case 'S': dir->x = NONE, dir->y = DOWN; break; 20 | case 'A': dir->x = LEFT, dir->y = NONE; break; 21 | case 'D': dir->x = RIGHT, dir->y = NONE; break; 22 | default: break; 23 | } 24 | printf(key_names[event.keycode]); 25 | printf("\n"); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /amgame/src/snake.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | static int w, h; 7 | 8 | static void init() { 9 | AM_GPU_CONFIG_T info = {0}; 10 | ioe_read(AM_GPU_CONFIG, &info); 11 | w = info.width; 12 | h = info.height; 13 | } 14 | 15 | void sk_init(Snake *sk) { 16 | init(); 17 | 18 | sk->size = SNAKE_INIT_SIZE; 19 | for (int i = 0; i < sk->size; i++) { 20 | sk->body[i].pos = (Position){ 0, i }; 21 | } 22 | sk->dir = (Direction){ NONE, DOWN }; 23 | } 24 | 25 | int sk_conflict(Snake *sk, Direction dir) { 26 | int id = sk->size - 1; 27 | int x = sk->body[id].pos.x + dir.x; 28 | int y = sk->body[id].pos.y + dir.y; 29 | 30 | // conflict with bound 31 | if (x < 0 || x * GRID_SIZE >= w - SNAKE_SIZE || 32 | y < 0 || y * GRID_SIZE >= h - SNAKE_SIZE) 33 | return 2; 34 | 35 | if (id == 0) return 0; 36 | 37 | // conflict with body 38 | if (x == sk->body[id - 1].pos.x && 39 | y == sk->body[id - 1].pos.y) 40 | return 1; 41 | return 0; 42 | } 43 | 44 | void sk_move(Snake *sk) { 45 | for (int i = 0; i < sk->size - 1; i++) { 46 | sk->body[i].pos.x = sk->body[i + 1].pos.x; 47 | sk->body[i].pos.y = sk->body[i + 1].pos.y; 48 | } 49 | sk->body[sk->size - 1].pos.x += sk->dir.x; 50 | sk->body[sk->size - 1].pos.y += sk->dir.y; 51 | } 52 | -------------------------------------------------------------------------------- /amgame/src/video.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | extern int state; 6 | 7 | static void draw_rect(int x, int y, int w, int h, uint32_t color) { 8 | uint32_t pixels[w * h]; // WARNING: large stack-allocated memory 9 | AM_GPU_FBDRAW_T event = { 10 | .x = x, .y = y, .w = w, .h = h, .sync = 1, 11 | .pixels = pixels, 12 | }; 13 | for (int i = 0; i < w * h; i++) { 14 | pixels[i] = color; 15 | } 16 | ioe_write(AM_GPU_FBDRAW, &event); 17 | } 18 | 19 | static void draw_snake_body(int x, int y, uint32_t color) { 20 | x = x * GRID_SIZE + GRID_PADDING, y = y * GRID_SIZE + GRID_PADDING; 21 | draw_rect(x, y, SNAKE_SIZE, SNAKE_SIZE, color); 22 | } 23 | 24 | void draw_snake(Snake *sk) { 25 | for (int i = 0; i < sk->size; i ++ ) { 26 | draw_snake_body( 27 | sk->body[i].pos.x, 28 | sk->body[i].pos.y, 29 | SNAKE_COLOR 30 | ); 31 | } 32 | } 33 | 34 | void draw_snake_move(Snake *sk, Direction dir, int *game_state) { 35 | switch (sk_conflict(sk, dir)) { 36 | case 1: 37 | // not change dir 38 | break; 39 | case 2: 40 | // game failed 41 | *game_state = 1; 42 | printf("You Failed\n"); 43 | return; 44 | default: 45 | sk->dir = dir; 46 | break; 47 | } 48 | draw_snake_body( 49 | sk->body[0].pos.x, 50 | sk->body[0].pos.y, 51 | GRID_COLOR 52 | ); 53 | sk_move(sk); 54 | draw_snake_body( 55 | sk->body[sk->size - 1].pos.x, 56 | sk->body[sk->size - 1].pos.y, 57 | SNAKE_COLOR 58 | ); 59 | } 60 | 61 | void draw_snake_clear(Snake *sk) { 62 | for (int i = 0; i < sk->size; i++) { 63 | draw_snake_body( 64 | sk->body[i].pos.x, 65 | sk->body[i].pos.y, 66 | GRID_COLOR 67 | ); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /amgame/tags: -------------------------------------------------------------------------------- 1 | !_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ 2 | !_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ 3 | !_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/ 4 | !_TAG_PROGRAM_NAME Exuberant Ctags // 5 | !_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/ 6 | !_TAG_PROGRAM_VERSION 5.9~svn20110310 // 7 | AM_HOME Makefile /^export AM_HOME := $(PWD)\/..\/abstract-machine$/;" m 8 | ARCH Makefile /^export ARCH := x86_64-qemu$/;" m 9 | COM_H include/com.h 2;" d 10 | DOWN include/snake.h /^typedef enum { NONE=0, UP=-1, DOWN=1, LEFT=-1, RIGHT=1 } STEP;$/;" e enum:__anon1 11 | Direction include/snake.h /^typedef struct Direction {$/;" s 12 | Direction include/snake.h /^} Direction;$/;" t typeref:struct:Direction 13 | GRID_COLOR include/com.h 6;" d 14 | GRID_PADDING include/com.h 5;" d 15 | GRID_SIZE include/com.h 4;" d 16 | KEYNAME src/keyboard.c 5;" d file: 17 | LEFT include/snake.h /^typedef enum { NONE=0, UP=-1, DOWN=1, LEFT=-1, RIGHT=1 } STEP;$/;" e enum:__anon1 18 | MODULE Makefile /^export MODULE := L0$/;" m 19 | NAME Makefile /^NAME := amgame$/;" m 20 | NONE include/snake.h /^typedef enum { NONE=0, UP=-1, DOWN=1, LEFT=-1, RIGHT=1 } STEP;$/;" e enum:__anon1 21 | Position include/snake.h /^typedef struct Position {$/;" s 22 | Position include/snake.h /^} Position;$/;" t typeref:struct:Position 23 | RIGHT include/snake.h /^typedef enum { NONE=0, UP=-1, DOWN=1, LEFT=-1, RIGHT=1 } STEP;$/;" e enum:__anon1 24 | SNAKE_COLOR include/com.h 8;" d 25 | SNAKE_H include/snake.h 2;" d 26 | SNAKE_INIT_SIZE include/snake.h 4;" d 27 | SNAKE_MAX_SIZE include/snake.h 5;" d 28 | SNAKE_SIZE include/com.h 7;" d 29 | SRCS Makefile /^SRCS := $(shell find -L .\/src\/ -name "*.c")$/;" m 30 | STEP include/snake.h /^typedef enum { NONE=0, UP=-1, DOWN=1, LEFT=-1, RIGHT=1 } STEP;$/;" t typeref:enum:__anon1 31 | Snake include/snake.h /^typedef struct Snake {$/;" s 32 | Snake include/snake.h /^} Snake;$/;" t typeref:struct:Snake 33 | SnakeBody include/snake.h /^typedef struct SnakeBody {$/;" s 34 | SnakeBody include/snake.h /^} SnakeBody;$/;" t typeref:struct:SnakeBody 35 | UP include/snake.h /^typedef enum { NONE=0, UP=-1, DOWN=1, LEFT=-1, RIGHT=1 } STEP;$/;" e enum:__anon1 36 | VIDEO_H include/video.h 2;" d 37 | body include/snake.h /^ SnakeBody body[SNAKE_MAX_SIZE + 1];$/;" m struct:Snake 38 | dir include/snake.h /^ Direction dir;$/;" m struct:SnakeBody 39 | draw_rect src/video.c /^static void draw_rect(int x, int y, int w, int h, uint32_t color) {$/;" f file: 40 | draw_snake src/video.c /^void draw_snake(Snake *sk) {$/;" f 41 | draw_snake_body src/video.c /^static void draw_snake_body(int x, int y, uint32_t color) {$/;" f file: 42 | draw_snake_move src/video.c /^void draw_snake_move(Snake *sk, Direction dir) {$/;" f 43 | get_key src/keyboard.c /^void get_key(Direction *dir) {$/;" f 44 | h src/snake.c /^static int w, h;$/;" v file: 45 | init src/snake.c /^static void init() {$/;" f file: 46 | key_names src/keyboard.c /^static const char *key_names[] = {$/;" v file: 47 | main src/game.c /^int main(const char *args) {$/;" f 48 | pos include/snake.h /^ Position pos;$/;" m struct:SnakeBody 49 | size include/snake.h /^ int size;$/;" m struct:Snake 50 | sk_conflict src/snake.c /^static int sk_conflict(Snake *sk, int id) {$/;" f file: 51 | sk_init src/snake.c /^void sk_init(Snake *sk) { $/;" f 52 | sk_move src/snake.c /^void sk_move(Snake *sk, Direction dir) {$/;" f 53 | w src/snake.c /^static int w, h;$/;" v file: 54 | x include/snake.h /^ STEP x, y;$/;" m struct:Direction 55 | x include/snake.h /^ int x, y;$/;" m struct:Position 56 | y include/snake.h /^ STEP x, y;$/;" m struct:Direction 57 | y include/snake.h /^ int x, y;$/;" m struct:Position 58 | -------------------------------------------------------------------------------- /crepl/Makefile: -------------------------------------------------------------------------------- 1 | NAME := $(shell basename $(PWD)) 2 | export MODULE := M4 3 | all: $(NAME)-64 $(NAME)-32 4 | LDFLAGS += -ldl 5 | 6 | include ../Makefile 7 | -------------------------------------------------------------------------------- /crepl/README.md: -------------------------------------------------------------------------------- 1 | # M4: C Real-Eval-Print-Loop (crepl) 2 | 3 | ## 1. 背景 4 | 5 | 大家一定很熟悉编程语言提供的交互式 [read-eval-print-loop](https://en.wikipedia.org/wiki/Read–eval–print_loop) (REPL),更俗一点的名字就是 “交互式的shell”。例如我们在课堂上展示的 Python Shell,可以快速帮助大家解决高等数学作业、高精度计算等烦恼: 6 | 7 | ![](../images/python-repl.svg) 8 | 9 | 现代程序设计语言通常都会提供交互式的模式,方便日常使用,包非解释型的程序设计语言也提供类似的设施,例如 Scala REPL、go-eval 等——当然也包括我们的 UNIX Shell! 10 | 11 | 在学习过动态链接和加载之后,你会预期 C 同样也可以实现 “交互式” 的 shell,支持即时定义函数,而且能计算 C 表达式的数值。如果你输入一行代码,比如`strlen("Hello World")`,这段代码会经历 gcc 编译、动态加载、调用执行,最终把代码执行得到的数值 `11` 打印到屏幕上。这就是本实验的内容。 12 | 13 | ## 2. 实验描述 14 | 15 | `crepl` - 逐行从 stdin 中输入,根据内容进行处理: 16 | 17 | - 如果输入的一行定义了一个函数,则把函数编译并加载到进程的地址空间中; 18 | - 如果输入是一个表达式,则把它的值输出。 19 | 20 | ### 总览 21 | 22 | crepl 23 | 24 | ### 描述 25 | 26 | 解释执行每一行标准输入中的 C “单行” 代码 (假设我们只使用 `int` 类型,即所有输入的表达式都是整数;定义函数的返回值也永远是整数),分如下两种情况: 27 | 28 | - **函数** 总是以 `int` 开头,例如 29 | 30 | ```c 31 | int fib(int n) { if (n <= 1) return 1; return fib(n - 1) + fib(n - 2); } 32 | ``` 33 | 34 | 函数接收若干 `int` 类型的参数,返回一个 `int` 数值。如果一行是一个函数,我们希望它将会经过 gcc 编译,并被加载到当前进程的地址空间中。函数可以引用之前定义过的函数。 35 | 36 | - 如果一行不是以 `int` 开头,我们认为这一行是一个 C 语言的 **表达式**,其类型为`int`,例如 37 | 38 | ```c 39 | 1 + 2 || (fib(3) * fib(4)) 40 | ``` 41 | 42 | **函数和表达式均可以调用之前定义过的函数**,但不允许访问全局的状态 (变量) 或调用标准 C 中的函数。如果一行既不是合法的函数 (例如调用了不允许调用的函数),也不是合法的表达式,`crepl` 可以不保证它们执行的结果 (不一定要报告错误,例如你的程序依然可以照常编译或执行,但你的程序要尽量不会 crash);重复定义重名函数你也可以当做 undefined behavior 不必做出过多处理——我们的测试用例中没有这样的情况。 43 | 44 | 以下是我们的参考实现,它调用了一些外挂程序在终端里实现了语法高亮。你完全没有做这件事情的必要——我们的环境里没有你需要的运行库,因此会导致你无情的 Compile Error 或 Wrong Answer。如果你使用外挂,一个更好的习惯 (也是编写软件常见的做法) 是在运行时检查外挂是否存在。如果存在则调用;如果不存在则直接输出没有外挂非高亮的版本。 45 | 46 | ![img](../images/crepl-demo.gif) 47 | 48 | 当然,和之前的实验一样,我们对大家只有最简的实验要求:你只要你为每一个函数或表达式输出一行即可,例如你可以把你的 crepl 实现成这样: 49 | 50 | ```bash 51 | $ ./crepl-64 52 | int gcd(int a, int b) { return b ? gcd(b, a % b) : a; } 53 | OK. 54 | gcd(256, 144) * gcd(56, 84) 55 | = 448. 56 | ``` 57 | 58 | 这个实验表明,编译和解释并没有明确的边界——在 OpenJDK 的实现中,即便是 “解释器” 也是编译的 (只是没有经过优化)。动态 (just-in-time) 技术在程序运行时 (而非程序执行前) 进行编译,并将编译得到的二进制代码 (指令/数据) 动态加载。其中最成功的案例之一是 Sun (现在是 Oracle) 的 Java 虚拟机 [HotSpot](https://wiki.openjdk.java.net/display/HotSpot/Main) (现在是OpenJDK的一部分),它使 Java 彻底摆脱了 “性能低下” 的诟病,也是引领 Web 热潮的核心后端技术。另一个最成功的案例是 JavaScript 的 [V8 引擎](https://v8.dev/)。借助 Webkit/v8,Chrome 成功地把微软公司的 Internet Explorer 拖下神坛,并且奠定了 Google 在互联网技术领域的霸主地位。 59 | 60 | ## 3. 正确性标准 61 | 62 | 你只要能正确解析单行的函数 (以 `int` 开头),并且默认其他输入都是表达式即可。我们可能会输入不合法的 C 代码 (例如不合法的表达式);你的程序应该给出错误提示而不应该 crash。你可以做出比较友好的假设——不像之前的实验,会为了 “强迫” 你掌握某些知识而使你疯狂 Wrong Answer。这个实验纯属放松,Online Judge 没有刁难你的测试用例,都和 demo 中的差不多。 63 | 64 | - 注意我们允许函数和表达式调用之前 (在 crepl 中) 定义过的函数; 65 | - 你可以假设我们输入的命令/表达式数量不超过 100 个; 66 | - 注意你处在的运行目录可能没有写入的权限。建议你将创建的临时文件都放在 `/tmp/` 目录下。建议使用 `mkstemp` family API 创建临时文件; 67 | - 主进程确实求出了所有表达式的值。 68 | - 禁止使用 C 标准库 system 和 popen。这稍稍增加了实验的难度,不过并没有增加多少。请把这个限制理解成强迫大家掌握操作系统知识的训练。 69 | 70 | > #### 禁止使用 system() 和 popen() 71 | > 72 | > 调用它们将会导致编译错误。好消息是这个实验我们不禁止 `exec`family 的系统调用:execl, execlp, execle, execv, execvp, execvpe 都是允许的。 73 | 74 | ## 4. 实验指南 75 | 76 | ### 4.1 解析读入的命令 77 | 78 | 框架代码里已经包含了读入命令的循环 (看起来像是一个小 shell),它打印出一个提示符,然后接受输入并解析: 79 | 80 | ```c 81 | int main(int argc, char *argv[]) { 82 | static char line[4096]; 83 | while (1) { 84 | printf("crepl> "); 85 | fflush(stdout); 86 | if (!fgets(line, sizeof(line), stdin)) { 87 | break; 88 | } 89 | printf("Got %zu chars.\n", strlen(line)); // WTF? 90 | } 91 | } 92 | ``` 93 | 94 | 当你在终端里按下 Ctrl-d,会结束 stdin 输入流,fgets 会得到 `NULL`。 95 | 96 | 这段代码里一个有趣的小细节是对 fflush 的调用:你会发现把它去掉对程序的运行并没有什么影响。但如果你在 fgets 之前插入一些延迟,例如 `sleep(1)`,你会发现 fgets 会 flush stdout 的缓冲区。但 C 标准并没有规定这个行为,glibc 只是因为大家用错得太多,为大家贴心地兜了——其实 System 领域这种 “事实行为” 并不少见,大家错得多了,我们的库函数、编译器等不得不做出防御性的行为容忍大家犯错。一个例子是某一时期本的 gcc 会非常激进地对能证明的 undefined behavior 进行优化,但却导致不少以前 “正确” 工作的代码的崩溃,到新版本里反而不再做这些激进的优化了。 97 | 98 | 回到实验,在上面的代码里,如果读入的字符串以 `int` 开头,你就可以假设是一个函数;否则就可以假设是一个表达式。 99 | 100 | ### 4.2 把函数编译成共享库 101 | 102 | 对于一个一行的函数,比如 103 | 104 | ```c 105 | int gcd(int a, int b) { return b ? gcd(b, a % b) : a; } 106 | ``` 107 | 108 | 如何把它编译成共享库?我们在课堂上讲解过编译成共享库 (shared object, so) 的代码,我们的 M2 (libco) 也实现了共享库。我们只需要把这个文件保存到临时文件里,例如 `a.c` 中,然后使用正确的选项调用 gcc 即可。 109 | 110 | > #### 选取合适的路径和文件名 111 | > 112 | > 如果你的工具在当前目录下创建文件,有可能会失败——例如,你可能在一个没有访问权限的工作目录上 (例如文件系统的根 `/`)。在 `/tmp` 中创建临时文件是更安全的做法。此外,glibc 还为我们提供了 `mkstemp` family API 调用,能够帮助我们生成名称唯一的临时文件。 113 | 114 | 除了编译和命名的问题,大家可能会感到困惑是,如果我的函数调用了其他函数怎么办? 115 | 116 | ```c 117 | int foo() { return bar() + baz(); } 118 | ``` 119 | 120 | 你不妨试着编译这个程序……它竟然可以被编译!所以忽略所有的 warnings 就好了!最后,为了巩固大家在上一个实验中学过的知识,我们限制你不能使用 libc 中的 system 和 popen——它们会让实验变得有些过于简单。 121 | 122 | ### 4.3 把表达式编译成共享库 123 | 124 | 把函数编译成共享库是常规操作——库函数主要就是为我们提供函数的。但表达式怎么办?又用到我们这门课里反复用的小技巧了:我们可以做一个 wrapper 呀!每当我们收到一个表达式,例如 `gcd(256, 144)` 的时候,我们都可以 “人工生成” 一段 C 代码 125 | 126 | ```c 127 | int __expr_wrapper_4() { 128 | return gcd(256, 144); 129 | } 130 | ``` 131 | 132 | 注意到函数名里的数字——我们通过加上数字为表达式生成不一样的名字。我们的表达式变成一个函数,我们就可以把它编译成共享库了。把动态库加载到地址空间并得到 `__expr_wrapper_4` 的地址,直接进行函数调用就能得到表达式的值了。 133 | 134 | ### 4.4 共享库的加载 135 | 136 | 我们可以使用 `dlopen` 加载共享库。我们已经为大家提供了 `-ldl` 的链接选项,大家可以阅读相关库函数的手册。另一个很不错的手册是 elf (5)。 137 | 138 | ![img](../images/rtfm.jpg) 139 | 140 | ### 4.5 试试自己用 mmap 加载? 141 | 142 | 参考 [loader-static](http://jyywiki.cn/pages/OS/2022/demos/loader-static.c),你也可以自己实现 dlopen。在这个实验里,我们的假设很简单,函数只访问局部变量,不涉及任何全局符号,因此只需要加载程序的代码即可——也就是说,你只需要把代码 mmap 到地址空间中,再解析符号找到入口地址,就可以不调用库函数实现加载了! -------------------------------------------------------------------------------- /crepl/crepl.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | static int wrapper_num; 9 | static char *wrapper_func[] = { 10 | "int ", "__expr_wrapper_", "(){return ", ";}\n", 11 | }; 12 | static char wrapper_filec[] = "/tmp/crepl_tmp.c"; 13 | static char wrapper_fileso[] = "/tmp/crepl_tmp.so"; 14 | static FILE *wrapper_fd; 15 | static char *const gcc_argv[] = { 16 | "gcc", 17 | "-fPIC", 18 | "-shared", 19 | wrapper_filec, 20 | "-o", 21 | wrapper_fileso, 22 | NULL 23 | }; 24 | 25 | void compile() { 26 | if (fork() == 0) { 27 | execvp("gcc", gcc_argv); 28 | perror("gcc error"); 29 | exit(-1); 30 | } 31 | wait(NULL); 32 | } 33 | 34 | int main(int argc, char *argv[]) { 35 | // empty the file 36 | wrapper_fd = fopen(wrapper_filec, "w"); 37 | fclose(wrapper_fd); 38 | 39 | static char line[4096]; 40 | void *handle; 41 | int (*wrapper)(); 42 | char wrapper_buf[100]; 43 | 44 | while (1) { 45 | printf("crepl> "); 46 | fflush(stdout); 47 | if (!fgets(line, sizeof(line), stdin)) { 48 | // read failed 49 | break; 50 | } 51 | 52 | int len = strlen(line); 53 | if (len >= 3 && !strncmp(line, "int", 3)) { 54 | // function define 55 | wrapper_fd = fopen(wrapper_filec, "a"); 56 | fprintf(wrapper_fd, "\n%s\n", line); 57 | fclose(wrapper_fd); 58 | } 59 | else { 60 | // expression 61 | wrapper_fd = fopen(wrapper_filec, "a"); 62 | fprintf(wrapper_fd, "%s%s%d%s%s%s", 63 | wrapper_func[0], wrapper_func[1], wrapper_num, wrapper_func[2], line, wrapper_func[3]); 64 | fclose(wrapper_fd); 65 | 66 | compile(); 67 | handle = dlopen(wrapper_fileso, RTLD_LAZY); 68 | if (!handle) { 69 | printf("handle error\n"); 70 | continue; 71 | } 72 | sprintf(wrapper_buf, "%s%d", wrapper_func[1], wrapper_num); 73 | wrapper = (int (*)()) dlsym(handle, wrapper_buf); 74 | if (!wrapper) { 75 | printf("wrapper error\n"); 76 | } 77 | else { 78 | printf("%d\n", wrapper()); 79 | } 80 | wrapper_num++; 81 | dlclose(handle); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /frecov/Makefile: -------------------------------------------------------------------------------- 1 | NAME := $(shell basename $(PWD)) 2 | export MODULE := M5 3 | all: $(NAME)-64 $(NAME)-32 4 | LDFLAGS += -lm 5 | 6 | include ../Makefile 7 | -------------------------------------------------------------------------------- /frecov/frecov.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | typedef uint8_t u8; 11 | typedef uint16_t u16; 12 | typedef uint32_t u32; 13 | 14 | // Copied from the manual 15 | struct fat32hdr { 16 | u8 BS_jmpBoot[3]; 17 | u8 BS_OEMName[8]; 18 | u16 BPB_BytsPerSec; 19 | u8 BPB_SecPerClus; 20 | u16 BPB_RsvdSecCnt; 21 | u8 BPB_NumFATs; 22 | u16 BPB_RootEntCnt; 23 | u16 BPB_TotSec16; 24 | u8 BPB_Media; 25 | u16 BPB_FATSz16; 26 | u16 BPB_SecPerTrk; 27 | u16 BPB_NumHeads; 28 | u32 BPB_HiddSec; 29 | u32 BPB_TotSec32; 30 | u32 BPB_FATSz32; 31 | u16 BPB_ExtFlags; 32 | u16 BPB_FSVer; 33 | u32 BPB_RootClus; 34 | u16 BPB_FSInfo; 35 | u16 BPB_BkBootSec; 36 | u8 BPB_Reserved[12]; 37 | u8 BS_DrvNum; 38 | u8 BS_Reserved1; 39 | u8 BS_BootSig; 40 | u32 BS_VolID; 41 | u8 BS_VolLab[11]; 42 | u8 BS_FilSysType[8]; 43 | u8 __padding_1[420]; 44 | u16 Signature_word; 45 | } __attribute__((packed)); 46 | 47 | 48 | void *map_disk(const char *fname); 49 | 50 | int main(int argc, char *argv[]) { 51 | if (argc < 2) { 52 | fprintf(stderr, "Usage: %s fs-image\n", argv[0]); 53 | exit(1); 54 | } 55 | 56 | setbuf(stdout, NULL); 57 | 58 | assert(sizeof(struct fat32hdr) == 512); // defensive 59 | 60 | // map disk image to memory 61 | struct fat32hdr *hdr = map_disk(argv[1]); 62 | 63 | // TODO: frecov 64 | 65 | // file system traversal 66 | munmap(hdr, hdr->BPB_TotSec32 * hdr->BPB_BytsPerSec); 67 | } 68 | 69 | void *map_disk(const char *fname) { 70 | int fd = open(fname, O_RDWR); 71 | 72 | if (fd < 0) { 73 | perror(fname); 74 | goto release; 75 | } 76 | 77 | off_t size = lseek(fd, 0, SEEK_END); 78 | if (size == -1) { 79 | perror(fname); 80 | goto release; 81 | } 82 | 83 | struct fat32hdr *hdr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 84 | if (hdr == (void *)-1) { 85 | goto release; 86 | } 87 | 88 | close(fd); 89 | 90 | if (hdr->Signature_word != 0xaa55 || 91 | hdr->BPB_TotSec32 * hdr->BPB_BytsPerSec != size) { 92 | fprintf(stderr, "%s: Not a FAT file image\n", fname); 93 | goto release; 94 | } 95 | return hdr; 96 | 97 | release: 98 | if (fd > 0) { 99 | close(fd); 100 | } 101 | exit(1); 102 | } 103 | -------------------------------------------------------------------------------- /images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/images/1.png -------------------------------------------------------------------------------- /images/3DhTVVP9avTrH.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/images/3DhTVVP9avTrH.jpg -------------------------------------------------------------------------------- /images/chenguanxi.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/images/chenguanxi.jpg -------------------------------------------------------------------------------- /images/crepl-demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/images/crepl-demo.gif -------------------------------------------------------------------------------- /images/fat-filename.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/images/fat-filename.png -------------------------------------------------------------------------------- /images/fork状态图1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/images/fork状态图1.PNG -------------------------------------------------------------------------------- /images/fork状态图2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/images/fork状态图2.PNG -------------------------------------------------------------------------------- /images/frecov-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/images/frecov-example.png -------------------------------------------------------------------------------- /images/frecov实验结果.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/images/frecov实验结果.png -------------------------------------------------------------------------------- /images/git-fire.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/images/git-fire.png -------------------------------------------------------------------------------- /images/hog-cell-gradients.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/images/hog-cell-gradients.png -------------------------------------------------------------------------------- /images/network-trace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/images/network-trace.png -------------------------------------------------------------------------------- /images/rtfm.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/images/rtfm.jpg -------------------------------------------------------------------------------- /images/sperf-demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/images/sperf-demo.gif -------------------------------------------------------------------------------- /images/sperf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/images/sperf.jpg -------------------------------------------------------------------------------- /images/图形化布局.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/images/图形化布局.PNG -------------------------------------------------------------------------------- /images/实验结果.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/images/实验结果.PNG -------------------------------------------------------------------------------- /kernel/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | -------------------------------------------------------------------------------- /kernel/Makefile: -------------------------------------------------------------------------------- 1 | NAME := kernel 2 | SRCS := framework/main.c $(shell find -L ./src/ -name "*.c") 3 | INC_PATH := include/ framework/ 4 | 5 | export AM_HOME := $(PWD)/../abstract-machine 6 | ifeq ($(ARCH),) 7 | export ARCH := x86_64-qemu 8 | endif 9 | 10 | include $(AM_HOME)/Makefile 11 | include ../Makefile.lab 12 | image: git 13 | 14 | test: git 15 | @gcc $(shell find src/ -name "*.c" | grep -v "dev" | grep -v "kmt") \ 16 | $(shell find test/ -name "*.c") \ 17 | -Iframework -Itest -DTEST -lpthread \ 18 | -o build/test 19 | @build/test 20 | -------------------------------------------------------------------------------- /kernel/compile_commands.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /kernel/framework/kernel.h: -------------------------------------------------------------------------------- 1 | #include 2 | #ifdef TEST 3 | #include 4 | #endif 5 | 6 | #define MODULE(mod) \ 7 | typedef struct mod_##mod##_t mod_##mod##_t; \ 8 | extern mod_##mod##_t *mod; \ 9 | struct mod_##mod##_t 10 | 11 | #define MODULE_DEF(mod) \ 12 | extern mod_##mod##_t __##mod##_obj; \ 13 | mod_##mod##_t *mod = &__##mod##_obj; \ 14 | mod_##mod##_t __##mod##_obj 15 | 16 | typedef Context *(*handler_t)(Event, Context *); 17 | MODULE(os) { 18 | void (*init)(); 19 | void (*run)(); 20 | Context *(*trap)(Event ev, Context *context); 21 | void (*on_irq)(int seq, int event, handler_t handler); 22 | }; 23 | 24 | MODULE(pmm) { 25 | void (*init)(); 26 | void *(*alloc)(size_t size); 27 | void (*free)(void *ptr); 28 | }; 29 | 30 | typedef struct task task_t; 31 | typedef struct spinlock spinlock_t; 32 | typedef struct semaphore sem_t; 33 | MODULE(kmt) { 34 | void (*init)(); 35 | int (*create)(task_t *task, const char *name, void (*entry)(void *arg), void *arg); 36 | void (*teardown)(task_t *task); 37 | void (*spin_init)(spinlock_t *lk, const char *name); 38 | void (*spin_lock)(spinlock_t *lk); 39 | void (*spin_unlock)(spinlock_t *lk); 40 | void (*sem_init)(sem_t *sem, const char *name, int value); 41 | void (*sem_wait)(sem_t *sem); 42 | void (*sem_signal)(sem_t *sem); 43 | }; 44 | 45 | typedef struct device device_t; 46 | MODULE(dev) { 47 | void (*init)(); 48 | device_t *(*lookup)(const char *name); 49 | }; 50 | -------------------------------------------------------------------------------- /kernel/framework/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | ioe_init(); 6 | os->init(); 7 | /* cte_init(os->trap); */ 8 | mpe_init(os->run); 9 | return 1; 10 | } 11 | -------------------------------------------------------------------------------- /kernel/include/common.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | -------------------------------------------------------------------------------- /kernel/include/devices.h: -------------------------------------------------------------------------------- 1 | typedef struct devops { 2 | int (*init)(device_t *dev); 3 | int (*read) (device_t *dev, int offset, void *buf, int count); 4 | int (*write)(device_t *dev, int offset, const void *buf, int count); 5 | } devops_t; 6 | extern devops_t tty_ops, fb_ops, sd_ops, input_ops; 7 | 8 | struct device { 9 | const char *name; 10 | int id; 11 | void *ptr; 12 | devops_t *ops; 13 | }; 14 | 15 | // Input 16 | // ------------------------------------------------------------------- 17 | 18 | struct input_event { 19 | uint32_t ctrl: 1, alt: 1; 20 | uint32_t data: 16; 21 | }; 22 | 23 | typedef struct { 24 | spinlock_t lock; 25 | sem_t event_sem; 26 | struct input_event *events; 27 | int front, rear; 28 | int capslock, shift_down[2], ctrl_down[2], alt_down[2]; 29 | } input_t; 30 | 31 | // ------------------------------------------------------------------- 32 | 33 | // Sprite-based virtual graphic accelerator 34 | // +--------------+---------------------------------+------------- 35 | // | Info (256B) | textures (65535 x 256B = 16M) | sprites 36 | // +--------------+---------------------------------+------------- 37 | // | | ^ | 38 | // | v 0x1000000 | 39 | // | +---+ | 40 | // | | | 8 x 8 x 32bit (ARRGGBB) tiles | 41 | // v +---+ v 42 | // struct display_info set of {#texture, x, y, z, #display} 43 | // ------------------------------------------------------------------- 44 | 45 | #define TEXTURE_W 8 46 | #define TEXTURE_H 8 47 | #define SPRITE_BRK 0x1000000 48 | 49 | struct display_info { 50 | uint32_t width, height; 51 | uint32_t num_displays; 52 | uint32_t current; 53 | uint32_t num_textures, num_sprites; 54 | }; 55 | 56 | struct texture { 57 | uint32_t pixels[TEXTURE_W * TEXTURE_H]; 58 | }; 59 | 60 | struct sprite { 61 | uint16_t texture, x, y; 62 | unsigned int display: 4; 63 | unsigned int z: 12; 64 | } __attribute__((packed)); 65 | 66 | typedef struct { 67 | struct display_info *info; 68 | struct texture *textures; 69 | struct sprite *sprites; 70 | } fb_t; 71 | 72 | // ------------------------------------------------------------------- 73 | // Virtual console on fb 74 | 75 | struct character { 76 | uint32_t metadata; 77 | unsigned char ch; 78 | }; 79 | 80 | struct tty_queue { 81 | char *buf, *end, *front, *rear; 82 | }; 83 | 84 | typedef struct { 85 | sem_t lock, cooked; 86 | device_t *fbdev; int display; 87 | int lines, columns, size; 88 | struct character *buf, *end, *cursor; 89 | struct tty_queue queue; 90 | uint8_t *dirty; 91 | struct sprite *sp_buf; 92 | } tty_t; 93 | 94 | // ------------------------------------------------------------------- 95 | // SCSI (Standard) Disk 96 | 97 | typedef struct { 98 | uint32_t blkcnt, blksz; 99 | uint8_t *buf; 100 | } sd_t; 101 | -------------------------------------------------------------------------------- /kernel/include/os.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct task { 4 | // TODO 5 | }; 6 | 7 | struct spinlock { 8 | // TODO 9 | }; 10 | 11 | struct semaphore { 12 | // TODO 13 | }; 14 | -------------------------------------------------------------------------------- /kernel/src/dev/dev.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define DEVICES(_) \ 5 | _(0, input_t, "input", 1, &input_ops) \ 6 | _(1, fb_t, "fb", 1, &fb_ops) \ 7 | _(2, tty_t, "tty1", 1, &tty_ops) \ 8 | _(3, tty_t, "tty2", 2, &tty_ops) \ 9 | _(4, sd_t, "sda", 1, &sd_ops) \ 10 | 11 | #define DEV_CNT(...) + 1 12 | device_t *devices[0 DEVICES(DEV_CNT)]; 13 | 14 | static device_t *dev_lookup(const char *name) { 15 | for (int i = 0; i < LENGTH(devices); i++) 16 | if (strcmp(devices[i]->name, name) == 0) 17 | return devices[i]; 18 | panic("lookup device failed."); 19 | return NULL; 20 | } 21 | 22 | static device_t *dev_create(int size, const char* name, int id, devops_t *ops) { 23 | device_t *dev = pmm->alloc(sizeof(device_t)); 24 | *dev = (device_t) { 25 | .name = name, 26 | .ptr = pmm->alloc(size), 27 | .id = id, 28 | .ops = ops, 29 | }; 30 | return dev; 31 | } 32 | 33 | void dev_input_task(); 34 | void dev_tty_task(); 35 | 36 | static void dev_init() { 37 | #define INIT(id, device_type, dev_name, dev_id, dev_ops) \ 38 | devices[id] = dev_create(sizeof(device_type), dev_name, dev_id, dev_ops); \ 39 | devices[id]->ops->init(devices[id]); 40 | 41 | DEVICES(INIT); 42 | 43 | kmt->create(pmm->alloc(sizeof(task_t)), "input-task", dev_input_task, NULL); 44 | kmt->create(pmm->alloc(sizeof(task_t)), "tty-task", dev_tty_task, NULL); 45 | } 46 | 47 | MODULE_DEF(dev) = { 48 | .init = dev_init, 49 | .lookup = dev_lookup, 50 | }; 51 | -------------------------------------------------------------------------------- /kernel/src/dev/dev_sd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static int sd_init(device_t *dev) { 5 | sd_t *sd = dev->ptr; 6 | if (!io_read(AM_DISK_CONFIG).present) { 7 | dev->ptr = NULL; 8 | } else { 9 | sd->blkcnt = io_read(AM_DISK_CONFIG).blkcnt; 10 | sd->blksz = io_read(AM_DISK_CONFIG).blksz; 11 | sd->buf = pmm->alloc(sd->blksz); 12 | } 13 | return 0; 14 | } 15 | 16 | static void blk_read(void *buf, int blkno, int blkcnt) { 17 | io_write(AM_DISK_BLKIO, false, buf, blkno, blkcnt); 18 | while (!io_read(AM_DISK_STATUS).ready) ; 19 | } 20 | 21 | static void blk_write(void *buf, int blkno, int blkcnt) { 22 | io_write(AM_DISK_BLKIO, true, buf, blkno, blkcnt); 23 | while (!io_read(AM_DISK_STATUS).ready) ; 24 | } 25 | 26 | static int sd_read(device_t *dev, int offset, void *buf, int count) { 27 | sd_t *sd = dev->ptr; 28 | panic_on(!sd, "no disk"); 29 | uint32_t pos = 0; 30 | for (uint32_t st = ROUNDDOWN(offset, sd->blksz); pos < count; st = offset) { 31 | uint32_t n = sd->blksz - (offset - st); 32 | if (n > count - pos) n = count - pos; 33 | blk_read(sd->buf, st / sd->blksz, 1); 34 | memcpy((char *)buf + pos, sd->buf + offset - st, n); 35 | pos += n; 36 | offset = st + sd->blksz; 37 | } 38 | return pos; 39 | } 40 | 41 | static int sd_write(device_t *dev, int offset, const void *buf, int count) { 42 | sd_t *sd = dev->ptr; 43 | panic_on(!sd, "no disk"); 44 | uint32_t pos = 0; 45 | for (uint32_t st = ROUNDDOWN(offset, sd->blksz); pos < count; st = offset) { 46 | uint32_t n = sd->blksz - (offset - st); 47 | if (n > count - pos) n = count - pos; 48 | if (n < sd->blksz) { 49 | blk_read(sd->buf, st / sd->blksz, 1); 50 | } 51 | memcpy(sd->buf + offset - st, (char *)buf + pos, n); 52 | blk_write(sd->buf, st / sd->blksz, 1); 53 | pos += n; 54 | offset = st + sd->blksz; 55 | } 56 | return pos; 57 | } 58 | 59 | devops_t sd_ops = { 60 | .init = sd_init, 61 | .read = sd_read, 62 | .write = sd_write, 63 | }; 64 | -------------------------------------------------------------------------------- /kernel/src/kmt.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | MODULE_DEF(kmt) = { 4 | // TODO 5 | }; 6 | -------------------------------------------------------------------------------- /kernel/src/os.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define TEST_PMM 1 4 | #if TEST_PMM 5 | #define alloc(sz) pmm->alloc(sz) 6 | #define free(addr) pmm->free(addr) 7 | void alloc_and_free() { 8 | void *a; 9 | a = alloc(1); free(a); 10 | a = alloc(128); free(a); 11 | a = alloc(4096); free(a); 12 | a = alloc(1 << 16); free(a); 13 | a = alloc(1 << 17); free(a); 14 | } 15 | void alloc_continuous(int sz) { 16 | void *a[100]; 17 | for (int i = 0; i < 100; i++) { a[i] = alloc(sz); } 18 | for (int i = 0; i < 100; i++) { free(a[i]); } 19 | } 20 | void alloc_too_many(int sz) { 21 | void *a[1 << 13]; 22 | for (int i = 0; i < 1 << 13; i++) { a[i] = alloc(sz); } 23 | for (int i = 0; i < 1 << 13; i++) { free(a[i]); } 24 | } 25 | void pmm_test() { 26 | // 1 27 | /* alloc_and_free(); */ 28 | // 2 29 | /* alloc_continuous(1); */ 30 | /* alloc_continuous(1); */ 31 | /* alloc_continuous(17); */ 32 | // 3 33 | /* alloc_too_many(1); */ 34 | } 35 | #endif 36 | 37 | static void os_init() { 38 | pmm->init(); 39 | } 40 | 41 | static void os_run() { 42 | #if TEST_PMM 43 | pmm_test(); 44 | #endif 45 | for (const char *s = "Hello World from CPU #*\n"; *s; s++) { 46 | putch(*s == '*' ? '0' + cpu_current() : *s); 47 | } 48 | while (1) ; 49 | } 50 | 51 | MODULE_DEF(os) = { 52 | .init = os_init, 53 | .run = os_run, 54 | }; 55 | -------------------------------------------------------------------------------- /kernel/test/am.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lxmwust/os-workbench/8adb316635344ab30d0ccdb066f46a1452bf965c/kernel/test/am.h -------------------------------------------------------------------------------- /kernel/test/common.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #define ROUNDUP(a, sz) ((((uintptr_t)a) + (sz) - 1) & ~((sz) - 1)) 5 | 6 | typedef struct { 7 | void *start, *end; 8 | } Area; 9 | Area heap; 10 | -------------------------------------------------------------------------------- /kernel/test/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static void entry(int tid) { 6 | void *addr = pmm->alloc(1 << 18); 7 | pmm->free(addr); 8 | addr = pmm->alloc(1 << 17); 9 | pmm->free(addr); 10 | /* addr = pmm->alloc(128); */ 11 | /* void *addr16 = pmm->alloc(16); */ 12 | /* pmm->free(addr); */ 13 | /* pmm->free(addr16); */ 14 | } 15 | static void finish() { printf("End\n"); } 16 | 17 | int main() { 18 | pmm->init(); 19 | for (int i = 0; i < 1; i++) { 20 | create(entry); 21 | } 22 | 23 | join(finish); 24 | } 25 | -------------------------------------------------------------------------------- /kernel/test/thread.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define NTHREAD 64 10 | enum { T_FREE = 0, T_LIVE, T_DEAD, }; 11 | struct thread { 12 | int id, status; 13 | pthread_t thread; 14 | void (*entry)(int); 15 | }; 16 | 17 | struct thread tpool[NTHREAD], *tptr = tpool; 18 | 19 | void *wrapper(void *arg) { 20 | struct thread *thread = (struct thread *)arg; 21 | thread->entry(thread->id); 22 | return NULL; 23 | } 24 | 25 | void create(void *fn) { 26 | assert(tptr - tpool < NTHREAD); 27 | *tptr = (struct thread) { 28 | .id = tptr - tpool + 1, 29 | .status = T_LIVE, 30 | .entry = fn, 31 | }; 32 | pthread_create(&(tptr->thread), NULL, wrapper, tptr); 33 | ++tptr; 34 | } 35 | 36 | void join() { 37 | for (int i = 0; i < NTHREAD; i++) { 38 | struct thread *t = &tpool[i]; 39 | if (t->status == T_LIVE) { 40 | pthread_join(t->thread, NULL); 41 | t->status = T_DEAD; 42 | } 43 | } 44 | } 45 | 46 | __attribute__((destructor)) void cleanup() { 47 | join(); 48 | } 49 | -------------------------------------------------------------------------------- /libco/Makefile: -------------------------------------------------------------------------------- 1 | NAME := $(shell basename $(PWD)) 2 | export MODULE := M2 3 | all: $(NAME)-64.so $(NAME)-32.so 4 | CFLAGS += -U_FORTIFY_SOURCE 5 | 6 | include ../Makefile 7 | -------------------------------------------------------------------------------- /libco/co.c: -------------------------------------------------------------------------------- 1 | #include "co.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | struct co *current; 11 | 12 | enum co_status { 13 | CO_NEW = 1, // 新创建,还未执行过 14 | CO_RUNNING, // 已经执行过 15 | CO_WAITING, // 在 co_wait 上等待 16 | CO_DEAD, // 已经结束,但还未释放资源 17 | }; 18 | 19 | #define K 1024 20 | #define STACK_SIZE (64 * K) 21 | 22 | struct co { 23 | const char *name; 24 | void (*func)(void *); // co_start 指定的入口地址和参数 25 | void *arg; 26 | 27 | enum co_status status; // 协程的状态 28 | struct co *waiter; // 是否有其他协程在等待当前协程 29 | jmp_buf context; // 寄存器现场 (setjmp.h) 30 | unsigned char stack[STACK_SIZE]; // 协程的堆栈 31 | }; 32 | 33 | typedef struct CONODE { 34 | struct co *coroutine; 35 | 36 | struct CONODE *fd, *bk; 37 | } CoNode; 38 | 39 | static CoNode *co_node = NULL; 40 | /* 41 | * 如果co_node == NULL,则创建一个新的双向循环链表即可,并返回 42 | * 如果co_node != NULL, 则在co_node和co_node->fd之间插入,仍然返回co_node的值 43 | */ 44 | static void co_node_insert(struct co *coroutine) { 45 | CoNode *victim = (CoNode *)malloc(sizeof(CoNode)); 46 | assert(victim); 47 | 48 | victim->coroutine = coroutine; 49 | if (co_node == NULL) { 50 | victim->fd = victim->bk = victim; 51 | co_node = victim; 52 | } else { 53 | victim->fd = co_node->fd; 54 | victim->bk = co_node; 55 | victim->fd->bk = victim->bk->fd = victim; 56 | } 57 | } 58 | 59 | /* 60 | * 如果当前只剩node一个,则返回该一个 61 | * 否则,拉取当前co_node对应的协程,并沿着bk方向移动 62 | */ 63 | static CoNode *co_node_remove() { 64 | CoNode *victim = NULL; 65 | 66 | if (co_node == NULL) { 67 | return NULL; 68 | } else if (co_node->bk == co_node) { 69 | victim = co_node; 70 | co_node = NULL; 71 | } else { 72 | victim = co_node; 73 | 74 | co_node = co_node->bk; 75 | co_node->fd = victim->fd; 76 | co_node->fd->bk = co_node; 77 | } 78 | 79 | return victim; 80 | } 81 | 82 | struct co *co_start(const char *name, void (*func)(void *), void *arg) { 83 | struct co *coroutine = (struct co *)malloc(sizeof(struct co)); 84 | assert(coroutine); 85 | 86 | coroutine->name = name; 87 | coroutine->func = func; 88 | coroutine->arg = arg; 89 | coroutine->status = CO_NEW; 90 | coroutine->waiter = NULL; 91 | 92 | co_node_insert(coroutine); 93 | return coroutine; 94 | } 95 | 96 | void co_wait(struct co *coroutine) { 97 | assert(coroutine); 98 | 99 | if (coroutine->status != CO_DEAD) { 100 | coroutine->waiter = current; 101 | current->status = CO_WAITING; 102 | co_yield (); 103 | } 104 | 105 | /* 106 | * 释放coroutine对应的CoNode 107 | */ 108 | while (co_node->coroutine != coroutine) { 109 | co_node = co_node->bk; 110 | } 111 | 112 | assert(co_node->coroutine == coroutine); 113 | 114 | free(coroutine); 115 | free(co_node_remove()); 116 | } 117 | 118 | /* 119 | * 切换栈,即让选中协程的所有堆栈信息在自己的堆栈中,而非调用者的堆栈。保存调用者需要保存的寄存器,并调用指定的函数 120 | */ 121 | static inline void stack_switch_call(void *sp, void *entry, void *arg) { 122 | asm volatile( 123 | #if __x86_64__ 124 | "movq %%rcx, 0(%0); movq %0, %%rsp; movq %2, %%rdi; call *%1" 125 | : 126 | : "b"((uintptr_t)sp - 16), "d"((uintptr_t)entry), "a"((uintptr_t)arg) 127 | #else 128 | "movl %%ecx, 4(%0); movl %0, %%esp; movl %2, 0(%0); call *%1" 129 | : 130 | : "b"((uintptr_t)sp - 8), "d"((uintptr_t)entry), "a"((uintptr_t)arg) 131 | #endif 132 | ); 133 | } 134 | /* 135 | * 从调用的指定函数返回,并恢复相关的寄存器。此时协程执行结束,以后再也不会执行该协程的上下文。这里需要注意的是,其和上面并不是对称的,因为调用协程给了新创建的选中协程的堆栈,则选中协程以后就在自己的堆栈上执行,永远不会返回到调用协程的堆栈。 136 | */ 137 | static inline void restore_return() { 138 | asm volatile( 139 | #if __x86_64__ 140 | "movq 0(%%rsp), %%rcx" 141 | : 142 | : 143 | #else 144 | "movl 4(%%esp), %%ecx" 145 | : 146 | : 147 | #endif 148 | ); 149 | } 150 | 151 | #define __LONG_JUMP_STATUS (1) 152 | void co_yield () { 153 | int status = setjmp(current->context); 154 | if (!status) { 155 | //此时开始查找待选中的进程,因为co_node应该指向的就是current对应的节点,因此首先向下移动一个,使当前线程优先级最低 156 | co_node = co_node->bk; 157 | while (!((current = co_node->coroutine)->status == CO_NEW || current->status == CO_RUNNING)) { 158 | co_node = co_node->bk; 159 | } 160 | 161 | assert(current); 162 | 163 | if (current->status == CO_RUNNING) { 164 | longjmp(current->context, __LONG_JUMP_STATUS); 165 | } else { 166 | ((struct co volatile *)current)->status = CO_RUNNING; //这里如果直接赋值,编译器会和后面的覆写进行优化 167 | 168 | // 栈由高地址向低地址生长 169 | stack_switch_call(current->stack + STACK_SIZE, current->func, current->arg); 170 | //恢复相关寄存器 171 | restore_return(); 172 | 173 | //此时协程已经完成执行 174 | current->status = CO_DEAD; 175 | 176 | if (current->waiter) { 177 | current->waiter->status = CO_RUNNING; 178 | } 179 | co_yield (); 180 | } 181 | } 182 | 183 | assert(status && current->status == CO_RUNNING); //此时一定是选中的进程通过longjmp跳转到的情况执行到这里 184 | } 185 | 186 | static __attribute__((constructor)) void co_constructor(void) { 187 | current = co_start("main", NULL, NULL); 188 | current->status = CO_RUNNING; 189 | } 190 | 191 | static __attribute__((destructor)) void co_destructor(void) { 192 | if (co_node == NULL) { 193 | return; 194 | } 195 | 196 | while (co_node) { 197 | current = co_node->coroutine; 198 | free(current); 199 | free(co_node_remove()); 200 | } 201 | } -------------------------------------------------------------------------------- /libco/co.h: -------------------------------------------------------------------------------- 1 | struct co* co_start(const char *name, void (*func)(void *), void *arg); 2 | void co_yield(); 3 | void co_wait(struct co *co); 4 | -------------------------------------------------------------------------------- /libco/demo/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all test clean 2 | 3 | demo: 4 | gcc -g demo.c 5 | 6 | test: 7 | gcc "test$(1).c" ../co.c -g 8 | 9 | clean: 10 | rm -f *.out 11 | 12 | -------------------------------------------------------------------------------- /libco/demo/demo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | int n = 0; 7 | jmp_buf buf; 8 | setjmp(buf); 9 | printf("Hello %d\n", n); 10 | longjmp(buf, n++); 11 | } 12 | -------------------------------------------------------------------------------- /libco/demo/demo1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | jmp_buf buf; 6 | 7 | void add(int p) { 8 | if (p >= 10000) return; 9 | int n = 0; 10 | add(p + 1); 11 | } 12 | 13 | void foo() { 14 | add(0); 15 | /* printf("%d" ,1); */ 16 | 17 | /* asm("movq %0, %%rsp;" : : "b"(sp) : "memory"); */ 18 | } 19 | 20 | int main() { 21 | int stack[1 << 20]; 22 | 23 | if (setjmp(buf) == 0) { 24 | #ifdef __x86_64__ 25 | asm("movq %0, %%rsp; jmp *%1;" : : "b"((uintptr_t)stack), "d"(foo) : "memory"); 26 | #endif 27 | longjmp(buf, 1); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /libco/demo/demo2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static inline void stack_switch_call(void *sp, void *entry, uintptr_t arg) { 6 | asm volatile ( 7 | #if __x86_64__ 8 | "movq %0, %%rsp; movq %2, %%rdi; jmp *%1" 9 | : : "b"((uintptr_t)sp), "d"(entry), "a"(arg) : "memory" 10 | #else 11 | "movl %0, %%esp; movl %2, 4(%0); jmp *%1" 12 | : : "b"((uintptr_t)sp - 8), "d"(entry), "a"(arg) : "memory" 13 | #endif 14 | ); 15 | } 16 | jmp_buf buf; 17 | 18 | struct arg { 19 | void (*func)(); 20 | int a; 21 | }; 22 | struct arg garg; 23 | 24 | void print() { 25 | printf("func: print\n"); 26 | } 27 | 28 | void foo(void *arg) { 29 | struct arg *parg = (struct arg*)arg; 30 | 31 | /* garg.func = parg->func; */ 32 | printf(" "); 33 | /* garg.a = parg->a; */ 34 | 35 | longjmp(buf, 1); 36 | } 37 | 38 | int main() { 39 | uint8_t stack[1 << 20]; 40 | struct arg arg = { print, 1 }; 41 | 42 | if (!setjmp(buf)) { 43 | stack_switch_call(stack, foo, (uintptr_t)&arg); 44 | } 45 | /* garg.func(); */ 46 | /* printf("%d\n", garg.a); */ 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /libco/demo/demo3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | jmp_buf buf; 6 | int stack[1 << 20]; 7 | 8 | void add(int p) { 9 | if (p >= 10000) return; 10 | int n = 0; 11 | add(p + 1); 12 | } 13 | 14 | void foo() { 15 | /* add(0); */ 16 | printf("Hello World\n"); 17 | 18 | longjmp(buf, 1); 19 | /* asm("movq %0, %%rsp;" : : "b"(sp) : "memory"); */ 20 | } 21 | 22 | int main() { 23 | 24 | if (setjmp(buf) == 0) { 25 | #ifdef __x86_64__ 26 | asm("movq %0, %%rsp; jmp *%1;" : : "b"((uintptr_t)stack), "d"(foo) : "memory"); 27 | #endif 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /libco/demo/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static inline void stack_switch_call(void *sp, void *entry, uintptr_t arg) { 6 | asm volatile ( 7 | #if __x86_64__ 8 | "movq %0, %%rsp; movq %2, %%rdi; jmp *%1" 9 | : : "b"((uintptr_t)sp), "d"(entry), "a"(arg) : "memory" 10 | #else 11 | "movl %0, %%esp; movl %2, 4(%0); jmp *%1" 12 | : : "b"((uintptr_t)sp - 8), "d"(entry), "a"(arg) : "memory" 13 | #endif 14 | ); 15 | } 16 | 17 | jmp_buf buf; 18 | uintptr_t sp; 19 | 20 | void foo(void *arg) { 21 | printf("Hello World\n"); 22 | /* printf("%s\n", (const char *)arg); */ 23 | longjmp(buf, 1); 24 | } 25 | 26 | int main() { 27 | int stack[1 << 20]; 28 | char s[10] = { 'H', 'i', '\0' }; 29 | 30 | if (setjmp(buf) == 0) { 31 | stack_switch_call(stack, foo, (uintptr_t)s); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /libco/demo/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | gcc test$1.c ../co.c -g 4 | ./a.out 5 | -------------------------------------------------------------------------------- /libco/demo/test0.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../co.h" 3 | 4 | void entry(void *arg) { 5 | printf("%s", (const char *)arg); 6 | co_yield(); 7 | } 8 | 9 | int main() { 10 | struct co *co1 = co_start("co1", entry, "a"); 11 | co_wait(co1); 12 | } 13 | -------------------------------------------------------------------------------- /libco/demo/test1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../co.h" 3 | 4 | void entry(void *arg) { 5 | printf("%s", (const char *)arg); 6 | co_yield(); 7 | } 8 | 9 | int main() { 10 | struct co *co1 = co_start("co1", entry, "a"); 11 | struct co *co2 = co_start("co2", entry, "b"); 12 | co_wait(co1); // never returns 13 | co_wait(co2); 14 | } 15 | -------------------------------------------------------------------------------- /libco/demo/test2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../co.h" 3 | 4 | int g_cnt = 0; 5 | 6 | void entry(void *arg) { 7 | for (int i = 0; i < 100; i ++ ) { 8 | printf("%s%d ", (const char *)arg, g_cnt); 9 | g_cnt ++ ; 10 | co_yield(); 11 | } 12 | } 13 | 14 | int main() { 15 | struct co *co1 = co_start("co1", entry, "a"); 16 | struct co *co2 = co_start("co2", entry, "b"); 17 | co_wait(co1); // never returns 18 | co_wait(co2); 19 | } 20 | -------------------------------------------------------------------------------- /libco/tests/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: test libco 2 | 3 | all: libco-test-64 libco-test-32 4 | 5 | test: libco all 6 | @echo "==== TEST 64 bit ====" 7 | @LD_LIBRARY_PATH=.. ./libco-test-64 8 | @echo "==== TEST 32 bit ====" 9 | @LD_LIBRARY_PATH=.. ./libco-test-32 10 | 11 | libco-test-64: main.c 12 | 13 | libco: 14 | @cd .. && make -s 15 | 16 | libco-test-64: main.c 17 | gcc -I.. -L.. -m64 main.c -o libco-test-64 -lco-64 18 | 19 | libco-test-32: main.c 20 | gcc -I.. -L.. -m32 main.c -o libco-test-32 -lco-32 21 | 22 | clean: 23 | rm -f libco-test-* 24 | -------------------------------------------------------------------------------- /libco/tests/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "co-test.h" 6 | 7 | int g_count = 0; 8 | 9 | static void add_count() { 10 | g_count++; 11 | } 12 | 13 | static int get_count() { 14 | return g_count; 15 | } 16 | 17 | static void work_loop(void *arg) { 18 | const char *s = (const char*)arg; 19 | for (int i = 0; i < 100; ++i) { 20 | printf("%s%d ", s, get_count()); 21 | add_count(); 22 | co_yield(); 23 | } 24 | } 25 | 26 | static void work(void *arg) { 27 | work_loop(arg); 28 | } 29 | 30 | static void test_1() { 31 | 32 | struct co *thd1 = co_start("thread-1", work, "X"); 33 | struct co *thd2 = co_start("thread-2", work, "Y"); 34 | 35 | co_wait(thd1); 36 | co_wait(thd2); 37 | 38 | // printf("\n"); 39 | } 40 | 41 | // ----------------------------------------------- 42 | 43 | static int g_running = 1; 44 | 45 | static void do_produce(Queue *queue) { 46 | assert(!q_is_full(queue)); 47 | Item *item = (Item*)malloc(sizeof(Item)); 48 | if (!item) { 49 | fprintf(stderr, "New item failure\n"); 50 | return; 51 | } 52 | item->data = (char*)malloc(10); 53 | if (!item->data) { 54 | fprintf(stderr, "New data failure\n"); 55 | free(item); 56 | return; 57 | } 58 | memset(item->data, 0, 10); 59 | sprintf(item->data, "libco-%d", g_count++); 60 | q_push(queue, item); 61 | } 62 | 63 | static void producer(void *arg) { 64 | Queue *queue = (Queue*)arg; 65 | for (int i = 0; i < 100; ) { 66 | if (!q_is_full(queue)) { 67 | // co_yield(); 68 | do_produce(queue); 69 | i += 1; 70 | } 71 | co_yield(); 72 | } 73 | } 74 | 75 | static void do_consume(Queue *queue) { 76 | assert(!q_is_empty(queue)); 77 | 78 | Item *item = q_pop(queue); 79 | if (item) { 80 | printf("%s ", (char *)item->data); 81 | free(item->data); 82 | free(item); 83 | } 84 | } 85 | 86 | static void consumer(void *arg) { 87 | Queue *queue = (Queue*)arg; 88 | while (g_running) { 89 | if (!q_is_empty(queue)) { 90 | do_consume(queue); 91 | } 92 | co_yield(); 93 | } 94 | } 95 | 96 | static void test_2() { 97 | 98 | Queue *queue = q_new(); 99 | 100 | struct co *thd1 = co_start("producer-1", producer, queue); 101 | struct co *thd2 = co_start("producer-2", producer, queue); 102 | struct co *thd3 = co_start("consumer-1", consumer, queue); 103 | struct co *thd4 = co_start("consumer-2", consumer, queue); 104 | 105 | co_wait(thd1); 106 | co_wait(thd2); 107 | 108 | g_running = 0; 109 | 110 | co_wait(thd3); 111 | co_wait(thd4); 112 | 113 | while (!q_is_empty(queue)) { 114 | do_consume(queue); 115 | } 116 | 117 | q_free(queue); 118 | } 119 | 120 | int main() { 121 | setbuf(stdout, NULL); 122 | 123 | printf("Test #1. Expect: (X|Y){0, 1, 2, ..., 199}\n"); 124 | test_1(); 125 | 126 | printf("\n\nTest #2. Expect: (libco-){200, 201, 202, ..., 399}\n"); 127 | test_2(); 128 | 129 | printf("\n\n"); 130 | 131 | return 0; 132 | } 133 | -------------------------------------------------------------------------------- /pstree/Makefile: -------------------------------------------------------------------------------- 1 | NAME := $(shell basename $(PWD)) 2 | export MODULE := M1 3 | all: $(NAME)-64 $(NAME)-32 4 | 5 | include ../Makefile 6 | -------------------------------------------------------------------------------- /pstree/my-pstree.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define RPATH "/proc/" 8 | #define SPATH "/stat" 9 | #define STPATH "/status" 10 | #define SN 100 11 | #define LN 10000 12 | 13 | struct Proc { 14 | unsigned int pid; // 线程号 15 | char comm[LN]; 16 | unsigned char state; 17 | unsigned int ppid; // 父进程号 18 | char name[SN]; // 进程名 19 | int ccnt; // 子进程数量 20 | struct Proc *chrilden[]; // 子进/线程 21 | }; 22 | 23 | struct Proc *ProcList[]; 24 | int ProcN = 0; 25 | 26 | void set_proc(char *pid, struct Proc *proc) { 27 | 28 | char stat_path[SN] = {}; 29 | char status_path[SN] = {}; 30 | 31 | strcat(stat_path, RPATH); 32 | strcat(stat_path, pid); 33 | strcat(stat_path, SPATH); 34 | 35 | strcat(status_path, RPATH); 36 | strcat(status_path, pid); 37 | strcat(status_path, STPATH); 38 | 39 | FILE *fp = fopen(stat_path, "r"); 40 | 41 | if (fp) { 42 | rewind(fp); 43 | fscanf(fp, "%d %s %c %d", &proc->pid, proc->comm, &proc->state, 44 | &proc->ppid); 45 | fclose(fp); 46 | } else { 47 | // 错误处理 48 | } 49 | 50 | fp = fopen(status_path, "r"); 51 | char tmp[33]; 52 | if (fp) { 53 | rewind(fp); 54 | fscanf(fp, "%s %s", tmp, proc->name); 55 | fclose(fp); 56 | } else { 57 | // 错误处理 58 | } 59 | proc->ccnt = 0; 60 | } 61 | 62 | void get_procs() { 63 | DIR *dp; 64 | struct dirent *dirp; 65 | char dirname[SN] = RPATH; 66 | int i = 1; 67 | 68 | if ((dp = opendir(dirname)) == NULL) 69 | printf("Can't open %s", dirname); 70 | 71 | while ((dirp = readdir(dp)) != NULL) { 72 | if (dirp->d_type == 73 | 4) { // d_type表示类型,4表示目录,8表示普通文件,0表示未知设备 74 | if (48 <= dirp->d_name[0] && dirp->d_name[0] <= 57) { // 数字开头 75 | 76 | struct Proc *proc = (struct Proc *)malloc(sizeof(struct Proc)); 77 | set_proc(dirp->d_name, proc); 78 | 79 | ProcList[i] = proc; 80 | i++; 81 | } 82 | } 83 | } 84 | ProcN = i; 85 | closedir(dp); 86 | } 87 | 88 | void gen_procs_tree(struct Proc *root) { 89 | 90 | printf("ProcN: %d\n", ProcN); 91 | for (int i = 1; i < ProcN; i++) { 92 | struct Proc *cp = ProcList[i]; 93 | 94 | printf("%-15s %-15d %-15d %-15p\n", cp->name, cp->pid, cp->ppid, cp); 95 | 96 | for (int j = 0; j < ProcN; j++) { 97 | struct Proc *pp = ProcList[j]; 98 | if (cp->ppid == pp->pid) { 99 | pp->chrilden[pp->ccnt] = cp; 100 | pp->ccnt++; 101 | } 102 | } 103 | } 104 | } 105 | 106 | void show_tree(struct Proc *node, int before_len) { 107 | printf("--%s(%d)", node->name, node->pid); 108 | before_len += strlen(node->name) + 7; // 调整这里可以调整对齐程度 109 | for (int i = 0; i < node->ccnt; i++) { 110 | 111 | if (i == 0) { 112 | printf("─┬─"); 113 | } else if (i == node->ccnt - 1) { 114 | for (int j = 0; j < before_len; j++) 115 | printf(" "); 116 | printf("└─"); 117 | } else { 118 | for (int j = 0; j < before_len; j++) 119 | printf(" "); 120 | printf("├─"); 121 | } 122 | 123 | show_tree(node->chrilden[i], before_len); 124 | printf("\n"); 125 | } 126 | } 127 | 128 | int main(int argc, char *argv[]) { 129 | for (int i = 0; i < argc; i++) { 130 | assert(argv[i]); 131 | printf("argv[%d] = %s\n", i, argv[i]); 132 | } 133 | assert(!argv[argc]); 134 | 135 | struct Proc *root = (struct Proc *)malloc(sizeof(struct Proc)); 136 | 137 | strcpy(root->name, "root"); 138 | root->pid = 0; 139 | root->ccnt = 0; 140 | ProcList[0] = root; 141 | 142 | get_procs(); 143 | 144 | gen_procs_tree(root); 145 | 146 | show_tree(root, 0); 147 | 148 | return 0; 149 | } 150 | 151 | // 未完成工作: 152 | // 1. -p 内容,线程的没写,在/proc/xxx/task 下面 153 | // 2. -n 排序的没有写,写一个冒泡排序即可 154 | 155 | // 效果 156 | // --root(0)─┬─--docker-init(1)─┬─--sleep(7) 157 | // ├─--dockerd(29)─┬─--containerd(114) 158 | 159 | // ├─--sshd(61) 160 | // └─--cpptools-srv(6059) 161 | 162 | // ├─--sh(786) 163 | // ├─--sh(836) 164 | // ├─--sh(1284)─┬─--node(1291)─┬─--node(1100002560) 165 | // ├─--node(2570)─┬─--cpptools(3851) 166 | // └─--node(18997) 167 | 168 | // └─--node(1100184864) 169 | 170 | // ├─--node(1618) 171 | // ├─--node(1630) 172 | // ├─--sh(1662) 173 | // ├─--sh(1745) 174 | // ├─--sh(2212)─┬─--node(2220)─┬─--node(2249) 175 | 176 | // ├─--sh(2606) 177 | // ├─--sh(2681) 178 | // ├─--sh(3210)─┬─--node(3217)─┬─--node(3239) 179 | 180 | // ├─--sh(4172) 181 | // ├─--sh(4237) 182 | // ├─--sh(4845)─┬─--node(4852)─┬─--node(4875) 183 | 184 | // ├─--node(4873) 185 | // └─--node(4899) 186 | -------------------------------------------------------------------------------- /pstree/pstree.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define VERSION "Version: 0.0.1" 11 | 12 | struct process_state { 13 | pid_t pid; 14 | char name[30]; 15 | char state; 16 | pid_t ppid; 17 | }; 18 | 19 | struct node { 20 | struct process_state ps; 21 | struct node *next; 22 | struct node *child; 23 | }; 24 | struct node *node_malloc(); 25 | int node_insert(struct node *sn, struct node *fn); 26 | void node_free(struct node *fn); 27 | 28 | static struct option longopts[] = { 29 | { "show-pids", 0, NULL, 'p' }, 30 | { "numeric-sort", 0, NULL, 'n' }, 31 | { "version", 0, NULL, 'V' }, 32 | { 0, 0, 0, 0 } 33 | }; 34 | 35 | int isNumber(char *str); 36 | void buildProcessTree(struct node *head); 37 | void printProcessTree(struct node *head, int depth, int type); 38 | void printProcess(struct node *node, int type); 39 | void printVersion(); 40 | 41 | int main(int argc, char *argv[]) { 42 | char opt; 43 | int option_index; 44 | struct node *head; 45 | 46 | head = node_malloc(); 47 | buildProcessTree(head); 48 | 49 | if (argc == 1) { 50 | printProcessTree(head, 0, 0); 51 | } 52 | else { 53 | while ((opt = getopt_long(argc, argv, "pnV", longopts, &option_index)) != -1) { 54 | switch (opt) { 55 | case 'p': 56 | printProcessTree(head, 0, 1); 57 | break; 58 | case 'n': 59 | printProcessTree(head, 0, 1); 60 | break; 61 | case 'V': 62 | printf("%s\n", VERSION); 63 | break; 64 | default: 65 | printf("pstree\n"); 66 | printf("A convenient tool to show running processes as a tree.\n"); 67 | printf("Use -p -n -V to see more"); 68 | break; 69 | } 70 | } 71 | } 72 | 73 | node_free(head); 74 | 75 | return 0; 76 | } 77 | 78 | int isNumber(char *str) { 79 | for (char *c = str; *c != '\0'; c ++ ) 80 | if (isdigit(*c) == 0) 81 | return 0; 82 | return 1; 83 | } 84 | 85 | struct node *node_malloc() { 86 | struct node *n = (struct node *)malloc(sizeof(struct node)); 87 | 88 | n->ps = (struct process_state){ 0, { }, 0 }; 89 | n->child = NULL; 90 | n->next = NULL; 91 | 92 | return n; 93 | } 94 | 95 | int node_insert(struct node *sn, struct node *fn) { 96 | struct node *p; 97 | 98 | if (sn->ps.ppid == fn->ps.pid) { 99 | if (fn->child == NULL) 100 | fn->child = sn; 101 | else { 102 | for (p = fn->child; p->next != NULL; p = p->next) 103 | ; 104 | p->next = sn; 105 | } 106 | return 1; 107 | } 108 | else { 109 | for (p = fn->child; p != NULL; p = p->next) 110 | if (node_insert(sn, p)) { 111 | return 1; 112 | } 113 | } 114 | 115 | return 0; 116 | } 117 | 118 | void node_free(struct node *fn) { 119 | struct node *p = fn->child; 120 | 121 | if (p != NULL) 122 | for ( ; p != NULL; ) { 123 | struct node *tmp = p; 124 | p = p->next; 125 | node_free(tmp); 126 | } 127 | 128 | free(fn); 129 | } 130 | 131 | void buildProcessTree(struct node *head) { 132 | DIR *d; 133 | struct dirent *dir; 134 | FILE *f; 135 | char path[100] = "/proc/"; 136 | int pathLen = 6; 137 | 138 | d = opendir(path); 139 | if (!d) { 140 | fprintf(stderr, "Directory %s does not exist\n", path); 141 | exit(1); 142 | } 143 | else { 144 | while ((dir = readdir(d)) != NULL) { 145 | if (isNumber(dir->d_name)) { 146 | strcpy(path + pathLen, dir->d_name); 147 | strcat(path, "/stat"); 148 | 149 | f = fopen(path, "r"); 150 | if (!f) { 151 | fprintf(stderr, "Open file %s failed\n", path); 152 | continue; 153 | } 154 | else { 155 | struct node *node = node_malloc(); 156 | fscanf(f, "%d (%[^)]) %c %d", 157 | &node->ps.pid, node->ps.name, &node->ps.state, &node->ps.ppid); 158 | node_insert(node, head); 159 | 160 | /* printf("%d %s %d\n", */ 161 | /* node->ps.pid, node->ps.name, node->ps.ppid); */ 162 | 163 | fclose(f); 164 | } 165 | } 166 | } 167 | closedir(d); 168 | } 169 | } 170 | 171 | void printProcessTree(struct node *node, int depth, int type) { 172 | if (node->ps.pid != 0) { 173 | printProcess(node, type); 174 | depth ++ ; 175 | } 176 | 177 | for (struct node *p = node->child; p != NULL; p = p->next) { 178 | for (int i = 0; i < depth; i ++ ) { 179 | printf(" "); 180 | } 181 | printProcessTree(p, depth, type); 182 | } 183 | } 184 | 185 | void printProcess(struct node *node, int type) { 186 | if (type == 0) { 187 | fprintf(stdout, "%s\n", node->ps.name); 188 | } 189 | else if (type == 1) { 190 | fprintf(stdout, "%s(%d)\n", node->ps.name, node->ps.pid); 191 | } 192 | } 193 | 194 | void printVersion() { 195 | fprintf(stdout, VERSION); 196 | } 197 | -------------------------------------------------------------------------------- /sperf/Makefile: -------------------------------------------------------------------------------- 1 | NAME := $(shell basename $(PWD)) 2 | export MODULE := M3 3 | all: $(NAME)-64 $(NAME)-32 4 | 5 | include ../Makefile 6 | -------------------------------------------------------------------------------- /sperf/simple-sperf/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all test clean 2 | 3 | NAME := sperf 4 | 5 | all: $(NAME) 6 | 7 | $(NAME): 8 | gcc $(NAME).c -o $@.out 9 | 10 | test: 11 | gcc -DLOCAL_MACHINE $(NAME).c -o $(NAME)-debug.out 12 | $(NAME)-debug.out echo hello 13 | 14 | clean: 15 | rm -f $(NAME).out $(NAME)-debug.out -------------------------------------------------------------------------------- /sperf/simple-sperf/sperf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef LOCAL_MACHINE 9 | #define debug(format, arg...) printf(format, ##arg) 10 | #define debug_info(format, ...) printf("\033[1m\033[45;33m Info:[%s:%s(%d)]: \033[0m" format "\n", __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__); 11 | #else 12 | #define debug(format, arg...); 13 | #define debug_info(format, ...) 14 | #endif 15 | 16 | #define zassert(x, s) \ 17 | do { if ((x) == 0) { printf("%s\n", s); assert((x)); } } while (0) 18 | 19 | char buf[BUFSIZ]; 20 | struct info { 21 | char name[100]; 22 | double time; 23 | struct info *next; 24 | }; 25 | struct info *syscall_info = NULL; 26 | void add(double time, char *name) { 27 | for (struct info *i = syscall_info; i != NULL; i = i->next) { 28 | if (strcmp(i->name, name) == 0) { 29 | i->time += time; 30 | return; 31 | } 32 | } 33 | struct info *si = (struct info *)malloc(sizeof(struct info)); 34 | strcpy(si->name, name); 35 | si->time = time; 36 | si->next = syscall_info; 37 | /* printf("-- %lf %s\n", si->time, si->name); */ 38 | debug_info("-- %lf %s\n", si->time, si->name); 39 | 40 | syscall_info = si; 41 | } 42 | 43 | int main(int argc, char *argv[], char *envp[]) { 44 | zassert(argc >= 2, "need at least one argument"); 45 | 46 | debug_info("Test Begin."); 47 | for (int i = 0; i < argc; i++) { 48 | debug_info("argv[%d]:%s", i, argv[i]); 49 | } 50 | 51 | char *strace_argv[] = { "strace", "-r", argv[1], NULL }; 52 | int pipefd[2]; 53 | int pid; 54 | 55 | zassert(pipe(pipefd) == 0, "create pipe failed"); 56 | 57 | pid = fork(); 58 | if (pid == 0) { 59 | // 关闭stderr 60 | close(2); 61 | // 将stderr接到管道的输入,stderr将输出到管道的输入 62 | dup2(pipefd[1], 2); 63 | close(pipefd[1]); 64 | // 关闭stdout(比如ls,会输出到stdout) 65 | close(1); 66 | // 关闭管道输出,用不到 67 | close(pipefd[0]); 68 | 69 | execve("/bin/strace", strace_argv, envp); 70 | zassert(0, "execve failed"); 71 | } 72 | else { 73 | // 关掉父进程的管道输入,不然管道输出会阻塞 74 | close(pipefd[1]); 75 | double time; 76 | char name[100]; 77 | 78 | while (fgets(buf, sizeof(buf), fdopen(pipefd[0], "r"))) { 79 | /* printf("%s", buf); */ 80 | sscanf(buf, "%lf %s", &time, name); 81 | if (name[0] == '+') { continue; } 82 | 83 | for (int i = 0; name[i]; i ++ ) { 84 | if (name[i] == '(') { 85 | name[i] = '\0'; 86 | break; 87 | } 88 | } 89 | add(time, name); 90 | /* printf("%lf %s\n", time, name); */ 91 | } 92 | } 93 | 94 | double total = 0, others = 0; 95 | struct info syscall_sort[5] = { }; 96 | 97 | for (struct info *i = syscall_info; i != NULL; i = i->next) { 98 | for (int j = 0; j < 4; j++) { 99 | if (syscall_sort[j].time < i->time) { 100 | for (int k = 2; k >= j; k--) { 101 | syscall_sort[k + 1] = syscall_sort[k]; 102 | } 103 | syscall_sort[j] = *i; 104 | break; 105 | } 106 | } 107 | total += i->time; 108 | /* printf("%s (%lf)\n", i->time, i->name); */ 109 | /* fflush(stdout); */ 110 | } 111 | 112 | others = total; 113 | for (int i = 0; i < 5; i++) { 114 | if (syscall_sort[i].time > 0) { 115 | printf("%s (%lf%%)\n", syscall_sort[i].name, syscall_sort[i].time / total); 116 | fflush(stdout); 117 | others -= syscall_sort[i].time; 118 | } 119 | else { 120 | printf("%s (%lf%%)\n", "others", others / total); 121 | fflush(stdout); 122 | } 123 | } 124 | 125 | for (struct info *i = syscall_info; i != NULL; ) { 126 | struct info *j = i; 127 | i = i->next; 128 | free(j); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /thread/demo-thread.c: -------------------------------------------------------------------------------- 1 | #include "thread.h" 2 | 3 | #ifdef LOCAL_MACHINE 4 | #define debug(...) \ 5 | printf("In file [%s] line [%d]: ", __FILE__, __LINE__); \ 6 | printf(__VA_ARGS__) 7 | #else 8 | #define debug(msg) 9 | #endif 10 | 11 | void Ta() { 12 | int i = 0; 13 | while (i < 5) { 14 | debug("a\n"); 15 | i++; 16 | usleep(100000); 17 | } 18 | } 19 | void Tb() { 20 | int i = 0; 21 | while (i < 5) { 22 | debug("b\n"); 23 | i++; 24 | usleep(10000); 25 | } 26 | } 27 | void Tc() { 28 | int i = 0; 29 | while (i < 5) { 30 | debug("c\n") 31 | i++; 32 | usleep(1000); 33 | } 34 | } 35 | 36 | int main() { 37 | create(Ta); 38 | create(Tb); 39 | create(Tc); 40 | debug("running...\n"); 41 | join(); 42 | debug("end...\n"); 43 | } 44 | 45 | // gcc a.c -lpthread -DLOCAL_MACHINE && ./a.out 46 | /* 47 | In file [a.c] line [14]: a 48 | In file [a.c] line [40]: running... 49 | In file [a.c] line [22]: b 50 | In file [a.c] line [30]: c 51 | In file [a.c] line [30]: c 52 | In file [a.c] line [30]: c 53 | In file [a.c] line [30]: c 54 | In file [a.c] line [30]: c 55 | In file [a.c] line [22]: b 56 | In file [a.c] line [22]: b 57 | In file [a.c] line [22]: b 58 | In file [a.c] line [22]: b 59 | In file [a.c] line [14]: a 60 | In file [a.c] line [14]: a 61 | In file [a.c] line [14]: a 62 | In file [a.c] line [14]: a 63 | In file [a.c] line [42]: end... 64 | */ -------------------------------------------------------------------------------- /thread/shm-test.c: -------------------------------------------------------------------------------- 1 | #include "thread.h" 2 | 3 | int x = 0; 4 | 5 | void Thello(int id) { 6 | // int x = 0; 7 | usleep(id * 100000); 8 | printf("Hello from thread #%c\n", "123456789ABCDEF"[x++]); 9 | } 10 | 11 | int main() { 12 | for (int i = 0; i < 10; i++) { 13 | create(Thello); 14 | } 15 | } 16 | 17 | /* 证明线程确实共享内存 18 | * $ gcc shm-test.c -lpthread 19 | * Hello from thread #1 20 | * Hello from thread #2 21 | * Hello from thread #3 22 | * Hello from thread #4 23 | * Hello from thread #5 24 | * Hello from thread #6 25 | * Hello from thread #7 26 | * Hello from thread #8 27 | * Hello from thread #9 28 | * Hello from thread #A 29 | */ -------------------------------------------------------------------------------- /thread/stack-probe.c: -------------------------------------------------------------------------------- 1 | #include "thread.h" 2 | 3 | __thread char *base, *cur; // thread-local variables 4 | __thread int id; 5 | 6 | // objdump to see how thread-local variables are implemented 7 | __attribute__((noinline)) void set_cur(void *ptr) { cur = ptr; } 8 | __attribute__((noinline)) char *get_cur() { return cur; } 9 | 10 | void stackoverflow(int n) { 11 | set_cur(&n); 12 | if (n % 1024 == 0) { 13 | int sz = base - get_cur(); 14 | printf("Stack size of T%d >= %d KB\n", id, sz / 1024); 15 | } 16 | stackoverflow(n + 1); 17 | } 18 | 19 | void Tprobe(int tid) { 20 | id = tid; 21 | base = (void *)&tid; 22 | stackoverflow(0); 23 | } 24 | 25 | int main() { 26 | setbuf(stdout, NULL); 27 | for (int i = 0; i < 4; i++) { 28 | create(Tprobe); 29 | } 30 | } 31 | 32 | /* 证明线程具有独立堆栈 (以及确定它们的范围) 33 | * $ gcc stack-probe.c -lpthread 34 | * Stack size of T1 >= 0 KB 35 | * Stack size of T2 >= 0 KB 36 | * Stack size of T3 >= 0 KB 37 | * Stack size of T4 >= 0 KB 38 | * Stack size of T1 >= 64 KB 39 | * Stack size of T2 >= 64 KB 40 | * Stack size of T3 >= 64 KB 41 | * Stack size of T4 >= 64 KB 42 | * Stack size of T1 >= 128 KB 43 | * ... 44 | * Stack size of T5 >= 7936 KB 45 | * Stack size of T3 >= 8000 KB 46 | * Stack size of T5 >= 8000 KB 47 | * Stack size of T3 >= 8064 KB 48 | * Stack size of T3 >= 8128 K 49 | */ 50 | -------------------------------------------------------------------------------- /thread/thread.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define NTHREAD 64 10 | enum { T_FREE = 0, 11 | T_LIVE, 12 | T_DEAD, 13 | }; 14 | struct thread { 15 | int id, status; 16 | pthread_t thread; 17 | void (*entry)(int); 18 | }; 19 | 20 | struct thread tpool[NTHREAD], *tptr = tpool; 21 | 22 | void *wrapper(void *arg) { 23 | struct thread *thread = (struct thread *)arg; 24 | thread->entry(thread->id); 25 | return NULL; 26 | } 27 | 28 | void create(void *fn) { 29 | assert(tptr - tpool < NTHREAD); 30 | *tptr = (struct thread){ 31 | .id = tptr - tpool + 1, 32 | .status = T_LIVE, 33 | .entry = fn, 34 | }; 35 | pthread_create(&(tptr->thread), NULL, wrapper, tptr); 36 | ++tptr; 37 | } 38 | 39 | void join() { 40 | for (int i = 0; i < NTHREAD; i++) { 41 | struct thread *t = &tpool[i]; 42 | if (t->status == T_LIVE) { 43 | pthread_join(t->thread, NULL); 44 | t->status = T_DEAD; 45 | } 46 | } 47 | } 48 | 49 | __attribute__((destructor)) void cleanup() { 50 | join(); 51 | } --------------------------------------------------------------------------------