从开机到main函数

  • 1. 启动BIOS,准备中断向量表和中断服务程序
    • 1.1 启动BIOS
    • 1.2 BIOS在内存中加载中断向量表和中断服务程序
  • 2 加载操作系统内核程序
    • 2.1 加载第一部分内核代码--引导程序(bootsect)
    • 2.2 加载第二部分内核代码--setup
    • 2.3 加载第三部分内核代码--system模块
  • 3 为调用main函数做准备
    • 3.1 关中断并将system移动到内存地址起始位置0x00000
    • 3.2 设置中断描述符表和全局描述符表
    • 3.3 打开A20,实现32位寻址
    • 3.4 为保护模式下执行head.s做准备
    • 3.5 执行head.s

从开机到main函数的执行分为三步完成,目的是实现从启动盘加载操作系统程序,完成执行main函数所需要的准备工作。 第一步,启动BIOS,准备实模式下的中断向量表和中断服务程序第二步,从启动盘加载操作系统程序到内存,加载操作系统程序的工作就是利用第一步中准备的终端服务程序实现的第三步,为执行32位的main函数做过渡工作

1. 启动BIOS,准备中断向量表和中断服务程序

1.1 启动BIOS

CPU上电之后将执行程序地址指向0xFFFF0处,这是一个纯硬件完成的动作,地址0xFFFF0的位置是BIOS程序的起始地址,也就是说,CPU上电之后,硬件引导执行BIOS程序。

1.2 BIOS在内存中加载中断向量表和中断服务程序

BIOS程序被固化在计算机主板上的一块很小的ROM芯片里。BIOS程序在内存最开始的位置(0x00000)用1KB的内存空间构建中断向量表,在紧挨着它的位置用256字节的内存空间构建BIOS数据区,并在大约57KB以后的位置加载了8KB左右的与中断向量表相应的若干中断服务程序。
中断向量表中有256个中断向量,每个中断向量占4个字节,其中两个字节是CS的值,两个字节是IP的值,每个中断向量都指向一个具体的中断服务程序。

2 加载操作系统内核程序

现在开始要执行真正的boot操作了,也就是将硬盘中的操作系统程序加载至内存。计算机分三批逐次加载操作系统的内核代码:第一批由BIOS中断int 0x19把第一扇区的bootsect的内容加载到内存第二批和第三批在bootsect的指挥下,分别将其后的4个扇区和随后的240个扇区的内容加载至内存

2.1 加载第一部分内核代码–引导程序(bootsect)

下面先介绍几个概念:
bootsect:引导程序,负责扇区存储内容的引导和加载。
Interrupt Vector Table:中断向量表,记录所有中断号对应的终端服务程序的内存地址。
Interrupt Service:中断服务,通过中断向量表的索引对中断进行响应服务。
BIOS程序启动之后,其要做的就是找到硬盘并加载第一扇区。int 0x19中断向量所指向的中断服务程序,即启动加载服务程序,就是我们所说的bootsect引导程序。第一扇区被称为启动扇区,第一扇区的载入,标志着Linux中的代码即将发挥作用。

2.2 加载第二部分内核代码–setup

 BIOS已经把bootsect载入到内存了,现在它的作用就是把第二批和第三批程序陆续加载到内存中。bootsect要做以下三个步骤:
①规划内存
为了把第二批和第三批程序加载到内存中的适当位置,bootsect首先做的工作就是规划内存。
②复制bootsect
bootsect把自身的所有程序(512B)从0x07C00的位置复制到0x90000的位置。
③将setup程序加载到内存中
BIOS利用int 0x13中断向量所指向的终端服务程序来完成setup程序的加载。
这里说一下目前所用到的两个中断向量int 0x19和int 0x13的区别:
Ⅰ.int 0x19中断向量所指向的启动加载服务程序是BIOS执行的,而int 0x13中断服务程序是Linux操作系统自身的启动代码bootsect执行的;
Ⅱ.int 0x19的中断服务程序只负责把第一扇区的代码加载到0x7C00位置,而int 0x13的中断服务程序则不然,它可以根据设计者的意图,把指定扇区的代码加载到内存的指定位置。

2.3 加载第三部分内核代码–system模块

BIOS借着BIOS中断 int 0x13,将240个扇区的system模块加载到内存。到此位置,第三批程序已经加载完毕,整个操作系统的代码已经全部加载至内存,bootsect的主要工作已经做完。
接下来setup程序开始执行。它做的第一件事情就是利用BIOS提供的中断服务程序从设备上提取内核运行所需要的机器系统数,其中包括光标位置、显示页面等数据,并分别从中断向量0x41和0x46向量值所指的内存地址处获取硬盘参数表。
到此为止,操作系统内核程序加载工作已完成。

3 为调用main函数做准备

之前操作系统是在16位实模式下工作的,接下来,操作系统要使计算机在32位保护模式下工作,这期间要做大量的重建工作,并且持续到操作系统的main函数执行,包括打开32位的寻址空间打开保护模式建立保护模式下的中断响应机制等于保护模式配套的相关工作、建立内存的分页机制,最后做好调用main函数的准备。

3.1 关中断并将system移动到内存地址起始位置0x00000

准备工作要先关闭中断,因为接下来的过程中,在main函数中能够适应保护模式的中断服务体系重建之前,系统都不应该收到中断源的影响。随后,setup程序将位于0x10000的内核程序复制到了内存地址起始位置0x00000处。这个复制动作将BIOS中断向量表和BIOS数据区完全覆盖,使它们不复存在,知道新的中断服务体系构建完毕之前,操作系统不再具备相应并处理中断的能力。

3.2 设置中断描述符表和全局描述符表

setup程序在完成3.1的步骤后,要通过自身的数据信息对中断描述符表寄存器(IDTR)和全局描述符表寄存器(GDTR)进行初始化设置。下面介绍有关的几个概念:
① GDT:全局描述符表(Global Descripter Table),在系统中唯一存放段寄存器内容的数组。可理解为所有进程的总目录表,其中存放每一个任务(task)局部描述符表(LDT)地址和任务状态段地址,完成进程中各段的寻址、现场保护与现场恢复。
② GDTR:GDT基地址寄存器(Global Descripter Table Register),保存GDT的起始地址
③ IDT:中断描述符表(Interrupt Descripter Table), 保存保护模式下所有中断服务程序的入口地址,类似于实模式下(1.2中)的中断向量表。
④ IDTR:IDT基地址寄存器(Interrupt Descripter Table Register),保存IDT的起始地址

3.3 打开A20,实现32位寻址

打开A20,以意味着CPU可以进行32位寻址,最大寻址空间为4GB。内存范围从0xFFFFF变到0xFFFFFFFF,从1MB变为4GB。地址线从20根变成了32根。

3.4 为保护模式下执行head.s做准备

为了建立保护模式下的中断机制,setup程序将对可编程中断控制器8259A进行重新编程。CPU在保护模式下,int 0x00~int 0x1F被Intel保留作为内部(不可屏蔽)中断和异常中断。如果不对8259A进行重新编程,int 0x00 ~ int 0x1F中断将被覆盖。
到这里,setup就执行完毕了。它为系统能够在保护模式下运行做一系列的准备工作。但这些准备工作还不够,后续的准备工作由head程序来完成。

3.5 执行head.s

在执行main函数之前,先要执行三个由汇编代码生成的程序,即bootsect,setup和head。之后才执行由main函数开始的C语言编写的操作系统内核程序。
根据前面的步骤,第一步,加载bootsect到0x7C00,然后复制到0x90000;第二步,加载setup到0x90200。这两段程序是分别加载,分别执行的。
head程序的加载方式是这样的:先将head.s汇编成目标代码,将用C语言编写的内核程序编译成目标代码,然后链接成system模块。也就是说,system模块里面既有内核程序,又有head程序,head程序在前,内核程序在后。所以head程序的名字为“head”。head程序在内存中占有25KB+184B的空间。根据3.1的内容,system模块加载到内存后,setup将system模块复制到0x00000位置,由于head程序在system的前面,所以实际上,head程序就在0x00000这个位置。head程序在内存中的分布示意图如下图所示:

head程序除了做一些调用main的准备工作之外,就是用程序自身的代码在程序所在的内存空间创建了内核分页机制,即在0x000000的位置创建了页目录表,页表,缓冲区,GDT,IDT,并将head程序已经执行过的代码所在的内存空间覆盖。这意味着head程序自己将自己废弃,main函数即将开始执行。

Linux内核(1)--从开机到main函数相关推荐

  1. linux 打印函数宏,linux内核中的嵌入式汇编宏函数

    在看linux内核代码时,常会遇到诸如:static inline _syscall0(int,fork)这样的函数.经查阅资料,发现该函数是嵌入式汇编宏函数. linux内核提供了7个非常有用的宏定 ...

  2. linux内核网络协议栈--发送流程及函数(十)

    本章会一步一步的分析,在linux内核中,数据是如何从网络中接收并最后到达应用程序的. 用户数据的发送流程如下图所示,不管是tfp,telnet,http都是类似的.当然我们在使用应用的时候,根本不会 ...

  3. linux内核申请内存的方法,Linux内核空间的内存申请常用函数

    在Linux内核编程中内存的申请不同于系统编程,她有自己的一套机制. 1. kmalloc 函数原型:void *kmalloc( size_t size, int flags ) 参数说明:size ...

  4. linux文件编程(3)—— main函数传参、myCp(配置成环境变量)、修改配置文件、整数和结构体数组写到文件

    参考:linux文件编程(3)-- 文件编程的简单应用:myCp.修改配置文件 作者:丶PURSUING 发布时间: 2021-04-09 23:45:05 网址:https://blog.csdn. ...

  5. 查看Linux内核启动时调用的init函数

    Linux内核引导加载后 会调用一些初始化函数 其中有很多模块化的代码使用do_initcalls调用 这些函数通过宏pure_initcall.core_initcall.subsys_initca ...

  6. linux 内核 fork,《Linux内核分析》之分析fork函数对应的系统调用处理过程

    实验过程 [toggle hide="yes" title="实验过程" color="#f50000"] 1.在实验楼中shell终端依次 ...

  7. linux内核网络协议栈--接收流程及函数(九)

    本章来看下,数据是如何从网络中接收并最后到达应用程序的. 网络层将数据链路层提供的帧组成数据包,包中封装有网络层包头,其中含有逻辑地址信息. 1.链路层 包到达机器的物理网卡时候触发一个中断,并将通过 ...

  8. linux中min函数用法,linux内核中的min、max函数

    这些天为了整理一下前段时间看ldd3时所学的驱动知识,所以就去看了看usb驱动.不看不知道,一看吓一跳,里面有很多语法我发现用的太好了,不像我们平时那样写代码.里面写的代码真是太好了.然而要理解到里面 ...

  9. linux内核开机显示企鹅logo,批改linux内核kernel开机logo(小企鹅)

    修改linux内核kernel开机logo(小企鹅) 修改linux内核kernel的开机图片(原为小企鹅图片). 转载请注明出处:http://blog.csdn.net/wang_zheng_ka ...

最新文章

  1. 微信拦截网站怎么办 微信屏蔽网址如何正常打开
  2. Python 图像处理 - 用PIL库提取图片中的颜色并展示为色谱实例演示,RGB颜色排序方法
  3. ALV 动态显示列Demo
  4. kali php 装mongodb,Linux系统如何安装mongodb数据库Mongo扩展
  5. 思科认证网络工程师CCNA(更新完毕)
  6. JAVA标识符命名规则及命名规范
  7. java 调用htm中js函数_Lua中调用C函数(lua5.2.3)
  8. echart 折线从左到右动画效果_echarts之自动切换折线图
  9. isecure center 综合安防管理平台_企业综合安全管理平台
  10. 中国风海报灵感|几款各具特色的汉字活动海报设计
  11. 业余学习python有用吗_对于那些不做编程工作的小伙伴来说,学习Python有什么用呢?...
  12. 一只青蛙一次可以_“七夕青蛙”被玩坏了,哈哈哈哈哈哈哈哈哈哈太好玩了
  13. UOS浏览器不支持NPAPI插件,怎么办?
  14. 类对象等式括号的意义
  15. Vue源码笔记之项目架构
  16. Win10小喇叭红叉叉显示未安装任何音频输出设备怎么解决?
  17. 【暑期每日一题】洛谷 P5708 【深基2.习2】三角形面积
  18. 50篇各种磨皮大法PS教程集合,想学磨皮方法的可以看看
  19. 二进制方式部署k8s集群1.21版本-域名形式
  20. 关于socket传输图片

热门文章

  1. linux文件类型缩写,常见Linux系统目录、文件类型、ls命令、alias命令
  2. fake_useragent.errors.FakeUserAgentError: Maximum amount of retries reached
  3. 渗透测试入门8之端口渗透
  4. this指向_前端面试之彻底搞懂this指向
  5. Android Studio 常用快捷键(超实用!!!)
  6. BZOJ4358: permu(带撤销并查集 不删除莫队)
  7. bzoj1925地精部落——数学
  8. struct数组初始化
  9. FastJSON、Gson和Jackson性能对比
  10. 朴素贝叶斯与贝叶斯网络