美文网首页
IA-32保护模式下多任务切换的编码实现和分析(一)

IA-32保护模式下多任务切换的编码实现和分析(一)

作者: v1gor | 来源:发表于2019-10-31 16:01 被阅读0次

内核加载程序(写在MBR上的引导程序)

boot.s

BOOTSEG = 0x07c0
SYSSEG  = 0x1000
SYSLEN  = 17

entry start
start:
    jmpi    go,#BOOTSEG     
go: mov ax,cs
    mov ds,ax
    mov ss,ax
    mov sp,#0x400

load_system:
    mov dx,#0x00000          
    mov cx,#0x0002
    mov ax,#SYSSEG            
    mov es,ax
    xor bx,bx
    mov ax,#0x200+SYSLEN
    int     0x13             
    jnc ok_load              
die:    jmp die              

ok_load:
    cli                     
    mov ax, #SYSSEG         
    mov ds, ax
    xor ax, ax
    mov es, ax
    mov cx, #0x2000
    sub si,si
    sub di,di
    rep
    movw
    mov ax, #BOOTSEG
    mov ds, ax
    lidt    idt_48          
    lgdt    gdt_48

    mov ax,#0x0001
    lmsw    ax
    jmpi    0,8 

gdt:    .word   0,0,0,0 

    .word   0x07FF      
    .word   0x0000      
    .word   0x9A00      
    .word   0x00C0      

    .word   0x07FF      
    .word   0x0000      
    .word   0x9200  
    .word   0x00C0  

idt_48: .word   0       
    .word   0,0     

gdt_48: .word   0x7ff       
    .word   0x7c00+gdt,0
.org 510
    .word   0xAA55

从BISO启动原理浅析

当按下开机按键,计算机会做哪些事呢?

  1. 通电自检,检查硬盘,内存,显卡这些硬件设备是否正确和CPU连接和正常使用.

  2. 启动BIOS程序(启动前硬件会先设置好需要使用的各个BIOS中断),将引导扇区(MBR)中的引导程序加载到内存的0x07c0:0x0000(实地址模式)处,开始执行引导程序(汇编源码就是下面的boot.s)

  3. 引导程序执行的结果是将操作系统内核代码加载到内存中,并将内核代码移到某块指定内存中,修改cs:eip到内核程序的起始地址开始执行.

从代码分析BIOS启动过程

boot.s :

首先第一句

jmpi    go,#BOOTSEG

就有说头.

jmpi的指令格式如下:

jmpi offset , segment address

简单来说就是跳转到某个段的某个偏移处,代码中可以看到,#BOOTSEG是0x07c0,因此这条语句的意思是跳转到段地址是0x7c00,偏移是go标签相对于第一行代码的偏移开始执行.

问题是为啥要特意使用jmpi来执行下一条语句呢,直接顺序执行不可以吗?老师给的解释是:

这个jmpi语句实际上是一个隐式赋值语句,修改cs和eip指向当前代码段和偏移。

下面通过调试来验证一下:

在jmpi执行前,cs和eip的值如下:

beforejmpi.png

可以看到执行jmpi前还是保留着BIOS的cs和eip的值.而执行之后,cs和eip的值如下:

afterjmpi.png

此时已经将段地址修改到了当前代码段基址,偏移设置成go标签对应的代码.

  • go:

    初始化各段寄存器

  • load_system:

    使用BIOS中断int 0x13来将内核代码加载到内存的0x10000处,因为这个地址离0x7c00较远,内核代码不会覆盖到当前正在执行的0x7c00的代码段.

  • ok_load:

    第一行代码是一个cli关中断,这里关中断的原因是在地址0x0处,之前存储的是BIOS的中断向量表,移动后将覆盖这部分内容,同时,引导程序也没有安装新的中断向量表,没有中断向量表就不能响应中断,所以应该关闭中断避免发生故障。

    首先把被加载到内存的内核代码移动到线性地址0x00处,这样做的原因应该是为了是利用已经无用的地址空间,因为BIOS中断表被硬件默认填到了地址0x00处,由于现在BIOS的工作已经完成,所以可以覆盖掉这些无用的地址.

    其次初始化idtr和gdtr,之后还有两个关键操作:

      lmsw    ax
      jmpi    0,8 
    
    • lmsw将ax的最后一位复制到CR0的最后一位,这里的效果是将CR0的最低位置位(PE位).此后操作系统由实模式进入保护模式,对cs等段寄存器的解释由段地址转换为GDT表索引

    • jmpi 0,8的执行结果看来和本程序的第一句jmpi go,#BOOTSEG是一样的:将8赋值给cs,0赋值给偏移eip.但是上一条指令已经将CPU切换到保护模式,cs的值就会被解释为段选择子32位保护模式下的段选择子的结构如下:

    segselector.png
因此cs为8代表以特权级0(ring0)索引GDT表的第1项(从0开始)并从中解析出需要跳转的基址,加上偏移值之后跳转到目标地址执行(这一系列工作均由硬件解析cs来完成).接下来就开始从地址0x00处开始执行真正的内核代码了.

**段选择子**的通用结构如下:

![segdes.png](https://img.haomeiwen.com/i19793687/b99e2efc04186329.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  • MBR标志

      .org 510
      .word   0xAA55
    

    CPU加载MBR时会检查此字段,如果不为0xAA55就会拒绝开机.

相关文章

网友评论

      本文标题:IA-32保护模式下多任务切换的编码实现和分析(一)

      本文链接:https://www.haomeiwen.com/subject/esetbctx.html