zoukankan      html  css  js  c++  java
  • 09 主引导程序控制权的转移

     

    参考

    https://www.cnblogs.com/wanmeishenghuo/tag/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/

    https://blog.51cto.com/13475106/category6.html

    这一节,我们来真正的读取文件中的内容到内存中,首先来看一下内存布局是什么样的,如下所示:

      Boot占用了512字节,Fat Table占用了4KB,而真正的文件中的内容,我们把它存在0x9000开始的内存地址处。

      加载文件内容的过程如下:

      实验步骤如下:

      1、在虚拟软盘中创建体积较大的文本文件,使之内容大小超过一个扇区。

      2、将文件的内容加载到BaseOfLoader地址处。

      3、打印加载的内容,判断是否加载完全。

    org 0x7c00
    
    jmp short start
    nop
    
    define:
        BaseOfStack      equ 0x7c00
        BaseOfLoader     equ 0x9000
        RootEntryOffset  equ 19
        RootEntryLength  equ 14
        EntryItemLength  equ 32
        FatEntryOffset   equ 1
        FatEntryLength   equ 9
    
    header:
        BS_OEMName     db "D.T.Soft"
        BPB_BytsPerSec dw 512
        BPB_SecPerClus db 1
        BPB_RsvdSecCnt dw 1
        BPB_NumFATs    db 2
        BPB_RootEntCnt dw 224
        BPB_TotSec16   dw 2880
        BPB_Media      db 0xF0
        BPB_FATSz16    dw 9
        BPB_SecPerTrk  dw 18
        BPB_NumHeads   dw 2
        BPB_HiddSec    dd 0
        BPB_TotSec32   dd 0
        BS_DrvNum      db 0
        BS_Reserved1   db 0
        BS_BootSig     db 0x29
        BS_VolID       dd 0
        BS_VolLab      db "D.T.OS-0.01"
        BS_FileSysType db "FAT12   "
    
    start:
        mov ax, cs
        mov ss, ax
        mov ds, ax
        mov es, ax
        mov sp, BaseOfStack
    
        mov ax, RootEntryOffset
        mov cx, RootEntryLength
        mov bx, Buf
    
        call ReadSector
    
        mov si, Target
        mov cx, TarLen
        mov dx, 0
    
        call FindEntry
    
        cmp dx, 0
        jz output
    
        mov si, bx
        mov di, EntryItem
        mov cx, EntryItemLength
    
        call MemCpy
    
        mov ax, FatEntryLength
        mov cx, [BPB_BytsPerSec]
        mul cx
        mov bx, BaseOfLoader
        sub bx, ax
    
        mov ax, FatEntryOffset
        mov cx, FatEntryLength
    
        call ReadSector
    
        mov dx, [EntryItem + 0x1A]
        mov si, BaseOfLoader
    
    loading:
        mov ax, dx
        add ax, 31
        mov cx, 1
        push dx
        push bx
        mov bx, si
        call ReadSector
        pop bx
        pop cx
        call FatVec
        cmp dx, 0xFF7
        jnb output
        add si, 512
        jmp loading
    
    output:
        mov bp, BaseOfLoader
        mov cx, [EntryItem + 0x1C]
        call Print
    
    last:
        hlt
        jmp last
    
    
    ; cx --> index
    ; bx --> fat table address
    ;
    ; return:
    ;     dx --> fat[index]
    FatVec:
        mov ax, cx
        mov cl, 2
        div cl
    
        push ax
    
        mov ah, 0
        mov cx, 3
        mul cx
        mov cx, ax
    
        pop ax
    
        cmp ah, 0
        jz even
        jmp odd
    
    even:    ; FatVec[j] = ( (Fat[i+1] & 0x0F) << 8 ) | Fat[i];
        mov dx, cx
        add dx, 1
        add dx, bx
        mov bp, dx
        mov dl, byte [bp]
        and dl, 0x0F
        shl dx, 8
        add cx, bx
        mov bp, cx
        or  dl, byte [bp]
        jmp return
    
    odd:     ; FatVec[j+1] = (Fat[i+2] << 4) | ( (Fat[i+1] >> 4) & 0x0F );
        mov dx, cx
        add dx, 2
        add dx, bx
        mov bp, dx
        mov dl, byte [bp]
        mov dh, 0
        shl dx, 4
        add cx, 1
        add cx, bx
        mov bp, cx
        mov cl, byte [bp]
        shr cl, 4
        and cl, 0x0F
        mov ch, 0
        or  dx, cx
    
    return:
        ret
    
    ; ds:si --> source
    ; es:di --> destination
    ; cx    --> length
    MemCpy:
    
        cmp si, di
    
        ja btoe
    
        add si, cx
        add di, cx
        dec si
        dec di
    
        jmp etob
    
    btoe:
        cmp cx, 0
        jz done
        mov al, [si]
        mov byte [di], al
        inc si
        inc di
        dec cx
        jmp btoe
    
    etob:
        cmp cx, 0
        jz done
        mov al, [si]
        mov byte [di], al
        dec si
        dec di
        dec cx
        jmp etob
    
    done:
        ret
    
    ; es:bx --> root entry offset address
    ; ds:si --> target string
    ; cx    --> target length
    ;
    ; return:
    ;     (dx !=0 ) ? exist : noexist
    ;        exist --> bx is the target entry
    FindEntry:
        push cx
    
        mov dx, [BPB_RootEntCnt]
        mov bp, sp
    
    find:
        cmp dx, 0
        jz noexist
        mov di, bx
        mov cx, [bp]
        push si
        call MemCmp
        pop si
        cmp cx, 0
        jz exist
        add bx, 32
        dec dx
        jmp find
    
    exist:
    noexist:
        pop cx
    
        ret
    
    ; ds:si --> source
    ; es:di --> destination
    ; cx    --> length
    ;
    ; return:
    ;        (cx == 0) ? equal : noequal
    MemCmp:
    
    compare:
        cmp cx, 0
        jz equal
        mov al, [si]
        cmp al, byte [di]
        jz goon
        jmp noequal
    goon:
        inc si
        inc di
        dec cx
        jmp compare
    
    equal:
    noequal:
    
        ret
    
    ; es:bp --> string address
    ; cx    --> string length
    Print:
        mov dx, 0
        mov ax, 0x1301
        mov bx, 0x0007
        int 0x10
        ret
    
    ; no parameter
    ResetFloppy:
    
        mov ah, 0x00
        mov dl, [BS_DrvNum]
        int 0x13
    
        ret
    
    ; ax    --> logic sector number
    ; cx    --> number of sector
    ; es:bx --> target address
    ReadSector:
    
        call ResetFloppy
    
        push bx
        push cx
    
        mov bl, [BPB_SecPerTrk]
        div bl
        mov cl, ah
        add cl, 1
        mov ch, al
        shr ch, 1
        mov dh, al
        and dh, 1
        mov dl, [BS_DrvNum]
    
        pop ax
        pop bx
    
        mov ah, 0x02
    
    read:
        int 0x13
        jc read
    
        ret
    
    MsgStr db  "No LOADER ..."
    MsgLen equ ($-MsgStr)
    Target db  "LOADER     "
    TarLen equ ($-Target)
    EntryItem times EntryItemLength db 0x00
    Buf:
        times 510-($-$$) db 0x00
        db 0x55, 0xaa
    

    95行跳转到加载文件内容的地址处,96行为文件的长度。运行bochs,可以看到文件内容全部打印出来了,结果如下:

     以上我们加载的文件只是文本内容,下面我们在文件中写入程序,并编译成可执行程序,然后将这个可执行程序文件放到虚拟软盘中,并加载到指定地址,然后跳转到这个地址执行。

      待加载文件中的内容如下:

    org 0x9000
    
    begin:
        mov si, msg
    
    print:
        mov al, [si]
        add si, 1
        cmp al, 0x00
        je end
        mov ah, 0x0E
        mov bx, 0x0F
        int 0x10
        jmp print
    
    end:
        hlt
        jmp end
    
    msg:
        db 0x0a, 0x0a
        db "Hello, D.T.OS!"
        db 0x0a, 0x0a
        db 0x00
    

    为了方便起见,我们修改makefile,如下:

    .PHONY : all clean rebuild
    
    BOOT_SRC := boot.asm
    BOOT_OUT := boot
    
    LOADER_SRC := loader.asm
    LOADER_OUT := loader
    
    IMG := data.img
    IMG_PATH := /mnt/hgfs
    
    RM := rm -fr
    
    all : $(IMG) $(BOOT_OUT) $(LOADER_OUT)
    	@echo "Build Success ==> D.T.OS!"
    
    $(IMG) :
    	bximage $@ -q -fd -size=1.44
    	
    $(BOOT_OUT) : $(BOOT_SRC)
    	nasm $^ -o $@
    	dd if=$@ of=$(IMG) bs=512 count=1 conv=notrunc
    	
    $(LOADER_OUT) : $(LOADER_SRC)
    	nasm $^ -o $@
    	sudo mount -o loop $(IMG) $(IMG_PATH)
    	sudo cp $@ $(IMG_PATH)/$@
    	sudo umount $(IMG_PATH)
    	
    clean :
    	$(RM) $(IMG) $(BOOT_OUT) $(LOADER_OUT)
    	
    rebuild :
    	@$(MAKE) clean
    	@$(MAKE) all
    

      makefile完成编译boot.asm,编译loader.asm,写入boot.bin到第一个扇区,挂载a.img到/mnt/hgfs目录,写入loader可执行文件,卸载a.img等。

      我们修改boot.asm,程序如下:

    org 0x7c00
    
    jmp short start
    nop
    
    define:
        BaseOfStack      equ 0x7c00
        BaseOfLoader     equ 0x9000
        RootEntryOffset  equ 19
        RootEntryLength  equ 14
        EntryItemLength  equ 32
        FatEntryOffset   equ 1
        FatEntryLength   equ 9
    
    header:
        BS_OEMName     db "D.T.Soft"
        BPB_BytsPerSec dw 512
        BPB_SecPerClus db 1
        BPB_RsvdSecCnt dw 1
        BPB_NumFATs    db 2
        BPB_RootEntCnt dw 224
        BPB_TotSec16   dw 2880
        BPB_Media      db 0xF0
        BPB_FATSz16    dw 9
        BPB_SecPerTrk  dw 18
        BPB_NumHeads   dw 2
        BPB_HiddSec    dd 0
        BPB_TotSec32   dd 0
        BS_DrvNum      db 0
        BS_Reserved1   db 0
        BS_BootSig     db 0x29
        BS_VolID       dd 0
        BS_VolLab      db "D.T.OS-0.01"
        BS_FileSysType db "FAT12   "
    
    start:
        mov ax, cs
    	mov ss, ax
    	mov ds, ax
    	mov es, ax
    	mov sp, BaseOfStack
    	
    	mov ax, RootEntryOffset
    	mov cx, RootEntryLength
    	mov bx, Buf
    	
    	call ReadSector
    	
    	mov si, Target
    	mov cx, TarLen
    	mov dx, 0
    	
    	call FindEntry
    	
    	cmp dx, 0
    	jz output
    	
    	mov si, bx
    	mov di, EntryItem
    	mov cx, EntryItemLength
    	
    	call MemCpy
    	
    	mov ax, FatEntryLength
    	mov cx, [BPB_BytsPerSec]
    	mul cx
    	mov bx, BaseOfLoader
    	sub bx, ax
    	
    	mov ax, FatEntryOffset
    	mov cx, FatEntryLength
    	
    	call ReadSector
    	
    	mov dx, [EntryItem + 0x1A]
    	mov si, BaseOfLoader
    	
    loading:
        mov ax, dx
        add ax, 31
        mov cx, 1
        push dx
        push bx
        mov bx, si
        call ReadSector
        pop bx
        pop cx
        call FatVec
        cmp dx, 0xFF7
        jnb BaseOfLoader
        add si, 512
        jmp loading
    	
    output:	
        mov bp, MsgStr
        mov cx, MsgLen
    	call Print
    	
    last:
        hlt
    	jmp last	
    
    
    ; cx --> index
    ; bx --> fat table address
    ;
    ; return:
    ;     dx --> fat[index]
    FatVec:
        mov ax, cx
        mov cl, 2
        div cl
        
        push ax
        
        mov ah, 0
        mov cx, 3
        mul cx
        mov cx, ax
        
        pop ax
        
        cmp ah, 0
        jz even
        jmp odd
    
    even:    ; FatVec[j] = ( (Fat[i+1] & 0x0F) << 8 ) | Fat[i];
        mov dx, cx
        add dx, 1
        add dx, bx
        mov bp, dx
        mov dl, byte [bp]
        and dl, 0x0F
        shl dx, 8
        add cx, bx
        mov bp, cx
        or  dl, byte [bp]
        jmp return
        
    odd:     ; FatVec[j+1] = (Fat[i+2] << 4) | ( (Fat[i+1] >> 4) & 0x0F );
        mov dx, cx
        add dx, 2
        add dx, bx
        mov bp, dx
        mov dl, byte [bp]
        mov dh, 0
        shl dx, 4
        add cx, 1
        add cx, bx
        mov bp, cx
        mov cl, byte [bp]
        shr cl, 4
        and cl, 0x0F
        mov ch, 0
        or  dx, cx
    
    return: 
        ret
    
    ; ds:si --> source
    ; es:di --> destination
    ; cx    --> length
    MemCpy:
        
        cmp si, di
        
        ja btoe
        
        add si, cx
        add di, cx
        dec si
        dec di
        
        jmp etob
        
    btoe:
        cmp cx, 0
        jz done
        mov al, [si]
        mov byte [di], al
        inc si
        inc di
        dec cx
        jmp btoe
        
    etob: 
        cmp cx, 0
        jz done
        mov al, [si]
        mov byte [di], al
        dec si
        dec di
        dec cx
        jmp etob
    
    done:   
        ret
    
    ; es:bx --> root entry offset address
    ; ds:si --> target string
    ; cx    --> target length
    ;
    ; return:
    ;     (dx !=0 ) ? exist : noexist
    ;        exist --> bx is the target entry
    FindEntry:
        push cx
        
        mov dx, [BPB_RootEntCnt]
        mov bp, sp
        
    find:
        cmp dx, 0
        jz noexist
        mov di, bx
        mov cx, [bp]
        push si
        call MemCmp
        pop si
        cmp cx, 0
        jz exist
        add bx, 32
        dec dx
        jmp find
    
    exist:
    noexist: 
        pop cx
           
        ret
    
    ; ds:si --> source
    ; es:di --> destination
    ; cx    --> length
    ;
    ; return:
    ;        (cx == 0) ? equal : noequal
    MemCmp:
    
    compare:
        cmp cx, 0
        jz equal
        mov al, [si]
        cmp al, byte [di]
        jz goon
        jmp noequal
    goon:
        inc si
        inc di
        dec cx
        jmp compare
        
    equal: 
    noequal:   
    
        ret
    
    ; es:bp --> string address
    ; cx    --> string length
    Print:
        mov dx, 0
        mov ax, 0x1301
    	mov bx, 0x0007
    	int 0x10
        ret
    
    ; no parameter
    ResetFloppy:
        
        mov ah, 0x00
        mov dl, [BS_DrvNum]
        int 0x13
        
        ret
    
    ; ax    --> logic sector number
    ; cx    --> number of sector
    ; es:bx --> target address
    ReadSector:
        
        call ResetFloppy
        
        push bx
        push cx
        
        mov bl, [BPB_SecPerTrk]
        div bl
        mov cl, ah
        add cl, 1
        mov ch, al
        shr ch, 1
        mov dh, al
        and dh, 1
        mov dl, [BS_DrvNum]
        
        pop ax
        pop bx
        
        mov ah, 0x02
    
    read:    
        int 0x13
        jc read
        
        ret
    
    MsgStr db  "No LOADER ..."	
    MsgLen equ ($-MsgStr)
    Target db  "LOADER     "
    TarLen equ ($-Target)
    EntryItem times EntryItemLength db 0x00
    Buf:
    	times 510-($-$$) db 0x00
    	db 0x55, 0xaa
    

    第90行改为跳转到文件内容加载地址处,而不再跳转到output。第309行文件的名字也改为LOADER。

      执行make,然后运行bochs,结果如下:

      可以看到,文件中的可执行程序被加载并成功执行了,成功打印出字符串。此时的打印是文件中的可执行程序中print函数实现的,而不是我们的加载程序中的Print函数实现的。

      我们将data.img拷贝到windows下,在真正的机器上试一下,设置如下:

      启动虚拟机,我们看到了以下结果:

      我们的加载程序和可执行文件都成功运行了。

      

      

      

      

      

  • 相关阅读:
    Linux安装Jenkins
    python实现寻找目录中最新的文件
    python代码实现邮件发送
    面向对象(一) 类与类之间的关系之依赖和关联
    常见模块(五) random模块
    装饰器如何装饰带参数的函数
    常见模块(四) os模块
    常见模块(二) logging模块
    常见模块(三) pickle模块和json模块
    初识模块
  • 原文地址:https://www.cnblogs.com/lh03061238/p/14034915.html
Copyright © 2011-2022 走看看