操作系统-哈工大笔记1
【操作系统基础笔记】(哈工大)
前言
笔记中的参考资料是哈工大OS慕课课程 这是关于操作系统的第一份笔记 相关资料也参考了网上其他人的写法 主要目的就是未来学习笔记所用 主要讲了操作系统内核启动中的bootset.s 希望大家批评指正
一、什么是操作系统
操作系统是底层计算机硬件与上层应用软件之间的一个软件,计算机的一切活动都是通过cpu、内存、显卡、显示器等硬件设备来实现的。
这里介绍一下相关概念:
中央处理器(CPU),是电子计算机的主要设备之一,电脑中的核心配件。其功能主要是解释计算机指令以及处理计算机软件中的数据。
CPU在执行指令时,通过代码寄存器CS和指令指针寄存器IP(instruction Pointer)来确定要执行的下一条指令的内存地址。 CS:IP 两个寄存器指示了CPU当前要赌气的指令地址,计算方式一般为CS左移4位然后加上IP寄存器,作为地址去取内容。
计算机的工作就是从磁盘取指令到内存,然后执行指令;即“取指执行”。
开机的一瞬间CS和IP的值是多少这个问题是由硬件决定的,对于X86的PC机来说,开机时, CS=0xFFFF; IP=0x0000;因此地址为0xFFFF0(ROM BIOS映射区),刚开机时,内存里面只有这个地方有数据,这部分程序的功能是:检查RAM、键盘、显示器等硬件(这部分数据是固化在内存里面的,只能读不能写)。然后将磁盘0磁道0扇区(一个扇区是512个字节)内容读入0x7c00处,磁盘的0磁道0扇区存储的就是操作系统的引导程序(即bootsect.s);同时设置CS=0x07c0,ip=0x0000,即开始执行操作系统。
二、操作系统流程
从机器加电开始执行顺序如上图所示
bootsect.s 和setup.s是实时模式下运行的16位代码程序,采用近似Intel语法,而head.s使用GUN汇编格式(AT&T),并且运行到保护模式下。
刚开机时候,CPU自动进入实模式,并从地址0XFFFF0开始执行程序代码,这个地址通常是ROM-BIOS中的地址,PC机的BIOS将执行某些系统检测,并在物理地址0处开始初始化中断向量。然后,它将可以启动设备的第一个扇区(磁盘引导扇区,512byte)读入内存绝对地址0x7C00处,并跳转到这个地方,启动设备通常是软驱或者硬盘。
Linux最前面部分(boot/bootsect.s),它将由BIOS读入内存绝对地址0x7C00处,当它被执行时就会把自己移动到内存绝对地址0X90000处,并把启动设备中后2kb字节代码(boot/setup.s)读入到内存0x90200处,而内核的其他部分(system模块)则被读入到内存地址0x10000开始处
setup.s将会把system模块移动到物理内存起始位置处,这样system模块中代码的地址就等于实际的物理地址,便于对内核代码和数据操作。
整个系统从地址0x10000移至0x0000处,进入保护模式并跳转至系统的余下部分(在0x0000chu)。此时所有的32位运行方式的设置启动被完成:IDT,GDT和LDT被加载,处理器和协处理器也确认,分页工作也设置完成。
最终调用init/main.c中main()程序
三、内核启动
1.bootsect.s
引导扇区代码:bootsect.s
操作系统引导程序文件名是:bootsect.s,为什么不是bootsect.c呢?.s说明是汇编程序,.c是c程序,操作系统在刚刚启动的时候每一条指令都是严格要求的,不能有任何的出入,汇编程序和机器指令是一一对应的;但是c程序就不一样,比如:int a;a这个变量的地址就是随机的,所以不能是.c。
bootsect.s代码是磁盘引导块程序,驻留在磁盘的第一个扇区中(引导扇区,0磁道(柱面),0磁头,第一个扇区)
在PC机加电ROM BIOS自检后,ROM BIOS会把引导扇区代码bootsect加载到内存地址0x7C00开始处并执行之。在bootsect代码执行期间,它会将自己移动到内存绝对地址0x90000开始处并继续执行。
该程序的主要作用是首先把从磁盘第2个扇区开始的4个扇区的setup模块(由 setupo.s编译而成)加载到内存紧接着bootsect后面位置处(0x90200),然后利用BIOS中断 0x13 ,取磁盘参数表中当前启动引导盘的参数,接着在屏幕上显示“Loading system.”字符串。
再把磁盘上setup模块后面的system模块加载到内存0x10000开始的地方。随后确定根文件系统的设备号,若没有指定,则根据所保存的引导盘的每磁道扇区数判别出盘的类型和种类并保存其设备号于 root_dev(
引导块的508地址处),最后长跳转到setup程序的开始处(0x00200)执行sctup程序。
BOOTSEG = 0x07c0
INITSEG = 0x9000
SETUPSEG = 0x9020
; bootsect启动程序将它自身从内容0x07c00(BOOTSEG)处复制至内存0x9000(INITSEG)处
entry start ;关键字entry告诉链接器"程序入口"
start:
mov ax,#BOOTSEG ;BOOTSEG = 0x7c00 赋值给ax,
mov ds,ax ;源地址
mov ax,#INITSEG ;INITSEG = 0x9000 赋值给bx
mov es,ax ;目标地址
mov cx,#256 ;循环次数,每次循环完次数减一
sub si,si ;清零
sub di,di ;清零
rep movw ; 表示移动字,移动的个数是cx=256,也就是512个字节,也就是说这段代码的作用就是将从0x07c00地址处开始的512个字节移动到0x90000处
jmpi go,INITSEG ; 这条指令是间接跳转,go->ip,INITSEG->CS,前面已经说了INITSEG就是0x9000,go是一个标号,go表示的是距离start的偏移,现在因为已经将0x07c00处的512个字节移动到了0x90000处,所以go相较于start的偏移其实也就是相较于INITSEG的偏移,所以也就是顺序执行。
; 从这里开始cpu已经跳到内存0x90000去执行,
; BIOS把引导扇区加载到0x7c00处并把执行权交给引导程序,(ss=0x00,sp=0xfffe)
; 将ds,es,ss,都设置成移动后代码所在段(0x9000)
go: mov ax,cs ;ax = cs = INITSEG = 0x9000
mov ds,ax ;数据段地址
mov es,ax ;附加段地址
! put stack at 0x9ff00. ;将堆栈指针sp指向0x9fff00(0x9000:0xff00)
mov ss,ax ;栈段地址
; 保证栈指针sp只要指向远大于512byte字节偏移(即地址0x90200)
; 因为在0x90200后要存放setup程序,大约为4个扇区 sp指向大于(0x200+0x200*4+堆栈大小)
mov sp,#0xFF00 ! arbitrary value >>512
! load the setup-sectors directly after the bootblock.
; 在bootsect程序紧跟着加载setup程序
! Note that 'es' is already set up.
; es在移动代码时设置好了指向目的地址0x9000
;0x13是BIOS读磁盘扇区的中断: ah=0x02(读磁盘),al=扇区数量(SETUPLEN=4),
ch=柱面号,cl=开始扇区,dh=磁头号,dl=驱动器号,es:bx=内存地址
load_setup: //载入setup模块
mov dx,#0x0000 mov cx,#0x0002 mov bx,#0x0200
mov ax,#0x0200+SETUPLEN int 0x13 //BIOS中断
jnc ok_load_setup
mov dx,#0x0000
mov ax,#0x0000 //复位
int 0x13
j load_setup //重读
到目前为止,只有bootsect.s的一个扇区被读进内存了,其他的还没有读进去,因此其他内容使用
int 0x13 号中断读进去。
开始扇区cl:02;扇区数:al:4;就是说从第二个扇区开始读4个扇区到内存,
ip的值为 es:bx ;es:0x9000;bx:0x0200;也就是说从0x90200开始;对的,因为bootsect是512个字节。512用十六进制表示就是200。所以,load_setup: 的功能就是将setup读进内存,紧接着bootsect后面
ok_load_setup:
! Get disk drive parameters, specifically nr of sectors/track
; 取磁盘驱动器的参数,特别是每道的扇区数量
; 取磁盘驱动器的参数 INT 0x13调用格式和返回信息:
; 调用格式:
; ah = 0x08 dl = 驱动器号(如果是硬盘则位7要置位)
; 返回信息:
; 如果出错,则CF值位,并且ah = 状态码
; ah = 0, al = 0 bl = 驱动器类型(AT/PS2)
; ch = 磁道(柱面)号低8位
; cl = 开始扇区(位0-5),磁道号高两位(位6-7)
; dh = 最大磁头数 , dl = 驱动器数量
; es:di--->软驱磁盘参数表
mov dl,#0x00
mov ax,#0x0800 ! AH=8 is get drive parameters
int 0x13
mov ch,#0x00
; 这条指令表示下一条指令的操作数在cs段寄存器所指的段中
seg cs
; 保持每磁道扇区数 (cx = 每磁道扇区数)
mov sectors,cx
mov ax,#INITSEG
; 由于上面取磁道参数中断改掉了es的值,这里重新复制,
mov es,ax
msg1:.byte 13,10
.ascii “Loading system...”
.byte 13,10,13,10
因此就是在屏幕上显示 “loading system…”, cx 是表示显示的字符数量(字节),bx 是显示属性。具体这些东西可以自己百度。
后面的 read_it 还是读操作系统到内存里面。然后bootsect.s结束。因此bootsect.s的功能就是将操作系统读入内存。
并且显示logo:”loading system…”。bootsect到此结束。
bootsect.s的小总结
bootsect.s是操作系统的最开始部分,共512个字节,在磁盘的0磁道0扇区位置,首先内存里面肯定是有代码的,具体存在哪个位置是由硬件决定的,然后从那个位置开始读入操作系统,首先读入的是操作系统的bootsect部分,对于x86PC来说,bootsect读进来是放在0x07c00这个位置,然后将其转移到0x90000这个位置,并继续执行;利用int 0x13中断,将操作系统的setup读入到0x90200开始的内存处,setup在磁盘上是第二到第五个扇区,第一个是bootsect扇区;读入setup之后,bootsect继续执行,在屏幕上显示开机logo “loading system…”。然后进入 read_it 继续读操作系统模块,然后将控制权转移到setup中,执行setup中的内容。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)