项目的源码
相比较于 显示字符的toy bootloader 这个的修改, proj2的基础上的主要修改如下。
λ git status
On branch master
Your branch is up to date with 'origin/master'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: Makefile
modified: boot/bootasm.S
modified: boot/bootmain.c
modified: libs/types.h
modified: libs/x86.h
modified: tools/gdbinit
Untracked files:
(use "git add <file>..." to include in what will be committed)
libs/elf.h
no changes added to commit (use "git add" and/or "git commit -a")
新增了一个elf头文件,因为要解析elf文件的格式。必须要有描述其的结构体。
boot/bootmain.c 是主要的修改的地方
#define ELFHDR ((struct elfhdr *)0x10000) // scratch space
void
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) {
cons_putc('E');
}
/* do nothing */
while (1);
我们查看一下readseg函数的实现
static void
readseg(uintptr_t va, uint32_t count, uint32_t offset) {
//起始地址是0x10000, 结束的地址是 0x10000 + count, 这里的地址指的都是cpu的逻辑地址, offset是从硬盘的哪个地方开始读取
uintptr_t end_va = va + count;
// round down to sector boundary
va -= offset % SECTSIZE; //这个是为了避免offset不是512的整数倍出现的问题。但是设计的时候一般都是整数的,不会设计的这么无聊
// translate from bytes to sectors; kernel starts at sector 1
uint32_t secno = (offset / SECTSIZE) + 1;//计算一下offset对应的硬盘sector是哪一个,因为第0个sector是主引导分区
// If this is too slow, we could read lots of sectors at a time.
// We'd write more to memory than asked, but it doesn't matter --
// we load in increasing order.
for (; va < end_va; va += SECTSIZE, secno ++) {
readsect((void *)va, secno);
}
}
我们使用gdb调试这个工程,因为现在 ((struct elfhdr *)0x10000) 地址处没有任何的东西,所以现在这个程序执行肯定是有问题的,他只是把磁盘的某个位置读取到了内存里。
一个硬盘分区的大小是一个sector,也就是512个字节
#define SECTSIZE 512