0x0 背景



在我参加的面试和我面试别人、或者参加别人对别人的面试的事后经常遇到的一个问题就是:请从计算机加电开始描述一下计算机启动到操作系统正式启动起来的全过程。这是一个考验对计算机体系结构和基本知识了解程度的问题。今天也就特别针对这个问题做一个回答,答案是基于80x86结构Linux 2.6及更高版本内核的为基准操作系统为例来回答的。

0x1 从加电到BIOS启动



STEP 1 加电引导寄存器置位


这一过程指的是,计算机加电后,一个特殊电路会在CPU对应的一阵针脚产生一个逻辑电平,这个电平的值从针脚进入CPU后,会引发将寄存器(cs、eip等等)设置成特定值。

STEP 2 引导BIOS启动


这一过程指的是系统从物理地址0xfffffff0处加载一段程序到只读内存(ROM-> Read Only Memory),这个程序在80x86体系架构中一般称为BIOS。

相关知识学习


  • MS-DOS的很多系统调用依赖BIOS
  • Linux进入保护模式后不再依赖BIOS,BIOS只能以实模式运行。
实模式的寻址是20位总线寻址,支持的寻址空间为2^20,也就是1MB,保护模式目前在x86结构下,支持4GB寻址;
实际区别主要是EIP中的虚地址到实地址转化的区别:
实模式是seg(eip地址)*16+offset(4为偏移量);
保护模式实EIP的16位地址代表页面位置,一个页在操作系统中都学习过是4KB,1M*4K = 4G,我相信很多人就此理解了为啥页的大小要设计成4K;

0x2 BIOS引导操作系统镜像的加载



STEP 1 检查硬件


没啥可说的,一般可认为是开机加电自检,这个阶段会显示一些信息,包括BIOS版本这一类的信息。

STEP 2 初始化硬件


主要是避免IRQ先与I/O冲突,本阶段最后会显示所有PCI(总线--内部硬件通信线路)设备信息。

STEP 3 搜索操作系统


从软盘、网络、磁盘、CD-ROM的主引导扇区上搜索。找到后加载注意到扇区的内容到0x00007c00的位置(RAM中),跳转到这个地址,开始执行这段代码,这段程序叫做bootloader。

由于大小限制,linux的启动程序GRUB(GRand Unified BootLoader)或者是LILO(LInux LOader)被分为两部分。
第一部分就是加载到0x00007c00的这一段,他会把自己移动到0x00096a00的位置,建立实模式栈(0x00098000~0x000969ff)
第一部分吧第二部分加载到0x00096c00开始的位置中。
以上的位置都是在RAM中。
第二部分搜索磁盘上的OS景象,,把对应的扇区拷贝到RAM中执行:
1、首先把内核景象的第一个512B的部分从0x00090000处装入RAM中;
2、把setup()函数代码段装入0x00090200位置(RAM);
3、加载其他内核部分从高(0x00100000)或低(0x00010000)两个位置任选其一加载到RAM中,分别称为大映像内核和小映像内核;
4、跳转到setup函数执行;

0x3 setup函数引导内核



这个过程主要是检查和初始化硬件、虽然BIOS完成了相似的大部分工作,但是因为不依赖与BIOS,所以,还是重新初始化了硬件方面的事情;重要的过程有:

1、移动低装载小映像内核的位置到0x00001000去,如果是高装载则不移动;
2、建立IDT(临时中断描述符表)和GDT(临时全局描述符表);
3、如果需要,重置浮点单元(FPU);
4、重新编写可编程终端控制器(PIC),屏蔽除IRQ2外的所有终端;
5、设置cr0寄存器到PE位,设置PG位为0,切换到保护模式,暂未启用分页;
6、跳转到startup_32()函数;

0x4 内核建立阶段



STEP 1 startup_32()函数


主要做的事情如下:

1、初始化段寄存器和一个临时堆栈,并清零eflags寄存器所有为;
2、用0填充_edata 和_end符号标识的内核未初始化数据区;
3、调用decompress_kernel函数解压内核映像;
【低装载的情况解压内容放在0x00100000位置开始的RAM中,高装载的放在这后面的一个临时缓冲区内,解压后的内核就被移动到0x00100000位置】
4、跳转到0x00100000位置开始执行,新的执行点事arch/i386/kernerlhead.s中的另一个startup_32函数。

STEP 2 再战startup_32()函数


这个函数就是init进程(也是pid=0的0号进程)主要做了一下工作:

1、段寄存器初始化为最终值,内核的bss段填写为0;
2、初始化临时内核页表,初始化pg0,使得线性地址一律映射到统一的物理地址上;
3、cr3寄存器保存了页全局目录,并设置cr0的pg位启用分页;
4、清零eflags,使用setup_idt函数用空的终端处理程序填充IDT;
5、从bios获取的数据(系统参数和传递给os的参数)放入页框1;
6、识别处理器、用GDT和IDT填充gdtr和idtr寄存器;
7、跳转到start_kernel函数

0x5 内核完善阶段start_kernel函数



这一阶段最终完善了内核的初始化的后续工作,启动了程序调度、内存管理等操作系统的功能,其中就涉及到了著名的函数sched_init函数,至此,系统完全启动成功。

计算机从加电到系统(Linux)启动完成的更多相关文章

  1. 第1章 从开机加电到main函数之前的过程

    主要讲解了80x86cpu在启动的时候时bios如何工作,以及如何最终转换到保护模式. 1.1 启动bios 80x86作为冯诺依曼结构下的cpu,工作模式也是取指执行,即cpu根据cs:ip寄存器的 ...

  2. 深入理解Linux启动过程

    深入理解Linux启动过程       本文详细分析了Linux桌面操作系统的启动过程,涉及到BIOS系统.LILO 和GRUB引导装载程序,以及bootsect.setup.vmlinux等映像文件 ...

  3. Linux启动流程详解

    在BIOS阶段,计算机的行为基本上被写死了,可以做的事情并不多:一般就是通电.BIOS.主引导记录.操作系统这四步.所以我们一般认为加载内核是linux启动流程的第一步. 第一步.加载内核 操作系统接 ...

  4. Linux启动流程详解【转载】

    在BIOS阶段,计算机的行为基本上被写死了,可以做的事情并不多:一般就是通电.BIOS.主引导记录.操作系统这四步.所以我们一般认为加载内核是linux启动流程的第一步. 第一步.加载内核 操作系统接 ...

  5. lesson - 2 yum /单用户/救援模式/Linux 启动

    课程大纲:1.  yum使用yum 是一个在线安装软件包的工具,它可以帮我们解决软件包的依赖,这个日后会详细介绍.我们介绍了以下几个用法:yum list    这个命令可以列出所有安装过和未安装的软 ...

  6. 详解linux系统的启动过程及系统初始化

    一.linux系统的启动流程 关于linux系统的启动流程我们可以按步进行划分为如下: POST加电自检 -->BIOS(Boot Sequence)-->加载对应引导上的MBR(boot ...

  7. linux内核剖析(零)linux系统启动过程详解-开机加电后发生了什么

    本文参考了如下文章 深入理解linux启动过程 mbr (主引导记录(Master Boot Record)) 电脑从开机加电到操作系统main函数之前执行的过程 详解linux系统的启动过程及系统初 ...

  8. linux系统启动过程具体解释-开机加电后发生了什么 --linux内核剖析(零)

    本文參考了例如以下文章 深入理解linux启动过程 mbr (主引导记录(Master Boot Record)) 电脑从开机加电到操作系统main函数之前执行的过程 详细解释linux系统的启动过程 ...

  9. 计算机/linux启动过程

    开机过程指的是从打开计算机电源直到LINUX显示用户登录画面的全过程. 分析LINUX开机过程也是深入了解LINUX核心工作原理的一个很好的途径. 计算机开机过程是一个非常复杂的过程,想真正理解透彻并 ...

随机推荐

  1. sublime text3支持Vue语法高亮显示

    1.下载文件链接: 或https://github.com/vuejs/vue-syntax-highlight 解开压缩包vue-syntax-highlight-master,其内所有文件备用. ...

  2. 腾讯QQ积分CSRF导致积分任意挥霍(我的积分为什么少了)

    触发点:http://jifen.qq.com/html5/index.html?ADTAG=JIFEN.MART.INDEX 随意兑换一个商品: 因为刚才我已经兑换过了,所以积分没有了.. 没关系, ...

  3. Android学习之——ListView下拉刷新

    背景知识 ListView使用非常广泛,对于使用ListView的应用来说,下拉刷新是必不可少要实现的功能. 我们常用的微博.网易新闻,搜狐新闻都使用了这一功能,如下图所示.     微博 搜狐新闻 ...

  4. python Thread对象的setDaemon(True)的作用。

    1.如果主线程是永远都不会结束的,那设置一个线程为守护线程是没必要的,设不设置都一样. 2.什么时候需要设置为守护线程?如果希望子线程一直运行,可以把子线程的代码写在while True里面一直循环, ...

  5. python -m 命令单独运行一个文件,怎么解决单独运行文件报错?

    依旧是续上篇解决为什么项目能运行,单独文件不能运行. 依旧是python3先发下目录结构,依旧是cmd运行,不要弄pycharm开始运行,否则有些错误就发现不了! 项目下面有pac1文件夹,pac1下 ...

  6. CMD 切换管理员权限

    方法一:鼠标右键 这个方法比较比较普通,点开开始找到cmd,右击鼠标“以管理员身份运行(A)”这样调用就是管理员的权限: 方法二:快捷模式 在点开win+R后,选择“以管理员身份运行”,然后确定:可以 ...

  7. 使用 CSV 文件存储

    将爬取到的数据以 CSV 文件形式存储: import csv import requests req = requests.get("http://www.baidu.com/" ...

  8. 使用 urllib 设置代理服务

    (1) 如果我们一直用同一个IP去请求同一个网站上的网页,久了之后可能会被该网站服务器屏蔽,因此我们可以使用代理IP来发起请求,代理实际上指的就是代理服务器(2) 当我们使用代理IP发起请求时,服务器 ...

  9. windows下nodejs与coffeeScript环境搭建

    [本文档摘抄自网上资料] 安装NodeJS和CoffeeScript方法 首先安装Node(因为nodeJs是服务器端javascript运行环境),到http://nodejs.org/下载对应格式 ...

  10. js 简易模板引擎 , 持续更新。。。

    <script> var _mytpl = (function(){ var _verson = 1.0; return { _data:{}, load:function(html,da ...