美丽的'花枝'

很喜欢看中央十套科教频道的栏目,感觉在中央台的这十几套节目当中,也就属这套科教频道’清新典雅’、’与世无争’了(不知道该用什么词藻描述了^_^)。昨晚偶然间看到的’人与社会‘栏目让我知道了一朵美丽的’花枝’的感人故事,这里和大家一起来感动。

我并没有从头看起,一打开电视调到科教频道,映入眼帘的就是一起重大的车祸,当时还猜不出片子到底要讲一个什么样的故事。继续往下看,镜头在采访伤者和现场指挥之间切换着。而伤者讲述和现场指挥耳闻的都是一个’连续的、平静的、带有鼓励的声音’ — ‘坚持’。也是这个声音让很多绝望了的受伤的乘客重新燃起求生的欲望。这个声音到底是谁发出来的呢?随着片子的深入,一个瘦弱的年轻女孩儿出现在屏幕上,她的脸上有几丝血迹,靠在车座上一动也不能动。当救援人员试图对她进行营救的时候,她居然说:“别管我,先救游客”。也许看到这时你惊叹于她的行为,我也是。也许很多人这时会认为她受伤较轻,所以先想着别人也是情有可原的。片子继续,在救援过程中,这个女孩儿曾经昏死过去多次,但每当醒来她都会用平静的声音鼓励其他游客’坚持’。她是最后一个被救出来的,在被救出的那一刹那她还问了一句话:’都救出去了么?’。经过近十个小时的手术,这个女孩的命保住了,可是却永远的失去了一条左腿,这也推翻了我们前面的’轻伤’的想法。按医生的说法:如果早来一段时间,她的腿是能保住的!

这个女孩儿究竟是谁?她就是我们美丽的’花枝’ — 湘潭新天地旅行社的导游文花枝,今年才22岁。设想一下我们的22岁时如果遇到这样的一起事故,我们的表现会是什么样子的呢?一个表面上文静弱小的女孩儿在突发危险的时候如此镇定自若,真是令人敬佩,或用用一位网友的词’敬仰’也不为过。事后文花枝的父亲曾责备她说"如果早点接受救援,就可以保住左腿"。文花枝大致(句子中有方言成分)是这样回答的"你家的小孩儿是宝贝,别人家的就不是宝贝了么?"。看到这时我的心里也说不上来是什么样的感觉,很多词如’感动’、’震撼’、’伟大’等等都一股脑儿的涌了出来。面对自己伤残的左腿,文花枝脸上还是带着那种乐观、向上的表情。短短22年的人生体验,能有如此的生活态度,真是让我佩服,值得我们去体会去学习!

令我欣慰的是文花枝现在得到了许许多多社会上的好心人的帮助,生活一切正常,她也正准备着给自己安装一个先进的假肢。也许在若干时间后,我们在某旅游景点仍旧能看到花枝美丽灿烂的笑容。

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.

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言精进之路1 Go语言精进之路2 Go语言编程指南
商务合作请联系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