现在的位置: 首页 > 综合 > 正文

一个操作系统的实现实验之 搭建工作环境

2013年03月17日 ⁄ 综合 ⁄ 共 3975字 ⁄ 字号 评论关闭

搭建工作环境 Linux平台+Nasm+Bochs


Nasm的安装

1.官网下载nasm的linux版本

2.依次执行./configure,make,sudo make install。最后提示某个文件创建失败,不过不影响编译过哦功能。

3.nasm boot.asm -o boot.bin


Bochs的安装(文件格式tar.gz   版本2.3.5和2.4.5)
1.tar zvxf解压
2.在解压后的目录中执行 ./configure --enable-debugger --enable-disasm
3.make。
2.3.5  遇到"ISO C++ forbids declaration of ‘hash_map’ with no type"的错误。
在网上查到的修改方法为:加入hash_map的命名空间,修改bx_debug/symbols.cc。
在文件开始加入  #include <ext/hash_map>和using namespace __gnu_cxx;(别忘了分号)
文章还提到了另外一个错误"没有找到yacc命令"。解决方法:安装yacc包,sudo apt-get install bison++

2.4.5  遇到"MakeGTKthreads()  gtk_enh_dbg_osdep.cc:2120: undefined reference to 'pthread_create'"错误。
解决方法:Makefile文件 92行末尾增加 -lpthread参数。

4.sudo make install

5.bximage创建a.img,用dd命令将boot.bin文件写入a.img。用vi打开a.img,如果dd执行成功可以看到文件开头内容发生了变化。

6.修改.bochsrc配置文件。
找了老半天也没找到了它,后来从网上的文章才知道它是隐藏文件,书上也没指出这点,害的我浪费了不少时间。
用vi打开,修改了书上指出的比较关键的选项,保存退出,启动bochs。
满以为可以看到"Hello,os world!",不过等待我的是一个错误消息对话框,提示信息为"ata0 M30.sample 无法打开"。
我心想这么大的错误怎么书上一点没提啊,真急人。
重新打开.bochsrc,找到关于ata0的部分,换了一个用c.img的选项,退出重新试着启动bochs,仍然是类似的错误提示。
没办法只能打开google搜索解决办法了。
在搜索结果里看到别人写的有关atao的语句,分别用了c.img、hda0.img。
结合前两次考到的提示,明白是因为设置语句中指定的给ata0的img文件有问题,所以boch总是执行到这里报错。
同时也想到用bximage创建一个硬盘的img文件给ata0用。于是就按着创建a.img的步骤创建了hdc.img,并记下了相关参数。
按记下的数据修改了.bochsrc,启动bochs,这回终于没报错了。
bochs顺利启动,停在了debug提示符处。
输入c,回车,在bochs窗口中看到了"Hello,os world!"。


bochs的常用调试命令

b addr 在物理地址处设置断点;b 0x7c00 让系统停在语句0x7c00处,也就是引导扇区开始工作的地方。

lb 在线性地址处设置断点;

info break 显示当前所有的断点的信;

dump_cpu   查看寄存器;

xp /nuf addr 显示物理内存的数据;:xp /32bx 0x7c00 ----显示0x7c00 开始处的内存  32bx --b 代表字节  x 表示16进制

x /nuf addr 显示线性内存地址的数据

n 单步执行,跳过子程序;

s 单步执行;

s num ( s指令后加一数字) 执行n步

trace-reg on 每执行一步显示主要寄存器信息

c 继续执行,直到遇到断点

disassemble [/count] start end 反汇编一段线性内存;


主要调试信息分析

1.bochs启动后,等待输入时,此时为cpu刚刚上电状态,来看看一些主要寄存器信息(输入dump_cpu)。

esp:0x00000000,  

eip:0x0000fff0,  

cs:s=0xf000,  其它段寄存器都为0

gdtr:base=0x00000000, limit=0xffff

对以上信息的解释引用自《PC开机过程-386以上cpu》:

8086的CPU开机后执行的第一条指令的物理地址是0xFFFF0,这个物理地址的形成是利用CS的值0xF000左移4位然后加上偏移量IP的值0xFFF0形成的;
32位CPU开机后执行的第一条指令的物理地址是0xFFFFFFF0(CS和IP的值和也是0xF000和0xFFF0);那么这个物理地址是如何形成的呢?
答案是这样的:我们通常都说32位CPU开机后首先是处于实模式;不过刚开机的时候CPU并不是按照我们通常所说的那种实模式寻址,即:物理地址=CS×16+IP;而是使用保护模式下的那种寻址方式;一旦CS中的值被改变了,那么CPU就会恢复到我们通常所说的那种实模式的寻址方式下。然而我们知道保护模式寻址需要根据段选择子从GDT或者LDT中找出相应的描述符,然后取出段基址,用段基址加上偏移量才能得到线性地址;不过在执行第一条指令的时候根本不存在GDT和LDT阿;原来从80286开始每个段寄存器都配有一个高速缓冲寄存器,称之为段描述符高速缓冲寄存器,对程序员而言它是不可见的。每当把一个选择子装入到某个段寄存器时,处理器自动从描述符表中取出相应的描述符,把描述符中的信息保存到对应的高速缓冲寄存器中。此后对该段访问时,处理器都使用对应高速缓冲寄存器中的描述符信息,而不用再从描述符表中取描述符。刚开机的时候CPU会把CS对应的段描述符高速缓冲寄存器中的段基址初始化为0xFFFF0000,并且段限长初始化为0xFFFF(64KB)。这样就能得到第一条指令的物理地址是0xFFFFFFF0。

也因为这个原因,ROM BIOS要被映射到了内存物理地址空间中最后一个段中。当BIOS初始化完毕之后远跳转到0x7c00处开始运行实模式程序时就开始按照通常的实模式寻址方式了,按理说这时候最大寻址空间就是1M,为什么仍然能在0xf000段中访问到ROM BIOS中的代码呢?
请看下面:我们说的BIOS ROM,包括很多BIOS的ROM,如视频BIOS ROM和SCSI卡BIOS ROM等,当然还包括我们传统意义上的包含冷启动程序代码以及一系列原始中断服务程序的BIOS的ROM,由于技术的发展,这一部分ROM现在变得非常大,如现在一般的传统BIOS ROM就达2M以上,而视频BIOS ROM等都更大,以前习惯上把这些ROM的地址空间安排在640k以上1M以下的空间里(也就是说640k~1M这一段地址指向ROM而不是指向 RAM)。但这一点空间是明显安排不下现在的ROM的,又为了不让这一段ROM的地址将RAM的地址隔离成两段,一般都将这段ROM的地址空间安排在 CPU所能访问到的地址的最高端。

但为什么我们的程序经过内存空间最高端(0xFFFFXXXX~0xFFFFFFF0)这一段reset code(冷启动代码),并跳转到0x0000:7c00之后,却能从内存地址640k~1M的一段空间里看到诸如reset code等只有在BIOS ROM空间里才会存在的东东的蛛丝马迹呢?理论上此时的640k~1M应该是RAM空间啊?没错这一段现在的确是RAM空间,但基于一个这样的事实,那就是一般ROM的读写速度都比RAM的读写速度慢,所以在执行BIOS ROM中的冷启动代码时,该段代码会将一些重要的与以前的BIOS ROM兼容的东西(如冷启动代码本身)拷贝到640k~1M的地址空间,以后要访问这些内容时就直接到640k~1M的地方去拿,这同时还解决了一个很重要的问题,那就是在实模式下默认是访问不了1M以上的空间的,而BIOS ROM又位于1M以上,那么正好通过访问640k~1M的BIOS ROM副本达到访问BIOS ROM的目的,我们同时也可以看到,拷贝到640k~1M中来的原BIOS ROM中的内容,也是与实模式紧密相关的内容(而那些与实模式关系不大的内容一般就不拷贝过来,也没有地方容纳得下),这个过程叫做BIOS地址映射,它不但达到了提高BIOS访问速度的目的(因为实际上是访问RAM),又使RAM的地址空间没有被隔离开,同时还保持了与8086的兼容性(因为8086默认保留640k~1M的空间给BIOS使用)。

但是现在又有一个问题:通过什么方法把处于接近4G物理地址处的BIOS中关于实模式的内容映射到实际物理地址640K~1M的地方?事情是这样的:在刚加电或者reset时,CPU实际上处于一种特殊“保护模式”状态。因此此时虽然 CS Selector = 0xF000,但是不能用实模式下的左移4位再加Offset来确定实际地址。此时:CS Base 就是 0xFFFF0000。而此时的EIP就是CS段中偏移值。 而所有其他段寄存器(ES,DS,ES,FS,SS等)值都是0,基地址 base也为0。因此一开始除CS以外其他段寄存器都可以寻址物理地址0--64KB范围,而CS也只能寻址64KB范围,因为其段限长也是64KB。因此可以看出,EPROM中必定包含一个使用大模式(这是我随便起的名称:))用来操作代码和数据移动到低端(640KB-1MB)。即BIOS ROM中应该有临时在GDT中设置一个长4GB大段的代码。

2.停在0x7c00处u时

esp:0x0000ffdc,

eip:0x00007c00,
cs:s=0x0000, dl=0x0000ffff, dh=0x00009b00, valid=1
gdtr:base=0x000fa802, limit=0x30
此时GDTR已经被初始化,说明cpu运行在保护模式下了。

抱歉!评论已关闭.