setup开启了实模式,移动system到内存0地址,并跳转到0地址,此时位于system的head模块。
; 之前的setup为了jmpi临时设置了gdt,这里重新设置
call setup_idt call setup_gdt
; 设置页表,页表设置成功后,跳转到main.c
jmp after_page_tables
after_page_table:
; 0 0 0是main的三个参数,L6是main的返回地址
push $0 push $0 push $0 push $L6 push $_main
jmp setup_paging
L6: jmp L6 ; main返回,系统就会死机,所以main不应该返回
setup_paging:
... ; 设置页表
ret ; 返回到main
head准备了有关数据结构,并跳转到了main.c执行。main的工作就是做内存、中断、设备、时钟、CPU等内容的初始化。
void main(void) {
mem_init();
trap_init();
blk_dev_init();
chr_dev_init();
tty_init();
time_init();
sched_init();
buffer_init();
hd_init();
floppy_init();
sti();
move_to_user_mode();
if(!fork()) {init();}
}
此处举例说明mem_init对内存的初始化操作。
// linux/mm/memory.c
void mem_init(long start_mem, long end_mem) {
// end_mem就是多大内存,从0x90002获取
int i;
for(i = 0; i < PAGING_PAGES; ++i) {
mem_map[i] = USED;
}
i = MAP_NR(start_mem);
end_mem -= start_mem;
end_mem >>= 12; // 每次把4k空间(页)置零
while(end_mem-- > 0) {
mem_map[i++] = 0;
}
}
mem_init()自高地址向低地址标记可用,永远标记低地址是已用,因为低地址存放着操作系统。