硬件开机

从硬件开机到系统启动,都经历了什么
BIOS做完计算机的初始化后,将会选择启动设备的第一个扇区进行加载,并将CPU控制权转移到
0x7C00的位置,将由Bootloader完成从实模式到保护模式的切换

bootsect.s

start

start就是Linux的bios启动程序入口,被加载到0x7c00处 给ds赋值BOOTSEG作为数据加载段,es为INITSEG作为代码拷贝处,使用rep汇编指令身内存拷贝到INITSEG,并跳转到INITSEG执行。

start:mov    ax,#BOOTSEGmov  ds,axmov    ax,#INITSEGmov  es,axmov    cx,#256sub  si,sisub    di,direpmovwjmpi    go,INITSEG

INITSEG

设置堆栈0x9ff00

go:  mov ax,csmov    ds,axmov    es,ax
! put stack at 0x9ff00.mov  ss,axmov    sp,#0xFF00      ! arbitrary value >>512

使用BIOS中断INT 13从磁盘第二个扇区加载setup

load_setup:
! ah = 0x02 - 读磁盘扇区到内存;al = 需要读出的扇区数量;
! ch = 磁道(柱面)号的低8 位; cl = 开始扇区(0-5 位),磁道号高2 位(6-7);
! dh = 磁头号; dl = 驱动器号(如果是硬盘则要置位7);
! es:bx ??指向数据缓冲区; 如果出错则CF 标志置位。mov  dx,#0x0000      ! drive 0, head 0mov    cx,#0x0002      ! sector 2, track 0mov  bx,#0x0200      ! address = 512, in INITSEGmov ax,#0x0200+SETUPLEN    ! service 2, nr of sectorsint   0x13            ! read itjnc    ok_load_setup       ! ok - continuemov  dx,#0x0000mov   ax,#0x0000      ! reset the disketteint 0x13j   load_setup

打印字符串(省略代码),验证读取的扇区并跳转到setup.s 程序的开始处,程序继续执行,bootsect.s职责完成。

 seg csmov   ax,root_devcmp  ax,#0jne    root_definedseg csmov   bx,sectorsmov   ax,#0x0208      ! /dev/ps0 - 1.2Mbcmp   bx,#15je    root_definedmov ax,#0x021c      ! /dev/PS0 - 1.44Mbcmp  bx,#18je    root_defined
undef_root:jmp undef_root
root_defined:seg csmov  root_dev,ax! after that (everyting loaded), we jump to
! the setup-routine loaded directly after
! the bootblock:jmpi    0,SETUPSEG

setup.s

setup负责从bios中读取数据并将它复制到系统内存中

start

...!获取扩展内存大小
mov ah,#0x88
int 0x15
mov [2],ax!获取显示卡的模式
mov ah,#0x0f
int 0x10
mov [4],bx      ! bh = display page
mov [6],ax      ! al = video mode, ah = window width!检查显示方式(EGA/VGA)并取参数。
mov ah,#0x12
mov bl,#0x10
int 0x10
mov [8],ax
mov [10],bx
mov [12],cx...

移动内存

将system移到正确的地方,把从0x10000 到0x8ffff移动到0x00000位置。

 mov ax,#0x0000cld           ! 'direction'=0, movs moves forward
do_move:mov es,ax       ! destination segmentadd    ax,#0x1000cmp   ax,#0x9000jz    end_movemov ds,ax       ! source segmentsub di,disub    si,simov    cx,#0x8000repmovswjmp   do_move

IDT,GDT

idt_48:
!描述表长度.word 0           ! idt limit=0
!描述表基地址.word    0,0         ! idt base=0Lgdt_48:
!段最大长度限制.word   0x800       ! gdt limit=2048, 256 GDT entries
!描述表基地址.word    512+gdt,0x9    ! gdt base = 0X9xxxx

将内存移动完成后,使用lidt 加载中断描述符寄存器(IDT)。lgdt加载全局描述符表

end_move:!恢复ax寄存器的SETUPSEG值mov    ax,#SETUPSEG    ! right, forgot this at first. didn't work :-)mov  ds,axlidt   idt_48      ! load idt with 0,0lgdt gdt_48      ! load gdt with whatever appropriate

保护模式

主要是通过修改CR0寄存器进入保护模式

段选择符长度为16位
位0-1表示请求的特权级0-3(0-3环)
位1-2标识是全局或者局部描述符
位3-15是描述符表项的索引
段8(0b0000,0000,0000,1000)
表示请求特权级0、使用全局描述符表中的第1 项,由下面的代码可知基地址是0

gdt:.word    0,0,0,0     ! dummy.word    0x07FF      ! 8Mb - limit=2047 (2048*4096=8Mb).word   0x0000      ! base address=0.word  0x9A00      ! code read/exec.word   0x00C0      ! granularity=4096, 386.word   0x07FF      ! 8Mb - limit=2047 (2048*4096=8Mb).word   0x0000      ! base address=0.word  0x9200      ! data read/write.word  0x00C0      ! granularity=4096, 386

lmsw修改cr0寄存器进入保护模式,然后跳转到cs段8 offset0处,执行system的代码

 mov ax,#0x0001  ! protected mode (PE) bitlmsw   ax      ! This is it!!跳转到cs段8 offset0处jmpi   0,8     ! jmp offset 0 of segment 8 (cs)

head.s

head.s是从绝对地址0x00000000开始

startup_32

startup_32:!装载段寄存器movl $0x10,%eaxmov %ax,%dsmov %ax,%esmov %ax,%fsmov %ax,%gs!设置系统堆栈lss _stack_start,%esp!装载idt,gdt子程序call setup_idtcall setup_gdtmovl $0x10,%eax      # reload all the segment registersmov %ax,%ds       # after changing gdt. CS was alreadymov %ax,%es     # reloaded in 'setup_gdt'mov %ax,%fsmov %ax,%gslss _stack_start,%esp!A20 地址线是否已经开启xorl %eax,%eax
1: incl %eax # check that A20 really IS enabledmovl %eax,0x000000 # loop forever if it isn'tcmpl %eax,0x100000je 1b...jmp after_page_tables

调用main函数

after_page_tables:pushl $0       # These are the parameters to main :-)pushl $0pushl $0pushl $L6!压入跳转的main地址pushl $_mainjmp setup_paging...!首先对5 页内存(1 页目录 + 4 页页表)清零movl $1024*5,%ecxxorl %eax,%eaxxorl %edi,%edicld;rep;stosl!设置页目录中的项movl $pg0+7,_pg_dirmovl $pg1+7,_pg_dir+4movl $pg2+7,_pg_dir+8movl $pg3+7,_pg_dir+12movl $pg3+4092,%edi!最后1 项对应物理内存页面的地址是0xfff000,加上属性标志7,即为0xfff007movl $0xfff007,%eaxstd
1:  stoslsubl $0x1000,%eaxjge 1bxorl %eax,%eax!设置启动使用分页处理(cr0 的PG 标志,位31)movl %eax,%cr3movl %cr0,%eaxorl $0x80000000,%eaxmovl %eax,%cr0!弹出压入的main地址,开始执行main.c程序ret

head.s执行完后的内存视图

关注我的技术公众号
不定期分析各种技术文章

(一)Linux源码分析-硬件开机与引导相关推荐

  1. linux源码分析之cpu初始化 kernel/head.s,linux源码分析之cpu初始化

    linux源码分析之cpu初始化 kernel/head.s 收藏 来自:http://blog.csdn.net/BoySKung/archive/2008/12/09/3486026.aspx l ...

  2. tcp/ip 协议栈Linux源码分析一 IPv4分片报文重组分析一

    内核版本:3.4.39 之前因工作原因接触到了IPv4 报文重组这个话题,一直以来对这个重组流程不是很清楚,所以很多功能的实现都避开了分片报文的处理,一方面是因为重组比较复杂,另一方面是经验不多无从下 ...

  3. tcp/ip 协议栈Linux源码分析五 IPv6分片报文重组分析一

    做防火墙模块的时候遇到过IPv6分片报文处理的问题是,当时的问题是netfilter无法基于传输层的端口拦截IPv6分片报文,但是IPv4的分片报文可以.分析了内核源码得知是因为netfilter的连 ...

  4. tcp/ip 协议栈Linux源码分析四 IPv4分片 ip_fragment函数分析

    内核版本:3.4.39 很多项目涉及到IP分片的时候都是绕过去了,感觉分片挺难的.但是老这么做也不行啊,抽空分析了内核的分片处理函数ip_fragment,也不是特别复杂,感觉挺简单的,看来事情只有实 ...

  5. (二)Linux源码分析-init

    main 功能 前面介绍了head.s将执行权交给main.c,内核初始化完成,现在开始进入C代码的分析了.Init主要是取得前面setup.s设置的根文件设备号和一下内存全局变量,初始化陷阱门,块设 ...

  6. 第一次作业:深入Linux源码分析进程模型

    一.进程的概念 第一,进程是一个实体.每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region).数据区域(data region)和堆栈(stack region).文本区域 ...

  7. linux 定时器_通过linux源码分析nodejs的keep-alive

    之前已经分析过了keep-alive,最近在使用nodejs的keep-alive的时候发现了遗漏了一个内容.本文进行一个补充说明.我们先看一下nodejs中keep-alive的使用. enable ...

  8. tcp/ip 协议栈Linux源码分析三 IPv4分片报文重组分析三

    继续上篇,上次讲到了分片队列的查找操作,剩下的就是分片队列插入和重组两个部分了,这个也是分片重组的关键部分. 将收到的分片插入到分片队列是由函数inet_frag_queue()函数完成,这个函数比较 ...

  9. tcp/ip 协议栈Linux源码分析二 IPv4分片报文重组分析二

    继续接着上篇讲,之前我们说过,收到分片报文后首先会检查分片报文所占内存是否过大,如果超过阈值的话就要调用ip_evictor函数去释放一些旧的分片队列,关于如何释放分片队列资源上一篇已经总结完成,接下 ...

最新文章

  1. MCSE2003学习之四
  2. python并且怎么表示_Python-如何在Python中表示“Enum”?
  3. 生产环境可以用吗_小型熔喷布设备可以生产出好的熔喷布吗?
  4. 地铁人多不多可在线查询了 高德地图率先在北京上线新功能
  5. Linux计划任务之_Crontab
  6. ❤️使用Spring注解开发(建议收藏)
  7. python中字符a如何变成b_python 如何把'a=b'这样的字符解析成dict类型
  8. mac免费CAD模型设计软件FreeCAD怎样设置中文模式
  9. ubuntu 下如何调节显卡风扇转速?
  10. linux系统显卡显存容量,Linux下检查显存大小
  11. 这篇文章有毒《持续更新中。。。》
  12. 人人开源搭建后台管理系统 逆向工程生成CRUD代码
  13. 【送豪礼】死了都要爱!不告白不痛快!
  14. react 购物车组件
  15. Rotating reference frame
  16. 【解题报告】博弈专场 (CF 2000~2200)前五题
  17. 那些著名的黑客事件 七
  18. 机器学习算法——神经网络5(ART 1网络)
  19. 【Linux】linux下删除/清空文件夹/文件命令
  20. 德国IT行业薪酬2019年终大盘点

热门文章

  1. 计算机毕业设计Java准妈妈孕期交流平台(源码+系统+mysql数据库+Lw文档)
  2. Java基础一到五章复习笔记
  3. Service后台服务控制音乐的播放暂停和停止,播放完自动播放下一曲
  4. 双流电子计算机学校,成都市计算机电子信息学校2021年招生简介
  5. 男人衬衫讲究雅致简单
  6. TCP的推送比特PSH Push
  7. Springboot 指定重发的次数和延迟时间,定时异步执行 重发任务
  8. EasyExcel-简介-01
  9. R语言 for循环和while循环
  10. UL线材表面印字有什么相关标准?