• linux kernel 0.11 bootsect


     

    bootsect作用

     

    ①将自己移动到0x90000处

     

    ②将setup从磁盘读到0x90200处

     

    ③将system从磁盘读到0x10000处

     

    寄存器

    汇编代码中存在:数据段data seg  栈段 stack seg 

    汇编代码中的寄存器概念:

    第一组:

      DS:数据段寄存器  ES:额外数据段寄存器

      SS:栈段寄存器   

      SI:源索引寄存器  DI:目的索引寄存器

      通常 DS:SI和ES:DI配对时通常用来执行一些数据段字符串操作.

      SI和DI两个寄存器叫做索引寄存器, 这两个寄存器通常用来处理数组或字符串.

    第二组:

      BP(base pointer), SP(Stack Pointer), 和IP(Instriction pointer)叫做指针寄存器.

      BP:基指针     SP:栈指针    IP:指令指针

      通常BP用来保存使用局部变量的地址.

      SP用来指向当前的栈. 尽管SP可以被很容易地修改, 你还是一定要非常小心. 因为如果这个寄存器搞错了, 你的程序就毁了.

      IP用来指示当前运行程序的当前指针. 通常和CS一起使用, IP是不允许修改的.

     中断

    系统中断分为BIOS中断和系统中断。所以就存在两个中断向量表。

    其中BIOS中断的int 0x13是磁盘I/O中断。

     

    汇编中的字符串操作

    (1) lodsb、lodsw:把DS:SI指向的存储单元中的数据装入AL或AX,然后根据DF标志增减SI(CLD递增, STD递减)
    (2) stosb、stosw:把AL或AX中的数据装入ES:DI指向的存储单元,然后根据DF标志增减DI(CLD递增, STD递减)
    (3) movsb、movsw:把DS:SI指向的存储单元中的数据装入ES:DI指向的存储单元中,然后根据DF标志分别增减SI和DI
    (4) scasb、scasw:把AL或AX中的数据与ES:DI指向的存储单元中的数据相减,影响标志位,然后根据DF标志分别增减SI和DI
    (5) cmpsb、cmpsw:把DS:SI指向的存储单元中的数据与ES:DI指向的存储单元中的数据相减,影响标志位,然后根据DF标志分别增减SI和DI
    (6) rep:重复其后的串操作指令。重复前先判断CX是否为0,为0就结束重复,否则CX减1,重复其后的串操作指令。 主要用在MOVS和STOS前。一般不用在LODS前。

      上述指令涉及的寄存器:段寄存器DS和ES、变址寄存器SI和DI、累加器AX、计数器CX
          涉及的标志位:DF、AF、CF、OF、PF、SF、ZF

    搬移字串指令有两种,分别是 MOVSB 和 MOVSW,先说 MOVSB。MOVSB 的英文是 move string byte,意思是搬移一个字节,它是把 DS:SI 所指地址的一个字节搬移到 ES:DI 所指的地址上,搬移后原来的内容不变,但是原来 ES:DI 所指的内容会被覆盖而且在搬移之后SI 和 DI 会自动地址向下一个要搬移的地址。

    一般而言,通常程序设计师一般并不会只搬一个字节,通常都会重复许多次,如果要重复的话,就得把重复次数 ( 也就是字串长度 ) 先记录在 CX 寄存器,并且在 MOVSB 之前加上 REP 指令,REP 是重复 (repeat) 的意思。这种写法很是奇怪,一般而言汇编语言源文件的每一行都只有一个指令,但 REP MOVSB 却可以在同一行写两个指令,当然分开写也是一样的。

    1、操作指令功能
       移动 movsb, movsw, movsd   从 ESI 指向的内存位置向 EDI 指向的内存位置拷贝数据  
       比较 cmpsb, cmpsw, cmpsd   把 ESI 指向内存位置的数据和 EDI 指向内存位置拷的数据比较(ESI,EDI都指向相匹配元素的后面的那个元素) 
       搜索 scasb, scasw, scasd   把 al/ax/eax 中的数据与 EDI 寻址的内存数据比较(EDI指向查找到的元素的后面的那个元素) 
       储存 stosb, stosw, stosd   把 al/ax/eax 中的数据保存在 EDI 寻址的内存单元  
       加载 lodsb, lodsw, lodsd   把 ESI 寻址的内存数据加载到 al/ax/eax 中

    2、重复执行前缀
       rep           当 ecx>0 时重复  
       repe, repz    当 ecx>0 ,且 ZF==1 时重复(只用在比较和搜索中)  
       repne,repnz   当 ecx>0 ,且 ZF==0 时重复(只用在比较和搜索中)
      
    3、重复执行方向
       cld    清除 DF 标志,ESI 和 EDI  递增  
       std    设置 DF 标志,ESI 和 EDI  递减
      
    4、字符操作指令格式
       方向               cld, std  
       数据来源             esi,al/ax/eax  
       数据目的             edi,al/ax/eax  
       循环次数             ecx  
       重复前缀 操作指令  rep, repe, repne  movsb, cmpsb, scasb, stosb, lodsb

    bootsect源代码注释

     

      1 !
      2 ! SYS_SIZE is the number of clicks (16 bytes) to be loaded.
      3 ! 0x3000 is 0x30000 bytes = 196kB, more than enough for current
      4 ! versions of linux
      5 !
      6 SYSSIZE = 0x3000            !system模块的大小
      7 !
      8 !    bootsect.s        (C) 1991 Linus Torvalds
      9 !
     10 ! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
     11 ! iself out of the way to address 0x90000, and jumps there.
     12 !
     13 ! It then loads 'setup' directly after itself (0x90200), and the system
     14 ! at 0x10000, using BIOS interrupts. 
     15 !
     16 ! NOTE! currently system is at most 8*65536 bytes long. This should be no
     17 ! problem, even in the future. I want to keep it simple. This 512 kB
     18 ! kernel size should be enough, especially as this doesn't contain the
     19 ! buffer cache as in minix
     20 !
     21 ! The loader has been made as simple as possible, and continuos
     22 ! read errors will result in a unbreakable loop. Reboot by hand. It
     23 ! loads pretty fast by getting whole sectors at a time whenever possible.
     24 
     25 .globl begtext, begdata, begbss, endtext, enddata, endbss    !全局标识符
     26 .text                        !文本段
     27 begtext:                
     28 .data                        !数据段
     29 begdata:                
     30 .bss                        !堆栈段
     31 begbss:
     32 .text
     33 
     34 SETUPLEN = 4                ! nr of setup-sectors    setup程序的扇区数
     35 BOOTSEG  = 0x07c0            ! original address of boot-sector    
     36 INITSEG  = 0x9000            ! we move boot here - out of the way
     37 SETUPSEG = 0x9020            ! setup starts here
     38 SYSSEG   = 0x1000            ! system loaded at 0x10000 (65536).
     39 ENDSEG   = SYSSEG + SYSSIZE        ! where to stop loading
     40                                                             !    从0x10000加载system模块,大小为
     41 ! ROOT_DEV:    0x000 - same type of floppy as boot.
     42 !        0x301 - first partition on first drive etc
     43 ROOT_DEV = 0x306                            !根文件系统的在第二盘第一分区上
     44 
     45 entry start                                        !连接程序从start处开始执行
     46 start:
     47                                                             ! 47--56 行作用是将自身(bootsect) 从目前段位置 0x07c0(31k)
     48                                                             ! 移动到 0x9000(576k)处,共 256 字(512 字节),然后跳转到
     49                                                           ! 移动后代码的 go 标号处,也即本程序的下一语句处。
     50     mov    ax,#BOOTSEG
     51     mov    ds,ax                                        !    ds=07c0
     52     mov    ax,#INITSEG
     53     mov    es,ax                                        !    es=9000
     54     mov    cx,#256                                    !    cx=256=bootsect大小
     55     sub    si,si
     56     sub    di,di
     57     rep                                                    !    rep movb或rep movw根据cx的值,重复执行串传送指令
     58     movw                                                !    movw,串传送指令,将ds:si指向的内存单元的字数据送入到es:di中,将si和di增2
     59     jmpi    go,INITSEG                        !    jmp是段内跳转指令,而jmpi是段间跳转指令,所以需要提供段地址(第二个操作数)。
     60                                                             !    即jmpi的第一个操作数是段内偏移地址;第二个是跳转到的段地址。
     61 go:    mov    ax,cs                                    !    CS存放指令的段地址,此时已经为9000,IP存放指令的偏移地址。
     62     mov    ds,ax                                        !    将ds    es    ss指向新的代码段
     63     mov    es,ax                                        !    因为程序设计堆栈操作,所以必须设置堆栈
     64 ! put stack at 0x9ff00.
     65     mov    ss,ax
     66     mov    sp,#0xFF00        ! arbitrary value >>512
     67                                                             ! ?
     68                                                             !    栈指针指向9ff00处,因为90200处放setup,setup大约占4个扇区
     69                                                             !    所以sp指向,(200+200*4+堆栈大小)之外
     70 ! load the setup-sectors directly after the bootblock.
     71 ! Note that 'es' is already set up.
     72 
     73 load_setup:                                        !    cs指令的段基址+ip就指向了这里。
     74                                                             ! 68--77 行的用途是利用 BIOS 中断 INT 0x13 将 setup 模块从磁盘第 2 个扇区  
     75                                                             ! 开始读到 0x90200 开始处,共读 4 个扇区。如果读出错,则复位驱动器,并    
     76                                                             ! 重试,没有退路。INT 0x13 的使用方法如下:                               
     77                                                             ! 读扇区:                                                                
     78                                                             ! ah = 0x02 - 读磁盘扇区到内存;al = 需要读出的扇区数量;                 
     79                                                             ! ch = 磁道(柱面)号的低 8 位; cl = 开始扇区(0-5 位),磁道号高 2 位(6-7);
     80                                                             ! dh = 磁头号; dl = 驱动器号(如果是硬盘则要置位 7);                   
     81                                                             ! es:bx 指向数据缓冲区; 如果出错则 CF 标志置位。 
     82                                                             !    INT 13h / AH = 02h - read disk sectors into memory.
     83                                                             !    input:
     84                                                             !    AL = number of sectors to read/write (must be nonzero)
     85                                                             !    CH = cylinder number (0..79).
     86                                                             !    CL = sector number (1..18).
     87                                                             !    DH = head number (0..1).
     88                                                             !    DL = drive number (0..3 , depends on quantity of FLOPPY_? files).
     89                                                             !    ES:BX points to data buffer.
     90                                                             !    return:
     91                                                             !    CF set on error.
     92                                                             !    CF clear if successful.
     93                                                             !    AH = status (0 - if successful).
     94                                                             !    AL = number of sectors transferred. 
     95                                                             !    Note: each sector has 512 bytes.  
     96                                                             !    将从0磁道第二2扇区开始,读取4个扇区的数据到ES:BX指定的内存中。                     
     97     mov    dx,#0x0000        ! drive 0, head 0                        dx=dl+dh
     98     mov    cx,#0x0002        ! sector 2, track 0                    cx=cl+ch
     99     mov    bx,#0x0200        ! address = 512, in INITSEG    es+bx=090200,
    100     mov    ax,#0x0200+SETUPLEN    ! service 2, nr of sectors    读磁盘的位置+读取的扇区数目
    101     int    0x13            ! read it            产生中断,AH为入口参数,将数据读入,读取完毕!加载setup完毕!
    102     jnc    ok_load_setup        ! ok - continue    跳转 有添加跳转,如果中断操作成功,则输出system loading....
    103     mov    dx,#0x0000            !    否则复位磁盘,重新读取setup模块
    104     mov    ax,#0x0000        ! reset the diskette    复位磁盘
    105     int    0x13
    106     j    load_setup            !    无条件跳转
    107 
    108 ok_load_setup:                                !?
    109 
    110 ! Get disk drive parameters, specifically nr of sectors/track
    111 
    112     mov    dl,#0x00
    113     mov    ax,#0x0800        ! AH=8 is get drive parameters
    114     int    0x13
    115     mov    ch,#0x00
    116     seg cs
    117     mov    sectors,cx
    118     mov    ax,#INITSEG
    119     mov    es,ax
    120 
    121 ! Print some inane message
    122 
    123     mov    ah,#0x03        ! read cursor pos
    124     xor    bh,bh
    125     int    0x10
    126     
    127     mov    cx,#24
    128     mov    bx,#0x0007        ! page 0, attribute 7 (normal)
    129     mov    bp,#msg1            !    显示加载system
    130     mov    ax,#0x1301        ! write string, move cursor
    131     int    0x10
    132 
    133 ! ok, we've written the message, now
    134 ! we want to load the system (at 0x10000)
    135 
    136     mov    ax,#SYSSEG
    137     mov    es,ax        ! segment of 0x010000
    138     call    read_it            !子程序调用,读取system,es为参数
    139     call    kill_motor
    140 
    141 ! After that we check which root-device to use. If the device is
    142 ! defined (!= 0), nothing is done and the given device is used.
    143 ! Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending
    144 ! on the number of sectors that the BIOS reports currently.
    145 
    146     seg cs
    147     mov    ax,root_dev
    148     cmp    ax,#0
    149     jne    root_defined
    150     seg cs
    151     mov    bx,sectors
    152     mov    ax,#0x0208        ! /dev/ps0 - 1.2Mb
    153     cmp    bx,#15
    154     je    root_defined
    155     mov    ax,#0x021c        ! /dev/PS0 - 1.44Mb
    156     cmp    bx,#18
    157     je    root_defined
    158 undef_root:
    159     jmp undef_root
    160 root_defined:
    161     seg cs
    162     mov    root_dev,ax
    163 
    164 ! after that (everyting loaded), we jump to
    165 ! the setup-routine loaded directly after
    166 ! the bootblock:
    167 
    168     jmpi    0,SETUPSEG
    169 
    170 ! This routine loads the system at address 0x10000, making sure
    171 ! no 64kB boundaries are crossed. We try to load it as fast as
    172 ! possible, loading whole tracks whenever we can.
    173 !
    174 ! in:    es - starting address segment (normally 0x1000)
    175 !
    176 sread:    .word 1+SETUPLEN    ! sectors read of current track    
    177                                                     !    开始读取system在磁盘的开始扇区标号
    178                                                     !    1:bootsect mbr主引导扇区
    179                                                     !    SETUPLEN:setup所占的扇区数
    180                                                     !sread:读取system开始的扇区数
    181 head:    .word 0            ! current head
    182 track:    .word 0            ! current track
    183 
    184 read_it:
    185     mov ax,es
    186     test ax,#0x0fff        !    0x1000&&0x0ffff
    187 die:    jne die            ! es must be at 64kB boundary    如果不在0x10000处,则进入死循环
    188     xor bx,bx        ! bx is starting address within segment
    189 rp_read:
    190     mov ax,es
    191     cmp ax,#ENDSEG        ! have we loaded all yet?
    192     jb ok1_read                !    如果未结束,继续读取
    193     ret
    194 ok1_read:
    195     seg cs                        !    不想使用默认的段地址寄存器,那么你可以强制指定一个段地址寄存器
    196     mov ax,sectors        !    读取磁道的扇区数
    197     sub ax,sread            !    减去已读的磁道扇区数
    198     mov cx,ax                    !    cx=未读的扇区数
    199     shl cx,#9                    !    逻辑左移指令    cx=cx*512
    200     add cx,bx                    
    201     jnc ok2_read
    202     je ok2_read
    203     xor ax,ax
    204     sub ax,bx
    205     shr ax,#9
    206 ok2_read:
    207     call read_track
    208     mov cx,ax
    209     add ax,sread
    210     seg cs
    211     cmp ax,sectors
    212     jne ok3_read
    213     mov ax,#1
    214     sub ax,head
    215     jne ok4_read
    216     inc track
    217 ok4_read:
    218     mov head,ax
    219     xor ax,ax
    220 ok3_read:
    221     mov sread,ax
    222     shl cx,#9
    223     add bx,cx
    224     jnc rp_read
    225     mov ax,es
    226     add ax,#0x1000
    227     mov es,ax
    228     xor bx,bx
    229     jmp rp_read
    230 
    231 read_track:
    232     push ax
    233     push bx
    234     push cx
    235     push dx
    236     mov dx,track
    237     mov cx,sread
    238     inc cx
    239     mov ch,dl
    240     mov dx,head
    241     mov dh,dl
    242     mov dl,#0
    243     and dx,#0x0100
    244     mov ah,#2
    245     int 0x13
    246     jc bad_rt
    247     pop dx
    248     pop cx
    249     pop bx
    250     pop ax
    251     ret
    252 bad_rt:    mov ax,#0
    253     mov dx,#0
    254     int 0x13
    255     pop dx
    256     pop cx
    257     pop bx
    258     pop ax
    259     jmp read_track
    260 
    261 !/*
    262 ! * This procedure turns off the floppy drive motor, so
    263 ! * that we enter the kernel in a known state, and
    264 ! * don't have to worry about it later.
    265 ! */
    266 kill_motor:
    267     push dx
    268     mov dx,#0x3f2
    269     mov al,#0
    270     outb
    271     pop dx
    272     ret
    273 
    274 sectors:
    275     .word 0
    276 
    277 msg1:
    278     .byte 13,10
    279     .ascii "Loading system ..."
    280     .byte 13,10,13,10
    281 
    282 .org 508
    283 root_dev:
    284     .word ROOT_DEV
    285 boot_flag:
    286     .word 0xAA55
    287 
    288 .text
    289 endtext:
    290 .data
    291 enddata:
    292 .bss
    293 endbss:
  • 相关阅读:
    iOS 适配iPhoneX上tableHeaderView发生了高度拉伸、UI出现的空白间距
    无线加密WEP、WPA、WPA2及TKIP、AES
    字符替换操作
    jQuery版本升级问题汇总
    ipv6服务器及环境搭建
    git删除某次提交操作
    五种IO模型
    jQuery1.6以上attr改用prop
    线程创建pthread_create用法(转)
    网络字节序与主机字节序
  • 原文地址:https://www.cnblogs.com/cz-blog/p/4752203.html
Copyright © 2020-2023  润新知