您的位置:首页 > 运维架构 > Linux

linux 0.11 源码学习--head.s

2014-10-04 08:53 357 查看
关于head.s,它是在/boot目录下三个汇编程序中唯一一个使用AT&T指令的,对于我这个x86汇编看多的人有很多不适应的地方。

head.s主要实现的功能:

重新设置IDT和GDT;(至于为什么要重新设置IDT和GDT,在setup.s中设置的中断向量表和GDT,由于是在实模式下设置的,但是现在运行的程序是在保护模式下运行的,采用实模式的话,包含的信息较少,比如没有包含每个段的r,w,x等信息,因此要重新设置);
检测A20是否真的开启了;
检测PC机是否含有数字协处理器芯片;
设置页表;
将堆栈中的main的入口地址弹出,然后执行;

head.s部分代码分析:

AT&T中的立即数

mov $0x10,%eax
mov %ax,%ds
mov %ax,%es
mov %a,%fs
mov %ax,%gs

上面第一行中mov $0x10,%eax,如果没有$,则表示地址,即0x10表示地址,$0x10则表示段描述符表的选择项。这里也许有人会问如果要表示立即数怎么办,在第46行和第89行中$2,$8表示2和8这两个立即数。

A20地址线的开启

xorl %eax,%eax
1:incl %eax,
movl %eax,0x000000
cmpl %eax,0x100000
je 1b
这段代码我也花了很多的时间来理解,这里我解释一下如果A20线关闭,则当程序员给出100000H-10FFEFH之间的地址的时候,系统仍然使用8086/8088的方式,即访问模100000H之后的地址,在第35行中如果A20关闭,则访问ox100000时,系统访问的地址会模100000h的地址,即0x00000的地址,所以相等则A20是关闭的。如果知道了这个道理,我们也可以比较ox000001和0x100001这两个地址的内容。

关于IDT和GDT

IDT和GDT的设置和setup.s中的基本一样,将一个线性地址存到IDTR和GDTR中,这里的差别主要在与在保护模式下,各个段除了段地址,段长之外还用一些标志位,使用权限。因此,实模式下的中断向量表是不能满足要求的。

setup_idt:
lea ignore_int ,%edx
movl $0x00080000,%eax
movw %dx,%ax
mov w $0x8e00,%dx
lea _idt ,%edx
mov $256,%ecx
rp_sidt:
movl %eax,(%edi)
movl %edx,4(%edi)
addl $8,%edi
dec %ecx
jne rp_sidt
lidt idt_descr
ret
关于这段代码,我要提示一下这里的中断描述表项所表示的中断处理地址是0~1,6~7字节。根据对代码的理解,0~1表示的是低地址,6~7表示的是高地址,我的理解是0~1是偏移量,6~7表示的是段基址。

main入栈操作

pushl $0
pushl $0
pushl $0
pushl $L6
pushl $_main
jmp setup_pageing
L6:
jmp L6
关于这段代码,我觉得要联系后面的第218行代码看 ret。当程序执行到218行时,head.s的代码基本上已经到了最后了,调用ret,将栈中4个字节调出来,正好是_main的地址。

设置页表

清零

<span style="font-size:18px;">movl $1024*5,%ecx
xorl %eax,%eax
xorl %edi,%edi
cld;rep;stosl</span>


设置页目录项

<span style="font-size:18px;">movl $pg0+7,_pg_dir
movl $pg1+7,_pg_dir+4
movl $pg2+7,_pg_dir+8
movl $pg3+7,_pg_dir+12
</span>
这里已经开始覆盖了head.s的代码了,页目录在物理地址0开始。页目录项指向一个页表的首地址

设置页表项

<span style="font-size:18px;">movl $pg3+4.92,%edi
movl $0xfff007,%eax
std
1:
stosl
subl $0x1000,%eax
jge 1b</span>
页表项指向一个页的首地址(注意和页目录项的区别)。一共有4个页表,每个页表有1024项,每一项指向了一个4KB的页,从而可以指向4*1024*4KB=16MB的内存。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: