ucore lab1练习3

分析bootloader进入保护模式的过程

BIOS将通过读取硬盘主引导扇区到内存,并转跳到对应内存中的位置执行bootloader。请分析bootloader是如何完成从实模式进入保护模式的。

提示:需要阅读小节“保护模式和分段机制”和lab1/boot/bootasm.S源码,了解如何从实模式切换到保护模式。

问题1:

为何开启A20,以及如何开启A20

先回答第一个问题,为了兼容早起的版本,x86在开机的时候是实模式状态,寻址空间是1m。寄存器只有16位,为了模拟1m的寻址空间,用cs和ip来寻址(cs*16+ip),但是cs和ip这样组合是有可能大于1m的,为了防止这种现象,在实模式下先关闭A20地址线,等到进入保护模式在开启。

下面是开启A20地址线代码。

seta20.1:
    inb $0x64, %al                                  # Wait for not busy(8042 input buffer empty).
    testb $0x2, %al
    jnz seta20.1

    movb $0xd1, %al                                 # 0xd1 -> port 0x64
    outb %al, $0x64                                 # 0xd1 means: write data to 8042's P2 port

seta20.2:
    inb $0x64, %al                                  # Wait for not busy(8042 input buffer empty).
    testb $0x2, %al
    jnz seta20.2

    movb $0xdf, %al                                 # 0xdf -> port 0x60
    outb %al, $0x60                                 # 0xdf = 11011111, means set P2's A20 bit(the 1 bit) to 1

看一下这段代码(昨天梦里都在看):

seta20.1:
    inb $0x64, %al                                  # Wait for not busy(8042 input buffer empty).
    testb $0x2, %al
    jnz seta20.1

参考手册附录中有说明,从64h读取Status Register,然后对应的第2(index为1)个bit如果位1的话,说明input register (60h/64h) 有数据。

这里用test指令和jnz指令对这一步进行判断,这里只有input register 里面没有数据才能进行下一个指令。

    movb $0xd1, %al                                 # 0xd1 -> port 0x64
    outb %al, $0x64                                 # 0xd1 means: write data to 8042's P2 port

这一步是通过向0x64发送一个0xd1信号,然后就可以向0x60缓冲区写数据了。

然后通过讲p2的第2个bit置为1,开启A20地址线。

总结:先判断input register是否为空,空后向0x64写入0xd1。
然后再次判断,然后向0x60写入0xdf开启A20地址线。

问题2:

如何初始化GDT表
代码:

    lgdt gdtdesc

lgdt指令是初始化端寄存器gdtr,gdtr寄存器有48位,6个字节,其中2个字节表示段表长度,4个字节表示段表地址。

gdtdesc:
    .word 0x17                                      # sizeof(gdt) - 1
    .long gdt                                       # address gdt

其中0x17便是长度(-1),gdt就是地址。

而gdt中跟了三个数据,分别表示null段,代码段和数据段。(里面用到了.h里面的宏定义,这里不做详细介绍)。

gdt:
    SEG_NULLASM                                                 # null seg
    SEG_ASM(STA_X|STA_R, 0x0, 0xffffffff)           # code seg for bootloader and kernel
    SEG_ASM(STA_W, 0x0, 0xffffffff)                 # data seg for bootloader and kernel

问题3

如何使能和进入保护模式

先看这段代码:

    movl %cr0, %eax
    orl $CR0_PE_ON, %eax
    movl %eax, %cr0

这里涉及到了cr0寄存器,我们先看cr0寄存器的介绍:

CR0中含有控制处理器操作模式和状态的系统控制标志;
CR0的位0是启用保护(Protection Enable)标志。当设置该位时即开启了保护模式;

上面这段代码很明显,就是把cr0的第1位置位1,说明开启保护模式。

涉及汇编指令:

    cli:禁止中断 
    cld:清除方向标志,即将DF置‘0’。STD为设置方向标志,即将DF置‘1’。
    test:按位与运算
    in      I/O端口输入. ( 语法: IN   累加器,    {端口号│DX} )  
    out     I/O端口输出. ( 语法: OUT {端口号│DX},累加器 )输入输出端口由立即方式指定时,    其范围是 0-255; 由寄存器 DX 指定时,其范围是    0-65535.  

    jnz(jmp not zero):zf不为零则转移。
    zf位:零标志ZF用来反映运算结果是否为0。如果运算结果为0,则其值为1,否则其值为0。

    test:用来对两个数进行与运算,如果为1,则zf值位1。
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值