通过阅读bootmain.c,了解bootloader如何加载ELF文件。分析bootloader如何读取硬盘扇区的
以及bootloader如何加载ELF格式的OS。
首先我们来分析BOOTMAIN.C文件
bootmain(void) {
// read the 1st page off disk
readseg((uintptr_t)ELFHDR, SECTSIZE * 8, 0); //读取磁盘内容,
// is this a valid ELF?
if (ELFHDR->e_magic != ELF_MAGIC) { //判断e_magic的值,通过这个值判断是否有效
gotobad;
}
cons_putc('B'); //如果有效打印B
/* do nothing */
while (1);
bad:
cons_putc('E'); //如果出现了问题打印出E
outw(0x8A00, 0x8A00);
outw(0x8A00, 0x8E00);
/* do nothing */
while (1);
}
下面对于读取硬盘的函数单独的分析:
readseg: //用来读取扇区的内容
uintptr_t end_va = va +count;
//找到结束位置的地址
// round down to sector boundary
va -= offset % SECTSIZE;
// translate from bytes to sectors; kernel starts atsector 1
uint32_t secno = (offset / SECTSIZE) + 1; //将空间分为几个扇区进行读取操作
//用secno记录扇区数
for (; va < end_va; va += SECTSIZE, secno ++) {
readsect((void *)va,secno); //此时调用上面的函数进行操作
}
跟踪函数运行:
注意观察其中的指令地址为0x7c4a处的代码是CALL指令从这个地方开始执行bootmain函数
调用函数的压栈动作
观察下面的结果:
发现什么现象?
现象很奇怪:就是程序执行到0x7d8e停在了这里
这个指令为repnz,这也就是我们在proj执行时看到E的原因.
我们来分析这个看到无法正常执行信号E产生的原因:
在X86.h中的代码为:
insl(uint32_t port, void *addr, int cnt) {
asm volatile (
"cld;"
"repne;insl;"
: "=D"(addr), "=c" (cnt)
: "d"(port), "0" (addr), "1" (cnt)
:"memory", "cc");
}