代码阅读报告1_涂李傲

上传人:第*** 文档编号:31390371 上传时间:2018-02-07 格式:DOCX 页数:16 大小:63.08KB
返回 下载 相关 举报
代码阅读报告1_涂李傲_第1页
第1页 / 共16页
代码阅读报告1_涂李傲_第2页
第2页 / 共16页
代码阅读报告1_涂李傲_第3页
第3页 / 共16页
代码阅读报告1_涂李傲_第4页
第4页 / 共16页
代码阅读报告1_涂李傲_第5页
第5页 / 共16页
点击查看更多>>
资源描述

《代码阅读报告1_涂李傲》由会员分享,可在线阅读,更多相关《代码阅读报告1_涂李傲(16页珍藏版)》请在金锄头文库上搜索。

1、代码阅读报告(1)涂李傲 2010013234 软 01目录1:阅读内容2:代码阅读2.1 asm.h2.2 bootasm.s2.3 x86.h 2.4 elf.h2.5 bootmain.c3:操作系统启动引导的流程分析4:简答题5:阅读心得1:阅读内容本次阅读包含以下几个文件:asm.h:是 bootasm.s汇编文件所需要的头文件,主要是一些与X86保护模式的段访问方式相关的宏定义。bootasm.s:定义并实现了 bootloader最先执行的函数 start,此函数进行了一定的初始化,完成了从实模式到保护模式的转换,并调用 bootmain.c中的 bootmain函数。types

2、.h:包含一些无符号整型的缩写定义。x86.h:一些用 GNU C 嵌入式汇编实现的 C 函数。elf.h:定义了 ELF 文件的结构。bootmain.c:定义并实现了 bootmain 函数。2:代码阅读2.1.asm.h该文件是 bootasm.s汇编文件所需要的头文件,主要是一些段描述符的宏定义。(1)#define SEG_NULLASM .word 0, 0; .byte 0, 0, 0, 0 代码功能:把段(长度为 8字节)基地址和大小都置为0(感觉有点像 null) ,然后在 bootasm.h中的gdt:SEG_NULLASM # null seg调用了这个函数,构建了空段。

3、(2)#define SEG_ASM(type,base,lim) .word (lim) 12) .byte (base) 16) & 0xff), (0x90 | (type), (0xC0 | (lim) 28) & 0xf), (base) 24) & 0xff)代码功能:定义了长度为 8字节的一般段。(3)#define STA_X 0x8 / Executable segment#define STA_E 0x4 / Expand down (non-executable segments)#define STA_C 0x4 / Conforming code segment (e

4、xecutable only)#define STA_W 0x2 / Writeable (non-executable segments)#define STA_R 0x2 / Readable (executable segments)#define STA_A 0x1 / Accessed定义了段的六种类型2.2.bootasm.s该文件保存于硬盘设备的第一个扇区中,在开机的时候由BIOS加载到物理内存的 0x7C000x7CFF处,然后在 ”real mode”下开始执行,此时有 %CS=0 %IP=0x7C00(1)start:cli # Disable interrupts此处开始

5、进入 start函数,先发出一条指令“cli” ,那么它的用处是关闭中断。这里我的理解是 BIOS就像一个小的 CPU,它自己会产生中断,但是这个时候 BIOS已经运行完了,如果放任这些中断存在的话就会给硬件提供“interrupt handlers” ,但是这个时候存在“interrupt handlers”是不安全的,所以我们要关闭中断,等到 x86准备好了再重新恢复中断。(2)xorw %ax,%ax # Segment number zeromovw %ax,%ds # - Data Segmentmovw %ax,%es # - Extra Segmentmovw %ax,%ss #

6、 - Stack Segment由于在 BIOS中寄存器的值是不可知的,所以为了后面能够正常运行,在这里需要将寄存器进行初始化,这样代码就很直观了。就是先将寄存器%ax 置为 0,再将 0值赋给%ds,%es 和%ss(3)seta20.1:inb $0x64,%al # Wait for not busytestb $0x2,%aljnz seta20.1movb $0xd1,%al # 0xd1 - port 0x64outb %al,$0x64seta20.2:inb $0x64,%al # Wait for not busytestb $0x2,%aljnz seta20.2movb

7、$0xdf,%al # 0xdf - port 0x60outb %al,$0x60根据 x86相关文档,segment:offset 模式可以表示 21位的物理地址,但是 Intel 8088 只支持 20 位内存地址,但是通过段-偏移方式可以支持 21位内存地址。这样一来 Intel 8088 会将自动丢弃最高位的数据从而出现错误。IBM 为了避免这个问题,于是提供了一种兼容方式:当键盘控制器输出端口的第 2 位为低位时, A20始终清零,而当其置为高位时,A20 可以正常使用。在这段代码中通过检测 0x64寄存器中的第二位是否为 1来判断键盘缓存中是否有数据。当键盘空闲(第二位为 0时)

8、的时候向0x64寄存器中写入 0xd1(表示下一个写入 0x60 端口的数据将被置于 8042 键盘控制器的输出端口) ,向 0x60寄存器中写入 0xdf(将键盘控制端口的第二位置为 1)打开 A20地址线,这样就可以使用21位地址啦!(4)lgdt gdtdescmovl %cr0, %eaxorl $CR0_PE, %eaxmovl %eax, %cr0第一行的作用是将 GDT的地址设置为 gdtdesc。一旦装载了GDT 寄存器,扇区就会通过将 CR0_PE 装入寄存器 cr0开启“protected mode”。后面三行的作用则是置%cr0 寄存器的 PE 位。$CR0_PE=1,因

9、此,这三行是置%cr0 寄存器的第 0 位为 1,该位为 0 时,CPU 运行于“real mode” ,为 1 时,CPU 运行于“protected mode”。当第四行执行完成后,CPU 就运行在保护模式下了。(5)ljmp $(SEG_KCODE DS: Data Segmentmovw %ax, %es # - ES: Extra Segmentmovw %ax, %ss # - SS: Stack Segmentmovw $0, %ax # Zero segments not ready for usemovw %ax, %fs # - FSmovw %ax, %gs # - GS

10、这一块的作用和 bootasm.s最前面一块的作用基本是类似的,就不多说了。(7)movl $start, %espcall bootmain将$start 的地址(0x7C00)赋值给%esp 寄存器,将 0x7C00设置为栈顶,之后栈指针就会从 0x7c00 开始递减,而不会覆盖掉启动扇区的代码。而后面那一行就要开始调用 bootmain函数了,这个函数到目前为止还没有出现,所以我会在后面详细说。(8)movw $0x8a00, %ax # 0x8a00 - port 0x8a00movw %ax, %dxoutw %ax, %dxmovw $0x8ae0, %ax # 0x8ae0 -

11、port 0x8a00outw %ax, %in:jmp spin这段代码从 boot.pdf上来看好像是用来处理错误的,一般情况下我们不会调用,而一旦调用就会出现死循环,这个时候有这么一句话:“A real boot sector might attempt to print an error message first”。估计这样的直接结果就是重新启动计算机吧好的,现在我们已经把 bootasm.s给过了一遍,感觉总体上和 boot.pdf讲的差不多,接下来我们来看看几个头文件2.3 x86.h 该头文件包含了嵌入式汇编的 C函数,供 C程序使用汇编指令。由于在第一次作业中不是所有定义过的

12、函数都出现了,所以下面我只介绍在 bootmain.c中被用到的函数;(1)static inline ucharinb(ushort port)uchar data;asm volatile(in %1,%0 : =a (data) : d (port);return data;实现了将从外部 I/O 设备通过 port端口的输入数据(1 Byte)读入到 data 之中的功能。同时函数的最后返回了 data。(2)static inline voidoutb(ushort port, uchar data)asm volatile(out %0,%1 : : a (data), d (po

13、rt);这个感觉和 inb非常的像,就是将顺序反了一下,将 data 数据通过 port端口写入外部 I/O 设备。(3)static inline voidinsl(int port, void *addr, int cnt)asm volatile(cld; rep insl :=D (addr), =c (cnt) :d (port), 0 (addr), 1 (cnt) :memory, cc);从端口 port 中读取 4cnt 个字节到起始地址为 addr 的内存中。实现了类似字符串读入的操作。(4)static inline voidstosb(void *addr, int d

14、ata, int cnt)asm volatile(cld; rep stosb :=D (addr), =c (cnt) :0 (addr), 1 (cnt), a (data) :memory, cc);实现了将 data 数据重复 cnt次写向 addr所指向的地址。2.4 .elf.h该文件定义了 ELF 文件的结构。 ELF 文件格式是一个开放的标准各种 UNIX 系统的可执行文件都采用 ELF 格式,它有三种不同的类型: 可重定位的目标文件 可执行文件 共享库在 xv6 的 ELF 文件格式中,仅定义了可执行文件这一种类型;本文件定义了 elfhdr 和 prohdr 结构体,下面进行解释;(1)struct elfhdr uint magic; /前文所述的 ELFchar95 MAGICuchar elf12; /Magic Number和其他信息ushort

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 办公文档 > 其它办公文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号