Linux0.11内核源代码(2)

来源:互联网 发布:淘宝网春秋女装 编辑:程序博客网 时间:2024/05/16 08:17

INITSEG  = 0x9000! we move boot here - out of the waySYSSEG   = 0x1000! system loaded at 0x10000 (65536).SETUPSEG = 0x9020! this is the current segmentstart:movax,#INITSEGmovds,axmovah,#0x03xorbh,bhint0x10! mov[0],dx! movah,#0x88int0x15mov[2],ax!movah,#0x0fint0x10mov[4],bx! mov[6],ax! movah,#0x12movbl,#0x10int0x10mov[8],axmov[10],bxmov[12],cx
上面的代码主要对硬件进行检测,为了保证所有的段寄存器都指向正确的内存地址,代码起始位置首先重新设置一下段寄存器。由于bootsect已经不再有使用价值,所以可以重新覆盖用于保存检测到的一些硬件信息。首先利用int 0x10得到当前光标的信息,并将相应的信息存放到INITSEG段的起始位置。http://www.ctyme.com/intr/rb-0088.htm

int 0x15用于获取系统的扩展内存大小,也就是绝对地址超过1M的内存的大小。大小按照KB为单位保存在AX中,也就是扩展内存最大位64MB。http://www.ctyme.com/intr/rb-1529.htm

int 0x10用于返回当前显示模式,AX返回显示的显示的列数墓,BX则是当前显示的活动页。http://www.ctyme.com/intr/rb-0108.htm。接下来的int 0x10则用于返回显示内存,以后的显示打印可以通过这一部分内存进行直接的显示。

movax,#0x0000movds,axldssi,[4*0x41]movax,#INITSEGmoves,axmovdi,#0x0080movcx,#0x10repmovsbmovax,#0x0000movds,axldssi,[4*0x46]movax,#INITSEGmoves,axmovdi,#0x0090movcx,#0x10repmovsbmovax,#0x01500movdl,#0x81int0x13jcno_disk1cmpah,#3jeis_disk1no_disk1:movax,#INITSEGmoves,axmovdi,#0x0090movcx,#0x10movax,#0x00repstosbis_disk1:cli! no interrupts allowed !movax,#0x0000cld! 'direction'=0, movs moves forwarddo_move:moves,ax! destination segmentaddax,#0x1000cmpax,#0x9000jzend_movemovds,ax! source segmentsubdi,disubsi,simov cx,#0x8000repmovswjmpdo_moveend_move:
代码开始首先测试是否存在硬盘,两个硬盘参数存放在中断向量0x41和0x46中。因为英特尔体系架构下总共可以有256个中断。其中系统保留使用的有0x0-0x31则用于保留给异常使用,而剩下的0x32-0x47则用于系统中的可编程中断,剩下的可以由用户任意分配。因此这里的0x41和0x46号中断向量存放着找到硬盘信息的地址应该是一个默认的惯例。不过这也是因为Linux中的MBR部分不规范所导致的,按照规范的可引导MBR中,应该存放BPB参数表,参数表中包含相应的磁盘信息。但是这样在安装的时候需要收集磁盘的相关信息。int 0x13用于检测磁盘的格式(这里的第二个磁盘是否是除软盘外的第二个磁盘),如果第二个盘不存在则会将它的磁盘格式表进行清零操作。在检测得到所有的硬件信息后,将system中复制到0x0000段位置处。
end_move:movax,#SETUPSEG! right, forgot this at first. didn't work :-)movds,axlidtidt_48! load idt with 0,0lgdtgdt_48! load gdt with whatever appropriatecallempty_8042moval,#0xD1! command writeout#0x64,alcallempty_8042moval,#0xDF! A20 onout#0x60,alcallempty_8042moval,#0x11! initialization sequenceout#0x20,al! send it to 8259A-1.word0x00eb,0x00eb! jmp $+2, jmp $+2out#0xA0,al! and to 8259A-2.word0x00eb,0x00ebmoval,#0x20! start of hardware int's (0x20)out#0x21,al.word0x00eb,0x00ebmoval,#0x28! start of hardware int's 2 (0x28)out#0xA1,al.word0x00eb,0x00ebmoval,#0x04! 8259-1 is masterout#0x21,al.word0x00eb,0x00ebmoval,#0x02! 8259-2 is slaveout#0xA1,al.word0x00eb,0x00ebmoval,#0x01! 8086 mode for bothout#0x21,al.word0x00eb,0x00ebout#0xA1,al.word0x00eb,0x00ebmoval,#0xFF! mask off all interrupts for nowout#0x21,al.word0x00eb,0x00ebout#0xA1,almovax,#0x0001! protected mode (PE) bitlmswax! This is it!jmpi0,8! jmp offset 0 of segment 8 (cs)empty_8042:.word0x00eb,0x00ebinal,#0x64! 8042 status porttestal,#2! is input buffer full?jnzempty_8042! yes - loopretgdt:
对8042的设置可以防止系统内存的回卷,为了兼容以前的系统,在后续的英特尔架构下同样可以访问1M以及1M以上的内存。然而,这就不好区分是在实模式下访问1M以上内存还是在保护模式下访问1M以上内存。因此需要设置一个标志,防止系统在保护模式下访问1M以上内存出现回卷。这个标志就是设置键盘中的8042中控制寄存器的第二位为1。至于8042的操作就不具体介绍了,需要注意的是在进行这些处理时需要在关中断情况下进行处理。还有另外一个地方的0x00eb,起始是一个指令码。这个指令码表示向前跳转两个字节,主要用于同步。为了初始化8259中断控制器,总共发出了四个ICW命令控制字,除了ICW3之外用于区分8259的主从之分外,其他的都是一样的。最后将两个8259中的中断给屏蔽掉。然后跳转到32位代码处开始执行。在英特尔架构下CR0是一个控制寄存器,用于控制当前处理器的状态,比较重要的有两个位,一个是PE开启保护模式,另一个是PG开启页式内存管理。

gdt:.word0,0,0,0! dummy.word0x07FF! 8Mb - limit=2047 (2048*4096=8Mb).word0x0000! base address=0.word0x9A00! code read/exec.word0x00C0! granularity=4096, 386.word0x07FF! 8Mb - limit=2047 (2048*4096=8Mb).word0x0000! base address=0.word0x9200! data read/write.word0x00C0! granularity=4096, 386idt_48:.word0! idt limit=0.word0,0! idt base=0Lgdt_48:.word0x800! gdt limit=2048, 256 GDT entries.word512+gdt,0x9! gdt base = 0X9xxxx
进入到下一个话题之前,首先需要对上面这些结构进行分析。需要注意的第一点是英特尔是小端模式,因此高位在内存的高位地址。而GDTR中包含48位数据,32位为基地址找到对应的全局段寄存器,而16位作为GDTR的上限;IDTR也是类似的。因此GDTR给定的基地址是0x90512+gdt(也就是上面定义的gdt表在内存中的位置)。由于此时中断被禁止所以是一个无用的数值。gdt中第一个表项被设置为全部为0,是英特尔默认这一项无用。

左图是每一个段的表项的每一个位的解释,整个结构体单元被划分的稀烂。重点看三个,基地址,上限以及DPL。gdt的第二项的基地址是0x0,而上限时0x07ff;dpl则为0。而这正好和之前的长跳转相符,因此下一步的system代码将会在段基地址位0x0,上限为0x07ff处运行,正好和复制时0x8000一致。另外,需要注意的一点是第三个gdt表项,这个表项在接下来的处理中有着隐含的含义。另外需要注意的是,在jmpi指令之前,只需要直接按照原来的存取方式进行读取就可以了。

0 0
原创粉丝点击