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

来源:互联网 发布:易语言取网页源码乱码 编辑:程序博客网 时间:2024/05/18 02:04

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系统而言,计算机分三批逐次加载操作系统的代码:

    1. 第一批由BIOS中断int 0x19把第一扇区bootsect的内容加载到内存。
    2. 第二批和第三批在 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                                                             movwjmpi    go,INITSEG  

    首先,程序进入start这个入口点,然后将启动扇区被bios加载的位置(即BOOTSEG)进行存储在ds寄存器中,将要移动的新位置的地址(INITSEG)存入cx寄存器,下面的2条sub指令是分别使其为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是被加载的扇区数,对应参数ALint 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,#INITSEGmov es,ax! Print some inane message                          mov ah,#0x03        ! read cursor pos                             AH=03是入口参数,在文本坐标下,读取光标各种信息xor bh,bh                                                        !bh是显示页码int 0x10mov 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,否则置0die:    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数大小    retok1_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,#9ok2_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 trackok4_read:    mov head,ax    xor ax,axok3_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程序的任务全部完成了