本文参考MOOC哈工大操作系统课程,需要有一定的汇编基础
INT 0x13 参数参考:https://www.cnblogs.com/AmitX-moten/p/4823598.html
功能号:AH = 08H
调用参数:DL = 驱动器号,ES:BX = 格式化参数表指针
返回参数:成功 ⇒ BL = 磁盘大小,CX中的0-5位存扇区数,CX中的6-15位存柱面号,DH/DL = 磁头数/驱动器数,ES:DI = 磁盘驱动器参数列表地址,失败 ⇒ AH = 错误码,CF = 1
Ok_load_setup:载入代码后,设置dl=0x00,ax=0x0800,执行中断0x13,获取磁盘参数
设置ch=0x00,将扇区数取出给sectors。
通过INT 0x10中断读取光标,再通过该中断显示#mesg1处内存中的字符(loading system…)(cx寄存器代表字符长度)
然后执行call指令,将CS和IP入栈,跳转到read_it处执行代码
setup模块后就需要进入system模块,此时需要从磁盘载入该模块。
通过条件转移指令,跳转ok1_read执行,jb代表jump below,此时应该是为了防止程序跳到system外。
ok1_read代码将磁盘扇区数赋给ax,用ax减去已读扇区数,此时的ax代表未读的扇区数,然后开始读磁道。
至此bootsect.s引导扇区的代码执行完毕,此时需要转入setup模块进行执行。
setup模块,进行系统的设置
此时首先取出鼠标位置,放入[0](间接寻址此时指向CS:IP+0=0x90000)
再取出内存大小放入[2],0x90002处
因为此时CS:IP最多指向的地址空间为1M因为地址位数为20位,2^20bit=1M
所以需要扩展内存
此时SYSSET=0x1000,操作系统的代码放在0x10000起始的位置,下面要整体挪动到0x00000
do_move 此时又要开始移动了,将system模块放到0地址处,此时可以解释为何上面要移动0x07c00的代码到0x90000,就是因为这里要放system的地址。
从ds:si地址 移动到es:di=0x00000处 移动0x8000字节
将CPU从实模式转入保护模式/32位模式,寻址方式发生改变,通过CS选择子选择GDT表中的地址+IP即为内存地址
转入保护模式之前,其实setup还做了一件事,就是建立GDT表,为后面改变寻址方式做准备
此时可以解释一下jmpi 0,8的意思,CS=8选择子查GDT表得到的结果是0x00000000 32位地址,寻址空间为4G,此时CPU可以寻址的空间从1M转到了4G
此时已经跳出setup模块正式进入了system模块,system模块的第一个文件就是head.s,此时的汇编为32位汇编,head.s做了一系列设置(堆栈、idt、gdt、设置地址线等)执行后需要执行main.c,转入C语言执行
通过压栈压入_main的参数 0,0,0,和main的地址(L6死循环地址),跳转到set_paging,执行完设置页表,弹出栈时,main函数的地址被弹出,此时执行main(0,0,0)
上述代码中for循环将内存的页表从0开始的地方设置一段为USED,这一段即为系统所在的地址。
end_men-start_men为剩余的内存的大小,end_men >>=12,end_men右移12位,代表除以4k,此时end_men代表剩余内存有多少页,而mem_map就代表一个数组,这个数组中记录着每个内存页是否被使用。
上述代码中start_men和end_men即从之前的汇编处可以得到,0x90000和0x90002。
通过main.c初始化完成后,操作系统即启动了。
上一篇:关于孟子的名言
下一篇: 阿里巴巴的三次面试笔试经验