理解linux内核框架--预备知识

  系列blogs,目的在于建立起对linux内核的框架性理解,如果能有所帮助,开心。内容将随本人的理解,不定性地扩充和更改,欢迎指正!

linux内核

      为方便用户辨识,linux提供了一套编号方案。linux内核版本格式为“x.yy.zz”,x介于0至9之间,yy及zz介于0至99之间。通常数字俞高版本俞新。其中x的不同号码标志着内核在设计或实现上的重大改变,yy一方面表示版本的变迁,一方面标志着版本的种类,即yy为偶数表示相对稳定,已经发行的版本。若为奇数则表示正在开发中,目前还不太稳定,或在运行中可能会出现比较大问题的版本。zz表示内核增加的内容不多,改动不是很大的变迁,只能算是同一版本。“发行版”和“开发版”的zz是独立编号的,因此并没有固定的对应关系。例如,开发版2.3的版本号达到2.3.99时,相应的发行版还可只是2.2.18。另外,一些版本号若具有pNN字样,NN介于0至20之间。代表对某一版内核“打补丁”或修订次数。如0.99p15,表示对版本0.99内核版本的第15次修订。

Intel X86 CPU系列的寻址方式

      在X86系列中,8086和8088是16位处理器,而从80386开始为32位处理器,本blogs主要学习i386。首先,i386有哪些基本的资源:

8个16位通用寄存器:ax,bx,cx,dx,sp,bp,si,di
8个32位通用寄存器:eax,ebx,ecx,edx,esp,ebp,esi,edi
8个调试寄存器:dr0,dr1,dr2,dr3,dr5,dr6,dr7,dr8
6个16位段寄存器:cs,ds,ss,es
4个32位控制寄存器:cr0,cr1,cr2,cr3
4个系统地址寄存器:GDTR,IDTR,LDTR,TR

      其实若是到i386这样的32位处理器,代码逻辑地址大可不必再来一次段式管理,当然我们知道这是在向下兼容,毕竟是一个系列的产品。不妨举个例子,以便更直观理解和简述:

mov ax, 1000h       ; 段selector值为1000h
mov ds, ax          ; 更新DS.base = 1000h << 4 = 10000h
mov ax, [100h]      ; ax = DS.base + 100h

      上示,涉及到实地址模式下的段基址计算,向DS寄存器加载1000h值,DS.base的值将是1000h << 4 = 10000h(20位值),后面对100h地址读,那么ax的值将是地址10100h里的值。
      由上可知段管理基本规则便是:
            segment:offset –> segment << 4 + offset
            逻辑地址                   线性地址
      段基址为0x1000,偏移为0x100。上述实例为intel汇编,以后基本上接触的是linux下针对i386的AT&T汇编,上例若使用AT&T汇编会是这样的:

movw $0x1000, %ax  
movw %ax, %ds
movw $0, %si   
movw 0x100(%si), %ax

      这里不妨bochs调试做些验证,也补充下bochs使用,有关bochs调试源码获取和bochs的搭建参考上篇:
      http://blog.csdn.net/Je930502/article/details/79520639
      因为调试时发现0x10100处是无数据的,需我得先写点数据下去,这就麻烦了。0x7c00处肯定是有指令数据的,使用si或di都行,下面使用di。总之为调试方便同时结果更直观,使用段基址为0x0000,偏移为0x7c00。即:

movw $0x0000, %ax  
movw %ax, %ds
movw $0, %di
movw 0x7c00(%di), %ax

      看附录bochs调试信息可知,0x7c00物理地址处存放两指令字节0xd9e9,最后获取到的ax寄存器的内容也是0xd9e9,简单验证完毕!

实模式地址与虚模式地址

      在实模式中,通过段机制转化而来的线性地址,其实就是物理地址。这里涉及到三个地址,逻辑地址:1000h及100h,线性地址:10100h,物理地址:10100h。BTW,物理地址通俗的说就是实际存储器数据总线上的bits。
      就i386而言,实模式中能访问的数据范围20bits,即0-1M,又分段管理段寄存器16位64k对齐。据段寄存器内容确定的基地址,一个进程总是能访问从该基址开始的连续的64k地址空间,修改寄存器也没有指令特权这方面的限制,这样通过修改寄存器就能访问任何内存单元。8086只运行在便是类似i386实模式方式中,无所谓特权指令(特权指令,像i386中访问GDTR的指令等),内存寻址缺乏对内存空间的保护。一个操作系统缺乏对寄存器及内存的访问控制,可想而知,都不具备现代操作系统的基本要求。
      那么,在保护模式下,上述汇编实例,会是如何个原理呢,有哪些访问控制保护?
      在保护模式下改变段寄存器的功能,可使其从单纯的基地址(变相的基地址)变成指向这样一个数据结构的指针。这样,当一条访内指令发出一个内存地址时,CPU就可以这样归纳出实际上放上数据总线的地址:
      1 根据指令的性质来确定应该使用哪一个段寄存器,例如转移指令中的地址在代码段,而取数据指令的地址在数据段。这与实地址模式相同。
      2 根据段寄存器的内容,找到相应的“地址段描述结构”。
从地址段描述结构中得到基地址
      3 将指令中发出的地址作为位移,与段描述结构中规定的段长度相比,看是否越界。
      5 根据指令的性质和段描述符中的访问权限来确定是否越权
      6 将指令中发出的地址作为位移,与基地址相加而得出实际的“物理地址”。
      上述,6中得出的是实际的物理地址,而非线性地址或说此时两者是相等的,是因为在进入保护模式之前,实模式中需要做些工作,一当然是使能分段管理,二其实可以选择性的使能分页管理。若在实模式中没有使能,那进入保护模式中使能分页管理前,还是直接采用分段管理内存访问。不过此时的段式内存访问,采用了间接的地址段描述结构管理,而不是直接使用段寄存器内容计算基址,再者当然就是添加了内存访问控制。

小结

      简单介绍了linux内核的版本管理方式;linux内核学习i386平台的一些实例测试,今后会可能用到的工具;也延伸说到了有关虚或实地址的概念。

附bochs调试 log
<bochs:1> b 0x7c00           #跳到0x7c00处执行
<bochs:2> trace-reg on       #每次命令执行打印寄存器值
Register-Tracing enabled for CPU0
<bochs:3> c                  #继续执行
(0) Breakpoint 1, 0x00007c00 in ?? ()
Next at t=13162205
eax: 0x0000aa55 43605
ecx: 0x00090000 589824
edx: 0x00000000 0
ebx: 0x00000000 0
esp: 0x0000ffd6 65494
ebp: 0x00000000 0
esi: 0x000e0000 917504     
edi: 0x0000ffac 65452      #edi低位即di目前值
eip: 0x00007c00
eflags 0x00000082: id vip vif ac vm rf nt IOPL=0 of df if tf SF zf af pf cf
(0) [0x0000000000007c00] 0000:7c00 (unk. ctxt): jmp .+217 (0x00007cdc)    ; e9d900  #0xe9 0xd9两字节指令值
<bochs:4> n                 #下条指令执行
Next at t=13162206
eax: 0x0000aa55 43605       #特殊值,0xaa55 主引导记录
ecx: 0x00090000 589824
edx: 0x00000000 0
ebx: 0x00000000 0
esp: 0x0000ffd6 65494
ebp: 0x00000000 0
esi: 0x000e0000 917504
edi: 0x0000ffac 65452
eip: 0x00007cdc
eflags 0x00000082: id vip vif ac vm rf nt IOPL=0 of df if tf SF zf af pf cf
(0) [0x0000000000007cdc] 0000:7cdc (unk. ctxt): mov ax, cx                ; 89c8
<bochs:5> n
Next at t=13162207
eax: 0x00000000 0
ecx: 0x00090000 589824
edx: 0x00000000 0
ebx: 0x00000000 0
esp: 0x0000ffd6 65494
ebp: 0x00000000 0
esi: 0x000e0000 917504
edi: 0x0000ffac 65452
eip: 0x00007cde
eflags 0x00000082: id vip vif ac vm rf nt IOPL=0 of df if tf SF zf af pf cf
(0) [0x0000000000007cde] 0000:7cde (unk. ctxt): mov ds, ax                ; 8ed8
<bochs:6> n
Next at t=13162208
eax: 0x00000000 0
ecx: 0x00090000 589824
edx: 0x00000000 0
ebx: 0x00000000 0
esp: 0x0000ffd6 65494
ebp: 0x00000000 0
esi: 0x000e0000 917504
edi: 0x0000ffac 65452
eip: 0x00007ce0
eflags 0x00000082: id vip vif ac vm rf nt IOPL=0 of df if tf SF zf af pf cf
(0) [0x0000000000007ce0] 0000:7ce0 (unk. ctxt): mov es, ax                ; 8ec0
<bochs:7> n
Next at t=13162209
eax: 0x00000000 0
ecx: 0x00090000 589824
edx: 0x00000000 0
ebx: 0x00000000 0
esp: 0x0000ffd6 65494
ebp: 0x00000000 0
esi: 0x000e0000 917504
edi: 0x0000ffac 65452
eip: 0x00007ce2
eflags 0x00000082: id vip vif ac vm rf nt IOPL=0 of df if tf SF zf af pf cf
(0) [0x0000000000007ce2] 0000:7ce2 (unk. ctxt): mov ax, 0x0000            ; b80000
<bochs:8> n
Next at t=13162210
eax: 0x00000000 0
ecx: 0x00090000 589824
edx: 0x00000000 0
ebx: 0x00000000 0
esp: 0x0000ffd6 65494
ebp: 0x00000000 0
esi: 0x000e0000 917504
edi: 0x0000ffac 65452
eip: 0x00007ce5
eflags 0x00000082: id vip vif ac vm rf nt IOPL=0 of df if tf SF zf af pf cf
(0) [0x0000000000007ce5] 0000:7ce5 (unk. ctxt): mov ds, ax                ; 8ed8
<bochs:9> n
Next at t=13162211
eax: 0x00000000 0
ecx: 0x00090000 589824
edx: 0x00000000 0
ebx: 0x00000000 0
esp: 0x0000ffd6 65494
ebp: 0x00000000 0
esi: 0x000e0000 917504
edi: 0x0000ffac 65452
eip: 0x00007ce7
eflags 0x00000082: id vip vif ac vm rf nt IOPL=0 of df if tf SF zf af pf cf
(0) [0x0000000000007ce7] 0000:7ce7 (unk. ctxt): mov di, 0x0000            ; bf0000
<bochs:10> n
Next at t=13162212
eax: 0x00000000 0
ecx: 0x00090000 589824
edx: 0x00000000 0
ebx: 0x00000000 0
esp: 0x0000ffd6 65494
ebp: 0x00000000 0
esi: 0x000e0000 917504   #esi低位即si,调试用di不用si因为值低位全为0,再置0,值改无体现。 :)
edi: 0x00000000 0        #edi低位即di值置为0x0000
eip: 0x00007cea
eflags 0x00000082: id vip vif ac vm rf nt IOPL=0 of df if tf SF zf af pf cf
(0) [0x0000000000007cea] 0000:7cea (unk. ctxt): mov ax, word ptr ds:[di+31744] ; 8b85007c
<bochs:11> n
Next at t=13162213
eax: 0x0000d9e9 55785   #eax低位即ax置为0xd9e9
ecx: 0x00090000 589824
edx: 0x00000000 0
ebx: 0x00000000 0
esp: 0x0000ffd6 65494
ebp: 0x00000000 0
esi: 0x000e0000 917504
edi: 0x00000000 0
eip: 0x00007cee
eflags 0x00000082: id vip vif ac vm rf nt IOPL=0 of df if tf SF zf af pf cf
(0) [0x0000000000007cee] 0000:7cee (hunk. ctxt): call .-238 (0x00007c03)   ; e812ff
<bochs:12> xp /64xb 0x7c00  #打印0x7c00地址处开始的64个字节,可知起始两字节为0xe9,0xd9,即0xd9e9
[bochs]:
0x00007c00 <bogus+       0>:    0xe9    0xd9    0x00    0xb4    0x06    0xb0    0x00    0xb5
0x00007c08 <bogus+       8>:    0x00    0xb5    0x00    0xb6    0x18    0xb2    0x4f    0xb7
0x00007c10 <bogus+      16>:    0x07    0xcd    0x10    0xc3    0xb4    0x00    0xb0    0x13
0x00007c18 <bogus+      24>:    0xcd    0x10    0xc7    0x06    0x04    0x7d    0x13    0x00
0x00007c20 <bogus+      32>:    0xc7    0x06    0x06    0x7d    0x40    0x01    0xc7    0x06
0x00007c28 <bogus+      40>:    0x08    0x7d    0xc8    0x00    0x66    0xc7    0x06    0x0a
0x00007c30 <bogus+      48>:    0x7d    0x00    0x80    0x0b    0x00    0xc3    0xb8    0x00
0x00007c38 <bogus+      56>:    0x08    0x8e    0xc0    0x8e    0xd8    0x31    0xff    0xb4
<bochs:13> 

资料参考:
      linux内核情景分析
      x86_64体系探索及编程
      https://www.cnblogs.com/BoyXiao/archive/2010/11/20/1882716.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值