Chinaunix首页 | 论坛 | 博客
  • 博客访问: 120107
  • 博文数量: 41
  • 博客积分: 1410
  • 博客等级: 上尉
  • 技术积分: 306
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-01 10:41
文章分类

全部博文(41)

文章存档

2011年(1)

2009年(40)

我的朋友

分类:

2009-04-14 20:25:14

一。创建并载入全局描述符表GDT

二。由实模式切换到保护模式

三。由保护模式切换到实模式

一。[[Anchor(NBE1)]]创建并载入全局描述符表GDT

在从实模式切换到保护模式之前,首先是要建立合适的全局描述符表GDT,并使用48位指针gdtdesc指向该GDT。一般情况下,需要在GDT中设置代码段和数据段的描述符。在这里的例子是以grub中的模式转换为基础的,见stage2/asm.S。

在下面的GDT中,共设置了5个段描述符,并将代码段、数据段设置成线性平坦的模式,即虚拟地址等于线性地址:

  • .p2align 2;强制4字节对齐,即16位对齐

gdt:

  • .word 0, 0
  • .byte 0, 0, 0, 0 ;空段描述符
  • .word 0xFFFF, 0 ;代码段描述符,可以看到段界限低16位为0xFFFF
  • .byte 0, 0x9A, 0xCF, 0 ;第6、7字节为1100111110011010,段界限粒度G为1,段界限高四位都为1,可寻址到0xFFFFF*4K,即4G字节;段基址为0;权限为执行/读,
  • .word 0xFFFF, 0 ;数据段描述符
  • .byte 0, 0x92, 0xCF, 0 ;权限为读/写
  • .word 0xFFFF, 0 ;16位实模式代码段描述符
  • .byte 0, 0x9E, 0, 0 ;段界限粒度G为0,段界限为0xFFFF,可寻址到0xFFFF,即64K字节;段基址为0;权限为执行/读、一致码段
  • .word 0xFFFF, 0 ;16位实模式数据段描述符
  • .byte 0, 0x92, 0, 0 ;权限为读/写

gdtdesc:

  • .word 0x27 ;GDTR界限,可以描述(0x27+1)/8=5个描述符,和上面一致
  • .long gdt ;GDTR基地址,指向gdt

然后使用如下指令将GDT装载到GDTR:

  • lgdt gdtdesc

在gdtdesc指针指向的结构中,低字是以字节位单位的全局描述符表段的界限,即描述符数目,高双字为描述符表段的线性基地址。

二。[[Anchor(NBE2)]]由实模式切换到保护模式

在做好准备后,从实模式切换到保护模式并不难。原则上只要把控制寄存器CR0中的PE位置1即可。本实例采用如下三条指令设置PE位:

  • movl %cr0, %eax
  • or $1, %eax
  • mov %eax, %cr0

实际情况要比这复杂些。执行上面的三条指令后,处理器转入保护模式,但CS中的内容还是实模式下代码段的段值,而不是保护模式下代码段的选择子,所以在取指令之前得把代码段的选择子装入CS。为此,紧接着这三条指令,安排一条如下所示的段间转移指令:

  • ljmp $0x8, $protcseg ;就是gdtdesc的代码段选择子,重新载入代码段

这条段间转移指令在实模式下被预取并在保护方式下被执行。利用这条段间转移指令可把保护模式下代码段的选择子装入CS,同时也刷新指令预取队列。从此真正进入保护模式。

  • .code32

protcseg:

  • movw $0x10, %ax ;就是gdtdesc的数据段选择子,重新载入其它段
  • movw %ax, %ds
  • movw %ax, %es
  • movw %ax, %fs
  • movw %ax, %gs
  • movw %ax, %ss

三。[[Anchor(NBE3)]]由保护模式切换到实模式

在80386上,从保护模式切换到实模式的过程类似于从实模式切换到保护模式。原则上只要把控制寄存器CR0中的PE位清0即可。实际上,在此之后也要安排一条段间转移指令,一方面清指令预取队列,另一方面把实模式下代码段的段值送CS。这条段间转移指令在保护方式下被预取并在实模式下被执行。

首先设置实模式段地址:

  • lgdt gdtdesc
  • movw $0x20, %ax ;就是gdtdesc的16位实模式数据段选择子,重新载入数据段
  • movw %ax, %ds
  • movw %ax, %es
  • movw %ax, %fs
  • movw %ax, %gs
  • movw %ax, %ss
  • ljmp $0x18, $tmpcseg;就是gdtdesc的16位实模式代码段选择子,重新载入代码段

然后通过设置CR0的PE位返回实模式:

tmpcseg:

  • .code16
  • mov %cr0, %eax
  • and $11111110b, %al
  • mov %eax, %cr0

然后跳转到实模式的代码地址执行:

  • ljmp $0, $realcseg

realcseg:

  • xorl %eax, %eax
  • movw %ax, %ds
  • movw %ax, %es
  • movw %ax, %fs
  • movw %ax, %gs
  • movw %ax, %ss

这样就回到实模式了。

阅读(1436) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2009-09-30 09:12:34

有一个问题,请问进入asm。s以后为什么访问符号地址的时候不经过一个绝对地址转换的过程呢