Linux0.11内核--启动代码分析setup.s 建立页目录和页表

 

head.s开始

pg_dir

....

....

....

....

.org 0x1000

pg0:

 

.org 0x2000

pg1:

 

.org 0x3000

pg2:

 

.org 0x4000

pg3:

 

.org 0x5000

 

 

后面是setup_paging代码

 

setup_paging: movl $1024*5,%ecx /* 5 pages - pg_dir+4 page tables */ xorl %eax,%eax xorl %edi,%edi /* pg_dir is at 0x000 */ cld;rep;stosl movl $pg0+7,pg_dir /* set present bit/user r/w */ movl $pg1+7,pg_dir+4 /* --------- " " --------- */ movl $pg2+7,pg_dir+8 /* --------- " " --------- */ movl $pg3+7,pg_dir+12 /* --------- " " --------- */ movl $pg3+4092,%edi movl $0xfff007,%eax /* 16Mb - 4096 + 7 (r/w user,p) */ std 1: stosl /* fill pages backwards - more efficient :-) */ subl $0x1000,%eax jge 1b xorl %eax,%eax /* pg_dir is at 0x0000 */ movl %eax,%cr3 /* cr3 - page directory start */ movl %cr0,%eax orl $0x80000000,%eax movl %eax,%cr0 /* set paging (PG) bit */ ret /* this also flushes prefetch-queue */ 

其中:

 

movl $pg0+7,pg_dir /* set present bit/user r/w */

movl $pg1+7,pg_dir+4 /*  --------- " " --------- */

movl $pg2+7,pg_dir+8 /*  --------- " " --------- */

movl $pg3+7,pg_dir+12 /*  --------- " " --------- */

设置页目录表中的项

由于pg0的地址在0x1000位置,则$pg0+7表示的是0x00001007

第 1 个页表的属性标志 = 0x00001007 & 0x00000fff = 0x007,表示该页存在、用户可读写。(由于每个页大小为4K,用12 bit位表

示)

然后

 

movl $pg3+4092,%edi

movl $0xfff007,%eax /*  16Mb - 4096 + 7 (r/w user,p) */

std

1: stosl /* fill pages backwards - more efficient :-) */

subl $0x1000,%eax

jge 1b

填写4个也表的内容

由于每个页表有1024项*4个页表=4096项,4096*4K=16M,正好完全覆盖地址空间。

Linus是从后向前设置页表,最后一个页表的最后一项对应的地址为16M-4096,即0xFFF000,然后加上属性标志0x007,得0xFFF007

每写一项地址减0x1000,也就是减去4K,正好对应一个页。

这程序循环0xFFF+1次

最后:

 

设置页目录基址寄存器 cr3 的值,指向页目录表

 

xorl %eax,%eax /* pg_dir is at 0x0000 */ movl %eax,%cr3 /* cr3 - page directory start */ 

 

设置启动使用分页处理(cr0 的 PG 标志,位 31)

movl %cr0,%eax orl $0x80000000,%eax movl %eax,%cr0 /* set paging (PG) bit */ ret /* this also flushes prefetch-queue */ 
使用ret指令,将main函数地址从栈中弹出至CS,跳转到main去执行。

 

 

 

你可能感兴趣的:(linux,user,代码分析)