#include <inc/x86.h>
#include <inc/elf.h>
/*这是一个简单粗略的boot loader,它唯一的工作就是
从硬盘的第一个扇区启动格式为ELF的内核镜像
硬盘布局
这个程序(包括boot.S和main.c)组成了bootloader,
它应该存储在硬盘的第一个扇区
第二个扇区存储着内核映像
内核映像必须为ELF格式的
启动步骤
当CPU启动时,它加载BIOS到内存中并且执行BIOS
BIOS程序初始化设备,设置中断例程,并且将启动装置(例如硬盘)
中的第一个扇区的内容加载到内存,并且跳转到那里
假设这个bootloader存储在硬盘的第一个扇区,这个代码从BIOS接收了CPU控制权
控制从boot.S文件开始--这个文件设置了保护模式和一个栈,这样
C代码就可以运行了,然后再调用bootmain()
这个文件中的bootmain函数接过控制权之后,读取内核文件并且跳转到内核*/
//扇区的大小为512
#define SECTSIZE 512
//将内核加载到内存的起始地址
#define ELFHDR ((struct Elf *) 0x10000) // scratch space
//该函数的作用是读取一个节的内容,也就是读取一个扇区的内容
void readsect(void*, uint32_t);
//函数的作用是读取一个程序段
void readseg(uint32_t, uint32_t, uint32_t);
void
bootmain(void)
{
//定义了两个程序头表项指针
struct Proghdr *ph, *eph;
//将硬盘上从第一个扇区开始的4096个字节读到内存中地址为0x10000处
readseg((uint32_t) ELFHDR, SECTSIZE*8, 0);
//检查这是否是一个合法的ELF文件
if (ELFHDR->e_magic != ELF_MAGIC)
goto bad;
//找到第一程序头表项的起始地址
ph = (struct Proghdr *) ((uint8_t *) ELFHDR + ELFHDR->e_phoff);
//程序头表的结束位置
eph = ph + ELFHDR->e_phnum;
//将内核加载进入内存
for (; ph < eph; ph++)
//p_pa就是该程序段应该加载到内存中的位置
//读取一个程序段的数据到内存中
readseg(ph->p_pa, ph->p_memsz, ph->p_offset);
//开始执行内核
((void (*)(void)) (ELFHDR->e_entry))();
bad:
outw(0x8A00, 0x8A00);
outw(0x8A00, 0x8E00);
while (1)
/* do nothing */;
}
//这个函数的作用是从ELF文件偏移为offset处,读取count个字节到内存地址为pa处
void
readseg(uint32_t pa, uint32_t count, uint32_t offset)
{
//段的结束地址
uint32_t end_pa;
//计算段的结束地址
end_pa = pa + count;
//将pa设置为512字节对齐的地方
pa &= ~(SECTSIZE - 1);
//将相对于ELF文件头的偏移量转换为扇区,ELF格式的内核文件存放在第一个扇区中
offset = (offset / SECTSIZE) + 1;
//开始读取该程序段的内容
while (pa < end_pa) {
//每次读取程序的一个节,即一个扇区
//也就是将offset扇区中的内容,读到物理地址为pa的地方
readsect((uint8_t*) pa, offset);
//将pa的值增加512字节
pa += SECTSIZE;
//读取下一个扇区
offset++;
}
}
void
waitdisk(void)
{
// wait for disk reaady
while ((inb(0x1F7) & 0xC0) != 0x40)
/* do nothing */;
}
void
readsect(void *dst, uint32_t offset)
{
// wait for disk to be ready
waitdisk();
outb(0x1F2, 1); // count = 1
outb(0x1F3, offset);
outb(0x1F4, offset >> 8);
outb(0x1F5, offset >> 16);
outb(0x1F6, (offset >> 24) | 0xE0);
outb(0x1F7, 0x20); // cmd 0x20 - read sectors
// wait for disk to be ready
waitdisk();
// read a sector
insl(0x1F0, dst, SECTSIZE/4);
}