您的位置:首页 > 运维架构 > Linux

Linux源码分析笔记1 (bootsect.s文件分析)

2017-05-19 18:32 507 查看

linux0.11源码分析1 bootsect.s文件分析

从开机加电到执行main函数的过程

由于linux0.11系统当时存储在软盘上,所以其加电过程主要目的就是从启动盘加载操作系统程序,完成执行main函数的准备工作。

从开机到mian函数的启动共分三部分:

第一部分是启动bios,准备实模式下的中断向量表和中断服务程序。

第二部分是从启动盘加载操作系统到内存

第三部分为执行32位的main函数做过渡工作

第一部分

从硬件来看,Intel将所有的80x86系列的CPU的硬件都设计为加电进入16位实模式运行,加电后指向0xFFFF0位置

BIOS程序在内存最开始的位置用1kb的内存空间(0x00400~0x004FF)构建中断向量表。 在紧挨着的地方用256字节的内存空间构建BIOS数据区(0x00400~0x004FF),在56kb以后的位置(0x0E2CE)加载了8kb左右的中断向量表相应的中断服务程序。

第二部分

对于linux0.11系统而言,计算机分三批逐次加载操作系统的代码:

第一批由BIOS中断
int 0x19
把第一扇区bootsect的内容加载到内存。

第二批和第三批在 bootsect的指挥下,分别把其后的四个扇区和随后的240个扇区的内容加载至内存

对于
int 0x19
中断向量所指向的中断服务程序将软驱0号磁头对应盘面的0磁道1扇区的内容拷贝至内存0x07C00(这个地址属于DRAM区域)处。该磁道扇区存放的是bootsect的代码。

实模式下的最大寻址内存只有1MB,所以需要规划内存。

bootsect复制自身的操作代码如下:

entry start                                                                  !  表示程序的入口点
start:
mov ax,#BOOTSEG
mov ds,ax
mov ax,#INITSEG
mov es,ax
mov cx,#256
sub si,si
sub di,di
rep
movw
jmpi    go,INITSEG


首先,程序进入start这个入口点,然后将启动扇区被bios加载的位置(即BOOTSEG)进行存储在ds寄存器中,将要移动的新位置的地址(INITSEG)存入cx寄存器,下面的2条s
4000
ub指令是分别使其为0x0000,cx为256,并且操作是movw,说明是字复制操作,则总共移动512个字节。(这里需要了解movw这条指令的执行方式,见本人另一博客的笔记)

接下来执行的代码

jmpi    go,INITSEG
go: mov ax,cs
mov ds,ax
mov es,ax
! put stack at   0x9ff00
mov ss,ax
mov sp,#0xFF00      ! arbitrary value >>512


复制完毕后,执行jmpi指令,其意思是跳转到go:INITSEG, CS的值变为 INITSEG,IP的值变为从INITSEG到go:mov ax,cs的偏移。

然后将DS、ES、SS进行调整,把cs当前的值赋给他们,栈顶指针sp指向偏移地址为0xFF00处。 注意:SS和SP构成了栈数据在内存中的位置。

- 将setup程序加载进内存

需要借助BIOS提供的中断0x13中断指向的中断服务程序来完成。
int 0x13
把指定的扇区的代码加载到内存的指定位置。

int 0x13是直接磁盘服务,具体的参数和用法参考如此

代码如下:

mov dx,#0x0000      ! drive 0, head 0
mov cx,#0x0002      ! sector 2, track 0
mov bx,#0x0200      ! address = 512, in INITSEG                     存放偏移地址512
mov ax,#0x0200+SETUPLEN ! service 2, nr of sectors                      SETUPLEN是被加载的扇区数,对应参数AL
int 0x13            ! read it                                      指向的是磁盘服务程序,根据AH的值对应于02,是读扇区功能,AL是扇区数
jnc ok_load_setup       ! ok - continue                        如果cf标志为为0,则跳转
mov dx,#0x0000
mov ax,#0x0000      ! reset the diskette                            不为0则重置
int 0x13                                                         !  继续中断
j   load_setup                                                   !返回load_setup位置


前面4个mov是先对参数进行设置,注意第4个mov,给定了AH=02,表明是功能02H读扇区。AL是扇区数。

然后调用int 0x13中断,进入中断服务程序,读取将软盘从第二扇区开始的四个扇区加载至

ES:BX代表的是缓冲区地址,所以bx偏移量为512,es的值还是当前段。

加载第三部分代码

bootsect借着BIOS中断int 0x13,将240个扇区的system模块加载进内存 加载工作由bootsect调用read it子程序完成,这个子程序将软盘第6扇区开始的240个扇区的system模块加载进内存的SYSSEG(0x10000)处往后的120kb空间中。

代码如下:

ok_load_setup:
! Get disk drive parameters, specifically nr of sectors/track

mov dl,#0x00                                                              !DL=驱动器
mov ax,#0x0800      ! AH=8 is get drive parameters                          AH=08表示读取驱动器参数
int 0x13                                                              !中断13向量
mov ch,#0x00                                                         !ch=柱面
seg cs                                                                  !表示下一条指令将使用段超越
mov sectors,cx
mov ax,#INITSEG
mov es,ax

! Print some inane message

mov ah,#0x03        ! read cursor pos                             AH=03是入口参数,在文本坐标下,读取光标各种信息
xor bh,bh                                                        !bh是显示页码
int 0x10

mov cx,#24                                                     !CH为光标的起始行,CL为光标的终止行
mov bx,#0x0007      ! page 0, attribute 7 (normal)                  !bx是显示页面
mov bp,#msg1                                                        !ES:BP=显示字符串的地址,msg1在源码中该文件的最后面几行位置
mov ax,#0x1301      ! write string, move cursor                          !AH=13表示显示字符串,AL=1表示字符串只显含字符,显示后,光标位置改变。
int 0x10                                                                    !显示服务的中断,进行屏幕写操作


上述就进行了读取驱动器参数, 并且打印加载系统的文字信息。调用int 0x10中断。

接着,调用read_it函数进行读取扇区内容,代码如下:

read_it:
mov ax,es
test ax,#0x0fff             !测试ax中的某有位是否为0,如果为0,则ax为0,将zf置1,否则置0
die:    jne die         ! es must be at 64kB boundary    zf不等于0则跳转
xor bx,bx       ! bx is starting address within segment                     !异或指令
rp_read:
mov ax,es
cmp ax,#ENDSEG      ! have we loaded all yet?                  !对两数进行相减,进行比较
jb ok1_read                                         !判断2数大小
ret
ok1_read:
seg cs
mov ax,sectors
sub ax,sread
mov cx,ax
shl cx,#9
add cx,bx
jnc ok2_read
je ok2_read
xor ax,ax
sub ax,bx
shr ax,#9
ok2_read:
call read_track
mov cx,ax
add ax,sread
seg cs
cmp ax,sectors
jne ok3_read
mov ax,#1
sub ax,head
jne ok4_read
inc track
ok4_read:
mov head,ax
xor ax,ax
ok3_read:
mov sread,ax
shl cx,#9
add bx,cx
jnc rp_read
mov ax,es
add ax,#0x1000
mov es,ax
xor bx,bx
jmp rp_read


调用kill_motor函数

/*
* 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 dx
mov dx,#0x3f2
mov al,#0
outb
pop dx
ret


接下来还有一段代码是确定根文件系统号的。

通过执行
jmpi 0,SETUPSEG


将跳转到0x90200处,即setup程序加载的位置,CS:IP指向setup程序的第一条指令。

现在,整个bootsect程序的任务全部完成了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: