├── .gitignore ├── Makefile ├── README.md ├── make.bat ├── readthedocs.yaml └── source ├── IA32_manual.md ├── Linuxv0.11_read.md ├── _static └── week1 │ ├── image-20210912102241118.png │ ├── image-20210912102242723.png │ ├── image-20210912103906024.png │ ├── image-20210912104110438.png │ ├── image-20210912105353051.png │ ├── image-20210912105457100.png │ ├── image-20210912105650873.png │ ├── image-20210912105927574.png │ ├── image-20210912110042298.png │ ├── image-20210912111303132.png │ └── image-20210912114908328.png ├── about.md ├── conf.py ├── index.md ├── intro.md ├── missing_detail.md ├── nasm_tutorial.md ├── ref.md ├── requirements.txt ├── week1.md ├── week2.md ├── week3.md ├── week4.md ├── week5.md ├── week6.md ├── week7.md └── week8.md /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 介绍 2 | 3 | 武汉大学网络安全学院2021-2022学年操作系统实践wiki 4 | 5 | 参考书籍《Orange's》 6 | 7 | 网站链接https://whu-os-ex-2021.readthedocs.io/ 8 | 9 | ## 开发维护人员 10 | 11 | [桑乾龙](https://github.com/codefuturedalao) -------------------------------------------------------------------------------- /make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Build documentation in the docs/ directory with Sphinx 9 | sphinx: 10 | configuration: source/conf.py 11 | 12 | # Optionally build your docs in additional formats such as PDF 13 | formats: 14 | - pdf 15 | 16 | # Optionally set the version of Python and requirements required to build your docs 17 | python: 18 | version: "3.7" 19 | install: 20 | - requirements: source/requirements.txt 21 | -------------------------------------------------------------------------------- /source/IA32_manual.md: -------------------------------------------------------------------------------- 1 | ## System Architecture Overview 2 | 3 | ### Modes of operation 4 | 5 | IA-32共有以下四种操作模式: 6 | 7 | * 实模式 8 | 9 | * 保护模式 10 | 11 | * 虚拟8086模式 12 | 13 | 该模式允许在保护模式下执行8086程序 14 | 15 | * 系统管理模式(system management mode, SMM) 16 | 17 | 为操作系统或执行环境提供了电源管理的透明机制,通过激活外部系统中断引脚(SMI#)触发系统管理中断(system managemtn interrupt, SMI)来进入SMM模式。在SMM模式中,处理器切换到分离的地址空间,透明执行指定的代码,然后执行RSM指令返回到之前的模式。 18 | 19 | ![image-20210921101657821](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210921101657821.png) 20 | 21 | 其中实模式和保护模式是我们关注的重点。所有的Intel 64和32位处理器在加电后都会进入实模式,之后软件切换到保护模式下运行。 22 | 23 | 系统总览图如下: 24 | 25 | ![image-20210922112336635](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210922112336635.png) 26 | 27 | ### EFLAGS 28 | 29 | EFLAGS寄存器控制着IO、可屏蔽硬件中断、任务切换和虚拟8086模式等。只有特权代码才允许修改这些位。 30 | 31 | ![image-20210921102053952](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210921102053952.png) 32 | 33 | * TF:Trap(bit 8),为1时表示单步中断模式,处理器在每条指令执行后触发调试异常(debug exception),这允许检查程序每条指令执行的状态。当程序通过```POPF, POPFD, IRET```指令设置了TF位,则后面跟着的指令开始触发调试一场。 34 | * IF:Interrupt enable(bit 9),控制处理器对可屏蔽中断的响应,如果为1,则表示处理器响应可屏蔽中断,为0表示禁止可屏蔽中断。**IF位不影响异常和不可屏蔽中断。**CPL、IOPL和CR4中的VME位决定IF位是否能被CLI,STI,POPF,POPFD和IRET指令修改。 35 | * IOPL:I/O privilege level field(bits 12 and 13)表示当前运行程序的IO特权级,当前运行程序的CPL必须数值上小于或等于IOPL值才可以访问IO地址空间,只有当CPL为0时,才可以通过POPF和IRET指令修改IOPL位。 36 | * NT:Nested task(bit 14),控制被中断和被调用任务,当通过call指令、异常或中断进入任务时,处理器置该位为1。当IRET从任务中返回时会检查和修改该位。 37 | * RF:Resume(bit 16),控制处理器对程序断点的响应,为1时,屏蔽指令断点产生debug异常;为0时,允许指令断点产生debug异常。RF的主要功能是防止处理器进入debug异常死循环。 38 | * VM:Virtual-8086 mode(bit 17),置为表示进入虚拟8086模式,清除表示返回保护模式。 39 | * ID:Identification(bit21),表示是否支持CPUID指令。 40 | 41 | ### GDTR、LDTR、IDTR和TR 42 | 43 | ![image-20210921103902353](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210921103902353.png) 44 | 45 | GDT和IDT都不能称之为段,因为他们既没有段选择符,也没有段描述符。 46 | 47 | #### GDTR 48 | 49 | 当处理器上电或reset时,GDTR的基地址为0,界限为0FFFFH,在进入保护模式之前,新的基地址和界限必须被加载进GDTR中。 50 | 51 | #### LDTR 52 | 53 | LDTR寄存器包含16位的段选择符、基地址、短界限和描述符属性,当LLDT指令向LDTR中加载段选择符时,基地址、段界限和描述符属性会被自动加载如LDTR中。当发生任务切换时,LDTR自动加载新任务的段选择符和描述符。 54 | 55 | 当处理器上电或reset时,GDTR的基地址为0,界限为0FFFFH。 56 | 57 | #### IDTR 58 | 59 | 当处理器上电或reset时,GDTR的基地址为0,界限为0FFFFH。 60 | 61 | #### TR 62 | 63 | TR寄存器包含当前任务TSS的16位的段选择符、基地址、短界限和描述符属性。段选择符指向GDT表中的TSS描述符。 64 | 65 | 当LTR指令向TR中加载段选择符时,基地址、段界限和描述符属性会被自动加载如TR中。当发生任务切换时,TR自动加载新任务TSS的段选择符和描述符。 66 | 67 | ### Control Registers 68 | 69 | ![image-20210921105345794](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210921105345794.png) 70 | 71 | ```{admonition} 72 | 在保护模式下0特权级下,MOV指令允许读取和加载控制寄存器。其他特权级下的程序无法读取和修改控制寄存器 73 | ``` 74 | 75 | * CR0:包含控制操作模式和处理器状态的系统控制位 76 | * PG:Paging(bit 31):为1时表示启动分页,为0时表示禁止分页。当禁止分页时,所有的线性地址可以直接看作物理地址。当PE位为0时,设置PG位会触发保护异常,即只有操作系统是保护模式时,才可以启动分页。 77 | * CD:Cache Disable 78 | * NW:Not Write-through 79 | * WP:Write Protect(bit 16),为1时,阻止高特权级程序向只读页面进行写操作;为0时,允许高特权级程序向只读页面写入(忽略U/S位) 80 | * EM:Emulation(bit 2),为1时表示处理器没有内部或外部的x87 FPU;为0时表示存在x87 FPU 81 | * PE:Protection Enable(bit 0),为1时表示启动保护模式;为0时表示进入是模式。 82 | 83 | * CR1:Reserved 84 | * CR2:包含触发缺页异常的线性地址 85 | * CR3:包含页目录的起始物理地址和两个控制位(PCD和PWT) 86 | * CR4:包含一些架构扩展控制位 87 | * PVI:Protected-Mode Virtual Interrupts(bit 1),为1时启动对虚拟中断的硬件支持;为0时禁止虚拟中断。 88 | * PSE:Page Size Extensions(bit 4),为1时表示页的大小为4MB,为0时表示页的大小为4KB。 89 | * PAE:Physical Address Extension(bit 5),为1时,启动物理地址扩展,允许分页产生超过32位的物理地址;为0时,禁止物理地址扩展。 90 | * VMXE:VMX-Enable Bit(bit 13),为1时,启动虚拟机操作扩展;为0时,禁止虚拟机操作扩展。 91 | 92 | ### System Instruction Summary 93 | 94 | 系统指令只允许在特权级0上执行,其他特权级不允许执行。 95 | 96 | ![image-20210921113540448](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210921113540448.png) 97 | 98 | ## Protected-Mode Memory Management 99 | 100 | ### Overview 101 | 102 | IA-32中的内存管理机制被分为两部分:分段和分页。**在保护模式中,分段模式自动开启,没有控制位来禁止分段。**而分页机制则是可选的。 103 | 104 | ![image-20210921114706298](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210921114706298.png) 105 | 106 | ### Segment 107 | 108 | 分段机制可用来实现一系列系统设计,这些设计包含简单使用分段的平坦模型到使用分段建立了健壮的操作环境的多分段模型。 109 | 110 | * Basic Flat Model 111 | 112 | 代码段和数据段基地址从0开始,界限为4GB,访问不存在内存设备的物理地址也不会触发异常,需要分页机制来实现进程和进程的内存空间隔离与保护。 113 | 114 | ![image-20210921115600711](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210921115600711.png) 115 | 116 | * Protected Flat Model 117 | 118 | 设置了段界限,避开了不存在物理内存的物理地址,需要分页机制来实现进程和进程的内存空间隔离与保护。 119 | 120 | ![image-20210921115733505](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210921115733505.png) 121 | 122 | * Multi-segmented Model 123 | 124 | 充分使用了分段机制,每个程序拥有自己的段描述符表和段,每个段都做到了充分的隔离。 125 | 126 | ![image-20210921115853091](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210921115853091.png) 127 | 128 | #### Segment Selector 129 | 130 | ![image-20210921144638225](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210921144638225.png) 131 | 132 | 由于GDT的第一个描述符不会被处理器使用,因此指向该描述符的选择符(index和ti为0)被用作null段选择符,可以用来初始化一个未使用的段寄存器,然而,通过null段选择符访问数据以及向CS和SS寄存器加载null段选择符会导致保护异常(#GP)。 133 | 134 | #### Segment Registers 135 | 136 | 为了减少地址转换时间和代码复杂度,处理器提供了6个段寄存器。每一个段寄存器都有一个可见部分和隐藏部分,当段选择符被加载到段寄存器的可见部分,处理器会自动将段寄存器的隐藏部分(段基址、段界限和访问信息)加载进来。这样处理器每次访问内存便不用再去段选择符指向的描述符中获取信息,而是直接从段寄存器中获取。 137 | 138 | ![image-20210921145351514](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210921145351514.png) 139 | 140 | 当段描述符发生变化,软件有责任重新更新段寄存器的内容,否则段寄存器很可能使用过时的信息来访问内存。 141 | 142 | #### Segment Descriptor 143 | 144 | 段描述符通常由编译器或操作系统创建,而不是应用程序。 145 | 146 | ![image-20210921150627003](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210921150627003.png) 147 | 148 | **注:段基址最好为16字节对齐,这样有利于提高性能。** 149 | 150 | 描述符共有以下几种类型: 151 | 152 | * 代码和数据段描述符(S位为1) 153 | 154 | ![image-20210925154615181](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210925154615181.png) 155 | 156 | ![image-20210921151102035](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210921151102035.png) 157 | 158 | * 系统描述符(S位为0) 159 | 160 | * 系统段描述符(指向系统段) 161 | 162 | ![image-20210925154638553](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210925154638553.png) 163 | 164 | * LDT段描述符 165 | 166 | * TSS描述符 167 | 168 | ![image-20211001105448440](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211001105448440.png) 169 | 170 | * 门描述符(包含指向代码段或TSS的选择符) 171 | 172 | * 调用门 173 | 174 | ![image-20210925194355975](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210925194355975.png) 175 | 176 | * 中断门 177 | 178 | ![image-20210926153813439](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210926153813439.png) 179 | 180 | * 陷阱门 181 | 182 | ![image-20210926153802998](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210926153802998.png) 183 | 184 | * 任务门 185 | 186 | ![image-20210926153754277](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210926153754277.png) 187 | 188 | ![image-20210921152527514](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210921152527514.png) 189 | 190 | ### Paging 191 | 192 | 软件通过MOV指令设置CR0的PG位来启动分页,在此之前要确保CR3中包含页目录的起始地址以及初始化相应内容。 193 | 194 | IA-64处理器共支持四种不同的分页方式: 195 | 196 | * 32位分页 197 | * PAE分页 198 | * 4级分页 199 | * 5级分页 200 | 201 | 我们用到的是32位分页。此时CR0.PG=1以及CR4.PAE=0。 202 | 203 | 当CR4的PSE和PDE的PS位为0,表示采用4KB页大小,寻址方式如下所示: 204 | 205 | ![image-20210921200917925](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210921200917925.png) 206 | 207 | ![image-20210921201712475](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210921201712475.png) 208 | 209 | * R/W:0表示只读,1表示可读写 210 | * U/S:为0表示不允许用户模式访问,只允许特权级为0、1、2的程序访问。为1时,允许所有特权级程序访问。 211 | * A:Accessd,由处理器固件来设置,用来指示此表象所指向的页是否被访问过。 212 | * D:Dirty,由处理器固件来设置,用来指示此表象所指向的页是否被写过数据。 213 | * PAT 214 | * G:如果CR4.PGE=1,决定是否地址转换为全局。 215 | 216 | #### Access Rights 217 | 218 | 对线性地址的访问可以分为两种: 219 | 220 | * supervisor-mode access:CPL < 3 221 | * user-mode access:CPL=3 222 | 223 | 其中对线性地址隐式的访问如从GDT或LDT中加载段选择符被视为supervisor-mode access(不管其CPL为多少)。 224 | 225 | 其访问权限的判断过于复杂,此处略去,推荐同学们去手册中直接查看。粗略总结就是supervisor-mode access可以访问supervisor和user的地址(由U/S位决定)。但user只能访问自己的,不可以访问supervisor的。 226 | 227 | #### Page Fault Exception 228 | 229 | 缺页异常由两种情况导致: 230 | 231 | 1. 没有线性地址对应的物理地址转换(P位为0) 232 | 2. 有地址转换,但access rights不允许本次访问 233 | 234 | ## Protection 235 | 236 | ### Limit Checking 237 | 238 | 对于向上扩展的段,段界限指向了段中最后一个允许被访问的字节,数值上为段大小减一。 239 | 240 | 对于向下扩展的段,段界限指向了段中最后一个不允许被访问的字节。 241 | 242 | ### Type Checking 243 | 244 | 处理器通常会在以下几种情况执行类型检查: 245 | 246 | 1. 当段选择符加载进段寄存器 247 | * CS寄存器只能加载代码段选择符 248 | * 系统段和不可读代码段选择符不能被加载到DS、ES、FS和GS寄存器中 249 | * 只有可写的数据段可以被加载到SS寄存器 250 | 2. 当通过指令访问段时 251 | * 不能写入可执行代码段 252 | * 不能写入只读数据段 253 | * 不能读不可读代码段 254 | 3. 当指令操作数为段选择符时 255 | * 远跳转的call和jmp指令只能访问一致性代码段、非一致性代码段、调用门、任务门和TSS。 256 | * LLDT指令的选择符指向LDT段描述符 257 | * LTR指令的选择符指向TSS描述符 258 | * IDT的表项必须是中断、陷阱和任务门。 259 | 4. 在特定的内部操作中 260 | * 当call或jump通过调用门转移时,处理器自动检查指向的段描述符是代码段描述符 261 | * 当call或jump通过任务门转移时,处理器自动检查任务门指向的段描述符为TSS 262 | * 当call或jump直接通过TSS转移时,处理器自动检查指向的段描述符是TSS 263 | * 当从嵌套任务中返回时,处理器检查目前TSS中指向的前一个任务的段描述符是TSS 264 | 265 | ### Privilege Checking 266 | 267 | **特权检查发生在向段寄存器中加载段选择符时。** 268 | 269 | ![image-20210925161655782](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210925161655782.png) 270 | 271 | * CPL:当前任务或程序的特权级,被存储在CS寄存器和SS寄存器的最低两位。通常情况下,CPL等于代码段的DPL,处理器在转移到不同特权级的代码段下时,会改变CPL。**但是当转移到一致性代码段时,CPL不发生变化**,此时CPL和代码段的DPL可能会出现不一致的情况。 272 | * DPL:段或门的特权级,被存储在段或门描述符的DPL域中。当目前执行的代码尝试访问一个段或门时,段或门的DPL用来和CPL和选择符的RPL进行比较,确认程序是否具有权限访问。 273 | * 数据段DPL:显示允许访问该段的最低特权级。 274 | * 非一致性代码段(不使用调用门):显示访问该段需要具有的特权级 275 | * 调用门DPL:显示允许调用该门的最低特权级 276 | * 一致性代码段和非一致性代码段通过门访问:显示允许访问该段的最高特权级。 277 | * TSS DPL:显示允许访问该段的最低特权级 278 | * RPL:段选择符的最低两位,用来确保高特权级代码不会代替低特权级代码访问一个段,除非低特权级代码有权限来访问。主要和ARPL指令搭配使用。 279 | 280 | #### Accessing Data Segments 281 | 282 | 在将数据段选择符加载到段寄存器之前,处理器会根据CPL,段选择符的RPL和数据段描述符的DPL进行比较,当DPL数值上都大于等于CPL和RPL时,允许加载,否则产生general-protection异常。 283 | 284 | ![image-20210925164854662](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210925164854662.png) 285 | 286 | 值得注意的是,段选择符的RPL是软件控制的,举个例子,CPL为3的应用程序可以设置数据段选择符的RPL为0,从而绕过RPL检查,只需要检查CPL。 287 | 288 | #### Accessing Stack Segments 289 | 290 | 加载入SS寄存器中的选择符RPL和段描述符DPL必须和当前CPL保持一致。如果RPL和DPL与当前的CPL不一致,则触发general-protection 异常。 291 | 292 | #### Transfer between Code Segments 293 | 294 | 程序的转移可以通过以下指令实现: 295 | 296 | JMP、CALL、RET、SYSENTER、SYSEXIT、SYSCALL、SYSRET,INT n和IRET指令,以及异常和中断。 297 | 298 | JMP和CALL指令可以通过以下四种方式实现代码段的切换: 299 | 300 | * 操作数为指向目标代码段的选择符 301 | * 操作数为指向调用门的选择符,调用门描述符中包含指向目标代码段的选择符。 302 | * 操作数为指向TSS的选择符,TSS中包含指向目标代码段的选择符。 303 | * 操作数为指向任务门的选择符,任务门中包含指向TSS的选择符,TSS中包含指向目标代码段的选择符。 304 | 305 | ##### Direct calls or jumps to Code Segment 306 | 307 | ![image-20210925193534192](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210925193534192.png) 308 | 309 | * CPL:调用程序的CPL 310 | * DPL:目标代码段的DPL 311 | * RPL:指向目标代码段的选择符的RPL 312 | * C flag:目标代码段描述符的C位,表示该段是一致性代码段还是非遗执行代码段。 313 | 314 | 1. 访问非一致性代码段(C=0) 315 | 316 | CPL必须等于DPL,RPL数值像小于等于CPL(可以看作DPL)。 317 | 318 | 2. 访问一致性代码段 319 | 320 | CPL数值上大于等于DPL,RPL不用检查。转移后CPL不发生变化。 321 | 322 | ##### Call Gates 323 | 324 | 调用门描述符可以放在GDT或LDT中,不能放在IDT中。 325 | 326 | ![image-20210925194544771](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210925194544771.png) 327 | 328 | * Segment Selector:指向目标代码段 329 | * Offset:目标代码段的入口点 330 | * P:调用门是否有效 331 | * Param Count:参数个数,当堆栈发生切换,表示需要从调用者堆栈复制到被调用者堆栈的参数个数。 332 | 333 | ![image-20210925195215964](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210925195215964.png) 334 | 335 | 由于调用门中包含代码段偏移量,因此jmp和call中的代码偏移量是不被使用的,但要给出一个值,随便设置即可。 336 | 337 | 调用门的特权级检查需要用到下面五个值: 338 | 339 | ![image-20210925195601715](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210925195601715.png) 340 | 341 | * CPL 342 | * 指向调用门的选择符的RPL 343 | * 调用门描述符中的DPL 344 | * 目标代码段的DPL 345 | * 目标代码段的C flag 346 | 347 | call和jmp规则稍有不同,jmp跳转不能更改特权级,call跳转可以更改特权级(当跳转到非一致性高特权级代码段时),特权级检查规则如下: 348 | 349 | ![image-20210925195622406](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210925195622406.png) 350 | 351 | ### Stack Switching 352 | 353 | 当特权级发生变换时,如通过call调用门到非一致性高特权级代码段,会发生栈切换,因为不同的特权级具有不同的堆栈,防止因为栈空间不足而崩溃,以及特权级隔离。 354 | 355 | 1. Uses the DPL of the destination code segment (the new CPL) to select a pointer to the new stack (segment selector and stack pointer) from the TSS. 356 | 357 | 2. Reads the segment selector and stack pointer for the stack to be switched to from the current TSS. Any limit violations detected while reading the stack-segment selector, stack pointer, or stack-segment descriptor cause an invalid TSS (#TS) exception to be generated. 358 | 359 | 3. Checks the stack-segment descriptor for the proper privileges and type and generates an invalid TSS (#TS) exception if violations are detected. 360 | 361 | 4. Temporarily saves the current values of the SS and ESP registers. 362 | 363 | 5. Loads the segment selector and stack pointer for the new stack in the SS and ESP registers. 364 | 365 | 6. Pushes the temporarily saved values for the SS and ESP registers (for the calling procedure) onto the new stack (see Figure 5-13). 366 | 367 | 7. Copies the number of parameter specified in the parameter count field of the call gate from the calling procedure’s stack to the new stack. If the count is 0, no parameters are copied. 368 | 369 | 8. Pushes the return instruction pointer (the current contents of the CS and EIP registers) onto the new stack. 370 | 371 | 9. Loads the segment selector for the new code segment and the new instruction pointer from the call gate into the CS and EIP registers, respectively, and begins execution of the called procedure. 372 | 373 | ![image-20210925202340675](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210925202340675.png) 374 | 375 | 当从高特权级retf返回低特权级时,执行以下操作 376 | 377 | 1. Checks the RPL field of the saved CS register value to determine if a privilege level change is required on the return. 378 | 379 | 2. Loads the CS and EIP registers with the values on the called procedure’s stack. (Type and privilege level checks are performed on the code-segment descriptor and RPL of the code- segment selector.) 380 | 381 | 3. (If the RET instruction includes a parameter count operand and the return requires a privilege level change.) Adds the parameter count (**in bytes obtained from the RET instruction**) to the current ESP register value (after popping the CS and EIP values), to step past the parameters on the called procedure’s stack. The resulting value in the ESP register points to the saved SS and ESP values for the calling procedure’s stack. (Note that the byte count in the RET instruction must be chosen to match the parameter count in the call gate that the calling procedure referenced when it made the original call multiplied by the size of the parameters.) 382 | 383 | 4. (If the return requires a privilege level change.) Loads the SS and ESP registers with the saved SS and ESP values and switches back to the calling procedure’s stack. **The SS and ESP values for the called procedure’s stack are discarded**. Any limit violations detected while loading the stack-segment selector or stack pointer cause a general-protection exception (#GP) to be generated. The new stack-segment descriptor is also checked for type and privilege violations. 384 | 385 | 5. (If the RET instruction includes a parameter count operand.) Adds the parameter count (in bytes obtained from the RET instruction) to the current ESP register value, to step past the parameters on the calling procedure’s stack. The resulting ESP value is not checked against the limit of the stack segment. If the ESP value is beyond the limit, that fact is not recognized until the next stack operation. 386 | 387 | 6. (If the return requires a privilege level change.) Checks the contents of the DS, ES, FS, and GS segment registers. If any of these registers refer to segments whose DPL is less than the new CPL (excluding conforming code segments), the segment register is loaded with a null segment selector. 388 | 389 | ### Page-Level Protection 390 | 391 | 处理器执行两种页面级别的保护 392 | 393 | * Restriction of addressable domain (supervisor and user modes). 394 | 395 | 当CPL为0,1和2时,我们称代码运行在supervisor mode,如果为3,则运行在user mode。当处理器在supervisor mode下工作时,可以访问所有的页,当在user mode下工作室,只能访问用户级别的页。 396 | 397 | * Page type (read only or read/write). 398 | 399 | 当处理器在S模式下,且CR0的WP位为0,所有的页均为可读写。当处理器在U模式下,只能写入用户级别的可读写的页。当WP为1,只读页不可以被任何特权级下的代码写入。 400 | 401 | 任何违反了以上两种保护的操作都会触发page-fault异常。 402 | 403 | ## Interrupt And Exception Handling 404 | 405 | 当检测到中断或异常时,当前执行程序或任务会被挂起,处理器转去执行中断或异常处理程序,当处理程序执行完毕,处理器会恢复被中断程序或任务的执行。 406 | 407 | x86架构对中断和异常进行了区分,中断和异常的区别在于中断是异步事件,异常是同步事件。 408 | 409 | ### Exception and interrupt vectors 410 | 411 | 为了更方便地处理异常和中断,处理器为一些中断异常事件分配了一个专门的数字,称为向量号(vector number),处理器使用向量号作为IDT表的索引,获取中断或异常处理程序的入口点。 412 | 413 | 向量号的范围是0~255,通常0~31被intel所保留,用于架构预先定义的异常和中断,但并不是所有的向量号都已经被分配,有些在0~31范围内的向量号还未分配给特定的异常和中断,请不要使用这些未分配的向量号,因为未来的某一天intel可能就会用到。 414 | 415 | ![image-20210926110540837](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210926110540837.png) 416 | 417 | ![image-20210926110558347](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210926110558347.png) 418 | 419 | 而32~255范围内的向量号用于分配给用户自定义的中断,这些中断的来源可能是外部I/O设备等。 420 | 421 | ### Sources of interrupts 422 | 423 | 中断的来源分为以下两种 424 | 425 | * 外部中断 426 | * 软件生成的中断 427 | 428 | #### External Interrupts 429 | 430 | 外部中断由处理器的引脚或本地APIC设备获取 431 | 432 | External interrupts are received through pins on the processor or through the local APIC. The primary interrupt pins on Pentium 4, Intel Xeon, P6 family, and Pentium processors are the LINT[1:0] pins, which are connected to the local APIC. When the local APIC is enabled, the LINT[1:0] pins can be programmed through the APIC’s local vector table (LVT) to be associated with any of the processor’s exception or interrupt vectors. 433 | 434 | When the local APIC is global/hardware disabled, these pins are configured as INTR and NMI pins, respectively. Asserting the INTR pin signals the processor that an external interrupt has occurred. The processor reads from the system bus the interrupt vector number provided by an external interrupt controller, such as an 8259A (see Section 6.2, “Exception and Interrupt Vectors”). Asserting the NMI pin signals a non-maskable interrupt (NMI), which is assigned to interrupt vector 2. 435 | 436 | #### Software-Generated Interrupts 437 | 438 | ```Int n```指令允许软件触发中断,比如,```Int 35```可以隐式地调用35号中断的处理器程序。0~255号中断都可以通过该指令触发,但是当触发NMI中断时,处理器的行为和当NMI从外部触发时的行为不一致,会调用对应的中断处理程序,但不会执行相应的硬件操作。 439 | 440 | 软件触发的中断不能被IF位所屏蔽。 441 | 442 | ### Exceptions 443 | 444 | 异常的来源有以下几种: 445 | 446 | * 处理器检测到程序的错误导致的异常 447 | 448 | 比如除0 449 | 450 | * 软件触发的异常 451 | 452 | ```INTO```,```INT1```,```INT3```和```BOUND```指令用来触发软件异常 453 | 454 | * 机器检查的异常(Machine-Check exceptions) 455 | 456 | P6和奔腾处理器提供了机器检查机制来检查内部芯片硬件和总线事务,当出现错误时,处理器会产生机器检查一场(vector 18) 457 | 458 | 异常的分类: 459 | 460 | * Faults:处理后重新执行异常指令 461 | * Traps:处理后执行异常指令下一条指令 462 | * Aborts:不需要精确报告异常指令的位置,也不允许重新执行导致异常的程序或任务。 463 | 464 | ### Enable and Disable Interrupts 465 | 466 | 处理器根据处理器状态、IF和RF位来屏蔽一些中断的产生。 467 | 468 | #### Masking Maskable Hardware interrupt 469 | 470 | 当处理器IF位为0,INTR引脚接受的中断都会被屏蔽掉。IF为不影响不可屏蔽中断(NMI)和异常。 471 | 472 | 当CPL数值上小于IOPL时,才能使用STI/CLI指令设置或清楚IF位,否则会产生异常。 473 | 474 | #### Masking Instruction Breakpoints 475 | 476 | RF为1屏蔽指令断点触发的debug异常。 477 | 478 | #### Masking Exceptions and interrupts when switching stacks 479 | 480 | 当MOV或POP指令修改了SS寄存器的值时,在下一条指令执行时屏蔽指令断点触发的debug异常和单步陷阱异常。 481 | 482 | Intel推荐使用```LSS```指令同时加载SS和ESP寄存器。 483 | 484 | ### Prioritization of concurrent events 485 | 486 | ![image-20210926151630260](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210926151630260.png) 487 | 488 | ![image-20210926151638694](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210926151638694.png) 489 | 490 | 处理器先处理高特权级事件,此时低特权级异常会被抛弃,低特权级终端仍然挂起等待处理。 491 | 492 | ### IDT 493 | 494 | 和GDT、LDT一样,IDT也是8字节描述符的数组,将每个中断或异常和一个门描述符联系起来。但和GDT不一样的是,IDT第一个表项是可用的描述符。 495 | 496 | 由于只有256个中断或异常向量,因此IDT只需要容纳256个描述符即可,也可以少于256个。 497 | 498 | IDT包含以下三种门 499 | 500 | ![image-20210926153738446](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210926153738446.png) 501 | 502 | * 任务门 503 | 504 | * 中断门 505 | 506 | 清除TF位和IF位 507 | 508 | * 陷阱门 509 | 510 | 清除TF位,不清除IF位 511 | 512 | 中断门陷阱门和调用门非常类似,其中包含了目标代码段的选择符和偏移量。 513 | 514 | ![image-20210926154235838](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210926154235838.png) 515 | 516 | 当处理器调用中断或异常处理程序时,执行以下操作: 517 | 518 | * 如果目标代码段特权级更高,发生栈切换 519 | 520 | 从TSS获取对应堆栈的选择符和栈指针,在新栈中压入SS、ESP、EFLAGS、CS和EIP的值,如果该异常存在错误码(error code),最后压入Error Code。 521 | 522 | * 如果目标代码段特权级和当前特权级一致, 523 | 524 | 向堆栈中依次压入EFLAGS、CS、EIP和Error Code(如果有的话) 525 | 526 | ![image-20210926154657932](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210926154657932.png) 527 | 528 | ### Privilege Checking 529 | 530 | 中断或异常门的特权级检查和直接通过call指令访问调用门类似,除了以下两点: 531 | 532 | 1. 中断和异常向量没有RPL,因此不用检查RPL 533 | 2. 当通过```INT n```,```INT3```或```INTO```等指令产生软件中断或异常时,需要检查门描述符的DPL,需要确保DPL数值上大于等于CPL,防止低特权级程序通过这些指令访问高特权级代码。对于硬件产生的中断和处理器检测到的异常,门描述符的DPL不用被检查。 534 | 535 | ## Task Management 536 | 537 | ### Overview 538 | 539 | 任务是处理器可以分派、执行和挂起的工作单位 540 | 541 | 任务由两部分组成: 542 | 543 | * 任务执行空间:代码段、栈段和数据段 544 | * 任务状态段(TSS) 545 | 546 | ![image-20211001102031293](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211001102031293.png) 547 | 548 | ### Executing a Task 549 | 550 | Software or the processor can dispatch a task for execution in one of the following ways: 551 | 552 | * A explicit call to a task with the CALL instruction.(task gate or tss) 553 | * A explicit jump to a task with the JMP instruction.(task gate or tss) 554 | * An implicit call (by the processor) to an interrupt-handler or exception-handler task.(task gate) 555 | * A return (initiated with an IRET instruction) when the NT flag in the EFLAGS register is set. 556 | 557 | ### Task management data structure 558 | 559 | 处理器根据五项数据结构来处理和任务有关的活动 560 | 561 | 在保护模式下,对于一个任务来说,TSS和TSS descriptor是必要的,且指向TSS descriptor的选择符需要加载到TR寄存器中。 562 | 563 | #### Task-state segment 564 | 565 | ![image-20211001103053778](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211001103053778.png) 566 | 567 | TSS的域被分为两个主要的部分: 568 | 569 | * dynamic field:任务切换时进行更新 570 | * 通用寄存器 571 | * 段选择符 572 | * EFLAGS 573 | * EIP 574 | * Previous Task Link 575 | * static field:任务切换时不进行更新,在任务创建时设置 576 | * LDT segment selector field 577 | * CR3 578 | * 不同特权级的堆栈 579 | * T flag 580 | * IO 位图 581 | * SSP 582 | 583 | #### TSS descriptor 584 | 585 | ![image-20211001105634078](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211001105634078.png) 586 | 587 | **TSS描述符只能放在GDT中,不能放在LDT或IDT中** 588 | 589 | 当G=0,段界限必须等于或大于0x67(比TSS最小长度少1),访问一个段界限小于0x67的TSS会触发无效TSS异常。 590 | 591 | 任何CPL数值上小于等于DPL的程序可以通过call或jump分配任务,RPL不检查。 592 | 593 | #### Task register 594 | 595 | 保存TSS的段选择符,分为两部分 596 | 597 | * 可见部分:TSS段选择符 598 | * 不可见部分:TSS段描述符 599 | 600 | ![image-20211001110149991](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211001110149991.png) 601 | 602 | #### Task-gate descriptor 603 | 604 | ![image-20211001110233051](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211001110233051.png) 605 | 606 | 可以被放置在GDT、LDT或IDT中,其中的TSS段选择符指向一个GDT中的TSS描述符。 607 | 608 | 当call或jump指令操作数为任务门描述符时,CPL和任务门选择符的RPL需要数值上都小于等于任务门的DPL,TSS的DPL不检查。 609 | 610 | ![image-20211001111240074](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211001111240074.png) 611 | 612 | #### NT flag in EFLAGS register 613 | 614 | ### Task Switching 615 | 616 | The processor performs the following operations when switching to a new task: 617 | 618 | 1. Obtains the TSS segment selector for the new task as the operand of the JMP or CALL instruction, from a task gate, or from the previous task link field (for a task switch initiated with an IRET instruction). 619 | 620 | 2. Checks that the current (old) task is allowed to switch to the new task. Data-access privilege rules apply to JMP and CALL instructions. The CPL of the current (old) task and the RPL of the segment selector for the new task must be less than or equal to the DPL of the TSS descriptor or task gate being referenced. Exceptions, interrupts (except for those identified in the next sentence), and the IRET and INT1 instructions are permitted to switch tasks regardless of the DPL of the destination task-gate or TSS descriptor. For interrupts generated by the INT *n*, INT3, and INTO instructions, the DPL is checked and a general-protection exception (#GP) results if it is less than the CPL.1 621 | 622 | 3. Checks that the TSS descriptor of the new task is marked present and has a valid limit (greater than or equal to 67H). If the task switch was initiated by IRET and shadow stacks are enabled at the current CPL, then the SSP must be aligned to 8 bytes, else a #TS(current task TSS) fault is generated. If CR4.CET is 1, then the TSS must be a 32 bit TSS and the limit of the new task’s TSS must be greater than or equal to 107 bytes, else a #TS(new task TSS) fault is generated. 623 | 624 | 4. Checks that the new task is available (call, jump, exception, or interrupt) or busy (IRET return). 625 | 626 | 5. Checks that the current (old) TSS, new TSS, and all segment descriptors used in the task switch are paged into system memory. 627 | 628 | 6. Saves the state of the current (old) task in the current task’s TSS. The processor finds the base address of the current TSS in the task register and then copies the states of the following registers into the current TSS: all the general-purpose registers, segment selectors from the segment registers, the temporarily saved image of the EFLAGS register, and the instruction pointer register (EIP). 629 | 630 | 7. Loads the task register with the segment selector and descriptor for the new task's TSS. 631 | 8. The TSS state is loaded into the processor. This includes the LDTR register, the PDBR (control register CR3), the EFLAGS register, the EIP register, the general-purpose registers, and the segment selectors. A fault during the load of this state may corrupt architectural state. (If paging is not enabled, a PDBR value is read from the new task's TSS, but it is not loaded into CR3.) 632 | 9. If the task switch was initiated with a JMP or IRET instruction, the processor clears the busy (B) flag in the current (old) task’s TSS descriptor; if initiated with a CALL instruction, an exception, or an interrupt: the busy (B) flag is left set. (See Table 7-2.) 633 | 10. If the task switch was initiated with an IRET instruction, the processor clears the NT flag in a temporarily saved image of the EFLAGS register; if initiated with a CALL or JMP instruction, an exception, or an interrupt, the NT flag is left unchanged in the saved EFLAGS image. 634 | 11. If the task switch was initiated with a CALL instruction, an exception, or an interrupt, the processor will set the NT flag in the EFLAGS loaded from the new task. If initiated with an IRET instruction or JMP instruction, the NT flag will reflect the state of NT in the EFLAGS loaded from the new task (see Table 7-2). 635 | 12. If the task switch was initiated with a CALL instruction, JMP instruction, an exception, or an interrupt, the processor sets the busy (B) flag in the new task’s TSS descriptor; if initiated with an IRET instruction, the busy (B) flag is left set. 636 | 13. The descriptors associated with the segment selectors are loaded and qualified. Any errors associated with this loading and qualification occur in the context of the new task and may corrupt architectural state. 637 | 14. Begins executing the new task. (To an exception handler, the first instruction of the new task appears not to have been executed.) 638 | 639 | ### Task Linking 640 | 641 | call指令,中断和异常导致的任务切换,处理器会设置新任务的NT位以及TSS的previous task link位。 642 | 643 | jmp指令导致的任务切换,previous task link域不修改 644 | 645 | ![image-20211001113735018](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211001113735018.png) 646 | 647 | ## Reference 648 | 649 | Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3 (3A, 3B, 3C & 3D): System Programming Guide 650 | 651 | -------------------------------------------------------------------------------- /source/Linuxv0.11_read.md: -------------------------------------------------------------------------------- 1 | ## Boot 2 | 3 | ## Main 4 | 5 | ## Reference 6 | -------------------------------------------------------------------------------- /source/_static/week1/image-20210912102241118.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codefuturedalao/whu_os_ex_2021/3c834df5673f4714feab54f9483dd4ef922879f7/source/_static/week1/image-20210912102241118.png -------------------------------------------------------------------------------- /source/_static/week1/image-20210912102242723.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codefuturedalao/whu_os_ex_2021/3c834df5673f4714feab54f9483dd4ef922879f7/source/_static/week1/image-20210912102242723.png -------------------------------------------------------------------------------- /source/_static/week1/image-20210912103906024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codefuturedalao/whu_os_ex_2021/3c834df5673f4714feab54f9483dd4ef922879f7/source/_static/week1/image-20210912103906024.png -------------------------------------------------------------------------------- /source/_static/week1/image-20210912104110438.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codefuturedalao/whu_os_ex_2021/3c834df5673f4714feab54f9483dd4ef922879f7/source/_static/week1/image-20210912104110438.png -------------------------------------------------------------------------------- /source/_static/week1/image-20210912105353051.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codefuturedalao/whu_os_ex_2021/3c834df5673f4714feab54f9483dd4ef922879f7/source/_static/week1/image-20210912105353051.png -------------------------------------------------------------------------------- /source/_static/week1/image-20210912105457100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codefuturedalao/whu_os_ex_2021/3c834df5673f4714feab54f9483dd4ef922879f7/source/_static/week1/image-20210912105457100.png -------------------------------------------------------------------------------- /source/_static/week1/image-20210912105650873.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codefuturedalao/whu_os_ex_2021/3c834df5673f4714feab54f9483dd4ef922879f7/source/_static/week1/image-20210912105650873.png -------------------------------------------------------------------------------- /source/_static/week1/image-20210912105927574.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codefuturedalao/whu_os_ex_2021/3c834df5673f4714feab54f9483dd4ef922879f7/source/_static/week1/image-20210912105927574.png -------------------------------------------------------------------------------- /source/_static/week1/image-20210912110042298.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codefuturedalao/whu_os_ex_2021/3c834df5673f4714feab54f9483dd4ef922879f7/source/_static/week1/image-20210912110042298.png -------------------------------------------------------------------------------- /source/_static/week1/image-20210912111303132.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codefuturedalao/whu_os_ex_2021/3c834df5673f4714feab54f9483dd4ef922879f7/source/_static/week1/image-20210912111303132.png -------------------------------------------------------------------------------- /source/_static/week1/image-20210912114908328.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codefuturedalao/whu_os_ex_2021/3c834df5673f4714feab54f9483dd4ef922879f7/source/_static/week1/image-20210912114908328.png -------------------------------------------------------------------------------- /source/about.md: -------------------------------------------------------------------------------- 1 | # This is about 2 | 3 | ## hello everyone -------------------------------------------------------------------------------- /source/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | # import os 14 | # import sys 15 | # sys.path.insert(0, os.path.abspath('.')) 16 | 17 | 18 | # -- Project information ----------------------------------------------------- 19 | 20 | project = 'OsEx2021' 21 | copyright = '2021, jacksonsang' 22 | author = 'jacksonsang' 23 | 24 | # The full version, including alpha/beta/rc tags 25 | release = 'v1' 26 | 27 | 28 | # -- General configuration --------------------------------------------------- 29 | 30 | # Add any Sphinx extension module names here, as strings. They can be 31 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 32 | # ones. 33 | extensions = [ 34 | 'sphinxemoji.sphinxemoji', 35 | 'myst_parser', 36 | ] 37 | 38 | sphinxemoji_style = 'twemoji' 39 | 40 | # Add any paths that contain templates here, relative to this directory. 41 | templates_path = ['_templates'] 42 | 43 | # The language for content autogenerated by Sphinx. Refer to documentation 44 | # for a list of supported languages. 45 | # 46 | # This is also used if you do content translation via gettext catalogs. 47 | # Usually you set "language" from the command line for these cases. 48 | language = 'zh_CN' 49 | 50 | # List of patterns, relative to source directory, that match files and 51 | # directories to ignore when looking for source files. 52 | # This pattern also affects html_static_path and html_extra_path. 53 | exclude_patterns = [] 54 | 55 | 56 | # -- Options for HTML output ------------------------------------------------- 57 | 58 | # The theme to use for HTML and HTML Help pages. See the documentation for 59 | # a list of builtin themes. 60 | # 61 | html_theme = 'sphinx_rtd_theme' 62 | 63 | # Add any paths that contain custom static files (such as style sheets) here, 64 | # relative to this directory. They are copied after the builtin static files, 65 | # so a file named "default.css" will overwrite the builtin "default.css". 66 | html_static_path = ['_static'] 67 | -------------------------------------------------------------------------------- /source/index.md: -------------------------------------------------------------------------------- 1 | # OS_EX Tutorial 2 | 3 | ```{toctree} 4 | --- 5 | maxdepth: 2 6 | caption: 课程概述 7 | --- 8 | 9 | intro 10 | 11 | ``` 12 | 13 | ```{toctree} 14 | --- 15 | maxdepth: 1 16 | caption: 进度计划 17 | --- 18 | 19 | week1 20 | week2 21 | week3 22 | week4 23 | week5 24 | week6 25 | week7 26 | week8 27 | week9 28 | week10 29 | week11 30 | week12 31 | 32 | 33 | ``` 34 | 35 | ```{toctree} 36 | --- 37 | maxdepth: 1 38 | caption: 参考资料 39 | --- 40 | 41 | ref 42 | 43 | ``` 44 | -------------------------------------------------------------------------------- /source/intro.md: -------------------------------------------------------------------------------- 1 | ## 课程目标 2 | 3 | * 配套《操作系统原理》课程,实践操作 4 | 系统原理 5 | * 实践操作系统设计中的主要安全技术 6 | * 掌握x86架构操作系统的基本实现技术 7 | 8 | ## 课程组织形式 9 | 10 | * 总学时数:2学分,1—12周,12周 11 | * 时间: 12 | - 每周四晚上:18:00——21:00 B310 13 | - 每周五上午:8:50——12:15 14 | * 分组安排,分组完成报告,每个小组不超过4 15 | 人。 16 | * 教辅:桑乾龙,QQ:985438046 17 | 18 | 19 | ## 课程内容 20 | 21 | 课程分为两部分: 22 | * 操作系统设计实践(主,课内时间为主) 23 | - 以x86架构为对象,开展操作系统的设计实验 24 | * 操作系统安全实践(辅,课下时间为主) 25 | - 以本课程所实现的模拟OS为对象,对安全性进行改造分析实验 26 | 27 | 28 | ## 课程教材 29 | 30 | * Orange’s 一个操作系统的实现,于渊,电子工 31 | 业出版社,2008年 – 获取形式:Kindle 32 | - 随书源码:[https://github.com/yyu/](https://github.com/yyu/osfs00) 33 | * 可参考的资料 34 | - [Intel® 64 and IA-32 Architectures Software Developer Manuals, Intel Press](https://software.intel.com/content/www/us/en/develop/articles/intel-sdm.html) (阅读需要一定基础) 35 | - [清华大学,操作系统教程](https://chyyuu.gitbooks.io/ucore_os_docs/) 36 | 37 | 38 | ## 考核方式 39 | 40 | 1. 实验状况与考勤:20% 41 | - 每人本学期会被随堂抽查2--3次,对老师提出问题进行回答。 42 | - 每次记录考勤,三次不到,记为缺课,直接重修。 43 | - 有特殊情况,办理请假手续,学工办签字盖章。 44 | - 每次做完本次实验方可离开实验室,不得早退 45 | - 不得在上课时间做与本课无关事情(包括玩手机、闲聊、浏览与课程无关网页、完成其他课程作业等),一旦发现扣分处理! 46 | 47 | 2. 实验报告:40%,本学期继续分组! 48 | - 实验报告:每组完成每个实验后,提交一份实验报告,必须提交电子版:A4格式,不需要纸板。 49 | - 格式参考模版,内容包括:实验目的、实验环境、关键技术、设计与实验过程、测试过程与测试结果、小结与分析、小组同学承担任务分工与个人心得 **(每个人会有单独评分!!!)** 50 | - 提交时间节点: 51 | - 电子版:每次实验课程上课前,提交上周实验报告,由课代表收齐交给教辅。 52 | - 非特殊原因,逾期视为未交 53 | 54 | 3. 课下实验:20%,纸板+电子版 55 | - 针对期末布置的课下实验,进行选做,本学期结束前按照规定时间提交。 56 | 4. 课程期末报告:20%,纸板+电子版 57 | - 在学期末,每人以本学期所学技术进行综合,自行组合知识点,完成一个操作系统综合设计实验,并提交个人学期操作系统安全综合实验报告。 58 | - 该报告需要通过老师/教辅的答辩检查。 59 | - 题目必须与本课程紧密相关 60 | - 对象不局限于x86平台 61 | - 不允许一作业多投,不允许雷同! 62 | 63 | ```{caution} 64 | 65 | 抄袭是道德问题,一旦发现后果很严重! 66 | ``` 67 | -------------------------------------------------------------------------------- /source/missing_detail.md: -------------------------------------------------------------------------------- 1 | ## Why [0x0000fffffff0] f000:fff0 instead of ffff:0000? 2 | 3 | ![image-20210923123532962](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210923123532962.png) 4 | 5 | 以上是计算机加电执行的第一条指令,在该行的左侧,显示了该指令所在的物理内存地址,该地址是用方括号围起来的,你可能会想,他怎么会是0x0000FFFFFFF0呢? 6 | 7 | 8086有20根地址线,加电启动后,代码段寄存器CS的内容为0xFFFF,指令指针寄存器IP的内容为0x0000,因此第一条指令的物理地址是20位的0xFFFF0。但是8086已经成为历史,它之后的处理器都能够兼容8086的功能,但却拥有超过32根的地址线。在当前的这个Bochs虚拟机上,地址线的数量就是32根,bochs在这里用48位的宽度来显示物理地址,但是它的值应该是0x0000000FFFF0,不是吗? 8 | 9 | 事情是这样的,和8086不同,现代处理器在加电启动时,段寄存器CS的内容位0xF000,指令指针寄存器IP的内容位0xFFF0,这就是的处理器地址线的低20位同样是0xFFFF0。这还不算完,在刚刚启动时,处理器将其余的(高位部分)地址线强制为高电平,直到遇到并执行了第一个段间指令。因为当前bochs的地址线位32根,所以,初始发出的物理地址内存地址就是0x0000FFFFFFF0了。 10 | 11 | 之所以这样做,是因为处理器的设计者希望把ROM-BIOS放到4GB(32地址线可选值范围为4GB)的最高端,这样,4GB以下,连同传统的地段1MB都是连续的RAM区,连续的、不间断的RAM能为操作系统管理内存带来方便。 12 | 13 | 问题在于,计算机制造商们会考虑很多现实问题。老的硬件和软件依赖于地段1MB的ROM-BIOS来工作,**这涉及到兼容性**。最终,这两个地址区段都指向同一块ROM芯片。 14 | 15 | ## Why 0x7c00? 16 | 17 | [阮一峰网络日志:为什么主引导记录的内存地址是0x7C00?](http://www.ruanyifeng.com/blog/2015/09/0x7c00.html) 18 | 19 | ## Why 0100h in com 20 | 21 | ## Why we need rpl? 22 | 23 | ## How does BIOS establish IVT? 24 | 25 | 你可能会奇怪,BIOS如何建立起低地址1KB的中断向量表和相应的中断例程?它又是怎么知道访问硬件的?毕竟,即使是它,要访问硬件也要通过端口一级的途径。 26 | 27 | 答案是,BIOS可能会为一些简单的外围设备提供初始化代码和功能调用代码,并填写中断向量表,但也有一些BIOS中断是由外部设备接口自己建立的。 28 | 29 | 首先,每个外部设备接口,包括各种板卡,如网卡、显卡、键盘接口电路、硬件控制器等,都有自己的只读存储器(ROM),类似于BIOS芯片,这些ROM提供了他自己的功能例程,以及本设备的初始化代码。按照规范,前两个单元的内容是0x55和0xAA,第三个单元是本ROM中以512字节为单位的代码长度;从第四个单元开始,就是实际的ROM代码。 30 | 31 | 其次,我们知道,从内存物理地址A0000开始,到FFFFF结束,有相当一部分空间是留给外围设备的,如果设备存在,那么,它自带的ROM会映射到分配给它的地址范围内。在计算机启动期间,BIOS程序会以2KB为单位搜索内存地址C0000~E0000之间的区域。当他发现某个区域的头两个字节是0x55和0xAA时,那意味着该区域有ROM代码存在,是有效的。接着对该区域做累加和检查,看结果是否和第三个单元相符,如果相符,则从第四个单元进入。这是处理器执行的是硬件自带的程序指令,这些指令初始化外部设备的相关寄存器和工作状态,最后,填写相关的中断向量表,使他们指向自带的中断处理过程。 32 | 33 | ![image-20210923115930672](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210923115930672.png) 34 | 35 | 详情参考:[https://en.wikipedia.org/wiki/BIOS](https://en.wikipedia.org/wiki/BIOS) -------------------------------------------------------------------------------- /source/nasm_tutorial.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | nasm是一个x86架构的汇编器,支持一系列目标文件格式,如a.out、elf、obj、COFF等。 4 | 5 | ## Running Nasm 6 | 7 | 如果想要汇编一个文件,命令格式如下: 8 | 9 | ```shell 10 | nasm -f [-o ] 11 | ``` 12 | 13 | 比如想要将myfile.asm汇编为ELF格式的目标文件,可以使用以下命令: 14 | 15 | ```shell 16 | nasm -f elf myfile.asm -o myfile.elf 17 | ``` 18 | 19 | 当不指定目标文件类型时,默认生成bin格式的目标文件。因此可以简单的使用```nasm boot.asm -o boot.bin```命令,即可生成boot.bin文件。(其实还可以更简单,当不指定目标文件名称时,nasm会去掉源文件名的后缀作为目标文件名,即生成boot文件) 20 | 21 | ### -i选项:包含文件搜索目录 22 | 23 | 当NASM看到````%include```或```%pathsearch```命令时,除了会在当前目录下搜索,也会在-i选项指定的目录下搜索文件,因此可以包含一些文件作为库文件。例如: 24 | 25 | ```shell 26 | nasm -ic:\macrolib\ -f obj myfile.asm 27 | ``` 28 | 29 | ### -p选项:预包含一个文件 30 | 31 | 使用-p选项,等同于将%include命令放置在文件头 32 | 33 | 例如: 34 | 35 | ```shell 36 | nasm myfile.asm -p myinc.inc 37 | ``` 38 | 39 | 等同于```nams myfile.asm```,同时将```%include "myinc.inc"```放在文件最开始 40 | 41 | ### -d选项:预定义宏 42 | 43 | 使用-d选项,等同于将%define命令放置在文件头 44 | 45 | ### NASM的几个要点 46 | 47 | 1. 大小写敏感 48 | 49 | 2. 访问内存中数据时需要加上方括号,否则统一视为地址 50 | 51 | 3. 不存储变量类型 52 | 53 | 有些汇编器将变量名加冒号视为标签,不加冒号视为变量,同时并自动记忆变量类型,对于这种类型的汇编器,一下汇编指令是正确的 54 | 55 | ```assembly 56 | var dw 0 57 | .... 58 | mov var, 2 59 | ``` 60 | 61 | 但是nasm中只记忆var的地址信息,并不记忆其类型,因此需要显式地指出其类型,如```mov word [var], 2```。 62 | 63 | 4. 没有assume命令 64 | 65 | 5. 不支持内存模型 66 | 67 | 代码编写人员需要自己明确什么时候使用far call,是么使用使用near call,同时正确使用ret和retf指令。 68 | 69 | ## NASM Language 70 | 71 | 通常nasm每一行包含以下要素 72 | 73 | ```assembly 74 | label: instruction operands ; comment 75 | ``` 76 | 77 | 通常来说,上面的域均为可选的,有时候可以没有标签和评论,对于一些指令也不需要有操作数。 78 | 79 | 在nasm,标签后面的冒号是可选的,如果你不小心将lodsb指令写为lodab,nasm会将其视为一个标签而不会报错。 80 | 81 | nasm中标识符(即变量名)可以由字母,数字,`_`, `$`, `#`, `@`, `~`, `.` 和`?`组成,只有数字、.、下划线和问好可以作为首字母,标识符最大长度为4095个字符。 82 | 83 | ### 伪指令 84 | 85 | 伪指令并不是真正的x86机器指令,而是为了方便使用由汇编器自定义的指令。 86 | 87 | nasm中的伪指令包括`DB`, `DW`, `DD`, `DQ`, `DT`, `DO`, `DY` 和 `DZ`; `RESB`, `RESW`, `RESD`, `RESQ`, `REST`, `RESO`, `RESY`和`RESZ`; `INCBIN,EQU`和 `TIMES` 。 88 | 89 | #### Dx:声明初始化的数据 90 | 91 | 他们可以用以下方式使用 92 | 93 | ```assembly 94 | db 0x55 ; just the byte 0x55 95 | db 0x55,0x56,0x57 ; three bytes in succession 96 | db 'a',0x55 ; character constants are OK 97 | db 'hello',13,10,'$' ; so are string constants 98 | dw 0x1234 ; 0x34 0x12 99 | dw 'a' ; 0x61 0x00 (it's just a number) 100 | dw 'ab' ; 0x61 0x62 (character constant) 101 | dw 'abc' ; 0x61 0x62 0x63 0x00 (string) 102 | dd 0x12345678 ; 0x78 0x56 0x34 0x12 103 | dd 1.234567e20 ; floating-point constant 104 | dq 0x123456789abcdef0 ; eight byte constant 105 | dq 1.234567e20 ; double-precision float 106 | dt 1.234567e20 ; extended-precision float 107 | ``` 108 | 109 | #### RESx:声明未初始化的数据 110 | 111 | RESx命令用于BSS section中,声明未初始化的存储空间,例子如下: 112 | 113 | ```assembly 114 | buffer: resb 64 ; reserve 64 bytes 115 | wordvar: resw 1 ; reserve a word 116 | realarray resq 10 ; array of ten reals 117 | ymmval: resy 1 ; one YMM register 118 | zmmvals: resz 32 ; 32 ZMM registers 119 | ``` 120 | 121 | nasm 2.15版本后开始支持masm的语法?和DUP,因此可以用一下命令实现同样的效果 122 | 123 | ```assembly 124 | buffer: db 64 dup (?) ; reserve 64 bytes 125 | wordvar: dw ? ; reserve a word 126 | realarray dq 10 dup (?) ; array of ten reals 127 | ymmval: dy ? ; one YMM register 128 | zmmvals: dz 32 dup (?) ; 32 ZMM registers 129 | ``` 130 | 131 | #### INCBIN:包含外部二进制文件 132 | 133 | #### EQU:定义常量 134 | 135 | EQU给指定的符号赋值常量,例子: 136 | 137 | ```assembly 138 | message db 'hello, world' 139 | msglen equ $-message 140 | ``` 141 | 142 | #### TIMES:重复指令或数据 143 | 144 | 指令格式为```times expression data/inst```,例子如下 145 | 146 | ```assembly 147 | zerobuf: times 64 db 0 148 | 149 | 150 | buffer: db 'hello, world' 151 | times 64-$+buffer db ' ' 152 | 153 | times 100 movsb 154 | ``` 155 | 156 | ### 有效地址(effective addresses) 157 | 158 | effective address是指令中指向内存的操作数,在nasm中,有效地址被放在方括号内。例子如下: 159 | 160 | ```assembly 161 | wordvar dw 123 162 | mov ax,[wordvar] 163 | mov ax,[wordvar+1] 164 | mov ax,[es:wordvar+bx] 165 | ``` 166 | 167 | ### 常量(Constant) 168 | 169 | #### 数值常量 170 | 171 | 通过加后缀H/X,D/T,Q/O,B/Y来表示十六进制、十进制、八进制和二进制。或者可以通过加0x/0h前缀来表示十六进制、0d/ot表示十进制,0o/0q表示八进制以及0b/0y表示二进制。例子如下: 172 | 173 | ```assembly 174 | mov ax,200 ; decimal 175 | mov ax,0200 ; still decimal 176 | mov ax,0200d ; explicitly decimal 177 | mov ax,0d200 ; also decimal 178 | mov ax,0c8h ; hex 179 | mov ax,$0c8 ; hex again: the 0 is required 180 | mov ax,0xc8 ; hex yet again 181 | mov ax,0hc8 ; still hex 182 | mov ax,310q ; octal 183 | mov ax,310o ; octal again 184 | mov ax,0o310 ; octal yet again 185 | mov ax,0q310 ; octal yet again 186 | mov ax,11001000b ; binary 187 | mov ax,1100_1000b ; same binary constant 188 | mov ax,1100_1000y ; same binary constant once more 189 | mov ax,0b1100_1000 ; same binary constant yet again 190 | mov ax,0y1100_1000 ; same binary constant yet again 191 | ``` 192 | 193 | #### 字符常量 194 | 195 | 在nasm中单引号和双引号没有区别 196 | 197 | ### SEG和WRT 198 | 199 | 当程序具有多个段时,可以用seg来获取标签的段地址,标签本身代表其偏移地址。 200 | 201 | 当多个段出现重叠时,wrt用于获取标签相对指定段的偏移地址。 202 | 203 | ### Critical Expressions 204 | 205 | ### 局部标签 206 | 207 | 以点号开头的标签为局部标签,他和之前非局部标签联系在一起。 208 | 209 | ## The Nasm Preprocessor 210 | 211 | #### Single-Line Macros 212 | 213 | 以%开头,字符\表示多行 214 | 215 | 可以重载有参数的宏,不能重载无参数的宏,大小写敏感,具有防递归调用的机制 216 | 217 | =号用于计算值 218 | 219 | &号用于转换为字符串 220 | 221 | +号用于可变参数 222 | 223 | %idefine不区分大小写 224 | 225 | 226 | 227 | #### Multi-line Macros:%macro 228 | 229 | ```assembly 230 | %macro prologue 1 231 | 232 | push ebp 233 | mov ebp,esp 234 | sub esp,%1 235 | 236 | %endmacro 237 | ``` 238 | 239 | 宏名后面跟参数的数量,使用%加数字来引用参数 -------------------------------------------------------------------------------- /source/ref.md: -------------------------------------------------------------------------------- 1 | ## IA-32 Manual summary (doing) 2 | 3 | 4 | ```{toctree} 5 | --- 6 | maxdepth: 1 7 | --- 8 | 9 | 10 | IA32_manual 11 | 12 | ``` 13 | 14 | ## NASM tutorial (doing) 15 | 16 | ```{toctree} 17 | --- 18 | maxdepth: 1 19 | --- 20 | 21 | nasm_tutorial 22 | 23 | ``` 24 | 25 | ## Linux v0.11 source code reading (todo) 26 | 27 | ```{toctree} 28 | --- 29 | maxdepth: 1 30 | --- 31 | 32 | 33 | Linuxv0.11_read 34 | 35 | ``` 36 | 37 | 38 | ## Missing details (doing) 39 | 40 | ```{toctree} 41 | --- 42 | maxdepth: 1 43 | --- 44 | 45 | missing_detail 46 | 47 | ``` 48 | 49 | -------------------------------------------------------------------------------- /source/requirements.txt: -------------------------------------------------------------------------------- 1 | myst_parser 2 | sphinxemoji 3 | -------------------------------------------------------------------------------- /source/week1.md: -------------------------------------------------------------------------------- 1 | # week1 2 | 3 | ## 实验内容 4 | 5 | 1. 认真阅读章节资料 6 | 7 | 2. 在实验机上安装虚拟运行环境,并安装ubuntu(实验室机器已安装,若需要可在自己笔记本电脑另行安装) 8 | 9 | 3. 安装ubuntu开发环境,32位环境 10 | 11 | 4. 下载bochs源码,编译并安装bochs环境 12 | 13 | 5. 使用bochs自带工具bximage创建虚拟软驱 14 | 15 | 6. 阅读、编译boot.asm,并反汇编阅读 16 | 17 | 7. 修改bochsrc,运行并调试你的第一个程序 18 | 19 | 8. 完成实验练习要求 20 | 21 | ## 实验步骤 22 | 23 | 1. 下载virtualbox或vmware 24 | 25 | 2. 下载32位ubuntu镜像文件并安装 26 | 27 | * [14.06](https://mirrors.163.com/ubuntu-releases/14.04/ubuntu-14.04.6-desktop-i386.iso) 28 | * [16.06](https://mirrors.163.com/ubuntu-releases/16.04/ubuntu-16.04.6-desktop-i386.iso) 29 | 30 | 3. 修改ubuntu源(可选) 31 | 32 | 1. 首先要清楚自己Ubuntu的版本信息 33 | 34 | 2. 搜索对应版本Ubuntu的apt源 35 | 36 | * Ubuntu16.04 apt源(阿里) 37 | 38 | ``` 39 | deb-src http://archive.ubuntu.com/ubuntu xenial main restricted #Added by software-properties 40 | deb http://mirrors.aliyun.com/ubuntu/ xenial main restricted 41 | deb-src http://mirrors.aliyun.com/ubuntu/ xenial main restricted multiverse universe #Added by software-properties 42 | deb http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted 43 | deb-src http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted multiverse universe #Added by software-properties 44 | deb http://mirrors.aliyun.com/ubuntu/ xenial universe 45 | deb http://mirrors.aliyun.com/ubuntu/ xenial-updates universe 46 | deb http://mirrors.aliyun.com/ubuntu/ xenial multiverse 47 | deb http://mirrors.aliyun.com/ubuntu/ xenial-updates multiverse 48 | deb http://mirrors.aliyun.com/ubuntu/ xenial-backports main restricted universe multiverse 49 | deb-src http://mirrors.aliyun.com/ubuntu/ xenial-backports main restricted universe multiverse #Added by software-properties 50 | deb http://archive.canonical.com/ubuntu xenial partner 51 | deb-src http://archive.canonical.com/ubuntu xenial partner 52 | deb http://mirrors.aliyun.com/ubuntu/ xenial-security main restricted 53 | deb-src http://mirrors.aliyun.com/ubuntu/ xenial-security main restricted multiverse universe #Added by software-properties 54 | deb http://mirrors.aliyun.com/ubuntu/ xenial-security universe 55 | deb http://mirrors.aliyun.com/ubuntu/ xenial-security multiverse 56 | ``` 57 | 58 | * Ubuntu14.04 apt源(阿里) 59 | 60 | ``` 61 | deb http://mirrors.aliyun.com/ubuntu/ trusty main restricted universe multiverse 62 | deb http://mirrors.aliyun.com/ubuntu/ trusty-security main restricted universe multiverse 63 | deb http://mirrors.aliyun.com/ubuntu/ trusty-updates main restricted universe multiverse 64 | deb http://mirrors.aliyun.com/ubuntu/ trusty-proposed main restricted universe multiverse 65 | deb http://mirrors.aliyun.com/ubuntu/ trusty-backports main restricted universe multiverse 66 | deb-src http://mirrors.aliyun.com/ubuntu/ trusty main restricted universe multiverse 67 | deb-src http://mirrors.aliyun.com/ubuntu/ trusty-security main restricted universe multiverse 68 | deb-src http://mirrors.aliyun.com/ubuntu/ trusty-updates main restricted universe multiverse 69 | deb-src http://mirrors.aliyun.com/ubuntu/ trusty-proposed main restricted universe multiverse 70 | deb-src http://mirrors.aliyun.com/ubuntu/ trusty-backports main restricted universe multiverse 71 | ``` 72 | 73 | 3. 修改/etc/apt/sources.list文件 74 | 75 | 4. bochs下载(源码下载) 76 | 77 | * 版本:2.6.9 78 | * 链接:[http://bochs.sourceforge.net/getcurrent.html](http://bochs.sourceforge.net/getcurrent.html) 79 | 80 | 5. 安装依赖库 81 | 82 | 需要安装build-essential、libx11-dev、libxrandr-dev、libsdl1.2-dev、vgabios、bximage,可在编译过程中发现 83 | 84 | ```shell 85 | sudo apt install build-essential libx11-dev libxrandr-dev libsdl1.2-dev vgabios bximage 86 | ``` 87 | 88 | 6. 编译和安装bochs 89 | 90 | 1. 配置 91 | 92 | 在bochs源码文件夹下运行命令```./configure --withsdl --enable-debugger --enable-disasm``` 93 | 94 | ```{admonition} 提示 95 | 96 | 如果运行该命令后出现warning: --enable-disasm xxxx这种警告,表示不需要加该参数,disasm模块已经默认设置好,继续下一步即可 97 | ``` 98 | 99 | 2. 安装 100 | 101 | 运行命令```sudo make``` 102 | 103 | 3. 下载 104 | 105 | 运行命令```sudo make install``` 106 | 107 | 7. 下载本书源码 108 | 109 | * QQ群内提供iso.gz文件 110 | 111 | * 直接从github上[下载](https://github.com/yyu/osfs00/blob/master/osfromscratch2010.iso.gz) 112 | 113 | ```{caution} 114 | 115 | 不建议在windows系统中提取出iso中的文件然后传入ubuntu中,原因是windwos和linux中换行符存在差异,导致跨系统文件有时不能正常工作。 116 | 117 | 建议在linux中挂载好iso后将文件拷贝出去,不要直接在挂载目录下运行,因为该iso为只读文件,会导致后续命令出现问题 118 | ``` 119 | 120 | 8. 修改源码文件中的bochsrc 121 | 122 | * 修改vgaromimage对应的文件位置,以你的实际安装位置为准 123 | 124 | * 注释掉keyboard_mapping一行 125 | 126 | * 增加display_library: sdl(某些linux下该项可选) 127 | 128 | 9. 制作可启动软盘 129 | 130 | 1. 编译源码 131 | 132 | ```shell 133 | nasm boot.asm –o boot.bin 134 | ``` 135 | 136 | 2. 产生虚拟软驱 137 | 138 | ```shell 139 | bximage 140 | ``` 141 | 142 | 3. 写引导盘 143 | 144 | ```shell 145 | dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc 146 | ``` 147 | 148 | 10. 启动 149 | 150 | ```shell 151 | bochs –f ./bochsrc 152 | ``` 153 | 154 | ![image-20210912103906024](./_static/week1/image-20210912103906024.png) 155 | 156 | 在bochs中输入字符c,表示继续运行,此时可以看到"Hello , OS world" 157 | 158 | ![image-20210912104110438](_static/week1/image-20210912104110438.png) 159 | 160 | ```{admonition} 提示 161 | -f参数不是必须的,当你输入一个不带参数的的bochs命令时,bochs会在当前目录顺序寻找.bochsrc、bochsrc文件作为默认配置文件,详情请参考书上32页 162 | ``` 163 | 164 | ## 实验练习 165 | 166 | 1. 删除0xAA55,观察程序效果,找出原因 167 | 2. 修改程序中输出为,一个包含自己名字的字符串,调 168 | 试程序 169 | 3. 把生成的可执行文件反汇编,看看输出的内容是怎样 170 | 的,并在虚拟机启动过程,设置断点进行调试,在实 171 | 验报告中截图 172 | 4. 为什么要jmp $,如何改造程序,让这个输出过程执 173 | 行100次 174 | 5. 回答:为什么要对段寄存器进行赋值 175 | 6. 回答:如何在该程序中调用系统中断 176 | 177 | ## FAQ 178 | 179 | ### Q: apt安装一些包时产生依赖无法解决 180 | 181 | apt产生依赖报错一般是是源的问题,新手很容易出现源的版本和ubuntu版本不适配问题。检查步骤如下 182 | 183 | 命令行输入```lsb_release -a```命令,查看codename(以ubuntu14.04为例) 184 | 185 | ![image-20210912105927574](_static/week1/image-20210912105927574.png) 186 | 187 | 可以看到对应的code那么为trusty,查看/etc/apt/sources.list中对应的源版本,检查是否一致,如果为xenial说明使用了ubuntu16的apt源。 188 | 189 | ![image-20210912110042298](_static/week1/image-20210912110042298.png) 190 | 191 | ### Q: 如何在虚拟机和宿主机之间传递文件 192 | 193 | 1. 共享文件夹(需要自己摸索) 194 | 2. 邮件传递 195 | 3. 使用相关网站如[奶牛快传](https://cowtransfer.com/),在主机中上传文件,在虚拟机中下载文件 196 | 197 | ### Q: 安装bochs源码时迟迟未弹出下载窗口 198 | 199 | 由于网络的问题,在sourceforge下载bochs源码时确实需要等待一段时间,请耐心等候30秒。 200 | 201 | 30秒已过你有点等不及了,可以使用wget命令,直接在命令行中输入``` wget https://sourceforge.net/projects/bochs/files/bochs/2.6.9/bochs-2.6.9.tar.gz```进行下载 202 | 203 | ### Q: 如何找到vgaromimage和romimage的对应文件位置 204 | 205 | 使用find命令在根目录下寻找文件"BIOS-bochs-latest"和"vgabios.bin"文件。 206 | 207 | ![image-20210912105353051](_static/week1/image-20210912105353051.png) 208 | 209 | 将结果写入bochsrc中 210 | 211 | ![image-20210912105650873](_static/week1/image-20210912105650873.png) 212 | 213 | ### Q: tar.gz、gz、iso这些文件要怎么用 214 | 215 | 对于使用命令行的同学,我相信你已经熟悉linux了,这些知识谷歌一下就出来了。 216 | 217 | 对于使用图形化界面的同学,就更为简单了,tar.gz和gz都是压缩包,右键点击文件解压缩即可,iso文件需要挂在到linux中,同样右键点击文件挂载(mount)即可。 218 | 219 | ### Q: bochs报错cannot open rom image file xxxx 220 | 221 | ![image-20210912111303132](_static/week1/image-20210912111303132.png) 222 | 223 | 很简单,请检查romimage路径是否正确。 224 | 225 | ### Q: bochs报错cpu directive malformed 226 | 227 | ![image-20210912114908328](_static/week1/image-20210912114908328.png) 228 | 229 | 很有可能是因为在bochs-2.6.9的源码目录下直接运行了bochs,请到本书配套源码的目录下运行bochs,并修改好bochsrc,以及使用```-f```指定bochsrc的位置。 230 | -------------------------------------------------------------------------------- /source/week2.md: -------------------------------------------------------------------------------- 1 | # week2 2 | 3 | ## 实验内容 4 | 5 | 1. 认真阅读章节资料,掌握什么是保护模式,弄清关键数据结构:GDT、descriptor、selector、GDTR, 及其之间关系,阅读pm.inc文件中数据结构以及含义,写出对宏Descriptor的分析 6 | 7 | 2. 调试代码,/a/ 掌握从实模式到保护模式的基本方法,画出代码流程图,如果代码/a/中,第71行有dword前缀和没有前缀,编译出来的代码有区别么,为什么,请调试截图。 8 | 9 | 3. 调试代码,/b/,掌握GDT的构造与切换,从保护模式切换回实模式方法 10 | 11 | 4. 调试代码,/c/,掌握LDT切换 12 | 13 | 5. 调试代码,/d/掌握一致代码段、非一致代码段、数据段的权限访问规则,掌握CPL、DPL、RPL之间关系,以及段间切换的基本方法 14 | 15 | 6. 调试代码,/e/掌握利用调用门进行特权级变换的转移的基本方法 16 | 17 | ## 实验步骤 18 | 19 | ### 配置环境 20 | 21 | 1. 运行命令```dd if=pmtest1.bin of=a.img bs=512 count=1 conv=notrunc```将pmtest1.bin写入a.img,然后启动bochs,查看结果,可以看到界面右侧出现红色p 22 | 23 | ![image-20210917145432463](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210917145432463.png) 24 | 25 | 2. 下载[freedos](http://bochs.sourceforge.net/guestos/freedos-img.tar.gz),将解压后的a.img命名为freedos.img,复制到工作目录下(linux中命令行重命名命令为mv) 26 | 27 | 3. 用bximage生成一个软盘映像,起名为pm.img 28 | 29 | 4. 修改bochsrc,确保有以下三行。我们来解释一下,这三行说明我们有两个软盘,分别是freedos.img和pm.img,我们将从a盘也就是floppya启动,floppyb会自动成为b盘。 30 | 31 | ![image-20210917145903441](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210917145903441.png) 32 | 33 | 5. 启动bochs。 34 | 35 | ![image-20210917150004023](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210917150004023.png) 36 | 37 | 6. 输入```format b:```格式化B盘,B盘其实就是我们的pm.img镜像文件 38 | 39 | ![image-20210917150137783](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210917150137783.png) 40 | 41 | 格式化操作相当于将其转化为FAT16文件系统,当我们到terminal查看pm.img内容时,可以看到pm.img中已经写入了一些文件系统相关的东西,不再是那个全为0的它了。 42 | 43 | ![image-20210917150538255](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210917150538255.png) 44 | 45 | 7. 修改pmtest1.asm代码中的```07c00h```为```0100h``` 46 | 47 | ![image-20210917150659111](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210917150659111.png) 48 | 49 | 8. 输入命令```nasm pmtest1.asm -o pmtest1.com```将pmtest1.asm编译为com文件 50 | 51 | 9. 挂载pm.img,并将生成的pmtest.com拷贝到软盘中 52 | 53 | ``` 54 | sudo mkdir /mnt/floppy 55 | sudo mount -o loop pm.img /mnt/floppy 56 | sudo cp pmtest1.com /mnt/floppy/ 57 | sudo umount /mnt/floppy 58 | ``` 59 | 60 | 10. 重新启动bochs,在freedos中运行命令,可以看到界面右侧出现红色字母p 61 | 62 | ![image-20210917151405604](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210917151405604.png) 63 | 64 | 由于pmtest1中的```jmp $```,你会看到程序未将控制权交还给freedos,不用担心,后面你会看到如何将控制权交还给freedos。 65 | 66 | ### 升级装备 67 | 68 | 现在休息一下,可以喝口水什么的。 69 | 70 | 你可能发现由于我们不知道freedos把程序加载到了哪里,所以在哪里打断点来进行调试对于我们来说非常棘手😔,这里推荐查看一下FAQ中的how to debug in freedos。 71 | 72 | 现在假设你已经已经知道了如何调试,那么我们后面的任务无非就是在想要打断点的位置加上```xchg bx, bx```,然后启动bochs进行调试即可。 73 | 74 | 实验的时候,我们需要改动pmtest中的代码,然后汇编、挂载pm.img、拷贝、取消挂载以及启动bochs,这几个重复且枯燥的动作让人心疲力竭,于是这里提供一个简单的脚本,可能可以节省一下我们的时间。(直接使用makefile也可以实现同样的效果) 75 | 76 | ```shell 77 | #!/bin/sh 78 | 79 | # Author : jackson sang 80 | # toy script 81 | 82 | sudo mount pm.img -o loop /mnt/floppy 83 | for f in *.asm; 84 | do 85 | nasm "${f}" -o "${f%.asm}.com" 86 | if [ $? -ne 0 ]; 87 | then 88 | sudo umount /mnt/floppy 89 | echo "Failed to assemble!!!" 90 | exit 1 91 | fi 92 | sudo cp "${f%.asm}.com" /mnt/floppy 93 | rm "${f%.asm}.com" 94 | done 95 | 96 | sudo umount /mnt/floppy 97 | bochs 98 | ``` 99 | 100 | 上面代码的作用就是将当前文件夹下所有的汇编文件编译为com文件,然后写入pm.img,最后启动bochs。 101 | 102 | 如果你愿意使用的话,请新建一个build.sh文件,将上面代码拷贝进去,然后使用```sudo chmod +x build.sh```命令使build.sh可执行,之后每次修改完汇编文件,使用命令```./build.sh```即可启动bochs了。 103 | 104 | ### 课后实验 105 | 106 | ```{admonition} 提示 107 | 108 | 课后实验思路仅供参考,故尽可能减少示例图片的出现和文字描述。 109 | 110 | ``` 111 | 112 | #### 课后动手改1 113 | 114 | 1. 编写GDT代码段,写入内存内容 115 | 116 | ![image-20210917200414001](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210917200414001.png) 117 | 118 | 2. 编写LDT代码段,读取GDT内容并打印 119 | 120 | ![image-20210917200457485](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210917200457485.png) 121 | 122 | 3. 增加GDT代码段描述符,以及设置选择符 123 | 124 | 4. 增加LDT代码段描述符,以及设置选择符 125 | 126 | 5. 在实模式代码中初始化新增段的描述符 127 | 128 | ![image-20210917200601733](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210917200601733.png) 129 | 130 | ![image-20210917200610459](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210917200610459.png) 131 | 132 | 6. 编译执行(请注意修改相应位置来确保你的代码会跳转到新增的两个代码段执行) 133 | 134 | ![image-20210917200728687](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210917200728687.png) 135 | 136 | #### 课后动手改2 137 | 138 | 实验代码已经提供了高特权级通过retf跳到低特权级,低特权级通过调用门跳回高特权级的代码,于是我们采用另一种方法,通过设置高特权级代码段为一致性代码段,从而实现低特权级到高特权级的跳转。(哪种方式都是可以的,只要实现不同特权级代码段跳转即可) 139 | 140 | 1. 定义dpl=3的数据段并定义段描述符和段选择符,同时初始化段描述符。 141 | 142 | ![image-20210924111925899](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210924111925899.png) 143 | 144 | 2. 定义ring3代码段描述符和段选择符,同时初始化段描述符 145 | 146 | 3. 编写ring3代码段,实现输出字符串,并通过call指令跳转到ring0代码段 147 | 148 | ![image-20210924110712138](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210924110712138.png) 149 | 150 | 4. 定义ring0代码段描述符和选择符,同时初始化段描述符 151 | 152 | 需要在代码段中设置DA_CCO属性,表示为一致性代码段。 153 | 154 | ![image-20210924111411154](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210924111411154.png) 155 | 156 | 5. 编写ring0代码段,实现输出字符串 157 | 158 | 请注意,由于从ring3跳转到ring0一致性代码段不更改cpl,因此此时代码段相当于运行在特权级3下,向ds加载数据段选择符时,加载了指向dpl=3的数据段选择符。同时由于特权级的问题,也不能直接从改代码段通过```jmp SelectorCode16:0```跳到16位代码段,需要通过retf返回到ring3,之后通过给出的调用门进行返回。 159 | 160 | ![image-20210924112709677](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210924112709677.png) 161 | 162 | 6. 实验效果 163 | 164 | ![image-20210924112003595](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210924112003595.png) 165 | 166 | ## 实验练习 167 | 168 | 1. GDT、Descriptor、Selector、GDTR结构,及其含义是什么?他们的关联关系如何?pm.inc所定义的宏怎么使用? 169 | 170 | 2. 从实模式到保护模式,关键步骤有哪些?为什么要关中断?为什么要打开A20地址线?从保护模式切换回实模式,又需要哪些步骤? 171 | 172 | 3. 解释不同权限代码的切换原理,call, jmp,retf使用场景如何,能够互换吗? 173 | 174 | 4. 课后动手改: 175 | 176 | 1. 自定义添加1个GDT代码段、1个LDT代码段,GDT段内要对一个内存数据结构写入一段字符串,然后LDT段内代码段功能为读取并打印该GDT的内容; 177 | 2. 自定义2个GDT代码段A、B,分属于不同特权级,功能自定义,要求实现A-->B的跳转,以及B-->A的跳转。 178 | 179 | 180 | ## FAQ 181 | ### Q: No Boot Device 182 | 183 | 这种情况大概率是因为在做chapter3/a时以a.img为启动盘,但是a.img结尾并没有55aa标志(可使用hexdump命令查看),请拷贝chapter1/a/目录下的a.img(确保具有55aa标志),然后重新将pmtest1.bin重新写入a.img,之后再次启动bochs。 184 | 185 | ### Q: wrong fs type, bad option, bad superblock on 186 | 187 | 请先将在freedos中将pm.img进行格式化,mount命令无法直接识别一个img文件,需要挂载可识别的文件系统。 188 | 189 | ### Q: format b: error 190 | 191 | 具体原因多种多样,请按照以下步骤排查: 192 | 193 | 1. 确保bochsrc中添加要求的三行内容,**并删去了之前的floppya : xxxx**。 194 | 2. 确保bximage新建了pm.img 195 | 3. 确保pm.img有写入权限 196 | 4. 确保pm.img的owner和group是当前用户而非root,否则用chown和chgrp命令进行修改。 197 | 198 | ### Q: how to debug in freedos 199 | 200 | 1. debug 201 | 202 | 本指导提供的freedos-img.tar.gz中c.img中装了debug程序,可以使用debug来调试程序。修改配置文件如下 203 | 204 | ![image-20210917162205973](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210917162205973.png) 205 | 206 | 运行bochs,可以发现c盘的BIN目录下有debug程序,输入命令```path c:\bin```,进入b盘,输入命令```debug pmtest1.com```便可以进行调试。 207 | 208 | 2. 加死循环 209 | 210 | 在程序开头加上```jmp $```令程序死循环,执行程序后,在bochs调试窗口按ctrl-c,之后修改eip寄存器的值指向程序入口。 211 | 212 | 3. magic number(推荐) 213 | 214 | 在bochsrc中添加```magic_break: enabled=1``` 215 | 216 | ![image-20210917162323976](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210917162323976.png) 217 | 218 | 在程序开头添加命令```xchg bx,bx``` 219 | 220 | 重新编译运行,可以发现当运行程序时bochs会在程序开头停止,现在可以进行调试了。 221 | 222 | ![image-20210917162706733](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20210917162706733.png) 223 | 224 | ```xchg bx, bx```的机器码为```87 DB```,不知出于什么原因bochsrc遇到87 DB会停止运行,因此你可以将xchg插入到任何你想要调试的地方,达到断点的效果。 225 | 226 | ### Q: bochs中键盘不响应 227 | 228 | 等待或重新启动bochs。 229 | -------------------------------------------------------------------------------- /source/week3.md: -------------------------------------------------------------------------------- 1 | # week3 2 | 3 | ## 实验内容 4 | 5 | 1. 认真阅读章节资料,掌握什么是分页机制 6 | 2. 调试代码,掌握分页机制基本方法与思路 7 | * 代码3.22中,212行---237行,设置断点调试这几个循环,分析究竟在这里做了什么? 8 | 3. 掌握PDE,PTE的计算方法 9 | * 动手画一画这个映射图 10 | * 为什么代码3.22里面,PDE初始化添加了一个PageTblBase(Line 212),而PTE初始化时候没有类似的基地址呢(Line224)? 11 | 4. 熟悉如何获取当前系统内存布局的方法 12 | 5. 掌握内存地址映射关系的切换 13 | * 画出流程图 14 | 6. 基础题:依据实验的代码, 15 | * 自定义一个函数,给定一个虚拟地址,能够返回该地址从虚拟地址到物理地址的计算过程,如果该地址不存在,则返回一个错误提示。 16 | * 完善分页管理功能,补充alloc_pages, free_pages两个函数功能 17 | 7. 进阶题(选做) 18 | * 设计一个内存管理器,选择其一实现:首次适应算法、最佳适应算法、伙伴算法,要求实现内存的分配与回收。(提示,均按照页为最小单位进行分配、对于空闲空间管理可采用位图法或者双向链表法管理) 19 | 20 | ## 实验步骤 21 | 22 | ```{admonition} 提示 23 | 24 | 课后实验思路仅供参考,故尽可能减少示例图片的出现和文字描述。鼓励更加完善的内存管理方式 25 | 26 | ``` 27 | 28 | ### 虚拟地址到物理地址 29 | 30 | #### 编写程序 31 | 32 | ![image-20211001083449615](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211001083449615.png) 33 | 34 | 程序可以大致分为以下几个部分: 35 | 36 | * 从cr3寄存器获取页目录物理地址 37 | * 通过掩码和右移得到线性地址高10位,左移两位(乘4)作为索引,寻找对应的页目录项,从页目录项中得到页表物理地址 38 | * 通过掩码和右移得到线性地址中间10位,左移两位(乘4)作为索引,寻找对应的页表项,从页表项中得到页物理地址高20位 39 | * 与低12位拼接,可得到对应物理地址 40 | 41 | 注:出于简化的目的,当页目录项或页表项不存在时,返回物理地址全为1,表示出错。 42 | 43 | #### 编写测试代码 44 | 45 | 通过TestL2P函数来对代码进行测试,打印相关信息。 46 | 47 | 分别在PSwitch前后查看LinearAddrDemo对应的物理地址,查看是否发生变化 48 | 49 | ![image-20211001084158851](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211001084158851.png) 50 | 51 | #### 调用测试函数,查看输出 52 | 53 | ![image-20211001084130800](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211001084130800.png) 54 | 55 | ### Alloc_pages函数 56 | 57 | ```{admonition} 注解 58 | 59 | 函数的重点是建立线性地址和物理地址的映射,不在于如何管理线性空间,因此简单的选取可用线性地址返回即可 60 | 61 | ``` 62 | 63 | #### 物理页管理 64 | 65 | * 定义位图 66 | 67 | 通过在数据段定义位图的形式,假设0~1MB物理内存均被占用,1MB~2MB物理内存均未分配 68 | 69 | ![image-20211001085007382](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211001085007382.png) 70 | 71 | * 寻找空闲页并返回物理地址 72 | 73 | 通过bts寻找位图中第一个0比特,将其位置乘以4KB得到物理地址,如果没有可用空间,直接停机(简化操作) 74 | 75 | ![image-20211001085214251](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211001085214251.png) 76 | 77 | #### 虚拟页管理 78 | 79 | * 假设线性地址从0x8000_0000开始分配 80 | 81 | ![image-20211001085357967](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211001085357967.png) 82 | 83 | * 获取线性地址,然后查找对应页目录项,如果页目录项对应的页表不存在,则创建页表 84 | 85 | ![image-20211001092124162](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211001092124162.png) 86 | 87 | * 修改对应页表项,将alloc_a_4k_page返回的物理地址和相应属性写入。 88 | 89 | ![image-20211001092143705](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211001092143705.png) 90 | 91 | ### Free_pages函数 92 | 93 | 给定线性地址和页大小(不用考虑是否越界的问题),修改对应页表项和页目录项,取消映射关系。 94 | 95 | 同学们自己coding⌨练练手 96 | 97 | ### 测试两个函数 98 | 99 | ![image-20211001092026739](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211001092026739.png) 100 | 101 | * 查看alloc_pages前地址映射关系 102 | 103 | ![image-20211001090427737](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211001090427737.png) 104 | 105 | * 查看alloc_pages后地址映射关系 106 | 107 | ![image-20211001090519049](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211001090519049.png) 108 | 109 | * 查看free_pages后地址映射关系 110 | 111 | ![image-20211001090623863](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211001090623863.png) 112 | 113 | ## FAQ 114 | 115 | -------------------------------------------------------------------------------- /source/week4.md: -------------------------------------------------------------------------------- 1 | # week4 2 | 3 | ## 实验内容 4 | 5 | 1. 理解中断与异常的机制 6 | 7 | 2. 调试8259A的编程基本例程 8 | 9 | 3. 调试时钟中断例程 10 | 11 | 4. 实现一个自定义的中断向量,功能可自由设想 12 | 13 | ## 实验步骤 14 | 15 | ### 添加IDT表项 16 | 17 | 添加21号中断对应的中断门,同时初始化8259A打开相应的中断 18 | 19 | ![image-20211003202534811](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211003202534811.png) 20 | 21 | ### 编写中断处理程序 22 | 23 | 编写处理程序,每次接收到键盘输入,修改字符的颜色 24 | 25 | ![image-20211003202653007](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211003202653007.png) 26 | 27 | ### 查看实验结果 28 | 29 | 每次敲击键盘,可以看到右上角颜色发生变化。 30 | 31 | ![image-20211003202911027](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211003202911027.png) 32 | 33 | ## FAQ 34 | 35 | ### Q:编写键盘中断,为什么运行程序后还没按下键盘就执行了键盘中断程序 36 | 37 | 可能是因为enter键松开时,键盘中断被程序所收到,导致执行键盘中断程序 38 | 39 | ### Q:为什么只能按下键盘触发一次键盘中断? 40 | 41 | 请按以下步骤排查: 42 | 43 | 1. 检查是否发送了EOI 44 | 2. 检查是否使用命令```in al, 0x60```清除了键盘缓冲区 45 | 46 | ### Q:是否可以使用BIOS中断? 47 | 48 | 进入保护模式后,中断从原来的从IVT找中断向量变成了根据中断向量号索引IDT中的门描述符,无法在使用int指令调用BIOS中断。 -------------------------------------------------------------------------------- /source/week5.md: -------------------------------------------------------------------------------- 1 | # week5 2 | 3 | ## 实验内容 4 | 5 | 1. 向软盘镜像文件写入一个你自己任意创建的文件,手工方式在软盘中找到指定的文件,读取其扇区信息,记录你的步骤。 6 | 7 | 2. 将指定的可执行文件装入指定内存区,并执行,记录原理与步骤 8 | 9 | 3. 学会使用xxd读取二进制信息,通过1、2来验证。 10 | 11 | ## 实验问题 12 | 13 | 1. FAT12格式是怎样的? 14 | 15 | 2. 如何读取一张软盘的信息 16 | 17 | 3. 如何在软盘中找到指定的文件 18 | 19 | 4. 如何在系统引导过程中,从读取并加载一个可执行文件到内存,并转交控制权? 20 | 21 | 5. 为什么需要这个Loader程序不包含dos系统调用? 22 | 23 | 6. 扩展提高:调研在硬盘上,文件系统格式为FAT32或者NTFS,应该怎么来实现类似功能呢?(可粗略参阅第9章) 24 | 25 | ## 实验步骤 26 | 27 | ### 阅读文档 28 | 29 | 阅读[FAT12文档](https://www.eit.lth.se/fileadmin/eit/courses/eitn50/Literature/fat12_description.pdf),对FAT12文件系统有大致的了解,熟悉如何区分目录和文件,如何根据FAT表获取文件全部内容, 30 | 31 | ### 跟书实践 32 | 33 | 跟着书上做即可,这章比较简单,但内容较多,希望同学们仔细看书体会。🤣 34 | 35 | ## FAQ 36 | 37 | ### Q:为什么我自己的文件内容不是从0x4200开始? 38 | 39 | 需要检查文件条目对应的开始簇号,书中的例子为0x0002,因此计算得到文件内容从0x4200开始,假如为0x0003,则对应内容从0x4400开始。 -------------------------------------------------------------------------------- /source/week6.md: -------------------------------------------------------------------------------- 1 | # week6 2 | 3 | ## 实验内容 4 | 5 | 1. 汇编和C的互相调用方法 6 | 7 | 在例程基础上,在汇编与C程序中各添加一个简单带参数的函数调用,让两种语言撰写的程序实现混合调用,功能可自定义。 8 | 9 | 2. ELF文件格式 10 | 11 | 依照书上方法,分析你修改的这个可执行文件 12 | 13 | 3. 使用Loader加载ELF文件 14 | 15 | 4. 如何加载并扩展内核 16 | 17 | 5. 设计题:修改启动代码,在引导过程中在屏幕上画出一个你喜欢的ASCII图案,并将第三章的内存管理功能代码、你自己设计的中断代码集成到你的kernel文件目录管理中,并建立makefile文件,编译成内核,并引导 18 | 19 | ## 实验问题 20 | 21 | 1. 汇编和C的调用方法是怎样的? 22 | 23 | 2. 描述ELF文件格式以及作用 24 | 25 | 3. 描述从Loader引导ELF的原理 26 | 27 | 4. 一个内核要能基本使用应该扩展哪些功能,怎么扩展? 28 | 29 | 5. 怎么管理内核文件目录? 30 | 31 | ## 实验步骤 32 | 33 | ### 启动显示ASCII图案 34 | 35 | 1. 通过neofetch或figlet工具获取图案(什么图案都可以) 36 | 37 | ![image-20211024100021459](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211024100021459.png) 38 | 39 | 2. 在kernel/start.c中编写函数,显示图案 40 | 41 | ![image-20211024100125866](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211024100125866.png) 42 | 43 | 3. 在kernel/kernel.asm中extern声明printBootLogo函数,同时在合适的位置调用(需要修改disp_str函数实现超出屏幕范围翻页的功能) 44 | 45 | ![image-20211024100256029](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211024100256029.png) 46 | 47 | ### 中断函数集成 48 | 49 | 以实现的键盘中断为例 50 | 51 | 1. 修改代码,使kernel进入死循环(不然hlt被中断唤醒后会继续执行hlt后面的指令,导致出现错误) 52 | 53 | ![image-20211024100817477](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211024100817477.png) 54 | 55 | 2. 修改hwint01函数,改成自己的中断处理代码 56 | 57 | ![image-20211024100854184](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211024100854184.png) 58 | 59 | 3. 测试程序,每次按键盘,发现颜色变化 60 | 61 | ![image-20211024101142507](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211024101142507.png) 62 | 63 | ### 内存管理集成 64 | 65 | 为了简单展示修改Makefile,我们将创建mm文件夹,将前面内存管理的函数放入该文件夹的pageManage.asm文件中 66 | 67 | 1. 将代码拷贝进入pageManage.asm中,注意声明标号以及添加所需要的数据结构 68 | 69 | ![image-20211024101341949](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211024101341949.png) 70 | 71 | 需要注意的是,对数据的引用无需使用```xxx equ _xxx - $$```,直接使用```_xxx```即可,请思考为什么。 72 | 73 | 2. 在kernel/kernel.asm中添加测试函数并调用,被测试函数记得extern声明。 74 | 75 | ![image-20211024102148285](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211024102148285.png) 76 | 77 | 3. 修改Makefile,在OBJS中添加```mm/pageManage.o```,在文件末尾添加对该文件的汇编命令 78 | 79 | ![image-20211024101730081](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211024101730081.png) 80 | 81 | 4. 测试程序,由于之前验证过其正确性,因此正常显示输出即可判定其工作正常。 82 | 83 | ![image-20211024102119780](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211024102119780.png) 84 | 85 | 在断点处分别查看页表的映射情况,alloc_pages和free_pages也正常工作 86 | 87 | ![image-20211024102329706](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211024102329706.png) 88 | 89 | ## FAQ 90 | 91 | ### Q: 出现undefined reference to `__stack_chk_fail`错误,如何解决? 92 | 93 | 需要在 `Makefile` 中的 `$(CFLAGS)` 后面加上 `-fno-stack-protector`,即不需要栈保护 94 | 95 | ![image-20211024102407702](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211024102407702.png) 96 | 97 | ### Q:出现xxx is incompatible with i386:x86-64 output 98 | 99 | 有些同学的Ubuntu系统是64位,而不是32位,那么gcc默认编译的目标文件是64位,无法和32位汇编文件汇编出的目标文件进行链接,需要在Makefile的CFLAGS后面添加```-m32```,LDFLAGS后面添加```-m elf_i386 ``` 100 | 101 | ### Q:如何方便的在标号声明处和定义处进行跳转? 102 | 103 | 由于建立了文件目录,浏览代码时不容易查找标号对应的定义,对于使用vim的同学,推荐使用ctags工具,方便标号声明和定义的跳转,对于仍在使用自带编辑器的同学,可以尝试vscode。 104 | 105 | ### Q:myprint不好用,如何使用printf打印输出? 106 | 107 | 我们采用动态链接的方法将libc.so和程序链接起来。下面操作环境为Ubuntu14.04,gcc 4.8.4 108 | 109 | 首先包含头文件 110 | 111 | ![image-20211030090059779](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211030090059779.png) 112 | 113 | 修改Makefile,在链接参数中添加```--dynamic-linker /lib/ld-linux.so.2 -lc``` 114 | 115 | ![image-20211030090138171](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211030090138171.png) 116 | 117 | make后运行,可以看到正常打印 118 | 119 | ![image-20211030090318628](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211030090318628.png) 120 | 121 | ```{admonition} 提示 122 | 123 | 当你阅读到chapter5/f/start.c时,请留意memcpy第一个参数,尝试修改将gdt前面的&符号去掉,查看结果是否一致并思考为什么,这同时会帮助你理解在C语言中声明指针和数组后,在汇编语言中想要使用它们时有什么不同 124 | 125 | ``` 126 | -------------------------------------------------------------------------------- /source/week7.md: -------------------------------------------------------------------------------- 1 | # week7 2 | 3 | ## 实验内容 4 | 5 | 1. 掌握进程相关数据结构的定义方法: 6 | 进程控制块(进程表)、进程结构体、进程相关的GDT/LDT、进程相关的TSS,以及数据结构的关系 7 | 2. 掌握构造进程的关键技术: 8 | 初始化进程控制块的过程、初始化GDT和TSS、实现进程的启动 9 | 3. 进程的现场保护与切换,弄清楚需要哪些关键数据结构与步骤 10 | 时钟中断与进程调度关系,现场保护与恢复机理,从ring0-->ring1的上下文切换方法,中断重入机理 11 | 12 | ## 实验问题 13 | 14 | 1. 描述进程数据结构的定义与含义: 15 | 进程控制块(进程表)、进程结构体、进程相关的GDT/LDT、进程相关的TSS,画出数据结构的关系图 16 | 2. 画出以下关键技术的流程图: 17 | 初始化进程控制块的过程、初始化GDT和TSS、实现进程的启动 18 | 3. 怎么实现进程的现场保护与恢复? 19 | 4. 为什么需要从ring0-->ring1,怎么实现? 20 | 5. 进程为什么要中断重入,具体怎么实现,画出流程图? 21 | 22 | ## 实验步骤 23 | 24 | ![diy](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/diy.png) 25 | 26 | 本次实验没有太多实操,重在理解,这里给大家更新一个小的脚本,免去每次都需要修改Makefile来增加"-fno-stack-protector"以及更新bochsrc。 27 | 28 | ```shell 29 | #!/bin/sh 30 | 31 | # Author : jackson sang 32 | # another toy script 33 | 34 | if test "$#" -eq 0; 35 | then 36 | for file in `ls .` 37 | do 38 | if test -d $file 39 | then 40 | echo "deal with dir "$file 41 | sed -i 's/-c -fno-builtin/-c -fno-stack-protector -fno-builtin/' $file"/Makefile" 42 | cp bochsrc $file"/bochsrc" 43 | cd $file 44 | ctags -R . #optional 45 | cd ../ 46 | fi 47 | 48 | done 49 | else 50 | if test -d $1 51 | then 52 | echo "deal with dir "$1 53 | sed -i 's/-c -fno-builtin/-c -fno-stack-protector -fno-builtin/' $1"/Makefile" 54 | cp bochsrc $1"/bochsrc" 55 | cd $1 56 | ctags -R . #optional 57 | make image #may be 58 | bochs 59 | cd ../ 60 | fi 61 | fi 62 | ``` 63 | 64 | 使用方法为将想要替换的bochsrc和shell脚本放在chapterX文件夹下 65 | 66 | ![image-20211101152535848](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211101152535848.png) 67 | 68 | 然后直接运行```./update.sh```进行所有目录下Makefile修改和bochsrc的替换,或者```./update xxx```单独对某个文件下的Makefile修改以及bochsrc的替换,同时执行```make image```和```bochs```命令启动bochs。 69 | 70 | ## FAQ 71 | 72 | -------------------------------------------------------------------------------- /source/week8.md: -------------------------------------------------------------------------------- 1 | # week8 2 | 3 | ## 实验内容 4 | 5 | 1. 多进程问题,如何扩展单进程到多进程,如何扩展中断支持多进程? 6 | 2. 如何实现系统调用 7 | 3. 进程调度问题,弄清楚实现调度的基本思路 8 | 9 | ## 实验问题 10 | 11 | 1. 在单进程的基础上扩展实现多进程要考虑哪些问题? 12 | 13 | 2. 画出以下关键技术的流程图: 14 | 15 | 初始化多进程控制块的过程、扩展初始化LDT和TSS 16 | 17 | 3. 如何修改时钟中断来支持多进程管理,画出新的流程图。 18 | 4. 系统调用的基本框架是如何的,应该包含哪些基本功能,画出流程图。 19 | 5. 如何操控可编程计数器? 20 | 6. 进程调度的框架是怎样的?优先级调度如何实现? 21 | 7. 动手做:修改例子程序的调度算法,模拟实现一个多级反馈队列调度算法,并用其尝试调度5-8个任务。注意,抢占问题,注意时间片问题。 22 | 8. 思考题:从用户态进程读和写内核段的数据,看能否成功,是否会触发保护,并解释原因。 23 | 24 | ## 实验步骤 25 | 26 | 给出一个简化版多级反馈队列实现,没有到达时间和任务所需时间片的概念。 27 | 28 | 1. 头文件中添加相应数据结构,主要有三个队列和对应的时间片,队列用数组来实现,存储u32类型的pid,优先级越高的队列对应时间片越少。 29 | 30 | ![image-20211118201522411](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211118201522411.png) 31 | 32 | 2. 在kernel_main中初始化数据 33 | 34 | ![image-20211118201700353](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211118201700353.png) 35 | 36 | 3. 最开始向高优先级队列中加入A和B两个进程 37 | 38 | ![image-20211118201721768](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211118201721768.png) 39 | 40 | 4. 修改schedule,下面只给出部分代码,思路为寻找第一个不为-1的元素,找到后查看进程剩余时间片,如果大于0则进行调度,小于等于0则移到下一级队列中(通过数组元素移动)。 41 | 42 | ![image-20211118201821933](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211118201821933.png) 43 | 44 | 5. 令C在tick为12时,即A和B都进入中优先级队列时到达,进行抢占 45 | 46 | ![image-20211118202726711](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211118202726711.png) 47 | 48 | 6. 查看结果,发现A和B各自运行完5个时间片后,进入中优先级队列,A运行两个时间片后C到达进行抢占,C运行5个时间片后进入中优先级队列,A继续运行8个时间片,之后转入低优先级队列,B开始运行,然后C,循环往复。 49 | 50 | ![image-20211118202753608](https://sql-markdown-picture.oss-cn-beijing.aliyuncs.com/img/image-20211118202753608.png) 51 | 52 | ## FAQ 53 | 54 | --------------------------------------------------------------------------------