1、linux是一个操作系统在机器加电后,需要从硬件通过一个引导程序加载os kernel,那么在os kernel的main函数运行之前,都发生了什么呢?

(1)引导BIOS(存储在ROM芯片中,ROM:只读存贮器,现在一般为闪存)的启动(准备实模式下的中断向量表和中断服务程序)

实模式:Intel80x86系列的一种cpu运行模式,特点,20位地址寻址(1MB),可直接访问BIOS和周边的硬件,没有硬件支持的实时多任务和分页机制。

BIOS任务:把os 加载到RAM(随机存取存储器,也就是常见的内存条)

所有的cpu在加电时强行进入16位实模式,此时cpu的一些特殊值:

CS:0xF0000,IP:0xFFF0 所以起始地址为CS:IP   =   0xFFFF0也就是BIOS的地址。

CS:代码段寄存器

IP:指令指针寄存器(IP对应16位,EIP对应32位,RIP对应64位)

指令的地址:代码段其实地址+指令段内偏移地址 = CS + IP

中断向量表的位置:0x00000 ~ 0x003FF (一共1kb):一共256个中断向量(CS:IP),每个4B(CS:2B;IP:2B)

BIOS数据区:0x00400 ~ 0x004FF

中断服务程序:0x0E50B ~ 0x0FFFE

中断int

(2)加载第一部分kernel代码(bootsect)

BIOS收到int 0x19,转到中断服务程序0x0E6F2(启动加载服务程序的入口地址):把第一扇区的512B代码加载到内存制定位置(0x07C00)

(3)加载第二部分代码:

首先规划内存,然后拷贝自身从0x07C00 到0x90000

(DS/ES/FS/GS/SS段寄存器,SP栈顶指针)

然后是int 0x13,将setup.s这一部分代码加载到内存0x90200处。

bootsect和setup.s是紧紧连在一起的此时SS:SP的值是0x9FF00

(4)加载系统模块

bootsect利用int 0x13加载系统模块,执行加载任务的主要程序read_it ,将约120KB的内容加载值0x10000(SYSSEG)处

然后确认一下根设备号,根文件系统设备(root device):系统中利用工具做出一个文件系统并加载至本机。

(5)通过jumpi 0,SETUPSEG:跳转至setup.s(0x90200)处,执行setup

利用BIOS提供的中断服务程序从设备读取机器系统数据,从0x41 和 0x46 处读取 硬盘参数表1 和 硬盘参数表2 ,分别放置在

0x90080 和 0x90090 处

系统的数据加载到内存:0x90000-0x901FD total:510B

开始实模式到保护模式的变化

(6)关闭中断(CPU IF位:0)

开中断和关中断(cli 和 sti)

复制内核到内存的0x00000处(释放BIOS的中断向量表和中断服务程序,然后移动内核)

设置中断描述符表 和 全局描述符表 (IDT 和 GDT),

中断描述符表寄存器(IDTR)

全局描述符表寄存器(GDTR)系统中唯一存放段寄存器内容的数组,配合保护模式下的寻址

************************************************************************************************

存放任务的局部描述符表(LDT)地址 和 任务状态段(TSS)地址 完成进程各段的寻址,进城现场的保护与恢复

GDTR标示GDT的入口,一般用LGDT将GDT基地址加载到GDTR

IDT:中断服务程序的入口地址。

IDTR:保存IDT的起始地址。(LIDT指令完成)

*************************************************************************************************

(7)打开A20,实现32位寻址(否则,即在16位模式下,超范围寻址将导致寻址回滚)

32位寻址:最大寻址空间4GB

执行head.s

首先认识一下可编程中断控制器:8259A:单片可管理8级向量优先级中断(可联级,最多管理64级向量中断)

int 0x00 ~ int 0x1F   内部中断(不可屏蔽) 和 异常中断

保护模式下:IRQ0x00 ~ IRQ0x0F 对应中断号:int 0x20 ~ int 0x2F

设置保护模式的代码:

mov ax,#0x0001

lmsw ax

此时cr0寄存器第0位:PE置1

跳转到head.s入口结束setup开始执行head文件。

注:x87:数学协处理器,外置可选(从486之后一般改为内置)。

将head.s 汇编成目标代码,c语言kernel编译成目标代码,连接成system模块。

其中head:

25KB + 184B

head在0x000000位置创建也目录表,页表,缓冲区,GDT,IDT(占用覆盖head已经执行过的代码)

内核起始位置0x000000 _pg_dir (页表目录起始位置)

重建一套GDT,因为源GDT内存位置将被覆盖。

检查数学协处理器

最后的准备:

L6标号和main函数入口地址压栈,L6是main函数异常退出时的程序转接点:程跳转到setup_paging去建立分页机制。

一页:4KB

Main函数入口:0x064b8

全局描述符表:0x05cb8

中断描述符表:0x054b8

剩余184B:0x05400

软盘缓冲区:0x05000

页表3到页表0的起始:0x01000 0x03000 0x02000 0x01000

页表目录:0x00000

Pg位CR0寄存器第31位:控制分页。

CR3寄存器:分页机制虚拟地址到物理地址的映射。

然后开始调用main。

Linux系统内核main函数执行之前的更多相关文章

  1. Linux下main函数启动过程【程序员自我修养笔记】【自用】

    1. 入口函数和程序初始化 1.1 程序从main开始吗? 当程序执行到main函数的第一行时,很多事情都已经完成了: [证1]如下是一段C语言代码: 代码中可以看到,在程序刚刚执行到main的时候, ...

  2. c/c++ main函数执行之前/后

    转载自:http://bbs.csdn.net/topics/300103318#r_78088969 main函数之前--真正的函数执行入口或开始 一种解释: 实际上,在可执行文件被加载之后,控制权 ...

  3. main函数执行前、后再执行的代码

    一.main结束 不代表整个进程结束  (1)全局对象的构造函数会在main 函数之前执行,          全局对象的析构函数会在main函数之后执行:          用atexit注册的函数 ...

  4. main函数执行前后还会发生什么

    问题分析 首先main()函数只不过是提供了一个函数入口,在main()函数中的显示代码执行之前,会由编译器生成_main函数,其中会进行所有全局对象的构造以及初始化工作.简单来说对静态变量.全局变量 ...

  5. Linux中Main函数的执行过程

    1. 问题:Linux如何执行main函数. 本文使用一个简单的C程序(simple.c)作为例子讲解.代码如下, int main() { return(0); } 2.  编译 -#gcc -o ...

  6. GRADLE下运行main函数/执行测试用例

    group 'gongsibao.ged' version '1.0-SNAPSHOT' apply plugin: 'java' apply plugin: 'idea' sourceCompati ...

  7. [牛客网试题] Test.main() 函数执行后的输出是()

    public class Test { public static void main(String [] args){ System.out.println(new B().getValue()); ...

  8. 2)main函数在执行前和执行后有哪些操作

    main函数执行之前,主要就是初始化系统相关资源:      1. 设置栈指针      2. 初始化static静态和global全局变量,即data段的内容      3. 将未初始化部分的全局变 ...

  9. C/C++中如何在main()函数之前执行一条语句?

    在C语言中,如果使用GCC的话,可以通过attribute关键字声明constructor和destructor(C语言中如何在main函数开始前执行函数) #include <stdio.h& ...

随机推荐

  1. Cocos2d-x 3.0final 终结者系列教程06-Director和场景跳转

    这些天互联网大事不少呀 1.逻辑思维分家(所谓合久必分,分久必合,实属正常.切行切珍惜吧) 2. 锤子手机开卖  (无论你买没买,反正我没买,作为多年Android开发的我深知说的亮点事实上在我看来都 ...

  2. 检查 Linux 服务器性能

    如何用十条命令在一分钟内检查 Linux 服务器性能 如果你的Linux服务器突然负载暴增,报警短信快发爆你的手机,如何在最短时间内找出Linux性能问题所在?来看Netflix性能工程团队的这篇博文 ...

  3. innobackupex参数之 --throttle 限速这个值设置多少合理 原创

    innobackupex参数之--parallel --throttle--parallel 此参数用于开启多个子进程并发备份多个数据文件(注意,一个数据文件只会有一个进程完成备份).可以加快备份速度 ...

  4. Entity Framework优化一:引发了“System.Data.Entity.Core.EntityCommandExecutionException”类型的异常

    错误信息: “System.Data.Entity.Core.EntityCommandExecutionException”类型的异常在 EntityFramework.SqlServer.dll ...

  5. mac配置完ssh依然提示"Enter passphrase for key"解决方法

    使用Git,每次都提示输入命令. 这个问题折磨很久,明明已经配置过ssh了,可是每次还要提示输入密码,从网上查查,最后一条命令解决问题: 问题提示: Enter passphrase for key ...

  6. (转)windows下编译最新的x264

    二:<windows下编译最新的x264> X264更新的比较快,每天都有更新,但算法模块,基本结构是没有多大变化的.x264都是用C语言写的包括C99,但C99语法是在VC中是没法用的( ...

  7. 在windows下编译ffmpeg

    编译ffmpeg,我在网上找了很多相关的方法,但最后都没编译成功. 所以下面就记录下自己的编译方法吧,留着以后编译的时候做参考. 1.首先,下载编译工具MinGW+Msys,搭建编译环境.工具下载地址 ...

  8. oracle用sql 语句如何向表中插入时间?

    有关日期的操作中,更多的是涉及系统当前时间,用sysdate表示即可,如果是插入其他非系统时间的日期类型数据的话,用to_date转换再插入就可以了.例: insert into 表(c_date) ...

  9. 资深投资人全力反击: VC增值平台从来就不是一坨狗屎

    编者注: 本文来自海外著名科技博客VentureBeat, 英文原文出自Kyle Lacy之手 ,中文版由天地会珠海分舵进行编译. 文章主要是针对前几天德国VC Christian Claussen的 ...

  10. python--数据类型--1

    原创博文,转载请标明出处--周学伟http://www.cnblogs.com/zxouxuewei/ 视频教程::http://www.imooc.com/learn/177 http://www. ...