lab1-练习3 实模式与保护模式的转换

练习3:分析bootloader进入保护模式的过程。(要求在报告中写出分析)

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

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

  • 为何开启A20,以及如何开启A20
  • 如何初始化GDT表
  • 如何使能和进入保护模式

实验报告 练习3

实验指导书: 实模式&保护模式&段表的建立及其使用:

https://chyyuu.gitbooks.io/ucore_os_docs/content/lab1/lab1_3_2_1_protection_mode.html?q=

bootasm.S源码:(个人的注释用//标注)

#include <asm.h>

# Start the CPU: switch to 32-bit protected mode, jump into C.

# The BIOS loads this code from the first sector of the hard disk into

# memory at physical address 0x7c00 and starts executing in real mode

# with %cs=0 %ip=7c00.

.set PROT_MODE_CSEG,        0x8                     # kernel code segment selector
.set PROT_MODE_DSEG,        0x10                    # kernel data segment selector
.set CR0_PE_ON,             0x1                     # protected mode enable flag

# start address should be 0:7c00, in real mode, the beginning address of the running bootloader

.globl start
start://从start开始是实模式到保护模式的转变
.code16                                             # Assemble for 16-bit mode
    cli                                             # Disable interrupts 屏蔽中断
    cld                                             # String operations increment 字符串比较的时候指针自增

    # Set up the important data segment registers (DS, ES, SS).
    xorw %ax, %ax                                   # 将ax清零 异或自己,这样就能快速的清零
    movw %ax, %ds                                   # -> Data Segment 清零数据段
    movw %ax, %es                                   # -> es一般是数据段的偏移寄存器 清零
    movw %ax, %ss                                   # -> 清零栈寄存器
    
    # Enable A20:
    #  For backwards compatibility with the earliest PCs, physical
    #  address line 20 is tied low, so that addresses higher than
    #  1MB wrap around to zero by default. This code undoes this.
// 等待8042键盘控制器不忙
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
    
   //CR0中包含了6个预定义标志,0位是保护允许位PE(Protedted Enable),用于启动保护模式,如果PE位置1,则保护模式启动,如果PE=0,则在实模式下运行。
   //初始化GDT表:一个简单的GDT表和其描述符已经静态储存在引导区中,载入即可
    lgdt gdtdesc
    movl %cr0, %eax			
    orl $CR0_PE_ON, %eax	//或操作赋1,将PE置为1
    movl %eax, %cr0
    
   //跳转进保护模式代码
    ljmp $PROT_MODE_CSEG, $protcseg

.code32                                             # Assemble for 32-bit mode
protcseg:
    # Set up the protected-mode data segment registers
    movw $PROT_MODE_DSEG, %ax                       # 内核的数据段选择子全部初始化给有关数据的寄存器
    movw %ax, %ds                                   # -> DS: Data Segment
    movw %ax, %es                                   # -> ES: Extra Segment
    movw %ax, %fs                                   # -> FS
    movw %ax, %gs                                   # -> GS
    movw %ax, %ss                                   # -> SS: Stack Segment

    # 这一步是初始化C语言运行所需要的栈 ebp是栈底指针,esp是栈顶指针,程序到这里就进入bootmain执行
    movl $0x0, %ebp 
    movl $start, %esp
    call bootmain
    
    //如果程序返回,则进入spin,并且在spin

spin:
    jmp spin

# Bootstrap GDT

.p2align 2                                          # force 4 byte alignment
gdt://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

gdtdesc://gdt表的地址和长度
    .word 0x17                                      # sizeof(gdt) - 1
    .long gdt                                       # address gdt

总结一下,从实模式到保护模式干的事情:

1.将cr0 PE位置1 以保护模式的寻址方式寻址

2.加载固化在引导区里的GDT表

3/初始化C语言堆栈

posted @ 2021-01-03 20:05  lsxkugou  阅读(138)  评论(0编辑  收藏  举报