2006年三月月 发布的文章

Kernel 'head.S'

After being decompressed, the kernel image starts with another ‘startup_32′ function included in $(linux-2.6.15.3_dir/arch/i386/kernel/head.S’. This ‘head.S’ is the second one in linux source package, which is also called ‘kernel head’. And it is exactly what we want to describe in this artical.

The kernel head continues to perform higher initialization operations for the first linux process(process 0). It sets up an execution environment for the kernel main routine just like what the operating system does before an application begins to start. There are two entries for CPUs in this ‘head.S’ and we only talk about the execution routine of the boot CPU.

/*
 * ! $(linux2.6.3.15_dir)/arch/i386/kernel/head.S
 */
ENTRY(startup_32)

 /*
  * ! We still use liner address, since
  * ! %ds = %es = %fs = %gs = __BOOT_DS
  * ! we use the third segment which base
  * ! address starts from 0×00000000
  */
 cld
 lgdt boot_gdt_descr – __PAGE_OFFSET
 movl $(__BOOT_DS),%eax
 movl %eax,%ds
 movl %eax,%es
 movl %eax,%fs
 movl %eax,%gs

 /*
  * ! Clear the kernel bss
  */
 xorl %eax,%eax
 movl $__bss_start – __PAGE_OFFSET,%edi
 movl $__bss_stop – __PAGE_OFFSET,%ecx
 subl %edi,%ecx
 shrl $2,%ecx
 rep ; stosl

After copying the bootup parameters, it prepares to enable the paging. Before the paging enabled, some data structure should be loaded first following the ‘Intel Manual Vol3′.

 /*
  * ! Initialize the provisional kernel page tables
  * ! which are stored starting from pg0, right after
  * ! the end of the kernel’s uninitialized data segments(bss).
  * ! and the provisional page global directory is
  * ! contained in the swapper_pg_dir variable.
  * !
  * ! page_pde_offset = 0x0c00
  */
 page_pde_offset = (__PAGE_OFFSET >> 20);

 /*
  * ! this line indicates the table starts from ‘pg0′
  */
 movl $(pg0 – __PAGE_OFFSET), %edi

 /*
  * ! this line told us ‘swapper_pg_dir’ is the
  * ! page directory start point
  */
 movl $(swapper_pg_dir – __PAGE_OFFSET), %edx

 /*
  * ! There were 1024 entries in ‘swapper_pg_dir’
  * ! since the code below:
  * ! ENTRY(swapper_pg_dir)
  * !     .fill 1024,4,0
  * !
  * ! The first mapping:
  * !     both entry 0 and entry 0×300 (page_pde_offset/4) –> pg0
  * !     that is (0×00000000~0x007fffff) —> pg0
  * ! The second mapping:
  * !     both entry 1 and entry 0×301 (page_pde_offset/4+1) –> pg1 (the page following pg0)
  * !     that is (0xC0000000~0xC07fffff) —> pg1
  * !
  * ! The objective of this first phase of paging is to
  * ! allow these 8 MB of RAM to be easily addressed
  * ! both in real mode and protected mode.
  */
 movl $0×007, %eax   /* 0×007 = PRESENT+RW+USER */
10:
 leal 0×007(%edi),%ecx   /* Create PDE entry */
 movl %ecx,(%edx)   /* Store identity PDE entry */
 movl %ecx,page_pde_offset(%edx)  /* Store kernel PDE entry */
 addl $4,%edx
 movl $1024, %ecx
11:
 stosl
 addl $0×1000,%eax
 loop 11b
 /* End condition: we must map up to and including INIT_MAP_BEYOND_END */
 /* bytes beyond the end of our own page tables; the +0×007 is the attribute bits */
 leal (INIT_MAP_BEYOND_END+0×007)(%edi),%ebp
 cmpl %ebp,%eax
 jb 10b
 movl %edi,(init_pg_tables_end – __PAGE_OFFSET)

 /*
  * ! here just the boot CPU go this way
  */
#ifdef CONFIG_SMP
 xorl %ebx,%ebx    /* This is the boot CPU (BSP) */
 jmp 3f

The kernel page tables have been loaded and we can enable the paging now!

 /*
  * Enable paging
  */
 movl $swapper_pg_dir-__PAGE_OFFSET,%eax
 
 /*
  * ! load the table physical address into the %cr3
  */
 movl %eax,%cr3  /* set the page table pointer.. */
 movl %cr0,%eax
 orl $0×80000000,%eax
 
 /*
  * ! Enable the paging
  */
 movl %eax,%cr0  /* ..and set paging (PG) bit */
 
 /*
  * ! A relative jump after the paging enabled
  */
 ljmp $__BOOT_CS,$1f /* Clear prefetch and normalize %eip */
1:
 /* Set up the stack pointer */
 lss stack_start,%esp

There is a relative jump instruction – ‘ljmp $(__BOOT_CS), $1f’. Maybe you wonder what the ‘$1f’ means. ’1′ is a local symbol. To define a local symbol, write a label of the form ‘N:’ (where N represents any digit). To refer to the most recent previous definition of that symbol write ‘Nb’, using the same digit as when you defined the label. To refer to the next definition of a local label, write ‘Nf’. The ‘b’ stands for "backwards" and the ‘f’ stands for "forwards".  

Now we are in 32-bit protected mode with paging enable. so we still need to re-do something done in 16-bit mode for ‘real-mode’ operations.

 /*
  * ! Setup the interrupt descriptor table
  * ! All the 256 entries are pointing to
  * ! the default interrupt "handler" — ‘ignore_int’
  */
 call setup_idt

 ….
 ….

setup_idt:
 lea ignore_int,%edx
 movl $(__KERNEL_CS << 16),%eax
 movw %dx,%ax  /* selector = 0×0010 = cs */
 movw $0x8E00,%dx /* interrupt gate – dpl=0, present */

 /*
  * ! idt_table varible is defined
  * ! in $(linux2.6.3.15_dir)/arch/i386/kernel/traps.c
  */
 lea idt_table,%edi
 mov $256,%ecx
rp_sidt:
 movl %eax,(%edi)
 movl %edx,4(%edi)
 addl $8,%edi
 dec %ecx
 jne rp_sidt
 ret

After checking the type of CPU, the kernel head prepare to call the kernel main function ‘start_kernel’. 

 /*
  * ! use new descriptor table in safe place
  * ! then reload segment registers after lgdt
  */
 lgdt cpu_gdt_descr
 lidt idt_descr
 ljmp $(__KERNEL_CS),$1f
1: movl $(__KERNEL_DS),%eax # reload all the segment registers
 movl %eax,%ss   # after changing gdt.

 movl $(__USER_DS),%eax  # DS/ES contains default USER segment
 movl %eax,%ds
 movl %eax,%es

 xorl %eax,%eax   # Clear FS/GS and LDT
 movl %eax,%fs
 movl %eax,%gs
 lldt %ax
 cld   # gcc2 wants the direction flag cleared at all times

 …
 …

 /*
  * ! The boot CPU will jump to execute
  * ! $(linux2.6.3.15_dir)/init/main.c:start_kernel()
  * ! And the start_kernel() should never return :)
  */
 call start_kernel
L6:
 jmp L6   # main should never return here, but
    # just in case, we know what happens.

'瘦死的骆驼不如马'

今天是国际比赛日,我们的国足也开拔到阿联酋在著名的’艾因主场’与伊拉克队过招,进行’2007亚洲杯预选赛‘的第二场小组赛,写这篇Blog时,比赛正在直播,我也同步写下此时的感受。

[上半时 - 中国0 : 1伊拉克]
不出所料,朱指导排出四个后卫和三个后腰的阵容,虽然张耀坤出任右前卫,但是整个上半时张耀坤都在防守,而且还吃到一张黄牌。出任前锋的是两个在国外踢球的年轻前锋石俊和小董。石俊倒是很中规中矩,默默地执行着教练的意图,但是毕竟孤掌难鸣,抢不到球,即使抢到球也在伊拉克人的干扰下摆渡不到位,我想小石在场上一定很郁闷。在这种防守为方针指导的比赛中,他还能怎么样呢?也许很多人都和我一样不明白,为什么中国队要’缩头当孙子’?为什么中国队不能像个男人一样,即使死也要死得壮烈!而不是像现在这样,被一个不能在自己国家的土地上比赛,连自己的主场都没有的球队’蹂躏’。中国的球员从哪方面比较比伊拉克人差?是待遇、是金钱还是球技?我想都不是,从上半场比赛我看不出这批球员(特别是一些老球员)的国家荣誉感,他们不想想他们代表的是中国,先不谈输赢,为了国家的尊严我们也该像疯狗似的踢吧!朱指导不是说我们要有’疯狗’精神么?像个男人一样好不好?真TMD生气!下半场开始了… 最伟大的就是我们这些球迷了^_^,踢得那么滥,我们还要关注,因为我们有国家荣誉感,无论是哪个层次国家队的比赛,我们都会支持,尽管不能到现场。

[下半时 - 中国1 : 2伊拉克]
下半场刚开始,国足表现有所改观,换上了邵佳一,并在进一球后,换上了陈涛试图加强进攻。但是也许朱指导似乎忘了一点,那就是思维惯性,上半场45分钟的回缩防守已经让这批’终日’在一起集训的球员们忘记了如何进攻了,大脚的长传似乎让我们想到了若干年前那个更加落后的中国队,啥都不要说了,看来’瘦死的骆驼还不如马’呢!一直对朱指导印象不错,也一直不想评论朱指导,但这次我是要说了,’朱指导,你糊涂!’

就这样,中国人的尊严再一次被践踏!

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言精进之路1 Go语言精进之路2 商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats