操作系统system模块执行

操作系统全部笔记目录 见:操作系统笔记整理

注意我们程序执行时就是按照首先读第一个扇区,然后第一个扇区的bootset继续读后面的扇区,所以代码的安排必须要合理:

需要用makefile来自己设计编译细节。设计哪个放在前面,哪个放在后面。编译出来以后,操作系统叫image,一定要符合上图的样子。我们需要写到0磁道0扇区。

makefile如下:

disk: Image
dd bs=8192 if=Image of=/dev/PS0
Image: boot/bootsect boot/setup tools/system tools/build
tools/build boot/bootsect boot/setup tools/system > Image
tools/system: boot/head.o init/main.o $(DRIVERS) …
$(LD) boot/head.o init/main.o $(DRIVERS) … -o tools/system

生成Image需要很多依赖,依赖有了以后,就把这些东西合成到Image镜像里。同时这些依赖也分别要依赖其他项。注意上面的$(DRIVERS)表示驱动程序。

system的第一个部分就是head.s。

注意head.s是32位保护模式,所以要执行32位的汇编(和原来的汇编不一样了):

stratup_32: movl $0x10,%eax mov %ax,%ds mov %ax,%es
mov %as,%fs mov %as,%gs //指向gdt的0x10项(数据段)
lss _stack_start,%esp //设置栈(系统栈)
call setup_idt
call setup_gdt
xorl %eax,%eax
1:incl %eax
movl %eax,0x000000 cmpl %eax,0x100000
je 1b //0地址处和1M地址处相同(A20没开启), 就死循环
jmp after_page_tables //页表, 什么东东?
setup_idt: lea ignore_int,%edx
movl $0x00080000,%eax movw %dx,%ax
lea _idt,%edi movl %eax,(%edi)

主要工作就是重新设置idt和gdt表。因为之前的这个表是为了之前操作使用的,现在操作系统需要真正控制硬件了。

内嵌汇编就是C语言文件中,有些指令必须使用汇编来严格控制执行。

head.s文件执行完以后,要跳转到main.c。它的做法是:

after_page_tables:
pushl $0 pushl $0 pushl $0 pushl $L6
pushl $_main jmp set_paging
L6: jmp L6
setup_paging: 设置页表 ret

setup_paging执行ret后,会执行函数main()

进入main()后的栈为0, 0, 0, L6

main()函数的三个参数是0, 0, 0

main()函数返回时进入L6, L6是个死循环,即死机了。所以main永远不会返回(main里面也是不断循环)。

jmp set_paging以后,就跳到 set_paging ,然后设置页表,并执行ret,弹栈,main出栈,执行main函数。

main函数:

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();}
}

三个参数分别是envp,argv,argc,但此处main并没使用,此处的main只保留传统main的形式和命名,main表示C语言函数的入口。main的工作就是xx_init: 内存、 中断、 设备、时钟、 CPU等内容的初始化。

我们取出内存初始化程序来查看一下:(在linux/mm/memory.c中)

void mem_init(long start_mem,long end_mem)
{
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;
while(end_mem -- > 0)
mem_map[i++] = 0; }

end_mem >>= 12;  左移12表示除以2的12次方,即4K,也就是每4K分为1页。

注意start_mem和end_mem,回想之前学的内容,扩展内存的大小保存在0x90002的地方 。

前面使用的区域是操作系统的内存,后面是未使用区。通过执行内存初始化函数,我们就分出了用过的和空白的内存区域。

发布了182 篇原创文章 · 获赞 408 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/tiao_god/article/details/105477060