Linux0.11内核源码解析-bootsect.s
学习资料:
Linux内核完全注释
操作系统真像还原
极客时间-Linux内核源码趣读
Linux0.11内核源码
->上电
->80x86架构CPU会自动进入实模式
->从地址0xffff0自动执行程序代码
->bios执行系统检测,从物理地址0初始化中断向量,将第一个引导扇区512字节读入内存绝对地址0x7c00(BIOS把512字节的二进制数据从硬盘搬到内存中,作为操作系统的开发人员,我们只需要把代码放到0盘0磁道1扇区即可,对应的代码是bootsect.s)
->跳转到0x7c00(31KB)
->0x7c00当被执行的时候会把自己搬到0x90000(576KB)处,并把启动设备中后2KB代码(setup.s)读到0x90200处
# ROOT_DEV: 0x000 - same type of floppy as boot. 根文件系统设备使用与引导同样的软驱设备
# 0x301 - first partition on first drive etc 根文件系统设备在第一个硬盘的第一个分区上
# 0x300 /dev/hd0
# 0x301 /dev/hd1
# ...
# 0x304 /dev/hd4
# 0x305 /dev/hd5 第二个硬盘
# 0x306 /dev/hd6 第二个硬盘第一个分区.equ ROOT_DEV, 0x301 ljmp $BOOTSEG, $_start_start: # ds = 0x07c0mov $BOOTSEG, %axmov %ax, %ds# es = 0x9000mov $INITSEG, %axmov %ax, %es# move 256 word from 0x7c00(DS:SI) to 0x9000(ES:DI)#ds:si=0x07c0:0x0000#es:di=0x9000:0x0000mov $256, %cxsub %si, %sisub %di, %direp movsw#间接跳转0x9000ljmp $INITSEG, $go# 代码段移动后,重新设置堆栈段
go: mov %cs, %axmov %ax, %dsmov %ax, %es
# put stack at 0x9ff00.# cs=0x9000 ss=0x9000 sp=0xff00mov %ax, %ssmov $0xFF00, %sp # arbitrary value >>512
int 0x13
功能02H
功能描述:读扇区
入口参数:AH=02H
AL=扇区数
CH=柱面
CL=扇区
DH=磁头
DL=驱动器,00H~7FH:软盘;80H~0FFH:硬盘
ES:BX=缓冲区的地址
功能00H
功能描述:磁盘系统复位
入口参数:AH=00H
DL=驱动器,00H~7FH:软盘;80H~0FFH:硬盘
出口参数:CF=0——操作成功,AH=00H,否则,AH=状态代码,参见功能号01H中的说明
load_setup:mov $0x0000, %dx # drive 0, head 0mov $0x0002, %cx # from sector 2, track 0mov $0x0200, %bx # address = 512, in INITSEG.equ AX, 0x0200+4 # read 4 sector mov $AX, %ax # service 2, nr of sectorsint $0x13 # read itjnc ok_load_setup # ok - continuemov $0x0000, %dxmov $0x0000, %ax # reset the disketteint $0x13jmp load_setup
功能08H
功能描述:读取驱动器参数
入口参数:AH=08H
DL=驱动器,00H~7FH:软盘;80H~0FFH:硬盘
出口参数:CF=1——操作失败,AH=状态代码,参见功能号01H中的说明,否则, BL=01H — 360K
=02H — 1.2M
=03H — 720K
=04H — 1.44M
CH=柱面数的低8位
CL的位7-6=柱面数的该2位
CL的位5-0=扇区数
DH=磁头数
DL=驱动器数
ES:DI=磁盘驱动器参数表地址
ok_load_setup:# Get disk drive parameters, specifically nr of sectors/trackmov $0x00, %dlmov $0x0800, %ax # AH=8 is get drive parametersint $0x13mov $0x00, %ch#seg csmov %cx, %cs:sectors+0 # %cs means sectors is in %cs 保存磁道扇区数mov $INITSEG, %axmov %ax, %es #磁盘参数中断改掉了es的值,恢复es寄存器
# 后续装载系统模块需要装载240个扇区,是之前装载扇区数量的60倍,在此处显示一条信息提示用户等待
# Print some inane messagemov $0x03, %ah # read cursor posxor %bh, %bhint $0x10mov $24, %cxmov $0x0007, %bx # page 0, attribute 7 (normal)#lea msg1, %bpmov $msg1, %bpmov $0x1301, %ax # write string, move cursorint $0x10
把system 240个扇区拷贝到0x10000,关闭软驱电机
# ok, we've written the message, now
# we want to load the system (at 0x10000)mov $SYSSEG, %axmov %ax, %es # segment of 0x010000call read_itcall kill_motor
检查要使用哪个根文件系统设备,如果指定了设备!=0,就直接使用指定设备,否则根据BIOS报告的磁道扇区数来确定是用那个设备
跳转setup.s 0x90200
# After that we check which root-device to use. If the device is
# defined (#= 0), nothing is done and the given device is used.
# Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending
# on the number of sectors that the BIOS reports currently.#seg csmov %cs:root_dev+0, %ax # Root Device根文件系统设备cmp $0, %ax # 判断根设备号是否为0jne root_defined # ZF = 0时跳转,即ax不为0时,即根设备已设置#seg cs
# 根设备未设置mov %cs:sectors+0, %bx mov $0x0208, %ax # /dev/ps0 - 1.2Mbcmp $15, %bx # 取上面获取到每磁道扇区数,如果sectors=15则说明是1.2Mb的驱动器je root_definedmov $0x021c, %ax # /dev/PS0 - 1.44Mbcmp $18, %bx # 取上面获取到每磁道扇区数,如果sectors=18则说明是1.44Mb的软驱je root_defined
undef_root: # down机jmp undef_root
root_defined:#seg csmov %ax, %cs:root_dev+0# after that (everyting loaded), we jump to
# the setup-routine loaded directly after
# the bootblock:ljmp $SETUPSEG, $0
如果ES在64k,0x1000边界上,就立刻停止
# This routine loads the system at address 0x10000, making sure
# no 64kB boundaries are crossed. We try to load it as fast as
# possible, loading whole tracks whenever we can.
#
# in: es - starting address segment (normally 0x1000)
#
sread: .word 1+ SETUPLEN # sectors read of current track
head: .word 0 # current head
track: .word 0 # current trackread_it:mov %es, %axtest $0x0fff, %ax # TEST指令按位进行逻辑与运算,与AND指令的区别是两个操作数不会被改变
die: jne die # es must be at 64kB boundaryxor %bx, %bx # bx is starting address within segmentrp_read:mov %es, %axcmp $ENDSEG, %ax # have we loaded all yet?jb ok1_readret# 计算和验证当前磁道需要读取的扇区数,放在ax寄存器中,根据当前磁道未读取的扇区数以及段内数据字节开始偏移位置,
# 计算如果全部读取这些未读扇区,所读总字节数是否超过64KB段长度的限制,若会超过,则根据此次最多读入的字节数(64KB-段内偏移位置),反算出此次需要读取的扇区数
ok1_read:#seg csmov %cs:sectors+0, %ax # 获取磁道扇区数sub sread, %ax # 减去当前磁道已读扇区数mov %ax, %cx # cx = ax = 当前磁道未读扇区数shl $9, %cx # cx = cx * 512add %bx, %cx # cx = cx + bx段内当前偏移值jnc ok2_read # 没有超过64KB字节,则跳转ok2_readje ok2_readxor %ax, %ax # 加上此次将读磁道上所有未读扇区时会超过64KBsub %bx, %ax # 此时最多能读入字节数(64KB-段内读偏移位置),再转换shr $9, %ax # 读取扇区数ok2_read:call read_trackmov %ax, %cx # 该次操作已读扇区数add sread, %ax # 当前磁道上已经读取的扇区数#seg cscmp %cs:sectors+0, %ax # 如果当前磁道上的还有扇区未读,则跳转到ok3_readjne ok3_read # 读该磁道的下一磁头面上的数据,如果已经完成,则去读下一磁道mov $1, %axsub head, %ax # 判断当前磁头号jne ok4_read # 如果是0磁头号,则再去读1磁头面上的扇区数据incw track # 否则去读下一磁道ok4_read:mov %ax, head # 保存当前磁头号xor %ax, %ax # 清当前磁道已读扇区数ok3_read:mov %ax, sread # 保存当前磁道已读扇区shl $9, %cx # 上次已读扇区数*512字节add %cx, %bx # 调整当前段数据开始位置jnc rp_read # 小于64KB边界值,则跳转到rp_read,继续读数据mov %es, %ax # 否则调整当前段,为读下一段数据作准备add $0x1000, %ax # 将段基址指向为下一个64KB内存开始处mov %ax, %esxor %bx, %bx # 清段内数据开始偏移值jmp rp_read# 读当前磁道上指定开始扇区和需读扇区数的数据到es:bx,参见第67行下对BIOS磁盘读中断
# int 0x13, ah=2
# al 需读扇区数;es:bx 缓冲区开始位置
read_track:push %axpush %bxpush %cxpush %dxmov track, %dx # 取当前磁道mov sread, %cx # 取当前磁道上已读扇区数inc %cx # cl开始读扇区mov %dl, %ch # ch当前磁道号mov head, %dx # 取当前磁头号mov %dl, %dh # dh 磁头号mov $0, %dl # dl 磁动器号,0表示当前A驱动器and $0x0100, %dx # 磁头号大于1mov $2, %ah # ah = 2,读磁盘扇区功能号int $0x13jc bad_rt # 出错则跳转bad_rtpop %dxpop %cxpop %bxpop %axret# 执行驱动器复位操作,再跳转到read_track重试
bad_rt: mov $0, %axmov $0, %dxint $0x13pop %dxpop %cxpop %bxpop %axjmp read_track#/*
# * This procedure turns off the floppy drive motor, so
# * that we enter the kernel in a known state, and
# * don't have to worry about it later.
# */
kill_motor:push %dxmov $0x3f2, %dxmov $0, %aloutsbpop %dxretsectors:.word 0msg1:.byte 13,10.ascii "Loading system ...".byte 13,10,13,10.org 508
root_dev:.word ROOT_DEV
boot_flag:.word 0xAA55
1. 把 bootsect.s 编译成 bootsect 放在硬盘的 1 扇区;2. 把 setup.s 编译成 setup 放在硬盘的 2~5 扇区;3. 把剩下的全部代码(head.s 作为开头,与各种 .c 和其他 .s 等文件一起)编译并链接成 system,放在硬盘的随后 240 个扇区
为什么不把系统模块直接加载到物理地址0x0000处运行,而要在setup中进行移动,这是因为setup程序代码开始部分需要利用BIOS的中断获取机器的一些参数,BIOS初始化的时候会在物理内存开始处放置大小为0x400字节(1kb)的中断向量表,因此需要在BIOS中断调用后才能将这个区域覆盖掉。
Linux0.11内核源码解析-bootsect.s相关推荐
- Linux0.11内核源码解析-setup.s
学习资料: Linux内核完全注释 操作系统真像还原 极客时间-Linux内核源码趣读 Linux0.11内核源码 ->setup程序将system模块从0x10000~0x8ffff整块向下移 ...
- Linux0.11内核源码解析01
系统整体布局 第一部分:进入内核前的苦力活 第二部分:大战前期的初始化工作 第三部分:一个新进程的诞生 第四部分:shell 程序的到来 第五部分:从一个命令的执行看操作系统各模块的运作 第六部分:操 ...
- linux-0.11 内核源码学习笔记一(嵌入式汇编语法及使用)
linux内核源码虽然是用C写的,不过其中有很多用嵌入式汇编直接操作底层硬件的"宏函数",要想顺利的理解内核理论和具体实现逻辑,学会看嵌入式汇编是必修课,下面内容是学习过程中的笔记 ...
- Linux0.11内核源码分析(bootsect.s)
Intel 80x86系列的CPU可以分别在16位实模式和32位保护模式下运行.为了兼容,也为了解决最开始的启动问题,Intel将所有80x86系列的CPU,包括最新型号的CPU的硬件都设计为加电即进 ...
- Linux0.11内核源码分析1-main函数运行之前的准备
在阅读该文章之前,你起码有点操作系统的知识,了解实模式与保护模式的概念,了解分段机制,如果不懂得建议去阅读<操纵系统真象还原>这本书
- 小米9开源linux内核,发布即开源:小米开源新机Mi 11内核源码
小米已开源最近发布的新机小米 11 的源码,小米 11 系统内核基于 Android R,源码已更新至小米手机内核的 GitHub 仓库,代号为 venus-r-oss. 由于 Android 系统是 ...
- linux0.11操作系统源码剖析fork.c
fork() 用于创建 一个新的进程,一次调用两次返回.父进程返回子进程的PID 子进程是 0. fork() 采用写时复制,也就是 创建的时候 就复制了页表,并没有实际的内存空间,子进程这个时候和父 ...
- 关于互斥锁,条件变量的内核源码解析
一.解决问题和适用范围 主要是用来等待一个条件,这个条件可能需要另一个线程来满足这个条件.这个和我们平常适用的pthread_mutex_lock的最大不同在于后者保护的一般是一个代码段(也就是关键区 ...
- 视频教程-YOLOv3目标检测:原理与源码解析-计算机视觉
YOLOv3目标检测:原理与源码解析 大学教授,美国归国博士.博士生导师:人工智能公司专家顾问:长期从事人工智能.物联网.大数据研究:已发表学术论文100多篇,授权发明专利10多项 白勇 ¥78.00 ...
最新文章
- 简单的Linux扫描仪应用:C语言实现
- 在线生成 CSS3 的工具
- oracle domnode释放,关于释放引用DOM对象内存的问题
- 【小松教你手游开发】【面试必读(编程基础)】几种常用的设计模式介绍
- Mac 效率工具必备神器 —— Alfred
- 剑指Offer系列刷题笔记汇总
- 高通QMI_WWAN驱动详解
- 这个编辑器居然号称快如闪电!
- 男主龙失忆java_男主失忆的小说推荐:我忘了全世界,却记得对你的爱,一生不变...
- CSS代码缩写,占用更少的带宽/字体缩写/盒模型代码简写/颜色值缩写
- prefetch()
- 计算机财务管理知识点,财务管理知识点梳理(财务基础必背知识点整理篇)
- 自由复制360doc个人图书馆的文档
- 什么是脚本语言?什么是解释性语言?什么是编译性语言?
- Python全国二级等级考试(2019)
- Spring之——c3p0配置详解
- java计算机毕业设计驴友社区网站录屏源程序+mysql+系统+lw文档+远程调试
- abaqus无法定位html文档集,Abaqus:一种定位外部节点的方法?
- linux指令_齐南汕
- project 2010