2006年二月月 发布的文章

贴点经典台词

很多经典影视剧和小品都会给大家留下些’经典台词’,就拿今年的春晚小品’小崔说事’来说,我记住的就有’那是相当的xxx’、’女人啊,就该对自己下手狠一点’等。其实在春晚之前还有一部热播的电视剧给人们带来了欢笑,同时也让人们记住了很多让人捧腹的’台词’。这部剧就是’武林外传’。

1、嘘!嘘!嘘!低调!低调!都低调!
2、确定一定以及肯定;否决否认以及否定。
3、我吃的盐比你吃的饭都多。
      — 那是你口重。
      我过的桥比你走的路都多。
      — 那是我不乐意动。
4、如果上天能给我最后一次机会,我会对李大嘴说三个字,….少放盐。
5、郭芙蓉:刑捕头往那一站,就是七侠镇一霸(爸)!
      李大嘴:那谁是七侠镇一妈呀?
6、秀才:偷者,不告而拿也。
7、郭芙蓉对吕秀才:我一看你那呆样子就想野蛮….。
8、佟湘玉:“别说掌门,掌窗户也不行。”
9、小六:简直可以用四个字来形容。
      众人:令人发指。
      小六:再来四个。
      众人:惨绝人寰。
10、"莫掌门咋死的?"
        — "听说拿了帮里的钱盖房子……"
        "腐败啦?"
11、白展堂:好一条风姿绰月美艳动人的鸡腿呀!
12、郭芙蓉:热Face贴上了冷臀部!
13、吕秀才:也没什么,我就是比你多那么一点点内涵。
        郭芙蓉:你怎么不说你比我多一点内脏。
14、上联:抵制家庭暴力
        下联:呼唤社会爱心
        横披:不要和陌生人说话
15、十只羊,一只蹲在羊圈里,一只蹲在猪圈里 —— 抑扬顿挫。
16、吕秀才:天生我才必有有用,千金难买爷高兴;千金散尽还复来,爷想怎么用就怎么用。
17、白展堂:杨过和小龙女知道不?
       李大嘴:杨过我不知道,小聋女我知道,西街的那个,说不出话,阿巴阿巴。
18、你是马不知道自己的脸长;你是牛不知道自己的皮厚!
19、郭芙蓉:我最后一次警告你啊 请使用人类的语言和我交谈!
20、佟掌柜:继续热烈接近疯狂地鼓掌!
21、一般一般,港姐第三。很丑很丑,亚姐第九。

Transfer to '32-bit'

The phase we talked about before is in ‘Real-address Mode’, which runs 16-bit program modules. At the tail of "Begin ‘setup.S’", we had moved to ‘Protected Mode’, which usu runs 32-bit program modules. So there are two big problems which are ‘How to transfer control between 16-bit code and 32-bit code’ and how to transfer control from ‘real-mode’ to protected mode’. They are also what we wanna talk about in this artical.

The transfering codes are mainly in ‘setup.S and ‘head.S’. We have covered the ‘setup.S’ with a little detail about how to move to protected mode. Here we are going to make a supplementary.

First of all, let us have a look at the characteristics of 16-Bit and 32-Bit program modules, which quotes the ‘Intel Manual Vol3′.

Characteristic                         16-Bit Program Modules            32-Bit Program Modules
———————————————————————————————-
Segment Size                               0 to 64 KBytes                     0 to 4 GBytes
Operand Sizes                              8 bits and 16 bits              8 bits and 32 bits
Pointer Offset Size (Address Size)           16 bits                            32 bits
Stack Pointer Size                          16 Bits                              32 Bits
Control Transfers Allowed to Code           16 Bits                              32 Bits
Segments of This Size

The ‘Intel Manual Vol3′ also tells us how to distinguish between and support 16-bit and 32-bit segments and operations.

Details as follows:
(1) The D (default operand and address size) flag in code-segment descriptors.
(2) The B (default stack size) flag in stack-segment descriptors.
(3) 16-bit and 32-bit call gates, interrupt gates, and trap gates.
(4) Operand-size and address-size instruction prefixes.
(5) 16-bit and 32-bit general-purpose registers.

Due to the usage in ‘setup.S’, we are going to talk about item (4) in this artical and you can deep into the other four items by reading that bible book mentioned above. Before we say something about ‘instruction prefix’, we are going to do a review of ‘setup.S’. As we know, before switching to protected mode, a minimum set of system data structures and code modules must be loaded into memory. The GDT(Global Descriptor Table) is one of them. GDT consists of several 8-byte segment descriptors.

These segment descriptors describe the segment characteristics. They have several important fields. Some of the fields are listed below:
(1) ‘base’ – contains the linear address of the first byte of the segment.
(2) ‘G’ -  granularity flag, if it is cleared (equal to 0), the segment size is expressed in bytes; otherwise, it is expressed in multiples of 4096 bytes.
(3) ‘limit’ – holds the offset of the last memory cell in the segment, thus binding the segment length. When G is set to 0, the size of a segment may vary between 1 byte and 1 MB; otherwise, it may vary between 4 KB and 4 GB.

Here we are going to learn how the ‘setup.S’ define its provisional GDT, yeah, it is just a provisional GDT.

/*
 * ! $(linux-2.6.15.3_dir)/arch/i386/setup.S
 */
# Descriptor tables
#
# NOTE: The intel manual says gdt should be sixteen bytes aligned for
# efficiency reasons.  However, there are machines which are known not
# to boot with misaligned GDTs, so alter this at your peril!  If you alter
# GDT_ENTRY_BOOT_CS (in asm/segment.h) remember to leave at least two
# empty GDT entries (one for NULL and one reserved).
#
# NOTE: On some CPUs, the GDT must be 8 byte aligned.  This is
# true for the Voyager Quad CPU card which will not boot without
# This directive.  16 byte aligment is recommended by intel.
#
 .align 16
gdt:
 /*
  * ! #define GDT_ENTRY_BOOT_CS 2
  * ! The first segment descripter is setted by zero(Requested by Intel).
  * ! The second segment descripter is reserved and also setted by zero.
  * ! The third segment descripter:
  * !  base = 0; G flag = 4096(D) = 0×1000, limit = 0xFFFF * 0×1000 = 4Gb
  * ! The fourth segment descripter:
  * !  base = 0; G flag = 4096(D) = 0×1000, limit = 0xFFFF * 0×1000 = 4Gb
  */
 .fill GDT_ENTRY_BOOT_CS,8,0

 .word 0xFFFF    # 4Gb – (0×100000*0×1000 = 4Gb)
 .word 0    # base address = 0
 .word 0x9A00    # code read/exec
 .word 0x00CF    # granularity = 4096, 386
      #  (+5th nibble of limit)

 .word 0xFFFF    # 4Gb – (0×100000*0×1000 = 4Gb)
 .word 0    # base address = 0
 .word 0×9200    # data read/write
 .word 0x00CF    # granularity = 4096, 386
      #  (+5th nibble of limit)
gdt_end:
 .align 4
 
 .word 0    # alignment byte
idt_48:
 .word 0    # idt limit = 0
 .word 0, 0    # idt base = 0L

 .word 0    # alignment byte
gdt_48:
 /*
  * ! Segment descriptors are always 16 bytes long recommended by intel,
  * ! the GDT limit should always be one less than an integral
  * ! multiple of sixteen (that is, 16N – 1).
  * ! we can see that the gdt base will be reset later
  */
 .word gdt_end – gdt – 1  # gdt limit
 .word 0, 0    # gdt base (filled in later)

The following code performs an operation to load a liner address to GDTR(Global Descriptor Table Register). You must have to distinguish between GDTR(Global Descriptor Table Register) and GDT(Global Descriptor Table). The value stored in GDTR indicates where the GDT is. The GDTR is a key register when we moved to protected mode. so we must fill it before transferring control to protected mode. GDTR is 48-bit register, which consises of ‘limit’ field and ‘base’ field. We can use ‘lgdt m16/32′ instruction to fill this register. The ‘lgdt’ instruction loads a linear base address and limit value from a six-byte data operand in memory into the GDTR, respectively. If a 16-bit operand is used with ‘lgdt’, the register is loaded with a 16-bit limit and a 24-bit base, and the high-order eight bits of the six-byte data operand are not used. If a 32-bit operand is used, a 16-bit limit and a 32-bit base is loaded; the high-order eight bits of the six-byte operand are used as high-order base address bits. The following code showes us how the ‘setup.S’ loads the GDTR.
 
 # set up gdt and idt
 lidt idt_48    # load idt with 0,0
 xorl %eax, %eax   # Compute gdt_base
 movw %ds, %ax   # (Convert %ds:gdt to a linear ptr)
 shll $4, %eax
 addl $gdt, %eax

 /*
  * ! reset the GDT base to %ds:gdt, which is mentioned above
  * ! now %ds = SETUPSEG = 0×9020
  * ! after ‘lgdt’, the ‘base’ field value in GDTR is ((%ds << 4) + $gdt)
 movl %eax, (gdt_48+2)
 lgdt gdt_48    # load gdt with whatever is
                # appropriate

Thus, the preparation for
‘protected mode’ is over. What we want to do next is moving to the protected mode. We had mentioned that a far JMP instruction should be executed immediately after protected mode is enabled. Here ‘setup.S’ chooses a more simple way to transfer control to 32-bit protected mode. 

/*
 * ! $(linux-2.6.15.3_dir)/include/asm-i386/segment.h
 * Simple and small GDT entries for booting only
 */

#define GDT_ENTRY_BOOT_CS  2
#define __BOOT_CS (GDT_ENTRY_BOOT_CS * 8)

#define GDT_ENTRY_BOOT_DS  (GDT_ENTRY_BOOT_CS + 1)
#define __BOOT_DS (GDT_ENTRY_BOOT_DS * 8)

/*
 * $(linux-2.6.15.3_dir)/arch/i386/setup.S
 */
#
# jump to startup_32 in arch/i386/boot/compressed/head.S

# NOTE: For high loaded big kernels we need a
# jmpi    0×100000,__BOOT_CS
#
 .byte 0×66, 0xea   # prefix + jmpi-opcode
code32: .long 0×1000    # will be set to 0×100000
      # for big kernels
 .word __BOOT_CS

There is a hard-coding instruction to do the jump. ’0xea’ is the binary coding form of ‘jmpi’ instruction. the ‘jmpi’ instruction uses a four-byte(when operand’s size is 16 bits) or six-byte(when operand’s size is 32 bits) operand as a long pointer to the destination. Now we are in 16-bit mode, all the operand’s size is 16 bits(mainly the target offset). But we want to jump to a 32-bit program module where instructions are executed in 32-bit mode. How can we deal with it, since we can not directly jump there. The solution is to add ’0×66′ instruction prefix before ‘jmpi’. This instruction prefix reverse the default size selected by the D flag in the code-segment descriptor and guarantees that the CPU will properly take our 48 bit far pointer(it is also called ‘logical address’ in protected mode and it consists of 16-bit segment selector and 32-bit offset). the ‘jmpi’ loads ‘__BOOT_CS’ to %cs and treats the 0×100000(big kernel) as an offset.

Where are we arrived after the intersegmental jump? Which instruction is the CPU going to execute? Both of these are what we want to solve. Now we are in protected mode with paging disabled and the memory addressing model mode has been changed. It is the ‘segmented memory model’ in protected mode. In this model, to address a byte in a segment, a program must issue a logical address, which consists of a segment selector and an offset. Internally, the processor translates each logical address into a linear address to access a memory location. the segment selector decides which segment descriptor to be used in GDT and the final liner address could be caculated by such a formula ‘segment_descriptor.base + offset’.

There is a logical address available in ‘setup.S’, that is ‘__BOOT_CS(0000000000010000B) : 0×0010000′. The first high-order 13 bits decide the index(based on zero) of the segment descriptor to use in GDT. Here the index is equal to ’2′. Just review the code above, the segment descriptor is the third defined in lable ‘gdt’ and its base is 0. Now we can make a conclusion that the first instruction’s liner address is ’0 + 0×00100000′, that is 0×001000000. It is just the location where ‘head.S’(the first part of the system) stays.

/*
 * ! $(linux-2.6.15.3_dir)/arch/i386/boot/compressed/head.S
 */
 .globl startup_32
 
startup_32:
 cld
 cli
 movl $(__BOOT_DS),%eax
 movl %eax,%ds
 movl %eax,%es
 movl %eax,%fs
 movl %eax,%gs

Here there is still a question, that is why we do not use ‘jmpi startup_32, __BOOT_CS’ instead of ‘jmpi 0×100000, __BOOT_CS’? We know that linux finally makes paging enable and build its own virtual memory management system. At that time, the linux kernel will have 4G-byte virtual address space and it only runs over the high 1G-byte(from 0xC0000000 to 0xFFFFFFFF) space. But the physical address space always starts from 0×00000000. There is a offset between kernel’s virtual address space and the physical address space. The offset is just ’0xC0000000′. So when we build linux kernel image, all address of labels in protected mode and later phases are added the offset. The address of label startup_32 is 0xC0100000. It won’t be used unless the paging is enabled. The code in this ‘head.S’ is also to do preparation for paging.

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! 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