保护模式的进入

终于进入保护模式了,从放假开始纠结了4天,虽然是冰山一角,但还是很兴奋的~呵呵。之前没接触过汇编,很多概念都不清楚,所以学到了很多。

计算机在开机执行完BIOS进行最初的初始化之后,会跳转到0x7c00处执行引导程序,此时CPU运行在实地址模式下,在实模式下,只能寻址1MB的空间,而且操作系统的代码和数据并没有得到保护,应用程序可能会访问并修改他们,这是很不安全的。而保护模式,顾名思义,是为操作系统提供了保护措施的模式,在保护模式下,应用程序不能直接访问系统代码和数据,只能通过系统调用访问,而且每个进程独享自己4GB的地址空间。而保护模式还有一个更直观且很重要的作用就是它提高了寻址能力,应用程序可以访问4GB的空间。

进入保护模式的主要步骤有

1.创建GDT表

2.载入GDT表

3.打开A20地址线

4.设置CR0的PE位

5.跳转到保护模式

1.创建GDT表

GDT是全局描述符表,用来保存每个段的信息,包括段的限界、基地址和一些属性。描述符的结构如下

 

高地址………………………………………………………………………低地址

 

; |   7   |   6   |   5   |   4   |   3   |   2   |   1   |   0    |

; |7654321076543210765432107654321076543210765432107654321076543210| <- 共 8 字节

; |--------========--------========--------========--------========|

; ┏━━━┳━━━━━━━┳━━━━━━━━━━━┳━━━━━━━┓

; ┃31..24┃   (见下图)   ┃     段基址(23..0)    ┃ 段界限(15..0)┃

; ┃      ┃              ┃                      ┃              ┃

; ┃ 基址2┃③│②│    ①  ┃基址1b│   基址1a      ┃    段界限1   ┃

; ┣━━━╋━━━┳━━━╋━━━━━━━━━━━╋━━━━━━━┫

; ┃   %6 ┃  %5  ┃  %4  ┃  %3  ┃     %2       ┃       %1     ┃

; ┗━━━┻━━━┻━━━┻━━━┻━━━━━━━┻━━━━━━━┛

;         │                /_________

;         │                          /__________________

;         │                                             /________________________________________________

;         │                                                                                              /

;         ┏━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┓

;         ┃ 7  ┃ 6  ┃ 5  ┃ 4  ┃ 3  ┃ 2  ┃ 1  ┃ 0  ┃ 7  ┃ 6  ┃ 5  ┃ 4  ┃ 3  ┃ 2  ┃ 1  ┃ 0  ┃

;         ┣━━╋━━╋━━╋━━╋━━┻━━┻━━┻━━╋━━╋━━┻━━╋━━╋━━┻━━┻━━┻━━┫

;         ┃ G  ┃ D  ┃ 0  ┃ AVL┃   段界限 2 (19..16)  ┃  P ┃   DPL    ┃ S  ┃       TYPE           ┃

;         ┣━━┻━━┻━━┻━━╋━━━━━━━━━━━╋━━┻━━━━━┻━━┻━━━━━━━━━━━┫

;         ┃      ③: 属性 2      ┃    ②: 段界限 2      ┃                   ①: 属性1                  ┃

;         ┗━━━━━━━━━━━┻━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━┛

;       高地址                                                                                          低地址

在创建GDT时,一定要注意以下几点:

a.Intel是采用小端来保存数据的,我在此采用的是Nasm,Nasm中没有类似于GASM中.quad的指令,所以在Nasm中声明8字节数据时,必须要    按照从右到左的顺序声明。例如

   gdt:

   dw 0,0,0,0

   ;代码段描述符

   dw 0x0010;1-2字节

   dw 0x0000;3-4字节 可执行/写

   dw 0x9a00;5-6字节

   dw 0x00cf;7-8字节

   ;显示段描述符

   dw 0x0010

   dw 0x8000;可读/写

   dw 0x920B

   dw 0x00cf

   而且也要注意,拿代码段描述符的第1-2字节为例,[gdt+8]处的数据是0x10而不是0x00,因为是小端存放的。但是在寄存器中的数据仍然是      0x0010,即如果用访问内存的方式(加中括号)访问数据时,一定要注意存放的顺序,而在访问寄存器时则不用考虑。

b.在进入保护模式后,表达式seg:offset中的seg和实模式下seg的含义是完全不同的。实模式下seg的含义即为某个段的基地址,而保护模式下      seg只是一个索引,它指明了某个段在GDT中的索引,且叫作选择子,它也有自己的结构,如下

; 选择子图示:

;         ┏━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┳━━┓

;         ┃ 15 ┃ 14 ┃ 13 ┃ 12 ┃ 11 ┃ 10 ┃ 9   ┃ 8   ┃ 7   ┃ 6   ┃ 5   ┃ 4   ┃ 3   ┃ 2   ┃ 1   ┃ 0   ┃

;         ┣━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━┻━━╋━━╋━━┻━━┫

;         ┃                                 描述符索引                                                                  ┃ TI  ┃   RPL      ┃

;         ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━┻━━━━━┛

   其中TI=0表明请求的是在GDT中的段,TI=1表明是一个LDT中的段。RPL是请求特权级。可以看到,一个GDT中最多可以有2^13个段。

2.载入GDT表

   载入GDT表,可以用lgdt指令,它将一个结构载入gdtr寄存器,该结构指明了GDT表的地址和GDT的界限。GDTR结构共有六个字节,低两字节      指明GDT的界限,高四字节指明GDT的地址。此处也要注意从右到左的声明顺序。

 

   ;GDTR

   gdtptr:

   dw 0x0010

   dw gdt,0;不是0x7c00+gdt

其余三个步骤都较为简单且都差不多,所以不多说了。还要注意的是跳转到保护模式后,所有的代码都应该是在32位模式下,所以要在程序中用[BITS 32]指明。整个程序的代码如下:

程序中代码段和显示段是这样联系的:在disppmmsg中将显示段赋给gs,然后从12行开始,把要执行代码的地址赋给代码段的基地址。此处要执行的代码地址为当前段基址cs左移四位加上偏移。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值