zoukankan      html  css  js  c++  java
  • Linux内核剖析——操作系统的启动

    一.总体功能

    1.从通电到BIOS跳转

    1.1 CPU在通电后,先进入实模式,设置CS=0XFFFF,IP = 0X0000(指向BIOS)
    1.2 BIOS进行执行系统监测,并且在地址=0处初始化中断向量
    1.3 将启动设备的第一个扇区(引导扇区,512B)读入0x7c00处
    1.4 设置CS=0X07C0,IP=0X0000,跳转到该地址

    2.BootSect.S

    2.1 跳转到0x7c00时,该部分存放的是BootSect.S的程序,操作系统的所有故事从这开始
    2.2 开始执行后,把自身移动到地址0x90000处,并把setup.S读入到0x90200处,内核其他部分被读入到0x10000处
    机器从接电到开始的执行顺序如图

    程序执行顺序

    3.setup.S

    3.1 进入setup.后,将会自动识别主机的某些特性和VGA卡类型,并可以要求用户选择显示模式。
    3.2 将系统从0x10000处移动到0x0000处,进入保护模式并跳转到系统模块

    4.head.S

    设置并加载IDT,GDT,分页,CPU,并调用main.C中的main程序

    5.Main.c

    执行main程序

    6.系统启动程序转移图

    程序转移图

    7.部分说明

    7.1 bootsect.s为什么不直接移动内核程序位置,而要在setup.s中移动?
    ans:

    setup.s中的部分代码需要用到BIOS提供的中断向量表获取系统信息,在使用完BIOS之后才可将该区域覆盖。

    1. 2 仅在内存中加载了上述内核功能并不能让Linux系统运行,仍需要有完整的基本文件系统支持,即称为根文件系统。Linux0.12 使用了Minix的文件系统

    二.BootSect.S 代码解析

    主要作用

    该程序的主要作用是把自己移动到0x90000处并执行,把第二个扇区开始的四个扇区的Setup.s模块加载到bootsect.s之后,使用0x13中断取用当前引导盘的参数,并显示Loading system字符串。随后确定根文件系统的设备号,保存于root_dev,最后跳转到setup处去执行setup.s程序。后缀是大写的S,可以使用GNU C的预处理功能。

    核心代码

    BOOTSECT = 0X07C0
    INITSEG = 0X9000
    SETUPSEG = 0X9020
    mov ax,#BOOTSECT
    mov ds,ax
    mov ax,#INITSEG 
    mov es,ax
    mov cx,256
    sub si,si
    sub di,di
    rep
    movw //将DS:SI的内容赋值道ES:DI中,即把自身移动到0x90000处
    jmpi go,INITSEG//因为程序空间已经移动,所以需要使用jmpi指令进行继续执行
    go:
    mov ax,cs
    mov ds,ax
    mov es,ax
    mov ss,ax//把段寄存器全部初始化为当前代码段
    mov sp,0xff00//初始化栈
    ....//略过其余代码
    load_setup://载入setup程序
    xor dx,dx 
    mov cx,0x0002//扇区号为2
    mov bx,0x0200
    mov ax,0x0200+SETUPLEN//从第二个扇区开始,读4个扇区
    int 0x13
    //以上初始化0x13参数,并进行读取扇区,读入到es:bx
    jnc ok_load_setup
    xor dx,dx
    xor cx,cx
    int 0x13
    j load_setup
    ok_load_setup:
    //..略去打印loading system部分
    call read_it//读磁盘上的system模块
    jmpi 0,setupseg//跳转到setup.s
    //
    

    三.Setup.S 代码解析

    主要作用

    利用BIOS中断读取机器系统数据,并将这些数据保存到0X90000的位置,覆盖掉BootSect.s的数据,这些参数将被内核中的相关程序使用
    接着将system模块移动到0x0000处,加载idtr和gdtr,开启CPU保护模式,并跳转到最前面的head.S运行
    为了能让head.S在保护模式中运行,本程序中临时设定了IDT和GDT,并在GDT中设置了当前内核代码段的描述符和数据段的描述符

    核心代码

    start:
    mov ax,INITSEG
    mov ds,ax//将DS设置为INITSEG
    mov ah,0x03
    xor bh,bh
    int 0x10
    mov [0],dx//通过中断取得光标位置
    mov ah,0x88//获取扩展内存中断的功能调用
    int 0x15
    mov [2],ax//存储扩展内存数值
    ....//进行一系列参数获取
    cli //不允许中断
    mov ax,0x0000
    cld
    do_move:
    mov es,ax//目的地址
    add ax,0x1000
    cmp ax,0x9000//是否已经移动玩
    jz end_move//是,则跳转
    mov ds,ax//源地址
    sub di,di
    sub si,si
    mov cx,0x8000//移动64KB
    rep
    movsw
    jmp do_move
    call empty_8042//选通A20地址控制线,为了能使用1MB以上内存
    mov al,0xd1
    out 0x64,al
    call empty_8042
    mov al,0xdf
    out 0x60,al
    call empty_8042
    mov ax,0x0001
    mov cr0,ax//开启保护模式
    jmpi 0,8//保护模式寻址,查询GDT进入0地址处
    

    四.head.S 代码解析

    notice:

    head.s使用AT&T汇编编写,语法略有不同

    主要作用

    加载各个数据段寄存器,重新设置中断描述符表idt,重新设置GDT,检测A20地址线是否打开,设置分页后,打开main

    核心代码

    //主要就是调用main函数,过于简单,不写了
    
  • 相关阅读:
    Celery的使用
    python中使用redis
    Redis基础
    版本控制器git
    day 74作业
    Djangorestfromwork作业1
    Django rest-framework的jwt认证
    Django --form验证
    cx-oracle-------------------安装
    排序算法
  • 原文地址:https://www.cnblogs.com/alex101/p/14003822.html
Copyright © 2011-2022 走看看