《系统软件开发实践》 实验报告 第15页
ld命令将这些目标文件转变成可执行文件,比如此处的bootblock.out dd命令把bootloder放到ucore.img count的虚拟硬盘之中 还生成两个软件,一个是Bootloader,另一个是kernel 分析lab1/tools/sign.c中的代码一个被系统认为是符合规范的硬盘主引导扇区的特
征可以从以下代码看出,即一个规范的硬盘引导扇区的大小为512字节,硬盘结束标志位55AA。
fclose(ifp);
buf[510] = 0x55; buf[511] = 0xAA;
FILE *ofp = fopen(argv[2], \ size = fwrite(buf, 1, 512, ofp); if (size != 512) { fprintf(stderr, is %d.\\n\ return -1; }
fclose(ofp);
printf(\512 bytes boot sector: '%s' success!\\n\ return 0;
\
'%s'
error,
size
顺便谈一下Makefile,它是用于自动编译和链接的,一个工程有很多文件组成,每一个文件的改变都会导致工程的重新链接,但是不是所有的文件都需要重新编译,Makefile中纪录有文件的信息,在make时会决定在链接的时候需要重新编译哪些文件。Makefile就是让编译器知道要编译一个文件需要依赖其他的哪些文件。当那些依赖文件有了改变,编译器会自动的发现最终的生成文件已经过时,而重新编译相应的模块。
使用automake,程序开发人员只需要写一些 简单的含有预定义宏的文件,由autoconf根据一个宏文件生成configure,由automake根据另一个宏文件生成Makefile.in, 再使用configure依据Makefile.in来生成一个符合惯例的Makefile。
主引导扇区包括硬盘主引导记录和分区表DPT。其中主引导记录的作用就是检查分区表是否正确以及确定哪个分区为引导分区,并在程序结束时把该分区的启动程序,也就是操作系统引导扇区调入内存加以执行。
主引导扇区记录硬盘上每一个分区的数据的地方,这个地方不存放实际的数据,只保存每一个扇区的信息。类似图书馆里面的书和图书馆的藏书目录,主引导扇区是目录,每一个扇区里面存放的是书,如果目录丢失了,你将无法找到想要的书了,当然这个目录在某种情况下是能用软件恢复的的。 完成这个操作的方法有两种,一种是使用系统的格式化程序,我们知道在安装系统的时候我们最开的的操作就是划出分区,格式化硬盘才可以,这个操作就能完成。还有一种就是使用专业的硬盘操作软件,在DOS下完成。
}
-
《系统软件开发实践》 实验报告 第16页
(2)使用qemu执行并调试lab1中的软件
本次练习主要是了解从CPU加电后执行的第一条指令开始, 单步跟踪BIOS的执行并在初始化位置0x7c00设置实地址断点,测试断点正常、从0x7c00开始跟踪代码运行,将单步跟踪反汇编得到的代码与bootasm.S和 bootblock.asm进行比较。然后自己找一个bootloader或内核中的代码位置,设置断点并进行测试。
在初始化位置0x7c00 设置实地址断点,测试断点正常,下面是我在linux环境下运行的一张截图:
在tools/gdbinit结尾加上 set architecture i8086
b *0x7c00 //在0x7c00处设置断点。 continue
x /2i $pc //显示当前eip处的汇编指令
我们主要通过硬件模拟器qemu来进行各种实验。在实验的过程中我们可能会遇上各种各样的问题,调试是必要的。qemu支持使用gdb进行的强大而方便的调试。所以用好qemu和gdb是完成各种实验的基本要素。
将执行的汇编代码与bootasm.S和 bootblock.asm 进行比较可知Notice:在q.log中进入BIOS之后的跳转地址与实际应跳转地址不相符,汇编代码也与bootasm.S和 bootblock.asm不相同,这是由于在gdb之中调试的原因,可以直接输入make debug,在生成的qemu虚拟机之中进行调试可以看到在虚拟机中运行的汇编代码,之后再与bootasm.S和 bootblock.asm 进行比较与bootasm.S和bootblock.asm中的代码相同。
(3)分析bootloader进入保护模式的过程
本次以注释和代码相结合的方式分析bootloader进入保护模式的过程: globl start start: .code16
# 关中断,并清除方向标志,即将 DF 置“0”,这样(E)SI 及(E)DI 的修改为增量 cli cld
# 清零各数据段寄存器:DS、ES、FS xorw %ax, %ax movw %ax, %ds movw %ax, %es movw %ax, %ss
-
《系统软件开发实践》 实验报告 第17页
# 使能 A20 地址线,这样 80386 就可以突破 1MB 访存现在,而可访问 4GB 的 32 位地址空间 seta20.1:
inb $0x64, %al # 等待8042键盘控制器不忙testb $0x2, %al jnz seta20.1 movb $0xd1, %al outb %al, $0x64 seta20.2:
inb $0x64, %al # 等待8042键盘控制器不忙 testb $0x2, %al jnz seta20.2
movb $0xdf, %al # 打开A20 outb %al, $0x60 # 初始化gdt lgdtgdtdesc # 进入保护模式 movl %cr0, êx
orl $CR0_PE_ON, êx movl êx, %cr0 # 长跳转
ljmp $PROT_MODE_CSEG, $protcseg .code32 protcseg:
# 设置段寄存器,并建立堆栈 movw $PROT_MODE_DSEG, %ax movw %ax, %ds movw %ax, %es movw %ax, %fs movw %ax, %gs movw %ax, %ss # 设置堆栈
movl $0x0, ?p
movl $start, %esp # 栈顶为0x7c00 # 进入bootmain,不再返回 callbootmain spin: jmp spin
(4)分析 bootloader 加载 ELF 格式的 OS 的过程
读一个扇区的流程大致如下:首先读 I/O 地址 0x1f7,等待磁盘准备好,写 I/O 地址 0x1f2~0x1f5,0x1f7,发出读取第offseet个扇区处的磁盘数据的命令,读 I/O 地址 0x1f7,等待磁盘准备好,连续读 I/O 地址 0x1f0,然后把磁盘扇区数据读到指定内存。最后在bootmain函数中完成加载ELF格式os的操作如下: 1:读取ELF的头部;
2:判断ELF文件是否是合法;
-
《系统软件开发实践》 实验报告 第18页
3:将描述表的头地址存在ph;
4:按照描述表将ELF文件中数据载入内存;
5:根据ELF头部储存的入口信息,找到内核的入口。
(5)实现函数调用堆栈跟踪函数
在这个练习中需要注意ss:ebp指向的堆栈位置储存着caller的ebp,以此为线索可以得到所有使用堆栈的函数ebp。ss:ebp+4指向caller调用时的eip,ss:ebp+8等是参数。
(6)完善中断初始化和处理 1、完善初始化函数 idt_init
可以在/lab1/kern/mm/mmu.h中可以找到SETGATE函数,查找其具体操作。
idt_init(void) {
externuintptr_t __vectors[]; int i;
for (i = 0; i SETGATE(idt[i], 0, GD_KTEXT, __vectors[i], DPL_KERNEL); //设置IDT } lidt(&idt_pd); //载入IDT表 2、完善中断处理函数 trap case IRQ_OFFSET + IRQ_TIMER: ticks ++; //一次中断累加1 if (ticks % TICK_NUM == 0) { print_ticks(); } break; 实验六(第六周选作) 物理内存管理(lab2实验) 一、实验目的 1、理解基于段页式内存地址的转换机制; 2、理解页表的建立和使用方法; 3、理解物理内存的管理方法。 -
相关推荐: