1.操作系统的启动
- 1、从BIOS到系统kernel
- 1.1.开机取得BIOS
- 1.2.BIOS干什么
- 1.3. bootloader的512个字节做什么
- 1.4.代码表现
1、从BIOS到系统kernel
1.1.开机取得BIOS
BIOS 是存在一段掉电不丢失的rom中,或者说是内存中。计算机约定,上电后再所有硬件稳定后,到某个地方去取得BIOS的程序进行执行。(这里有点模糊,按照我学硬件想法BIOS应该是存在EEPROM(特点的掉电不丢失rom)中而不是内存中,因为内存关闭了就是会消失的,但是说成掉电不丢失内存也是可以的)。具体的约束图如下
开机启动,计算器处于实模式,它要取得的代码指针地址 PC = 16*CS+IP ,我们约定CS:IP = 0xf000:fff0 。就是1M的那个地方,开始读取BIOS;
1.2.BIOS干什么
当然BIOS会干很多事,要查看详细开发文档。但是总结我们需要关注的是
第一:它会把硬件检测好,将显示器,输入输出设备带入到一种正常的状态。
第二:它会读第一个扇区(一般是第一个)的512个字节(bootloader),放到内存中(约定0x7c00)。
这个两点大概是BIOS主要做的。最后BIOS通过JMP(每个cpu不同)指令,跳到0x7c00,以后就没有BIOS什么事情了。
1.3. bootloader的512个字节做什么
- 第一:使能段模式也就是保护模式,
- 第二:继续读取512个字节,也就是跟在自己屁股后面的kernel。它是个elf格式的文件,有文件头信息,可以知道代码偏移。可以知道数据段等。
把kernel放到内存中。最后还做JMP跳转到kernel放的那个地址。bootloader就没什么事了。所有的事都交给kernel。
kernel起来后需要做很多事情,需要,中断异常,系统调用,内存管理,进程管理等等很多事情。
1.4.代码表现
上面讲到从 BIOS --》bootloader --》kernel
从中说切换时都是JMP 跳转指令。这个切换只是说用JMP大概的概括,确实任何程序间的跳转都是可以用JMP来概括。我们来看下系统代码里的表现,
BIOS 到BootLoader 就不说了 最终会调用到 bootloader.S 然后切换到 BootLoader.c
在 bootloader汇编里面 直接调用 下面的指令
call bootmain
该函数在 BootLoader.c
void
bootmain(void) {
// call the entry point from the ELF header
// note: does not return init()
((void (*)(void))(ELFHDR->e_entry & 0xFFFFFF))();
bad:
outw(0x8A00, 0x8A00);
outw(0x8A00, 0x8E00);
/* do nothing */
while (1);
}
看注释 也是直接调用( ELFHDR->e_entry)而这个 e_entry 就是 kern_init
然后就是 while (1);死等这边。
其实注释也说了 init也别返回 如下
void
kern_init(void){
extern char edata[], end[];
memset(edata, 0, end - edata);
cons_init(); // init the console
const char *message = "(THU.CST) os is loading ...";
cprintf("%s\n\n", message);
print_kerninfo();
grade_backtrace();
pmm_init(); // init physical memory management
pic_init(); // init interrupt controller
idt_init(); // init interrupt descriptor table
clock_init(); // init clock interrupt
intr_enable(); // enable
lab1_switch_test();
/* do nothing */
while (1);
}
它就是内核了代码了,while(1)
就是前面的代码应该是一直有线程吧,中断响应啊等等。
这样一个操作系统就开始起来了。