操作系统的启动-学习报告

注:主要参考了《Linux内核实验教程》4.10
1.实验目的和任务要求
跟踪调试 Linux 0.11 在 PC 机上从 CPU 加电到完成初始化的过程。
查看 Linux 0.11 启动后的状态和行为,理解操作系统启动后的工作方式
2.实验原理
操作系统启动过程可以概括为以下步骤:
 操作系统启动图图2.1 操作系统启动图
当电源打开时,计算机的BIOS或UEFI固件执行POST(开机自检)。
BIOS/UEFI检测连接到系统的设备,包括CPU、内存和存储设备。
选择一个启动设备,可以是硬盘、网络服务器或CD ROM。
BIOS/UEFI运行引导加载器(如GRUB),提供选择操作系统或内核的菜单。
选定操作系统后,内核开始启动,准备执行用户空间。
内核启动systemd作为第一个用户空间进程,负责管理进程、服务、探测硬件、挂载文件系统,并运行桌面环境。
systemd默认激活default.target单元,同时执行其他分析单元。
系统运行一组启动脚本,配置运行环境。
最终,用户看到登录窗口,系统准备就绪,等待用户登录。
3.实验内容
3.1 准备实验
使用浏览器登录平台领取本次实验对应的任务,从而在平台上创建个人项目(Linux 0.11 内核项目),
然后使用 VSCode 将个人项目克隆到本地磁盘中并打开。
在这里插入图片描述

图3.1 准备1
在 VSCode 左侧的“文件资源管理器”窗口中打开 boot 文件夹中的 bootsect.asm 和 setup.asm 两个汇编文件。简单阅读一下这两个文件中的源代码和注释。
使用 Task 中的“生成项目”完成项目的生成过程后,使用 Windows 资源管理器打开项目文件夹中的boot 文件夹。找到由 bootsect.asm 生成的软盘引导扇区程序 bootsect.bin 文件,确认该文件的大小为512 字节(与软盘中一个扇区的大小相同)
在这里插入图片描述

图3.2 准备2
3.2 调试 Linux 0.11 操作系统的启动过程
(1)记录 init/main.c 文件中的内核入口函数 start 的地址
Linux 0.11 在执行完引导和加载程序后,执行的第一个内核函数就是 init/main.c 文件中的内核入口函数start。首先按照下面的步骤记录下 start 函数的地址,留待后续使用:
在这里插入图片描述

图3.3 调试1

  1. 找到 start 函数的代码行(init/main.c 文件中的第 134 行)。
  2. 在此代码行添加一个断点。
  3. 按 F5 启动调试,会在刚刚添加的断点处中断。
  4. 在 start 函数名称上双击鼠标左键选中此名称,然后在此名称上点击右键,选择菜单中的“Add to Watch”,可以在左侧的“WATCH”窗口中查看 start 函数的地址,如图3.4所示:
    在这里插入图片描述

图3.4 调试2
5.先在纸上记录下图中红色边框圈出的函数地址。
6. 结束此次调试。
(2)调试 BIOS 程序
接下来按照处理器加电运行的顺序,依次调试 BIOS 程序、软盘引导扇区程序和加载程序, 直到进入 Linux 0.11 操作系统的内核。由于 BIOS 程序、软盘引导扇区程序和加载程序没有提供调试信息, 所以这里无法使用类似前面介绍的调试 Linux 0.11 内核那样的功能来进行调试了,也就是说不能在 VSCode 中按 F5 启动调试,无法在汇编源代码文件中添加断点,也无法提供单步调试、查看变量的值、查看调用 堆栈等功能。幸好 Bochs 提供了命令调试功能,可以用来调试包括 BIOS 程序在内的每条需要处理器执行的指令。
在 VSCode 的“Terminal”菜单中选择“Run Build Task…”,会在 VSCode 的顶部中间位置弹出一个 可以执行的 Task 列表,选择其中的“Bochs命令调试”即可 ,此时会弹出两个 Bochs 窗口。标题为“Bochs for windows–Display”的窗口相当于计算机的显示器,显示操作系统的输出。标题为“Bochs for windows–Console”的窗口是 Bochs 的控制台,用来输入调试命令和输出调试信息。
在这里插入图片描述

图3.5 Bochs 1
启动调试后,Bochs在CPU要执行的第一条指令(即BIOS的第一条指令)处中断。此时,Display窗口没有显示任何内容,Console窗口显示将要执行的 BIOS 的第一条指令,并等待用户输入调试命令,如图3.6所示:
在这里插入图片描述

图3.6 Bochs 2
从 Console 窗口显示的内容中,可以获得关于 BIOS 的第一条指令的如下信息:
行首的[0x0000fffffff0]表示此条指令所在的物理地址。
f000:fff0 表示此条指令所在的逻辑地址(段地址:偏移地址)。
jmpf 0xf000:e05b 是此条指令的反汇编代码。
行末的 ea5be000f0 是此条指令的十六进制字节码,可以看出此条指令占用了 5 个字节。
接下来按照下面的步骤,查看 CPU 在没有执行任何指令前主要的寄存器中的数据(即 CPU 复位后的状态),以及内存中的数据:
1.在 Console 窗口中输入调试命令 sreg 后按回车,显示当前 CPU 中各个段寄存器的值,如图 2-3 所示。其中 CS 寄存器信息行中的“cs:0xf000”表示 CS 寄存器的值为0xf000。
在这里插入图片描述

图3.7 Bochs 3
2.在 Console 窗口中输入调试命令 r 后按回车,显示当前 CPU 中各个通用寄存器的值,如图 2-4 所示。其中“eip:0x0000fff0”表示 IP 寄存器的值为 0xfff0。结合 BIOS 的第一条指令的地址,可以验证 CPU 将要执行的指令地址为 CS:IP。
在这里插入图片描述

图3.8 Bochs 4

3.输入调试命令xp /1024b 0x0000,查看从地址0开始的1024个字节的物理内存。在Console中输出的这1K物理内存的值都为0,说明BIOS中断向量表还没有被加载到从地址 0 开始的物理内存。
4.输入调试命令xp /512b 0x7c00,查看软盘引导扇区要被加载到的物理内存。输出的内存值都为0,说明软盘引导扇区还没有被加载到从地址 0x7c00 开始的物理内存。
通过以上的实验步骤,可以验证 BIOS 第一条指令的逻辑地址中的段地址和 CS 寄存器值是一致的,偏移地址和 IP 寄存器的值是一致的。由于物理内存还没有被使用,所以其中的值都为 0。
(3)查看软盘引导扇区程序生成的列表文件
NASM 汇编器在将软盘引导扇区程序 bootsect.asm 生成为二进制 bootsect.bin 的同时,会生成一个 bootsect.lst 列表文件。二进制文件 bootsect.bin 中包含了指令的机器码,是给处理器使用的,人阅读起来就十分吃力。而列表文件是一个文本文件,可以准确反映出汇编源代码文件中的指令与二进制文件中机器码的关系,帮助调试 bootsect.asm 文件中的汇编代码。
按照下面的步骤查看 bootsect.lst 文件中的内容:
1.在 VSCode 的“文件资源管理器”窗口中打开“boot”文件夹,打开其中的bootsect.lst文件。
2.将 bootsect.lst 文件和 bootsect.asm 文件对比可以发现,此文件包含了 bootsect.asm 文件中所有的汇编代码,同时在代码的左侧又添加了更多的信息。
3.在 bootsect.lst 中查找到软盘引导扇区程序第一条指令所在的行
在这里插入图片描述

图3.9 boostsect.lst
此行包含的信息有:
32 是行号。
00000000 是此条指令相对于程序开始位置的偏移(第一条指令的偏移为 0)。
B8C007 是此条指令的机器码,此条指令包含了 3 个字节。
4.在 VSCode 的“文件资源管理器”窗口中打开“boot”文件夹,在其中的 bootsect.bin 文件上点击鼠标右键,在弹出的菜单中选择“Open With…”,会在 VSCode 的顶部中间位置弹出一个文件打开方式的列表,选择其中的“Hex Editor”,就会使用二进制编辑器打开此文件。可以看到bootsect.bin 文件中的机器码与列表文件 bootsect.lst 中的机器码是完全一致的。
在这里插入图片描述

图3.10 boostsect.bin
(4)调试软盘引导扇区程序(bootsect.asm)
BIOS 在执行完硬件设备自检和初始化工作后,会将软盘引导扇区(512 字节)加载到物理地址0x7c00-0x7dff位置,并从 0x7c00 处的指令开始执行引导程序。按照下面的步骤从 0x7c00 处调试软盘引导扇区程序:
1.在 Bochs 的 Console 窗口中输入调试命令 vb 0x0000:0x7c00,这样就在逻辑地址0x0000:0x7c00(相当于物理地址 0x7c00)处添加了一个断点。
2.输入调试命令 c 让 Bochs 继续执行,会在 0x7c00 处的断点中断。此时会在 Console 窗口中输出下一个要执行的指令,即软盘引导扇区程序的第一条指令,如图3.11所示:
在这里插入图片描述

图3.11 boostsect.asm

3.为了方便后面的使用,可以在纸上记录下此条指令的字节码(b8c007)。
4.输入调试命令 sreg 验证 CS 寄存器的值(0x0000)。
在这里插入图片描述

图3.12 boostsect.asm2
5.输入调试命令 r 验证 IP 寄存器的值(0x7c00)。
在这里插入图片描述

图3.13 boostsect.asm3
6.由于 BIOS 程序此时已经执行完毕,输入调试命令 xp /1024b 0x0000 验证此时 BIOS 中断向量表已经被载入。
在这里插入图片描述

图3.14 boostsect.asm4
7.输入 xp /512b 0x7c00 显示软盘引导扇区程序的所有字节码。观察此块内存最开始的三个字节分别是 0xb8、0xc0 和 0x07,这和引导程序第一条指令的字节码是相同的。如果将Bochs的Console窗口中显示的 512 个字节与 bootsect.lst 文件中的机器码进行比较,或者与使用二进制编辑器打开的 bootsect.bin 文件中的内容进行比较,会发现它们的内容是完全相同的。此块内存最后的两个字节分别是 0x55 和 0xaa,它们是魔数,是 BIOS 规定这两个字节的值必须为 0x55和0xaa 时才表示引导扇区是激活的,可以用来引导操作系统。这两个字节对应bootsect.asm中最后一行语句(注意,字节顺序使用Little- endian):
在这里插入图片描述

图3.15 boostsect.asm5
接下来查看引导程序将自己复制到 0x90000 后的情况
1.输入调试命令 xp /512b 0x9000:0x0000 可以验证此时引导程序还没有将自己移动到0x9000:0x0000 处。
2.输入调试命令 vb 0x9000:0x0018,在 0x9000:0x0018 处设置一个断点。
在这里插入图片描述

图3.16 boostsect.asm6
3.输入调试命令 c 继续执行,会在刚刚添加的断点处中断。
在这里插入图片描述

图3.17 boostsect.asm7
4.再次输入调试命令 xp /512b 0x9000:0x0000,并与之前的内存比较,可以知道引导程序已经将自己移到了 0x90000 处,并在 0x9000:0x0018 处中断执行了。
在这里插入图片描述

图3.18 boostsect.asm8
5.输入调试命令 xp /512b 0x9000:0x0200,可以验证此时 setup.bin 模块还没有被装入内存
6.根据 bootsect.lst 文件下面一行的内容(执行此行指令时说明 setup.bin 加载完毕),输入调试命令 vb 0x9000:0x0031,在逻辑地址 0x9000:0x0031 处设置一个断点。
在这里插入图片描述

图3.19 boostsect.asm9
7.输入调试命令 c 继续执行,会在刚刚添加的断点处中断。
在这里插入图片描述

图3.20 boostsect.asm10
8.输入调试命令 xp /512b 0x9000:0x0200,此块内存已经发生改变。将此块内存中的字节码与init/setup.lst 文件和 init/setup.bin 文件中的内容比较,可以知道此时 setup.bin 模块已经被载入内存。
在这里插入图片描述

图3.21 boostsect.asm11
9.输入调试命令 xp /512b 0x1000:0x0000,可以看到除前面有少量数据(BIOS 自检程序残留下的),后面全是 0。可以知道此时内核模块 linux011.bin 还没有被装载进入内存。
在这里插入图片描述

图3.22 boostsect.asm12
10.根据 bootsect.lst 文件下面一行的内容(执行此行指令时说明 linux011.bin 加载完毕,软盘驱动器中的马达被关闭了),输入调试命令 vb 0x9000:0x006e,在逻辑地址 0x9000:0x006e 处设置一个断点。
在这里插入图片描述

图3.23 boostsect.asm13
11.输入调试命令 c 继续执行,会在刚刚添加的断点处中断。
在这里插入图片描述

图3.24 boostsect.asm14
12.输入调试命令 xp /512b 0x1000:0x0000,显示此块内存中的字节码与 boot/head.lst 文件(由init/head.asm 编译时生成)和 linux011.bin 文件中开始位置的机器码是完全一致的。原因是init/head.asm 生成了目标文件 init/head.o,此目标文件中的代码段(包括指令的机器码)会在链接时写入内核模块 linux011.bin 的代码段的开始位置。由此可知,此时内核模块linux011.bin 已经被装入物理内存。
在这里插入图片描述

图3.25 boostsect.asm15
(5)调试加载程序(setup.asm)
setup.asm 生成的 setup.bin 被加载到从地址 0x90200 开始的物理内存。可以按照下面的步骤进行调试。
1.在 Bochs 的 Console 窗口中输入调试命令 vb 0x9020:0x0000,在逻辑地址 0x9020:0x0000(即setup 程序的第一条指令)处设置一个断点。
在这里插入图片描述

图3.26 setup.asm1
2.输入调试命令 c 继续执行,可在 0x9020:0x0000 处中断,如图3.27。打开 setup.lst 文件,可以看到其中第一条指令的字节码与此处将要执行的指令的字节码是相同的,说明Linux 0.11 将要开始执行 setup 模块。
在这里插入图片描述

图3.27 setup.asm2
3.输入调试命令 xp /2b 0x9000:0x0000,查看取得各种机器参数之前物理内存 0x90000-0x901FF 中前两个字节的值并记录下来,如图3.28所示
在这里插入图片描述

图3.28 setup.asm3
4.根据 setup.lst 文件下面一行的内容,输入调试命令 vb 0x9020:0x0080。
在这里插入图片描述

图3.29 setup.asm4
5.输入调试命令 c 继续运行,在刚刚添加的断点处中断。此时 Linux 0.11 已经将各种机器参数放入 0x90000-0x901FF 的物理内存中。
6.输入调试命令 xp /2b 0x9000:0x0000,查看此处内存的值,如图3.29,并和步骤 3 进行对比。可以知道此时该地址处的内存值已经改变。
在这里插入图片描述

图3.30 setup.asm5
7.根据 setup.lst 文件下面一行的内容,输入调试命令 vb 0x9020:0x010b。
在这里插入图片描述

图3.31 setup.asm6
8.输入调试命令 c 继续运行,可以在刚刚添加的断点处中断。此时,setup.asm 已经完成了它的工作,并让处理器从实模式进入了保护模式,下一条将要执行的跳转指令是工作在保护模式下的,所以要指定段选择符和偏移,才会跳转到 head.s 的第一条指令处执行。注意,这里的段值的 8 已经是保护模式下的段选择符了,用于选择描述符表和描述符表项以及所要求的特权级。
(6)调试内核模块中的 head.s
1.打开 head.lst,找到其第一条指令所在行,如下(此条指令包含了 5 个字节)
在这里插入图片描述

图3.32 head.s
在生成 Linux 0.11 内核的过程中,head.s 会生成目标文件 head.o,此目标文件中的代码段在链接时会写入 Linxu011.bin 中代码段的开始位置,并且 linux011.bin 会被从之前的 0x10000 起始的物理内存移动到 0x00000 起始的物理内存。所以,可以在物理地址 0x0000 处设置一个断点。注意,执行到这里时,CPU 已经处于保护模式了,使用在物理地址添加断点的命令比较方便,所以输入的调试命令为:pb 0x0000。
2.输入调试命令 c 继续执行,可在图 2-9 所示的指令处中断。对比 head.lst 文件中第一条指令的字节码,可以确认已经进入了 head.s 模块。
在这里插入图片描述

图3.33 head.s1
3.根据 head.lst 文件下面一行的内容,输入调试命令:pb 0x540b。 该指令负责将内核入口点函数 start 的地址压入栈。
在这里插入图片描述

图3.34 head.s2
4.输入调试命令 c 继续执行,在步骤 3 设置的断点处中断,如图3.35。
在这里插入图片描述

图3.35 head.s3
将图中红框中的地址与之前记录的 start 函数的地址比较,可以确认这个地址就是 start 函数的地址。最终就是通过这个地址跳转到操作系统内核的入口点开始执行,从而结束引导过程的。
5.根据 head.lst 文件下面一行的内容,输入调试命令:pb 0x54a5。
在这里插入图片描述

图3.36 head.s4
6.输入调试命令 c 继续执行,在 ret 指令处中断。然后接着输入调试命令 s,单步执行此行的 ret指令,可以得到图3.37:

图3.37 head.s5
图中红线圈出的是 IP 寄存器将要执行的下一条指令。对比可以发现它和图 2-10 中圈出的值是一样的,说明接下来就开始执行 start 函数中的指令了。将内核入口点 start 函数的地址压入栈,然后再通过 ret 指令进入此函数执行是这里的一个小技巧。
调试到这里,操作系统启动的部分就全部结束了,接下来操作系统将跳入 init/main.c 中的 start 函 数去执行,head.s 还做了许多其它事情,如对中断描述符表和全局描述符表进行设置,对页表的设置等。

4.实验的思考与问题分析
1.为什么Linux 0.11操作系统从软盘启动时要使用bootsect.bin和setup.bin两个程序?使用一个可以吗?它们各自的主要功能是什么?如果将setup.bin的功能移动到bootsect.bin文件中,则bootsect.bin文件的大小是否仍然能保持小于512字节?
答:
原因:
Linux 0.11操作系统从软盘启动时使用bootsect.bin和setup.bin两个程序,而不是合并成一个的主要原因是引导扇区的大小限制为512字节。这两个程序各自承担了不同的任务,保持它们分开有助于在引导阶段内限制文件大小,以确保能够正确加载。
bootsect.bin的主要功能:
bootsect.bin是引导扇区的程序,大小受到极大的限制,一般为512字节。主要任务包括在计算机启动时由BIOS加载,将自身移动到内存指定位置,加载setup.bin和linux011.bin。bootsect.bin的紧凑性很重要,因为它必须容纳引导逻辑和辅助引导加载器(如GRUB)的信息。
setup.bin的主要功能:
setup.bin是一个更大的程序,被bootsect.bin加载后负责完成一系列复杂的系统初始化工作。包括切换到保护模式、设置中断描述符表(IDT)、初始化硬件等任务。setup.bin的任务较多,因此相对较大,不适合合并到bootsect.bin。
合并setup.bin的功能到bootsect.bin是否可行:
合并setup.bin的功能到bootsect.bin可能会导致总体大小超过512字节。引导扇区的大小限制是一个硬性规定,超出限制可能导致引导失败。因此,要确保新的bootsect.bin文件大小不超过512字节,以保持引导扇区规范。

2.结合前面“预备知识”中对三个汇编语言源文件的介绍,在源代码文件中找到对应的实现代码,加深 对Linux 0.11操作系统启动过程的理解。
答:
bootsect.asm:
① 引导程序加载到内存的指定位置:
在这里插入图片描述

图4.1 bootsect实现代码1
这部分代码将引导加载程序从 BOOTSEG 处复制到 INITSEG 处,然后通过跳转开始执行。
② 设置段寄存器,包括栈寄存器SS和SP:
在这里插入图片描述

图4.2 bootsect实现代码2
这段代码设置了一些段寄存器和栈寄存器,准备加载后续的操作系统组件。
③ 加载 setup 模块:
在这里插入图片描述

图4.3 bootsect实现代码3
load_setup 子程序使用 BIOS 中断 INT 0x13 从软盘加载 setup.bin 到内存的 0x90200 处。
④ 输出加载信息并加载 Linux 内核:
在这里插入图片描述

图4.4 bootsect实现代码4
这部分代码输出加载信息,然后通过跳转将控制权转移到 setup.bin 中的代码。根据设置,setup.bin 将进一步加载 Linux 内核。
setup.asm :
① 读取机器参数:
在这里插入图片描述

图4.4 setup实现代码1
② 获取扩展内存大小:
在这里插入图片描述

图4.5 setup实现代码2
③ 获取显示模式和参数:
在这里插入图片描述

图4.6 setup实现代码3
④ 检查显示方式(EGA/VGA)并获取参数:
在这里插入图片描述

图4.7 setup实现代码4
⑤ 获取硬盘参数表信息:
在这里插入图片描述

图4.8 setup实现代码5
⑥ 检查第2个硬盘是否存在:
在这里插入图片描述

图4.9 setup实现代码6
⑦ 移动system模块到正确位置:
在这里插入图片描述

图4.10 setup实现代码7
⑧ 加载段描述符表和中断描述符表寄存器(idtr):
在这里插入图片描述

图4.11 setup实现代码8
⑨ 开启A20地址线:
在这里插入图片描述

图4.12 setup实现代码9
⑩ 进入保护模式:
在这里插入图片描述

图4.13 setup实现代码10
head.s:
① 设置中断描述符表(IDT):
在这里插入图片描述

图4.14 head实现代码11
在上述代码中,_setup_idt是设置中断描述符表的子程序。通过循环设置256个中断门描述符,每个中断门描述符占8字节。ignore_int是一个默认的中断处理程序。
② 设置全局描述符表(GDT):
在这里插入图片描述

图4.15 head实现代码12
在上述代码中,_setup_gdt是设置全局描述符表的子程序。通过加载全局描述符表寄存器gdt_descr,将全局描述符表设置好。
③ 设置分页:
在这里插入图片描述

图4.16 head实现代码13
在上述代码中,setup_paging是设置分页的子程序。通过填写页目录表和页表的项,最终启用分页处理。
3.仔细阅读 mkfloppy 应用程序项目的源代码。此应用程序默认会将 linux011.bin 文件写入软盘镜像文件从 5 号(从 0 开始计数)扇区开始的位置。尝试修改该应用程序,将 linux011.bin 文件写入从 8 号扇区开始的位置。将生成的 mkfloppy.exe 拷贝覆盖 VSCode 中的原有文件(旧文件做好备份,用于恢复)。修改 boot\bootsect.asm 中的汇编代码,使之能够从软盘 A 的 8 号扇区加载 linux011.bin 文件,确保 Linux 0.11 能够正常启动。
答:

** int ** Loadfile(**FILE ** * f, ** int ** off ** int ** size)
{
    **char ** buf[SECTOR_SIZE];
    ** int ** i,n;
    fseek(f,0SEEK_SET);
    ** if ** (off) fseek(f,off * SECTOR SIZE,SEEK SET);
    ** for ** (i=0: i < size: i + -SECTOR_SIZE) {
        fread(buf,1,SECTOR_SIZE,f);
        n = fwrite(buf,1,SECTOR_SIZE,img);
        ** if ** (n != SECTOR_SIZE) {
            fprintf(stderr, "write image error %d\n",n);
            **return ** -1;
        }
    }
** return ** 0;
}

这将文件写入从第8个扇区开始的位置.
然后将汇编文件bootsect asm中的mov cx1修改为mov cx4使之能够从软盘 A的 8号扇区加载 inux011.bin 文件,至此,文件可正常启动
4.将Linux 0.11内核项目中的makefile文件中目标all的脚本修改为如下内容:

BOOT = boot\bootsect.bin 
LOADER = boot\setup.bin 
...... 
TARGET = linux011.exe 
ARTIFACT = artifact.done 
...... 
all: $(TARGET) $(BOOT) $(LOADER) $(ARTIFACT) 
@echo - 
@echo -------- Build floppya.img -------- 
strip $(TARGET)
mkfloppy.exe $(BOOT) $(LOADER) $(TARGET) floppya.img 
@echo - 
@echo -------- Build Linux 0.11 success! --------

这样就会将 PE 格式的内核文件 linux011.exe 直接写入软盘镜像文件中,需要修改boot\bootsect.asm 中的汇编代码,使之在读取软盘 A 中的内核文件时,能够识别 PE 文件的格式,并且将 PE 文件中的指令和数据直接加载到内存中的指定位置,从而使 Linux 0.11 仍然能够正常启动。可以参考 pe2bin 项目中的源代码完成此练习。
答:
修改bootlbootsectasm中的代码。将代码中所有的 mov ax 0x9000和 mov es,ax语替换为以下代码:

1.mov ax,0x07c0;setup.s  ;将 setup 程序加载到此处
2.add ax,288           ;setup.s 加载的实际地址
3.mov ds,ax
4.mov es,ax

在代码中添加以下代码,以便在软盘 A 中寻找 PE 文件的头部:

1.mov bx,0x0080 ; PE 头部的偏移量,可以在 pe2bin 项目中找到
2.mov ah,2;BIOS 中的读磁盘函数mov
3.mov al,15;15个扇区
4.mov ch,0 ;柱面号为 0
5.mov cl,8;从第 8 个扇区开始读取
6.mov dh,0;磁头号为 0
7.**int**  0X13;调用读磁盘函数
8.jc boot_error ;如果出现错误,则跳转到 boot_error 标签

在代码中添加以下代码,以便将 PE 文件中的指令和数据直接加载到内存中的指定位置:

1.mov ax,0x1000;内核加载的地址
2.mov es,ax;用 ES 寄存器来指定段地址
3.mov bx,0x0000 ;偏移地址为 0
4.mov ah,2;BIOS 中的读磁盘函数
5.mov al,15 ;15个扇区
6.mov ch,0;柱面号为 0
7.mov cl,9;从第 9 个扇区开始读取,因为前 8 个扇区已经被用来加载 setup 和内核了
8.mov dh,0;磁头号为 0
9.**int** 0X13;调用读磁盘函数
10.jc boot error;如果出现错误,则跳转到 boot_error 标签

5.总结和感想体会
通过本次实验,我深刻理解了Linux 0.11操作系统的启动过程,这是对操作系统底层运行机制的一次深入学习。一开始,我通过学习了Linux 0.11操作系统启动的原理和整体过程,对bootsect.bin和setup.bin的功能有了清晰的认识。
在实验中,通过模拟实验和亲自动手进行代码实践,我更加深入地理解了bootsect.bin和setup.bin的作用以及它们在整个启动过程中的角色。成功地启动了Linux 0.11操作系统是对我学习成果的一个实质性体现,这使我对操作系统的启动过程有了更为直观和深入的认识。
此外,实验还让我认识到操作系统启动的复杂性和重要性。在启动过程中,硬件和软件需要紧密协调,每个环节都必须精确执行,任何一个环节出现问题都可能导致系统无法正常启动或运行不稳定。这对于我理解系统底层运行机制,提高代码调试和排查问题的能力都是非常有益的。
最重要的是,通过实验,我对Linux操作系统的底层实现和原理有了更深入的了解。这为我今后在系统编程、内核开发等方面的学习和工作奠定了坚实的基础。总体而言,这是一次收获颇丰、知识水平得到提升的实践性学习经历。
参考文献
[1]汪杭军,操作系统内核的比较与研究[J],2005
[2]杜传业. 嵌入式Linux内核解析[D].河北工业大学,2007
[3]《Linux内核实验教程》
[4]唐朔飞著。计算机组成原理。北京:高等教育出版社,2000

  • 14
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

白鹿依海

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值